trimethylcyclohexane chirality error (#8272)

* Fix for trimethylcyclohexane error

* removed unused variable

* removed debugging code
This commit is contained in:
tadhurst-cdd
2025-02-24 10:41:54 -06:00
committed by GitHub
parent 55dc5c73e3
commit 2dbf83898d
2 changed files with 92 additions and 44 deletions

View File

@@ -654,31 +654,53 @@ void flagRingStereo(ROMol &mol,
if (!knownAtoms[aidx] && (!possibleAtoms || !possibleAtoms->test(aidx))) {
continue;
}
if (!ringIsOddSized) {
// find the index of the atom on the opposite side of the even-sized
// ring
auto oppositeIdx = aring[(ai + halfSize) % sz];
bool toAtomOppositePossible = false;
auto oppositeAtom = mol.getAtomWithIdx(oppositeIdx);
for (auto bond : mol.atomBonds(oppositeAtom)) {
auto bidx = bond->getIdx();
if ((knownBonds[bidx] ||
(possibleBonds && possibleBonds->test(bidx))) &&
std::find(bring.begin(), bring.end(), bidx) == bring.end()) {
toAtomOppositePossible = true;
break;
}
}
if (knownAtoms[oppositeIdx] ||
(possibleAtoms && possibleAtoms->test(oppositeIdx)) ||
toAtomOppositePossible) {
nHere += 1 + toAtomOppositePossible;
possibleAtomsInRing.set(aidx);
possibleAtomsInRing.set(oppositeIdx);
mol.getAtomWithIdx(aidx)->setProp(
common_properties::_ringStereoOtherAtom, oppositeIdx);
continue;
for (unsigned int ringDivisor : {2, 3}) {
bool ringIsMultipleOfDivisor = ((sz % ringDivisor) == 0);
auto incrementSize = sz / ringDivisor;
if (ringIsMultipleOfDivisor) {
// find the two indices of the atoms 1/3 the way around the ring
unsigned int otherFoundByBondCount = 0;
unsigned int otherFoundByAtomCount = 0;
for (unsigned int indexIncrement = incrementSize; indexIncrement < sz;
indexIncrement += incrementSize) {
auto otherIdx = aring[(ai + indexIncrement) % sz];
auto otherAtom = mol.getAtomWithIdx(otherIdx);
for (auto bond : mol.atomBonds(otherAtom)) {
auto bidx = bond->getIdx();
if ((knownBonds[bidx] ||
(possibleBonds && possibleBonds->test(bidx))) &&
std::find(bring.begin(), bring.end(), bidx) == bring.end()) {
otherFoundByBondCount++;
break;
}
}
if (otherFoundByBondCount == 0) {
if (knownAtoms[otherIdx] ||
(possibleAtoms && possibleAtoms->test(otherIdx))) {
otherFoundByAtomCount++;
}
}
}
if (otherFoundByBondCount == ringDivisor - 1 ||
otherFoundByAtomCount == ringDivisor - 1) {
nHere += 1 + otherFoundByBondCount;
for (unsigned int indexIncrement = 0; indexIncrement < sz;
indexIncrement += incrementSize) {
possibleAtomsInRing.set(aring[(ai + indexIncrement) % sz]);
}
if (ringDivisor == 2) {
mol.getAtomWithIdx(aidx)->setProp(
common_properties::_ringStereoOtherAtom,
aring[(ai + incrementSize) % sz]);
}
continue;
}
}
}

View File

@@ -2301,8 +2301,8 @@ TEST_CASE("ring bond stereochemistry in CXSMILES") {
{"C1CCCCC=CCCC1 |c:5|", "C1=C\\CCCCCCCC/1 |c:0|"},
{"C1CCCC/C=C/CCC1 |c:5|", "C1=C\\CCCCCCCC/1 |c:0|"},
{"C1=CCCCCCCCC1 |ctu:0|", "C1=CCCCCCCCC1 |ctu:0|"},
{"C=CCCCCCCCC |ctu:0|",
"C=CCCCCCCCC"} // we don't write the markers for non-ring bonds
{"C=CCCCCCCCC |ctu:0|", "C=CCCCCCCCC"}
// we don't write the markers for non-ring bonds
};
for (const auto &[smi, val] : tests) {
std::unique_ptr<RWMol> m{SmilesToMol(smi)};
@@ -2993,45 +2993,71 @@ TEST_CASE("Ignore atom map numbers") {
}
TEST_CASE("Github #7340", "[Reaction][CX][CXSmiles]") {
SECTION("Test getCXExtensions with a Vector"){
SECTION("Test getCXExtensions with a Vector") {
// Create the MOL_SPTR_VECT to hold the molecular pointers
const auto mols = {
"CCO* |$;;;_R1$(0,0,0;1.5,0,0;1.5,1.5,0;0,1.5,0)|"_smiles,
"C1CCCCC1 |$;label2;$|"_smiles,
"CC(=O)O |$;label1;$|"_smiles,
"*-C-* |$star_e;;star_e$,Sg:n:1::ht|"_smiles,
"CCO* |$;;;_R1$(0,0,0;1.5,0,0;1.5,1.5,0;0,1.5,0)|"_smiles,
"C1CCCCC1 |$;label2;$|"_smiles,
"CC(=O)O |$;label1;$|"_smiles,
"*-C-* |$star_e;;star_e$,Sg:n:1::ht|"_smiles,
};
std::vector<ROMol *> mol_vect;
mol_vect.reserve(mols.size());
for (const auto& mol : mols) {
mol_vect.push_back(mol.get());
for (const auto &mol : mols) {
mol_vect.push_back(mol.get());
}
// Write to smiles to populate atom and bond output order properties
for (const auto& entry : mol_vect) {
for (const auto &entry : mol_vect) {
MolToSmiles(*entry);
}
std::string cxExt = SmilesWrite::getCXExtensions(mol_vect, RDKit::SmilesWrite::CXSmilesFields::CX_ALL);
std::string cxExt = SmilesWrite::getCXExtensions(
mol_vect, RDKit::SmilesWrite::CXSmilesFields::CX_ALL);
CHECK(cxExt == "|(0,1.5,;1.5,1.5,;1.5,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,),$_R1;;;;;label2;;;;;;label1;;;star_e;;star_e$,Sg:n:15::ht:::|");
CHECK(
cxExt ==
"|(0,1.5,;1.5,1.5,;1.5,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,;0,0,),$_R1;;;;;label2;;;;;;label1;;;star_e;;star_e$,Sg:n:15::ht:::|");
}
SECTION("Expects an error"){
SECTION("Expects an error") {
const auto mols = {
"CCO* |$;;;_R1$(0,0,0;1.5,0,0;1.5,1.5,0;0,1.5,0)|"_smiles,
"C1CCCCC1 |$;label2;$|"_smiles,
"CC(=O)O |$;label1;$|"_smiles,
"*-C-* |$star_e;;star_e$,Sg:n:1::ht|"_smiles,
"CCO* |$;;;_R1$(0,0,0;1.5,0,0;1.5,1.5,0;0,1.5,0)|"_smiles,
"C1CCCCC1 |$;label2;$|"_smiles,
"CC(=O)O |$;label1;$|"_smiles,
"*-C-* |$star_e;;star_e$,Sg:n:1::ht|"_smiles,
};
std::vector<ROMol *> mol_vect;
mol_vect.reserve(mols.size());
for (const auto& mol : mols) {
mol_vect.push_back(mol.get());
for (const auto &mol : mols) {
mol_vect.push_back(mol.get());
}
CHECK_THROWS_AS(SmilesWrite::getCXExtensions(mol_vect, RDKit::SmilesWrite::CXSmilesFields::CX_ALL), ValueErrorException);
CHECK_THROWS_AS(SmilesWrite::getCXExtensions(
mol_vect, RDKit::SmilesWrite::CXSmilesFields::CX_ALL),
ValueErrorException);
}
}
TEST_CASE("trimethylcyclohexane") {
SECTION("Basic") {
UseLegacyStereoPerceptionFixture useLegacy(false);
auto smi = "C[C@H]1C[C@@H](C)C[C@@H](C)C1";
RDKit::v2::SmilesParse::SmilesParserParams smilesParserParams;
auto m1 = RDKit::v2::SmilesParse::MolFromSmiles(smi, smilesParserParams);
auto smiOut = RDKit::MolToCXSmiles(*m1);
CHECK(smiOut == "C[C@@H]1C[C@H](C)C[C@H](C)C1");
}
SECTION("WithEnhancedStereo") {
UseLegacyStereoPerceptionFixture useLegacy(false);
auto smi = "C[C@H]1C[C@@H](C)C[C@@H](C)C1 |o1:1,o2:6,o3:3|";
RDKit::v2::SmilesParse::SmilesParserParams smilesParserParams;
auto m1 = RDKit::v2::SmilesParse::MolFromSmiles(smi, smilesParserParams);
auto smiOut = RDKit::MolToCXSmiles(*m1);
CHECK(smiOut == "C[C@H]1C[C@H](C)C[C@H](C)C1 |o1:1,o2:3,o3:6|");
}
}