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

File Contents

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