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

File Contents

# Content
1 /**********************************************************************
2 atom.cpp - Handle OBAtom class.
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 "typer.hpp"
23 #include "molchrg.hpp"
24 #include "phmodel.hpp"
25
26 #include "matrix3x3.hpp"
27
28 #if !HAVE_STRNCASECMP
29 extern "C" int strncasecmp(const char *s1, const char *s2, size_t n);
30 #endif
31
32 using namespace std;
33
34 namespace OpenBabel
35 {
36
37 /** \class OBAtom
38 \brief Atom class
39
40 To understand the OBAtom class it is important to state a key
41 decision on which the design was based. In OBabel the atom class
42 existed, but it was only a data container. All data access and
43 modification of atoms was done through the molecule. The result
44 was a molecule class that was very large an unwieldy. So the OBAtom
45 class was made smarter, and many of the atom-specific routines
46 were separated into the OBAtom thereby decentralizing and
47 shrinking the OBMol class. As a result the OBAtom class not only
48 holds data, but facilitates extraction of data perceived from both
49 the atom and the molecule.
50
51 A number of data extraction methods perform what is called
52 <a href="http://en.wikipedia.org/wiki/Lazy_evaluation">`Lazy Evaluation,'</a> which is essentially on-the-fly evaluation.
53 For example, when an atom is queried as to whether it is cyclic
54 or what it's hybridization state is the information is perceived
55 automatically. The perception of a particular trait is actually
56 performed on the entire molecule the first time it is requested of
57 an atom or bond, and stored for subsequent requests for the same
58 trait of additional atoms or bonds.The OBAtom class is similar to
59 OBMol and the whole of Open Babel in that data access and modification
60 is done through Get and Set methods.
61
62 The following code demonstrates how to print out the atom numbers,
63 element numbers, and coordinates of a molecule:
64 \code
65 OBMol mol;
66
67 FOR_ATOMS_IN_MOL(atom, mol)
68 {
69 cout << atom->GetIdx() << ` `;
70 cout << atom->GetAtomicNum() << ` `;
71 cout << atom->GetVector() << endl;
72 }
73 \endcode
74 A number of the property member functions indicate that atoms
75 have some knowlege of their covalently attached neighbor atoms.
76 Bonding information is partly redundant within a molecule in
77 that an OBMol has a complete list of bonds in a molecule, and
78 an OBAtom has a list bonds of which it is a member. The following
79 code demonstrates how an OBAtom uses its bond information to loop
80 over atoms attached to itself:
81 \code
82 OBMol mol;
83 OBAtom *atom;
84
85 atom = mol.GetAtom(1);
86 FOR_NBORS_OF_ATOM(nbr, atom)
87 {
88 cout << "atom #" << atom->GetIdx() << " is attached to atom #" << nbr->GetIdx() << endl;
89 }
90 \endcode
91
92 should produce an output like
93 \code
94 atom #1 is attached to atom #2
95 \endcode
96 */
97
98 extern OBAromaticTyper aromtyper;
99 extern OBAtomTyper atomtyper;
100 extern OBPhModel phmodel;
101
102 //
103 // OBAtom member functions
104 //
105
106 OBAtom::OBAtom()
107 {
108 _parent = (OBMol*)NULL;
109 Clear();
110 }
111
112 OBAtom::~OBAtom()
113 {
114 if (_residue != NULL)
115 _residue->RemoveAtom(this);
116 if (!_vdata.empty())
117 {
118 vector<OBGenericData*>::iterator m;
119 for (m = _vdata.begin();m != _vdata.end();m++)
120 delete *m;
121 _vdata.clear();
122 }
123 }
124
125 void OBAtom::Clear()
126 {
127 _c = (double**)NULL;
128 _cidx = 0;
129 _flags=0;
130 _idx = 0;
131 _hyb = 0;
132 _ele = (char)0;
133 _isotope = 0;
134 _spinmultiplicity=0; // CM 18 Sept 2003
135 _impval = 0;
136 _fcharge = 0;
137 _type[0] = '\0';
138 _pcharge = 0.0;
139 _vbond.clear();
140 _vbond.reserve(4);
141 _residue = (OBResidue*)NULL;
142 _vdata.clear();
143 }
144
145 OBAtom &OBAtom::operator=(OBAtom &src)
146 //copy atom information
147 //bond info is not copied here as ptrs may be invalid
148 //vdata is also not copied yet (again it's unclear what can work)
149 {
150 _idx = src.GetIdx();
151 _hyb = src.GetHyb();
152 _ele = src.GetAtomicNum();
153 _isotope = src.GetIsotope();
154 _fcharge = src.GetFormalCharge();
155 _spinmultiplicity = src.GetSpinMultiplicity();
156 strcpy(_type,src.GetType());
157 _pcharge = src.GetPartialCharge();
158 _v = src.GetVector();
159 _flags = src.GetFlag();
160 _residue = (OBResidue*)NULL;
161 return(*this);
162 }
163
164 bool OBAtom::IsConnected(OBAtom *a1)
165 {
166 vector<OBEdgeBase*>::iterator i;
167 OBBond *bond;
168
169 for (bond = BeginBond(i);bond;bond = NextBond(i))
170 if (bond->GetBeginAtom() == a1 || bond->GetEndAtom() == a1)
171 return(true);
172
173 return(false);
174 }
175
176 bool OBAtom::IsOneThree(OBAtom *a1)
177 {
178 OBAtom *atom1,*atom2;
179 OBBond *bond1,*bond2;
180 vector<OBEdgeBase*>::iterator i,j;
181 atom1 = this;
182 atom2 = a1;
183
184 for (bond1 = atom1->BeginBond(i);bond1;bond1 = atom1->NextBond(i))
185 for (bond2 = atom2->BeginBond(j);bond2;bond2 = atom2->NextBond(j))
186 if (bond1->GetNbrAtom(atom1) == bond2->GetNbrAtom(atom2))
187 return(true);
188
189 return(false);
190 }
191
192 bool OBAtom::IsOneFour(OBAtom *a1)
193 {
194 OBAtom *atom1,*atom2;
195 OBBond *bond1,*bond2;
196 vector<OBEdgeBase*>::iterator i,j;
197 atom1 = this;
198 atom2 = a1;
199
200 for (bond1 = atom1->BeginBond(i);bond1;bond1 = atom1->NextBond(i))
201 for (bond2 = atom2->BeginBond(j);bond2;bond2 = atom2->NextBond(j))
202 if ((bond1->GetNbrAtom(atom1))->IsConnected(bond2->GetNbrAtom(atom2)))
203 return(true);
204
205 return(false);
206 }
207
208 bool OBAtom::IsAxial()
209 {
210 double tor;
211 OBAtom *a,*b,*c;
212 vector<OBEdgeBase*>::iterator i,j,k;
213
214 for (a = BeginNbrAtom(i);a;a = NextNbrAtom(i))
215 if (a->GetHyb() == 3 && a->IsInRing() && !(*i)->IsInRing())
216 for (b = a->BeginNbrAtom(j);b;b = a->NextNbrAtom(j))
217 if (b != this && b->IsInRing() && b->GetHyb() == 3)
218 for (c = b->BeginNbrAtom(k);c;c = b->NextNbrAtom(k))
219 if (c != a && c->IsInRing())
220 {
221 tor = fabs(((OBMol*)GetParent())->GetTorsion(this,a,b,c));
222 return(tor > 55.0 && tor < 75.0);
223 }
224
225 return(false);
226 }
227
228
229 bool OBAtom::HasAlphaBetaUnsat(bool includePandS)
230 {
231 OBAtom *a1,*a2;
232 vector<OBEdgeBase*>::iterator i,j;
233
234 for (a1 = BeginNbrAtom(i);a1;a1 = NextNbrAtom(i))
235 if (includePandS || (!a1->IsPhosphorus() && !a1->IsSulfur()))
236 for (a2 = a1->BeginNbrAtom(j);a2;a2 = a1->NextNbrAtom(j))
237 if (a2 != this && ((*j)->GetBO() == 2 || (*j)->GetBO() == 3 || (*j)->GetBO() == 5))
238 return(true);
239
240 return(false);
241 }
242
243 bool OBAtom::HasBondOfOrder(unsigned int order)
244 {
245 OBBond *bond;
246 vector<OBEdgeBase*>::iterator i;
247 for (bond = BeginBond(i);bond;bond = NextBond(i))
248 if (bond->GetBO() == order)
249 return(true);
250
251 return(false);
252 }
253
254 int OBAtom::CountBondsOfOrder(unsigned int order)
255 {
256 int count = 0;
257 OBBond *bond;
258 vector<OBEdgeBase*>::iterator i;
259 for (bond = BeginBond(i);bond;bond = NextBond(i))
260 if (bond->GetBO() == order)
261 count++;
262
263 return(count);
264 }
265
266 bool OBAtom::HasNonSingleBond()
267 {
268 OBBond *bond;
269 vector<OBEdgeBase*>::iterator i;
270 for (bond = BeginBond(i);bond;bond = NextBond(i))
271 if (bond->GetBO() != 1)
272 return(true);
273
274 return(false);
275 }
276
277 bool OBAtom::IsPolarHydrogen()
278 {
279 if (!IsHydrogen())
280 return(false);
281
282 OBAtom *atom;
283 OBBond *bond;
284 vector<OBEdgeBase*>::iterator i;
285 for (bond = BeginBond(i);bond;bond = NextBond(i))
286 {
287 atom = bond->GetNbrAtom(this);
288 if (atom->GetAtomicNum() == 7)
289 return(true);
290 if (atom->GetAtomicNum() == 8)
291 return(true);
292 if (atom->GetAtomicNum() == 15)
293 return(true);
294 if (atom->GetAtomicNum() == 16)
295 return(true);
296 }
297
298 return(false);
299 }
300
301 bool OBAtom::IsNonPolarHydrogen()
302 {
303 if (!IsHydrogen())
304 return(false);
305
306 OBAtom *atom;
307 OBBond *bond;
308 vector<OBEdgeBase*>::iterator i;
309 for (bond = BeginBond(i);bond;bond = NextBond(i))
310 {
311 atom = bond->GetNbrAtom(this);
312 if (atom->GetAtomicNum() == 6)
313 return(true);
314 }
315
316 return(false);
317 }
318
319 vector3 &OBAtom::GetVector()
320 {
321 if (!_c)
322 return(_v);
323
324 _v.Set((*_c)[_cidx],(*_c)[_cidx+1],(*_c)[_cidx+2]);
325 return(_v);
326 }
327
328 void OBAtom::SetVector()
329 {
330 // obAssert(_c);
331 if (_c)
332 _v.Set((*_c)[_cidx],(*_c)[_cidx+1],(*_c)[_cidx+2]);
333 }
334
335 void OBAtom::SetVector(vector3 &v)
336 {
337 if (!_c)
338 _v = v;
339 else
340 {
341 (*_c)[_cidx ] = v.x();
342 (*_c)[_cidx+1] = v.y();
343 (*_c)[_cidx+2] = v.z();
344 }
345 }
346
347 void OBAtom::SetVector(const double x,const double y,const double z)
348 {
349 if (!_c)
350 _v.Set(x,y,z);
351 else
352 {
353 (*_c)[_cidx ] = x;
354 (*_c)[_cidx+1] = y;
355 (*_c)[_cidx+2] = z;
356 }
357 }
358
359 void OBAtom::SetType(char *type)
360 {
361 strcpy(_type,type);
362 if (_ele == 1 && type[0] == 'D')
363 _isotope = 2;
364 }
365
366 void OBAtom::SetType(string &type)
367 {
368 strcpy(_type,type.c_str());
369 if (_ele == 1 && type[0] == 'D')
370 _isotope = 2;
371 }
372
373 void OBAtom::SetIsotope(unsigned int iso)
374 {
375 if (_ele == 1 && iso == 2)
376 SetType("D");
377 else if (_ele == 1 && (iso == 1 || iso == 0))
378 SetType("H");
379
380 _isotope = iso;
381 }
382
383 OBAtom *OBAtom::GetNextAtom()
384 {
385 OBMol *mol = (OBMol*)GetParent();
386 return(((unsigned)GetIdx() == mol->NumAtoms())? NULL : mol->GetAtom(GetIdx()+1));
387 }
388
389 OBResidue *OBAtom::GetResidue()
390 {
391 if (_residue != NULL)
392 return _residue;
393 else if (!((OBMol*)GetParent())->HasChainsPerceived())
394 {
395 chainsparser.PerceiveChains(*((OBMol*)GetParent()));
396 ((OBMol*)GetParent())->SetChainsPerceived();
397 return _residue;
398 }
399 else
400 return NULL;
401 }
402
403 double OBAtom::GetAtomicMass() const
404 {
405 if (_isotope == 0)
406 return etab.GetMass(_ele);
407 else
408 return isotab.GetExactMass(_ele, _isotope);
409 }
410
411 double OBAtom::GetExactMass() const
412 {
413 return isotab.GetExactMass(_ele, _isotope);
414 }
415
416 char *OBAtom::GetType()
417 {
418 OBMol *mol = (OBMol*)GetParent();
419 if (mol && !mol->HasAtomTypesPerceived())
420 atomtyper.AssignTypes(*((OBMol*)GetParent()));
421
422 if (strlen(_type) == 0) // Somehow we still don't have a type!
423 {
424 char num[6];
425 string fromType = ttab.GetFromType(); // save previous types
426 string toType = ttab.GetToType();
427
428 ttab.SetFromType("ATN");
429 ttab.SetToType("INT");
430 snprintf(num, 6, "%d", GetAtomicNum());
431 ttab.Translate(_type, num);
432
433 ttab.SetFromType(fromType.c_str());
434 ttab.SetToType(toType.c_str());
435 }
436 if (_ele == 1 && _isotope == 2)
437 snprintf(_type, 6, "%s", "D");
438
439 return(_type);
440 }
441
442 unsigned int OBAtom::GetImplicitValence() const
443 {
444 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
445 if (mol && !mol->HasImplicitValencePerceived())
446 atomtyper.AssignImplicitValence(*((OBMol*)((OBAtom*)this)->GetParent()));
447
448 return((unsigned int)_impval);
449 }
450
451 unsigned int OBAtom::GetHyb() const
452 {
453 //hybridization is assigned when atoms are typed
454 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
455 if (mol && !mol->HasHybridizationPerceived())
456 atomtyper.AssignHyb(*mol);
457
458 return(_hyb);
459 }
460
461
462 unsigned int OBAtom::GetHvyValence() const
463 {
464 unsigned int count=0;
465
466 OBBond *bond;
467 vector<OBEdgeBase*>::iterator i;
468 for (bond = ((OBAtom*)this)->BeginBond(i); bond; bond = ((OBAtom*)this)->NextBond(i))
469 if (!(bond->GetNbrAtom((OBAtom*)this)->IsHydrogen()))
470 count++;
471
472 return(count);
473 }
474
475 unsigned int OBAtom::GetHeteroValence() const
476 {
477 unsigned int count=0;
478 OBBond *bond;
479 vector<OBEdgeBase*>::iterator i;
480 for (bond = ((OBAtom*)this)->BeginBond(i);bond;bond = ((OBAtom*)this)->NextBond(i))
481 if (bond->GetNbrAtom((OBAtom*)this)->IsHeteroatom())
482 count++;
483
484 return((unsigned int)count);
485 }
486
487 double OBAtom::GetPartialCharge()
488 {
489 if (!GetParent())
490 return(_pcharge);
491 if (!((OBMol*)GetParent())->AutomaticPartialCharge())
492 return(_pcharge);
493
494 if (!((OBMol*)GetParent())->HasPartialChargesPerceived())
495 {
496 //seed partial charges are set in the atom typing procedure
497 OBAtom *atom;
498 OBMol *mol = (OBMol*)GetParent();
499 vector<OBNodeBase*>::iterator i;
500 for (atom = mol->BeginAtom(i); atom; atom = mol->NextAtom(i))
501 atom->SetPartialCharge(0.0);
502
503 phmodel.AssignSeedPartialCharge(*((OBMol*)GetParent()));
504 OBGastChrg gc;
505 gc.AssignPartialCharges(*((OBMol*)GetParent()));
506 }
507
508 return(_pcharge);
509 }
510
511 //! Returns true if nitrogen is part of an amide
512 bool OBAtom::IsAmideNitrogen()
513 {
514 if (!IsNitrogen())
515 return(false);
516
517 OBAtom *nbratom,*atom;
518 OBBond *abbond,*bond;
519
520 vector<OBEdgeBase*>::iterator i,j;
521 atom = this;
522 for (bond = BeginBond(i);bond;bond = NextBond(i))
523 {
524 nbratom = bond->GetNbrAtom(atom);
525 for (abbond = nbratom->BeginBond(j);abbond;abbond = nbratom->NextBond(j))
526 if (abbond->GetBO() == 2 &&
527 (((abbond->GetNbrAtom(nbratom))->GetAtomicNum() == 8) ||
528 ((abbond->GetNbrAtom(nbratom))->GetAtomicNum() == 16)))
529 return(true);
530 }
531
532 return(false);
533 }
534
535 bool OBAtom::IsAromaticNOxide()
536 {
537 if (!IsNitrogen() || !IsAromatic())
538 return(false);
539
540 OBAtom *atom;
541 vector<OBEdgeBase*>::iterator i;
542
543 for (atom = BeginNbrAtom(i);atom;atom = NextNbrAtom(i))
544 if (atom->IsOxygen() && !(*i)->IsInRing() && (*i)->GetBO() == 2)
545 return(true);
546
547 return(false);
548 }
549
550 bool OBAtom::IsCarboxylOxygen()
551 {
552 if (!IsOxygen())
553 return(false);
554 if (GetHvyValence() != 1)
555 return(false);
556
557 OBAtom *atom;
558 OBBond *bond;
559 vector<OBEdgeBase*>::iterator i;
560
561 atom = NULL;
562 for (bond = BeginBond(i);bond;bond = NextBond(i))
563 if ((bond->GetNbrAtom(this))->IsCarbon())
564 {
565 atom = bond->GetNbrAtom(this);
566 break;
567 }
568 if (!atom)
569 return(false);
570 if (atom->CountFreeOxygens() != 2)
571 return(false);
572
573 //atom is connected to a carbon that has a total
574 //of 2 attached free oxygens
575 return(true);
576 }
577
578 bool OBAtom::IsPhosphateOxygen()
579 {
580 if (!IsOxygen())
581 return(false);
582 if (GetHvyValence() != 1)
583 return(false);
584
585 OBAtom *atom;
586 OBBond *bond;
587 vector<OBEdgeBase*>::iterator i;
588
589 atom = NULL;
590 for (bond = BeginBond(i);bond;bond = NextBond(i))
591 if ((bond->GetNbrAtom(this))->IsPhosphorus())
592 {
593 atom = bond->GetNbrAtom(this);
594 break;
595 }
596 if (!atom)
597 return(false);
598 if (atom->CountFreeOxygens() > 2)
599 return(true);
600
601 //atom is connected to a carbon that has a total
602 //of 2 attached free oxygens
603 return(false);
604 }
605
606 bool OBAtom::IsSulfateOxygen()
607 {
608 if (!IsOxygen())
609 return(false);
610 if (GetHvyValence() != 1)
611 return(false);
612
613 OBAtom *atom;
614 OBBond *bond;
615 vector<OBEdgeBase*>::iterator i;
616
617 atom = NULL;
618 for (bond = BeginBond(i);bond;bond = NextBond(i))
619 if ((bond->GetNbrAtom(this))->IsSulfur())
620 {
621 atom = bond->GetNbrAtom(this);
622 break;
623 }
624 if (!atom)
625 return(false);
626 if (atom->CountFreeOxygens() < 3)
627 return(false);
628
629 //atom is connected to a carbon that has a total
630 //of 2 attached free oxygens
631 return(true);
632 }
633
634 bool OBAtom::IsNitroOxygen()
635 {
636 if (!IsOxygen())
637 return(false);
638 if (GetHvyValence() != 1)
639 return(false);
640
641 OBAtom *atom;
642 OBBond *bond;
643 vector<OBEdgeBase*>::iterator i;
644
645 atom = NULL;
646 for (bond = BeginBond(i);bond;bond = NextBond(i))
647 if ((bond->GetNbrAtom(this))->IsNitrogen())
648 {
649 atom = bond->GetNbrAtom(this);
650 break;
651 }
652 if (!atom)
653 return(false);
654 if (atom->CountFreeOxygens() != 2)
655 return(false);
656
657 //atom is connected to a nitrogen that has a total
658 //of 2 attached free oxygens
659 return(true);
660 }
661
662 bool OBAtom::IsHeteroatom()
663 {
664 switch(GetAtomicNum())
665 {
666 case 7:
667 case 8:
668 case 15:
669 case 16:
670 case 33:
671 case 34:
672 case 51:
673 case 52:
674 case 83:
675 case 84:
676 return(true);
677 }
678 return(false);
679 }
680
681 bool OBAtom::IsNotCorH()
682 {
683 switch(GetAtomicNum())
684 {
685 case 1:
686 case 6:
687 return(false);
688 }
689 return(true);
690 }
691
692 bool OBAtom::IsAromatic() const
693 {
694 if (((OBAtom*)this)->HasFlag(OB_AROMATIC_ATOM))
695 return(true);
696
697 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
698
699 if (!mol->HasAromaticPerceived())
700 {
701 aromtyper.AssignAromaticFlags(*mol);
702 if (((OBAtom*)this)->HasFlag(OB_AROMATIC_ATOM))
703 return(true);
704 }
705
706 return(false);
707 }
708
709 bool OBAtom::IsInRing() const
710 {
711 if (((OBAtom*)this)->HasFlag(OB_RING_ATOM))
712 return(true);
713
714 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
715 if (!mol->HasRingAtomsAndBondsPerceived())
716 {
717 mol->FindRingAtomsAndBonds();
718 if (((OBAtom*)this)->HasFlag(OB_RING_ATOM))
719 return(true);
720 }
721
722 return(false);
723 }
724
725 bool OBAtom::IsChiral()
726 {
727 if (HasFlag(OB_CHIRAL_ATOM))
728 return(true);
729
730 if (!((OBMol*)GetParent())->HasChiralityPerceived())
731 {
732 ((OBMol*)GetParent())->FindChiralCenters();
733 if (HasFlag(OB_CHIRAL_ATOM))
734 return(true);
735 }
736
737 return(false);
738 }
739
740 bool OBAtom::IsInRingSize(int size) const
741 {
742 vector<OBRing*> rlist;
743 vector<OBRing*>::iterator i;
744
745 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
746 if (!mol->HasSSSRPerceived())
747 mol->FindSSSR();
748
749 if (!((OBAtom*)this)->HasFlag(OB_RING_ATOM))
750 return(false);
751
752 rlist = mol->GetSSSR();
753 for (i = rlist.begin();i != rlist.end();i++)
754 if ((*i)->IsInRing(GetIdx()) && (*i)->PathSize() == size)
755 return(true);
756
757 return(false);
758 }
759
760 unsigned int OBAtom::MemberOfRingCount() const
761 {
762 vector<OBRing*> rlist;
763 vector<OBRing*>::iterator i;
764 unsigned int count=0;
765
766 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
767
768 if (!mol->HasSSSRPerceived())
769 mol->FindSSSR();
770
771 if (!((OBAtom*)this)->IsInRing())
772 return(0);
773
774 rlist = mol->GetSSSR();
775
776 for (i = rlist.begin();i != rlist.end();i++)
777 if ((*i)->IsInRing(GetIdx()))
778 count++;
779
780 return((unsigned int)count);
781 }
782
783 unsigned int OBAtom::MemberOfRingSize() const
784 {
785 vector<OBRing*> rlist;
786 vector<OBRing*>::iterator i;
787
788 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
789
790 if (!mol->HasSSSRPerceived())
791 mol->FindSSSR();
792
793 if (!((OBAtom*)this)->IsInRing())
794 return(0);
795
796 rlist = mol->GetSSSR();
797
798 for (i = rlist.begin();i != rlist.end();i++)
799 if ((*i)->IsInRing(GetIdx()))
800 return((*i)->Size());
801
802 return(0);
803 }
804
805 double OBAtom::SmallestBondAngle()
806 {
807 OBAtom *b, *c;
808 vector3 v1, v2;
809 double degrees, minDegrees;
810 // vector<OBNodeBase*>::iterator i;
811 vector<OBEdgeBase*>::iterator j,k;
812
813 minDegrees = 360.0;
814
815 for (b = BeginNbrAtom(j); b; b = NextNbrAtom(j))
816 {
817 k = j;
818 for (c = NextNbrAtom(k); c; c = NextNbrAtom(k))
819 {
820 v1 = b->GetVector() - GetVector();
821 v2 = c->GetVector() - GetVector();
822 degrees = vectorAngle(v1, v2);
823 if (degrees < minDegrees)
824 minDegrees = degrees;
825 }
826 }
827 return minDegrees;
828 }
829
830 double OBAtom::AverageBondAngle()
831 {
832 OBAtom *b, *c;
833 vector3 v1, v2;
834 double degrees, avgDegrees;
835 // vector<OBNodeBase*>::iterator i;
836 vector<OBEdgeBase*>::iterator j,k;
837 int n=0;
838
839 avgDegrees = 0.0;
840
841 for (b = BeginNbrAtom(j); b; b = NextNbrAtom(j))
842 {
843 k = j;
844 for (c = NextNbrAtom(k); c; c = NextNbrAtom(k))
845 {
846 v1 = b->GetVector() - GetVector();
847 v2 = c->GetVector() - GetVector();
848 degrees = vectorAngle(v1, v2);
849 avgDegrees += degrees;
850 n++;
851 }
852 }
853
854 if (n >=1)
855 avgDegrees /= n;
856
857 return avgDegrees;
858 }
859
860 unsigned int OBAtom::CountFreeOxygens() const
861 {
862 unsigned int count = 0;
863 OBAtom *atom;
864 OBBond *bond;
865 vector<OBEdgeBase*>::iterator i;
866
867 for (bond = ((OBAtom*)this)->BeginBond(i);bond;bond = ((OBAtom*)this)->NextBond(i))
868 {
869 atom = bond->GetNbrAtom((OBAtom*)this);
870 if (atom->IsOxygen() && atom->GetHvyValence() == 1)
871 count++;
872 }
873
874 return(count);
875 }
876
877 unsigned int OBAtom::BOSum() const
878 {
879 unsigned int bo;
880 unsigned int bosum=0;
881 OBBond *bond;
882 vector<OBEdgeBase*>::iterator i;
883
884 for (bond = ((OBAtom*)this)->BeginBond(i);bond;bond = ((OBAtom*)this)->NextBond(i))
885 {
886 bo = bond->GetBO();
887 bosum += (bo < 4) ? 2*bo : 3;
888 }
889
890 bosum /= 2;
891 return(bosum);
892 }
893
894 unsigned int OBAtom::KBOSum() const
895 {
896 OBBond *bond;
897 unsigned int bosum;
898 vector<OBEdgeBase*>::iterator i;
899
900 bosum = GetImplicitValence();
901
902 for (bond = ((OBAtom*)this)->BeginBond(i);bond;bond = ((OBAtom*)this)->NextBond(i))
903 {
904 if (bond->IsKDouble())
905 bosum++;
906 else if (bond->IsKTriple())
907 bosum += 2;
908 }
909
910 return(bosum);
911 }
912
913 unsigned int OBAtom::ImplicitHydrogenCount() const
914 {
915 //handles H,C,N,S,O,X
916 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
917 if (mol && !mol->HasImplicitValencePerceived())
918 atomtyper.AssignImplicitValence(*((OBMol*)((OBAtom*)this)->GetParent()));
919
920 int impval = _impval - GetHvyValence();
921 //Jan 05 Implicit valency now left alone; use spin multiplicity for implicit Hs
922 int mult = GetSpinMultiplicity();
923 if(mult==2) //radical
924 impval-=1;
925 else if(mult==1 || mult==3) //carbene
926 impval-=2;
927 return((impval>0)?impval:0);
928 }
929
930 unsigned int OBAtom::ExplicitHydrogenCount() const
931 {
932 int numH=0;
933 OBAtom *atom;
934 vector<OBEdgeBase*>::iterator i;
935 for (atom = ((OBAtom*)this)->BeginNbrAtom(i);atom;atom = ((OBAtom*)this)->NextNbrAtom(i))
936 if (atom->IsHydrogen())
937 numH++;
938
939 return(numH);
940 }
941
942 bool OBAtom::DeleteBond(OBBond *bond)
943 {
944 vector<OBEdgeBase*>::iterator i;
945 for (i = _vbond.begin();i != _vbond.end();i++)
946 if ((OBBond*)bond == *i)
947 {
948 _vbond.erase(i);
949 return(true);
950 }
951 return(false);
952 }
953
954 bool OBAtom::MatchesSMARTS(const char *pattern)
955 {
956 OBMol *mol = (OBMol*)((OBAtom*)this)->GetParent();
957 vector<vector<int> > mlist;
958 vector<vector<int> >::iterator l;
959
960 OBSmartsPattern test;
961 test.Init(pattern);
962 if (test.Match(*mol))
963 {
964 mlist = test.GetUMapList();
965 for (l = mlist.begin(); l != mlist.end(); l++)
966 if (GetIdx() == mol->GetAtom((*l)[0])->GetIdx())
967 return true;
968 }
969 return false;
970 }
971
972 OBBond *OBAtom::BeginBond(vector<OBEdgeBase*>::iterator &i)
973 {
974 i = _vbond.begin();
975 return((i == _vbond.end()) ? (OBBond*)NULL : (OBBond*)*i);
976 }
977
978 OBBond *OBAtom::NextBond(vector<OBEdgeBase*>::iterator &i)
979 {
980 i++;
981 return((i == _vbond.end()) ? (OBBond*)NULL : (OBBond*)*i);
982 }
983
984 OBAtom *OBAtom::BeginNbrAtom(vector<OBEdgeBase*>::iterator &i)
985 {
986 i = _vbond.begin();
987 return((i != _vbond.end()) ? ((OBBond*) *i)->GetNbrAtom(this):NULL);
988 }
989
990 OBAtom *OBAtom::NextNbrAtom(vector<OBEdgeBase*>::iterator &i)
991 {
992 i++;
993 return((i != _vbond.end()) ? ((OBBond*) *i)->GetNbrAtom(this):NULL);
994 }
995
996 double OBAtom::GetDistance(OBAtom *b)
997 {
998 return(( this->GetVector() - b->GetVector() ).length());
999 }
1000
1001 double OBAtom::GetDistance(int b)
1002 {
1003 OBMol *mol = (OBMol*)GetParent();
1004 return(( this->GetVector() - mol->GetAtom(b)->GetVector() ).length());
1005 }
1006
1007 double OBAtom::GetAngle(OBAtom *b, OBAtom *c)
1008 {
1009 vector3 v1,v2;
1010
1011 v1 = this->GetVector() - b->GetVector();
1012 v2 = c->GetVector() - b->GetVector();
1013
1014 return(vectorAngle(v1, v2));
1015 }
1016
1017 double OBAtom::GetAngle(int b, int c)
1018 {
1019 OBMol *mol = (OBMol*)GetParent();
1020 vector3 v1,v2;
1021
1022 v1 = this->GetVector() - mol->GetAtom(b)->GetVector();
1023 v2 = mol->GetAtom(c)->GetVector() - mol->GetAtom(b)->GetVector();
1024
1025 return(vectorAngle(v1, v2));
1026 }
1027
1028 bool OBAtom::GetNewBondVector(vector3 &v,double length)
1029 {
1030 // ***experimental code***
1031
1032 OBAtom *atom;
1033 vector<OBEdgeBase*>::iterator i,j;
1034 v = VZero;
1035
1036 if (GetValence() == 0)
1037 {
1038 v = VX;
1039 v *= length;
1040 v += GetVector();
1041 return(true);
1042 }
1043
1044 if (GetValence() == 1)
1045 {
1046 vector3 vtmp,v1,v2;
1047 atom = BeginNbrAtom(i);
1048 if (atom)
1049 vtmp = GetVector() - atom->GetVector();
1050
1051 if (GetHyb() == 2 || (IsOxygen() && HasAlphaBetaUnsat()))
1052 {
1053 bool quit = false;
1054 OBAtom *a1,*a2;
1055 v2 = VZero;
1056 for (a1 = BeginNbrAtom(i);a1 && !quit;a1 = NextNbrAtom(i))
1057 for (a2 = a1->BeginNbrAtom(j);a2 && !quit;a2 = a1->NextNbrAtom(j))
1058 if (a1 && a2 && a2 != this)
1059 {
1060 v2 = a1->GetVector() - a2->GetVector();
1061 quit = true;
1062 }
1063
1064 if (v2 == VZero)
1065 {
1066 v1 = cross(vtmp,VX);
1067 v2 = cross(vtmp,VY);
1068 if (v1.length() < v2.length())
1069 v1 = v2;
1070 }
1071 else
1072 v1 = cross(vtmp,v2);
1073
1074 matrix3x3 m;
1075 m.RotAboutAxisByAngle(v1,60.0);
1076 v = m*vtmp;
1077 v.normalize();
1078 }
1079 else if (GetHyb() == 3)
1080 {
1081 v1 = cross(vtmp,VX);
1082 v2 = cross(vtmp,VY);
1083 if (v1.length() < v2.length())
1084 v1 = v2;
1085 matrix3x3 m;
1086 m.RotAboutAxisByAngle(v1,70.5);
1087 v = m*vtmp;
1088 v.normalize();
1089 }
1090 if (GetHyb() == 1)
1091 v = vtmp;
1092
1093 v *= length;
1094 v += GetVector();
1095 return(true);
1096 }
1097
1098 if (GetValence() == 2)
1099 {
1100 vector3 v1,v2,vtmp,vsum,vnorm;
1101 atom = BeginNbrAtom(i);
1102 if (!atom)
1103 return(false);
1104 v1 = GetVector() - atom->GetVector();
1105 atom = NextNbrAtom(i);
1106 if (!atom)
1107 return(false);
1108 v2 = GetVector() - atom->GetVector();
1109 v1.normalize();
1110 v2.normalize();
1111 vsum = v1+v2;
1112 vsum.normalize();
1113
1114 if (GetHyb() == 2)
1115 v = vsum;
1116 else if (GetHyb() == 3)
1117 {
1118 vnorm = cross(v2,v1);
1119 vnorm.normalize();
1120
1121 #ifndef ONE_OVER_SQRT3
1122 #define ONE_OVER_SQRT3 0.57735026918962576451
1123 #endif //SQRT_TWO_THIRDS
1124 #ifndef SQRT_TWO_THIRDS
1125 #define SQRT_TWO_THIRDS 0.81649658092772603272
1126 #endif //ONE_OVER_SQRT3
1127
1128 vsum *= ONE_OVER_SQRT3;
1129 vnorm *= SQRT_TWO_THIRDS;
1130
1131 v = vsum + vnorm;
1132 }
1133
1134 v *= length;
1135
1136 v += GetVector();
1137 return(true);
1138 }
1139
1140 if (GetValence() == 3)
1141 {
1142 vector3 vtmp,vsum;
1143 OBAtom *atom;
1144 vector<OBEdgeBase*>::iterator i;
1145 for (atom = BeginNbrAtom(i);atom;atom = NextNbrAtom(i))
1146 {
1147 vtmp = GetVector() - atom->GetVector();
1148 vtmp.normalize();
1149 vtmp /= 3.0;
1150 vsum += vtmp;
1151 }
1152 vsum.normalize();
1153 v = vsum;
1154 v *= length;
1155 v += GetVector();
1156 return(true);
1157 }
1158
1159 return(true);
1160 }
1161
1162 bool OBAtom::HtoMethyl()
1163 {
1164 if (!IsHydrogen())
1165 return(false);
1166
1167 obErrorLog.ThrowError(__FUNCTION__,
1168 "Ran OpenBabel::HtoMethyl", obAuditMsg);
1169
1170 OBMol *mol = (OBMol*)GetParent();
1171
1172 mol->BeginModify();
1173
1174 SetAtomicNum(6);
1175 SetType("C3");
1176 SetHyb(3);
1177
1178 OBAtom *atom;
1179 OBBond *bond;
1180 vector<OBEdgeBase*>::iterator i;
1181 atom = BeginNbrAtom(i);
1182 bond = (OBBond *)*i;
1183 if (!atom)
1184 {
1185 mol->EndModify();
1186 return(false);
1187 }
1188
1189 double br1,br2;
1190 br1 = etab.CorrectedBondRad(6,3);
1191 br2 = etab.CorrectedBondRad(atom->GetAtomicNum(),atom->GetHyb());
1192 bond->SetLength(atom,br1+br2);
1193
1194 OBAtom *hatom;
1195 br2 = etab.CorrectedBondRad(1,0);
1196 vector3 v;
1197
1198 for (int j = 0;j < 3;j++)
1199 {
1200 hatom = mol->NewAtom();
1201 hatom->SetAtomicNum(1);
1202 hatom->SetType("H");
1203
1204 GetNewBondVector(v,br1+br2);
1205 hatom->SetVector(v);
1206 mol->AddBond(GetIdx(),mol->NumAtoms(),1);
1207 }
1208
1209 mol->EndModify();
1210 return(true);
1211 }
1212
1213 static void ApplyRotMatToBond(OBMol &mol,matrix3x3 &m,OBAtom *a1,OBAtom *a2)
1214 {
1215 vector<int> children;
1216 mol.FindChildren(children,a1->GetIdx(),a2->GetIdx());
1217 children.push_back(a2->GetIdx());
1218
1219 vector3 v;
1220 vector<int>::iterator i;
1221 for (i = children.begin();i != children.end();i++)
1222 {
1223 v = mol.GetAtom(*i)->GetVector();
1224 v -= a1->GetVector();
1225 v *= m;
1226 v += a1->GetVector();
1227 mol.GetAtom(*i)->SetVector(v);
1228 }
1229
1230 }
1231
1232 bool OBAtom::SetHybAndGeom(int hyb)
1233 {
1234 obErrorLog.ThrowError(__FUNCTION__,
1235 "Ran OpenBabel::SetHybridizationAndGeometry",
1236 obAuditMsg);
1237
1238 //if (hyb == GetHyb()) return(true);
1239 if (GetAtomicNum() == 1)
1240 return(false);
1241 if (hyb == 0 && GetHvyValence() > 1)
1242 return(false);
1243 if (hyb == 1 && GetHvyValence() > 2)
1244 return(false);
1245 if (hyb == 2 && GetHvyValence() > 3)
1246 return(false);
1247 if (hyb == 3 && GetHvyValence() > 4)
1248 return(false);
1249
1250 OBMol *mol = (OBMol*)GetParent();
1251
1252 OBAtom *nbr;
1253 vector<OBAtom*> delatm;
1254 vector<OBEdgeBase*>::iterator i;
1255
1256 for (nbr = BeginNbrAtom(i);nbr;nbr = NextNbrAtom(i))
1257 if (nbr->IsHydrogen())
1258 delatm.push_back(nbr);
1259
1260 //delete attached hydrogens
1261 mol->IncrementMod();
1262 vector<OBAtom*>::iterator j;
1263 for (j = delatm.begin();j != delatm.end();j++)
1264 mol->DeleteAtom(*j);
1265 mol->DecrementMod();
1266
1267 double targetAngle;
1268 if (hyb == 3)
1269 targetAngle = 109.5;
1270 else if (hyb == 2)
1271 targetAngle = 120.0;
1272 else if (hyb == 1)
1273 targetAngle = 180.0;
1274 else
1275 targetAngle = 0.0;
1276
1277 if (IsInRing())
1278 targetAngle = 180.0 - (360.0 / MemberOfRingSize());
1279
1280 //adjust attached acyclic bond lengths
1281 double br1,br2, length;
1282 br1 = etab.CorrectedBondRad(GetAtomicNum(),hyb);
1283 for (nbr = BeginNbrAtom(i);nbr;nbr = NextNbrAtom(i))
1284 if (!(*i)->IsInRing())
1285 {
1286 br2 = etab.CorrectedBondRad(nbr->GetAtomicNum(),nbr->GetHyb());
1287 length = br1 + br2;
1288 if ((*i)->IsAromatic())
1289 length *= 0.93;
1290 else if ((*i)->GetBO() == 2)
1291 length *= 0.91;
1292 else if ((*i)->GetBO() == 3)
1293 length *= 0.87;
1294 ((OBBond*) *i)->SetLength(this, length);
1295 }
1296
1297 if (GetValence() > 1)
1298 {
1299 double angle;
1300 matrix3x3 m;
1301 vector3 v1,v2,v3,v4,n,s;
1302 OBAtom *r1,*r2,*r3,*a1,*a2,*a3,*a4;
1303 r1 = r2 = r3 = a1 = a2 = a3 = a4 = NULL;
1304
1305 //find ring atoms first
1306 for (nbr = BeginNbrAtom(i);nbr;nbr = NextNbrAtom(i))
1307 if ((*i)->IsInRing())
1308 if (!r1)
1309 r1 = nbr;
1310 else if (!r2)
1311 r2 = nbr;
1312 else if (!r3)
1313 r3 = nbr;
1314
1315 //find non-ring atoms
1316 for (nbr = BeginNbrAtom(i);nbr;nbr = NextNbrAtom(i))
1317 if (!(*i)->IsInRing())
1318 if (!a1)
1319 a1 = nbr;
1320 else if (!a2)
1321 a2 = nbr;
1322 else if (!a3)
1323 a3 = nbr;
1324 else if (!a4)
1325 a4 = nbr;
1326
1327 //adjust geometries of heavy atoms according to hybridization
1328 if (hyb == 1)
1329 {
1330 if (a2)
1331 {
1332 v1 = a1->GetVector()-GetVector();
1333 v1.normalize();
1334 v2 = a2->GetVector()-GetVector();
1335 v2.normalize();
1336 n = cross(v1,v2);
1337 angle = vectorAngle(v1,v2)-targetAngle;
1338 m.RotAboutAxisByAngle(n,-angle);
1339 ApplyRotMatToBond(*mol,m,this,a1);
1340 }
1341 }
1342 else if (hyb == 2)
1343 {
1344 if (r1 && r2 && a1)
1345 {
1346 v1 = r1->GetVector()-GetVector();
1347 v1.normalize();
1348 v2 = r2->GetVector()-GetVector();
1349 v2.normalize();
1350 v3 = a1->GetVector()-GetVector();
1351 s = v1+v2;
1352 s.normalize();
1353 s *= -1.0;
1354 n = cross(s,v3);
1355 angle = vectorAngle(s,v3);
1356 m.RotAboutAxisByAngle(n,angle);
1357 ApplyRotMatToBond(*mol,m,this,a1);
1358 }
1359 else
1360 {
1361 if (a2)
1362 {
1363 v1 = a1->GetVector()-GetVector();
1364 v1.normalize();
1365 v2 = a2->GetVector()-GetVector();
1366 v2.normalize();
1367 n = cross(v1,v2);
1368 angle = vectorAngle(v1,v2)-targetAngle;
1369 m.RotAboutAxisByAngle(n,-angle);
1370 ApplyRotMatToBond(*mol,m,this,a1);
1371 }
1372 if (a3)
1373 {
1374 v1 = a1->GetVector()-GetVector();
1375 v1.normalize();
1376 v2 = a2->GetVector()-GetVector();
1377 v2.normalize();
1378 v3 = a3->GetVector()-GetVector();
1379 s = v1+v2;
1380 s.normalize();
1381 s *= -1.0;
1382 n = cross(s,v3);
1383 angle = vectorAngle(s,v3);
1384 m.RotAboutAxisByAngle(n,angle);
1385 ApplyRotMatToBond(*mol,m,this,a3);
1386 }
1387 }
1388 }
1389 else if (hyb == 3)
1390 {
1391 if (r1 && r2 && r3 && a1)
1392 {
1393 v1 = r1->GetVector()-GetVector();
1394 v1.normalize();
1395 v2 = r2->GetVector()-GetVector();
1396 v2.normalize();
1397 v3 = r3->GetVector()-GetVector();
1398 v3.normalize();
1399 v4 = a1->GetVector()-GetVector();
1400 s = v1 + v2 + v3;
1401 s *= -1.0;
1402 s.normalize();
1403 n = cross(s,v4);
1404 angle = vectorAngle(s,v4);
1405 m.RotAboutAxisByAngle(n,angle);
1406 ApplyRotMatToBond(*mol,m,this,a1);
1407 }
1408 else if (r1 && r2 && !r3 && a1)
1409 {
1410 v1 = r1->GetVector()-GetVector();
1411 v1.normalize();
1412 v2 = r2->GetVector()-GetVector();
1413 v2.normalize();
1414 v3 = a1->GetVector()-GetVector();
1415 s = v1+v2;
1416 s *= -1.0;
1417 s.normalize();
1418 n = cross(v1,v2);
1419 n.normalize();
1420 s *= ONE_OVER_SQRT3; //1/sqrt(3)
1421 n *= SQRT_TWO_THIRDS; //sqrt(2/3)
1422 s += n;
1423 s.normalize();
1424 n = cross(s,v3);
1425 angle = vectorAngle(s,v3);
1426 m.RotAboutAxisByAngle(n,angle);
1427 ApplyRotMatToBond(*mol,m,this,a1);
1428
1429 if (a2)
1430 {
1431 v1 = r1->GetVector()-GetVector();
1432 v1.normalize();
1433 v2 = r2->GetVector()-GetVector();
1434 v2.normalize();
1435 v3 = a1->GetVector()-GetVector();
1436 v3.normalize();
1437 v4 = a2->GetVector()-GetVector();
1438 s = v1 + v2 + v3;
1439 s *= -1.0;
1440 s.normalize();
1441 n = cross(s,v4);
1442 angle = vectorAngle(s,v4);
1443 m.RotAboutAxisByAngle(n,angle);
1444 ApplyRotMatToBond(*mol,m,this,a2);
1445 }
1446 }
1447 else
1448 {
1449 if (a2)
1450 {
1451 v1 = a1->GetVector()-GetVector();
1452 v1.normalize();
1453 v2 = a2->GetVector()-GetVector();
1454 v2.normalize();
1455 n = cross(v1,v2);
1456 angle = vectorAngle(v1,v2)-targetAngle;
1457 m.RotAboutAxisByAngle(n,-angle);
1458 ApplyRotMatToBond(*mol,m,this,a1);
1459 }
1460 if (a3)
1461 {
1462 v1 = a1->GetVector()-GetVector();
1463 v1.normalize();
1464 v2 = a2->GetVector()-GetVector();
1465 v2.normalize();
1466 v3 = a3->GetVector()-GetVector();
1467 s = v1+v2;
1468 s *= -1.0;
1469 s.normalize();
1470 n = cross(v1,v2);
1471 n.normalize();
1472 s *= ONE_OVER_SQRT3; //1/sqrt(3)
1473 n *= SQRT_TWO_THIRDS; //sqrt(2/3)
1474 s += n;
1475 s.normalize();
1476 n = cross(s,v3);
1477 angle = vectorAngle(s,v3);
1478 m.RotAboutAxisByAngle(n,angle);
1479 ApplyRotMatToBond(*mol,m,this,a3);
1480 }
1481 }
1482 }
1483 }
1484
1485 //add hydrogens back to atom
1486 int impval=1;
1487 switch (GetAtomicNum())
1488 {
1489 case 6:
1490 if (hyb == 3)
1491 impval = 4;
1492 if (hyb == 2)
1493 impval = 3;
1494 if (hyb == 1)
1495 impval = 2;
1496 break;
1497 case 7:
1498 if (hyb == 3)
1499 impval = 3;
1500 if (hyb == 2)
1501 impval = 2;
1502 if (hyb == 1)
1503 impval = 1;
1504 break;
1505 case 8:
1506 if (hyb == 3)
1507 impval = 2;
1508 if (hyb == 2)
1509 impval = 2;
1510 if (hyb == 1)
1511 impval = 2;
1512 case 16:
1513 if (hyb == 3)
1514 impval = 2;
1515 if (hyb == 2)
1516 impval = 2;
1517 if (hyb == 1)
1518 impval = 0;
1519 break;
1520 case 15:
1521 if (hyb == 3)
1522 impval = 4;
1523 if (hyb == 2)
1524 impval = 3;
1525 if (hyb == 1)
1526 impval = 2;
1527 break;
1528 default:
1529 impval = 1;
1530 }
1531
1532 int hcount = impval-GetHvyValence();
1533 if (hcount)
1534 {
1535 int k;
1536 vector3 v;
1537 OBAtom *atom;
1538 double brsum = etab.CorrectedBondRad(1,0)+
1539 etab.CorrectedBondRad(GetAtomicNum(),GetHyb());
1540 SetHyb(hyb);
1541
1542 mol->BeginModify();
1543 for (k = 0;k < hcount;k++)
1544 {
1545 GetNewBondVector(v,brsum);
1546 atom = mol->NewAtom();
1547 atom->SetAtomicNum(1);
1548 atom->SetType("H");
1549 atom->SetVector(v);
1550 mol->AddBond(atom->GetIdx(),GetIdx(),1);
1551 }
1552 mol->EndModify();
1553 }
1554
1555
1556 return(true);
1557 }
1558
1559 OBBond *OBAtom::GetBond(OBAtom *nbr)
1560 {
1561 OBBond *bond;
1562 vector<OBEdgeBase *>::iterator i;
1563 for (bond = BeginBond(i) ; bond ; bond = NextBond(i))
1564 if (bond->GetNbrAtom(this) == nbr)
1565 return bond;
1566 return NULL;
1567 }
1568
1569 // OBGenericData methods
1570 bool OBAtom::HasData(string &s)
1571 //returns true if the generic attribute/value pair exists
1572 {
1573 if (_vdata.empty())
1574 return(false);
1575
1576 vector<OBGenericData*>::iterator i;
1577
1578 for (i = _vdata.begin();i != _vdata.end();i++)
1579 if ((*i)->GetAttribute() == s)
1580 return(true);
1581
1582 return(false);
1583 }
1584
1585 bool OBAtom::HasData(const char *s)
1586 //returns true if the generic attribute/value pair exists
1587 {
1588 if (_vdata.empty())
1589 return(false);
1590
1591 vector<OBGenericData*>::iterator i;
1592
1593 for (i = _vdata.begin();i != _vdata.end();i++)
1594 if ((*i)->GetAttribute() == s)
1595 return(true);
1596
1597 return(false);
1598 }
1599
1600 bool OBAtom::HasData(unsigned int dt)
1601 //returns true if the generic attribute/value pair exists
1602 {
1603 if (_vdata.empty())
1604 return(false);
1605
1606 vector<OBGenericData*>::iterator i;
1607
1608 for (i = _vdata.begin();i != _vdata.end();i++)
1609 if ((*i)->GetDataType() == dt)
1610 return(true);
1611
1612 return(false);
1613 }
1614
1615 OBGenericData *OBAtom::GetData(string &s)
1616 //returns the value given an attribute
1617 {
1618 vector<OBGenericData*>::iterator i;
1619
1620 for (i = _vdata.begin();i != _vdata.end();i++)
1621 if ((*i)->GetAttribute() == s)
1622 return(*i);
1623
1624 return(NULL);
1625 }
1626
1627 OBGenericData *OBAtom::GetData(const char *s)
1628 //returns the value given an attribute
1629 {
1630 vector<OBGenericData*>::iterator i;
1631
1632 for (i = _vdata.begin();i != _vdata.end();i++)
1633 if ((*i)->GetAttribute() == s)
1634 return(*i);
1635
1636 return(NULL);
1637 }
1638
1639 OBGenericData *OBAtom::GetData(unsigned int dt)
1640 {
1641 vector<OBGenericData*>::iterator i;
1642 for (i = _vdata.begin();i != _vdata.end();i++)
1643 if ((*i)->GetDataType() == dt)
1644 return(*i);
1645 return(NULL);
1646 }
1647
1648 void OBAtom::DeleteData(unsigned int dt)
1649 {
1650 vector<OBGenericData*> vdata;
1651 vector<OBGenericData*>::iterator i;
1652 for (i = _vdata.begin();i != _vdata.end();i++)
1653 if ((*i)->GetDataType() == dt)
1654 delete *i;
1655 else
1656 vdata.push_back(*i);
1657 _vdata = vdata;
1658 }
1659
1660 void OBAtom::DeleteData(vector<OBGenericData*> &vg)
1661 {
1662 vector<OBGenericData*> vdata;
1663 vector<OBGenericData*>::iterator i,j;
1664
1665 bool del;
1666 for (i = _vdata.begin();i != _vdata.end();i++)
1667 {
1668 del = false;
1669 for (j = vg.begin();j != vg.end();j++)
1670 if (*i == *j)
1671 {
1672 del = true;
1673 break;
1674 }
1675 if (del)
1676 delete *i;
1677 else
1678 vdata.push_back(*i);
1679 }
1680 _vdata = vdata;
1681 }
1682
1683 void OBAtom::DeleteData(OBGenericData *gd)
1684 {
1685 vector<OBGenericData*>::iterator i;
1686 for (i = _vdata.begin();i != _vdata.end();i++)
1687 if (*i == gd)
1688 {
1689 delete *i;
1690 _vdata.erase(i);
1691 }
1692
1693 }
1694
1695 bool OBAtom::IsHbondAcceptor()
1696 {
1697 return _ele == 7 || _ele == 8 || _ele == 9 ;
1698 }
1699
1700 bool OBAtom::IsHbondDonor()
1701 {
1702 return MatchesSMARTS("[$([#8,#7H,#9;!H0])]");
1703 }
1704
1705 bool OBAtom::IsHbondDonorH()
1706 {
1707 if (!IsHydrogen()) return(false);
1708
1709 OBAtom *atom;
1710 OBBond *bond;
1711 vector<OBEdgeBase*>::iterator i;
1712 for (bond = BeginBond(i);bond;bond = NextBond(i))
1713 {
1714 atom = bond->GetNbrAtom(this);
1715 if (atom->GetAtomicNum() == 7) return(true);
1716 if (atom->GetAtomicNum() == 8) return(true);
1717 if (atom->GetAtomicNum() == 9) return(true);
1718 }
1719
1720 return(false);
1721 }
1722
1723 } // end namespace OpenBabel
1724
1725 //! \file atom.cpp
1726 //! \brief Handle OBAtom class