From 49ce3d0184bc6dbab634ab11b1c3d4877c077589 Mon Sep 17 00:00:00 2001 From: John Mayfield Date: Wed, 23 Aug 2023 15:20:42 +0100 Subject: [PATCH 1/4] Fix - avoid placing a wedge on the right-angled bond when a centre is D3 and two neighbours are co-linear. --- .../cdk/stereo/StereoElementFactory.java | 2 +- .../cdk/layout/NonplanarBonds.java | 39 ++++++++++++++----- .../cdk/layout/NonPlanarBondsTest.java | 35 ++++++++++++----- 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/base/standard/src/main/java/org/openscience/cdk/stereo/StereoElementFactory.java b/base/standard/src/main/java/org/openscience/cdk/stereo/StereoElementFactory.java index 85a28f5dfe0..5b0989cbebd 100644 --- a/base/standard/src/main/java/org/openscience/cdk/stereo/StereoElementFactory.java +++ b/base/standard/src/main/java/org/openscience/cdk/stereo/StereoElementFactory.java @@ -699,7 +699,7 @@ else if (delta < -threshold) { Vector2d v1 = toUnitVector(focus, bonds.get(0).getOther(focus)); Vector2d v2 = toUnitVector(focus, bonds.get(1).getOther(focus)); Vector2d v3 = toUnitVector(focus, bonds.get(2).getOther(focus)); - String ambiuousStereoMesg = "Ambiguous stereochemistry - 3 neighbours and two"; + String ambiuousStereoMesg = "Ambiguous stereochemistry - 3 neighbours and two bonds are co-linear"; if (Math.abs(signedAngle(v1,v2) - Math.PI) < threshold) { if (elevationOf(focus, bonds.get(0)) == 0 && elevationOf(focus, bonds.get(1)) == 0 && diff --git a/tool/sdg/src/main/java/org/openscience/cdk/layout/NonplanarBonds.java b/tool/sdg/src/main/java/org/openscience/cdk/layout/NonplanarBonds.java index c80b4a59328..fb185cba5a9 100644 --- a/tool/sdg/src/main/java/org/openscience/cdk/layout/NonplanarBonds.java +++ b/tool/sdg/src/main/java/org/openscience/cdk/layout/NonplanarBonds.java @@ -40,6 +40,7 @@ import org.openscience.cdk.stereo.Octahedral; import org.openscience.cdk.stereo.SquarePlanar; import org.openscience.cdk.stereo.TrigonalBipyramidal; +import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; import javax.vecmath.Point2d; @@ -637,6 +638,15 @@ private void swap(List l, int i, int j) { l.set(j, tmp); } + private IBond.Stereo invert(IBond.Stereo disp) { + switch (disp) { + case UP: return DOWN; + case DOWN: return UP; + default: return disp; + } + } + + private IBond.Stereo flip(IBond.Stereo disp) { switch (disp) { case UP: return UP_INVERTED; @@ -894,7 +904,10 @@ private void label(final ITetrahedralChirality element) { // hydrogen is opposite all three neighbors. The central label needs to // be inverted, atoms could be laid out like this automatically, consider // CC1C[C@H]2CC[C@@H]1C2 + // Like wise if the other two bonds are co-linear we should not place a + // wedge on the one off to the side (avoid is set). int invert = -1; + int avoid = -1; if (n == 3) { // find a triangle of non-sequential neighbors (sorted clockwise) // which has anti-clockwise winding @@ -903,22 +916,26 @@ private void label(final ITetrahedralChirality element) { Point2d b = focus.getPoint2d(); Point2d c = atoms[rank[(i + 2) % n]].getPoint2d(); double det = (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x); - if (det > 0) { - invert = rank[(i + 1) % n]; - break; - } + if (Math.abs(det) <= 0.05) + avoid = rank[(i + 1) % n]; // i,i+2 are co-linear, i+1=no wedge + else if (det > 0.05 && invert == -1) + invert = rank[(i + 1) % n]; // acute angle, invert wedge } } - + // assign all up/down labels to an auxiliary array IBond.Stereo[] labels = new IBond.Stereo[n]; + IBond.Stereo refWedge = p > 0 ? UP : DOWN; for (int i = 0; i < n; i++) { int v = rank[i]; - - // 4 neighbors (invert every other one) - if (n == 4) p *= -1; - - labels[v] = invert == v ? p > 0 ? DOWN : UP : p > 0 ? UP : DOWN; + // no wedge here (would be ambiguous) + if (avoid == v) + labels[v] = NONE; + // invert (if D3 acute, or odd index of D4) + else if (invert == v || (n == 4 && i % 2 == 0)) + labels[v] = invert(refWedge); + else + labels[v] = refWedge; } // set the label for the highest priority and available bond @@ -928,6 +945,8 @@ private void label(final ITetrahedralChirality element) { IBond bond = bonds[v]; if (bond.getStereo() != NONE || bond.getOrder() != SINGLE) continue; + if (labels[v] == NONE) + continue; // first label if (firstlabel == null) { bond.setAtoms(new IAtom[]{focus, atoms[v]}); // avoids UP_INVERTED/DOWN_INVERTED diff --git a/tool/sdg/src/test/java/org/openscience/cdk/layout/NonPlanarBondsTest.java b/tool/sdg/src/test/java/org/openscience/cdk/layout/NonPlanarBondsTest.java index 997d9e261fa..07301e466a7 100644 --- a/tool/sdg/src/test/java/org/openscience/cdk/layout/NonPlanarBondsTest.java +++ b/tool/sdg/src/test/java/org/openscience/cdk/layout/NonPlanarBondsTest.java @@ -34,6 +34,8 @@ import org.openscience.cdk.interfaces.IBond; import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.ITetrahedralChirality; +import org.openscience.cdk.io.MDLV2000Reader; +import org.openscience.cdk.io.MDLV2000Writer; import org.openscience.cdk.silent.Atom; import org.openscience.cdk.silent.AtomContainer; import org.openscience.cdk.silent.SilentChemObjectBuilder; @@ -41,10 +43,15 @@ import org.openscience.cdk.stereo.Atropisomeric; import org.openscience.cdk.stereo.DoubleBondStereochemistry; import org.openscience.cdk.stereo.ExtendedTetrahedral; +import org.openscience.cdk.stereo.StereoElementFactory; import org.openscience.cdk.stereo.TetrahedralChirality; +import org.openscience.cdk.tools.ILoggingTool; +import org.openscience.cdk.tools.LoggingToolFactory; import javax.vecmath.Point2d; +import java.io.StringReader; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; @@ -322,8 +329,8 @@ void clockwiseSortShouldHandleExactlyOppositeAtoms() throws Exception { NonplanarBonds.assign(m); assertThat(m.getBond(2).getStereo(), is(IBond.Stereo.UP)); } - - + + // ethene is left alone and not marked as crossed @Test void dontCrossEtheneDoubleBond() { @@ -411,8 +418,8 @@ void useCrossedBondIfNeeded() { } /** - * @cdk.inchi InChI=1S/C6H14S/c1-5-7(4)6(2)3/h5H2,1-4H3/t7-/m0/s1 - */ + * @cdk.inchi InChI=1S/C6H14S/c1-5-7(4)6(2)3/h5H2,1-4H3/t7-/m0/s1 + */ @Test void dontMarkTetrahedralCentresWithDoubleBondsAsUnspecified() { IAtomContainer m = new AtomContainer(); @@ -436,7 +443,7 @@ void dontMarkTetrahedralCentresWithDoubleBondsAsUnspecified() { assertThat(m.getBond(2).getStereo(), is(not(IBond.Stereo.UP_OR_DOWN))); assertThat(m.getBond(3).getStereo(), is(not(IBond.Stereo.UP_OR_DOWN))); } - + @Test void dontMarkRingBondsInBezeneAsUnspecified() { IAtomContainer m = new AtomContainer(); @@ -454,7 +461,7 @@ void dontMarkRingBondsInBezeneAsUnspecified() { m.addBond(0, 5, IBond.Order.SINGLE); NonplanarBonds.assign(m); for (IBond bond : m.bonds()) { - assertThat(bond.getStereo(), is(IBond.Stereo.NONE)); + assertThat(bond.getStereo(), is(IBond.Stereo.NONE)); } } @@ -644,8 +651,8 @@ void atropisomerWedgeBonds() throws CDKException { SmilesParser smipar = new SmilesParser(SilentChemObjectBuilder.getInstance()); IAtomContainer mol = smipar.parseSmiles("OC1=CC=C2C=CC=CC2=C1C1=C(O)C=CC2=C1C=CC=C2"); - IBond focus = mol.getBond(mol.getAtom(10), - mol.getAtom(11)); + IBond focus = mol.getBond(mol.getAtom(10), + mol.getAtom(11)); List carriers = new ArrayList<>(); carriers.addAll(mol.getConnectedAtomsList(focus.getBegin())); carriers.addAll(mol.getConnectedAtomsList(focus.getEnd())); @@ -664,7 +671,7 @@ void atropisomerWedgeBonds() throws CDKException { assertThat(bond2.getOrder(), is(IBond.Order.SINGLE)); Assertions.assertTrue(bond1.getStereo() == IBond.Stereo.DOWN || - bond2.getStereo() == IBond.Stereo.DOWN, "One of the single bonds should have been wedged"); + bond2.getStereo() == IBond.Stereo.DOWN, "One of the single bonds should have been wedged"); } @@ -775,4 +782,14 @@ static IAtom atom(String symbol, int hCount, double x, double y) { return a; } + @Test + void testColinearD3bonds() throws CDKException { + SmilesParser smipar = new SmilesParser(SilentChemObjectBuilder.getInstance()); + IAtomContainer mol = smipar.parseSmiles("[C@@H]12[C@@H]([C@H]([C@@H]([C@@H](CO1)O2)O)O)O |(1.3,0.1,;1.3,-1.4,;0.01,-2.15,;-1.29,-1.4,;-1.29,0.1,;-1.29,1.95,;1.26,1.93,;0.01,0.85,;-2.59,-2.15,;0.01,-3.65,;2.6,-2.15,)|"); + NonplanarBonds.assign(mol); + // there are 4 + Assertions.assertEquals(5, + StereoElementFactory.using2DCoordinates(mol).withStrictMode().createAll().size()); + } + } From 250bcf1e0d117774ffbf947a3f79f874c104154d Mon Sep 17 00:00:00 2001 From: John Mayfield Date: Wed, 23 Aug 2023 15:26:42 +0100 Subject: [PATCH 2/4] Update this template to avoid ambiguous stereo assignment. --- .../org/openscience/cdk/layout/chebi-ring-templates.smi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/sdg/src/main/resources/org/openscience/cdk/layout/chebi-ring-templates.smi b/tool/sdg/src/main/resources/org/openscience/cdk/layout/chebi-ring-templates.smi index ee727ed3817..a961c98c667 100644 --- a/tool/sdg/src/main/resources/org/openscience/cdk/layout/chebi-ring-templates.smi +++ b/tool/sdg/src/main/resources/org/openscience/cdk/layout/chebi-ring-templates.smi @@ -440,7 +440,7 @@ N1NCCN1 |(.0,1.28,;1.21,.39,;.75,-1.03,;-.75,-1.03,;-1.21,.39,)| OC1CC(O)CC(C)C1 |(-.0,3.0,;-.0,1.5,;-1.3,.75,;-1.3,-.75,;-2.6,-1.5,;.0,-1.5,;1.3,-.75,;2.6,-1.5,;1.3,.75,)| OC1NC(N)NC(C)C1 |(-2.6,-1.5,;-1.3,-.75,;.0,-1.5,;1.3,-.75,;2.6,-1.5,;1.3,.75,;.0,1.5,;.0,3.0,;-1.3,.75,)| NC1CC(N)C(C)C(N)C1 |(.0,-3.3,;.0,-1.8,;1.3,-1.05,;1.3,.45,;2.6,1.2,;.0,1.2,;.0,2.7,;-1.3,.45,;-2.6,1.2,;-1.3,-1.05,)| -O1CC2OC1CCC2 |(1.26,1.93,;-1.29,1.95,;-1.29,.1,;.01,.85,;1.3,.1,;1.3,-1.4,;.01,-2.15,;-1.29,-1.4,)| +O1CC2OC1CCC2 |(1.64,0.75,;1.64,-0.75,;0.47,-1.69,;-0.5,,;0.47,1.69,;-0.99,1.35,;-1.64,,;-0.99,-1.35,)| OC1CC2N(C)C(CC2)C1 |(3.06,.0,;1.6,.0,;.86,-1.27,;-.6,-1.6,;-1.33,.0,;.17,.0,;-.6,1.6,;-2.01,.89,;-2.01,-.89,;.86,1.27,)| N1CC2CN3CCCCC3C(C1)C2 |(-2.92,.73,;-2.92,-.77,;-1.85,-1.83,;-.35,-1.83,;.71,-.77,;2.01,-1.51,;3.31,-.77,;3.31,.73,;2.01,1.49,;.71,.73,;-.35,1.79,;-1.85,1.79,;-1.79,.18,)| SC1CCCCC1 |(2.23,1.29,;.93,.54,;.93,-.96,;-.37,-1.71,;-1.67,-.96,;-1.67,.54,;-.37,1.29,)| From 41fff70a3c0553391d67e302dc892a81e4990aec Mon Sep 17 00:00:00 2001 From: John Mayfield Date: Wed, 23 Aug 2023 15:29:26 +0100 Subject: [PATCH 3/4] Better template orrientation. --- .../org/openscience/cdk/layout/chebi-ring-templates.smi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tool/sdg/src/main/resources/org/openscience/cdk/layout/chebi-ring-templates.smi b/tool/sdg/src/main/resources/org/openscience/cdk/layout/chebi-ring-templates.smi index a961c98c667..1c2854b3128 100644 --- a/tool/sdg/src/main/resources/org/openscience/cdk/layout/chebi-ring-templates.smi +++ b/tool/sdg/src/main/resources/org/openscience/cdk/layout/chebi-ring-templates.smi @@ -440,7 +440,7 @@ N1NCCN1 |(.0,1.28,;1.21,.39,;.75,-1.03,;-.75,-1.03,;-1.21,.39,)| OC1CC(O)CC(C)C1 |(-.0,3.0,;-.0,1.5,;-1.3,.75,;-1.3,-.75,;-2.6,-1.5,;.0,-1.5,;1.3,-.75,;2.6,-1.5,;1.3,.75,)| OC1NC(N)NC(C)C1 |(-2.6,-1.5,;-1.3,-.75,;.0,-1.5,;1.3,-.75,;2.6,-1.5,;1.3,.75,;.0,1.5,;.0,3.0,;-1.3,.75,)| NC1CC(N)C(C)C(N)C1 |(.0,-3.3,;.0,-1.8,;1.3,-1.05,;1.3,.45,;2.6,1.2,;.0,1.2,;.0,2.7,;-1.3,.45,;-2.6,1.2,;-1.3,-1.05,)| -O1CC2OC1CCC2 |(1.64,0.75,;1.64,-0.75,;0.47,-1.69,;-0.5,,;0.47,1.69,;-0.99,1.35,;-1.64,,;-0.99,-1.35,)| +O1CC2OC1CCC2 |(-0.75,1.64,;0.75,1.64,;1.69,0.47,;,-0.5,;-1.69,0.47,;-1.35,-0.99,;,-1.64,;1.35,-0.99,)| OC1CC2N(C)C(CC2)C1 |(3.06,.0,;1.6,.0,;.86,-1.27,;-.6,-1.6,;-1.33,.0,;.17,.0,;-.6,1.6,;-2.01,.89,;-2.01,-.89,;.86,1.27,)| N1CC2CN3CCCCC3C(C1)C2 |(-2.92,.73,;-2.92,-.77,;-1.85,-1.83,;-.35,-1.83,;.71,-.77,;2.01,-1.51,;3.31,-.77,;3.31,.73,;2.01,1.49,;.71,.73,;-.35,1.79,;-1.85,1.79,;-1.79,.18,)| SC1CCCCC1 |(2.23,1.29,;.93,.54,;.93,-.96,;-.37,-1.71,;-1.67,-.96,;-1.67,.54,;-.37,1.29,)| From 44d3df0740cc29f91d7423d70a7492db9ae163da Mon Sep 17 00:00:00 2001 From: John Mayfield Date: Wed, 23 Aug 2023 15:37:14 +0100 Subject: [PATCH 4/4] Unused import --- .../src/main/java/org/openscience/cdk/layout/NonplanarBonds.java | 1 - 1 file changed, 1 deletion(-) diff --git a/tool/sdg/src/main/java/org/openscience/cdk/layout/NonplanarBonds.java b/tool/sdg/src/main/java/org/openscience/cdk/layout/NonplanarBonds.java index fb185cba5a9..104f415f9bf 100644 --- a/tool/sdg/src/main/java/org/openscience/cdk/layout/NonplanarBonds.java +++ b/tool/sdg/src/main/java/org/openscience/cdk/layout/NonplanarBonds.java @@ -40,7 +40,6 @@ import org.openscience.cdk.stereo.Octahedral; import org.openscience.cdk.stereo.SquarePlanar; import org.openscience.cdk.stereo.TrigonalBipyramidal; -import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; import javax.vecmath.Point2d;