ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/src/openbabel/mol.cpp
Revision: 2518
Committed: Fri Dec 16 21:52:50 2005 UTC (18 years, 7 months ago) by tim
File size: 98102 byte(s)
Log Message:
changed __FUNCTION__ to __func__ to match C99 standard, and then added
an autoconf test to check for __func__ usability.  Changed some default
compile flags for the Sun architecture

File Contents

# User Rev Content
1 tim 2440 /**********************************************************************
2     mol.cpp - Handle molecules.
3    
4     Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5     Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison
6     Some portions Copyright (C) 2003 by Michael Banck
7    
8     This file is part of the Open Babel project.
9     For more information, see <http://openbabel.sourceforge.net/>
10    
11     This program is free software; you can redistribute it and/or modify
12     it under the terms of the GNU General Public License as published by
13     the Free Software Foundation version 2 of the License.
14    
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18     GNU General Public License for more details.
19     ***********************************************************************/
20    
21     #include "mol.hpp"
22     #include "rotamer.hpp"
23     #include "phmodel.hpp"
24     #include "bondtyper.hpp"
25     #include "matrix3x3.hpp"
26     #include "obiter.hpp"
27    
28     #ifdef HAVE_SSTREAM
29     #include <sstream>
30     #else
31     #include <strstream>
32     #endif
33    
34     using namespace std;
35    
36     namespace OpenBabel
37     {
38    
39     extern bool SwabInt;
40     extern OBPhModel phmodel;
41     extern OBAromaticTyper aromtyper;
42     extern OBAtomTyper atomtyper;
43     extern OBBondTyper bondtyper;
44    
45    
46     //
47     // OBMol member functions
48     //
49     void OBMol::SetTitle(const char *title)
50     {
51     _title = title;
52     Trim(_title);
53     }
54    
55     void OBMol::SetTitle(std::string &title)
56     {
57     _title = title;
58     Trim(_title);
59     }
60    
61     bool SortVVInt(const vector<int> &a,const vector<int> &b)
62     {
63     return(a.size() > b.size());
64     }
65    
66     bool SortAtomZ(const pair<OBAtom*,double> &a, const pair<OBAtom*,double> &b)
67     {
68     return (a.second < b.second);
69     }
70    
71     double OBMol::GetTorsion(int a,int b,int c,int d)
72     {
73     return(CalcTorsionAngle(((OBAtom*)_vatom[a-1])->GetVector(),
74     ((OBAtom*)_vatom[b-1])->GetVector(),
75     ((OBAtom*)_vatom[c-1])->GetVector(),
76     ((OBAtom*)_vatom[d-1])->GetVector()));
77     }
78    
79     void OBMol::SetTorsion(OBAtom *a,OBAtom *b,OBAtom *c, OBAtom *d, double ang)
80     {
81     vector<int> tor;
82     vector<int> atoms;
83    
84 tim 2518 obErrorLog.ThrowError(__func__,
85 tim 2440 "Ran OpenBabel::SetTorsion", obAuditMsg);
86    
87     tor.push_back(a->GetCIdx());
88     tor.push_back(b->GetCIdx());
89     tor.push_back(c->GetCIdx());
90     tor.push_back(d->GetCIdx());
91    
92     FindChildren(atoms, b->GetIdx(), c->GetIdx());
93     int j;
94     for (j = 0 ; (unsigned)j < atoms.size() ; j++ )
95     atoms[j] = (atoms[j] - 1) * 3;
96    
97     double v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z;
98     double c1x,c1y,c1z,c2x,c2y,c2z,c3x,c3y,c3z;
99     double c1mag,c2mag,radang,costheta,m[9];
100     double x,y,z,mag,rotang,sn,cs,t,tx,ty,tz;
101    
102     //calculate the torsion angle
103    
104     v1x = _c[tor[0]] - _c[tor[1]];
105     v2x = _c[tor[1]] - _c[tor[2]];
106     v1y = _c[tor[0]+1] - _c[tor[1]+1];
107     v2y = _c[tor[1]+1] - _c[tor[2]+1];
108     v1z = _c[tor[0]+2] - _c[tor[1]+2];
109     v2z = _c[tor[1]+2] - _c[tor[2]+2];
110     v3x = _c[tor[2]] - _c[tor[3]];
111     v3y = _c[tor[2]+1] - _c[tor[3]+1];
112     v3z = _c[tor[2]+2] - _c[tor[3]+2];
113    
114     c1x = v1y*v2z - v1z*v2y;
115     c2x = v2y*v3z - v2z*v3y;
116     c1y = -v1x*v2z + v1z*v2x;
117     c2y = -v2x*v3z + v2z*v3x;
118     c1z = v1x*v2y - v1y*v2x;
119     c2z = v2x*v3y - v2y*v3x;
120     c3x = c1y*c2z - c1z*c2y;
121     c3y = -c1x*c2z + c1z*c2x;
122     c3z = c1x*c2y - c1y*c2x;
123    
124     c1mag = SQUARE(c1x)+SQUARE(c1y)+SQUARE(c1z);
125     c2mag = SQUARE(c2x)+SQUARE(c2y)+SQUARE(c2z);
126     if (c1mag*c2mag < 0.01)
127     costheta = 1.0; //avoid div by zero error
128     else
129     costheta = (c1x*c2x + c1y*c2y + c1z*c2z)/(sqrt(c1mag*c2mag));
130    
131     if (costheta < -0.999999)
132     costheta = -0.999999;
133     if (costheta > 0.999999)
134     costheta = 0.999999;
135    
136     if ((v2x*c3x + v2y*c3y + v2z*c3z) > 0.0)
137     radang = -acos(costheta);
138     else
139     radang = acos(costheta);
140    
141     //
142     // now we have the torsion angle (radang) - set up the rot matrix
143     //
144    
145     //find the difference between current and requested
146     rotang = ang - radang;
147    
148     sn = sin(rotang);
149     cs = cos(rotang);
150     t = 1 - cs;
151     //normalize the rotation vector
152     mag = sqrt(SQUARE(v2x)+SQUARE(v2y)+SQUARE(v2z));
153     x = v2x/mag;
154     y = v2y/mag;
155     z = v2z/mag;
156    
157     //set up the rotation matrix
158     m[0]= t*x*x + cs;
159     m[1] = t*x*y + sn*z;
160     m[2] = t*x*z - sn*y;
161     m[3] = t*x*y - sn*z;
162     m[4] = t*y*y + cs;
163     m[5] = t*y*z + sn*x;
164     m[6] = t*x*z + sn*y;
165     m[7] = t*y*z - sn*x;
166     m[8] = t*z*z + cs;
167    
168     //
169     //now the matrix is set - time to rotate the atoms
170     //
171     tx = _c[tor[1]];
172     ty = _c[tor[1]+1];
173     tz = _c[tor[1]+2];
174     vector<int>::iterator i;
175     for (i = atoms.begin(),j=*i;i != atoms.end();i++,j=*i)
176     {
177     _c[j] -= tx;
178     _c[j+1] -= ty;
179     _c[j+2]-= tz;
180     x = _c[j]*m[0] + _c[j+1]*m[1] + _c[j+2]*m[2];
181     y = _c[j]*m[3] + _c[j+1]*m[4] + _c[j+2]*m[5];
182     z = _c[j]*m[6] + _c[j+1]*m[7] + _c[j+2]*m[8];
183     _c[j] = x;
184     _c[j+1] = y;
185     _c[j+2] = z;
186     _c[j] += tx;
187     _c[j+1] += ty;
188     _c[j+2] += tz;
189     }
190     }
191    
192    
193     double OBMol::GetTorsion(OBAtom *a,OBAtom *b,OBAtom *c,OBAtom *d)
194     {
195     return(CalcTorsionAngle(a->GetVector(),
196     b->GetVector(),
197     c->GetVector(),
198     d->GetVector()));
199     }
200    
201     void OBMol::ContigFragList(std::vector<std::vector<int> >&cfl)
202     {
203     int j;
204     OBAtom *atom;
205     OBBond *bond;
206     vector<OBNodeBase*>::iterator i;
207     vector<OBEdgeBase*>::iterator k;
208     OBBitVec used,curr,next,frag;
209     vector<int> tmp;
210    
211     used.Resize(NumAtoms()+1);
212     curr.Resize(NumAtoms()+1);
213     next.Resize(NumAtoms()+1);
214     frag.Resize(NumAtoms()+1);
215    
216     while ((unsigned)used.CountBits() < NumAtoms())
217     {
218     curr.Clear();
219     frag.Clear();
220     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
221     if (!used.BitIsOn(atom->GetIdx()))
222     {
223     curr.SetBitOn(atom->GetIdx());
224     break;
225     }
226    
227     frag |= curr;
228     while (!curr.IsEmpty())
229     {
230     next.Clear();
231     for (j = curr.NextBit(-1);j != curr.EndBit();j = curr.NextBit(j))
232     {
233     atom = GetAtom(j);
234     for (bond = atom->BeginBond(k);bond;bond = atom->NextBond(k))
235     if (!used.BitIsOn(bond->GetNbrAtomIdx(atom)))
236     next.SetBitOn(bond->GetNbrAtomIdx(atom));
237     }
238    
239     used |= curr;
240     used |= next;
241     frag |= next;
242     curr = next;
243     }
244    
245     tmp.clear();
246     frag.ToVecInt(tmp);
247     cfl.push_back(tmp);
248     }
249    
250     sort(cfl.begin(),cfl.end(),SortVVInt);
251     }
252    
253     /*!
254     **\brief Fills the OBGeneric OBTorsionData with torsions from the mol
255     */
256     void OBMol::FindTorsions()
257     {
258     //if already has data return
259     if(HasData(OBGenericDataType::TorsionData))
260     return;
261    
262     //get new data and attach it to molecule
263     OBTorsionData *torsions = new OBTorsionData;
264     SetData(torsions);
265    
266     OBTorsion torsion;
267     vector<OBEdgeBase*>::iterator bi1,bi2,bi3;
268     OBBond* bond;
269     OBAtom *a,*b,*c,*d;
270    
271     //loop through all bonds generating torsions
272     for(bond = BeginBond(bi1);bond;bond = NextBond(bi1))
273     {
274     b = bond->GetBeginAtom();
275     c = bond->GetEndAtom();
276     if(b->IsHydrogen() || c->IsHydrogen())
277     continue;
278    
279     for(a = b->BeginNbrAtom(bi2);a;a = b->NextNbrAtom(bi2))
280     {
281     if(a == c)
282     continue;
283    
284     for(d = c->BeginNbrAtom(bi3);d;d = c->NextNbrAtom(bi3))
285     {
286     if(d == b)
287     continue;
288     torsion.AddTorsion(a,b,c,d);
289     }
290     }
291     //add torsion to torsionData
292     if(torsion.GetSize())
293     torsions->SetData(torsion);
294     torsion.Clear();
295     }
296    
297     return;
298     }
299    
300     void OBMol::FindLargestFragment(OBBitVec &lf)
301     {
302     int j;
303     OBAtom *atom;
304     OBBond *bond;
305     vector<OBNodeBase*>::iterator i;
306     vector<OBEdgeBase*>::iterator k;
307     OBBitVec used,curr,next,frag;
308    
309     lf.Clear();
310     while ((unsigned)used.CountBits() < NumAtoms())
311     {
312     curr.Clear();
313     frag.Clear();
314     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
315     if (!used.BitIsOn(atom->GetIdx()))
316     {
317     curr.SetBitOn(atom->GetIdx());
318     break;
319     }
320    
321     frag |= curr;
322     while (!curr.IsEmpty())
323     {
324     next.Clear();
325     for (j = curr.NextBit(-1);j != curr.EndBit();j = curr.NextBit(j))
326     {
327     atom = GetAtom(j);
328     for (bond = atom->BeginBond(k);bond;bond = atom->NextBond(k))
329     if (!used.BitIsOn(bond->GetNbrAtomIdx(atom)))
330     next.SetBitOn(bond->GetNbrAtomIdx(atom));
331     }
332    
333     used |= curr;
334     used |= next;
335     frag |= next;
336     curr = next;
337     }
338    
339     if (lf.Empty() || lf.CountBits() < frag.CountBits())
340     lf = frag;
341     }
342     }
343    
344     //! locates all atoms for which there exists a path to 'end'
345     //! without going through 'bgn'
346     //! children must not include 'end'
347     void OBMol::FindChildren(vector<OBAtom*> &children,OBAtom *bgn,OBAtom *end)
348     {
349     OBBitVec used,curr,next;
350    
351     used |= bgn->GetIdx();
352     used |= end->GetIdx();
353     curr |= end->GetIdx();
354     children.clear();
355    
356     int i;
357     OBAtom *atom,*nbr;
358     vector<OBEdgeBase*>::iterator j;
359    
360     for (;;)
361     {
362     next.Clear();
363     for (i = curr.NextBit(-1);i != curr.EndBit();i = curr.NextBit(i))
364     {
365     atom = GetAtom(i);
366     for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
367     if (!used[nbr->GetIdx()])
368     {
369     children.push_back(nbr);
370     next |= nbr->GetIdx();
371     used |= nbr->GetIdx();
372     }
373     }
374     if (next.Empty())
375     break;
376     curr = next;
377     }
378     }
379    
380     //! locates all atoms for which there exists a path to 'second'
381     //! without going through 'first'
382     //! children must not include 'second'
383     void OBMol::FindChildren(vector<int> &children,int first,int second)
384     {
385     int i;
386     OBBitVec used,curr,next;
387    
388     used.SetBitOn(first);
389     used.SetBitOn(second);
390     curr.SetBitOn(second);
391    
392     OBAtom *atom;
393     OBBond *bond;
394     vector<OBEdgeBase*>::iterator j;
395    
396     while (!curr.IsEmpty())
397     {
398     next.Clear();
399     for (i = curr.NextBit(-1);i != curr.EndBit();i = curr.NextBit(i))
400     {
401     atom = GetAtom(i);
402     for (j = atom->BeginBonds(),bond=(OBBond *)*j;
403     j != atom->EndBonds();j++,bond=(OBBond *)*j)
404     if (!used.BitIsOn(bond->GetNbrAtomIdx(atom)))
405     next.SetBitOn(bond->GetNbrAtomIdx(atom));
406     }
407    
408     used |= next;
409     curr = next;
410     }
411    
412     used.SetBitOff(first);
413     used.SetBitOff(second);
414     used.ToVecInt(children);
415     }
416    
417     /*!
418     **\brief Calculates the graph theoretical distance of each atom.
419     ** Vector is indexed from zero
420     */
421     bool OBMol::GetGTDVector(vector<int> &gtd)
422     //calculates the graph theoretical distance for every atom
423     //and puts it into gtd
424     {
425     gtd.clear();
426     gtd.resize(NumAtoms());
427    
428     int gtdcount,natom;
429     OBBitVec used,curr,next;
430     OBAtom *atom,*atom1;
431     OBBond *bond;
432     vector<OBNodeBase*>::iterator i;
433     vector<OBEdgeBase*>::iterator j;
434    
435     next.Clear();
436    
437     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
438     {
439     gtdcount = 0;
440     used.Clear();
441     curr.Clear();
442     used.SetBitOn(atom->GetIdx());
443     curr.SetBitOn(atom->GetIdx());
444    
445     while (!curr.IsEmpty())
446     {
447     next.Clear();
448     for (natom = curr.NextBit(-1);natom != curr.EndBit();natom = curr.NextBit(natom))
449     {
450     atom1 = GetAtom(natom);
451     for (bond = atom1->BeginBond(j);bond;bond = atom1->NextBond(j))
452     if (!used.BitIsOn(bond->GetNbrAtomIdx(atom1)) && !curr.BitIsOn(bond->GetNbrAtomIdx(atom1)))
453     if (!(bond->GetNbrAtom(atom1))->IsHydrogen())
454     next.SetBitOn(bond->GetNbrAtomIdx(atom1));
455     }
456    
457     used |= next;
458     curr = next;
459     gtdcount++;
460     }
461     gtd[atom->GetIdx()-1] = gtdcount;
462     }
463     return(true);
464     }
465    
466     /*!
467     **\brief Calculates a set of graph invariant indexes using
468     ** the graph theoretical distance, number of connected heavy atoms,
469     ** aromatic boolean, ring boolean, atomic number, and
470     ** summation of bond orders connected to the atom.
471     ** Vector is indexed from zero
472     */
473     void OBMol::GetGIVector(vector<unsigned int> &vid)
474     {
475     vid.clear();
476     vid.resize(NumAtoms()+1);
477    
478     vector<int> v;
479     GetGTDVector(v);
480    
481     int i;
482     OBAtom *atom;
483     vector<OBNodeBase*>::iterator j;
484     for (i=0,atom = BeginAtom(j);atom;atom = NextAtom(j),i++)
485     {
486     vid[i] = (unsigned int)v[i];
487     vid[i] += (unsigned int)(atom->GetHvyValence()*100);
488     vid[i] += (unsigned int)(((atom->IsAromatic()) ? 1 : 0)*1000);
489     vid[i] += (unsigned int)(((atom->IsInRing()) ? 1 : 0)*10000);
490     vid[i] += (unsigned int)(atom->GetAtomicNum()*100000);
491     vid[i] += (unsigned int)(atom->GetImplicitValence()*10000000);
492     }
493     }
494    
495     static bool OBComparePairSecond(const pair<OBAtom*,unsigned int> &a,const pair<OBAtom*,unsigned int> &b)
496     {
497     return(a.second < b.second);
498     }
499    
500     static bool OBComparePairFirst(const pair<OBAtom*,unsigned int> &a,const pair<OBAtom*,unsigned int> &b)
501     {
502     return(a.first->GetIdx() < b.first->GetIdx());
503     }
504    
505     //! counts the number of unique symmetry classes in a list
506     static void ClassCount(vector<pair<OBAtom*,unsigned int> > &vp,unsigned int &count)
507     {
508     count = 0;
509     vector<pair<OBAtom*,unsigned int> >::iterator k;
510     sort(vp.begin(),vp.end(),OBComparePairSecond);
511    
512     k = vp.begin();
513     if (k != vp.end())
514     {
515     unsigned int id = k->second;
516     k->second = 0;
517     ++k;
518     for (;k != vp.end(); ++k)
519     {
520     if (k->second != id)
521     {
522     id = k->second;
523     k->second = ++count;
524     }
525     else
526     k->second = count;
527     }
528     ++count;
529     }
530     else
531     {
532     // [ejk] thinks count=0 might be OK for an empty list, but orig code did
533     //++count;
534     }
535     }
536    
537     //! creates a new vector of symmetry classes base on an existing vector
538     //! helper routine to GetGIDVector
539     static void CreateNewClassVector(vector<pair<OBAtom*,unsigned int> > &vp1,vector<pair<OBAtom*,unsigned int> > &vp2)
540     {
541     int m,id;
542     OBAtom *nbr;
543     vector<OBEdgeBase*>::iterator j;
544     vector<unsigned int>::iterator k;
545     vector<pair<OBAtom*,unsigned int> >::iterator i;
546     sort(vp1.begin(),vp1.end(),OBComparePairFirst);
547     vp2.clear();
548     for (i = vp1.begin();i != vp1.end();i++)
549     {
550     vector<unsigned int> vtmp;
551     for (nbr = i->first->BeginNbrAtom(j);nbr;nbr = i->first->NextNbrAtom(j))
552     vtmp.push_back(vp1[nbr->GetIdx()-1].second);
553     sort(vtmp.begin(),vtmp.end(),OBCompareUnsigned);
554     for (id=i->second,m=100,k = vtmp.begin();k != vtmp.end();k++,m*=100)
555     id += *k * m;
556    
557     vp2.push_back(pair<OBAtom*,unsigned int> (i->first,id));
558     }
559     }
560    
561     /*!
562     **\brief Calculates a set of symmetry identifiers for a molecule.
563     ** Atoms with the same symmetry ID are symmetrically equivalent.
564     ** Vector is indexed from zero
565     */
566     void OBMol::GetGIDVector(vector<unsigned int> &vgid)
567     {
568     vector<unsigned int> vgi;
569     GetGIVector(vgi); //get vector of graph invariants
570    
571     int i;
572     OBAtom *atom;
573     vector<OBNodeBase*>::iterator j;
574     vector<pair<OBAtom*,unsigned int> > vp1,vp2;
575     for (i=0,atom = BeginAtom(j);atom;atom = NextAtom(j),i++)
576     vp1.push_back(pair<OBAtom*,unsigned int> (atom,vgi[i]));
577    
578     unsigned int nclass1,nclass2; //number of classes
579     ClassCount(vp1,nclass1);
580    
581     if (nclass1 < NumAtoms())
582     {
583     for (i = 0;i < 100;i++) //sanity check - shouldn't ever hit this number
584     {
585     CreateNewClassVector(vp1,vp2);
586     ClassCount(vp2,nclass2);
587     vp1 = vp2;
588     if (nclass1 == nclass2)
589     break;
590     nclass1 = nclass2;
591     }
592     }
593    
594     vgid.clear();
595     sort(vp1.begin(),vp1.end(),OBComparePairFirst);
596     vector<pair<OBAtom*,unsigned int> >::iterator k;
597     for (k = vp1.begin();k != vp1.end();k++)
598     vgid.push_back(k->second);
599     }
600    
601     unsigned int OBMol::NumHvyAtoms()
602     {
603     OBAtom *atom;
604     vector<OBNodeBase*>::iterator(i);
605     unsigned int count = 0;
606    
607     for(atom = this->BeginAtom(i);atom;atom = this->NextAtom(i))
608     {
609     if(!atom->IsHydrogen())
610     count++;
611     }
612    
613     return(count);
614     }
615    
616     unsigned int OBMol::NumRotors()
617     {
618     OBBond *bond;
619     vector<OBEdgeBase*>::iterator i;
620    
621     unsigned int count = 0;
622     for (bond = BeginBond(i);bond;bond = NextBond(i))
623     if (bond->IsRotor())
624     count++;
625    
626     return(count);
627     }
628    
629     //! Returns a pointer to the atom after a safety check
630     //! 0 < idx <= NumAtoms
631     OBAtom *OBMol::GetAtom(int idx)
632     {
633     if ((unsigned)idx < 1 || (unsigned)idx > NumAtoms())
634     {
635 tim 2518 obErrorLog.ThrowError(__func__, "Requested Atom Out of Range", obDebug);
636 tim 2440 return((OBAtom*)NULL);
637     }
638    
639     return((OBAtom*)_vatom[idx-1]);
640     }
641    
642     OBAtom *OBMol::GetFirstAtom()
643     {
644     return((_vatom.empty()) ? (OBAtom*)NULL : (OBAtom*)_vatom[0]);
645     }
646    
647     //! Returns a pointer to the bond after a safety check
648     //! 0 <= idx < NumBonds
649     OBBond *OBMol::GetBond(int idx)
650     {
651     if (idx < 0 || (unsigned)idx >= NumBonds())
652     {
653 tim 2518 obErrorLog.ThrowError(__func__, "Requested Bond Out of Range", obDebug);
654 tim 2440 return((OBBond*)NULL);
655     }
656    
657     return((OBBond*)_vbond[idx]);
658     }
659    
660     OBBond *OBMol::GetBond(int bgn, int end)
661     {
662     return(GetBond(GetAtom(bgn),GetAtom(end)));
663     }
664    
665     OBBond *OBMol::GetBond(OBAtom *bgn,OBAtom *end)
666     {
667     OBAtom *nbr;
668     vector<OBEdgeBase*>::iterator i;
669    
670     for (nbr = bgn->BeginNbrAtom(i);nbr;nbr = bgn->NextNbrAtom(i))
671     if (nbr == end)
672     return((OBBond *)*i);
673    
674     return(NULL); //just to keep the SGI compiler happy
675     }
676    
677     OBResidue *OBMol::GetResidue(int idx)
678     {
679     if (idx < 0 || (unsigned)idx >= NumResidues())
680     {
681 tim 2518 obErrorLog.ThrowError(__func__, "Requested Residue Out of Range", obDebug);
682 tim 2440 return((OBResidue*)NULL);
683     }
684    
685     return (_residue[idx]);
686     }
687    
688     std::vector<OBInternalCoord*> OBMol::GetInternalCoord()
689     {
690     if (_internals.empty())
691     {
692     _internals.push_back((OBInternalCoord*)NULL);
693     for(unsigned int i = 1; i <= NumAtoms(); i++)
694     {
695     _internals.push_back(new OBInternalCoord);
696     }
697     CartesianToInternal(_internals, *this);
698     }
699     return _internals;
700     }
701    
702     //! Implements <a href="http://qsar.sourceforge.net/dicts/blue-obelisk/index.xhtml#findSmallestSetOfSmallestRings">blue-obelisk:findSmallestSetOfSmallestRings</a>.
703     vector<OBRing*> &OBMol::GetSSSR()
704     {
705     if (!HasSSSRPerceived())
706     FindSSSR();
707    
708     if (!HasData(OBGenericDataType::RingData))
709     SetData(new OBRingData);
710    
711     OBRingData *rd = (OBRingData *) GetData(OBGenericDataType::RingData);
712     return(rd->GetData());
713     }
714    
715     double OBMol::GetMolWt()
716     {
717     double molwt=0.0;
718     OBAtom *atom;
719     vector<OBNodeBase*>::iterator i;
720    
721     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
722     molwt += atom->GetAtomicMass();
723    
724     return(molwt);
725     }
726    
727     double OBMol::GetExactMass()
728     {
729     double mass=0.0;
730     OBAtom *atom;
731     vector<OBNodeBase*>::iterator i;
732    
733     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
734     mass += atom->GetExactMass();
735    
736     return(mass);
737     }
738    
739     //! Stochoimetric formula (e.g., C4H6O).
740     //! This is either set by OBMol::SetFormula() or generated on-the-fly
741     //! using the "Hill order" -- i.e., C first if present, then H if present
742     //! all other elements in alphabetical order.
743     string OBMol::GetFormula()
744     {
745     string attr = "Formula";
746     OBPairData *dp = (OBPairData *) GetData(attr);
747    
748     if (dp != NULL) // we already set the formula
749     return dp->GetValue();
750    
751 tim 2518 obErrorLog.ThrowError(__func__,
752 tim 2440 "Ran OpenBabel::SetFormula -- Hill order formula",
753     obAuditMsg);
754    
755     // OK, now let's generate the formula and store it for future use.
756     // These are the atomic numbers of the elements in alphabetical order.
757     const int NumElements = 110;
758     const int alphabetical[NumElements] = {
759     89, 47, 13, 95, 18, 33, 85, 79, 5, 56, 4, 107, 83, 97, 35, 6, 20, 48,
760     58, 98, 17, 96, 27, 24, 55, 29, 105, 66, 68, 99, 63, 9, 26, 100, 87, 31,
761     64, 32, 1, 2, 72, 80, 67, 108, 53, 49, 77, 19, 36, 57, 3, 103, 71, 101,
762     12, 25, 42, 109, 7, 11, 41, 60, 10, 28, 102, 93, 8, 76, 15, 91, 82, 46,
763     61, 84, 59, 78, 94, 88, 37, 75, 104, 45, 86, 44, 16, 51, 21, 34, 106, 14,
764     62, 50, 38, 73, 65, 43, 52, 90, 22, 81, 69, 92, 110, 23, 74, 54, 39, 70,
765     30, 40 };
766    
767     int atomicCount[NumElements];
768     // int index;
769     #ifdef HAVE_SSTREAM
770     stringstream formula;
771     #else
772     strstream formula;
773     #endif
774    
775     for (int i = 0; i < NumElements; i++)
776     atomicCount[i] = 0;
777    
778     FOR_ATOMS_OF_MOL(a, *this)
779     atomicCount[a->GetAtomicNum() - 1]++;
780    
781     if (atomicCount[5] != 0) // Carbon (i.e. 6 - 1 = 5)
782     {
783     if (atomicCount[5] > 1)
784     formula << "C" << atomicCount[5];
785     else if (atomicCount[5] == 1)
786     formula << "C";
787    
788     atomicCount[5] = 0; // So we don't output C twice
789    
790     // only output H if there's also carbon -- otherwise do it alphabetical
791     if (atomicCount[0] != 0) // Hydrogen (i.e., 1 - 1 = 0)
792     {
793     if (atomicCount[0] > 1)
794     formula << "H" << atomicCount[0];
795     else if (atomicCount[0] == 1)
796     formula << "H";
797    
798     atomicCount[0] = 0;
799     }
800     }
801    
802     for (int j = 0; j < NumElements; j++)
803     {
804     if (atomicCount[ alphabetical[j]-1 ] > 1)
805     formula << etab.GetSymbol(alphabetical[j])
806     << atomicCount[ alphabetical[j]-1 ];
807     else if (atomicCount[ alphabetical[j]-1 ] == 1)
808     formula << etab.GetSymbol( alphabetical[j] );
809     }
810    
811     dp = new OBPairData;
812     dp->SetAttribute(attr);
813     dp->SetValue( formula.str() );
814     SetData(dp);
815    
816     return (formula.str());
817     }
818    
819     void OBMol::SetFormula(string molFormula)
820     {
821     string attr = "Formula";
822     OBPairData *dp = (OBPairData *) GetData(attr);
823    
824     if (dp == NULL)
825     {
826     dp = new OBPairData;
827     dp->SetAttribute(attr);
828     }
829     dp->SetValue(molFormula);
830    
831     SetData(dp);
832     }
833    
834     void OBMol::SetTotalCharge(int charge)
835     {
836     SetFlag(OB_TCHARGE_MOL);
837     _totalCharge = charge;
838     }
839    
840     //! Returns the total molecular charge -- if it has not previously been set
841     //! it is calculated from the atomic formal charge information.
842     //! (This may or may not be correct!)
843     //! If you set atomic charges with OBAtom::SetFormalCharge()
844     //! you really should set the molecular charge with OBMol::SetTotalCharge()
845     int OBMol::GetTotalCharge()
846     {
847     if(HasFlag(OB_TCHARGE_MOL))
848     return(_totalCharge);
849     else // calculate from atomic formal charges (seems the best default)
850     {
851 tim 2518 obErrorLog.ThrowError(__func__,
852 tim 2440 "Ran OpenBabel::GetTotalCharge -- calculated from formal charges",
853     obAuditMsg);
854    
855     OBAtom *atom;
856     vector<OBNodeBase*>::iterator i;
857     int chg = 0;
858    
859     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
860     chg += atom->GetFormalCharge();
861     return (chg);
862     }
863     }
864    
865     void OBMol::SetTotalSpinMultiplicity(unsigned int spin)
866     {
867     SetFlag(OB_TSPIN_MOL);
868     _totalSpin = spin;
869     }
870    
871     //! Returns the total spin multiplicity -- if it has not previously been set
872     //! it is calculated from the atomic spin multiplicity information
873     //! assuming the high-spin case (i.e. it simply sums the atomic spins,
874     //! making no attempt to pair spins).
875     //! However, if you set atomic spins with OBAtom::SetSpinMultiplicity()
876     //! you really should set the molecular spin with
877     //! OBMol::SetTotalSpinMultiplicity()
878     unsigned int OBMol::GetTotalSpinMultiplicity()
879     {
880     if (HasFlag(OB_TSPIN_MOL))
881     return(_totalSpin);
882     else // calculate from atomic spin information (assuming high-spin case)
883     {
884 tim 2518 obErrorLog.ThrowError(__func__,
885 tim 2440 "Ran OpenBabel::GetTotalSpinMultiplicity -- calculating from atomic spins and high spin",
886     obAuditMsg);
887    
888     OBAtom *atom;
889     vector<OBNodeBase*>::iterator i;
890     unsigned int spin = 1;
891    
892     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
893     {
894     if (atom->GetSpinMultiplicity() > 1)
895     spin += atom->GetSpinMultiplicity() - 1;
896     }
897     return (spin);
898     }
899     }
900    
901     OBMol &OBMol::operator=(const OBMol &source)
902     //only atom and bond info is copied from src to dest
903     //Conformers are now copied also, MM 2/7/01
904     //Rotamers and residue information are copied, MM 4-27-01
905     {
906     OBMol &src = (OBMol &)source;
907     vector<OBNodeBase*>::iterator i;
908     vector<OBEdgeBase*>::iterator j;
909     OBAtom *atom;
910     OBBond *bond;
911    
912     Clear();
913     BeginModify();
914    
915     _vatom.reserve(src.NumAtoms());
916     _vbond.reserve(src.NumBonds());
917    
918     for (atom = src.BeginAtom(i);atom;atom = src.NextAtom(i))
919     AddAtom(*atom);
920     for (bond = src.BeginBond(j);bond;bond = src.NextBond(j))
921     AddBond(*bond);
922    
923     this->_title = src.GetTitle();
924     this->_energy = src.GetEnergy();
925    
926     EndModify();
927    
928     //Copy Residue information
929     unsigned int NumRes = src.NumResidues();
930     if (NumRes)
931     {
932     unsigned int k;
933     OBResidue *src_res=NULL;
934     OBResidue *res=NULL;
935     OBAtom *src_atom=NULL;
936     OBAtom *atom=NULL;
937     vector<OBAtom*>::iterator ii;
938     for (k=0 ; k<NumRes ; k++)
939     {
940     res = NewResidue();
941     src_res = src.GetResidue(k);
942     res->SetName(src_res->GetName());
943     res->SetNum(src_res->GetNum());
944     res->SetChain(src_res->GetChain());
945     res->SetChainNum(src_res->GetChainNum());
946     for (src_atom=src_res->BeginAtom(ii) ; src_atom ; src_atom=src_res->NextAtom(ii))
947     {
948     atom = GetAtom(src_atom->GetIdx());
949     res->AddAtom(atom);
950     res->SetAtomID(atom,src_res->GetAtomID(src_atom));
951     res->SetHetAtom(atom,src_res->IsHetAtom(src_atom));
952     res->SetSerialNum(atom,src_res->GetSerialNum(src_atom));
953     }
954     }
955     }
956    
957     //Copy conformer information
958     if (src.NumConformers() > 1)
959     {
960     int k,l;
961     vector<double*> conf;
962     double* xyz = NULL;
963     for (k=0 ; k<src.NumConformers() ; k++)
964     {
965     xyz = new double [3*src.NumAtoms()];
966     for (l=0 ; l<(int) (3*src.NumAtoms()) ; l++)
967     xyz[l] = src.GetConformer(k)[l];
968     conf.push_back(xyz);
969     }
970     SetConformers(conf);
971     }
972    
973     //Copy rotamer list
974     OBRotamerList *rml = (OBRotamerList *)src.GetData(OBGenericDataType::RotamerList);
975     if (rml && rml->NumAtoms() == src.NumAtoms())
976     {
977     //Destroy old rotamer list if necessary
978     if ((OBRotamerList *)GetData(OBGenericDataType::RotamerList))
979     {
980     DeleteData(OBGenericDataType::RotamerList);
981     }
982    
983     //Set base coordinates
984     OBRotamerList *cp_rml = new OBRotamerList;
985     unsigned int k,l;
986     vector<double*> bc;
987     double *c=NULL;
988     double *cc=NULL;
989     for (k=0 ; k<rml->NumBaseCoordinateSets() ; k++)
990     {
991     c = new double [3*rml->NumAtoms()];
992     cc = rml->GetBaseCoordinateSet(k);
993     for (l=0 ; l<3*rml->NumAtoms() ; l++)
994     c[l] = cc[l];
995     bc.push_back(c);
996     }
997     if (rml->NumBaseCoordinateSets())
998     cp_rml->SetBaseCoordinateSets(bc,rml->NumAtoms());
999    
1000     //Set reference array
1001     unsigned char *ref = new unsigned char [rml->NumRotors()*4];
1002     if (ref)
1003     {
1004     rml->GetReferenceArray(ref);
1005     cp_rml->Setup((*this),ref,rml->NumRotors());
1006     delete [] ref;
1007     }
1008    
1009     //Set Rotamers
1010     unsigned char *rotamers = new unsigned char [(rml->NumRotors()+1)*rml->NumRotamers()];
1011     if (rotamers)
1012     {
1013     vector<unsigned char*>::iterator kk;
1014     unsigned int idx=0;
1015     for (kk = rml->BeginRotamer();kk != rml->EndRotamer();kk++)
1016     {
1017     memcpy(&rotamers[idx],(const unsigned char*)*kk,sizeof(unsigned char)*(rml->NumRotors()+1));
1018     idx += sizeof(unsigned char)*(rml->NumRotors()+1);
1019     }
1020     cp_rml->AddRotamers(rotamers,rml->NumRotamers());
1021     delete [] rotamers;
1022     }
1023     SetData(cp_rml);
1024     }
1025    
1026     return(*this);
1027     }
1028    
1029     OBMol &OBMol::operator+=(const OBMol &source)
1030     {
1031     OBMol &src = (OBMol &)source;
1032     vector<OBNodeBase*>::iterator i;
1033     vector<OBEdgeBase*>::iterator j;
1034     OBAtom *atom;
1035     OBBond *bond;
1036    
1037     BeginModify();
1038    
1039     int prevatms = NumAtoms();
1040    
1041     _title += "_" + string(src.GetTitle());
1042    
1043     for (atom = src.BeginAtom(i) ; atom ; atom = src.NextAtom(i))
1044     AddAtom(*atom);
1045     for (bond = src.BeginBond(j) ; bond ; bond = src.NextBond(j))
1046     AddBond(bond->GetBeginAtomIdx() + prevatms, bond->GetEndAtomIdx() + prevatms, bond->GetBO(), bond->GetFlags());
1047    
1048     EndModify();
1049    
1050     return(*this);
1051     }
1052    
1053     bool OBMol::Clear()
1054     {
1055 tim 2518 obErrorLog.ThrowError(__func__,
1056 tim 2440 "Ran OpenBabel::Clear Molecule", obAuditMsg);
1057    
1058     vector<OBNodeBase*>::iterator i;
1059     vector<OBEdgeBase*>::iterator j;
1060     for (i = _vatom.begin();i != _vatom.end();i++)
1061     {
1062     DestroyAtom(*i);
1063     *i = NULL;
1064     }
1065     for (j = _vbond.begin();j != _vbond.end();j++)
1066     {
1067     DestroyBond(*j);
1068     *j = NULL;
1069     }
1070    
1071     _natoms = _nbonds = 0;
1072    
1073     //Delete residues
1074     unsigned int ii;
1075     for (ii=0 ; ii<_residue.size() ; ii++)
1076     {
1077     delete _residue[ii];
1078     }
1079     _residue.clear();
1080    
1081     //clear out the multiconformer data
1082     vector<double*>::iterator k;
1083     for (k = _vconf.begin();k != _vconf.end();k++)
1084     delete [] *k;
1085     _vconf.clear();
1086    
1087     if (!_vdata.empty()) //clean up generic data
1088     {
1089     vector<OBGenericData*>::iterator m;
1090     for (m = _vdata.begin();m != _vdata.end();m++)
1091     delete *m;
1092     _vdata.clear();
1093     }
1094    
1095     _c = (double*) NULL;
1096     _flags = 0;
1097     _mod = 0;
1098    
1099     return(true);
1100     }
1101    
1102     void OBMol::BeginModify()
1103     {
1104     //suck coordinates from _c into _v for each atom
1105     if (!_mod && !Empty())
1106     {
1107     OBAtom *atom;
1108     vector<OBNodeBase*>::iterator i;
1109     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
1110     {
1111     atom->SetVector();
1112     atom->ClearCoordPtr();
1113     }
1114    
1115     vector<double*>::iterator j;
1116     for (j = _vconf.begin();j != _vconf.end();j++)
1117     delete [] *j;
1118    
1119     _c = NULL;
1120     _vconf.clear();
1121    
1122     //Destroy rotamer list if necessary
1123     if ((OBRotamerList *)GetData(OBGenericDataType::RotamerList))
1124     {
1125     delete (OBRotamerList *)GetData(OBGenericDataType::RotamerList);
1126     DeleteData(OBGenericDataType::RotamerList);
1127     }
1128     }
1129    
1130     _mod++;
1131     }
1132    
1133     void OBMol::EndModify(bool nukePerceivedData)
1134     {
1135     if (_mod == 0)
1136     {
1137 tim 2518 obErrorLog.ThrowError(__func__, "_mod is negative - EndModify() called too many times", obDebug);
1138 tim 2440 return;
1139     }
1140    
1141     _mod--;
1142    
1143     if (_mod)
1144     return;
1145    
1146     if (nukePerceivedData)
1147     _flags = 0;
1148     _c = NULL;
1149    
1150     /*
1151     leave generic data alone for now - just nuke it on clear()
1152     if (HasData("Comment")) delete [] (char*)GetData("Comment");
1153     _vdata.clear();
1154     */
1155    
1156     if (Empty())
1157     return;
1158    
1159     //if atoms present convert coords into array
1160     double *c = new double [NumAtoms()*3];
1161     _c = c;
1162    
1163     int idx;
1164     OBAtom *atom;
1165     vector<OBNodeBase*>::iterator j;
1166     for (idx=0,atom = BeginAtom(j);atom;atom = NextAtom(j),idx++)
1167     {
1168     atom->SetIdx(idx+1);
1169     (atom->GetVector()).Get(&_c[idx*3]);
1170     atom->SetCoordPtr(&_c);
1171     }
1172     _vconf.push_back(c);
1173    
1174     //kekulize structure
1175     SetAromaticPerceived();
1176     Kekulize();
1177     //kekulize();
1178     UnsetAromaticPerceived();
1179    
1180     // for (atom = BeginAtom(j);atom;atom = NextAtom(j))
1181     // atom->UnsetAromatic();
1182    
1183     // OBBond *bond;
1184     // vector<OBEdgeBase*>::iterator k;
1185     // for (bond = BeginBond(k);bond;bond = NextBond(k))
1186     // bond->UnsetAromatic();
1187    
1188     UnsetImplicitValencePerceived();
1189     }
1190    
1191     OBAtom *OBMol::CreateAtom(void)
1192     {
1193     return new OBAtom;
1194     }
1195    
1196     OBBond *OBMol::CreateBond(void)
1197     {
1198     return new OBBond;
1199     }
1200    
1201     void OBMol::DestroyAtom(OBNodeBase *atom)
1202     {
1203     if (atom)
1204     {
1205     delete atom;
1206     atom = NULL;
1207     }
1208     }
1209    
1210     void OBMol::DestroyBond(OBEdgeBase *bond)
1211     {
1212     if (bond)
1213     {
1214     delete bond;
1215     bond = NULL;
1216     }
1217     }
1218    
1219     //! \brief Get a new atom to add to a molecule
1220     //!
1221     //! Also checks bond_queue for any bonds that should be made to the new atom
1222     OBAtom *OBMol::NewAtom()
1223     {
1224     BeginModify();
1225    
1226     OBAtom *obatom = CreateAtom();
1227     obatom->SetIdx(_natoms+1);
1228     obatom->SetParent(this);
1229    
1230    
1231     #define OBAtomIncrement 100
1232    
1233     if (_vatom.empty() || _natoms+1 >= (signed)_vatom.size())
1234     {
1235     _vatom.resize(_natoms+OBAtomIncrement);
1236     vector<OBNodeBase*>::iterator j;
1237     for (j = _vatom.begin(),j+=(_natoms+1);j != _vatom.end();j++)
1238     *j = (OBNodeBase*)NULL;
1239     }
1240     #undef OBAtomIncrement
1241    
1242     _vatom[_natoms] = obatom;
1243     _natoms++;
1244    
1245     if (HasData(OBGenericDataType::VirtualBondData))
1246     {
1247     /*add bonds that have been queued*/
1248     OBVirtualBond *vb;
1249     vector<OBGenericData*> verase;
1250     vector<OBGenericData*>::iterator i;
1251     for (i = BeginData();i != EndData();i++)
1252     if ((*i)->GetDataType() == OBGenericDataType::VirtualBondData)
1253     {
1254     vb = (OBVirtualBond*)*i;
1255     if (vb->GetBgn() > _natoms || vb->GetEnd() > _natoms)
1256     continue;
1257     if (obatom->GetIdx() == static_cast<unsigned int>(vb->GetBgn())
1258     || obatom->GetIdx() == static_cast<unsigned int>(vb->GetEnd()))
1259     {
1260     AddBond(vb->GetBgn(),vb->GetEnd(),vb->GetOrder());
1261     verase.push_back(*i);
1262     }
1263     }
1264    
1265     if (!verase.empty())
1266     DeleteData(verase);
1267     }
1268    
1269     EndModify();
1270    
1271     return(obatom);
1272     }
1273    
1274     OBResidue *OBMol::NewResidue()
1275     {
1276     OBResidue *obresidue = new OBResidue;
1277     obresidue->SetIdx(_residue.size());
1278     _residue.push_back(obresidue);
1279     return(obresidue);
1280     }
1281    
1282     //! \brief Add an atom to a molecule
1283     //!
1284     //! Also checks bond_queue for any bonds that should be made to the new atom
1285     bool OBMol::AddAtom(OBAtom &atom)
1286     {
1287     BeginModify();
1288    
1289     OBAtom *obatom = CreateAtom();
1290     *obatom = atom;
1291     obatom->SetIdx(_natoms+1);
1292     obatom->SetParent(this);
1293    
1294    
1295     #define OBAtomIncrement 100
1296    
1297     if (_vatom.empty() || _natoms+1 >= (signed)_vatom.size())
1298     {
1299     _vatom.resize(_natoms+OBAtomIncrement);
1300     vector<OBNodeBase*>::iterator j;
1301     for (j = _vatom.begin(),j+=(_natoms+1);j != _vatom.end();j++)
1302     *j = (OBNodeBase*)NULL;
1303     }
1304     #undef OBAtomIncrement
1305    
1306     _vatom[_natoms] = (OBNodeBase*)obatom;
1307     _natoms++;
1308    
1309     if (HasData(OBGenericDataType::VirtualBondData))
1310     {
1311     /*add bonds that have been queued*/
1312     OBVirtualBond *vb;
1313     vector<OBGenericData*> verase;
1314     vector<OBGenericData*>::iterator i;
1315     for (i = BeginData();i != EndData();i++)
1316     if ((*i)->GetDataType() == OBGenericDataType::VirtualBondData)
1317     {
1318     vb = (OBVirtualBond*)*i;
1319     if (vb->GetBgn() > _natoms || vb->GetEnd() > _natoms)
1320     continue;
1321     if (obatom->GetIdx() == static_cast<unsigned int>(vb->GetBgn())
1322     || obatom->GetIdx() == static_cast<unsigned int>(vb->GetEnd()))
1323     {
1324     AddBond(vb->GetBgn(),vb->GetEnd(),vb->GetOrder());
1325     verase.push_back(*i);
1326     }
1327     }
1328    
1329     if (!verase.empty())
1330     DeleteData(verase);
1331     }
1332    
1333     EndModify();
1334    
1335     return(true);
1336     }
1337    
1338     bool OBMol::InsertAtom(OBAtom &atom)
1339     {
1340     BeginModify();
1341    
1342     OBAtom *obatom = CreateAtom();
1343     *obatom = atom;
1344     obatom->SetIdx(_natoms+1);
1345     obatom->SetParent(this);
1346    
1347    
1348     #define OBAtomIncrement 100
1349    
1350     if (_vatom.empty() || _natoms+1 >= (signed)_vatom.size())
1351     {
1352     _vatom.resize(_natoms+OBAtomIncrement);
1353     vector<OBNodeBase*>::iterator j;
1354     for (j = _vatom.begin(),j+=(_natoms+1);j != _vatom.end();j++)
1355     *j = (OBNodeBase*)NULL;
1356     }
1357     #undef OBAtomIncrement
1358    
1359     _vatom[_natoms] = (OBNodeBase*)obatom;
1360     _natoms++;
1361    
1362     if (HasData(OBGenericDataType::VirtualBondData))
1363     {
1364     /*add bonds that have been queued*/
1365     OBVirtualBond *vb;
1366     vector<OBGenericData*> verase;
1367     vector<OBGenericData*>::iterator i;
1368     for (i = BeginData();i != EndData();i++)
1369     if ((*i)->GetDataType() == OBGenericDataType::VirtualBondData)
1370     {
1371     vb = (OBVirtualBond*)*i;
1372     if (vb->GetBgn() > _natoms || vb->GetEnd() > _natoms)
1373     continue;
1374     if (obatom->GetIdx() == static_cast<unsigned int>(vb->GetBgn())
1375     || obatom->GetIdx() == static_cast<unsigned int>(vb->GetEnd()))
1376     {
1377     AddBond(vb->GetBgn(),vb->GetEnd(),vb->GetOrder());
1378     verase.push_back(*i);
1379     }
1380     }
1381    
1382     if (!verase.empty())
1383     DeleteData(verase);
1384     }
1385    
1386     EndModify();
1387    
1388     return(true);
1389     }
1390    
1391     bool OBMol::AddResidue(OBResidue &residue)
1392     {
1393     BeginModify();
1394    
1395     OBResidue *obresidue = new OBResidue;
1396     *obresidue = residue;
1397    
1398     obresidue->SetIdx(_residue.size());
1399    
1400     _residue.push_back(obresidue);
1401    
1402     EndModify();
1403    
1404     return(true);
1405     }
1406    
1407     bool OBMol::StripSalts()
1408     {
1409     vector<vector<int> > cfl;
1410     vector<vector<int> >::iterator i,max;
1411    
1412     ContigFragList(cfl);
1413     if (cfl.empty() || cfl.size() == 1)
1414     return(false);
1415    
1416 tim 2518 obErrorLog.ThrowError(__func__,
1417 tim 2440 "Ran OpenBabel::StripSalts", obAuditMsg);
1418    
1419     max = cfl.begin();
1420     for (i = cfl.begin();i != cfl.end();i++)
1421     if ((*max).size() < (*i).size())
1422     max = i;
1423    
1424     vector<int>::iterator j;
1425     vector<OBNodeBase*> delatoms;
1426     for (i = cfl.begin();i != cfl.end();i++)
1427     if (i != max)
1428     for (j = (*i).begin();j != (*i).end();j++)
1429     delatoms.push_back(GetAtom(*j));
1430    
1431     if (!delatoms.empty())
1432     {
1433     int tmpflags = _flags & (~(OB_SSSR_MOL));
1434     BeginModify();
1435     vector<OBNodeBase*>::iterator k;
1436     for (k = delatoms.begin();k != delatoms.end();k++)
1437     DeleteAtom((OBAtom*)*k);
1438     EndModify();
1439     _flags = tmpflags;
1440     }
1441    
1442     return(true);
1443     }
1444    
1445     bool OBMol::DeleteNonPolarHydrogens()
1446     {
1447     OBAtom *atom;
1448     vector<OBNodeBase*>::iterator i;
1449     vector<OBNodeBase*> delatoms;
1450    
1451 tim 2518 obErrorLog.ThrowError(__func__,
1452 tim 2440 "Ran OpenBabel::DeleteHydrogens -- nonpolar",
1453     obAuditMsg);
1454    
1455     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
1456     if (atom->IsNonPolarHydrogen())
1457     delatoms.push_back(atom);
1458    
1459     if (delatoms.empty())
1460     return(true);
1461    
1462     /*
1463    
1464    
1465     int idx1,idx2;
1466     vector<double*>::iterator j;
1467     for (idx1=0,idx2=0,atom = BeginAtom(i);atom;atom = NextAtom(i),idx1++)
1468     if (!atom->IsHydrogen())
1469     {
1470     for (j = _vconf.begin();j != _vconf.end();j++)
1471     memcpy((char*)&((*j)[idx2*3]),(char*)&((*j)[idx1*3]),sizeof(double)*3);
1472     idx2++;
1473     }
1474     */
1475    
1476     IncrementMod();
1477    
1478     for (i = delatoms.begin();i != delatoms.end();i++)
1479     DeleteAtom((OBAtom *)*i);
1480    
1481     DecrementMod();
1482    
1483     return(true);
1484     }
1485    
1486     bool OBMol::DeleteHydrogens()
1487     {
1488     OBAtom *atom,*nbr;
1489     vector<OBNodeBase*>::iterator i;
1490     vector<OBNodeBase*> delatoms,va;
1491    
1492 tim 2518 obErrorLog.ThrowError(__func__,
1493 tim 2440 "Ran OpenBabel::DeleteHydrogens", obAuditMsg);
1494    
1495     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
1496     if (atom->IsHydrogen())
1497     delatoms.push_back(atom);
1498    
1499     if (delatoms.empty())
1500     return(true);
1501    
1502     /* decide whether these flags need to be reset
1503     _flags &= (~(OB_ATOMTYPES_MOL));
1504     _flags &= (~(OB_HYBRID_MOL));
1505     _flags &= (~(OB_PCHARGE_MOL));
1506     _flags &= (~(OB_IMPVAL_MOL));
1507     */
1508    
1509     //find bonds to delete
1510     vector<OBEdgeBase*> vdb;
1511     vector<OBEdgeBase*>::iterator j;
1512     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
1513     if (!atom->IsHydrogen())
1514     for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
1515     if (nbr->IsHydrogen())
1516     vdb.push_back(*j);
1517    
1518     IncrementMod();
1519     for (j = vdb.begin();j != vdb.end();j++)
1520     DeleteBond((OBBond *)*j); //delete bonds
1521     DecrementMod();
1522    
1523     int idx1,idx2;
1524     vector<double*>::iterator k;
1525     for (idx1=0,idx2=0,atom = BeginAtom(i);atom;atom = NextAtom(i),idx1++)
1526     if (!atom->IsHydrogen())
1527     {
1528     //Update conformer coordinates
1529     for (k = _vconf.begin();k != _vconf.end();k++)
1530     memcpy((char*)&((*k)[idx2*3]),(char*)&((*k)[idx1*3]),sizeof(double)*3);
1531    
1532     idx2++;
1533     va.push_back(atom);
1534     }
1535    
1536     for (i = delatoms.begin();i != delatoms.end();i++)
1537     {
1538     DestroyAtom(*i);
1539     _natoms--;
1540     }
1541    
1542     _vatom.clear();
1543     for (i = va.begin();i != va.end();i++)
1544     _vatom.push_back((OBNodeBase*)*i);
1545    
1546     //_atom = va;
1547     //_atom.resize(_atom.size()+1);
1548     //_atom[_atom.size()-1] = NULL;
1549     _natoms = va.size();
1550    
1551     //reset all the indices to the atoms
1552     for (idx1=1,atom = BeginAtom(i);atom;atom = NextAtom(i),idx1++)
1553     atom->SetIdx(idx1);
1554    
1555     return(true);
1556     }
1557    
1558     bool OBMol::DeleteHydrogens(OBAtom *atom)
1559     //deletes all hydrogens attached to the atom passed to the function
1560     {
1561     OBAtom *nbr;
1562     vector<OBNodeBase*>::iterator i;
1563     vector<OBEdgeBase*>::iterator k;
1564     vector<OBNodeBase*> delatoms;
1565    
1566     for (nbr = atom->BeginNbrAtom(k);nbr;nbr = atom->NextNbrAtom(k))
1567     if (nbr->IsHydrogen())
1568     delatoms.push_back(nbr);
1569    
1570     if (delatoms.empty())
1571     return(true);
1572    
1573     IncrementMod();
1574     for (i = delatoms.begin();i != delatoms.end();i++)
1575     DeleteHydrogen((OBAtom*)*i);
1576     DecrementMod();
1577    
1578     return(true);
1579     }
1580    
1581    
1582     bool OBMol::DeleteHydrogen(OBAtom *atom)
1583     //deletes the hydrogen atom passed to the function
1584     {
1585     //find bonds to delete
1586     OBAtom *nbr;
1587     vector<OBEdgeBase*> vdb;
1588     vector<OBEdgeBase*>::iterator j;
1589     for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
1590     vdb.push_back(*j);
1591    
1592     IncrementMod();
1593     for (j = vdb.begin();j != vdb.end();j++)
1594     DeleteBond((OBBond*)*j); //delete bonds
1595     DecrementMod();
1596    
1597     int idx;
1598     if (atom->GetIdx() != NumAtoms())
1599     {
1600     idx = atom->GetCIdx();
1601     int size = NumAtoms()-atom->GetIdx();
1602     vector<double*>::iterator k;
1603     for (k = _vconf.begin();k != _vconf.end();k++)
1604     memmove((char*)&(*k)[idx],(char*)&(*k)[idx+3],sizeof(double)*3*size);
1605    
1606     }
1607    
1608     _vatom.erase(_vatom.begin()+(atom->GetIdx()-1));
1609     DestroyAtom(atom);
1610     _natoms--;
1611    
1612     //reset all the indices to the atoms
1613     vector<OBNodeBase*>::iterator i;
1614     for (idx=1,atom = BeginAtom(i);atom;atom = NextAtom(i),idx++)
1615     atom->SetIdx(idx);
1616    
1617     return(true);
1618     }
1619    
1620     bool OBMol::AddHydrogens(bool polaronly,bool correctForPH)
1621     {
1622     if (!IsCorrectedForPH() && correctForPH)
1623     CorrectForPH();
1624    
1625     if (HasHydrogensAdded())
1626     return(true);
1627     SetHydrogensAdded();
1628    
1629     if (!polaronly)
1630 tim 2518 obErrorLog.ThrowError(__func__,
1631 tim 2440 "Ran OpenBabel::AddHydrogens", obAuditMsg);
1632     else
1633 tim 2518 obErrorLog.ThrowError(__func__,
1634 tim 2440 "Ran OpenBabel::AddHydrogens -- polar only", obAuditMsg);
1635    
1636     //count up number of hydrogens to add
1637     OBAtom *atom,*h;
1638     int hcount,count=0;
1639     vector<pair<OBAtom*,int> > vhadd;
1640     vector<OBNodeBase*>::iterator i;
1641     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
1642     {
1643     if (polaronly && !(atom->IsNitrogen() || atom->IsOxygen() ||
1644     atom->IsSulfur() || atom->IsPhosphorus()))
1645     continue;
1646    
1647     hcount = atom->GetImplicitValence() - atom->GetValence();
1648    
1649     //Jan 05 Implicit valency now left alone; use spin multiplicity for implicit Hs
1650     int mult = atom->GetSpinMultiplicity();
1651     if(mult==2) //radical
1652     hcount-=1;
1653     else if(mult==1 || mult==3) //carbene
1654     hcount-=2;
1655    
1656     if (hcount < 0)
1657     hcount = 0;
1658     if (hcount)
1659     {
1660     vhadd.push_back(pair<OBAtom*,int>(atom,hcount));
1661     count += hcount;
1662     }
1663     }
1664    
1665     if (count == 0)
1666     return(true);
1667     bool hasCoords = HasNonZeroCoords();
1668    
1669     //realloc memory in coordinate arrays for new hydrogens
1670     double *tmpf;
1671     vector<double*>::iterator j;
1672     for (j = _vconf.begin();j != _vconf.end();j++)
1673     {
1674     tmpf = new double [(NumAtoms()+count)*3];
1675     memset(tmpf,'\0',sizeof(double)*(NumAtoms()+count)*3);
1676     if (hasCoords)
1677     memcpy(tmpf,(*j),sizeof(double)*NumAtoms()*3);
1678     delete []*j;
1679     *j = tmpf;
1680     }
1681    
1682     IncrementMod();
1683    
1684     int m,n;
1685     vector3 v;
1686     vector<pair<OBAtom*,int> >::iterator k;
1687     double hbrad = etab.CorrectedBondRad(1,0);
1688    
1689    
1690     for (k = vhadd.begin();k != vhadd.end();k++)
1691     {
1692     atom = k->first;
1693     double bondlen = hbrad+etab.CorrectedBondRad(atom->GetAtomicNum(),atom->GetHyb());
1694     for (m = 0;m < k->second;m++)
1695     {
1696     for (n = 0;n < NumConformers();n++)
1697     {
1698     SetConformer(n);
1699     if (hasCoords)
1700     {
1701     atom->GetNewBondVector(v,bondlen);
1702     _c[(NumAtoms())*3] = v.x();
1703     _c[(NumAtoms())*3+1] = v.y();
1704     _c[(NumAtoms())*3+2] = v.z();
1705     }
1706     else
1707     memset((char*)&_c[NumAtoms()*3],'\0',sizeof(double)*3);
1708     }
1709     h = NewAtom();
1710     h->SetType("H");
1711     h->SetAtomicNum(1);
1712    
1713     // copy parent atom residue to added hydrogen REG 6/30/02
1714    
1715     if (atom->HasResidue())
1716     {
1717    
1718     string aname;
1719    
1720     aname = "H";
1721    
1722     // Add the new H atom to the appropriate residue list
1723     atom->GetResidue()->AddAtom(h);
1724    
1725     // Give the new atom a pointer back to the residue
1726     h->SetResidue(atom->GetResidue());
1727    
1728     atom->GetResidue()->SetAtomID(h,aname);
1729    
1730     }
1731    
1732     AddBond(atom->GetIdx(),h->GetIdx(),1);
1733     h->SetCoordPtr(&_c);
1734     }
1735     }
1736    
1737     DecrementMod();
1738     SetConformer(0);
1739    
1740     //reset atom type and partial charge flags
1741     _flags &= (~(OB_PCHARGE_MOL|OB_ATOMTYPES_MOL));
1742    
1743     return(true);
1744     }
1745    
1746     bool OBMol::AddPolarHydrogens()
1747     {
1748     return(AddHydrogens(true));
1749     }
1750    
1751     bool OBMol::AddHydrogens(OBAtom *atom)
1752     {
1753     OBAtom *h;
1754    
1755     //count up number of hydrogens to add
1756     int hcount,count=0;
1757     vector<pair<OBAtom*,int> > vhadd;
1758    
1759     hcount = atom->GetImplicitValence() - atom->GetValence();
1760    
1761     //Jan 05 Implicit valency now left alone; use spin multiplicity for implicit Hs
1762     int mult = atom->GetSpinMultiplicity();
1763     if(mult==2) //radical
1764     hcount-=1;
1765     else if(mult==1 || mult==3) //carbene
1766     hcount-=2;
1767    
1768     if (hcount < 0)
1769     hcount = 0;
1770     if (hcount)
1771     {
1772     vhadd.push_back(pair<OBAtom*,int>(atom,hcount));
1773     count += hcount;
1774     }
1775    
1776     if (count == 0)
1777     return(true);
1778    
1779     //realloc memory in coordinate arrays for new hydroges
1780     double *tmpf;
1781     vector<double*>::iterator j;
1782     for (j = _vconf.begin();j != _vconf.end();j++)
1783     {
1784     tmpf = new double [(NumAtoms()+count)*3+10];
1785     memcpy(tmpf,(*j),sizeof(double)*NumAtoms()*3);
1786     delete []*j;
1787     *j = tmpf;
1788     }
1789    
1790     IncrementMod();
1791    
1792     int m,n;
1793     vector3 v;
1794     vector<pair<OBAtom*,int> >::iterator k;
1795     double hbrad = etab.CorrectedBondRad(1,0);
1796    
1797     for (k = vhadd.begin();k != vhadd.end();k++)
1798     {
1799     atom = k->first;
1800     double bondlen = hbrad+etab.CorrectedBondRad(atom->GetAtomicNum(),atom->GetHyb());
1801     for (m = 0;m < k->second;m++)
1802     {
1803     for (n = 0;n < NumConformers();n++)
1804     {
1805     SetConformer(n);
1806     atom->GetNewBondVector(v,bondlen);
1807     _c[(NumAtoms())*3] = v.x();
1808     _c[(NumAtoms())*3+1] = v.y();
1809     _c[(NumAtoms())*3+2] = v.z();
1810     }
1811     h = NewAtom();
1812     h->SetType("H");
1813     h->SetAtomicNum(1);
1814     AddBond(atom->GetIdx(),h->GetIdx(),1);
1815     h->SetCoordPtr(&_c);
1816     }
1817     }
1818    
1819     DecrementMod();
1820     SetConformer(0);
1821    
1822     //reset atom type and partial charge flags
1823     //_flags &= (~(OB_PCHARGE_MOL|OB_ATOMTYPES_MOL));
1824    
1825     return(true);
1826     }
1827    
1828     bool OBMol::CorrectForPH()
1829     {
1830     if (IsCorrectedForPH())
1831     return(true);
1832     phmodel.CorrectForPH(*this);
1833    
1834 tim 2518 obErrorLog.ThrowError(__func__,
1835 tim 2440 "Ran OpenBabel::CorrectForPH", obAuditMsg);
1836    
1837     return(true);
1838     }
1839    
1840     //! \brief set spin multiplicity for H-deficient atoms
1841     bool OBMol::AssignSpinMultiplicity()
1842     {
1843     if (HasSpinMultiplicityAssigned())
1844     return(true);
1845    
1846     SetSpinMultiplicityAssigned();
1847    
1848 tim 2518 obErrorLog.ThrowError(__func__,
1849 tim 2440 "Ran OpenBabel::AssignSpinMultiplicity",
1850     obAuditMsg);
1851    
1852     OBAtom *atom;
1853     int diff;
1854     vector<OBNodeBase*>::iterator k;
1855     //begin CM 18 Sept 2003
1856     //if there are any explicit Hs on an atom, then they consitute all the Hs
1857     //Any discrepancy with the expected atom valency is because it is a radical of some sort
1858     //Also adjust the ImplicitValence for radical atoms
1859     for (atom = BeginAtom(k);atom;atom = NextAtom(k))
1860     {
1861    
1862     if (!atom->IsHydrogen() && atom->ExplicitHydrogenCount()!=0)
1863     {
1864     diff=atom->GetImplicitValence() - (atom->GetHvyValence() + atom->ExplicitHydrogenCount());
1865     if (diff)
1866     atom->SetSpinMultiplicity(diff+1);//radicals =2; all carbenes =3
1867     }
1868    
1869     //Jan05 mult=atom->GetSpinMultiplicity();
1870     // if(mult) //radical or carbene
1871     // atom->DecrementImplicitValence();
1872     // if(mult==1 || mult==3) //e.g.singlet or triplet carbene
1873     // atom->DecrementImplicitValence();
1874     }
1875     //end CM
1876    
1877     vector<OBNodeBase*>::iterator i;
1878     unsigned int spin = 1;
1879    
1880     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
1881     {
1882     if (atom->GetSpinMultiplicity() > 1)
1883     spin += atom->GetSpinMultiplicity() - 1;
1884     }
1885     _totalSpin = spin;
1886    
1887     return (true);
1888     }
1889    
1890    
1891     // Not used anywhere internally -- likely predates OBBase code
1892     // static void ResetVisit(OBMol &mol,vector<int> &visit,int depth)
1893     // {
1894     // OBBond *bond;
1895     // vector<OBEdgeBase*>::iterator i;
1896    
1897     // for (bond = mol.BeginBond(i);bond;bond = mol.NextBond(i))
1898     // if (bond->IsAromatic() && visit[bond->GetIdx()] >= depth)
1899     // visit[bond->GetIdx()] = 0;
1900     // }
1901    
1902     static int ValenceSum(OBAtom *atom)
1903     {
1904     int count = atom->GetImplicitValence();
1905    
1906     OBBond *bond;
1907     vector<OBEdgeBase*>::iterator i;
1908     for (bond = atom->BeginBond(i);bond;bond = atom->NextBond(i))
1909     if (bond->IsKDouble())
1910     count++;
1911    
1912     return(count);
1913     }
1914    
1915     static bool KekulePropagate(OBAtom *atom,vector<int> &visit,vector<int> &ival,int depth)
1916     {
1917     int count = 0;
1918     OBBond *bond;
1919     vector<OBEdgeBase*>::iterator i;
1920     for (bond = atom->BeginBond(i);bond;bond = atom->NextBond(i))
1921     if (!visit[bond->GetIdx()])
1922     count++;
1923    
1924     if (!count)
1925     return(ValenceSum(atom) == ival[atom->GetIdx()]);
1926    
1927     bool result = true;
1928     OBAtom *nbr;
1929    
1930     if (ValenceSum(atom) >= ival[atom->GetIdx()])
1931     {
1932     for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i))
1933     if (nbr->IsAromatic() && !visit[(*i)->GetIdx()])
1934     {
1935     visit[(*i)->GetIdx()] = depth;
1936     ((OBBond*)*i)->SetKSingle();
1937     result = KekulePropagate(nbr,visit,ival,depth);
1938     if (result)
1939     break;
1940     // if (!result) break;
1941     }
1942     }
1943     else if (count == 1)
1944     for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i))
1945     if (nbr->IsAromatic() && !visit[(*i)->GetIdx()])
1946     {
1947     visit[(*i)->GetIdx()] = depth;
1948     ((OBBond*)*i)->SetKDouble();
1949     result = KekulePropagate(nbr,visit,ival,depth);
1950     //break;
1951     if (result)
1952     break;
1953     }
1954     return(result);
1955     }
1956    
1957     int GetCurrentValence(OBAtom *atom)
1958     {
1959     int count = atom->GetImplicitValence();
1960    
1961     OBBond *bond;
1962     vector<OBEdgeBase*>::iterator i;
1963     for (bond = atom->BeginBond(i);bond;bond = atom->NextBond(i))
1964     {
1965     if (bond->IsKDouble())
1966     count++;
1967     else if (bond->IsKTriple())
1968     count += 2;
1969     // else if (bond->IsSingle()) count++;
1970     // else if (bond->IsDouble()) count += 2;
1971     // else if (bond->IsTriple()) count += 3;
1972     }
1973     return(count);
1974     }
1975    
1976     bool ExpandKekule(OBMol &mol, vector<OBNodeBase*> &va,
1977     vector<OBNodeBase*>::iterator i,
1978     vector<int> &maxv,bool secondpass)
1979     {
1980     if (i == va.end())
1981     {
1982     //check to see that the ideal valence has been achieved for all atoms
1983     vector<OBNodeBase*>::iterator j;
1984     for (j = va.begin();j != va.end();j++)
1985     {
1986     //let erroneously aromatic carboxylates pass
1987     if (((OBAtom*)*j)->IsOxygen() && ((OBAtom*)*j)->GetValence() == 1)
1988     continue;
1989     if (GetCurrentValence((OBAtom*)*j) != maxv[(*j)->GetIdx()])
1990     {
1991     // cout << " ExpandKekule atom: " << ((OBAtom*)*j)->GetIdx()
1992     // << " valence is " << (GetCurrentValence((OBAtom*)*j))
1993     // << " should be " << maxv[(*j)->GetIdx()] << endl;
1994     return(false);
1995     }
1996     }
1997     return(true);
1998     }
1999    
2000     //jump to next atom in list if current atom doesn't have any attached
2001     //aromatic bonds
2002     OBBond *bond;
2003     OBAtom *atom = (OBAtom*)*i;
2004     vector<OBEdgeBase*>::iterator j;
2005     bool done = true;
2006     for (bond = atom->BeginBond(j);bond;bond = atom->NextBond(j))
2007     if (bond->GetBO() == 5)
2008     {
2009     done = false;
2010     break;
2011     }
2012     if (done)
2013     return(ExpandKekule(mol,va,i+1,maxv,secondpass));
2014    
2015     //store list of attached aromatic atoms
2016     OBAtom *nbr;
2017     vector<OBEdgeBase*> vb;
2018     for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
2019     if ((*j)->GetBO() == 5)
2020     {
2021     vb.push_back(*j);
2022     ((OBBond *)*j)->SetBO(1);
2023     ((OBBond *)*j)->SetKSingle();
2024     }
2025    
2026     //try setting a double bond
2027     if (GetCurrentValence(atom) < maxv[atom->GetIdx()])
2028     {
2029     for (j = vb.begin();j != vb.end();j++)
2030     {
2031     nbr = ((OBBond *)*j)->GetNbrAtom(atom);
2032     if (GetCurrentValence(nbr) <= maxv[nbr->GetIdx()])
2033     {
2034     ((OBBond*)*j)->SetKDouble();
2035     ((OBBond*)*j)->SetBO(2);
2036     if (ExpandKekule(mol,va,i+1,maxv,secondpass))
2037     return(true);
2038     ((OBBond*)*j)->SetKSingle();
2039     ((OBBond*)*j)->SetBO(1);
2040     }
2041     }
2042    
2043     if (secondpass && atom->IsNitrogen() && atom->GetFormalCharge() == 0 &&
2044     atom->GetImplicitValence() == 2)
2045     {
2046     atom->IncrementImplicitValence();
2047     if (ExpandKekule(mol,va,i+1,maxv,secondpass))
2048     return(true);
2049     atom->DecrementImplicitValence();
2050     }
2051     }
2052     else //full valence - no double bond to set
2053     {
2054     if (ExpandKekule(mol,va,i+1,maxv,secondpass))
2055     return(true);
2056    
2057     bool trycharge = false;
2058     if (secondpass && atom->GetFormalCharge() == 0)
2059     {
2060     if (atom->IsNitrogen() && atom->GetHvyValence() == 3)
2061     trycharge = true;
2062     if (atom->IsOxygen() && atom->GetHvyValence() == 2)
2063     trycharge = true;
2064     if (atom->IsSulfur() && atom->GetHvyValence() == 2)
2065     trycharge = true;
2066     }
2067    
2068     if (trycharge) //attempt to charge up O,N,S to make a valid kekule form
2069     {
2070     maxv[atom->GetIdx()]++;
2071     atom->SetFormalCharge(1);
2072     for (j = vb.begin();j != vb.end();j++)
2073     {
2074     nbr = ((OBBond*)*j)->GetNbrAtom(atom);
2075     if (GetCurrentValence(nbr) <= maxv[nbr->GetIdx()])
2076     {
2077     ((OBBond*)*j)->SetKDouble();
2078     ((OBBond*)*j)->SetBO(2);
2079     if (ExpandKekule(mol,va,i+1,maxv,secondpass))
2080     return(true);
2081     ((OBBond*)*j)->SetKSingle();
2082     ((OBBond*)*j)->SetBO(1);
2083     }
2084     }
2085     maxv[atom->GetIdx()]--;
2086     atom->SetFormalCharge(0);
2087     }
2088    
2089     if (secondpass && atom->IsNitrogen() && atom->GetFormalCharge() == 0 &&
2090     atom->GetImplicitValence() == 2) //try protonating the nitrogen
2091     {
2092     atom->IncrementImplicitValence();
2093     if (ExpandKekule(mol,va,i+1,maxv,secondpass))
2094     return(true);
2095     atom->DecrementImplicitValence();
2096     }
2097     }
2098    
2099     //failed to find a valid solution - reset attached bonds
2100     for (j = vb.begin();j != vb.end();j++)
2101     {
2102     ((OBBond*)*j)->SetKSingle();
2103     ((OBBond*)*j)->SetBO(5);
2104     }
2105    
2106     return(false);
2107     }
2108    
2109     void CorrectBadResonanceForm(OBMol &mol)
2110     {
2111     string s;
2112     OBBond *b1,*b2,*b3;
2113     OBAtom *a1,*a2,*a3,*a4;
2114     vector<vector<int> > mlist;
2115     vector<vector<int> >::iterator i;
2116    
2117 tim 2518 obErrorLog.ThrowError(__func__,
2118 tim 2440 "Ran OpenBabel::CorrectBadResonanceForm", obAuditMsg);
2119    
2120     OBSmartsPattern acid;
2121     acid.Init("[oD1]c[oD1]");
2122    
2123     //carboxylic acid
2124     if (acid.Match(mol))
2125     {
2126     mlist = acid.GetUMapList();
2127     for (i = mlist.begin();i != mlist.end();i++)
2128     {
2129     a1 = mol.GetAtom((*i)[0]);
2130     a2 = mol.GetAtom((*i)[1]);
2131     a3 = mol.GetAtom((*i)[2]);
2132     b1 = a2->GetBond(a1);
2133     b2 = a2->GetBond(a3);
2134     if (!b1 || !b2)
2135     continue;
2136     b1->SetKDouble();
2137     b2->SetKSingle();
2138     }
2139     }
2140    
2141     //phosphonic acid
2142     OBSmartsPattern phosphate;
2143     phosphate.Init("[p]([oD1])([oD1])([oD1])[#6,#8]");
2144     if (phosphate.Match(mol))
2145     {
2146     mlist = phosphate.GetUMapList();
2147     for (i = mlist.begin();i != mlist.end();i++)
2148     {
2149     a1 = mol.GetAtom((*i)[0]);
2150     a2 = mol.GetAtom((*i)[1]);
2151     a3 = mol.GetAtom((*i)[2]);
2152     a4 = mol.GetAtom((*i)[3]);
2153     b1 = a1->GetBond(a2);
2154     b2 = a1->GetBond(a3);
2155     b3 = a1->GetBond(a4);
2156    
2157     if (!b1 || !b2 || !b3)
2158     continue;
2159     b1->SetKDouble();
2160     b2->SetKSingle();
2161     b3->SetKSingle();
2162     }
2163     }
2164    
2165     //amidene and guanidine
2166     OBSmartsPattern amidene;
2167     amidene.Init("[nD1]c([nD1])*");
2168     if (amidene.Match(mol))
2169     {
2170     mlist = amidene.GetUMapList();
2171     for (i = mlist.begin();i != mlist.end();i++)
2172     {
2173     a1 = mol.GetAtom((*i)[0]);
2174     a2 = mol.GetAtom((*i)[1]);
2175     a3 = mol.GetAtom((*i)[2]);
2176     b1 = a2->GetBond(a1);
2177     b2 = a2->GetBond(a3);
2178     if (!b1 || !b2)
2179     continue;
2180     b1->SetKDouble();
2181     b2->SetKSingle();
2182     }
2183     }
2184     }
2185    
2186     bool OBMol::PerceiveKekuleBonds()
2187     {
2188     if (HasKekulePerceived())
2189     return(true);
2190     SetKekulePerceived();
2191    
2192     OBBond *bond;
2193     vector<OBEdgeBase*>::iterator i;
2194    
2195     //initialize kekule bonds
2196     bool done = true;
2197     bool badResonanceForm = false;
2198     vector<bool> varo;
2199     varo.resize(NumAtoms()+1,false);
2200     for (bond = BeginBond(i);bond;bond = NextBond(i))
2201     switch (bond->GetBO())
2202     {
2203     case 2:
2204     bond->SetKDouble();
2205     break;
2206     case 3:
2207     bond->SetKTriple();
2208     break;
2209     case 5:
2210    
2211     bond->SetKSingle();
2212     if (bond->IsInRing())
2213     {
2214     varo[bond->GetBeginAtomIdx()] = true;
2215     varo[bond->GetEndAtomIdx()] = true;
2216     done = false;
2217     }
2218     else
2219     badResonanceForm = true;
2220    
2221     break;
2222    
2223     default:
2224     bond->SetKSingle();
2225     break;
2226     }
2227    
2228     if (badResonanceForm)
2229     CorrectBadResonanceForm(*this);
2230    
2231     if (done)
2232     return(true);
2233    
2234     //set the maximum valence for each aromatic atom
2235     OBAtom *atom,*nbr;
2236     vector<OBNodeBase*>::iterator j,k;
2237     vector<int> maxv;
2238     maxv.resize(NumAtoms()+1);
2239    
2240     for (atom = BeginAtom(j);atom;atom = NextAtom(j))
2241     if (varo[atom->GetIdx()])
2242     {
2243     switch (atom->GetAtomicNum())
2244     {
2245     case 6:
2246     maxv[atom->GetIdx()] = 4;
2247     break;
2248     case 8:
2249     case 16:
2250     case 34:
2251     case 52:
2252     maxv[atom->GetIdx()] = 2;
2253     break;
2254     case 7:
2255     case 15:
2256     case 33:
2257     maxv[atom->GetIdx()] = 3;
2258     break;
2259     }
2260     //correct valence for formal charges
2261     if (atom->IsCarbon())
2262     maxv[atom->GetIdx()] -= abs(atom->GetFormalCharge());
2263     else
2264     maxv[atom->GetIdx()] += atom->GetFormalCharge();
2265    
2266     if (atom->IsNitrogen() || atom->IsSulfur())
2267     for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i))
2268     if (nbr->IsOxygen() && (*i)->GetBO() == 2)
2269     maxv[atom->GetIdx()] += 2;
2270     }
2271    
2272     bool result = true;
2273     vector<bool> used;
2274     used.resize(NumAtoms()+1);
2275     vector<OBNodeBase*> va,curr,next;
2276     for (atom = BeginAtom(j);atom;atom = NextAtom(j))
2277     if (varo[atom->GetIdx()] && !used[atom->GetIdx()])
2278     {
2279     va.clear();
2280     va.push_back(atom);
2281     curr.clear();
2282     curr.push_back(atom);
2283     used[atom->GetIdx()] = true;
2284    
2285     for (;!curr.empty();)
2286     {
2287     next.clear();
2288     for (k = curr.begin();k != curr.end();k++)
2289     for (nbr = ((OBAtom*)*k)->BeginNbrAtom(i);nbr;nbr = ((OBAtom*)*k)->NextNbrAtom(i))
2290     if (varo[nbr->GetIdx()] && !used[nbr->GetIdx()])
2291     {
2292     used[nbr->GetIdx()] = true;
2293     next.push_back(nbr);
2294     va.push_back(nbr);
2295     }
2296     curr = next;
2297     }
2298    
2299     //try it first without protonating aromatic nitrogens
2300     if (!ExpandKekule(*this,va,va.begin(),maxv,false) &&
2301     !ExpandKekule(*this,va,va.begin(),maxv,true))
2302     {
2303     result = false;
2304     // cerr << " Died on atom " << atom->GetIdx() << endl;
2305     }
2306     }
2307    
2308     if (!result)
2309     {
2310     // cerr << "Kekulization Error = " << GetTitle() << endl;
2311     //exit(0);
2312     }
2313    
2314     return(result);
2315     }
2316    
2317     bool OBMol::Kekulize()
2318     {
2319     OBBond *bond;
2320     vector<OBEdgeBase*>::iterator i;
2321     // Not quite sure why this is here -GRH 2003
2322     // if (NumAtoms() > 255) return(false);
2323    
2324 tim 2518 obErrorLog.ThrowError(__func__,
2325 tim 2440 "Ran OpenBabel::Kekulize", obAuditMsg);
2326    
2327     for (bond = BeginBond(i);bond;bond = NextBond(i))
2328     if (bond->IsKSingle())
2329     bond->SetBO(1);
2330     else if (bond->IsKDouble())
2331     bond->SetBO(2);
2332     else if (bond->IsKTriple())
2333     bond->SetBO(3);
2334    
2335     return(true);
2336     }
2337    
2338     bool OBMol::DeleteAtom(OBAtom *atom)
2339     {
2340     if (atom->IsHydrogen())
2341     return(DeleteHydrogen(atom));
2342    
2343     BeginModify();
2344     //don't need to do anything with coordinates b/c
2345     //BeginModify() blows away coordinates
2346    
2347     //find bonds to delete
2348     OBAtom *nbr;
2349     vector<OBEdgeBase*> vdb;
2350     vector<OBEdgeBase*>::iterator j;
2351     for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
2352     vdb.push_back(*j);
2353    
2354     for (j = vdb.begin();j != vdb.end();j++)
2355     DeleteBond((OBBond *)*j); //delete bonds
2356    
2357     _vatom.erase(_vatom.begin()+(atom->GetIdx()-1));
2358     DestroyAtom(atom);
2359     _natoms--;
2360    
2361     //reset all the indices to the atoms
2362     int idx;
2363     vector<OBNodeBase*>::iterator i;
2364     for (idx=1,atom = BeginAtom(i);atom;atom = NextAtom(i),idx++)
2365     atom->SetIdx(idx);
2366    
2367     EndModify();
2368    
2369     return(true);
2370     }
2371    
2372     bool OBMol::DeleteResidue(OBResidue *residue)
2373     {
2374     unsigned short idx = residue->GetIdx();
2375     for ( unsigned short i = idx ; i < _residue.size() ; i++ )
2376     _residue[i]->SetIdx(i-1);
2377    
2378     _residue.erase(_residue.begin() + idx);
2379    
2380     if (residue)
2381     {
2382     delete residue;
2383     residue = NULL;
2384     }
2385    
2386     return(true);
2387     }
2388    
2389     bool OBMol::AddBond(int first,int second,int order,int stereo,int insertpos)
2390     {
2391     BeginModify();
2392    
2393     if ((unsigned)first <= NumAtoms() && (unsigned)second <= NumAtoms()
2394     && !GetBond(first, second))
2395     //atoms exist and bond doesn't
2396     {
2397     OBBond *bond = CreateBond();
2398     if (!bond)
2399     {
2400     EndModify();
2401     return(false);
2402     }
2403    
2404     OBAtom *bgn,*end;
2405     bgn = GetAtom(first);
2406     end = GetAtom(second);
2407     if (!bgn || !end)
2408     {
2409 tim 2518 obErrorLog.ThrowError(__func__, "Unable to add bond - invalid atom index", obDebug);
2410 tim 2440 return(false);
2411     }
2412     bond->Set(_nbonds,bgn,end,order,stereo);
2413     bond->SetParent(this);
2414    
2415     //set aromatic flags if it has the appropriate order
2416     if (order == 5)
2417     {
2418     bond->SetAromatic();
2419     bgn->SetAromatic();
2420     end->SetAromatic();
2421     }
2422    
2423     #define OBBondIncrement 100
2424     if (_vbond.empty() || _nbonds+1 >= (signed)_vbond.size())
2425     {
2426     _vbond.resize(_nbonds+OBBondIncrement);
2427     vector<OBEdgeBase*>::iterator i;
2428     for (i = _vbond.begin(),i+=(_nbonds+1);i != _vbond.end();i++)
2429     *i = (OBEdgeBase*)NULL;
2430     }
2431     #undef OBBondIncrement
2432    
2433     _vbond[_nbonds] = (OBEdgeBase*)bond;
2434     _nbonds++;
2435    
2436     if (insertpos == -1)
2437     {
2438     bgn->AddBond(bond);
2439     end->AddBond(bond);
2440     }
2441     else
2442     {
2443     if (insertpos >= static_cast<int>(bgn->GetValence())
2444     ) bgn->AddBond(bond);
2445     else //need to insert the bond for the connectivity order to be preserved
2446     { //otherwise stereochemistry gets screwed up
2447     vector<OBEdgeBase*>::iterator bi;
2448     bgn->BeginNbrAtom(bi);
2449     bi += insertpos;
2450     bgn->InsertBond(bi,bond);
2451     }
2452     end->AddBond(bond);
2453     }
2454     }
2455     else //at least one atom doesn't exist yet - add to bond_q
2456     SetData(new OBVirtualBond(first,second,order,stereo));
2457    
2458     EndModify();
2459     return(true);
2460     }
2461    
2462     bool OBMol::AddBond(OBBond &bond)
2463     {
2464     return(AddBond(bond.GetBeginAtomIdx(),
2465     bond.GetEndAtomIdx(),
2466     bond.GetBO(),
2467     bond.GetFlags()));
2468     }
2469    
2470     bool OBMol::DeleteBond(OBBond *bond)
2471     {
2472     BeginModify();
2473    
2474     (bond->GetBeginAtom())->DeleteBond(bond);
2475     (bond->GetEndAtom())->DeleteBond(bond);
2476     _vbond.erase(_vbond.begin() + bond->GetIdx());
2477    
2478     DestroyBond(bond);
2479    
2480     vector<OBEdgeBase*>::iterator i;
2481     int j;
2482     for (bond = BeginBond(i),j=0;bond;bond = NextBond(i),j++)
2483     bond->SetIdx(j);
2484    
2485     _nbonds--;
2486     EndModify();
2487     return(true);
2488     }
2489    
2490     void OBMol::Align(OBAtom *a1,OBAtom *a2,vector3 &p1,vector3 &p2)
2491     {
2492     vector<int> children;
2493    
2494 tim 2518 obErrorLog.ThrowError(__func__,
2495 tim 2440 "Ran OpenBabel::Align", obAuditMsg);
2496    
2497     //find which atoms to rotate
2498     FindChildren(children,a1->GetIdx(),a2->GetIdx());
2499     children.push_back(a2->GetIdx());
2500    
2501     //find the rotation vector and angle
2502     vector3 v1,v2,v3;
2503     v1 = p2 - p1;
2504     v2 = a2->GetVector() - a1->GetVector();
2505     v3 = cross(v1,v2);
2506     double angle = vectorAngle(v1,v2);
2507    
2508     //find the rotation matrix
2509     matrix3x3 m;
2510     m.RotAboutAxisByAngle(v3,angle);
2511    
2512     //rotate atoms
2513     vector3 v;
2514     OBAtom *atom;
2515     vector<int>::iterator i;
2516     for (i = children.begin();i != children.end();i++)
2517     {
2518     atom = GetAtom(*i);
2519     v = atom->GetVector();
2520     v -= a1->GetVector();
2521     v *= m; //rotate the point
2522     v += p1; //translate the vector
2523     atom->SetVector(v);
2524     }
2525     //set a1 = p1
2526     a1->SetVector(p1);
2527     }
2528    
2529     void OBMol::ToInertialFrame()
2530     {
2531     double m[9];
2532     for (int i = 0;i < NumConformers();i++)
2533     ToInertialFrame(i,m);
2534     }
2535    
2536     void OBMol::ToInertialFrame(int conf,double *rmat)
2537     {
2538     unsigned int i;
2539     double x,y,z;
2540     double mi;
2541     double mass = 0.0;
2542     double center[3],m[3][3];
2543    
2544 tim 2518 obErrorLog.ThrowError(__func__,
2545 tim 2440 "Ran OpenBabel::ToInertialFrame", obAuditMsg);
2546    
2547     for (i = 0;i < 3;i++)
2548     memset(&m[i],'\0',sizeof(double)*3);
2549     memset(center,'\0',sizeof(double)*3);
2550    
2551     SetConformer(conf);
2552     OBAtom *atom;
2553     vector<OBNodeBase*>::iterator j;
2554     //find center of mass
2555     for (atom = BeginAtom(j);atom;atom = NextAtom(j))
2556     {
2557     mi = atom->GetAtomicMass();
2558     center[0] += mi*atom->x();
2559     center[1] += mi*atom->y();
2560     center[2] += mi*atom->z();
2561     mass += mi;
2562     }
2563    
2564     center[0] /= mass;
2565     center[1] /= mass;
2566     center[2] /= mass;
2567    
2568     //calculate inertial tensor
2569     for (atom = BeginAtom(j);atom;atom = NextAtom(j))
2570     {
2571     x = atom->x()-center[0];
2572     y = atom->y()-center[1];
2573     z = atom->z()-center[2];
2574     mi = atom->GetAtomicMass();
2575    
2576     m[0][0] += mi*(y*y+z*z);
2577     m[0][1] -= mi*x*y;
2578     m[0][2] -= mi*x*z;
2579     m[1][0] -= mi*x*y;
2580     m[1][1] += mi*(x*x+z*z);
2581     m[1][2] -= mi*y*z;
2582     m[2][0] -= mi*x*z;
2583     m[2][1] -= mi*y*z;
2584     m[2][2] += mi*(x*x+y*y);
2585     }
2586    
2587     /* find rotation matrix for moment of inertia */
2588     ob_make_rmat(m,rmat);
2589    
2590     /* rotate all coordinates */
2591     double *c = GetConformer(conf);
2592     for(i=0; i < NumAtoms();i++)
2593     {
2594     x = c[i*3]-center[0];
2595     y = c[i*3+1]-center[1];
2596     z = c[i*3+2]-center[2];
2597     c[i*3] = x*rmat[0] + y*rmat[1] + z*rmat[2];
2598     c[i*3+1] = x*rmat[3] + y*rmat[4] + z*rmat[5];
2599     c[i*3+2] = x*rmat[6] + y*rmat[7] + z*rmat[8];
2600     }
2601     }
2602    
2603     /*NF
2604     istream& operator>> (istream &ifs, OBMol &mol)
2605     {
2606     bool retcode = OBFileFormat::ReadMolecule(ifs, mol);
2607    
2608     if (!retcode)
2609     {
2610     if (mol.GetMod())
2611     mol.EndModify();
2612     mol.Clear();
2613     }
2614    
2615     return(ifs);
2616     }
2617    
2618     ostream& operator<< (ostream &ofs, OBMol &mol)
2619     {
2620     OBFileFormat::WriteMolecule(ofs, mol);
2621     return(ofs);
2622     }
2623     */
2624    
2625     OBMol::OBMol()
2626     {
2627     _natoms = _nbonds = 0;
2628     _mod = 0;
2629     _energy = 0.0;
2630     _totalCharge = 0;
2631     _dimension = 3;
2632     _vatom.clear();
2633     _vbond.clear();
2634     _vdata.clear();
2635     _title = "";
2636     _c = (double*)NULL;
2637     _flags = 0;
2638     _vconf.clear();
2639     _autoPartialCharge = true;
2640     _autoFormalCharge = true;
2641     }
2642    
2643     OBMol::OBMol(const OBMol &mol) :
2644     OBGraphBase()
2645     {
2646     _natoms = _nbonds = 0;
2647     _mod = 0;
2648     _totalCharge = 0;
2649     _vatom.clear();
2650     _vbond.clear();
2651     _vdata.clear();
2652     _title = "";
2653     _c = (double*)NULL;
2654     _flags = 0;
2655     _vconf.clear();
2656     _autoPartialCharge = true;
2657     _autoFormalCharge = true;
2658     //NF _compressed = false;
2659     *this = mol;
2660     }
2661    
2662     OBMol::~OBMol()
2663     {
2664     OBAtom *atom;
2665     OBBond *bond;
2666     OBResidue *residue;
2667     vector<OBNodeBase*>::iterator i;
2668     vector<OBEdgeBase*>::iterator j;
2669     vector<OBResidue*>::iterator r;
2670     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
2671     DestroyAtom(atom);
2672     for (bond = BeginBond(j);bond;bond = NextBond(j))
2673     DestroyBond(bond);
2674     for (residue = BeginResidue(r);residue;residue = NextResidue(r))
2675     delete residue;
2676    
2677     //clear out the multiconformer data
2678     vector<double*>::iterator k;
2679     for (k = _vconf.begin();k != _vconf.end();k++)
2680     delete [] *k;
2681     _vconf.clear();
2682    
2683     if (!_vdata.empty())
2684     {
2685     vector<OBGenericData*>::iterator m;
2686     for (m = _vdata.begin();m != _vdata.end();m++)
2687     delete *m;
2688     _vdata.clear();
2689     }
2690     }
2691    
2692     bool OBMol::HasData(string &s)
2693     {
2694     if (_vdata.empty())
2695     return(false);
2696    
2697     vector<OBGenericData*>::iterator i;
2698    
2699     for (i = _vdata.begin();i != _vdata.end();i++)
2700     if ((*i)->GetAttribute() == s)
2701     return(true);
2702    
2703     return(false);
2704     }
2705    
2706     bool OBMol::HasData(const char *s)
2707     //returns true if the generic attribute/value pair exists
2708     {
2709     if (_vdata.empty())
2710     return(false);
2711    
2712     vector<OBGenericData*>::iterator i;
2713    
2714     for (i = _vdata.begin();i != _vdata.end();i++)
2715     if ((*i)->GetAttribute() == s)
2716     return(true);
2717    
2718     return(false);
2719     }
2720    
2721    
2722     bool OBMol::HasData(unsigned int dt)
2723     //returns true if the generic attribute/value pair exists
2724     {
2725     if (_vdata.empty())
2726     return(false);
2727    
2728     vector<OBGenericData*>::iterator i;
2729    
2730     for (i = _vdata.begin();i != _vdata.end();i++)
2731     if ((*i)->GetDataType() == dt)
2732     return(true);
2733    
2734     return(false);
2735     }
2736    
2737     //! Returns the value given an attribute name
2738     OBGenericData *OBMol::GetData(string &s)
2739     {
2740     vector<OBGenericData*>::iterator i;
2741    
2742     for (i = _vdata.begin();i != _vdata.end();i++)
2743     if ((*i)->GetAttribute() == s)
2744     return(*i);
2745    
2746     return(NULL);
2747     }
2748    
2749     //! Returns the value given an attribute name
2750     OBGenericData *OBMol::GetData(const char *s)
2751     {
2752     vector<OBGenericData*>::iterator i;
2753    
2754     for (i = _vdata.begin();i != _vdata.end();i++)
2755     if ((*i)->GetAttribute() == s)
2756     return(*i);
2757    
2758     return(NULL);
2759     }
2760    
2761     OBGenericData *OBMol::GetData(unsigned int dt)
2762     {
2763     vector<OBGenericData*>::iterator i;
2764     for (i = _vdata.begin();i != _vdata.end();i++)
2765     if ((*i)->GetDataType() == dt)
2766     return(*i);
2767     return(NULL);
2768     }
2769    
2770     void OBMol::DeleteData(unsigned int dt)
2771     {
2772     vector<OBGenericData*> vdata;
2773     vector<OBGenericData*>::iterator i;
2774     for (i = _vdata.begin();i != _vdata.end();i++)
2775     if ((*i)->GetDataType() == dt)
2776     delete *i;
2777     else
2778     vdata.push_back(*i);
2779     _vdata = vdata;
2780     }
2781    
2782     void OBMol::DeleteData(vector<OBGenericData*> &vg)
2783     {
2784     vector<OBGenericData*> vdata;
2785     vector<OBGenericData*>::iterator i,j;
2786    
2787     bool del;
2788     for (i = _vdata.begin();i != _vdata.end();i++)
2789     {
2790     del = false;
2791     for (j = vg.begin();j != vg.end();j++)
2792     if (*i == *j)
2793     {
2794     del = true;
2795     break;
2796     }
2797     if (del)
2798     delete *i;
2799     else
2800     vdata.push_back(*i);
2801     }
2802     _vdata = vdata;
2803     }
2804    
2805     void OBMol::DeleteData(OBGenericData *gd)
2806     {
2807     vector<OBGenericData*>::iterator i;
2808     for (i = _vdata.begin();i != _vdata.end();i++)
2809     if (*i == gd)
2810     {
2811     delete *i;
2812     _vdata.erase(i);
2813     }
2814    
2815     }
2816    
2817     bool OBMol::HasNonZeroCoords()
2818     {
2819     OBAtom *atom;
2820     vector<OBNodeBase*>::iterator i;
2821    
2822     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
2823     if (atom->GetVector() != VZero)
2824     return(true);
2825    
2826     return(false);
2827     }
2828    
2829     bool OBMol::Has2D()
2830     {
2831     bool hasX,hasY;
2832     OBAtom *atom;
2833     vector<OBNodeBase*>::iterator i;
2834    
2835     hasX = hasY = false;
2836     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
2837     {
2838     if (!hasX && !IsNearZero(atom->x()))
2839     hasX = true;
2840     if (!hasY && !IsNearZero(atom->y()))
2841     hasY = true;
2842    
2843     if (hasX && hasY)
2844     return(true);
2845     }
2846     return(false);
2847     }
2848    
2849     bool OBMol::Has3D()
2850     {
2851     bool hasX,hasY,hasZ;
2852     OBAtom *atom;
2853     vector<OBNodeBase*>::iterator i;
2854    
2855     hasX = hasY = hasZ = false;
2856     if (this->_c == NULL)
2857     return(false);
2858     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
2859     {
2860     if (!hasX && !IsNearZero(atom->x()))
2861     hasX = true;
2862     if (!hasY && !IsNearZero(atom->y()))
2863     hasY = true;
2864     if (!hasZ && !IsNearZero(atom->z()))
2865     hasZ = true;
2866    
2867     if (hasX && hasY && hasZ)
2868     return(true);
2869     }
2870     return(false);
2871     }
2872    
2873     bool OBMol::IsChiral()
2874     {
2875     OBAtom *atom;
2876     vector<OBNodeBase*>::iterator i;
2877    
2878     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
2879     if ((atom->IsCarbon() || atom->IsNitrogen()) && atom->GetHvyValence() > 2 && atom->IsChiral())
2880     return(true);
2881    
2882     return(false);
2883     }
2884    
2885     //! Renumber the atoms in this molecule according to the order in the supplied
2886     //! vector. This will return without action if the supplied vector is empty or
2887     //! does not have the same number of atoms as the molecule.
2888     void OBMol::RenumberAtoms(vector<OBNodeBase*> &v)
2889     {
2890     if (Empty())
2891     return;
2892    
2893 tim 2518 obErrorLog.ThrowError(__func__,
2894 tim 2440 "Ran OpenBabel::RenumberAtoms", obAuditMsg);
2895    
2896     OBAtom *atom;
2897     vector<OBNodeBase*> va;
2898     vector<OBNodeBase*>::iterator i;
2899    
2900     va = v;
2901    
2902     //make sure all atoms are represented in the vector
2903     if (va.empty() || va.size() != NumAtoms())
2904     return;
2905    
2906     OBBitVec bv;
2907     for (i = va.begin();i != va.end();i++)
2908     bv |= (*i)->GetIdx();
2909    
2910     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
2911     if (!bv[atom->GetIdx()])
2912     va.push_back(atom);
2913    
2914     int j,k;
2915     double *c;
2916     double *ctmp = new double [NumAtoms()*3];
2917    
2918     for (j = 0;j < NumConformers();j++)
2919     {
2920     c = GetConformer(j);
2921     for (k=0,i = va.begin();i != va.end();i++,k++)
2922     memcpy((char*)&ctmp[k*3],(char*)&c[((OBAtom*)*i)->GetCIdx()],sizeof(double)*3);
2923     memcpy((char*)c,(char*)ctmp,sizeof(double)*3*NumAtoms());
2924     }
2925    
2926     for (k=1,i = va.begin();i != va.end();i++,k++)
2927     (*i)->SetIdx(k);
2928    
2929     delete [] ctmp;
2930    
2931     _vatom.clear();
2932     for (i = va.begin();i != va.end();i++)
2933     _vatom.push_back(*i);
2934     }
2935    
2936     #ifdef REMOVE_LATER
2937     bool CompareBonds(const OBEdgeBase *a,const OBEdgeBase *b)
2938     {
2939     if (a->GetBgn()->GetIdx() == b->GetBgn()->GetIdx())
2940     return(a->GetEnd()->GetIdx() < b->GetEnd()->GetIdx());
2941    
2942     //return((a->GetBgn())->GetIdx() < (b->GetBgn())->GetIdx());
2943     }
2944     #endif
2945    
2946     bool WriteTitles(ostream &ofs, OBMol &mol)
2947     {
2948     ofs << mol.GetTitle() << endl;
2949     return true;
2950     }
2951    
2952     /*! This method adds single bonds between all atoms
2953     closer than their combined atomic covalent radii,
2954     then "cleans up" making sure bonded atoms are not
2955     closer than 0.4A and the atom does not exceed its valence.
2956     It implements blue-obelisk:rebondFrom3DCoordinates.
2957    
2958     */
2959     void OBMol::ConnectTheDots(void)
2960     {
2961     if (Empty())
2962     return;
2963     if (_dimension != 3) return; // not useful on non-3D structures
2964    
2965 tim 2518 obErrorLog.ThrowError(__func__,
2966 tim 2440 "Ran OpenBabel::ConnectTheDots", obAuditMsg);
2967    
2968     int j,k,max;
2969     bool unset = false;
2970     OBAtom *atom,*nbr;
2971     vector<OBNodeBase*>::iterator i;
2972     vector<pair<OBAtom*,double> > zsortedAtoms;
2973     vector<double> rad;
2974     vector<int> zsorted;
2975    
2976     double *c = new double [NumAtoms()*3];
2977     rad.resize(_natoms);
2978    
2979     for (j = 0, atom = BeginAtom(i) ; atom ; atom = NextAtom(i), j++)
2980     {
2981     (atom->GetVector()).Get(&c[j*3]);
2982     pair<OBAtom*,double> entry(atom, atom->GetVector().z());
2983     zsortedAtoms.push_back(entry);
2984     }
2985     sort(zsortedAtoms.begin(), zsortedAtoms.end(), SortAtomZ);
2986    
2987     max = zsortedAtoms.size();
2988    
2989     for ( j = 0 ; j < max ; j++ )
2990     {
2991     atom = zsortedAtoms[j].first;
2992     rad[j] = etab.GetCovalentRad(atom->GetAtomicNum());
2993     zsorted.push_back(atom->GetIdx()-1);
2994     }
2995    
2996     int idx1, idx2;
2997     double d2,cutoff,zd;
2998     for (j = 0 ; j < max ; j++)
2999     {
3000     idx1 = zsorted[j];
3001     for (k = j + 1 ; k < max ; k++ )
3002     {
3003     idx2 = zsorted[k];
3004    
3005     // bonded if closer than elemental Rcov + tolerance
3006     cutoff = SQUARE(rad[j] + rad[k] + 0.45);
3007    
3008     zd = SQUARE(c[idx1*3+2] - c[idx2*3+2]);
3009     if (zd > 25.0 )
3010     break; // bigger than max cutoff
3011    
3012     d2 = SQUARE(c[idx1*3] - c[idx2*3]);
3013     d2 += SQUARE(c[idx1*3+1] - c[idx2*3+1]);
3014     d2 += zd;
3015    
3016     if (d2 > cutoff)
3017     continue;
3018     if (d2 < 0.40)
3019     continue;
3020    
3021     atom = GetAtom(idx1+1);
3022     nbr = GetAtom(idx2+1);
3023    
3024     if (atom->IsConnected(nbr))
3025     continue;
3026     if (atom->IsHydrogen() && nbr->IsHydrogen())
3027     continue;
3028    
3029     AddBond(idx1+1,idx2+1,1);
3030     }
3031     }
3032    
3033     // If between BeginModify and EndModify, coord pointers are NULL
3034     // setup molecule to handle current coordinates
3035    
3036     if (_c == NULL)
3037     {
3038     _c = c;
3039     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
3040     atom->SetCoordPtr(&_c);
3041     _vconf.push_back(c);
3042     unset = true;
3043     }
3044    
3045     // Cleanup -- delete long bonds that exceed max valence
3046     OBBond *maxbond, *bond;
3047     double maxlength;
3048     vector<OBEdgeBase*>::iterator l;
3049     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
3050     {
3051     while (atom->BOSum() > static_cast<unsigned int>(etab.GetMaxBonds(atom->GetAtomicNum()))
3052     || atom->SmallestBondAngle() < 45.0)
3053     {
3054     maxbond = atom->BeginBond(l);
3055     maxlength = maxbond->GetLength();
3056     for (bond = atom->BeginBond(l);bond;bond = atom->NextBond(l))
3057     {
3058     if (bond->GetLength() > maxlength)
3059     {
3060     maxbond = bond;
3061     maxlength = bond->GetLength();
3062     }
3063     }
3064     DeleteBond(maxbond);
3065     }
3066     }
3067    
3068     if (unset)
3069     {
3070     _c = NULL;
3071     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
3072     atom->ClearCoordPtr();
3073     _vconf.resize(_vconf.size()-1);
3074     }
3075    
3076     delete [] c;
3077     }
3078    
3079     /*! This method uses bond angles and geometries from current
3080     connectivity to guess atom types and then filling empty valences
3081     with multiple bonds. It currently has a pass to detect some
3082     frequent functional groups. It still needs a pass to detect aromatic
3083     rings to "clean up." */
3084     void OBMol::PerceiveBondOrders()
3085     {
3086     if (Empty())
3087     return;
3088     if (_dimension != 3) return; // not useful on non-3D structures
3089    
3090 tim 2518 obErrorLog.ThrowError(__func__,
3091 tim 2440 "Ran OpenBabel::PerceiveBondOrders", obAuditMsg);
3092    
3093     OBAtom *atom, *b, *c;
3094     vector3 v1, v2;
3095     double angle;//, dist1, dist2;
3096     vector<OBNodeBase*>::iterator i;
3097     vector<OBEdgeBase*>::iterator j;//,k;
3098    
3099     // BeginModify();
3100    
3101     // Pass 1: Assign estimated hybridization based on avg. angles
3102     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
3103     {
3104     angle = atom->AverageBondAngle();
3105    
3106     if (angle > 155.0)
3107     atom->SetHyb(1);
3108     else if ( angle <= 155.0 && angle > 115)
3109     atom->SetHyb(2);
3110     } // pass 1
3111    
3112     // Make sure upcoming calls to GetHyb() don't kill these temporary values
3113     SetHybridizationPerceived();
3114    
3115     // Pass 2: look for 5-member rings with torsions <= 7.5 degrees
3116     // and 6-member rings with torsions <= 12 degrees
3117     // (set all atoms with at least two bonds to sp2)
3118    
3119     vector<OBRing*> rlist;
3120     vector<OBRing*>::iterator ringit;
3121     vector<int> path;
3122     double torsions = 0.0;
3123    
3124     if (!HasSSSRPerceived())
3125     FindSSSR();
3126     rlist = GetSSSR();
3127     for (ringit = rlist.begin(); ringit != rlist.end(); ringit++)
3128     {
3129     if ((*ringit)->PathSize() == 5)
3130     {
3131     path = (*ringit)->_path;
3132     torsions =
3133     ( fabs(GetTorsion(path[0], path[1], path[2], path[3])) +
3134     fabs(GetTorsion(path[1], path[2], path[3], path[4])) +
3135     fabs(GetTorsion(path[2], path[3], path[4], path[0])) +
3136     fabs(GetTorsion(path[3], path[4], path[0], path[1])) +
3137     fabs(GetTorsion(path[4], path[0], path[1], path[2])) ) / 5.0;
3138     if (torsions <= 7.5)
3139     {
3140     for (unsigned int ringAtom = 0; ringAtom != path.size(); ringAtom++)
3141     {
3142     b = GetAtom(path[ringAtom]);
3143     // if an aromatic ring atom has valence 3, it is already set
3144     // to sp2 because the average angles should be 120 anyway
3145     // so only look for valence 2
3146     if (b->GetValence() == 2)
3147     b->SetHyb(2);
3148     }
3149     }
3150     }
3151     else if ((*ringit)->PathSize() == 6)
3152     {
3153     path = (*ringit)->_path;
3154     torsions =
3155     ( fabs(GetTorsion(path[0], path[1], path[2], path[3])) +
3156     fabs(GetTorsion(path[1], path[2], path[3], path[4])) +
3157     fabs(GetTorsion(path[2], path[3], path[4], path[5])) +
3158     fabs(GetTorsion(path[3], path[4], path[5], path[0])) +
3159     fabs(GetTorsion(path[4], path[5], path[0], path[1])) +
3160     fabs(GetTorsion(path[5], path[0], path[1], path[2])) ) / 6.0;
3161     if (torsions <= 12.0)
3162     {
3163     for (unsigned int ringAtom = 0; ringAtom != path.size(); ringAtom++)
3164     {
3165     b = GetAtom(path[ringAtom]);
3166     if (b->GetValence() == 2 || b->GetValence() == 3)
3167     b->SetHyb(2);
3168     }
3169     }
3170     }
3171     }
3172    
3173     // Pass 3: "Antialiasing" If an atom marked as sp hybrid isn't
3174     // bonded to another or an sp2 hybrid isn't bonded
3175     // to another (or terminal atoms in both cases)
3176     // mark them to a lower hybridization for now
3177     bool openNbr;
3178     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
3179     {
3180     if (atom->GetHyb() == 2 || atom->GetHyb() == 1)
3181     {
3182     openNbr = false;
3183     for (b = atom->BeginNbrAtom(j); b; b = atom->NextNbrAtom(j))
3184     {
3185     if (b->GetHyb() < 3 || b->GetValence() == 1)
3186     {
3187     openNbr = true;
3188     break;
3189     }
3190     }
3191     if (!openNbr && atom->GetHyb() == 2)
3192     atom->SetHyb(3);
3193     else if (!openNbr && atom->GetHyb() == 1)
3194     atom->SetHyb(2);
3195     }
3196     } // pass 3
3197    
3198     // Pass 4: Check for known functional group patterns and assign bonds
3199     // to the canonical form
3200     // Currently we have explicit code to do this, but a "bond typer"
3201     // is in progress to make it simpler to test and debug.
3202     bondtyper.AssignFunctionalGroupBonds(*this);
3203    
3204     // Pass 5: Check for aromatic rings and assign bonds as appropriate
3205     // This is just a quick and dirty approximation that marks everything
3206     // as potentially aromatic
3207    
3208     // This doesn't work perfectly, but it's pretty decent.
3209     // Need to have a list of SMARTS patterns for common rings
3210     // which would "break ties" on complicated multi-ring systems
3211     // (Most of the current problems lie in the interface with the
3212     // Kekulize code anyway, not in marking everything as potentially aromatic)
3213    
3214     bool typed; // has this ring been typed?
3215     unsigned int loop, loopSize;
3216     for (ringit = rlist.begin(); ringit != rlist.end(); ringit++)
3217     {
3218     typed = false;
3219     loopSize = (*ringit)->PathSize();
3220     if (loopSize == 5 || loopSize == 6)
3221     {
3222     path = (*ringit)->_path;
3223     for(loop = 0; loop < loopSize; loop++)
3224     {
3225     atom = GetAtom(path[loop]);
3226     if(atom->HasBondOfOrder(2) || atom->HasBondOfOrder(3)
3227     || atom->GetHyb() != 2)
3228     {
3229     typed = true;
3230     break;
3231     }
3232     }
3233    
3234     if (!typed)
3235     for(loop = 0; loop < loopSize; loop++)
3236     {
3237     // cout << " set aromatic " << path[loop] << endl;
3238     (GetBond(path[loop], path[(loop+1) % loopSize]))->SetBO(5);
3239     (GetBond(path[loop], path[(loop+1) % loopSize]))->UnsetKekule();
3240     }
3241     }
3242     }
3243     _flags &= (~(OB_KEKULE_MOL));
3244     Kekulize();
3245    
3246     // Pass 6: Assign remaining bond types, ordered by atom electronegativity
3247     vector<pair<OBAtom*,double> > sortedAtoms;
3248     vector<double> rad;
3249     vector<int> sorted;
3250     int iter, max;
3251     double maxElNeg, shortestBond, currentElNeg;
3252    
3253     for (atom = BeginAtom(i) ; atom ; atom = NextAtom(i))
3254     {
3255     // if atoms have the same electronegativity, make sure those with shorter bonds
3256     // are handled first (helps with assignment of conjugated single/double bonds)
3257     shortestBond = 1.0e5f;
3258     for (b = atom->BeginNbrAtom(j); b; b = atom->NextNbrAtom(j))
3259     {
3260     if (b->GetAtomicNum()!=1) shortestBond =
3261     min(shortestBond,(atom->GetBond(b))->GetLength());
3262     }
3263     pair<OBAtom*,double> entry(atom,
3264     etab.GetElectroNeg(atom->GetAtomicNum())*1e6+shortestBond);
3265    
3266     sortedAtoms.push_back(entry);
3267     }
3268     sort(sortedAtoms.begin(), sortedAtoms.end(), SortAtomZ);
3269    
3270     max = sortedAtoms.size();
3271    
3272     for (iter = 0 ; iter < max ; iter++ )
3273     {
3274     atom = sortedAtoms[iter].first;
3275     if ( (atom->GetHyb() == 1 || atom->GetValence() == 1)
3276     && atom->BOSum() + 2 <= static_cast<unsigned int>(etab.GetMaxBonds(atom->GetAtomicNum()))
3277     )
3278     {
3279     // loop through the neighbors looking for a hybrid or terminal atom
3280     // (and pick the one with highest electronegativity first)
3281     // *or* pick a neighbor that's a terminal atom
3282    
3283     if (atom->HasNonSingleBond() ||
3284     (atom->GetAtomicNum() == 7 && atom->BOSum() + 2 > 3))
3285     continue;
3286    
3287     maxElNeg = 0.0;
3288     shortestBond = 5000.0;
3289     c = NULL;
3290     for (b = atom->BeginNbrAtom(j); b; b = atom->NextNbrAtom(j))
3291     {
3292     currentElNeg = etab.GetElectroNeg(b->GetAtomicNum());
3293     if ( (b->GetHyb() == 1 || b->GetValence() == 1)
3294     && b->BOSum() + 2 <= static_cast<unsigned int>(etab.GetMaxBonds(b->GetAtomicNum()))
3295     && (currentElNeg > maxElNeg ||
3296     (IsNear(currentElNeg,maxElNeg)
3297     && (atom->GetBond(b))->GetLength() < shortestBond)) )
3298     {
3299     if (b->HasNonSingleBond() ||
3300     (b->GetAtomicNum() == 7 && b->BOSum() + 2 > 3))
3301     continue;
3302    
3303     shortestBond = (atom->GetBond(b))->GetLength();
3304     maxElNeg = etab.GetElectroNeg(b->GetAtomicNum());
3305     c = b; // save this atom for later use
3306     }
3307     }
3308     if (c)
3309     (atom->GetBond(c))->SetBO(3);
3310     }
3311     else if ( (atom->GetHyb() == 2 || atom->GetValence() == 1)
3312     && atom->BOSum() + 1 <= static_cast<unsigned int>(etab.GetMaxBonds(atom->GetAtomicNum())) )
3313     {
3314     // as above
3315     if (atom->HasNonSingleBond() ||
3316     (atom->GetAtomicNum() == 7 && atom->BOSum() + 1 > 3))
3317     continue;
3318    
3319     maxElNeg = 0.0;
3320     shortestBond = 5000.0;
3321     c = NULL;
3322     for (b = atom->BeginNbrAtom(j); b; b = atom->NextNbrAtom(j))
3323     {
3324     currentElNeg = etab.GetElectroNeg(b->GetAtomicNum());
3325     if ( (b->GetHyb() == 2 || b->GetValence() == 1)
3326     && b->BOSum() + 1 <= static_cast<unsigned int>(etab.GetMaxBonds(b->GetAtomicNum()))
3327     && (GetBond(atom, b))->IsDoubleBondGeometry()
3328     && (currentElNeg > maxElNeg ||
3329     (IsNear(currentElNeg,maxElNeg)
3330     // If only the bond length counts, prefer double bonds in the ring
3331     && (((atom->GetBond(b))->GetLength() < shortestBond)
3332     && (!atom->IsInRing() || !c || !c->IsInRing() || b->IsInRing()))
3333     || (atom->IsInRing() && c && !c->IsInRing() && b->IsInRing()))))
3334     {
3335     if (b->HasNonSingleBond() ||
3336     (b->GetAtomicNum() == 7 && b->BOSum() + 1 > 3))
3337     continue;
3338    
3339     shortestBond = (atom->GetBond(b))->GetLength();
3340     maxElNeg = etab.GetElectroNeg(b->GetAtomicNum());
3341     c = b; // save this atom for later use
3342     }
3343     }
3344     if (c)
3345     (atom->GetBond(c))->SetBO(2);
3346     }
3347     } // pass 6
3348    
3349     // Now let the atom typer go to work again
3350     _flags &= (~(OB_HYBRID_MOL));
3351     _flags &= (~(OB_KEKULE_MOL));
3352     _flags &= (~(OB_AROMATIC_MOL));
3353     _flags &= (~(OB_ATOMTYPES_MOL));
3354     _flags &= (~(OB_IMPVAL_MOL));
3355     // EndModify(true); // "nuke" perceived data
3356     }
3357    
3358     void OBMol::Center()
3359     {
3360     int j,size;
3361     double *c,x,y,z,fsize;
3362    
3363     size = NumAtoms();
3364     fsize = -1.0/(double)NumAtoms();
3365    
3366 tim 2518 obErrorLog.ThrowError(__func__,
3367 tim 2440 "Ran OpenBabel::Center", obAuditMsg);
3368    
3369     vector<double*>::iterator i;
3370     for (i = _vconf.begin();i != _vconf.end();i++)
3371     {
3372     c = *i;
3373     x = y = z = 0.0;
3374     for (j = 0;j < size;j++)
3375     {
3376     x += c[j*3];
3377     y += c[j*3+1];
3378     z += c[j*3+2];
3379     }
3380     x *= fsize;
3381     y *= fsize;
3382     z *= fsize;
3383    
3384     for (j = 0;j < size;j++)
3385     {
3386     c[j*3]+=x;
3387     c[j*3+1]+=y;
3388     c[j*3+2]+=z;
3389     }
3390     }
3391    
3392     }
3393    
3394     vector3 OBMol::Center(int nconf)
3395     {
3396 tim 2518 obErrorLog.ThrowError(__func__,
3397 tim 2440 "Ran OpenBabel::Center", obAuditMsg);
3398    
3399     SetConformer(nconf);
3400    
3401     OBAtom *atom;
3402     vector<OBNodeBase*>::iterator i;
3403    
3404     double x=0.0,y=0.0,z=0.0;
3405     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
3406     {
3407     x += atom->x();
3408     y += atom->y();
3409     z += atom->z();
3410     }
3411    
3412     x /= (double)NumAtoms();
3413     y /= (double)NumAtoms();
3414     z /= (double)NumAtoms();
3415    
3416     vector3 vtmp;
3417     vector3 v(x,y,z);
3418    
3419     for (atom = BeginAtom(i);atom;atom = NextAtom(i))
3420     {
3421     vtmp = atom->GetVector() - v;
3422     atom->SetVector(vtmp);
3423     }
3424    
3425     return(v);
3426     }
3427    
3428    
3429     /*! this method adds the vector v to all atom positions in all conformers */
3430     void OBMol::Translate(const vector3 &v)
3431     {
3432     for (int i = 0;i < NumConformers();i++)
3433     Translate(v,i);
3434     }
3435    
3436     /*! this method adds the vector v to all atom positions in the
3437     conformer nconf. If nconf == OB_CURRENT_CONFORMER, then the atom
3438     positions in the current conformer are translated. */
3439     void OBMol::Translate(const vector3 &v,int nconf)
3440     {
3441 tim 2518 obErrorLog.ThrowError(__func__,
3442 tim 2440 "Ran OpenBabel::Translate", obAuditMsg);
3443    
3444     int i,size;
3445     double x,y,z;
3446     double *c = (nconf == OB_CURRENT_CONFORMER)? _c : GetConformer(nconf);
3447    
3448     x = v.x();
3449     y = v.y();
3450     z = v.z();
3451     size = NumAtoms();
3452     for (i = 0;i < size;i++)
3453     {
3454     c[i*3 ] += x;
3455     c[i*3+1] += y;
3456     c[i*3+2] += z;
3457     }
3458     }
3459    
3460     void OBMol::Rotate(const double u[3][3])
3461     {
3462     int i,j,k;
3463     double m[9];
3464     for (k=0,i = 0;i < 3;i++)
3465     for (j = 0;j < 3;j++)
3466     m[k++] = u[i][j];
3467    
3468     for (i = 0;i < NumConformers();i++)
3469     Rotate(m,i);
3470     }
3471    
3472     void OBMol::Rotate(const double m[9])
3473     {
3474     for (int i = 0;i < NumConformers();i++)
3475     Rotate(m,i);
3476     }
3477    
3478     void OBMol::Rotate(const double m[9],int nconf)
3479     {
3480     int i,size;
3481     double x,y,z;
3482     double *c = (nconf == OB_CURRENT_CONFORMER)? _c : GetConformer(nconf);
3483    
3484 tim 2518 obErrorLog.ThrowError(__func__,
3485 tim 2440 "Ran OpenBabel::Rotate", obAuditMsg);
3486    
3487     size = NumAtoms();
3488     for (i = 0;i < size;i++)
3489     {
3490     x = c[i*3 ];
3491     y = c[i*3+1];
3492     z = c[i*3+2];
3493     c[i*3 ] = m[0]*x + m[1]*y + m[2]*z;
3494     c[i*3+1] = m[3]*x + m[4]*y + m[5]*z;
3495     c[i*3+2] = m[6]*x + m[7]*y + m[8]*z;
3496     }
3497     }
3498    
3499    
3500     void OBMol::SetConformers(vector<double*> &v)
3501     {
3502     vector<double*>::iterator i;
3503     for (i = _vconf.begin();i != _vconf.end();i++)
3504     delete [] *i;
3505    
3506     _vconf = v;
3507     _c = (_vconf.empty()) ? NULL : _vconf[0];
3508    
3509     }
3510    
3511     void OBMol::CopyConformer(double *c,int idx)
3512     {
3513     // obAssert(!_vconf.empty() && (unsigned)idx < _vconf.size());
3514     memcpy((char*)_vconf[idx],(char*)c,sizeof(double)*3*NumAtoms());
3515     }
3516    
3517     // void OBMol::CopyConformer(double *c,int idx)
3518     // {
3519     // obAssert(!_vconf.empty() && (unsigned)idx < _vconf.size());
3520    
3521     // unsigned int i;
3522     // for (i = 0;i < NumAtoms();i++)
3523     // {
3524     // _vconf[idx][i*3 ] = (double)c[i*3 ];
3525     // _vconf[idx][i*3+1] = (double)c[i*3+1];
3526     // _vconf[idx][i*3+2] = (double)c[i*3+2];
3527     // }
3528     // }
3529    
3530     void OBMol::DeleteConformer(int idx)
3531     {
3532     if (idx < 0 || idx >= (signed)_vconf.size())
3533     return;
3534    
3535     delete [] _vconf[idx];
3536     _vconf.erase((_vconf.begin()+idx));
3537     }
3538    
3539     ///Converts for instance [N+]([O-])=O to N(=O)=O
3540     bool OBMol::ConvertDativeBonds()
3541     {
3542 tim 2518 obErrorLog.ThrowError(__func__,
3543 tim 2440 "Ran OpenBabel::ConvertDativeBonds", obAuditMsg);
3544    
3545     //Look for + and - charges on adjacent atoms
3546     OBAtom* patom;
3547     vector<OBNodeBase*>::iterator i;
3548     for (patom = BeginAtom(i);patom;patom = NextAtom(i))
3549     {
3550     vector<OBEdgeBase*>::iterator itr;
3551     OBBond *pbond;
3552     for (pbond = patom->BeginBond(itr);patom->GetFormalCharge() && pbond;pbond = patom->NextBond(itr))
3553     {
3554     OBAtom* pNbratom = pbond->GetNbrAtom(patom);
3555     int chg1 = patom->GetFormalCharge();
3556     int chg2 = pNbratom->GetFormalCharge();
3557     if((chg1>0 && chg2<0)|| (chg1<0 && chg2>0))
3558     {
3559     //dative bond. Reduce charges and increase bond order
3560     if(chg1>0)
3561     --chg1;
3562     else
3563     ++chg1;
3564     patom->SetFormalCharge(chg1);
3565     if(chg2>0)
3566     --chg2;
3567     else
3568     ++chg2;
3569     pNbratom->SetFormalCharge(chg2);
3570     pbond->SetBO(pbond->GetBO()+1);
3571     }
3572     }
3573     }
3574     return true;
3575     }
3576    
3577     OBAtom *OBMol::BeginAtom(vector<OBNodeBase*>::iterator &i)
3578     {
3579     i = _vatom.begin();
3580     return((i == _vatom.end()) ? (OBAtom*)NULL : (OBAtom*)*i);
3581     }
3582    
3583     OBAtom *OBMol::NextAtom(vector<OBNodeBase*>::iterator &i)
3584     {
3585     i++;
3586     return((i == _vatom.end()) ? (OBAtom*)NULL : (OBAtom*)*i);
3587     }
3588    
3589     OBBond *OBMol::BeginBond(vector<OBEdgeBase*>::iterator &i)
3590     {
3591     i = _vbond.begin();
3592     return((i == _vbond.end()) ? (OBBond*)NULL : (OBBond*)*i);
3593     }
3594    
3595     OBBond *OBMol::NextBond(vector<OBEdgeBase*>::iterator &i)
3596     {
3597     i++;
3598     return((i == _vbond.end()) ? (OBBond*)NULL : (OBBond*)*i);
3599     }
3600    
3601     } // end namespace OpenBabel
3602    
3603     //! \file mol.cpp
3604     //! \brief Handle molecules. Implementation of OBMol.