mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
* add test * potential fix * whops\! * support disabling ring stereo in rankMolAtoms * pass atom ranks into the ring-stereo detection code * all tests pass * forgot a file --------- Co-authored-by: Ric R. <ricrogz@gmail.com>
This commit is contained in:
@@ -1450,7 +1450,9 @@ void findAtomNeighborsHelper(const ROMol &mol, const Atom *atom,
|
||||
// 4) three ring neighbors with two different ranks
|
||||
// example for this last one: C[C@H]1CC2CCCC3CCCC(C1)[C@@H]23
|
||||
// Note that N atoms are only candidates if they are in a 3-ring
|
||||
bool atomIsCandidateForRingStereochem(const ROMol &mol, const Atom *atom) {
|
||||
bool atomIsCandidateForRingStereochem(
|
||||
const ROMol &mol, const Atom *atom,
|
||||
const std::vector<unsigned int> &atomRanks) {
|
||||
PRECONDITION(atom, "bad atom");
|
||||
bool res = false;
|
||||
std::set<unsigned int> nbrRanks;
|
||||
@@ -1474,23 +1476,20 @@ bool atomIsCandidateForRingStereochem(const ROMol &mol, const Atom *atom) {
|
||||
} else {
|
||||
const Atom *nbr = bond->getOtherAtom(atom);
|
||||
ringNbrs.push_back(nbr);
|
||||
unsigned int rnk = 0;
|
||||
nbr->getPropIfPresent(common_properties::_CIPRank, rnk);
|
||||
nbrRanks.insert(rnk);
|
||||
nbrRanks.insert(atomRanks[nbr->getIdx()]);
|
||||
}
|
||||
}
|
||||
unsigned int rank1 = 0, rank2 = 0;
|
||||
// std::cerr << "!!!! " << atom->getIdx() << " " << nbrRanks.size() << " "
|
||||
// << ringNbrs.size() << " " << nonRingNbrs.size() << std::endl;
|
||||
switch (nonRingNbrs.size()) {
|
||||
case 2:
|
||||
if (nonRingNbrs[0]->getPropIfPresent(common_properties::_CIPRank,
|
||||
rank1) &&
|
||||
nonRingNbrs[1]->getPropIfPresent(common_properties::_CIPRank,
|
||||
rank2)) {
|
||||
res = rank1 != rank2;
|
||||
}
|
||||
// they have to be different
|
||||
res = atomRanks[nonRingNbrs[0]->getIdx()] !=
|
||||
atomRanks[nonRingNbrs[1]->getIdx()];
|
||||
|
||||
break;
|
||||
case 1:
|
||||
if (ringNbrs.size() >= 2) {
|
||||
if (ringNbrs.size() > nbrRanks.size()) {
|
||||
res = true;
|
||||
}
|
||||
break;
|
||||
@@ -1507,6 +1506,7 @@ bool atomIsCandidateForRingStereochem(const ROMol &mol, const Atom *atom) {
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
// std::cerr<<" candidate? "<<res<<std::endl;
|
||||
atom->setProp(common_properties::_ringStereochemCand, res, 1);
|
||||
}
|
||||
return res;
|
||||
@@ -1515,7 +1515,8 @@ bool atomIsCandidateForRingStereochem(const ROMol &mol, const Atom *atom) {
|
||||
// finds all possible chiral special cases.
|
||||
// at the moment this is just candidates for ring stereochemistry
|
||||
void findChiralAtomSpecialCases(ROMol &mol,
|
||||
boost::dynamic_bitset<> &possibleSpecialCases) {
|
||||
boost::dynamic_bitset<> &possibleSpecialCases,
|
||||
const std::vector<unsigned int> &atomRanks) {
|
||||
PRECONDITION(possibleSpecialCases.size() >= mol.getNumAtoms(),
|
||||
"bit vector too small");
|
||||
possibleSpecialCases.reset();
|
||||
@@ -1534,7 +1535,7 @@ void findChiralAtomSpecialCases(ROMol &mol,
|
||||
if (atom->getChiralTag() == Atom::CHI_UNSPECIFIED ||
|
||||
atom->hasProp(common_properties::_CIPCode) ||
|
||||
!mol.getRingInfo()->numAtomRings(atom->getIdx()) ||
|
||||
!atomIsCandidateForRingStereochem(mol, atom)) {
|
||||
!atomIsCandidateForRingStereochem(mol, atom, atomRanks)) {
|
||||
continue;
|
||||
}
|
||||
// do a BFS from this ring atom along ring bonds and find other
|
||||
@@ -1566,7 +1567,7 @@ void findChiralAtomSpecialCases(ROMol &mol,
|
||||
atomsSeen.set(ratom->getIdx());
|
||||
if (ratom->getChiralTag() != Atom::CHI_UNSPECIFIED &&
|
||||
!ratom->hasProp(common_properties::_CIPCode) &&
|
||||
atomIsCandidateForRingStereochem(mol, ratom)) {
|
||||
atomIsCandidateForRingStereochem(mol, ratom, atomRanks)) {
|
||||
int same = (ratom->getChiralTag() == atom->getChiralTag()) ? 1 : -1;
|
||||
ringStereoAtoms.push_back(same * (ratom->getIdx() + 1));
|
||||
INT_VECT oringatoms(0);
|
||||
@@ -2369,10 +2370,6 @@ void legacyStereoPerception(ROMol &mol, bool cleanIt,
|
||||
}
|
||||
|
||||
if (cleanIt) {
|
||||
// if the ranks are needed again, this will force them to be
|
||||
// re-calculated based on the stereo calculated above.
|
||||
// atomRanks.clear();
|
||||
|
||||
for (auto atom : mol.atoms()) {
|
||||
if (atom->hasProp(common_properties::_ringStereochemCand)) {
|
||||
atom->clearProp(common_properties::_ringStereochemCand);
|
||||
@@ -2382,7 +2379,7 @@ void legacyStereoPerception(ROMol &mol, bool cleanIt,
|
||||
}
|
||||
}
|
||||
boost::dynamic_bitset<> possibleSpecialCases(mol.getNumAtoms());
|
||||
Chirality::findChiralAtomSpecialCases(mol, possibleSpecialCases);
|
||||
Chirality::findChiralAtomSpecialCases(mol, possibleSpecialCases, atomRanks);
|
||||
|
||||
for (auto atom : mol.atoms()) {
|
||||
if (atom->getChiralTag() != Atom::CHI_UNSPECIFIED &&
|
||||
|
||||
@@ -818,15 +818,17 @@ bool updateAtoms(ROMol &mol, const std::vector<unsigned int> &aranks,
|
||||
needAnotherRound = true;
|
||||
}
|
||||
sinfos.push_back(std::move(sinfo));
|
||||
} else if (possibleAtoms[aidx]) {
|
||||
} else {
|
||||
// Only do another round if we change anything here
|
||||
needAnotherRound |= possibleAtoms[aidx];
|
||||
possibleAtoms[aidx] = 0;
|
||||
atomSymbols[aidx] = getAtomCompareSymbol(*atom);
|
||||
needAnotherRound = true;
|
||||
|
||||
// if this was creating possible ring stereo, update that info now
|
||||
if (possibleRingStereoAtoms[aidx]) {
|
||||
--possibleRingStereoAtoms[aidx];
|
||||
if (!possibleRingStereoAtoms[aidx]) {
|
||||
needAnotherRound = true;
|
||||
// we're no longer in any ring with possible ring stereo. Go
|
||||
// update all the other atoms/bonds in rings that we're in:
|
||||
for (unsigned int ridx = 0;
|
||||
@@ -838,6 +840,12 @@ bool updateAtoms(ROMol &mol, const std::vector<unsigned int> &aranks,
|
||||
--possibleRingStereoAtoms[raidx];
|
||||
if (possibleRingStereoAtoms[raidx]) {
|
||||
++nHere;
|
||||
} else {
|
||||
// In case there's no possible ring stereo anymore,
|
||||
// un-fix these atoms so we can recheck them in the next
|
||||
// iteration, for the case that they are no longer chiral
|
||||
// after removing the current chirality
|
||||
fixedAtoms[raidx] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1032,6 +1040,10 @@ void cleanMolStereo(ROMol &mol, const boost::dynamic_bitset<> &fixedAtoms,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void findChiralAtomSpecialCases(ROMol &mol,
|
||||
boost::dynamic_bitset<> &possibleSpecialCases,
|
||||
const std::vector<unsigned int> &atomRanks);
|
||||
|
||||
std::vector<StereoInfo> runCleanup(ROMol &mol, bool flagPossible,
|
||||
bool cleanIt) {
|
||||
// This potentially does two passes of "canonicalization" to identify
|
||||
@@ -1121,13 +1133,14 @@ std::vector<StereoInfo> runCleanup(ROMol &mol, bool flagPossible,
|
||||
const bool breakTies = false;
|
||||
const bool includeAtomMaps = false;
|
||||
const bool includeChiralPresence = false;
|
||||
const bool useRingStereo = false;
|
||||
// Now apply the canonical atom ranking code with basic connectivity
|
||||
// invariants The necessary condition for chirality is that an atom's
|
||||
// neighbors must have unique ranks
|
||||
Canon::rankFragmentAtoms(mol, aranks, atomsInPlay, bondsInPlay,
|
||||
&atomSymbols, &bondSymbols, breakTies,
|
||||
includeChirality, includeIsotopes, includeAtomMaps,
|
||||
includeChiralPresence);
|
||||
includeChiralPresence, useRingStereo);
|
||||
#endif
|
||||
// check if any new atoms definitely now have stereo; do another loop if
|
||||
// so
|
||||
@@ -1209,10 +1222,11 @@ std::vector<StereoInfo> runCleanup(ROMol &mol, bool flagPossible,
|
||||
const bool includeIsotopes = false;
|
||||
const bool includeAtomMaps = false;
|
||||
const bool includeChiralPresence = false;
|
||||
Canon::rankFragmentAtoms(mol, aranks, atomsInPlay, bondsInPlay,
|
||||
&atomSymbols, &bondSymbols, breakTies,
|
||||
includeChirality, includeIsotopes,
|
||||
includeAtomMaps, includeChiralPresence);
|
||||
const bool useRingStereo = false;
|
||||
Canon::rankFragmentAtoms(
|
||||
mol, aranks, atomsInPlay, bondsInPlay, &atomSymbols, &bondSymbols,
|
||||
breakTies, includeChirality, includeIsotopes, includeAtomMaps,
|
||||
includeChiralPresence, useRingStereo);
|
||||
#endif
|
||||
needAnotherRound = updateAtoms(
|
||||
mol, aranks, atomSymbols, possibleAtoms, knownAtoms, fixedAtoms,
|
||||
@@ -1222,6 +1236,10 @@ std::vector<StereoInfo> runCleanup(ROMol &mol, bool flagPossible,
|
||||
knownAtoms, knownBonds, fixedBonds, res);
|
||||
}
|
||||
}
|
||||
|
||||
boost::dynamic_bitset<> possibleSpecialCases(mol.getNumAtoms());
|
||||
findChiralAtomSpecialCases(mol, possibleSpecialCases, aranks);
|
||||
|
||||
for (const auto atom : mol.atoms()) {
|
||||
atom->setProp<unsigned int>(common_properties::_ChiralAtomRank,
|
||||
aranks[atom->getIdx()], true);
|
||||
|
||||
@@ -1 +1 @@
|
||||
CC1C[C@@]2(CC[C@H](C)CC2)CC[C@@H]1C |(3.08,-2.0006,;2.31,-0.6669,;0.77,-0.6669,;0,0.6668,;-0.77,2.0005,;-2.31,2.0005,;-3.08,0.6668,;-4.62,0.6668,;-2.31,-0.6669,;-0.77,-0.6669,;0.77,2.0005,;2.31,2.0005,;3.08,0.6668,;4.62,0.6668,),wD:12.14,wU:3.3,6.6|
|
||||
CC1C[C@]2(CC[C@@H]1C)CC[C@H](C)CC2 |(3.08,-2.0006,;2.31,-0.6669,;0.77,-0.6669,;0,0.6668,;0.77,2.0005,;2.31,2.0005,;3.08,0.6668,;4.62,0.6668,;-0.77,2.0005,;-2.31,2.0005,;-3.08,0.6668,;-4.62,0.6668,;-2.31,-0.6669,;-0.77,-0.6669,),wD:6.7,wU:3.8,10.11|
|
||||
@@ -1 +1 @@
|
||||
CC1C[C@@]2(CC[C@H](C)CC2)CC[C@@H]1C |(3.08,-2.0006,;2.31,-0.6669,;0.77,-0.6669,;0,0.6668,;-0.77,2.0005,;-2.31,2.0005,;-3.08,0.6668,;-4.62,0.6668,;-2.31,-0.6669,;-0.77,-0.6669,;0.77,2.0005,;2.31,2.0005,;3.08,0.6668,;4.62,0.6668,),wD:12.14,wU:3.3,6.6|
|
||||
CC1C[C@]2(CC[C@@H]1C)CC[C@H](C)CC2 |(3.08,-2.0006,;2.31,-0.6669,;0.77,-0.6669,;0,0.6668,;0.77,2.0005,;2.31,2.0005,;3.08,0.6668,;4.62,0.6668,;-0.77,2.0005,;-2.31,2.0005,;-3.08,0.6668,;-4.62,0.6668,;-2.31,-0.6669,;-0.77,-0.6669,),wD:6.7,wU:3.8,10.11|
|
||||
@@ -970,10 +970,12 @@ void canonicalizeStereoGroups(std::unique_ptr<ROMol> &mol,
|
||||
const bool useNonStereoRanks = false;
|
||||
const bool includeChiralPresence = true;
|
||||
const bool includeStereoGroups = false;
|
||||
const bool includeRingStereo = false;
|
||||
|
||||
Canon::rankMolAtoms(*mol, ranks, breakTies, includeChirality, includeIsotopes,
|
||||
includeAtomMaps, includeChiralPresence,
|
||||
includeStereoGroups, useNonStereoRanks);
|
||||
includeStereoGroups, useNonStereoRanks,
|
||||
includeRingStereo);
|
||||
|
||||
for (auto atom : mol->atoms()) {
|
||||
atom->setProp(common_properties::_CanonicalRankingNumber,
|
||||
|
||||
@@ -464,15 +464,15 @@ TEST_CASE("pseudoTest1") {
|
||||
"C[C@H](Cl)C[C@@H](C)Cl"},
|
||||
|
||||
{"N[C@H]1CC[C@@H](O)CC1 |a:1,4|", "N[C@H]1CC[C@@H](O)CC1 |o1:1,4|",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
{"N[C@H]1CC[C@@H](O)CC1 |a:1,4|", "N[C@H]1CC[C@@H](O)CC1 |&1:1,4|",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
{"N[C@H]1CC[C@@H](O)CC1 |a:1,4|", "N[C@@H]1CC[C@H](O)CC1 |a:1,4|",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
{"N[C@H]1CC[C@@H](O)CC1 |a:1,4|", "N[C@@H]1CC[C@H](O)CC1 |o1:1,4|",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
{"N[C@H]1CC[C@@H](O)CC1 |a:1,4|", "N[C@@H]1CC[C@H](O)CC1 |&1:1,4|",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
|
||||
// {"C[C@H]1C[C@@H](C)C[C@@H](C)C1 |o1:1,o2:6,o3:3|",
|
||||
// "C[C@@H]1C[C@H](C)C[C@@H](C)C1 |a:3,o1:6,o3:1|",
|
||||
@@ -484,63 +484,63 @@ TEST_CASE("pseudoTest1") {
|
||||
|
||||
{"C[C@H]1CC[C@H](CC1)C1CC(CC(C1)[C@@H]1CC[C@H](C)CC1)[C@@H]1CC[C@H](C)CC1 |o1:23,o2:20,o3:13,o4:16,o5:4,&6:1|",
|
||||
"C[C@H]1CC[C@@H](CC1)C1CC(CC(C1)[C@H]1CC[C@H](C)CC1)[C@H]1CC[C@H](C)CC1 |a:1,13,20,o2:4,o6:16,&4:23|",
|
||||
"C[C@H]1CC[C@@H](C2CC([C@@H]3CC[C@H](C)CC3)CC([C@@H]3CC[C@H](C)CC3)C2)CC1 |a:4,8,17,o1:1,o2:11,&1:20|"},
|
||||
"C[C@H]1CC[C@@H](C2CC([C@H]3CC[C@@H](C)CC3)CC([C@H]3CC[C@@H](C)CC3)C2)CC1 |a:4,8,17,o1:1,o2:11,&1:20|"},
|
||||
|
||||
{"C[C@H]1CC[C@H](CC1)C1CC(CC(C1)[C@@H]1CC[C@H](C)CC1)[C@@H]1CC[C@H](C)CC1 |o1:23,o2:20,o3:13,o4:16,o5:4,o6:1|",
|
||||
"C[C@H]1CC[C@@H](CC1)C1CC(CC(C1)[C@H]1CC[C@H](C)CC1)[C@H]1CC[C@H](C)CC1 |a:4,13,23,o2:20,o4:16,o6:1|",
|
||||
"C[C@H]1CC[C@@H](C2CC([C@@H]3CC[C@H](C)CC3)CC([C@@H]3CC[C@H](C)CC3)C2)CC1 |a:4,8,17,o1:1,o2:11,o3:20|"},
|
||||
"C[C@H]1CC[C@@H](C2CC([C@H]3CC[C@@H](C)CC3)CC([C@H]3CC[C@@H](C)CC3)C2)CC1 |a:4,8,17,o1:1,o2:11,o3:20|"},
|
||||
|
||||
{"C[C@H]1CC[C@@H](C[C@@H]2CC[C@H](C)CC2)CC1 |a:9,o1:6,&1:4,&2:1|",
|
||||
"C[C@H]1CC[C@H](C[C@H]2CC[C@H](C)CC2)CC1 |a:4,9,&1:6,o2:1|",
|
||||
"C[C@H]1CC[C@H](C[C@@H]2CC[C@H](C)CC2)CC1 |a:4,6,o1:1,&1:9|"},
|
||||
"C[C@H]1CC[C@@H](C[C@H]2CC[C@@H](C)CC2)CC1 |a:4,6,o1:1,&1:9|"},
|
||||
|
||||
{"C[C@H]1CC[C@@H](C[C@@H]2CC[C@H](C)CC2)CC1 |o1:6,o2:1,9,o3:4|",
|
||||
"C[C@H]1CC[C@H](C[C@H]2CC[C@H](C)CC2)CC1 |o1:6,o2:1,9,o3:4|",
|
||||
"C[C@H]1CC[C@@H](C[C@@H]2CC[C@H](C)CC2)CC1 |a:4,6,o1:1,o2:9|"},
|
||||
"C[C@H]1CC[C@@H](C[C@H]2CC[C@@H](C)CC2)CC1 |a:4,6,o1:1,o2:9|"},
|
||||
|
||||
{"C[C@H]1CC[C@@H](C[C@@H]2CC[C@H](C)CC2)CC1 |o1:6,o2:1,9,o3:4|",
|
||||
"C[C@H]1CC[C@H](C[C@H]2CC[C@H](C)CC2)CC1 |a:4,9,o1:6,o2:1|",
|
||||
"C[C@H]1CC[C@@H](C[C@@H]2CC[C@H](C)CC2)CC1 |a:4,6,o1:1,o2:9|"},
|
||||
"C[C@H]1CC[C@@H](C[C@H]2CC[C@@H](C)CC2)CC1 |a:4,6,o1:1,o2:9|"},
|
||||
|
||||
{"N[C@H]1CC[C@@H](O)CC1", "N[C@@H]1CC[C@H](O)CC1",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
{"N[C@H]1CC[C@@H](O)CC1 |o2:1,4|", "N[C@@H]1CC[C@H](O)CC1 |o2:1,4|",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
{"N[C@H]1CC[C@@H](O)CC1 |&2:1,4|", "N[C@@H]1CC[C@H](O)CC1 |&2:1,4|",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
{"N[C@H]1CC[C@@H](O)CC1 |a:1,4|", "N[C@@H]1CC[C@H](O)CC1 |a:1,4|",
|
||||
"N[C@@H]1CC[C@H](O)CC1"},
|
||||
"N[C@H]1CC[C@@H](O)CC1"},
|
||||
|
||||
// no enhanced stereo
|
||||
{"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1"},
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1"},
|
||||
|
||||
// enhance stereo abs,abs,abs
|
||||
{"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1 |a:3,11,14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1"},
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1"},
|
||||
|
||||
// abs, abs, or and abs, or abs
|
||||
|
||||
{"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,o1:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,11,o1:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1 |a:3,11,o1:14|"},
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,11,o1:14|"},
|
||||
{"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,o1:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,14,o1:11|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1 |a:3,11,o1:14|"},
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,11,o1:14|"},
|
||||
{"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,o1:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,o1:11,o2:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1 |a:3,11,o1:14|"},
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,11,o1:14|"},
|
||||
{"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,&1:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,11,&1:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1 |a:3,11,&1:14|"},
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,11,&1:14|"},
|
||||
{"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,&1:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,14,&1:11|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1 |a:3,11,&1:14|"},
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,11,&1:14|"},
|
||||
{"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,&1:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,&1:11,&2:14|",
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@@H]1CC[C@H](C)CC1 |a:3,11,&1:14|"},
|
||||
"CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@H](C)CC1 |a:3,11,&1:14|"},
|
||||
|
||||
};
|
||||
|
||||
@@ -563,6 +563,9 @@ TEST_CASE("pseudoTest1") {
|
||||
idxV[i] = i;
|
||||
}
|
||||
|
||||
RDKit::canonicalizeStereoGroups(mol2);
|
||||
auto outSmi2 = MolToCXSmiles(*mol2);
|
||||
REQUIRE(outSmi2 == smiExpected);
|
||||
auto randomGen = std::mt19937(0xf00d);
|
||||
for (auto i = 0; i < 100; ++i) {
|
||||
INFO("i: " << i);
|
||||
@@ -572,14 +575,11 @@ TEST_CASE("pseudoTest1") {
|
||||
std::unique_ptr<ROMol> nmol{MolOps::renumberAtoms(*mol1, nVect)};
|
||||
|
||||
RDKit::canonicalizeStereoGroups(nmol);
|
||||
RDKit::canonicalizeStereoGroups(mol2);
|
||||
|
||||
auto outSmi1 = MolToCXSmiles(*nmol);
|
||||
auto outSmi2 = MolToCXSmiles(*mol2);
|
||||
|
||||
CHECK(outSmi1 == outSmi2);
|
||||
CHECK(outSmi1 == smiExpected);
|
||||
CHECK(outSmi2 == smiExpected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1118,4 +1118,42 @@ TEST_CASE("meso impact on atom ranking") {
|
||||
CHECK(ranks[3] != ranks[10]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("allow disabling ring stereo in ranking") {
|
||||
UseLegacyStereoPerceptionFixture reset_stereo_perception(false);
|
||||
|
||||
std::string smi = "C[C@@H]1CC[C@@H](C)CC1";
|
||||
auto m = v2::SmilesParse::MolFromSmiles(smi);
|
||||
REQUIRE(m);
|
||||
|
||||
bool breakTies = false;
|
||||
bool includeChirality = true;
|
||||
bool includeIsotopes = true;
|
||||
bool includeAtomMaps = true;
|
||||
bool includeChiralPresence = false;
|
||||
bool includeStereoGroups = true;
|
||||
bool useNonStereoRanks = false;
|
||||
bool includeRingStereo = true;
|
||||
std::vector<unsigned int> res1;
|
||||
Canon::rankMolAtoms(*m, res1, breakTies, includeChirality, includeIsotopes,
|
||||
includeAtomMaps, includeChiralPresence,
|
||||
includeStereoGroups, useNonStereoRanks,
|
||||
includeRingStereo);
|
||||
CHECK(res1.size() == m->getNumAtoms());
|
||||
CHECK(res1[2] != res1[7]);
|
||||
CHECK(res1[2] == res1[3]);
|
||||
CHECK(res1[3] != res1[6]);
|
||||
CHECK(res1[6] == res1[7]);
|
||||
|
||||
includeRingStereo = false;
|
||||
Canon::rankMolAtoms(*m, res1, breakTies, includeChirality, includeIsotopes,
|
||||
includeAtomMaps, includeChiralPresence,
|
||||
includeStereoGroups, useNonStereoRanks,
|
||||
includeRingStereo);
|
||||
CHECK(res1.size() == m->getNumAtoms());
|
||||
CHECK(res1[2] == res1[7]);
|
||||
CHECK(res1[2] == res1[3]);
|
||||
CHECK(res1[3] == res1[6]);
|
||||
CHECK(res1[6] == res1[7]);
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <GraphMol/StereoGroup.h>
|
||||
#include <GraphMol/Chirality.h>
|
||||
#include <GraphMol/MolOps.h>
|
||||
#include <GraphMol/new_canon.h>
|
||||
#include <GraphMol/test_fixtures.h>
|
||||
|
||||
#include <GraphMol/FileParsers/FileParsers.h>
|
||||
@@ -2149,7 +2150,7 @@ TEST_CASE(
|
||||
RDLog::LogStateSetter setter; // disable irritating warning messages
|
||||
auto molblock = R"CTAB(
|
||||
RDKit 3D
|
||||
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 5 4 0 0 0
|
||||
@@ -2679,7 +2680,7 @@ TEST_CASE("useLegacyStereoPerception feature flag") {
|
||||
CHECK(m->getAtomWithIdx(9)->getChiralTag() != Atom::CHI_UNSPECIFIED);
|
||||
}
|
||||
std::string molblock = R"CTAB(
|
||||
Mrv2108 05202206352D
|
||||
Mrv2108 05202206352D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -2797,7 +2798,7 @@ M END
|
||||
TEST_CASE("github 5307: AssignAtomChiralTagsFromStructure ignores Hydrogens") {
|
||||
std::string mb = R"CTAB(
|
||||
RDKit 3D
|
||||
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 5 4 0 0 0
|
||||
@@ -3317,7 +3318,7 @@ void testStereoValidationFromMol(std::string molBlock,
|
||||
}
|
||||
|
||||
std::string validateStereoMolBlockSpiro = R"(
|
||||
Mrv2308 06232316112D
|
||||
Mrv2308 06232316112D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -3359,7 +3360,7 @@ M END
|
||||
)";
|
||||
|
||||
std::string validateStereoMolBlockDoubleBondNoStereo = R"(
|
||||
Mrv2308 06232316392D
|
||||
Mrv2308 06232316392D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -3391,7 +3392,7 @@ M END
|
||||
)";
|
||||
|
||||
std::string validateStereoMolBlockDoubleBondNoStereo2 = R"(
|
||||
Mrv0541 07011416342D
|
||||
Mrv0541 07011416342D
|
||||
|
||||
21 22 0 0 0 0 999 V2000
|
||||
-1.9814 1.4834 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
@@ -3449,7 +3450,7 @@ $$$$
|
||||
)";
|
||||
|
||||
std::string validateStereoError1 = R"(
|
||||
-ISIS- -- StrEd --
|
||||
-ISIS- -- StrEd --
|
||||
|
||||
29 32 0 0 0 0 0 0 0 0999 V2000
|
||||
-1.2050 -4.7172 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
@@ -3525,7 +3526,7 @@ $$$$
|
||||
)";
|
||||
|
||||
std::string validateStereoUniq1 = R"(
|
||||
Mrv0541 06301412152D
|
||||
Mrv0541 06301412152D
|
||||
|
||||
15 15 0 0 0 0 999 V2000
|
||||
1.0464 -0.3197 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
@@ -3764,7 +3765,7 @@ TEST_CASE(
|
||||
}
|
||||
SECTION("ensure we can enumerate stereo on either double bonds") {
|
||||
auto mol = R"CTAB(
|
||||
Mrv2004 11072316002D
|
||||
Mrv2004 11072316002D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -3807,7 +3808,7 @@ M END)CTAB"_ctab;
|
||||
TEST_CASE("adding two wedges to chiral centers") {
|
||||
SECTION("basics") {
|
||||
auto mol = R"CTAB(
|
||||
Mrv2219 02112315062D
|
||||
Mrv2219 02112315062D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -4102,7 +4103,7 @@ TEST_CASE("zero bond-length chirality cases") {
|
||||
SECTION("basics") {
|
||||
{
|
||||
auto m = R"CTAB(derived from CHEMBL3183068
|
||||
Mrv2211 07202306222D
|
||||
Mrv2211 07202306222D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -4140,7 +4141,7 @@ M END
|
||||
}
|
||||
{
|
||||
auto m = R"CTAB(derived from CHEMBL3183068
|
||||
Mrv2211 07202306222D
|
||||
Mrv2211 07202306222D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -4255,7 +4256,7 @@ M END
|
||||
SECTION("four-coordinate") {
|
||||
{
|
||||
auto m = R"CTAB(
|
||||
Mrv2211 07202306492D
|
||||
Mrv2211 07202306492D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -4282,7 +4283,7 @@ M END
|
||||
}
|
||||
{
|
||||
auto m = R"CTAB(
|
||||
Mrv2211 07202306492D
|
||||
Mrv2211 07202306492D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -4309,7 +4310,7 @@ M END
|
||||
}
|
||||
{
|
||||
auto m = R"CTAB(
|
||||
Mrv2211 07202306492D
|
||||
Mrv2211 07202306492D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -4470,7 +4471,7 @@ M END
|
||||
auto m =
|
||||
R"CTAB(derived from CHEMBL2373651. This was wrong in the RDKit implementation
|
||||
Mrv2211 07212313282D
|
||||
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 7 7 0 0 1
|
||||
@@ -4666,7 +4667,7 @@ M V30 BEGIN BOND
|
||||
M V30 1 1 2 1 CFG=1
|
||||
M V30 2 1 3 2
|
||||
M V30 3 1 4 6
|
||||
M V30 4 1 5 3
|
||||
M V30 4 1 5 3
|
||||
M V30 5 1 6 2
|
||||
M V30 6 1 5 7 CFG=1
|
||||
M V30 7 1 2 8 CFG=3
|
||||
@@ -4925,7 +4926,7 @@ TEST_CASE(
|
||||
UseLegacyStereoPerceptionFixture reset_stereo_perception(legacy_stereo);
|
||||
|
||||
auto m = R"CTAB(
|
||||
Mrv2311 12122315472D
|
||||
Mrv2311 12122315472D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -4961,7 +4962,7 @@ TEST_CASE(
|
||||
UseLegacyStereoPerceptionFixture reset_stereo_perception(legacy_stereo);
|
||||
|
||||
auto m = R"CTAB(
|
||||
Mrv2211 01252410552D
|
||||
Mrv2211 01252410552D
|
||||
|
||||
10 9 0 0 0 0 999 V2000
|
||||
0.0000 -1.4364 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
@@ -5237,7 +5238,7 @@ M END
|
||||
}
|
||||
SECTION("cage") {
|
||||
auto m = R"CTAB(
|
||||
Mrv2305 03052406362D
|
||||
Mrv2305 03052406362D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -5535,7 +5536,7 @@ M END
|
||||
}
|
||||
SECTION("favor larger rings") {
|
||||
auto m = R"CTAB(
|
||||
Mrv2401 04262410272D
|
||||
Mrv2401 04262410272D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -6020,7 +6021,7 @@ TEST_CASE(
|
||||
TEST_CASE("Github issue #7983: stereogroup lost on chiral sulfoxide") {
|
||||
SECTION("basics") {
|
||||
auto m = R"CTAB(
|
||||
Mrv2317 02032512242D
|
||||
Mrv2317 02032512242D
|
||||
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
@@ -6151,7 +6152,7 @@ TEST_CASE("Github #8420: imines and crossed bonds") {
|
||||
UseLegacyStereoPerceptionFixture reset_stereo_perception(useLegacy);
|
||||
SECTION("as reported") {
|
||||
std::string ctab = R"CTAB(
|
||||
MJ250100
|
||||
MJ250100
|
||||
|
||||
7 7 0 0 1 0 0 0 0 0999 V2000
|
||||
0.6961 0.4995 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
@@ -6173,4 +6174,177 @@ M END)CTAB";
|
||||
REQUIRE(m);
|
||||
CHECK(m->getBondWithIdx(0)->getStereo() == Bond::BondStereo::STEREONONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Github #8712: Modern stereo + 3D SD file leads to bad stereo detection for some molecules") {
|
||||
UseLegacyStereoPerceptionFixture reset_stereo_perception(false);
|
||||
SECTION("as reported") {
|
||||
std::string ctab = R"CTAB(
|
||||
RDKit 3D
|
||||
|
||||
0 0 0 0 0 0 0 0 0 0999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 23 23 0 0 0
|
||||
M V30 BEGIN ATOM
|
||||
M V30 1 C 2.628222 -0.014974 0.390914 0
|
||||
M V30 2 N 1.918195 0.260032 -0.835284 0
|
||||
M V30 3 C 0.487110 0.206615 -0.681308 0
|
||||
M V30 4 C 0.079788 -1.165009 -0.217881 0
|
||||
M V30 5 C -1.428295 -1.378335 -0.390798 0
|
||||
M V30 6 S -2.156694 -0.136366 0.671587 0
|
||||
M V30 7 O -1.585579 -0.347357 2.045208 0
|
||||
M V30 8 O -3.651696 -0.172351 0.647489 0
|
||||
M V30 9 C -1.519569 1.415993 0.067834 0
|
||||
M V30 10 C -0.010801 1.307036 0.207366 0
|
||||
M V30 11 H 1.988100 -0.320407 1.230786 0
|
||||
M V30 12 H 3.238742 0.867078 0.711200 0
|
||||
M V30 13 H 3.359131 -0.825206 0.185242 0
|
||||
M V30 14 H 2.223613 -0.317010 -1.647727 0
|
||||
M V30 15 H 0.041778 0.347830 -1.688472 0
|
||||
M V30 16 H 0.284353 -1.370499 0.832996 0
|
||||
M V30 17 H 0.580676 -1.905979 -0.844599 0
|
||||
M V30 18 H -1.673500 -2.379109 -0.016810 0
|
||||
M V30 19 H -1.696056 -1.195326 -1.452807 0
|
||||
M V30 20 H -1.827609 1.481487 -0.996993 0
|
||||
M V30 21 H -1.921584 2.283368 0.626641 0
|
||||
M V30 22 H 0.172726 1.108075 1.288878 0
|
||||
M V30 23 H 0.468947 2.250412 -0.133459 0
|
||||
M V30 END ATOM
|
||||
M V30 BEGIN BOND
|
||||
M V30 1 1 1 2
|
||||
M V30 2 1 2 3
|
||||
M V30 3 1 3 4
|
||||
M V30 4 1 4 5
|
||||
M V30 5 1 5 6
|
||||
M V30 6 2 6 7
|
||||
M V30 7 2 6 8
|
||||
M V30 8 1 6 9
|
||||
M V30 9 1 9 10
|
||||
M V30 10 1 10 3
|
||||
M V30 11 1 1 11
|
||||
M V30 12 1 1 12
|
||||
M V30 13 1 1 13
|
||||
M V30 14 1 2 14
|
||||
M V30 15 1 3 15
|
||||
M V30 16 1 4 16
|
||||
M V30 17 1 4 17
|
||||
M V30 18 1 5 18
|
||||
M V30 19 1 5 19
|
||||
M V30 20 1 9 20
|
||||
M V30 21 1 9 21
|
||||
M V30 22 1 10 22
|
||||
M V30 23 1 10 23
|
||||
M V30 END BOND
|
||||
M V30 END CTAB
|
||||
M END
|
||||
)CTAB";
|
||||
auto m = v2::FileParsers::MolFromMolBlock(ctab);
|
||||
REQUIRE(m);
|
||||
|
||||
auto smiles = MolToSmiles(*m);
|
||||
CHECK(smiles.find('@') == std::string::npos);
|
||||
}
|
||||
SECTION("counterexample from the doc tests") {
|
||||
// Do not break this one!
|
||||
// I'm adding it here because it seems we don't have this case
|
||||
// in any other C++ test.
|
||||
auto m = R"SMI(C1C[C@H](C)[C@H](C)[C@H](C)C1)SMI"_smiles;
|
||||
REQUIRE(m);
|
||||
for (auto i : {2, 4, 6}) {
|
||||
CHECK(m->getAtomWithIdx(i)->getChiralTag() !=
|
||||
Atom::ChiralType::CHI_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
TEST_CASE(
|
||||
"Github #8689: stereo canonicalization depends on bond iteration order") {
|
||||
bool useLegacy = GENERATE(true, false);
|
||||
CAPTURE(useLegacy);
|
||||
UseLegacyStereoPerceptionFixture reset_stereo_perception(useLegacy);
|
||||
|
||||
std::string pathName = getenv("RDBASE");
|
||||
pathName += "/Code/GraphMol/test_data/";
|
||||
|
||||
SECTION("simplified") {
|
||||
pathName += "github8689_2.sdf";
|
||||
v2::FileParsers::SDMolSupplier suppl(pathName);
|
||||
auto m1 = suppl[0];
|
||||
REQUIRE(m1);
|
||||
auto m2 = suppl[1];
|
||||
REQUIRE(m2);
|
||||
// m1->debugMol(std::cerr);
|
||||
// m2->debugMol(std::cerr);
|
||||
|
||||
CIPLabeler::assignCIPLabels(*m1);
|
||||
CIPLabeler::assignCIPLabels(*m2);
|
||||
REQUIRE(m1->getAtomWithIdx(7)->hasProp(common_properties::_CIPCode));
|
||||
REQUIRE(m1->getAtomWithIdx(8)->hasProp(common_properties::_CIPCode));
|
||||
REQUIRE(m2->getAtomWithIdx(7)->hasProp(common_properties::_CIPCode));
|
||||
REQUIRE(m2->getAtomWithIdx(8)->hasProp(common_properties::_CIPCode));
|
||||
|
||||
CHECK(m1->getAtomWithIdx(7)->getProp<std::string>(
|
||||
common_properties::_CIPCode) ==
|
||||
m2->getAtomWithIdx(7)->getProp<std::string>(
|
||||
common_properties::_CIPCode));
|
||||
CHECK(m1->getAtomWithIdx(8)->getProp<std::string>(
|
||||
common_properties::_CIPCode) ==
|
||||
m2->getAtomWithIdx(8)->getProp<std::string>(
|
||||
common_properties::_CIPCode));
|
||||
|
||||
auto smi1 = MolToSmiles(*m1);
|
||||
auto smi2 = MolToSmiles(*m2);
|
||||
CHECK(smi1 == smi2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
TEST_CASE("extra ring stereo with new stereo perception") {
|
||||
UseLegacyStereoPerceptionFixture reset_stereo_perception(false);
|
||||
SECTION("basics") {
|
||||
std::string smi = "C2O[C@H]3[C@@]4([C@](CCC(C24))(O)CC=C3)C";
|
||||
auto m = v2::SmilesParse::MolFromSmiles(smi);
|
||||
REQUIRE(m);
|
||||
m->debugMol(std::cerr);
|
||||
// for (const auto atm : m->atoms()) {
|
||||
// std::cerr << atm->getIdx() << ": "
|
||||
// << atm->getProp<unsigned int>(
|
||||
// common_properties::_ChiralAtomRank)
|
||||
// << std::endl;
|
||||
// }
|
||||
for (auto idx : {2, 3, 4}) {
|
||||
INFO(idx);
|
||||
const auto atm = m->getAtomWithIdx(idx);
|
||||
REQUIRE(atm);
|
||||
CHECK(atm->getChiralTag() != Atom::ChiralType::CHI_UNSPECIFIED);
|
||||
CHECK(!atm->hasProp(common_properties::_ringStereoAtoms));
|
||||
}
|
||||
}
|
||||
SECTION("don't destroy actual ring stereo") {
|
||||
std::string smi = "C[C@@H]1CC[C@@H](C)CC1";
|
||||
auto m = v2::SmilesParse::MolFromSmiles(smi);
|
||||
REQUIRE(m);
|
||||
// m->debugMol(std::cerr);
|
||||
// for (const auto atm : m->atoms()) {
|
||||
// std::cerr << atm->getIdx() << ": "
|
||||
// << atm->getProp<unsigned int>(
|
||||
// common_properties::_ChiralAtomRank)
|
||||
// << std::endl;
|
||||
// }
|
||||
for (auto idx : {1, 4}) {
|
||||
INFO(idx);
|
||||
const auto atm = m->getAtomWithIdx(idx);
|
||||
REQUIRE(atm);
|
||||
CHECK(atm->getChiralTag() != Atom::ChiralType::CHI_UNSPECIFIED);
|
||||
CHECK(atm->hasProp(common_properties::_ringStereoAtoms));
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_CASE("ring stereo basics with new stereo") {
|
||||
UseLegacyStereoPerceptionFixture reset_stereo_perception(false);
|
||||
auto m = "CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,&1:14|"_smiles;
|
||||
REQUIRE(m);
|
||||
auto smi = MolToCXSmiles(*m);
|
||||
CHECK(smi == "CC(C)[C@H]1CCCCN1C(=O)[C@H]1CC[C@@H](C)CC1 |a:3,11,&1:14|");
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ void compareRingAtomsConcerningNumNeighbors(Canon::canon_atom *atoms,
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
void rankWithFunctor(T &ftor, bool breakTies, int *order, bool useSpecial,
|
||||
bool useChirality,
|
||||
bool useChirality, bool includeRingStereo,
|
||||
const boost::dynamic_bitset<> *atomsInPlay,
|
||||
const boost::dynamic_bitset<> *bondsInPlay) {
|
||||
PRECONDITION(order, "bad pointer");
|
||||
@@ -297,7 +297,7 @@ void rankWithFunctor(T &ftor, bool breakTies, int *order, bool useSpecial,
|
||||
ties = true;
|
||||
}
|
||||
}
|
||||
if (useChirality && ties) {
|
||||
if (useChirality && ties && includeRingStereo) {
|
||||
SpecialChiralityAtomCompareFunctor scftor(atoms, mol, atomsInPlay,
|
||||
bondsInPlay);
|
||||
ActivatePartitions(nAts, order, count.get(), activeset, next.get(),
|
||||
@@ -760,7 +760,8 @@ void updateAtomNeighborNumSwaps(
|
||||
void rankMolAtoms(const ROMol &mol, std::vector<unsigned int> &res,
|
||||
bool breakTies, bool includeChirality, bool includeIsotopes,
|
||||
bool includeAtomMaps, bool includeChiralPresence,
|
||||
bool includeStereoGroups, bool useNonStereoRanks) {
|
||||
bool includeStereoGroups, bool useNonStereoRanks,
|
||||
bool includeRingStereo) {
|
||||
if (!mol.getNumAtoms()) {
|
||||
return;
|
||||
}
|
||||
@@ -777,13 +778,14 @@ void rankMolAtoms(const ROMol &mol, std::vector<unsigned int> &res,
|
||||
AtomCompareFunctor ftor(&atoms.front(), mol);
|
||||
ftor.df_useIsotopes = includeIsotopes;
|
||||
ftor.df_useChirality = includeChirality;
|
||||
ftor.df_useChiralityRings = includeChirality;
|
||||
ftor.df_useChiralityRings = includeChirality && includeRingStereo;
|
||||
ftor.df_useAtomMaps = includeAtomMaps;
|
||||
ftor.df_useNonStereoRanks = useNonStereoRanks;
|
||||
ftor.df_useChiralPresence = includeChiralPresence;
|
||||
|
||||
auto order = std::make_unique<int[]>(mol.getNumAtoms());
|
||||
detail::rankWithFunctor(ftor, breakTies, order.get(), true, includeChirality);
|
||||
detail::rankWithFunctor(ftor, breakTies, order.get(), true, includeChirality,
|
||||
includeRingStereo);
|
||||
|
||||
for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
|
||||
res[order[i]] = atoms[order[i]].index;
|
||||
@@ -801,7 +803,7 @@ void rankFragmentAtoms(const ROMol &mol, std::vector<unsigned int> &res,
|
||||
const std::vector<std::string> *bondSymbols,
|
||||
bool breakTies, bool includeChirality,
|
||||
bool includeIsotopes, bool includeAtomMaps,
|
||||
bool includeChiralPresence) {
|
||||
bool includeChiralPresence, bool includeRingStereo) {
|
||||
PRECONDITION(atomsInPlay.size() == mol.getNumAtoms(), "bad atomsInPlay size");
|
||||
PRECONDITION(bondsInPlay.size() == mol.getNumBonds(), "bad bondsInPlay size");
|
||||
PRECONDITION(!atomSymbols || atomSymbols->size() == mol.getNumAtoms(),
|
||||
@@ -833,7 +835,7 @@ void rankFragmentAtoms(const ROMol &mol, std::vector<unsigned int> &res,
|
||||
|
||||
auto order = std::make_unique<int[]>(mol.getNumAtoms());
|
||||
detail::rankWithFunctor(ftor, breakTies, order.get(), true, includeChirality,
|
||||
&atomsInPlay, &bondsInPlay);
|
||||
includeRingStereo, &atomsInPlay, &bondsInPlay);
|
||||
|
||||
for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) {
|
||||
res[order[i]] = atoms[order[i]].index;
|
||||
|
||||
@@ -179,12 +179,15 @@ class RDKIT_GRAPHMOL_EXPORT SpecialChiralityAtomCompareFunctor {
|
||||
if (!dp_atomsInPlay || (*dp_atomsInPlay)[j]) {
|
||||
updateAtomNeighborNumSwaps(dp_atoms, dp_atoms[j].bonds, j, swapsj);
|
||||
}
|
||||
|
||||
for (unsigned int ii = 0; ii < swapsi.size() && ii < swapsj.size(); ++ii) {
|
||||
int cmp = swapsi[ii].second - swapsj[ii].second;
|
||||
|
||||
if (cmp) {
|
||||
return cmp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
@@ -852,7 +855,8 @@ RDKIT_GRAPHMOL_EXPORT void rankMolAtoms(
|
||||
const ROMol &mol, std::vector<unsigned int> &res, bool breakTies = true,
|
||||
bool includeChirality = true, bool includeIsotopes = true,
|
||||
bool includeAtomMaps = true, bool includeChiralPresence = false,
|
||||
bool includeStereoGroups = true, bool useNonStereoRanks = false);
|
||||
bool includeStereoGroups = true, bool useNonStereoRanks = false,
|
||||
bool includeRingStereo = true);
|
||||
|
||||
//! Note that atom maps on dummy atoms will always be used
|
||||
RDKIT_GRAPHMOL_EXPORT void rankFragmentAtoms(
|
||||
@@ -862,7 +866,7 @@ RDKIT_GRAPHMOL_EXPORT void rankFragmentAtoms(
|
||||
const std::vector<std::string> *atomSymbols,
|
||||
const std::vector<std::string> *bondSymbols, bool breakTies,
|
||||
bool includeChirality, bool includeIsotope, bool includeAtomMaps,
|
||||
bool includeChiralPresence);
|
||||
bool includeChiralPresence, bool includeRingStereo = true);
|
||||
|
||||
//! Note that atom maps on dummy atoms will always be used
|
||||
inline void rankFragmentAtoms(
|
||||
@@ -872,10 +876,10 @@ inline void rankFragmentAtoms(
|
||||
const std::vector<std::string> *atomSymbols = nullptr,
|
||||
bool breakTies = true, bool includeChirality = true,
|
||||
bool includeIsotopes = true, bool includeAtomMaps = true,
|
||||
bool includeChiralPresence = false) {
|
||||
bool includeChiralPresence = false, bool includeRingStereo = true) {
|
||||
rankFragmentAtoms(mol, res, atomsInPlay, bondsInPlay, atomSymbols, nullptr,
|
||||
breakTies, includeChirality, includeIsotopes,
|
||||
includeAtomMaps, includeChiralPresence);
|
||||
includeAtomMaps, includeChiralPresence, includeRingStereo);
|
||||
};
|
||||
|
||||
RDKIT_GRAPHMOL_EXPORT void chiralRankMolAtoms(const ROMol &mol,
|
||||
@@ -898,6 +902,7 @@ void initFragmentCanonAtoms(const ROMol &mol,
|
||||
template <typename T>
|
||||
void rankWithFunctor(T &ftor, bool breakTies, int *order,
|
||||
bool useSpecial = false, bool useChirality = false,
|
||||
bool includeRingStereo = true,
|
||||
const boost::dynamic_bitset<> *atomsInPlay = nullptr,
|
||||
const boost::dynamic_bitset<> *bondsInPlay = nullptr);
|
||||
|
||||
|
||||
96
Code/GraphMol/test_data/github8689_2.sdf
Executable file
96
Code/GraphMol/test_data/github8689_2.sdf
Executable file
@@ -0,0 +1,96 @@
|
||||
Original molblock
|
||||
2D
|
||||
Structure written by MMmdl.
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 17 18 0 0 0
|
||||
M V30 BEGIN ATOM
|
||||
M V30 1 C 5.9462 5.2500 0.0000 0
|
||||
M V30 2 C 8.5442 5.2500 0.0000 0
|
||||
M V30 3 C 3.3481 5.2500 0.0000 0
|
||||
M V30 4 C 4.6471 6.0000 0.0000 0
|
||||
M V30 5 C 5.9462 3.7500 0.0000 0
|
||||
M V30 6 C 3.3481 3.7500 0.0000 0
|
||||
M V30 7 C 9.8433 6.0000 0.0000 0
|
||||
M V30 8 C 8.5442 3.7500 0.0000 0
|
||||
M V30 9 C 11.1423 5.2500 0.0000 0
|
||||
M V30 10 C 9.8433 3.0000 0.0000 0
|
||||
M V30 11 C 11.1423 3.7500 0.0000 0
|
||||
M V30 12 C 4.6471 3.0000 0.0000 0
|
||||
M V30 13 C 7.2452 3.0000 0.0000 0
|
||||
M V30 14 C 2.0490 6.0000 0.0000 0
|
||||
M V30 15 C 12.4414 6.0000 0.0000 0
|
||||
M V30 16 O 0.7500 5.2500 0.0000 0
|
||||
M V30 17 N 2.0490 7.5000 0.0000 0
|
||||
M V30 END ATOM
|
||||
M V30 BEGIN BOND
|
||||
M V30 1 1 1 4
|
||||
M V30 2 1 1 5
|
||||
M V30 3 1 2 7
|
||||
M V30 4 1 2 8
|
||||
M V30 5 1 3 4
|
||||
M V30 6 1 3 6
|
||||
M V30 7 1 3 14
|
||||
M V30 8 1 5 12
|
||||
M V30 9 1 5 13
|
||||
M V30 10 1 6 12
|
||||
M V30 11 1 7 9
|
||||
M V30 12 1 8 10
|
||||
M V30 13 1 8 13 CFG=3
|
||||
M V30 14 1 9 11
|
||||
M V30 15 1 9 15 CFG=3
|
||||
M V30 16 1 10 11
|
||||
M V30 17 2 14 16
|
||||
M V30 18 1 14 17
|
||||
M V30 END BOND
|
||||
M V30 END CTAB
|
||||
M END
|
||||
$$$$
|
||||
shuffled bonds
|
||||
2D
|
||||
Structure written by MMmdl.
|
||||
0 0 0 0 0 999 V3000
|
||||
M V30 BEGIN CTAB
|
||||
M V30 COUNTS 17 18 0 0 0
|
||||
M V30 BEGIN ATOM
|
||||
M V30 1 C 5.9462 5.2500 0.0000 0
|
||||
M V30 2 C 8.5442 5.2500 0.0000 0
|
||||
M V30 3 C 3.3481 5.2500 0.0000 0
|
||||
M V30 4 C 4.6471 6.0000 0.0000 0
|
||||
M V30 5 C 5.9462 3.7500 0.0000 0
|
||||
M V30 6 C 3.3481 3.7500 0.0000 0
|
||||
M V30 7 C 9.8433 6.0000 0.0000 0
|
||||
M V30 8 C 8.5442 3.7500 0.0000 0
|
||||
M V30 9 C 11.1423 5.2500 0.0000 0
|
||||
M V30 10 C 9.8433 3.0000 0.0000 0
|
||||
M V30 11 C 11.1423 3.7500 0.0000 0
|
||||
M V30 12 C 4.6471 3.0000 0.0000 0
|
||||
M V30 13 C 7.2452 3.0000 0.0000 0
|
||||
M V30 14 C 2.0490 6.0000 0.0000 0
|
||||
M V30 15 C 12.4414 6.0000 0.0000 0
|
||||
M V30 16 O 0.7500 5.2500 0.0000 0
|
||||
M V30 17 N 2.0490 7.5000 0.0000 0
|
||||
M V30 END ATOM
|
||||
M V30 BEGIN BOND
|
||||
M V30 14 1 9 11
|
||||
M V30 2 1 1 5
|
||||
M V30 5 1 3 4
|
||||
M V30 15 1 9 15 CFG=3
|
||||
M V30 18 1 14 17
|
||||
M V30 11 1 7 9
|
||||
M V30 8 1 5 12
|
||||
M V30 16 1 10 11
|
||||
M V30 9 1 5 13
|
||||
M V30 4 1 2 8
|
||||
M V30 13 1 8 13 CFG=3
|
||||
M V30 6 1 3 6
|
||||
M V30 17 2 14 16
|
||||
M V30 12 1 8 10
|
||||
M V30 1 1 1 4
|
||||
M V30 7 1 3 14
|
||||
M V30 10 1 6 12
|
||||
M V30 3 1 2 7
|
||||
M V30 END BOND
|
||||
M V30 END CTAB
|
||||
M END
|
||||
$$$$
|
||||
Reference in New Issue
Block a user