mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
- implemented correct resonance structure sorting for degenerate cases
- moved classes that do not need being exposed in Resonance.h to Resonance.cpp - added the ALLOW_CHARGE_SEPARATION flag: now by default charge separation structures are not displayed if there's at least one structure with no charge separation - TODO * add SWIG wrappers * add a few test tp resMolSupplierTest.cpp
This commit is contained in:
@@ -14,6 +14,308 @@
|
||||
#include <RDGeneral/hash/hash.hpp>
|
||||
|
||||
namespace RDKit {
|
||||
// class definitions that do not need being exposed in Resonance.h
|
||||
class CEVect2 {
|
||||
public:
|
||||
CEVect2(CEMap &ceMap);
|
||||
ConjElectrons *getCE(unsigned int depth, unsigned int width);
|
||||
unsigned int ceCount() {
|
||||
return d_ceVect.size();
|
||||
}
|
||||
unsigned int depth() {
|
||||
return d_degVect.size();
|
||||
}
|
||||
void resize(unsigned int size);
|
||||
void idxToDepthWidth(unsigned int idx,
|
||||
unsigned int &d, unsigned int &w);
|
||||
unsigned int ceCountAtDepth(unsigned int depth);
|
||||
unsigned int ceCountUntilDepth(unsigned int depth);
|
||||
private:
|
||||
static bool resonanceStructureCompare
|
||||
(const ConjElectrons *a, const ConjElectrons *b);
|
||||
CEVect d_ceVect;
|
||||
std::vector<unsigned int> d_degVect;
|
||||
};
|
||||
|
||||
class CEMetrics {
|
||||
friend class ConjElectrons;
|
||||
public:
|
||||
CEMetrics();
|
||||
bool operator==(const CEMetrics& other);
|
||||
bool operator!=(const CEMetrics& other) {
|
||||
return !(*this == other);
|
||||
}
|
||||
private:
|
||||
unsigned int d_absFormalCharges;
|
||||
unsigned int d_fcSameSignDist;
|
||||
unsigned int d_fcOppSignDist;
|
||||
unsigned int d_nbMissing;
|
||||
boost::uint64_t d_wtdFormalCharges;
|
||||
};
|
||||
|
||||
class ConjElectrons {
|
||||
public:
|
||||
typedef enum {
|
||||
HAVE_CATION_RIGHT_OF_N = (1 << 0),
|
||||
HAVE_CATION = (1 << 1),
|
||||
HAVE_ANION = (1 << 2)
|
||||
} ConjElectronsFlags;
|
||||
typedef enum {
|
||||
FP_BONDS = (1 << 0),
|
||||
FP_ATOMS = (1 << 1)
|
||||
} FPFlags;
|
||||
ConjElectrons(ResonanceMolSupplier *parent,
|
||||
unsigned int groupIdx);
|
||||
ConjElectrons(const ConjElectrons &ce);
|
||||
~ConjElectrons();
|
||||
unsigned int groupIdx() const
|
||||
{
|
||||
return d_groupIdx;
|
||||
};
|
||||
unsigned int currElectrons() const
|
||||
{
|
||||
return d_currElectrons;
|
||||
};
|
||||
unsigned int totalElectrons() const
|
||||
{
|
||||
return d_totalElectrons;
|
||||
};
|
||||
void decrCurrElectrons(unsigned int d);
|
||||
AtomElectrons *getAtomElectronsWithIdx(unsigned int ai);
|
||||
BondElectrons *getBondElectronsWithIdx(unsigned int bi);
|
||||
int getAtomConjGrpIdx(unsigned int ai) const;
|
||||
int getBondConjGrpIdx(unsigned int bi) const;
|
||||
void pushToBeginStack(unsigned int ai);
|
||||
bool popFromBeginStack(unsigned int &ai);
|
||||
bool isBeginStackEmpty() {
|
||||
return d_beginAIStack.empty();
|
||||
};
|
||||
unsigned int lowestFcIndex() const;
|
||||
unsigned int lowestMultipleBondIndex() const;
|
||||
int allowedChgLeftOfN() const
|
||||
{
|
||||
return d_allowedChgLeftOfN;
|
||||
};
|
||||
void decrAllowedChgLeftOfN(int d)
|
||||
{
|
||||
d_allowedChgLeftOfN -= d;
|
||||
};
|
||||
int totalFormalCharge() const
|
||||
{
|
||||
return d_totalFormalCharge;
|
||||
};
|
||||
bool hasCationRightOfN() const
|
||||
{
|
||||
return static_cast<bool>(d_flags & HAVE_CATION_RIGHT_OF_N);
|
||||
};
|
||||
bool hasChargeSeparation() const
|
||||
{
|
||||
return static_cast<bool>((d_flags & HAVE_CATION)
|
||||
&& (d_flags & HAVE_ANION));
|
||||
};
|
||||
unsigned int absFormalCharges() const {
|
||||
return d_ceMetrics.d_absFormalCharges;
|
||||
};
|
||||
unsigned int fcSameSignDist() const
|
||||
{
|
||||
return d_ceMetrics.d_fcSameSignDist;
|
||||
};
|
||||
unsigned int fcOppSignDist() const
|
||||
{
|
||||
return d_ceMetrics.d_fcOppSignDist;
|
||||
};
|
||||
unsigned int nbMissing() const
|
||||
{
|
||||
return d_ceMetrics.d_nbMissing;
|
||||
}
|
||||
CEMetrics &metrics() {
|
||||
return d_ceMetrics;
|
||||
}
|
||||
boost::uint64_t wtdFormalCharges() const {
|
||||
return d_ceMetrics.d_wtdFormalCharges;
|
||||
};
|
||||
void enumerateNonBonded(CEMap &ceMap);
|
||||
void initCeFromMol();
|
||||
void assignNonBonded();
|
||||
void assignFormalCharge();
|
||||
bool assignFormalChargesAndStore
|
||||
(CEMap &ceMap, unsigned int fpFlags);
|
||||
void assignBondsFormalChargesToMol(ROMol &mol);
|
||||
bool checkCharges();
|
||||
void computeMetrics();
|
||||
bool storeFP(CEMap &ceMap, unsigned int flags);
|
||||
ResonanceMolSupplier *parent() const
|
||||
{
|
||||
return d_parent;
|
||||
};
|
||||
private:
|
||||
unsigned int d_groupIdx;
|
||||
unsigned int d_totalElectrons;
|
||||
unsigned int d_currElectrons;
|
||||
unsigned int d_numFormalCharges;
|
||||
int d_totalFormalCharge;
|
||||
int d_allowedChgLeftOfN;
|
||||
boost::uint8_t d_flags;
|
||||
CEMetrics d_ceMetrics;
|
||||
ConjBondMap d_conjBondMap;
|
||||
ConjAtomMap d_conjAtomMap;
|
||||
std::stack<unsigned int> d_beginAIStack;
|
||||
ResonanceMolSupplier *d_parent;
|
||||
ConjElectrons &operator=(const ConjElectrons&);
|
||||
unsigned int countTotalElectrons();
|
||||
void computeDistFormalCharges();
|
||||
void checkOctets();
|
||||
};
|
||||
|
||||
class CEVect2Store {
|
||||
public:
|
||||
CEVect2Store(CEVect &ceVect);
|
||||
unsigned int ceCount() {
|
||||
return d_ceCount;
|
||||
}
|
||||
ConjElectrons *getCE(unsigned int i, unsigned int j);
|
||||
private:
|
||||
unsigned int d_ceCount;
|
||||
CEVect2 d_ceVect2;
|
||||
};
|
||||
|
||||
class AtomElectrons {
|
||||
public:
|
||||
typedef enum {
|
||||
LAST_BOND = (1 << 0),
|
||||
DEFINITIVE = (1 << 1),
|
||||
STACKED = (1 << 2)
|
||||
} AtomElectronsFlags;
|
||||
typedef enum {
|
||||
NEED_CHARGE_BIT = 1
|
||||
} AllowedBondFlag;
|
||||
AtomElectrons(ConjElectrons *parent, const Atom *a);
|
||||
AtomElectrons(ConjElectrons *parent, const AtomElectrons &ae);
|
||||
~AtomElectrons() {};
|
||||
boost::uint8_t findAllowedBonds(unsigned int bi);
|
||||
bool hasOctet() const
|
||||
{
|
||||
return ((d_nb + d_tv * 2) == 8);
|
||||
};
|
||||
bool isLastBond() const
|
||||
{
|
||||
return (d_flags & LAST_BOND);
|
||||
};
|
||||
void setLastBond() {
|
||||
d_flags |= LAST_BOND;
|
||||
};
|
||||
bool isDefinitive() const
|
||||
{
|
||||
return (d_flags & DEFINITIVE);
|
||||
};
|
||||
void setDefinitive()
|
||||
{
|
||||
d_flags |= DEFINITIVE;
|
||||
};
|
||||
bool isStacked() const
|
||||
{
|
||||
return (d_flags & STACKED);
|
||||
};
|
||||
void setStacked() {
|
||||
d_flags |= STACKED;
|
||||
};
|
||||
void clearStacked() {
|
||||
d_flags &= ~STACKED;
|
||||
};
|
||||
unsigned int conjGrpIdx() const
|
||||
{
|
||||
return d_parent->parent()->getAtomConjGrpIdx(d_atom->getIdx());
|
||||
};
|
||||
void finalizeAtom();
|
||||
unsigned int nb() const
|
||||
{
|
||||
return d_nb;
|
||||
};
|
||||
unsigned int tv() const
|
||||
{
|
||||
return d_tv;
|
||||
};
|
||||
unsigned int oe() const
|
||||
{
|
||||
return PeriodicTable::getTable()->getNouterElecs
|
||||
(d_atom->getAtomicNum());
|
||||
};
|
||||
int fc() const
|
||||
{
|
||||
return d_fc;
|
||||
};
|
||||
void tvIncr(unsigned int i) {
|
||||
d_tv += i;
|
||||
};
|
||||
unsigned int neededNbForOctet() const
|
||||
{
|
||||
return (8 - (2 * d_tv + d_nb));
|
||||
}
|
||||
const Atom *atom()
|
||||
{
|
||||
return d_atom;
|
||||
}
|
||||
void initTvNbFcFromAtom();
|
||||
void assignNonBonded(unsigned int nb) {
|
||||
d_nb = nb;
|
||||
}
|
||||
void assignFormalCharge() {
|
||||
d_fc = oe() - (d_nb + d_tv);
|
||||
}
|
||||
bool isNbrCharged(unsigned int bo, unsigned int oeConstraint = 0);
|
||||
private:
|
||||
boost::uint8_t d_nb;
|
||||
boost::uint8_t d_tv;
|
||||
boost::int8_t d_fc;
|
||||
boost::uint8_t d_flags;
|
||||
const Atom *d_atom;
|
||||
ConjElectrons *d_parent;
|
||||
AtomElectrons &operator=(const AtomElectrons&);
|
||||
boost::uint8_t canAddBondWithOrder(unsigned int bi,
|
||||
unsigned int bo);
|
||||
void allConjBondsDefinitiveBut(unsigned int bi);
|
||||
};
|
||||
|
||||
class BondElectrons {
|
||||
public:
|
||||
typedef enum {
|
||||
DEFINITIVE = (1 << 0)
|
||||
} BondElectronsFlags;
|
||||
BondElectrons(ConjElectrons *parent, const Bond *b);
|
||||
BondElectrons(ConjElectrons *parent, const BondElectrons &be);
|
||||
~BondElectrons() {};
|
||||
bool isDefinitive() const
|
||||
{
|
||||
return (d_flags & DEFINITIVE);
|
||||
};
|
||||
void setDefinitive() {
|
||||
d_flags |= DEFINITIVE;
|
||||
};
|
||||
int conjGrpIdx() const
|
||||
{
|
||||
return d_parent->getBondConjGrpIdx(d_bond->getIdx());
|
||||
};
|
||||
void setOrder(unsigned int bo);
|
||||
unsigned int order() const
|
||||
{
|
||||
return d_bo;
|
||||
};
|
||||
unsigned int orderFromBond();
|
||||
void initOrderFromBond()
|
||||
{
|
||||
d_bo = orderFromBond();
|
||||
};
|
||||
const Bond *bond() {
|
||||
return d_bond;
|
||||
};
|
||||
private:
|
||||
boost::uint8_t d_bo;
|
||||
boost::uint8_t d_flags;
|
||||
const Bond *d_bond;
|
||||
ConjElectrons *d_parent;
|
||||
BondElectrons &operator=(const BondElectrons&);
|
||||
};
|
||||
|
||||
namespace ResonanceUtils {
|
||||
// depending on the number of atoms which won't have a complete
|
||||
// octet (nCandSlots) and the number of those which need non-bonded
|
||||
@@ -60,8 +362,7 @@ namespace RDKit {
|
||||
(*ai)->updatePropertyCache();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // end of namespace ResonanceUtils
|
||||
|
||||
// object constructor
|
||||
AtomElectrons::AtomElectrons(ConjElectrons *parent, const Atom *a) :
|
||||
@@ -284,6 +585,24 @@ namespace RDKit {
|
||||
d_bo = bo;
|
||||
}
|
||||
|
||||
CEMetrics::CEMetrics() :
|
||||
d_absFormalCharges(0),
|
||||
d_fcSameSignDist(0),
|
||||
d_fcOppSignDist(0),
|
||||
d_nbMissing(0),
|
||||
d_wtdFormalCharges(0)
|
||||
{
|
||||
};
|
||||
|
||||
bool CEMetrics::operator==(const CEMetrics& other)
|
||||
{
|
||||
return ((d_absFormalCharges == other.d_absFormalCharges)
|
||||
&& (d_fcSameSignDist == other.d_fcSameSignDist)
|
||||
&& (d_fcOppSignDist == other.d_fcOppSignDist)
|
||||
&& (d_nbMissing == other.d_nbMissing)
|
||||
&& (d_wtdFormalCharges == other.d_wtdFormalCharges));
|
||||
}
|
||||
|
||||
// object constructor
|
||||
ConjElectrons::ConjElectrons(ResonanceMolSupplier *parent,
|
||||
unsigned int groupIdx) :
|
||||
@@ -291,11 +610,6 @@ namespace RDKit {
|
||||
d_totalElectrons(0),
|
||||
d_numFormalCharges(0),
|
||||
d_totalFormalCharge(0),
|
||||
d_absFormalCharges(0),
|
||||
d_fcSameSignDist(0),
|
||||
d_fcOppSignDist(0),
|
||||
d_nbMissing(0),
|
||||
d_wtdFormalCharges(0.0),
|
||||
d_flags(0),
|
||||
d_parent(parent)
|
||||
{
|
||||
@@ -337,11 +651,7 @@ namespace RDKit {
|
||||
d_numFormalCharges(ce.d_numFormalCharges),
|
||||
d_totalFormalCharge(ce.d_totalFormalCharge),
|
||||
d_allowedChgLeftOfN(ce.d_allowedChgLeftOfN),
|
||||
d_absFormalCharges(ce.d_absFormalCharges),
|
||||
d_fcSameSignDist(ce.d_fcSameSignDist),
|
||||
d_fcOppSignDist(ce.d_fcOppSignDist),
|
||||
d_nbMissing(ce.d_nbMissing),
|
||||
d_wtdFormalCharges(ce.d_wtdFormalCharges),
|
||||
d_ceMetrics(ce.d_ceMetrics),
|
||||
d_flags(ce.d_flags),
|
||||
d_beginAIStack(ce.d_beginAIStack),
|
||||
d_parent(ce.d_parent)
|
||||
@@ -491,6 +801,10 @@ namespace RDKit {
|
||||
// formal charges should be between -2 and +1
|
||||
areAcceptable = ((ae->fc() < 2) && (ae->fc() > -3));
|
||||
if (areAcceptable) {
|
||||
if (ae->fc() > 0)
|
||||
d_flags |= HAVE_CATION;
|
||||
else if (ae->fc() < 0)
|
||||
d_flags |= HAVE_ANION;
|
||||
if (ae->oe() > 4) {
|
||||
if (!ae->hasOctet())
|
||||
haveIncompleteOctetRightOfC = true;
|
||||
@@ -550,7 +864,7 @@ namespace RDKit {
|
||||
return areAcceptable;
|
||||
}
|
||||
|
||||
// assign formal charges and, if the latter acceptable, store
|
||||
// assign formal charges and, if they are acceptable, store
|
||||
// return true if FPs did not already exist in ceMap, false if they did
|
||||
bool ConjElectrons::assignFormalChargesAndStore
|
||||
(CEMap &ceMap, unsigned int fpFlags)
|
||||
@@ -650,29 +964,29 @@ namespace RDKit {
|
||||
|
||||
void ConjElectrons::computeMetrics()
|
||||
{
|
||||
// Electronegativity according to the Allen scale
|
||||
// 1000 * Electronegativity according to the Allen scale
|
||||
// (Allen, L.C. J. Am. Chem. Soc. 1989, 111, 9003-9014)
|
||||
static const double en[] = {
|
||||
2.300, 4.160, 0.912, 1.576, 2.051, 2.544, 3.066, 3.610,
|
||||
4.193, 4.789, 0.869, 1.293, 1.613, 1.916, 2.253, 2.589,
|
||||
2.869, 3.242, 0.734, 1.034, 1.19, 1.38, 1.53, 1.65,
|
||||
1.75, 1.80, 1.84, 1.88, 1.85, 1.59, 1.756, 1.994,
|
||||
2.211, 2.434, 2.685, 2.966, 0.706, 0.963, 1.12, 1.32,
|
||||
1.41, 1.47, 1.51, 1.54, 1.56, 1.59, 1.87, 1.52,
|
||||
1.656, 1.824, 1.984, 2.158, 2.359, 2.582, 0.659, 0.881,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.09, 1.16,
|
||||
1.34, 1.47, 1.60, 1.65, 1.68, 1.72, 1.92, 1.76,
|
||||
1.789, 1.854, 2.01, 2.19, 2.39, 2.60, 0.67, 0.89
|
||||
static const unsigned int en[] = {
|
||||
2300, 4160, 912, 1576, 2051, 2544, 3066, 3610,
|
||||
4193, 4789, 869, 1293, 1613, 1916, 2253, 2589,
|
||||
2869, 3242, 734, 1034, 1190, 1380, 1530, 1650,
|
||||
1750, 1800, 1840, 1880, 1850, 1590, 1756, 1994,
|
||||
2211, 2434, 2685, 2966, 706, 963, 1120, 1320,
|
||||
1410, 1470, 1510, 1540, 1560, 1590, 1870, 1520,
|
||||
1656, 1824, 1984, 2158, 2359, 2582, 659, 881,
|
||||
1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000,
|
||||
1000, 1000, 1000, 1000, 1000, 1000, 1090, 1160,
|
||||
1340, 1470, 1600, 1650, 1680, 1720, 1920, 1760,
|
||||
1789, 1854, 2010, 2190, 2390, 2600, 670, 890
|
||||
};
|
||||
const unsigned int enSize = sizeof(en) / sizeof(double);
|
||||
for (ConjAtomMap::const_iterator it = d_conjAtomMap.begin();
|
||||
it != d_conjAtomMap.end(); ++it) {
|
||||
d_absFormalCharges += abs(it->second->fc());
|
||||
d_ceMetrics.d_absFormalCharges += abs(it->second->fc());
|
||||
int anIdx = it->second->atom()->getAtomicNum() - 1;
|
||||
d_wtdFormalCharges += static_cast<double>(it->second->fc())
|
||||
* ((anIdx >= enSize) ? 1.0 : en[anIdx]);
|
||||
d_nbMissing += it->second->neededNbForOctet();
|
||||
d_ceMetrics.d_wtdFormalCharges += (it->second->fc()
|
||||
* ((anIdx >= enSize) ? 1000 : en[anIdx]));
|
||||
d_ceMetrics.d_nbMissing += it->second->neededNbForOctet();
|
||||
}
|
||||
computeDistFormalCharges();
|
||||
}
|
||||
@@ -692,9 +1006,9 @@ namespace RDKit {
|
||||
unsigned int dist = MolOps::getShortestPath(d_parent->mol(),
|
||||
it1->first, it2->first).size();
|
||||
if ((it1->second->fc() * it2->second->fc()) > 0)
|
||||
d_fcSameSignDist += dist;
|
||||
d_ceMetrics.d_fcSameSignDist += dist;
|
||||
else
|
||||
d_fcOppSignDist += dist;
|
||||
d_ceMetrics.d_fcOppSignDist += dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -728,7 +1042,11 @@ namespace RDKit {
|
||||
// decrement the count of current electrons by d
|
||||
void ConjElectrons::decrCurrElectrons(unsigned int d)
|
||||
{
|
||||
PRECONDITION((d_currElectrons >= d), "d_currElectrons < d");
|
||||
if (d_currElectrons < d) {
|
||||
std::stringstream ss;
|
||||
ss << "d_currElectrons = " << d_currElectrons << ", d = " << d;
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
d_currElectrons -= d;
|
||||
}
|
||||
|
||||
@@ -755,6 +1073,123 @@ namespace RDKit {
|
||||
return ok;
|
||||
}
|
||||
|
||||
// function used to sort ConjElectrons objects based on their
|
||||
// importance to describe the structure; criteria in order of decreasing
|
||||
// priority follow:
|
||||
// 1) Number of unsatisfied octets
|
||||
// 2) Number of formal charges
|
||||
// 3) Number of formal charges weighted by atom electronegativity
|
||||
// 4) Distance between formal charges with the same sign
|
||||
// 5) Distance between formal charges with opposite signs
|
||||
// 6) Index of the first atom bearing a formal charge
|
||||
// 7) Index of the first multiple bond
|
||||
bool CEVect2::resonanceStructureCompare
|
||||
(const ConjElectrons *a, const ConjElectrons *b)
|
||||
{
|
||||
return ((a->nbMissing() != b->nbMissing())
|
||||
? (a->nbMissing() < b->nbMissing())
|
||||
: (a->absFormalCharges() != b->absFormalCharges())
|
||||
? (a->absFormalCharges() < b->absFormalCharges())
|
||||
: (a->wtdFormalCharges() != b->wtdFormalCharges())
|
||||
? (a->wtdFormalCharges() < b->wtdFormalCharges())
|
||||
: (a->fcSameSignDist() != b->fcSameSignDist())
|
||||
? (a->fcSameSignDist() > b->fcSameSignDist())
|
||||
: (a->fcOppSignDist() != b->fcOppSignDist())
|
||||
? (a->fcOppSignDist() > b->fcOppSignDist())
|
||||
: (a->lowestFcIndex() != b->lowestFcIndex())
|
||||
? (a->lowestFcIndex() < b->lowestFcIndex())
|
||||
: (a->lowestMultipleBondIndex() < b->lowestMultipleBondIndex())
|
||||
);
|
||||
}
|
||||
|
||||
CEVect2::CEVect2(CEMap &ceMap)
|
||||
{
|
||||
d_ceVect.reserve(ceMap.size());
|
||||
for (CEMap::const_iterator it = ceMap.begin();
|
||||
it != ceMap.end(); ++it)
|
||||
d_ceVect.push_back(it->second);
|
||||
std::sort(d_ceVect.begin(), d_ceVect.end(),
|
||||
resonanceStructureCompare);
|
||||
bool first = true;
|
||||
unsigned int i = 0;
|
||||
CEMetrics metricsPrev;
|
||||
for (CEVect::const_iterator it = d_ceVect.begin();
|
||||
it != d_ceVect.end(); ++it) {
|
||||
if (first || ((*it)->metrics() != metricsPrev)) {
|
||||
metricsPrev = (*it)->metrics();
|
||||
d_degVect.push_back(1);
|
||||
}
|
||||
else
|
||||
++d_degVect.back();
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
ConjElectrons *CEVect2::getCE(unsigned int depth, unsigned int width)
|
||||
{
|
||||
if (depth >= d_degVect.size()) {
|
||||
std::stringstream ss;
|
||||
ss << "depth = " << depth << ", d_degVect.size() = " << d_degVect.size();
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
if (width >= d_degVect[depth]) {
|
||||
std::stringstream ss;
|
||||
ss << "width = " << width << ", d_degVect[" << depth << "] = "
|
||||
<< d_degVect[depth];
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
unsigned int i = 0;
|
||||
for (unsigned int d = 0; d < depth; ++d)
|
||||
i += d_degVect[d];
|
||||
i += width;
|
||||
return d_ceVect[i];
|
||||
}
|
||||
|
||||
void CEVect2::resize(unsigned int size)
|
||||
{
|
||||
d_ceVect.resize(size ? ceCountUntilDepth(size - 1) : 0);
|
||||
d_degVect.resize(size);
|
||||
}
|
||||
|
||||
unsigned int CEVect2::ceCountAtDepth(unsigned int depth)
|
||||
{
|
||||
if (depth >= d_degVect.size()) {
|
||||
std::stringstream ss;
|
||||
ss << "depth = " << depth << ", d_degVect.size() = " << d_degVect.size();
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
return d_degVect[depth];
|
||||
}
|
||||
|
||||
unsigned int CEVect2::ceCountUntilDepth(unsigned int depth)
|
||||
{
|
||||
if (depth >= d_degVect.size()) {
|
||||
std::stringstream ss;
|
||||
ss << "depth = " << depth << ", d_degVect.size() = " << d_degVect.size();
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
unsigned int i = 0;
|
||||
for (unsigned int d = 0; d <= depth; ++d)
|
||||
i += d_degVect[d];
|
||||
return i;
|
||||
}
|
||||
|
||||
void CEVect2::idxToDepthWidth(unsigned int idx,
|
||||
unsigned int &d, unsigned int &w)
|
||||
{
|
||||
if (idx >= d_ceVect.size()) {
|
||||
std::stringstream ss;
|
||||
ss << "idx = " << idx << ", d_ceVect.size() = " << d_ceVect.size();
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
d = 0;
|
||||
while (idx >= d_degVect[d]) {
|
||||
idx -= d_degVect[d];
|
||||
++d;
|
||||
}
|
||||
w = idx;
|
||||
}
|
||||
|
||||
// get the pointer to the BondElectrons object for bond having index bi
|
||||
BondElectrons *ConjElectrons::getBondElectronsWithIdx
|
||||
(unsigned int bi)
|
||||
@@ -786,47 +1221,41 @@ namespace RDKit {
|
||||
return d_totalElectrons;
|
||||
}
|
||||
|
||||
// sort CEVectVect by increasing size
|
||||
bool ResonanceMolSupplier::vectSizeCompare
|
||||
(const std::vector<ConjElectrons *> *a,
|
||||
const std::vector<ConjElectrons *> *b)
|
||||
{
|
||||
if (a->size() != b->size())
|
||||
return (a->size() < b->size());
|
||||
if (a->size() && b->size())
|
||||
return ((*a)[0]->groupIdx() < (*b)[0]->groupIdx());
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the total number of resonance structures exceeds d_maxStructs,
|
||||
// trim the number of ConjElectrons object for each conjugated group
|
||||
// to exclude the less likely structures and save memory
|
||||
// we are going to generate the complete resonance structures
|
||||
// combining the most likely ConjElectrons objects in a breadth-first
|
||||
// fashion
|
||||
void ResonanceMolSupplier::trimCeVectVect()
|
||||
void ResonanceMolSupplier::trimCeVect2()
|
||||
{
|
||||
if (d_length == d_maxStructs) {
|
||||
std::vector<unsigned int> s(d_nConjGrp, 0);
|
||||
std::vector<unsigned int> t(d_nConjGrp, 0);
|
||||
boost::uint64_t currSize = 0;
|
||||
while (currSize < d_length) {
|
||||
currSize = 1;
|
||||
for (unsigned int conjGrpIdx = 0; (currSize < d_length)
|
||||
&& (conjGrpIdx < d_nConjGrp); ++conjGrpIdx) {
|
||||
if (s[conjGrpIdx] < d_ceVect3[conjGrpIdx]->size())
|
||||
if (s[conjGrpIdx] < d_ceVect3[conjGrpIdx]->depth()) {
|
||||
t[conjGrpIdx] +=
|
||||
d_ceVect3[conjGrpIdx]->ceCountAtDepth(s[conjGrpIdx]);
|
||||
++s[conjGrpIdx];
|
||||
currSize *= s[conjGrpIdx];
|
||||
}
|
||||
currSize *= t[conjGrpIdx];
|
||||
}
|
||||
}
|
||||
for (unsigned int conjGrpIdx = 0;
|
||||
conjGrpIdx < d_nConjGrp; ++conjGrpIdx) {
|
||||
for (unsigned int i = s[conjGrpIdx];
|
||||
i < d_ceVect3[conjGrpIdx]->size(); ++i)
|
||||
delete (*(d_ceVect3[conjGrpIdx]))[i];
|
||||
for (unsigned int d = s[conjGrpIdx];
|
||||
d < d_ceVect3[conjGrpIdx]->depth(); ++d) {
|
||||
for (unsigned int w = 0;
|
||||
w < d_ceVect3[conjGrpIdx]->ceCountAtDepth(d); ++w)
|
||||
delete (d_ceVect3[conjGrpIdx]->getCE(d, w));
|
||||
}
|
||||
d_ceVect3[conjGrpIdx]->resize(s[conjGrpIdx]);
|
||||
}
|
||||
}
|
||||
//std::sort(d_ceVect3.begin(), d_ceVect3.end(), vectSizeCompare);
|
||||
}
|
||||
|
||||
// get the ConjElectrons indices to be combined given
|
||||
@@ -834,14 +1263,19 @@ namespace RDKit {
|
||||
void ResonanceMolSupplier::idxToCEPerm
|
||||
(unsigned int idx, std::vector<unsigned int> &c) const
|
||||
{
|
||||
// the c vector holds a pair of values for each ConjGrp,
|
||||
// namely depth and width where the ConjElectrons
|
||||
// object lies in the CEVect2 vector
|
||||
c.resize(d_nConjGrp * 2);
|
||||
unsigned int g = d_nConjGrp;
|
||||
while (g) {
|
||||
--g;
|
||||
unsigned int gt2 = g * 2;
|
||||
unsigned int d = 1;
|
||||
for (unsigned int j = 0; j < g; ++j) {
|
||||
d *= d_ceVect3[j]->size();
|
||||
d *= d_ceVect3[j]->ceCount();
|
||||
}
|
||||
c[g] = idx / d;
|
||||
d_ceVect3[g]->idxToDepthWidth(idx / d, c[gt2], c[gt2 + 1]);
|
||||
idx %= d;
|
||||
}
|
||||
}
|
||||
@@ -854,7 +1288,7 @@ namespace RDKit {
|
||||
{
|
||||
unsigned int aSum = 0;
|
||||
unsigned int bSum = 0;
|
||||
for (unsigned int i = 0; i < a->v.size(); ++i) {
|
||||
for (unsigned int i = 0; i < a->v.size(); i += 2) {
|
||||
aSum += a->v[i];
|
||||
bSum += b->v[i];
|
||||
}
|
||||
@@ -862,7 +1296,7 @@ namespace RDKit {
|
||||
return (aSum < bSum);
|
||||
unsigned int aMax = 0;
|
||||
unsigned int bMax = 0;
|
||||
for (unsigned int i = 0; i < a->v.size(); ++i) {
|
||||
for (unsigned int i = 0; i < a->v.size(); i += 2) {
|
||||
if (!i || (a->v[i] > aMax))
|
||||
aMax = a->v[i];
|
||||
if (!i || (b->v[i] > bMax))
|
||||
@@ -870,7 +1304,13 @@ namespace RDKit {
|
||||
}
|
||||
if (aMax != bMax)
|
||||
return (aMax < bMax);
|
||||
for (unsigned int i = 0; i < a->v.size(); ++i) {
|
||||
for (unsigned int i = 0; i < a->v.size(); i += 2) {
|
||||
if (a->v[i] != b->v[i])
|
||||
return (a->v[i] < b->v[i]);
|
||||
}
|
||||
// if the other criteria didn't discriminate,
|
||||
// sort based on degenerate resonance structures
|
||||
for (unsigned int i = 1; i < a->v.size(); i += 2) {
|
||||
if (a->v[i] != b->v[i])
|
||||
return (a->v[i] < b->v[i]);
|
||||
}
|
||||
@@ -886,20 +1326,9 @@ namespace RDKit {
|
||||
for (unsigned int i = 0; i < d_length; ++i) {
|
||||
cePermVect[i] = new CEPerm;
|
||||
cePermVect[i]->idx = i;
|
||||
cePermVect[i]->v.resize(d_nConjGrp);
|
||||
idxToCEPerm(i, cePermVect[i]->v);
|
||||
}
|
||||
std::cerr << "unsorted" << std::endl;
|
||||
for (unsigned int i = 0; i < d_length; ++i) {
|
||||
for (unsigned int j = 0; j < d_nConjGrp; ++j)
|
||||
std::cerr << cePermVect[i]->v[j] << (j == d_nConjGrp - 1 ? "\n" : "\t");
|
||||
}
|
||||
std::sort(cePermVect.begin(), cePermVect.end(), cePermCompare);
|
||||
std::cerr << "\nsorted" << std::endl;
|
||||
for (unsigned int i = 0; i < d_length; ++i) {
|
||||
for (unsigned int j = 0; j < d_nConjGrp; ++j)
|
||||
std::cerr << cePermVect[i]->v[j] << (j == d_nConjGrp - 1 ? "\n" : "\t");
|
||||
}
|
||||
for (unsigned int i = 0; i < d_length; ++i) {
|
||||
d_enumIdx[i] = cePermVect[i]->idx;
|
||||
delete cePermVect[i];
|
||||
@@ -926,26 +1355,20 @@ namespace RDKit {
|
||||
buildCEMap(conjGrpIdx);
|
||||
storeCEMap(conjGrpIdx);
|
||||
}
|
||||
std::cerr << "1) d_length = " << d_length << std::endl;
|
||||
std::cerr << "d_ceVect3.size() = " << d_ceVect3.size() << std::endl;
|
||||
for (unsigned int i = 0; i < d_ceVect3.size(); ++i)
|
||||
std::cerr << i << "\t" << d_ceVect3[i]->size() << std::endl;
|
||||
trimCeVectVect();
|
||||
std::cerr << "after trimCeVectVect() d_ceVect3.size() = " << d_ceVect3.size() << std::endl;
|
||||
for (unsigned int i = 0; i < d_ceVect3.size(); ++i)
|
||||
std::cerr << i << "\t" << d_ceVect3[i]->size() << std::endl;
|
||||
trimCeVect2();
|
||||
prepEnumIdxVect();
|
||||
}
|
||||
|
||||
// object destructor
|
||||
ResonanceMolSupplier::~ResonanceMolSupplier()
|
||||
{
|
||||
for (CEVect2::const_iterator ceVect3It = d_ceVect3.begin();
|
||||
for (CEVect3::const_iterator ceVect3It = d_ceVect3.begin();
|
||||
ceVect3It != d_ceVect3.end();
|
||||
++ceVect3It) {
|
||||
for (std::vector<ConjElectrons *>::const_iterator
|
||||
ceIt = (*ceVect3It)->begin(); ceIt != (*ceVect3It)->end(); ++ceIt)
|
||||
delete(*ceIt);
|
||||
for (unsigned int d = 0; d < (*ceVect3It)->depth(); ++d) {
|
||||
for (unsigned int w = 0; w < (*ceVect3It)->ceCountAtDepth(d); ++w)
|
||||
delete((*ceVect3It)->getCE(d, w));
|
||||
}
|
||||
delete(*ceVect3It);
|
||||
}
|
||||
if (d_mol)
|
||||
@@ -1009,14 +1432,23 @@ namespace RDKit {
|
||||
unsigned int minNbMissing = 0;
|
||||
bool first = true;
|
||||
bool haveNoCationsRightOfN = false;
|
||||
bool haveNoChargeSeparation = false;
|
||||
for (CEMap::const_iterator it = d_ceMap.begin();
|
||||
(it != d_ceMap.end()); ++it) {
|
||||
if (first || (it->second->nbMissing() < minNbMissing)) {
|
||||
first = false;
|
||||
minNbMissing = it->second->nbMissing();
|
||||
}
|
||||
}
|
||||
for (CEMap::const_iterator it = d_ceMap.begin();
|
||||
(it != d_ceMap.end()); ++it) {
|
||||
if (!(d_flags & ALLOW_INCOMPLETE_OCTETS)
|
||||
&& (it->second->nbMissing() > minNbMissing))
|
||||
continue;
|
||||
if (!it->second->hasCationRightOfN())
|
||||
haveNoCationsRightOfN = true;
|
||||
if (!it->second->hasChargeSeparation())
|
||||
haveNoChargeSeparation = true;
|
||||
}
|
||||
for (CEMap::iterator it = d_ceMap.begin(); it != d_ceMap.end();) {
|
||||
// if the flag ALLOW_INCOMPLETE_OCTETS is not set, ConjElectrons
|
||||
@@ -1026,7 +1458,9 @@ namespace RDKit {
|
||||
if ((!(d_flags & ALLOW_INCOMPLETE_OCTETS)
|
||||
&& (it->second->nbMissing() > minNbMissing))
|
||||
|| (!(d_flags & UNCONSTRAINED_CATIONS)
|
||||
&& it->second->hasCationRightOfN() && haveNoCationsRightOfN)) {
|
||||
&& it->second->hasCationRightOfN() && haveNoCationsRightOfN)
|
||||
|| (!(d_flags & ALLOW_CHARGE_SEPARATION)
|
||||
&& it->second->hasChargeSeparation() && haveNoChargeSeparation)) {
|
||||
CEMap::iterator toBeDeleted = it;
|
||||
++it;
|
||||
delete(toBeDeleted->second);
|
||||
@@ -1037,35 +1471,6 @@ namespace RDKit {
|
||||
}
|
||||
}
|
||||
|
||||
// function used to sort ConjElectrons objects based on their
|
||||
// importance to describe the structure; criteria in order of decreasing
|
||||
// priority follow:
|
||||
// 1) Number of unsatisfied octets
|
||||
// 2) Number of formal charges
|
||||
// 3) Number of formal charges weighted by atom electronegativity
|
||||
// 4) Distance between formal charges with the same sign
|
||||
// 5) Distance between formal charges with opposite signs
|
||||
// 6) Index of the first atom bearing a formal charge
|
||||
// 7) Index of the first multiple bond
|
||||
bool ResonanceMolSupplier::resonanceStructureCompare
|
||||
(const ConjElectrons *a, const ConjElectrons *b)
|
||||
{
|
||||
return ((a->nbMissing() != b->nbMissing())
|
||||
? (a->nbMissing() < b->nbMissing())
|
||||
: (a->absFormalCharges() != b->absFormalCharges())
|
||||
? (a->absFormalCharges() < b->absFormalCharges())
|
||||
: (a->wtdFormalCharges() != b->wtdFormalCharges())
|
||||
? (a->wtdFormalCharges() < b->wtdFormalCharges())
|
||||
: (a->fcSameSignDist() != b->fcSameSignDist())
|
||||
? (a->fcSameSignDist() > b->fcSameSignDist())
|
||||
: (a->fcOppSignDist() != b->fcOppSignDist())
|
||||
? (a->fcOppSignDist() > b->fcOppSignDist())
|
||||
: (a->lowestFcIndex() != b->lowestFcIndex())
|
||||
? (a->lowestFcIndex() < b->lowestFcIndex())
|
||||
: (a->lowestMultipleBondIndex() < b->lowestMultipleBondIndex())
|
||||
);
|
||||
}
|
||||
|
||||
// function which enumerates all possible multiple bond arrangements
|
||||
// for each conjugated group, stores each arrangement in a ConjElectrons
|
||||
// object ans stores the latter in a map (d_ceMapTmp), keyed with its
|
||||
@@ -1265,8 +1670,12 @@ namespace RDKit {
|
||||
unsigned int ResonanceMolSupplier::getBondConjGrpIdx
|
||||
(unsigned int bi) const
|
||||
{
|
||||
PRECONDITION(bi < d_bondConjGrpIdx.size(),
|
||||
"bi >= d_bondConjGrpIdx.size()");
|
||||
if (bi >= d_bondConjGrpIdx.size()) {
|
||||
std::stringstream ss;
|
||||
ss << "d_bondConjGrpIdx.size() = " << d_bondConjGrpIdx.size()
|
||||
<< ", bi = " << bi;
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
return d_bondConjGrpIdx[bi];
|
||||
}
|
||||
|
||||
@@ -1275,8 +1684,12 @@ namespace RDKit {
|
||||
unsigned int ResonanceMolSupplier::getAtomConjGrpIdx
|
||||
(unsigned int ai) const
|
||||
{
|
||||
PRECONDITION(ai < d_atomConjGrpIdx.size(),
|
||||
"ai >= d_atomConjGrpIdx.size()");
|
||||
if (ai >= d_atomConjGrpIdx.size()) {
|
||||
std::stringstream ss;
|
||||
ss << "d_atomConjGrpIdx.size() = " << d_atomConjGrpIdx.size()
|
||||
<< ", ai = " << ai;
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
return d_atomConjGrpIdx[ai];
|
||||
}
|
||||
|
||||
@@ -1290,13 +1703,7 @@ namespace RDKit {
|
||||
// in the d_ceVect3 vector, and clears d_ceMapTmp and d_ceMap
|
||||
void ResonanceMolSupplier::storeCEMap(unsigned int conjGrpIdx)
|
||||
{
|
||||
d_ceVect3[conjGrpIdx] = new std::vector<ConjElectrons *>();
|
||||
d_ceVect3[conjGrpIdx]->reserve(d_ceMap.size());
|
||||
for (CEMap::const_iterator it = d_ceMap.begin();
|
||||
it != d_ceMap.end(); ++it)
|
||||
d_ceVect3[conjGrpIdx]->push_back(it->second);
|
||||
std::sort(d_ceVect3[conjGrpIdx]->begin(),
|
||||
d_ceVect3[conjGrpIdx]->end(), resonanceStructureCompare);
|
||||
d_ceVect3[conjGrpIdx] = new CEVect2(d_ceMap);
|
||||
if (d_length < d_maxStructs)
|
||||
d_length = std::min(d_maxStructs, d_length * d_ceMap.size());
|
||||
d_ceMapTmp.clear();
|
||||
@@ -1325,7 +1732,11 @@ namespace RDKit {
|
||||
// sets the ResonanceMolSupplier index to idx
|
||||
void ResonanceMolSupplier::moveTo(unsigned int idx)
|
||||
{
|
||||
PRECONDITION(idx < d_length, "idx >= d_length");
|
||||
if (idx >= d_length) {
|
||||
std::stringstream ss;
|
||||
ss << "d_length = " << d_length << ", idx = " << idx;
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
d_idx = idx;
|
||||
}
|
||||
|
||||
@@ -1335,8 +1746,12 @@ namespace RDKit {
|
||||
// likely complete resonance structures first
|
||||
ROMol *ResonanceMolSupplier::operator[](unsigned int idx) const
|
||||
{
|
||||
PRECONDITION(idx < d_length, "idx >= d_length");
|
||||
std::vector<unsigned int> c(d_nConjGrp);
|
||||
if (idx >= d_length) {
|
||||
std::stringstream ss;
|
||||
ss << "d_length = " << d_length << ", idx = " << idx;
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
std::vector<unsigned int> c;
|
||||
idxToCEPerm(d_enumIdx[idx], c);
|
||||
return assignBondsFormalCharges(c);
|
||||
}
|
||||
@@ -1349,7 +1764,8 @@ namespace RDKit {
|
||||
{
|
||||
for (unsigned int conjGrpIdx = 0;
|
||||
conjGrpIdx < d_nConjGrp; ++conjGrpIdx) {
|
||||
ConjElectrons *ce = (*d_ceVect3[conjGrpIdx])[c[conjGrpIdx]];
|
||||
unsigned int i = conjGrpIdx * 2;
|
||||
ConjElectrons *ce = d_ceVect3[conjGrpIdx]->getCE(c[i], c[i + 1]);
|
||||
ce->assignBondsFormalChargesToMol(mol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,11 @@ namespace RDKit {
|
||||
class BondElectrons;
|
||||
class AtomElectrons;
|
||||
class ConjElectrons;
|
||||
class CEVect2;
|
||||
typedef std::map<unsigned int, BondElectrons *> ConjBondMap;
|
||||
typedef std::map<unsigned int, AtomElectrons *> ConjAtomMap;
|
||||
typedef std::vector<std::vector<ConjElectrons *> *> CEVect2;
|
||||
typedef std::vector<ConjElectrons *> CEVect;
|
||||
typedef std::vector<CEVect2 *> CEVect3;
|
||||
typedef std::vector<boost::uint8_t> ConjFP;
|
||||
typedef boost::unordered_map<std::size_t, ConjElectrons *> CEMap;
|
||||
class ResonanceMolSupplier
|
||||
@@ -34,18 +36,21 @@ namespace RDKit {
|
||||
/*! include resonance structures whose octets are less complete
|
||||
* than the the most octet-complete structure */
|
||||
ALLOW_INCOMPLETE_OCTETS = (1 << 0),
|
||||
/*! include resonance structures featuring charge separation also
|
||||
* when uncharged resonance structures exist */
|
||||
ALLOW_CHARGE_SEPARATION = (1 << 1),
|
||||
/*! enumerate all possible degenerate Kekule resonance structures
|
||||
* (the default is to include just one) */
|
||||
KEKULE_ALL = (1 << 1),
|
||||
KEKULE_ALL = (1 << 2),
|
||||
/*! if the UNCONSTRAINED_CATIONS flag is not set, positively
|
||||
* charged atoms left and right of N with an incomplete octet are
|
||||
* acceptable only if the conjugated group has a positive total
|
||||
* formal charge */
|
||||
UNCONSTRAINED_CATIONS = (1 << 2),
|
||||
UNCONSTRAINED_CATIONS = (1 << 3),
|
||||
/*! if the UNCONSTRAINED_ANIONS flag is not set, negatively
|
||||
* charged atoms left of N are acceptable only if the conjugated
|
||||
* group has a negative total formal charge */
|
||||
UNCONSTRAINED_ANIONS = (1 << 3),
|
||||
UNCONSTRAINED_ANIONS = (1 << 4)
|
||||
} ResonanceFlags;
|
||||
/*!
|
||||
* \param mol - the starter molecule
|
||||
@@ -110,7 +115,7 @@ namespace RDKit {
|
||||
unsigned int d_flags;
|
||||
boost::uint64_t d_maxStructs;
|
||||
unsigned int d_idx;
|
||||
CEVect2 d_ceVect3;
|
||||
CEVect3 d_ceVect3;
|
||||
CEMap d_ceMapTmp;
|
||||
CEMap d_ceMap;
|
||||
void buildCEMap(unsigned int conjGrpIdx);
|
||||
@@ -123,7 +128,7 @@ namespace RDKit {
|
||||
ResonanceMolSupplier &operator=(const ResonanceMolSupplier&);
|
||||
void assignConjGrpIdx();
|
||||
void resizeCeVect();
|
||||
void trimCeVectVect();
|
||||
void trimCeVect2();
|
||||
void prepEnumIdxVect();
|
||||
void idxToCEPerm(unsigned int idx,
|
||||
std::vector<unsigned int> &c) const;
|
||||
@@ -133,254 +138,7 @@ namespace RDKit {
|
||||
void assignBondsFormalChargesHelper(ROMol &mol,
|
||||
std::vector<unsigned int> &c) const;
|
||||
ROMol *assignBondsFormalCharges(std::vector<unsigned int> &c) const;
|
||||
static bool resonanceStructureCompare
|
||||
(const ConjElectrons *a, const ConjElectrons *b);
|
||||
static bool cePermCompare(const CEPerm *a, const CEPerm *b);
|
||||
static bool vectSizeCompare(const std::vector<ConjElectrons *> *a,
|
||||
const std::vector<ConjElectrons *> *b);
|
||||
};
|
||||
|
||||
class ConjElectrons {
|
||||
public:
|
||||
typedef enum {
|
||||
HAVE_CATION_RIGHT_OF_N = (1 << 0)
|
||||
} ConjElectronsFlags;
|
||||
typedef enum {
|
||||
FP_BONDS = (1 << 0),
|
||||
FP_ATOMS = (1 << 1)
|
||||
} FPFlags;
|
||||
ConjElectrons(ResonanceMolSupplier *parent,
|
||||
unsigned int groupIdx);
|
||||
ConjElectrons(const ConjElectrons &ce);
|
||||
~ConjElectrons();
|
||||
unsigned int groupIdx() const
|
||||
{
|
||||
return d_groupIdx;
|
||||
};
|
||||
unsigned int currElectrons() const
|
||||
{
|
||||
return d_currElectrons;
|
||||
};
|
||||
unsigned int totalElectrons() const
|
||||
{
|
||||
return d_totalElectrons;
|
||||
};
|
||||
void decrCurrElectrons(unsigned int d);
|
||||
AtomElectrons *getAtomElectronsWithIdx(unsigned int ai);
|
||||
BondElectrons *getBondElectronsWithIdx(unsigned int bi);
|
||||
int getAtomConjGrpIdx(unsigned int ai) const;
|
||||
int getBondConjGrpIdx(unsigned int bi) const;
|
||||
void pushToBeginStack(unsigned int ai);
|
||||
bool popFromBeginStack(unsigned int &ai);
|
||||
bool isBeginStackEmpty() {
|
||||
return d_beginAIStack.empty();
|
||||
};
|
||||
unsigned int absFormalCharges() const {
|
||||
return d_absFormalCharges;
|
||||
};
|
||||
double wtdFormalCharges() const {
|
||||
return d_wtdFormalCharges;
|
||||
};
|
||||
unsigned int lowestFcIndex() const;
|
||||
unsigned int lowestMultipleBondIndex() const;
|
||||
int allowedChgLeftOfN() const
|
||||
{
|
||||
return d_allowedChgLeftOfN;
|
||||
};
|
||||
void decrAllowedChgLeftOfN(int d)
|
||||
{
|
||||
d_allowedChgLeftOfN -= d;
|
||||
};
|
||||
int totalFormalCharge() const
|
||||
{
|
||||
return d_totalFormalCharge;
|
||||
};
|
||||
unsigned int fcSameSignDist() const
|
||||
{
|
||||
return d_fcSameSignDist;
|
||||
};
|
||||
unsigned int fcOppSignDist() const
|
||||
{
|
||||
return d_fcOppSignDist;
|
||||
};
|
||||
unsigned int nbMissing() const
|
||||
{
|
||||
return d_nbMissing;
|
||||
}
|
||||
bool hasCationRightOfN() const
|
||||
{
|
||||
return static_cast<bool>(d_flags & HAVE_CATION_RIGHT_OF_N);
|
||||
};
|
||||
void enumerateNonBonded(CEMap &ceMap);
|
||||
void initCeFromMol();
|
||||
void assignNonBonded();
|
||||
void assignFormalCharge();
|
||||
bool assignFormalChargesAndStore
|
||||
(CEMap &ceMap, unsigned int fpFlags);
|
||||
void assignBondsFormalChargesToMol(ROMol &mol);
|
||||
bool checkCharges();
|
||||
void computeMetrics();
|
||||
bool storeFP(CEMap &ceMap, unsigned int flags);
|
||||
ResonanceMolSupplier *parent() const
|
||||
{
|
||||
return d_parent;
|
||||
};
|
||||
private:
|
||||
unsigned int d_groupIdx;
|
||||
unsigned int d_totalElectrons;
|
||||
unsigned int d_currElectrons;
|
||||
unsigned int d_numFormalCharges;
|
||||
int d_totalFormalCharge;
|
||||
int d_allowedChgLeftOfN;
|
||||
unsigned int d_absFormalCharges;
|
||||
unsigned int d_fcSameSignDist;
|
||||
unsigned int d_fcOppSignDist;
|
||||
unsigned int d_nbMissing;
|
||||
double d_wtdFormalCharges;
|
||||
boost::uint8_t d_flags;
|
||||
ConjBondMap d_conjBondMap;
|
||||
ConjAtomMap d_conjAtomMap;
|
||||
std::stack<unsigned int> d_beginAIStack;
|
||||
ResonanceMolSupplier *d_parent;
|
||||
ConjElectrons &operator=(const ConjElectrons&);
|
||||
unsigned int countTotalElectrons();
|
||||
void computeDistFormalCharges();
|
||||
void checkOctets();
|
||||
};
|
||||
class AtomElectrons {
|
||||
public:
|
||||
typedef enum {
|
||||
LAST_BOND = (1 << 0),
|
||||
DEFINITIVE = (1 << 1),
|
||||
STACKED = (1 << 2)
|
||||
} AtomElectronsFlags;
|
||||
typedef enum {
|
||||
NEED_CHARGE_BIT = 1
|
||||
} AllowedBondFlag;
|
||||
AtomElectrons(ConjElectrons *parent, const Atom *a);
|
||||
AtomElectrons(ConjElectrons *parent, const AtomElectrons &ae);
|
||||
~AtomElectrons() {};
|
||||
boost::uint8_t findAllowedBonds(unsigned int bi);
|
||||
bool hasOctet() const
|
||||
{
|
||||
return ((d_nb + d_tv * 2) == 8);
|
||||
};
|
||||
bool isLastBond() const
|
||||
{
|
||||
return (d_flags & LAST_BOND);
|
||||
};
|
||||
void setLastBond() {
|
||||
d_flags |= LAST_BOND;
|
||||
};
|
||||
bool isDefinitive() const
|
||||
{
|
||||
return (d_flags & DEFINITIVE);
|
||||
};
|
||||
void setDefinitive()
|
||||
{
|
||||
d_flags |= DEFINITIVE;
|
||||
};
|
||||
bool isStacked() const
|
||||
{
|
||||
return (d_flags & STACKED);
|
||||
};
|
||||
void setStacked() {
|
||||
d_flags |= STACKED;
|
||||
};
|
||||
void clearStacked() {
|
||||
d_flags &= ~STACKED;
|
||||
};
|
||||
unsigned int conjGrpIdx() const
|
||||
{
|
||||
return d_parent->parent()->getAtomConjGrpIdx(d_atom->getIdx());
|
||||
};
|
||||
void finalizeAtom();
|
||||
unsigned int nb() const
|
||||
{
|
||||
return d_nb;
|
||||
};
|
||||
unsigned int tv() const
|
||||
{
|
||||
return d_tv;
|
||||
};
|
||||
unsigned int oe() const
|
||||
{
|
||||
return PeriodicTable::getTable()->getNouterElecs
|
||||
(d_atom->getAtomicNum());
|
||||
};
|
||||
int fc() const
|
||||
{
|
||||
return d_fc;
|
||||
};
|
||||
void tvIncr(unsigned int i) {
|
||||
d_tv += i;
|
||||
};
|
||||
unsigned int neededNbForOctet() const
|
||||
{
|
||||
return (8 - (2 * d_tv + d_nb));
|
||||
}
|
||||
const Atom *atom()
|
||||
{
|
||||
return d_atom;
|
||||
}
|
||||
void initTvNbFcFromAtom();
|
||||
void assignNonBonded(unsigned int nb) {
|
||||
d_nb = nb;
|
||||
}
|
||||
void assignFormalCharge() {
|
||||
d_fc = oe() - (d_nb + d_tv);
|
||||
}
|
||||
bool isNbrCharged(unsigned int bo, unsigned int oeConstraint = 0);
|
||||
private:
|
||||
boost::uint8_t d_nb;
|
||||
boost::uint8_t d_tv;
|
||||
boost::int8_t d_fc;
|
||||
boost::uint8_t d_flags;
|
||||
const Atom *d_atom;
|
||||
ConjElectrons *d_parent;
|
||||
AtomElectrons &operator=(const AtomElectrons&);
|
||||
boost::uint8_t canAddBondWithOrder(unsigned int bi,
|
||||
unsigned int bo);
|
||||
void allConjBondsDefinitiveBut(unsigned int bi);
|
||||
};
|
||||
class BondElectrons {
|
||||
public:
|
||||
typedef enum {
|
||||
DEFINITIVE = (1 << 0)
|
||||
} BondElectronsFlags;
|
||||
BondElectrons(ConjElectrons *parent, const Bond *b);
|
||||
BondElectrons(ConjElectrons *parent, const BondElectrons &be);
|
||||
~BondElectrons() {};
|
||||
bool isDefinitive() const
|
||||
{
|
||||
return (d_flags & DEFINITIVE);
|
||||
};
|
||||
void setDefinitive() {
|
||||
d_flags |= DEFINITIVE;
|
||||
};
|
||||
int conjGrpIdx() const
|
||||
{
|
||||
return d_parent->getBondConjGrpIdx(d_bond->getIdx());
|
||||
};
|
||||
void setOrder(unsigned int bo);
|
||||
unsigned int order() const
|
||||
{
|
||||
return d_bo;
|
||||
};
|
||||
unsigned int orderFromBond();
|
||||
void initOrderFromBond()
|
||||
{
|
||||
d_bo = orderFromBond();
|
||||
};
|
||||
const Bond *bond() {
|
||||
return d_bond;
|
||||
};
|
||||
private:
|
||||
boost::uint8_t d_bo;
|
||||
boost::uint8_t d_flags;
|
||||
const Bond *d_bond;
|
||||
ConjElectrons *d_parent;
|
||||
BondElectrons &operator=(const BondElectrons&);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -89,6 +89,7 @@ namespace RDKit {
|
||||
static void wrap() {
|
||||
python::enum_<ResonanceMolSupplier::ResonanceFlags>("ResonanceFlags")
|
||||
.value("ALLOW_INCOMPLETE_OCTETS", ResonanceMolSupplier::ALLOW_INCOMPLETE_OCTETS)
|
||||
.value("ALLOW_CHARGE_SEPARATION", ResonanceMolSupplier::ALLOW_CHARGE_SEPARATION)
|
||||
.value("KEKULE_ALL", ResonanceMolSupplier::KEKULE_ALL)
|
||||
.value("UNCONSTRAINED_CATIONS", ResonanceMolSupplier::UNCONSTRAINED_CATIONS)
|
||||
.value("UNCONSTRAINED_ANIONS", ResonanceMolSupplier::UNCONSTRAINED_ANIONS)
|
||||
|
||||
@@ -168,7 +168,8 @@ void testButadiene() {
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol,
|
||||
ResonanceMolSupplier::ALLOW_INCOMPLETE_OCTETS
|
||||
| ResonanceMolSupplier::UNCONSTRAINED_CATIONS
|
||||
| ResonanceMolSupplier::UNCONSTRAINED_ANIONS);
|
||||
| ResonanceMolSupplier::UNCONSTRAINED_ANIONS
|
||||
| ResonanceMolSupplier::ALLOW_CHARGE_SEPARATION);
|
||||
TEST_ASSERT(resMolSuppl->length() == 3);
|
||||
std::map<unsigned int, int> fcMap;
|
||||
while (!resMolSuppl->atEnd()) {
|
||||
@@ -192,11 +193,16 @@ void testZwitterion() {
|
||||
ResonanceMolSupplier *resMolSuppl;
|
||||
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol);
|
||||
TEST_ASSERT(resMolSuppl->length() == 2);
|
||||
TEST_ASSERT(resMolSuppl->length() == 1);
|
||||
ROMol *mol0 = (*resMolSuppl)[0];
|
||||
TEST_ASSERT(mol0->getAtomWithIdx(0)->getFormalCharge() == 0);
|
||||
TEST_ASSERT(mol0->getAtomWithIdx(6)->getFormalCharge() == 0);
|
||||
delete mol0;
|
||||
delete resMolSuppl;
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol,
|
||||
ResonanceMolSupplier::ALLOW_CHARGE_SEPARATION);
|
||||
TEST_ASSERT(resMolSuppl->length() == 2);
|
||||
mol0 = (*resMolSuppl)[0];
|
||||
ROMol *mol1 = (*resMolSuppl)[1];
|
||||
TEST_ASSERT(mol1->getAtomWithIdx(0)->getFormalCharge() == 1);
|
||||
TEST_ASSERT(mol1->getAtomWithIdx(6)->getFormalCharge() == -1);
|
||||
@@ -234,7 +240,7 @@ void testChargeSeparation1() {
|
||||
ResonanceMolSupplier *resMolSuppl;
|
||||
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol);
|
||||
TEST_ASSERT(resMolSuppl->length() == 4);
|
||||
TEST_ASSERT(resMolSuppl->length() == 3);
|
||||
std::map<unsigned int, int> fcMap;
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
ROMol *resMol = (*resMolSuppl)[i];
|
||||
@@ -247,6 +253,10 @@ void testChargeSeparation1() {
|
||||
TEST_ASSERT(fcMap.find(indices[i]) != fcMap.end());
|
||||
TEST_ASSERT(fcMap[indices[i]] == 1);
|
||||
}
|
||||
delete resMolSuppl;
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol,
|
||||
ResonanceMolSupplier::ALLOW_CHARGE_SEPARATION);
|
||||
TEST_ASSERT(resMolSuppl->length() == 4);
|
||||
resMolSuppl->moveTo(3);
|
||||
ROMol *resMol = resMolSuppl->next();
|
||||
TEST_ASSERT(resMol->getAtomWithIdx(0)->getFormalCharge() == 1);
|
||||
@@ -263,6 +273,10 @@ void testChargeSeparation2() {
|
||||
ResonanceMolSupplier *resMolSuppl;
|
||||
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol);
|
||||
TEST_ASSERT(resMolSuppl->length() == 2);
|
||||
delete resMolSuppl;
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol,
|
||||
ResonanceMolSupplier::ALLOW_CHARGE_SEPARATION);
|
||||
TEST_ASSERT(resMolSuppl->length() == 8);
|
||||
// less charge separation in the first 2,
|
||||
// more charge separation in the last 6
|
||||
@@ -306,6 +320,7 @@ void testChargeSeparation2() {
|
||||
TEST_ASSERT(haveCarbanion);
|
||||
delete resMol;
|
||||
}
|
||||
delete resMolSuppl;
|
||||
}
|
||||
|
||||
void testMultipleConjGroups1() {
|
||||
@@ -314,7 +329,8 @@ void testMultipleConjGroups1() {
|
||||
RWMol *mol = SmilesToMol("NC(C(=O)[O-])=CC=C(CCC(=O)[O-])C=O");
|
||||
ResonanceMolSupplier *resMolSuppl;
|
||||
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol);
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol,
|
||||
ResonanceMolSupplier::ALLOW_CHARGE_SEPARATION);
|
||||
TEST_ASSERT(resMolSuppl->length() == 16);
|
||||
for (unsigned int i = 0; i < 8; ++i) {
|
||||
const ROMol *resMol = (*resMolSuppl)[i];
|
||||
@@ -342,7 +358,8 @@ void testMultipleConjGroups1() {
|
||||
}
|
||||
delete resMolSuppl;
|
||||
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol, 0, 8);
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol,
|
||||
ResonanceMolSupplier::ALLOW_CHARGE_SEPARATION, 8);
|
||||
TEST_ASSERT(resMolSuppl->length() == 8);
|
||||
for (unsigned int i = 0; i < 8; ++i) {
|
||||
const ROMol *resMol = (*resMolSuppl)[i];
|
||||
@@ -415,7 +432,7 @@ void testDimethylMalonate() {
|
||||
|
||||
void testMethylAcetate() {
|
||||
// cation on oxygen should appear only when UNCONSTRAINED_CATIONS
|
||||
// is set
|
||||
// and ALLOW_CHARGE_SEPARATION are set
|
||||
BOOST_LOG(rdInfoLog) << "-----------------------\n"
|
||||
<< "testMethylAcetate" << std::endl;
|
||||
RWMol *mol = SmilesToMol("CC(=O)OC");
|
||||
@@ -436,7 +453,8 @@ void testMethylAcetate() {
|
||||
delete resMolSuppl;
|
||||
|
||||
resMolSuppl = new ResonanceMolSupplier((ROMol &)*mol,
|
||||
ResonanceMolSupplier::UNCONSTRAINED_CATIONS);
|
||||
ResonanceMolSupplier::ALLOW_CHARGE_SEPARATION
|
||||
| ResonanceMolSupplier::UNCONSTRAINED_CATIONS);
|
||||
TEST_ASSERT(resMolSuppl->length() == 2);
|
||||
for (unsigned int i = 0; i < 2; ++i) {
|
||||
const ROMol *resMol = (*resMolSuppl)[i];
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user