mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
@@ -264,45 +264,55 @@ void assignRadicals(RWMol &mol) {
|
||||
!atom->getAtomicNum()) {
|
||||
continue;
|
||||
}
|
||||
double accum = 0.0;
|
||||
RWMol::OEDGE_ITER beg, end;
|
||||
boost::tie(beg, end) = mol.getAtomBonds(atom);
|
||||
while (beg != end) {
|
||||
accum += mol[*beg]->getValenceContrib(atom);
|
||||
++beg;
|
||||
}
|
||||
accum += atom->getNumExplicitHs();
|
||||
int totalValence = static_cast<int>(accum + 0.1);
|
||||
const auto &valens =
|
||||
PeriodicTable::getTable()->getValenceList(atom->getAtomicNum());
|
||||
int chg = atom->getFormalCharge();
|
||||
int nOuter =
|
||||
PeriodicTable::getTable()->getNouterElecs(atom->getAtomicNum());
|
||||
int baseCount = 8;
|
||||
if (atom->getAtomicNum() == 1 || atom->getAtomicNum() == 2) {
|
||||
baseCount = 2;
|
||||
}
|
||||
if (valens.size() != 1 || valens[0] != -1) {
|
||||
double accum = 0.0;
|
||||
RWMol::OEDGE_ITER beg, end;
|
||||
boost::tie(beg, end) = mol.getAtomBonds(atom);
|
||||
while (beg != end) {
|
||||
accum += mol[*beg]->getValenceContrib(atom);
|
||||
++beg;
|
||||
}
|
||||
accum += atom->getNumExplicitHs();
|
||||
int totalValence = static_cast<int>(accum + 0.1);
|
||||
int baseCount = 8;
|
||||
if (atom->getAtomicNum() == 1 || atom->getAtomicNum() == 2) {
|
||||
baseCount = 2;
|
||||
}
|
||||
|
||||
// applies to later (more electronegative) elements:
|
||||
int numRadicals = baseCount - nOuter - totalValence + chg;
|
||||
if (numRadicals < 0) {
|
||||
numRadicals = 0;
|
||||
// can the atom be "hypervalent"? (was github #447)
|
||||
const INT_VECT &valens =
|
||||
PeriodicTable::getTable()->getValenceList(atom->getAtomicNum());
|
||||
if (valens.size() > 1) {
|
||||
for (auto val : valens) {
|
||||
if (val - totalValence + chg >= 0) {
|
||||
numRadicals = val - totalValence + chg;
|
||||
break;
|
||||
// applies to later (more electronegative) elements:
|
||||
int numRadicals = baseCount - nOuter - totalValence + chg;
|
||||
if (numRadicals < 0) {
|
||||
numRadicals = 0;
|
||||
// can the atom be "hypervalent"? (was github #447)
|
||||
const INT_VECT &valens =
|
||||
PeriodicTable::getTable()->getValenceList(atom->getAtomicNum());
|
||||
if (valens.size() > 1) {
|
||||
for (auto val : valens) {
|
||||
if (val - totalValence + chg >= 0) {
|
||||
numRadicals = val - totalValence + chg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// applies to earlier elements:
|
||||
int numRadicals2 = nOuter - totalValence - chg;
|
||||
if (numRadicals2 >= 0) {
|
||||
numRadicals = std::min(numRadicals, numRadicals2);
|
||||
}
|
||||
atom->setNumRadicalElectrons(numRadicals);
|
||||
} else {
|
||||
// if this is an atom where we have no preferred valence info at all,
|
||||
// e.g. for transition metals, then we shouldn't be guessing. This was
|
||||
// #3330
|
||||
auto nValence = nOuter - chg;
|
||||
atom->setNumRadicalElectrons(nValence % 2);
|
||||
}
|
||||
// applies to earlier elements:
|
||||
int numRadicals2 = nOuter - totalValence - chg;
|
||||
if (numRadicals2 >= 0) {
|
||||
numRadicals = std::min(numRadicals, numRadicals2);
|
||||
}
|
||||
atom->setNumRadicalElectrons(numRadicals);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1481,4 +1481,20 @@ TEST_CASE("needsHs function", "[chemistry]") {
|
||||
REQUIRE(m);
|
||||
CHECK(!MolOps::needsHs(*m));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"github #3330: incorrect number of radicals electrons calculated for "
|
||||
"metals",
|
||||
"[chemistry][metals]") {
|
||||
SECTION("basics") {
|
||||
std::vector<std::pair<std::string, unsigned int>> data = {
|
||||
{"[Mn+2]", 1}, {"[Mn+1]", 0}, {"[Mn]", 1}, {"[Mn-1]", 0},
|
||||
{"[C]", 4}, {"[C+1]", 3}, {"[C-1]", 3}};
|
||||
for (const auto &pr : data) {
|
||||
std::unique_ptr<ROMol> m(SmilesToMol(pr.first));
|
||||
REQUIRE(m);
|
||||
CHECK(m->getAtomWithIdx(0)->getNumRadicalElectrons() == pr.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user