Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support allenes in canonicalizing double bonds, fixes #7044 #7137

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
10 changes: 7 additions & 3 deletions Code/GraphMol/Canon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,13 @@ void canonicalizeDoubleBond(Bond *dblBond, UINT_VECT &bondVisitOrders,
firstVisitOrder = mol.getNumBonds() + 1;
findNeighborBonds(atom2, firstFromAtom2, secondFromAtom2, dir2Set);

// make sure we found everything we need to find:
CHECK_INVARIANT(firstFromAtom1, "could not find atom1");
CHECK_INVARIANT(firstFromAtom2, "could not find atom2");
// Make sure we found everything we need to find.
// This really shouldn't be a problem, but molecules can end up in odd
// states; for example, allenes can end up here. Instead of checking for them
// explicitly, exit early in any such possible state.
if (!firstFromAtom1 || !firstFromAtom2) {
return;
}

bool setFromBond1 = true;
Bond::BondDir atom1Dir = Bond::NONE;
Expand Down
60 changes: 59 additions & 1 deletion Code/GraphMol/MolStandardize/testTautomer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,14 @@ void testEnumerator() {
checkAns("C/C=C/C(C)=O", {"C=C(O)C=CC", "C=CC=C(C)O", "C=CCC(=C)O",
"C=CCC(C)=O", "CC=CC(C)=O"});

// No stereochemistry in conjugated double bonds to nitro
checkAns("c1ccnc(c1)C=C[N+](=O)[O-]", {"O=[N+]([O-])C=Cc1ccccn1",
"[O-][N+](O)=C=Cc1ccccn1"});

// Retain stereochemistry in conjugated double bonds to nitro
checkAns("c1ccnc(c1)/C=C/[N+](=O)[O-]", {"O=[N+]([O-])/C=C/c1ccccn1",
"[O-][N+](O)=C=Cc1ccccn1"});

// Remove stereochemistry from mobile double bonds
std::string smi66 = "C/C=C\\C(C)=O";
ROMOL_SPTR m66(SmilesToMol(smi66));
Expand All @@ -334,7 +342,7 @@ void testEnumerator() {
std::sort(ans66.begin(), ans66.end());
TEST_ASSERT(sm66 == ans66);

// Gaunine tautomers
// Guanine tautomers
std::string smi67 = "N1C(N)=NC=2N=CNC2C1=O";
ROMOL_SPTR m67(SmilesToMol(smi67));
TautomerEnumeratorResult res67 = te.enumerate(*m67);
Expand Down Expand Up @@ -490,6 +498,56 @@ void testEnumeratorParams() {
}
}
}
std::string eOximeSmi = "c1ccnc(c1)/C=N/O";
ROMOL_SPTR eOxime(SmilesToMol(eOximeSmi));
TEST_ASSERT(eOxime->getBondWithIdx(6)->getStereo() == Bond::STEREOE);
{
// test remove oxime E stereochemistry
CleanupParameters params;
params.tautomerRemoveBondStereo = true;
TautomerEnumerator te(params);
TautomerEnumeratorResult res = te.enumerate(*eOxime);
for (const auto &taut : res) {
TEST_ASSERT(taut->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
}
}
{
// test retain enol E stereochemistry
CleanupParameters params;
params.tautomerRemoveBondStereo = false;
TautomerEnumerator te(params);
TautomerEnumeratorResult res = te.enumerate(*eOxime);
for (const auto &taut : res) {
if (taut->getBondWithIdx(6)->getBondType() == Bond::DOUBLE) {
TEST_ASSERT(taut->getBondWithIdx(6)->getStereo() == Bond::STEREOE);
}
}
}
ROMOL_SPTR zOxime = "c1ccnc(c1)/C=N\\O"_smiles;
// zOxime->debugMol(std::cerr);
TEST_ASSERT(zOxime->getBondWithIdx(6)->getStereo() == Bond::STEREOZ);
{
// test remove enol Z stereochemistry
CleanupParameters params;
params.tautomerRemoveBondStereo = true;
TautomerEnumerator te(params);
TautomerEnumeratorResult res = te.enumerate(*zOxime);
for (const auto &taut : res) {
TEST_ASSERT(taut->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
}
}
{
// test retain enol Z stereochemistry
CleanupParameters params;
params.tautomerRemoveBondStereo = false;
TautomerEnumerator te(params);
TautomerEnumeratorResult res = te.enumerate(*zOxime);
for (const auto &taut : res) {
if (taut->getBondWithIdx(6)->getBondType() == Bond::DOUBLE) {
TEST_ASSERT(taut->getBondWithIdx(6)->getStereo() == Bond::STEREOZ);
}
}
}
ROMOL_SPTR chembl2024142 =
"[2H]C1=C(C(=C2C(=C1[2H])C(=O)C(=C(C2=O)C([2H])([2H])[2H])C/C=C(\\C)/CC([2H])([2H])/C=C(/CC/C=C(\\C)/CCC=C(C)C)\\C([2H])([2H])[2H])[2H])[2H]"_smiles;
MolOps::RemoveHsParameters hparams;
Expand Down
13 changes: 13 additions & 0 deletions Code/GraphMol/catch_graphmol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3475,6 +3475,19 @@ TEST_CASE(
CHECK(bnd->getStereoAtoms().empty());
}

TEST_CASE(
"github #7044: canonicalization error when allenes have specified stereo") {
SECTION("basics") {
auto m = "CC=C=CC"_smiles;
REQUIRE(m);
m->getBondWithIdx(2)->setStereoAtoms(1, 4);
m->getBondWithIdx(2)->setStereo(Bond::STEREOCIS);

auto smi = MolToSmiles(*m);
CHECK(smi == "CC=C=CC");
}
}

TEST_CASE(
"Github Issue #7128: ReplaceBond may cause valence issues in specific edge cases",
"[bug][RWMol]") {
Expand Down