Repository: rdkit/rdkit — pull request #6901 (cpp)
Title: Removing stereoatoms requires removing CIS/Trans stereo flags

Fixes #6900 

When we remove stereo atoms from a cis/trans bond we should also remove the CIS/TRANS stereo flags since they require stereo atoms for canonicalization.

This might not be the correct fix for this particular problem since we should want:

"C/C=C/N" to fragment with the  into "*/C=C/N" not 
"*C=CN"

However, because we removethe first bond which affects the stereo atoms in the double bond, this causes the errors down stream.

The correct fix is probably to have a custom removeBond that detects this and handles it correctly by adding the new dummy atoms to the stereo bond.

However this fix preserves the current behavior:

```
mol = MolFromSmiles("N/C=C/C")
frag1 = rdMMPA.FragmentMol(mol)

for a,b in frag1:
    if a: print(Chem.MolToSmiles(a),end=", ")
    else: print(a,end=", " )
    print(Chem.MolToSmiles(b))
```

results in 

```
None, CC=C[*:1].N[*:1]
C(=C[*:2])[*:1], C[*:1].N[*:2]
None, C[*:1].NC=C[*:1]
```

Resolved issues:
title: MMPA FragmentMol segfaults when new stereo perception is turned on
body: For this molecule, the MMPA fragmentation runs fine when legacy stereo perception is used but crashes otherwise

```
>>> from rdkit.Chem import MolFromSmiles
>>> from rdkit.Chem import rdMMPA
>>> from rdkit.Chem import rdmolops
>>> rdmolops.SetUseLegacyStereoPerception(False)
>>> mol = MolFromSmiles("CN1CCCN=C1/C=C/c1cccs1")
>>> frag1 = rdMMPA.FragmentMol(mol)
zsh: segmentation fault  python

```


Hints:

Fix patch:
diff --git a/Code/GraphMol/RWMol.cpp b/Code/GraphMol/RWMol.cpp
index e92e6cc5ead..d102bacaf15 100644
--- a/Code/GraphMol/RWMol.cpp
+++ b/Code/GraphMol/RWMol.cpp
@@ -468,6 +468,12 @@ void RWMol::removeBond(unsigned int aid1, unsigned int aid2) {
     }
     if (std::find(obnd->getStereoAtoms().begin(), obnd->getStereoAtoms().end(),
                   aid2) != obnd->getStereoAtoms().end()) {
+      // github #6900 if we remove stereo atoms we need to remove
+      //  the CIS and or TRANS since this requires stereo atoms
+      if (obnd->getStereo() == Bond::BondStereo::STEREOCIS ||
+          obnd->getStereo() == Bond::BondStereo::STEREOTRANS ) {
+          obnd->setStereo(Bond::BondStereo::STEREONONE);
+      }
       obnd->getStereoAtoms().clear();
     }
   }
@@ -484,6 +490,12 @@ void RWMol::removeBond(unsigned int aid1, unsigned int aid2) {
     }
     if (std::find(obnd->getStereoAtoms().begin(), obnd->getStereoAtoms().end(),
                   aid1) != obnd->getStereoAtoms().end()) {
+      // github #6900 if we remove stereo atoms we need to remove
+      //  the CIS and or TRANS since this requires stereo atoms
+      if (obnd->getStereo() == Bond::BondStereo::STEREOCIS ||
+        obnd->getStereo() == Bond::BondStereo::STEREOTRANS ) {
+        obnd->setStereo(Bond::BondStereo::STEREONONE);
+      }
       obnd->getStereoAtoms().clear();
     }
   }
diff --git a/Code/GraphMol/catch_chirality.cpp b/Code/GraphMol/catch_chirality.cpp
index c3d5c2f5849..f449aaf03de 100644
--- a/Code/GraphMol/catch_chirality.cpp
+++ b/Code/GraphMol/catch_chirality.cpp
@@ -1297,6 +1297,26 @@ TEST_CASE("ring stereo finding is overly aggressive", "[chirality][bug]") {
         Chirality::findPotentialStereo(*mol, cleanIt, flagPossible);
     CHECK(stereoInfo.size() == 2);
   }
+  SECTION("Removal of stereoatoms requires removing CIS/TRANS when using legacy stereo") {
+      UseLegacyStereoPerceptionFixture reset_stereo_perception;
+      Chirality::setUseLegacyStereoPerception(false);
+
+    {
+      auto mol = "N/C=C/C"_smiles;
+      CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::BondStereo::STEREOTRANS);
+      auto rwmol = dynamic_cast<RWMol*>(mol.get());
+      rwmol->removeBond(0,1);
+      CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::BondStereo::STEREONONE);
+    }
+    {
+      auto mol = "N/C=C/C"_smiles;
+      CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::BondStereo::STEREOTRANS);
+      auto rwmol = dynamic_cast<RWMol*>(mol.get());
+      rwmol->removeBond(2,3);
+      CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::BondStereo::STEREONONE);
+    }
+	  
+  }
 }
 
 TEST_CASE(


Test patch:
diff --git a/Code/GraphMol/MMPA/MMPA_UnitTest.cpp b/Code/GraphMol/MMPA/MMPA_UnitTest.cpp
index 962d2558e49..a82c1700704 100644
--- a/Code/GraphMol/MMPA/MMPA_UnitTest.cpp
+++ b/Code/GraphMol/MMPA/MMPA_UnitTest.cpp
@@ -49,6 +49,7 @@
 #include <iostream>
 #include <RDGeneral/RDLog.h>
 #include <RDGeneral/utils.h>
+#include <GraphMol/Chirality.h>
 #include "../RDKitBase.h"
 #include "../FileParsers/FileParsers.h"  //MOL single molecule !
 #include "../FileParsers/MolSupplier.h"  //SDF
@@ -690,6 +691,14 @@ std::endl;
 //====================================================================================================
 //====================================================================================================
 
+void testGithub6900 () {
+  RDKit::Chirality::setUseLegacyStereoPerception(false);
+  //auto mol = "CN1CCCN=C1/C=C/c1cccs1"_smiles;
+  auto mol = "N/C=C/C"_smiles;
+  std::vector<std::pair<ROMOL_SPTR, ROMOL_SPTR>> res;
+  RDKit::MMPA::fragmentMol(*mol, res, 3);
+  RDKit::Chirality::setUseLegacyStereoPerception(true);
+}
 int main() {
   BOOST_LOG(rdInfoLog)
       << "*******************************************************\n";
@@ -703,7 +712,7 @@ int main() {
 #else
   setpriority(PRIO_PROCESS, getpid(), -20);
 #endif
-
+  testGithub6900();
   T0 = nanoClock();
   t0 = nanoClock();
 
@@ -711,6 +720,7 @@ int main() {
   // /*
   test2();
   test3();
+    
   //    test4();
   // */
   //    debugTest1("C[*:1].O=C(NCCO)c1c([*:1])n([O-])c2ccccc2[n+]1=O");