ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/openbabel/obbond.cpp
Revision: 2466
Committed: Wed Nov 23 01:05:59 2005 UTC (18 years, 7 months ago) by chuckv
File size: 15363 byte(s)
Log Message:
Changed file names that conflict w/ oopse file name object files.

File Contents

# Content
1 /**********************************************************************
2 bond.cpp - Handle OBBond class
3
4 Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5 Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison
6
7 This file is part of the Open Babel project.
8 For more information, see <http://openbabel.sourceforge.net/>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation version 2 of the License.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 ***********************************************************************/
19
20 #include "mol.hpp"
21 #include "typer.hpp"
22
23 using namespace std;
24
25 namespace OpenBabel
26 {
27
28 extern OBAromaticTyper aromtyper;
29
30 /** \class OBBond
31 \brief Bond class
32
33 The OBBond class is straightforward in its data access and
34 modification methods. OBBonds store pointers to the atoms on each end
35 of the bond. In storing pointers to atoms instead of integer indices,
36 the necessity of having to reorder bonds when atoms are shuffled,
37 added, or delete is obviated.
38 */
39
40 // *******************************
41 // *** OBBond member functions ***
42 // *******************************
43
44 OBBond::OBBond()
45 {
46 _idx=0;
47 _order=0;
48 _flags=0;
49 _bgn=NULL;
50 _end=NULL;
51 _vdata.clear();
52 }
53
54 OBBond::~OBBond()
55 {
56 if (!_vdata.empty())
57 {
58 vector<OBGenericData*>::iterator m;
59 for (m = _vdata.begin();m != _vdata.end();m++)
60 delete *m;
61 _vdata.clear();
62 }
63 }
64
65 void OBBond::Set(int idx,OBAtom *begin,OBAtom *end,int order,int flags)
66 {
67 SetIdx(idx);
68 SetBegin(begin);
69 SetEnd(end);
70 SetBO(order);
71 SetFlag(flags);
72 }
73
74 void OBBond::SetBO(int order)
75 {
76 _order = (char)order;
77 if (order == 5)
78 {
79 SetAromatic();
80 if (_bgn)
81 _bgn->SetAromatic();
82 if (_end)
83 _end->SetAromatic();
84 }
85 else
86 {
87 if (order == 1)
88 SetKSingle();
89 else if (order == 2)
90 SetKDouble();
91 else if (order == 3)
92 SetKTriple();
93
94 UnsetAromatic();
95 }
96 }
97
98 void OBBond::SetLength(OBAtom *fixed, double length)
99 {
100 unsigned int i;
101 OBMol *mol = (OBMol*)fixed->GetParent();
102 vector3 v1,v2,v3,v4,v5;
103 vector<int> children;
104
105 obErrorLog.ThrowError(__FUNCTION__,
106 "Ran OpenBabel::SetBondLength", obAuditMsg);
107
108 int a = fixed->GetIdx();
109 int b = GetNbrAtom(fixed)->GetIdx();
110
111 mol->FindChildren(children,a,b);
112 children.push_back(b);
113
114 v1 = GetNbrAtom(fixed)->GetVector();
115 v2 = fixed->GetVector();
116 v3 = v1 - v2;
117 v3.normalize();
118 v3 *= length;
119 v3 += v2;
120 v4 = v3 - v1;
121
122 for ( i = 0 ; i < children.size() ; i++ )
123 {
124 v1 = mol->GetAtom(children[i])->GetVector();
125 v1 += v4;
126 mol->GetAtom(children[i])->SetVector(v1);
127 /*
128 idx = (children[i]-1) * 3;
129 c[idx] += x;
130 c[idx+1] += y;
131 c[idx+2] += z;
132 */
133 }
134 }
135
136 bool OBBond::IsRotor()
137 {
138 return(_bgn->GetHvyValence() > 1 && _end->GetHvyValence() > 1 &&
139 _order == 1 && !IsInRing() && _bgn->GetHyb() != 1 &&
140 _end->GetHyb() != 1);
141 }
142
143 bool OBBond::IsAmide()
144 {
145 OBAtom *a1,*a2;
146 a1 = a2 = NULL;
147
148 if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7)
149 {
150 a1 = (OBAtom*)_bgn;
151 a2 = (OBAtom*)_end;
152 }
153
154 if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6)
155 {
156 a1 = (OBAtom*)_end;
157 a2 = (OBAtom*)_bgn;
158 }
159
160 if (!a1 || !a2)
161 return(false);
162 if (GetBO() != 1)
163 return(false);
164
165 OBBond *bond;
166 vector<OBEdgeBase*>::iterator i;
167 for (bond = a1->BeginBond(i);bond;bond = a1->NextBond(i))
168 if (bond->IsCarbonyl())
169 return(true);
170
171 return(false);
172 }
173
174 bool OBBond::IsPrimaryAmide()
175 {
176 OBAtom *a1,*a2;
177 a1 = a2 = NULL;
178
179 if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 7)
180 {
181 a1 = (OBAtom*)_bgn;
182 a2 = (OBAtom*)_end;
183 }
184
185 if (_bgn->GetAtomicNum() == 7 && _end->GetAtomicNum() == 6)
186 {
187 a1 = (OBAtom*)_end;
188 a2 = (OBAtom*)_bgn;
189 }
190
191 if (!a1 || !a2)
192 return(false);
193 if (GetBO() != 1)
194 return(false);
195
196 OBBond *bond;
197 vector<OBEdgeBase*>::iterator i;
198 for (bond = a1->BeginBond(i);bond;bond = a1->NextBond(i))
199 if (bond->IsCarbonyl())
200 if (a2->GetHvyValence() == 2)
201 return(true);
202
203 return(false);
204 }
205
206 //! \todo Implement this properly -- currently always returns false
207 bool OBBond::IsSecondaryAmide()
208 {
209 return(false);
210 }
211
212 bool OBBond::IsEster()
213 {
214 OBAtom *a1,*a2;
215 a1 = a2 = NULL;
216
217 if (_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 8)
218 {
219 a1 = (OBAtom*)_bgn;
220 a2 = (OBAtom*)_end;
221 }
222
223 if (_bgn->GetAtomicNum() == 8 && _end->GetAtomicNum() == 6)
224 {
225 a1 = (OBAtom*)_end;
226 a2 = (OBAtom*)_bgn;
227 }
228
229 if (!a1 || !a2)
230 return(false);
231 if (GetBO() != 1)
232 return(false);
233
234 OBBond *bond;
235 vector<OBEdgeBase*>::iterator i;
236 for (bond = a1->BeginBond(i);bond;bond = a1->NextBond(i))
237 if (bond->IsCarbonyl())
238 return(true);
239
240 return(false);
241 }
242
243 bool OBBond::IsCarbonyl()
244 {
245 if (GetBO() != 2)
246 return(false);
247
248 if ((_bgn->GetAtomicNum() == 6 && _end->GetAtomicNum() == 8) ||
249 (_bgn->GetAtomicNum() == 8 && _end->GetAtomicNum() == 6))
250 return(true);
251
252 return(false);
253 }
254
255 bool OBBond::IsSingle()
256 {
257 if (HasFlag(OB_AROMATIC_BOND))
258 return(false);
259
260 if (!((OBMol*)GetParent())->HasAromaticPerceived())
261 {
262 aromtyper.AssignAromaticFlags(*((OBMol*)GetParent()));
263 }
264
265 if ((this->GetBondOrder()==1) && !(HasFlag(OB_AROMATIC_BOND)))
266 return(true);
267
268 return(false);
269 }
270
271 bool OBBond::IsDouble()
272 {
273 if (HasFlag(OB_AROMATIC_BOND))
274 return(false);
275
276 if (!((OBMol*)GetParent())->HasAromaticPerceived())
277 {
278 aromtyper.AssignAromaticFlags(*((OBMol*)GetParent()));
279 }
280
281 if ((this->GetBondOrder()==2) && !(HasFlag(OB_AROMATIC_BOND)))
282 return(true);
283
284 return(false);
285 }
286
287 bool OBBond::IsTriple()
288 {
289 if (HasFlag(OB_AROMATIC_BOND))
290 return(false);
291
292 if (!((OBMol*)GetParent())->HasAromaticPerceived())
293 {
294 aromtyper.AssignAromaticFlags(*((OBMol*)GetParent()));
295 }
296
297 if ((this->GetBondOrder()==3) && !(HasFlag(OB_AROMATIC_BOND)))
298 return(true);
299
300 return(false);
301 }
302
303 bool OBBond::IsAromatic() const
304 {
305 if (((OBBond*)this)->HasFlag(OB_AROMATIC_BOND))
306 return(true);
307
308 OBMol *mol = (OBMol*)((OBBond*)this)->GetParent();
309 if (!mol->HasAromaticPerceived())
310 {
311 aromtyper.AssignAromaticFlags(*mol);
312 if (((OBBond*)this)->HasFlag(OB_AROMATIC_BOND))
313 return(true);
314 }
315
316 return(false);
317 }
318
319 /*! This method checks if the geometry around this bond looks unsaturated
320 by measuring the torsion angles formed by all connected atoms X-start=end-Y
321 and checking that they are close to 0 or 180 degrees */
322 bool OBBond::IsDoubleBondGeometry()
323 {
324 double torsion;
325 OBAtom *nbrStart,*nbrEnd;
326 vector<OBEdgeBase*>::iterator i,j;
327 // We concentrate on sp2 atoms with valence up to 3 and ignore the rest (like sp1 or S,P)
328 // As this is called from PerceiveBondOrders, GetHyb() may still be undefined.
329 if (_bgn->GetHyb()==1 || _bgn->GetValence()>3||
330 _end->GetHyb()==1 || _end->GetValence()>3)
331 return(true);
332
333 for (nbrStart = static_cast<OBAtom*>(_bgn)->BeginNbrAtom(i); nbrStart;
334 nbrStart = static_cast<OBAtom*>(_bgn)->NextNbrAtom(i))
335 {
336 if (nbrStart != _end)
337 {
338 for (nbrEnd = static_cast<OBAtom*>(_end)->BeginNbrAtom(j);
339 nbrEnd; nbrEnd = static_cast<OBAtom*>(_end)->NextNbrAtom(j))
340 {
341 if (nbrEnd != _bgn)
342 {
343 torsion=fabs(CalcTorsionAngle(nbrStart->GetVector(),
344 static_cast<OBAtom*>(_bgn)->GetVector(),
345 static_cast<OBAtom*>(_end)->GetVector(),
346 nbrEnd->GetVector()));
347
348 // >12&&<168 not enough
349 if (torsion > 15.0f && torsion < 165.0f)
350 {
351 // Geometry does not match a double bond
352 return(false);
353 }
354
355 }
356 } // end loop for neighbors of end
357 }
358 } // end loop for neighbors of start
359 return(true);
360 }
361
362 void OBBond::SetKSingle()
363 {
364 _flags &= (~(OB_KSINGLE_BOND|OB_KDOUBLE_BOND|OB_KTRIPLE_BOND));
365 _flags |= OB_KSINGLE_BOND;
366 }
367
368 void OBBond::SetKDouble()
369 {
370 _flags &= (~(OB_KSINGLE_BOND|OB_KDOUBLE_BOND|OB_KTRIPLE_BOND));
371 _flags |= OB_KDOUBLE_BOND;
372 }
373
374 void OBBond::SetKTriple()
375 {
376 _flags &= (~(OB_KSINGLE_BOND|OB_KDOUBLE_BOND|OB_KTRIPLE_BOND));
377 _flags |= OB_KTRIPLE_BOND;
378 }
379
380 bool OBBond::IsKSingle()
381 {
382 if (_flags & OB_KSINGLE_BOND)
383 return(true);
384 if (!((OBMol*)GetParent())->HasKekulePerceived())
385 ((OBMol*)GetParent())->NewPerceiveKekuleBonds();
386
387 return((_flags & OB_KSINGLE_BOND) != 0) ? true : false;
388 }
389
390 bool OBBond::IsKDouble()
391 {
392 if (_flags & OB_KDOUBLE_BOND)
393 return(true);
394 if (!((OBMol*)GetParent())->HasKekulePerceived())
395 ((OBMol*)GetParent())->NewPerceiveKekuleBonds();
396
397 return((_flags & OB_KDOUBLE_BOND) != 0) ? true : false;
398 }
399
400 bool OBBond::IsKTriple()
401 {
402 if (_flags & OB_KTRIPLE_BOND)
403 return(true);
404 if (!((OBMol*)GetParent())->HasKekulePerceived())
405 ((OBMol*)GetParent())->NewPerceiveKekuleBonds();
406
407 return((_flags & OB_KTRIPLE_BOND) != 0) ? true : false;
408 }
409
410 bool OBBond::IsInRing() const
411 {
412 if (((OBBond*)this)->HasFlag(OB_RING_BOND))
413 return(true);
414
415 OBMol *mol = (OBMol*)((OBBond*)this)->GetParent();
416 if (!mol->HasRingAtomsAndBondsPerceived())
417 {
418 mol->FindRingAtomsAndBonds();
419 if (((OBBond*)this)->HasFlag(OB_RING_BOND))
420 return(true);
421 }
422
423 return(false);
424 }
425
426 bool OBBond::IsClosure()
427 {
428 OBMol *mol = (OBMol*)GetParent();
429 if (!mol)
430 return(false);
431 if (mol->HasClosureBondsPerceived())
432 return(HasFlag(OB_CLOSURE_BOND));
433
434 mol->SetClosureBondsPerceived();
435
436 obErrorLog.ThrowError(__FUNCTION__,
437 "Ran OpenBabel::PerceiveClosureBonds", obAuditMsg);
438
439 OBBond *bond;
440 OBAtom *atom,*nbr;
441 OBBitVec uatoms,ubonds;
442 vector<OBNodeBase*> curr,next;
443 vector<OBNodeBase*>::iterator i;
444 vector<OBEdgeBase*>::iterator j;
445
446 uatoms.Resize(mol->NumAtoms()+1);
447 ubonds.Resize(mol->NumAtoms()+1);
448
449 for (;uatoms.CountBits() < (signed)mol->NumAtoms();)
450 {
451 if (curr.empty())
452 for (atom = mol->BeginAtom(i);atom;atom = mol->NextAtom(i))
453 if (!uatoms[atom->GetIdx()])
454 {
455 uatoms |= atom->GetIdx();
456 curr.push_back(atom);
457 break;
458 }
459
460 for (;!curr.empty();)
461 {
462 for (i = curr.begin();i != curr.end();i++)
463 for (nbr = ((OBAtom*)*i)->BeginNbrAtom(j);nbr;nbr = ((OBAtom*)*i)->NextNbrAtom(j))
464 if (!uatoms[nbr->GetIdx()])
465 {
466 uatoms |= nbr->GetIdx();
467 ubonds |= (*j)->GetIdx();
468 next.push_back(nbr);
469 }
470
471 curr = next;
472 next.clear();
473 }
474 }
475
476 for (bond = mol->BeginBond(j);bond;bond = mol->NextBond(j))
477 if (!ubonds[bond->GetIdx()])
478 bond->SetClosure();
479
480 return(HasFlag(OB_CLOSURE_BOND));
481 }
482
483 double OBBond::GetEquibLength()
484 {
485 double length;
486 OBAtom *begin, *end;
487 // CorrectedBondRad will always return a # now
488 // if (!CorrectedBondRad(GetBeginAtom(),rad1)) return(0.0);
489 // if (!CorrectedBondRad(GetEndAtom(),rad2)) return(0.0);
490
491 begin = GetBeginAtom();
492 end = GetEndAtom();
493 length = etab.CorrectedBondRad(begin->GetAtomicNum(), begin->GetHyb())
494 + etab.CorrectedBondRad(end->GetAtomicNum(), end->GetHyb());
495
496 if (IsAromatic())
497 length *= 0.93;
498 else if (GetBO() == 2)
499 length *= 0.91;
500 else if (GetBO() == 3)
501 length *= 0.87;
502 return(length);
503 }
504
505 double OBBond::GetLength()
506 {
507 double d2;
508 OBAtom *begin, *end;
509 begin = GetBeginAtom();
510 end = GetEndAtom();
511
512 d2 = SQUARE(begin->GetX() - end->GetX());
513 d2 += SQUARE(begin->GetY() - end->GetY());
514 d2 += SQUARE(begin->GetZ() - end->GetZ());
515
516 return(sqrt(d2));
517 }
518
519 // OBGenericData methods
520 bool OBBond::HasData(string &s)
521 //returns true if the generic attribute/value pair exists
522 {
523 if (_vdata.empty())
524 return(false);
525
526 vector<OBGenericData*>::iterator i;
527
528 for (i = _vdata.begin();i != _vdata.end();i++)
529 if ((*i)->GetAttribute() == s)
530 return(true);
531
532 return(false);
533 }
534
535 bool OBBond::HasData(const char *s)
536 //returns true if the generic attribute/value pair exists
537 {
538 if (_vdata.empty())
539 return(false);
540
541 vector<OBGenericData*>::iterator i;
542
543 for (i = _vdata.begin();i != _vdata.end();i++)
544 if ((*i)->GetAttribute() == s)
545 return(true);
546
547 return(false);
548 }
549
550 bool OBBond::HasData(unsigned int dt)
551 //returns true if the generic attribute/value pair exists
552 {
553 if (_vdata.empty())
554 return(false);
555
556 vector<OBGenericData*>::iterator i;
557
558 for (i = _vdata.begin();i != _vdata.end();i++)
559 if ((*i)->GetDataType() == dt)
560 return(true);
561
562 return(false);
563 }
564
565 OBGenericData *OBBond::GetData(string &s)
566 //returns the value given an attribute
567 {
568 vector<OBGenericData*>::iterator i;
569
570 for (i = _vdata.begin();i != _vdata.end();i++)
571 if ((*i)->GetAttribute() == s)
572 return(*i);
573
574 return(NULL);
575 }
576
577 OBGenericData *OBBond::GetData(const char *s)
578 //returns the value given an attribute
579 {
580 vector<OBGenericData*>::iterator i;
581
582 for (i = _vdata.begin();i != _vdata.end();i++)
583 if ((*i)->GetAttribute() == s)
584 return(*i);
585
586 return(NULL);
587 }
588
589 OBGenericData *OBBond::GetData(unsigned int dt)
590 {
591 vector<OBGenericData*>::iterator i;
592 for (i = _vdata.begin();i != _vdata.end();i++)
593 if ((*i)->GetDataType() == dt)
594 return(*i);
595 return(NULL);
596 }
597
598 void OBBond::DeleteData(unsigned int dt)
599 {
600 vector<OBGenericData*> vdata;
601 vector<OBGenericData*>::iterator i;
602 for (i = _vdata.begin();i != _vdata.end();i++)
603 if ((*i)->GetDataType() == dt)
604 delete *i;
605 else
606 vdata.push_back(*i);
607 _vdata = vdata;
608 }
609
610 void OBBond::DeleteData(vector<OBGenericData*> &vg)
611 {
612 vector<OBGenericData*> vdata;
613 vector<OBGenericData*>::iterator i,j;
614
615 bool del;
616 for (i = _vdata.begin();i != _vdata.end();i++)
617 {
618 del = false;
619 for (j = vg.begin();j != vg.end();j++)
620 if (*i == *j)
621 {
622 del = true;
623 break;
624 }
625 if (del)
626 delete *i;
627 else
628 vdata.push_back(*i);
629 }
630 _vdata = vdata;
631 }
632
633 void OBBond::DeleteData(OBGenericData *gd)
634 {
635 vector<OBGenericData*>::iterator i;
636 for (i = _vdata.begin();i != _vdata.end();i++)
637 if (*i == gd)
638 {
639 delete *i;
640 _vdata.erase(i);
641 }
642
643 }
644
645 } // end namespace OpenBabel
646
647 //! \file bond.cpp
648 //! \brief Handle OBBond class