ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/openbabel/mol.cpp
Revision: 3057
Committed: Thu Oct 19 20:49:05 2006 UTC (17 years, 11 months ago) by gezelter
File size: 99684 byte(s)
Log Message:
updated OpenBabel to version 2.0.2

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