Task: Fixes #7552 (rdkit/rdkit#7564)

org: rdkit
repo: rdkit
pr_number: 7564
issue_title: Fixes #7552
issue_body: This adds code to recognize tetrahedral centers which are involved in more than one ring with < members and be more tolerant when checking their geometries.
resolved_issues: number: 7552
title: AllChem.EmbedMolecule returns -1
body: Howdy,

I want to get the 3D conformation information for any given molecule; however, some molecules fail to produce the conformer. Following is the code that reproduces the issue.

`from rdkit import Chem`
`from rdkit.Chem import AllChem`
`sample_smiles = 'O=CCC1OC2COC12'`
`mol = Chem.AddHs(Chem.MolFromSmiles(sample_smiles))`
`AllChem.EmbedMolecule(mol) # -1`

If the molecule can generate conformation information, `AllChem.EmbedMolecule()` would return 0; I have identified many smiles/molecules that result in -1 when calling `AllChem.EmbedMolecule(mol)` , you may find some of those smiles in the picture below.

![image](https://github.com/rdkit/rdkit/assets/40327643/bab1a067-2e7d-492e-b4fc-782ab9260f5e)

Appreciate any suggestions! 



Reference solution:
fix_patch: diff --git a/Code/DistGeom/ChiralSet.h b/Code/DistGeom/ChiralSet.h
index 6b9a077dfe6..a1b26035cb0 100644
--- a/Code/DistGeom/ChiralSet.h
+++ b/Code/DistGeom/ChiralSet.h
@@ -17,6 +17,11 @@
 
 namespace DistGeom {
 
+enum class ChiralSetStructureFlags : std::uint64_t {
+  IN_FUSED_SMALL_RINGS =
+      1 << 0,  // a chiral center involved in fusing 2 or more small rings
+};
+
 /*! \brief Class used to store a quartet of points and chiral volume bounds on
  *them
  *
@@ -30,17 +35,20 @@ class RDKIT_DISTGEOMETRY_EXPORT ChiralSet {
   unsigned int d_idx4;
   double d_volumeLowerBound;
   double d_volumeUpperBound;
+  std::uint64_t d_structureFlags =
+      0;  // used to track special cases that may make embedding more difficult
 
   ChiralSet(unsigned int pid0, unsigned int pid1, unsigned int pid2,
             unsigned int pid3, unsigned int pid4, double lowerVolBound,
-            double upperVolBound)
+            double upperVolBound, std::uint64_t structureFlags = 0)
       : d_idx0(pid0),
         d_idx1(pid1),
         d_idx2(pid2),
         d_idx3(pid3),
         d_idx4(pid4),
         d_volumeLowerBound(lowerVolBound),
-        d_volumeUpperBound(upperVolBound) {
+        d_volumeUpperBound(upperVolBound),
+        d_structureFlags(structureFlags) {
     CHECK_INVARIANT(lowerVolBound <= upperVolBound, "Inconsistent bounds\n");
     d_volumeLowerBound = lowerVolBound;
     d_volumeUpperBound = upperVolBound;
diff --git a/Code/GraphMol/DistGeomHelpers/Embedder.cpp b/Code/GraphMol/DistGeomHelpers/Embedder.cpp
index 1ce159a81df..ee97ccde868 100644
--- a/Code/GraphMol/DistGeomHelpers/Embedder.cpp
+++ b/Code/GraphMol/DistGeomHelpers/Embedder.cpp
@@ -308,12 +308,21 @@ bool _volumeTest(const DistGeom::ChiralSetPtr &chiralSet,
   RDGeom::Point3D v4 = p0 - p4;
   v4.normalize();
 
+  // be more tolerant of tethrahedral centers that are involved in multiple
+  // small rings
+  double volScale = 1;
+  if (chiralSet->d_structureFlags &
+      static_cast<std::uint64_t>(
+          DistGeom::ChiralSetStructureFlags::IN_FUSED_SMALL_RINGS)) {
+    volScale = 0.25;
+  }
+
   RDGeom::Point3D crossp = v1.crossProduct(v2);
   double vol = crossp.dotProduct(v3);
   if (verbose) {
     std::cerr << "   " << fabs(vol) << std::endl;
   }
-  if (fabs(vol) < MIN_TETRAHEDRAL_CHIRAL_VOL) {
+  if (fabs(vol) < volScale * MIN_TETRAHEDRAL_CHIRAL_VOL) {
     return false;
   }
   crossp = v1.crossProduct(v2);
@@ -321,7 +330,7 @@ bool _volumeTest(const DistGeom::ChiralSetPtr &chiralSet,
   if (verbose) {
     std::cerr << "   " << fabs(vol) << std::endl;
   }
-  if (fabs(vol) < MIN_TETRAHEDRAL_CHIRAL_VOL) {
+  if (fabs(vol) < volScale * MIN_TETRAHEDRAL_CHIRAL_VOL) {
     return false;
   }
   crossp = v1.crossProduct(v3);
@@ -329,7 +338,7 @@ bool _volumeTest(const DistGeom::ChiralSetPtr &chiralSet,
   if (verbose) {
     std::cerr << "   " << fabs(vol) << std::endl;
   }
-  if (fabs(vol) < MIN_TETRAHEDRAL_CHIRAL_VOL) {
+  if (fabs(vol) < volScale * MIN_TETRAHEDRAL_CHIRAL_VOL) {
     return false;
   }
   crossp = v2.crossProduct(v3);
@@ -337,7 +346,7 @@ bool _volumeTest(const DistGeom::ChiralSetPtr &chiralSet,
   if (verbose) {
     std::cerr << "   " << fabs(vol) << std::endl;
   }
-  return fabs(vol) >= MIN_TETRAHEDRAL_CHIRAL_VOL;
+  return fabs(vol) >= volScale * MIN_TETRAHEDRAL_CHIRAL_VOL;
 }
 
 bool _sameSide(const RDGeom::Point3D &v1, const RDGeom::Point3D &v2,
@@ -1035,19 +1044,33 @@ void findChiralSets(const ROMol &mol, DistGeom::VECT_CHIRALSET &chiralCenters,
           nbrs.insert(nbrs.end(), atom->getIdx());
         }
 
+        // set a flag for tetrahedral centers that are in multiple small rings
+        auto numSmallRings = 0u;
+        constexpr int smallRingSize = 5;
+        for (const auto sz : mol.getRingInfo()->atomRingSizes(atom->getIdx())) {
+          if (sz < smallRingSize) {
+            ++numSmallRings;
+          }
+        }
+        std::uint64_t structureFlags = 0;
+        if (numSmallRings > 1) {
+          structureFlags = static_cast<std::uint64_t>(
+              DistGeom::ChiralSetStructureFlags::IN_FUSED_SMALL_RINGS);
+        }
+
         // now create a chiral set and set the upper and lower bound on the
         // volume
         if (chiralType == Atom::CHI_TETRAHEDRAL_CCW) {
           // positive chiral volume
-          auto *cset =
-              new DistGeom::ChiralSet(atom->getIdx(), nbrs[0], nbrs[1], nbrs[2],
-                                      nbrs[3], volLowerBound, volUpperBound);
+          auto *cset = new DistGeom::ChiralSet(atom->getIdx(), nbrs[0], nbrs[1],
+                                               nbrs[2], nbrs[3], volLowerBound,
+                                               volUpperBound, structureFlags);
           DistGeom::ChiralSetPtr cptr(cset);
           chiralCenters.push_back(cptr);
         } else if (chiralType == Atom::CHI_TETRAHEDRAL_CW) {
-          auto *cset =
-              new DistGeom::ChiralSet(atom->getIdx(), nbrs[0], nbrs[1], nbrs[2],
-                                      nbrs[3], -volUpperBound, -volLowerBound);
+          auto *cset = new DistGeom::ChiralSet(atom->getIdx(), nbrs[0], nbrs[1],
+                                               nbrs[2], nbrs[3], -volUpperBound,
+                                               -volLowerBound, structureFlags);
           DistGeom::ChiralSetPtr cptr(cset);
           chiralCenters.push_back(cptr);
         } else {
@@ -1059,8 +1082,9 @@ void findChiralSets(const ROMol &mol, DistGeom::VECT_CHIRALSET &chiralCenters,
             // the coordMap
             // there's no sense doing 3-rings because those are a nightmare
           } else {
-            auto *cset = new DistGeom::ChiralSet(
-                atom->getIdx(), nbrs[0], nbrs[1], nbrs[2], nbrs[3], 0.0, 0.0);
+            auto *cset = new DistGeom::ChiralSet(atom->getIdx(), nbrs[0],
+                                                 nbrs[1], nbrs[2], nbrs[3], 0.0,
+                                                 0.0, structureFlags);
             DistGeom::ChiralSetPtr cptr(cset);
             tetrahedralCenters.push_back(cptr);
           }