1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
// $Id$
//
// Copyright (C) 2001-2008 Greg Landrum and Rational Discovery LLC
//
// @@ All Rights Reserved @@
// This file is part of the RDKit.
// The contents are covered by the terms of the BSD license
// which is included in the file license.txt, found at the root
// of the RDKit source tree.
//
#include "ROMol.h"
#include "RWMol.h"
#include "Atom.h"
#include "Bond.h"
#include "MolOps.h"
#include "PeriodicTable.h"
#include "AtomIterators.h"
#include "BondIterators.h"
namespace RDKit {
// local utility namespace:
namespace {
bool isAtomConjugCand(const Atom *at) {
// the second check here is for Issue211, where the c-P bonds in
// Pc1ccccc1 were being marked as conjugated. This caused the P atom
// itself to be SP2 hybridized. This is wrong. For now we'll do a quick
// hack and forbid this check from adding conjugation to anything out of
// the first row of the periodic table. (Conjugation in aromatic rings
// has already been attended to, so this is safe.)
int nouter = PeriodicTable::getTable()->getNouterElecs(at->getAtomicNum());
if (((at->getAtomicNum() <= 10) || (nouter != 5 && nouter != 6) ||
(nouter == 6 && at->getTotalDegree() < 2)) &&
(MolOps::countAtomElec(at) > 0)) {
return true;
}
return false;
}
void markConjAtomBonds(Atom *at) {
if (!isAtomConjugCand(at)) return;
ROMol &mol = at->getOwningMol();
Atom *at2;
int atx = at->getIdx();
// make sure that have either 2 or 3 subtitutions on this atom
int sbo = at->getDegree() + at->getTotalNumHs();
if ((sbo < 2) || (sbo > 3)) {
return;
}
ROMol::OEDGE_ITER bnd1, end1, bnd2, end2;
boost::tie(bnd1, end1) = mol.getAtomBonds(at);
while (bnd1 != end1) {
if (mol[*bnd1]->getValenceContrib(at) < 1.5) {
bnd1++;
continue;
}
boost::tie(bnd2, end2) = mol.getAtomBonds(at);
while (bnd2 != end2) {
if (bnd1 == bnd2) {
bnd2++;
continue;
}
at2 = mol.getAtomWithIdx(mol[*bnd2]->getOtherAtomIdx(atx));
sbo = at2->getDegree() + at2->getTotalNumHs();
if (sbo > 3) {
bnd2++;
continue;
}
if (isAtomConjugCand(at2)) {
mol[*bnd1]->setIsConjugated(true);
mol[*bnd2]->setIsConjugated(true);
}
bnd2++;
}
bnd1++;
}
}
int numBondsPlusLonePairs(Atom *at) {
PRECONDITION(at, "bad atom");
int deg = at->getTotalDegree();
ROMol::OEDGE_ITER beg, end;
boost::tie(beg, end) = at->getOwningMol().getAtomBonds(at);
while (beg != end) {
Bond* bond = at->getOwningMol()[*beg];
if (bond->getBondType() == Bond::ZERO) --deg;
++beg;
}
if (at->getAtomicNum() <= 1) {
return deg;
}
int nouter = PeriodicTable::getTable()->getNouterElecs(at->getAtomicNum());
int totalValence = at->getExplicitValence() + at->getImplicitValence();
int chg = at->getFormalCharge();
int numFreeElectrons = nouter - (totalValence + chg);
if (totalValence + nouter - chg < 8) {
// we're below an octet, so we need to think
// about radicals:
int numRadicals = at->getNumRadicalElectrons();
int numLonePairs = (numFreeElectrons - numRadicals) / 2;
return deg + numLonePairs + numRadicals;
} else {
int numLonePairs = numFreeElectrons / 2;
return deg + numLonePairs;
}
}
} // end of utility namespace
namespace MolOps {
bool atomHasConjugatedBond(const Atom *at) {
PRECONDITION(at, "bad atom");
ROMol::OEDGE_ITER beg, end;
boost::tie(beg, end) = at->getOwningMol().getAtomBonds(at);
while (beg != end) {
if (at->getOwningMol()[*beg]->getIsConjugated()) return true;
beg++;
}
return false;
}
void setConjugation(ROMol &mol) {
// start with all bonds being marked unconjugated
// except for aromatic bonds
ROMol::BondIterator bi;
for (bi = mol.beginBonds(); bi != mol.endBonds(); bi++) {
if ((*bi)->getIsAromatic()) {
(*bi)->setIsConjugated(true);
} else {
(*bi)->setIsConjugated(false);
}
}
ROMol::AtomIterator ai;
// loop over each atom and check if the bonds connecting to it can
// be conjugated
for (ai = mol.beginAtoms(); ai != mol.endAtoms(); ai++) {
markConjAtomBonds(*ai);
}
}
void setHybridization(ROMol &mol) {
ROMol::AtomIterator ai;
int norbs;
for (ai = mol.beginAtoms(); ai != mol.endAtoms(); ai++) {
if ((*ai)->getAtomicNum() == 0) {
(*ai)->setHybridization(Atom::UNSPECIFIED);
} else {
norbs = numBondsPlusLonePairs(*ai);
switch (norbs) {
case 0:
// This occurs for things like Na+
(*ai)->setHybridization(Atom::S);
break;
case 1:
(*ai)->setHybridization(Atom::S);
break;
case 2:
(*ai)->setHybridization(Atom::SP);
break;
case 3:
(*ai)->setHybridization(Atom::SP2);
break;
case 4:
// potentially SP3, but we'll set it down to SP2
// if we have a conjugated bond (like the second O
// in O=CO)
// we'll also avoid setting the hybridization down to
// SP2 in the case of an atom with degree higher than 3
// (e.g. things like CP1(C)=CC=CN=C1C, where the P
// has norbs = 4, and a conjugated bond, but clearly should
// not be SP2)
// This is Issue276
if ((*ai)->getDegree() > 3 || !MolOps::atomHasConjugatedBond(*ai)) {
(*ai)->setHybridization(Atom::SP3);
} else {
(*ai)->setHybridization(Atom::SP2);
}
break;
case 5:
(*ai)->setHybridization(Atom::SP3D);
break;
case 6:
(*ai)->setHybridization(Atom::SP3D2);
break;
default:
(*ai)->setHybridization(Atom::UNSPECIFIED);
}
}
}
}
} // end of namespace MolOps
} // end of namespace RDKit
|