From 9827d076bfd59429e06bf48ec1c087e94f3fae3a Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Mon, 4 Dec 2023 15:29:03 -0500 Subject: [PATCH 1/9] fixed CIP stereo bug --- .../ncats/molwitch/cdk/CdkChemicalImpl.java | 32 ++++++- src/test/java/TestChiralRead.java | 86 +++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java index fae4832..3469012 100644 --- a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java +++ b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java @@ -53,8 +53,17 @@ import org.openscience.cdk.aromaticity.ElectronDonation; import org.openscience.cdk.aromaticity.Kekulization; import org.openscience.cdk.atomtype.CDKAtomTypeMatcher; +import org.openscience.cdk.config.IsotopeFactory; +import org.openscience.cdk.config.Isotopes; import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.geometry.cip.CIPTool; +import org.openscience.cdk.geometry.cip.ILigand; +import org.openscience.cdk.geometry.cip.ImplicitHydrogenLigand; +import org.openscience.cdk.geometry.cip.Ligand; +import org.openscience.cdk.geometry.cip.VisitedAtoms; +import org.openscience.cdk.geometry.cip.CIPTool.CIP_CHIRALITY; +import org.openscience.cdk.geometry.cip.CIPToolMod; +import org.openscience.cdk.geometry.cip.rules.ISequenceSubRule; import org.openscience.cdk.graph.ConnectivityChecker; import org.openscience.cdk.graph.Cycles; import org.openscience.cdk.graph.GraphUtil; @@ -67,6 +76,7 @@ import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IDoubleBondStereochemistry; +import org.openscience.cdk.interfaces.IIsotope; import org.openscience.cdk.interfaces.IMolecularFormula; import org.openscience.cdk.interfaces.IRing; import org.openscience.cdk.interfaces.IRingSet; @@ -91,6 +101,8 @@ import org.openscience.cdk.stereo.StereoElementFactory; import org.openscience.cdk.stereo.Stereocenters; import org.openscience.cdk.tools.CDKHydrogenAdder; +import org.openscience.cdk.tools.ILoggingTool; +import org.openscience.cdk.tools.LoggingToolFactory; import org.openscience.cdk.tools.manipulator.AtomContainerManipulator; import org.openscience.cdk.tools.manipulator.AtomTypeManipulator; import org.openscience.cdk.tools.manipulator.MolecularFormulaManipulator; @@ -198,6 +210,9 @@ public class CdkChemicalImpl implements ChemicalImpl{ } ); + + + CachedSupplier cahnIngoldPrelogSupplier = CachedSupplier.of(()->{ try { makeStereoElms() ; @@ -207,13 +222,22 @@ public class CdkChemicalImpl implements ChemicalImpl{ withModifiedForm(c->{ CdkChemicalImpl cimp = (CdkChemicalImpl) c.getImpl(); // cimp. - CIPTool.label(cimp.getContainer()); + + //Due to a bug in CDK, this doesn't work as expected + //CIPTool.label(cimp.getContainer()); + + //We currently have to use a modified form for now + CIPToolMod.label(cimp.getContainer()); + for (int i = 0; i < container.getAtomCount(); i++) { IAtom ai =container.getAtom(i); IAtom ain =cimp.getContainer().getAtom(i); Object p = ain.getProperty(CDKConstants.CIP_DESCRIPTOR); + ai.removeProperty(CDKConstants.CIP_DESCRIPTOR); - ai.setProperty(CDKConstants.CIP_DESCRIPTOR, p); + if(p!=null) { + ai.setProperty(CDKConstants.CIP_DESCRIPTOR, p); + } } return null; @@ -1156,8 +1180,12 @@ public List getExtendedTetrahedrals() { } public T withModifiedForm(Function calc) { + + Chemical c = new Chemical(this); +// if(true)return calc.apply(c); + List> operations = new ArrayList<>(); diff --git a/src/test/java/TestChiralRead.java b/src/test/java/TestChiralRead.java index 6122674..23014fa 100644 --- a/src/test/java/TestChiralRead.java +++ b/src/test/java/TestChiralRead.java @@ -461,6 +461,92 @@ public void testHavingExplicitHydrogenOnStereoCenterDoesNotInvalidatePhosphateCe assertEquals(2,mol.getTetrahedrals().size()); } + @Test + public void testHavingBondTableOrderChangedShouldKeepSameStereo() throws Exception { + + + Chemical mol=Chemical.parse("\n" + + " JSDraw212042310502D\n" + + "\n" + + " 14 14 0 0 1 0 999 V2000\n" + + " 21.4047 -8.8605 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.0654 -9.2811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4188 -8.5056 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1278 -7.7212 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.9094 -6.8325 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.0050 -8.5767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.6898 -5.7439 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 28.1943 -6.0199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4240 -6.9456 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.5922 -5.3944 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.7756 -6.0051 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.5338 -4.4447 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.6247 -10.2116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.0654 -10.8412 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 3 6 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 5 7 1 0 0 0 0\n" + + " 7 8 1 0 0 0 0\n" + + " 3 9 1 0 0 0 0\n" + + " 9 4 1 0 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 9 10 1 1 0 0 0\n" + + " 4 11 1 0 0 0 0\n" + + " 7 12 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 1 13 1 0 0 0 0\n" + + " 2 14 1 0 0 0 0\n" + + "M END"); + Optional opChi=mol.getTetrahedrals().stream() + .map(ca->ca.getChirality()) + .filter(ca->!ca.isEither()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.R, opChi.get()); + + + mol=Chemical.parse("\n" + + " JSDraw212042310502D\n" + + "\n" + + " 14 14 0 0 1 0 999 V2000\n" + + " 21.4047 -8.8605 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.0654 -9.2811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4188 -8.5056 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1278 -7.7212 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.9094 -6.8325 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.0050 -8.5767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.6898 -5.7439 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 28.1943 -6.0199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4240 -6.9456 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.5922 -5.3944 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.7756 -6.0051 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.5338 -4.4447 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.6247 -10.2116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.0654 -10.8412 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 6 1 0 0 0 0\n" + + " 5 7 1 0 0 0 0\n" + + " 7 8 1 0 0 0 0\n" + + " 3 9 1 0 0 0 0\n" + + " 9 4 1 0 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 9 10 1 1 0 0 0\n" + + " 4 11 1 0 0 0 0\n" + + " 7 12 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 1 13 1 0 0 0 0\n" + + " 2 14 1 0 0 0 0\n" + + "M END"); + opChi=mol.getTetrahedrals().stream() + .map(ca->ca.getChirality()) + .filter(ca->!ca.isEither()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.R, opChi.get()); + } + @Test public void testReadingSmilesShouldNotGenerateCoordinates() throws Exception { From 195a7a36cf95647436e9c3997d4f1053f8d7c6d0 Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Mon, 4 Dec 2023 15:31:01 -0500 Subject: [PATCH 2/9] added missing files --- .../cdk/geometry/cip/CIPToolMod.java | 270 ++++++++++++++++++ .../geometry/cip/rules/CIPLigandRule2.java | 80 ++++++ 2 files changed, 350 insertions(+) create mode 100644 src/main/java/org/openscience/cdk/geometry/cip/CIPToolMod.java create mode 100644 src/main/java/org/openscience/cdk/geometry/cip/rules/CIPLigandRule2.java diff --git a/src/main/java/org/openscience/cdk/geometry/cip/CIPToolMod.java b/src/main/java/org/openscience/cdk/geometry/cip/CIPToolMod.java new file mode 100644 index 0000000..be6ff1d --- /dev/null +++ b/src/main/java/org/openscience/cdk/geometry/cip/CIPToolMod.java @@ -0,0 +1,270 @@ +package org.openscience.cdk.geometry.cip; + +import java.util.List; + +import org.openscience.cdk.CDKConstants; +import org.openscience.cdk.geometry.cip.CIPTool.CIP_CHIRALITY; +import org.openscience.cdk.geometry.cip.rules.CIPLigandRule; +import org.openscience.cdk.geometry.cip.rules.CIPLigandRule2; +import org.openscience.cdk.geometry.cip.rules.ISequenceSubRule; +import org.openscience.cdk.interfaces.IAtom; +import org.openscience.cdk.interfaces.IAtomContainer; +import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IDoubleBondStereochemistry; +import org.openscience.cdk.interfaces.IDoubleBondStereochemistry.Conformation; +import org.openscience.cdk.interfaces.IStereoElement; +import org.openscience.cdk.interfaces.ITetrahedralChirality; +import org.openscience.cdk.interfaces.ITetrahedralChirality.Stereo; + +/** + * This modified version of {@link CIPTool} is just present temporarily to correct + * a CIP bug in CDK. CDK's default CIP rule works well, but has a bug in the recursive + * part where, if there's a tie between 2 ligands based on atomic number/mass, it will + * then get all sub-ligands and compare them. The issue is that each set of sub-ligands + * is sorted by a mass+atomic number only priority, and each sub-ligand from the parent + * ligand is compared only to its matched counterpart, not to all potentially higher + * priority ligands. + * + *
+ * Consider this case below (4S)-2,3,4,5-tetramethyloctane:  
+ *  
+ *     3'    5'
+ *     M     C
+ *     |  4  | 
+ * M-C-C-[C]-C-C-C-M
+ *   | 3  :  5
+ *   M    M
+ *        4'
+ * 
+ * M = Methyl
+ * C = Carbon
+ * : = Dashed bond
+ * # = Locant 
+ * 
+ * + * The 4 postion [C] is a stereo center with S configuration (as demonstrated + * with the : dashed bond to the methyl group below). The carbon atoms at 3, 4 + * and 5 positions are tied for priority based on first pass CIP rules (atom + * numbner and mass). However, 3 and 5 are quickly seen as higher priority than + * 4' in the first tie-break as 4' has no sub-ligands. 3 and 5, however, both + * have 2 sub-ligands. 3 has [3',2] and 5 has [5',6] as sub-ligands. The next + * step CDK CIP rules do is to ORDER these sub-ligands and then compare them. + * In this case, we need to order [3',2] and [5',6] individually. For [3',2], + * this is done by comparing only the ATOMIC NUMBER+MASS between 3' and 2, + * and since they are both carbon atoms, this will result in a tie. This means + * that if the starting order of [3',2] was [3',2] it will remain that way. If + * the starting order is [2,3'] it will remain [2,3']. Since the input order + * of the ligands is based on read-order (order of bonds in the bond table in + * the CTAB, for example), this means the ordering of the sub-ligands is effectively + * non-deterministic. 2 is certainly higher priority than 3' in full CIP rules, + * and 6 is higher priorty than 5' as well. In the above cases there are 4 ways + * the ligand ordering can go + *
+ * Possibility 1: both sub-ligands in right order
+ *    3 vs 5 =>
+ *    [2,3'] vs [6,5'] => 
+ *    2 vs 6 => 2 is higher priority
+ *    therefore 3 is higher priority (correct)
+ * 
+ * Possibility 2: 3 sub-ligands wrong order, 5 right order
+ *    3 vs 5 =>
+ *    [3',2] vs [6,5'] => 
+ *    3' vs 6 => 6 is higher priority
+ *    therefore 5 is higher priority (incorrect)
+ * 
+ * Possibility 3: 3 sub-ligands RIGHT order, 5 wrong order
+ *    3 vs 5 =>
+ *    [2,3'] vs [5',6] => 
+ *    2 vs 5' => 2 is higher priority
+ *    therefore 3 is higher priority (correct)
+ * 
+ * Possibility 4: both sub-ligands in WRONG order
+ *    3 vs 5 =>
+ *    [3',2] vs [5',6] => 
+ *    3' vs 5' => TIE, go to next
+ *    2 vs 6 => 2 is higher priority
+ *    therefore 3 is higher priority (correct)
+ * 
+ *

+ * Notice here that 3 of the 4 possibilities above will give the correct + * CIP ordering. This is indeed typical. The bug only applies in circumstances + * where 2 or more "principal" ligands are tied for CIP priority based on + * atom number and atomic weight AND those 2 ligands both have sub-ligands + * (non-hydrogens) AND at least 2 sub-ligands of those ligands are tied for + * atomic weight and atomic mass. Even still, the majority of the time the + * criteria is met, CDK will still produce the correct CIP labeling. + *

+ *

+ * This class corrects the bug by switching how the ordering is done to instead + * call the full CIP ordering for sub-ligands. This is potentially computationally + * more expensive. The actual code here is largely just copy/pasted methods needed + * to perform the same methods as {@link CIPTool} and a reference to a modified {@link CIPLigandRule} + * (called {@link CIPLigandRule2}). + * + *

+ * + * + * + * @author tyler + * + */ +public class CIPToolMod { + + private static ISequenceSubRule cipRule = new CIPLigandRule2(); + + /** + * GSRS-MODIFIED: Temporary bug fix for {@link CIPTool#label(IAtomContainer)} + * + * @param container structure to label + */ + public static void label(IAtomContainer container) { + + for (IStereoElement stereoElement : container.stereoElements()) { + if (stereoElement instanceof ITetrahedralChirality) { + ITetrahedralChirality tc = (ITetrahedralChirality) stereoElement; + tc.getChiralAtom().setProperty(CDKConstants.CIP_DESCRIPTOR, getCIPChirality(container, tc).toString()); + } else if (stereoElement instanceof IDoubleBondStereochemistry) { + IDoubleBondStereochemistry dbs = (IDoubleBondStereochemistry) stereoElement; + dbs.getStereoBond() + .setProperty(CDKConstants.CIP_DESCRIPTOR, getCIPChirality(container, dbs).toString()); + } + } + + } + + + /** + * GSRS-MODIFIED: Temporary bug fix for {@link CIPTool#getCIPChirality(IAtomContainer, ITetrahedralChirality)} + * + * @param container structure to label + */ + public static CIP_CHIRALITY getCIPChirality(IAtomContainer container, ITetrahedralChirality stereoCenter) { + + // the LigancyFourChirality is kind of redundant but we keep for an + // easy way to get the ILigands array + LigancyFourChirality tmp = new LigancyFourChirality(container, stereoCenter); + Stereo stereo = stereoCenter.getStereo(); + + int parity = permParity(tmp.getLigands()); + + if (parity == 0) return CIP_CHIRALITY.NONE; + if (parity < 0) stereo = stereo.invert(); + + if (stereo == Stereo.CLOCKWISE) return CIP_CHIRALITY.R; + if (stereo == Stereo.ANTI_CLOCKWISE) return CIP_CHIRALITY.S; + + return CIP_CHIRALITY.NONE; + } + + /** + * GSRS-MODIFIED: Temporary bug fix for {@link CIPTool#getCIPChirality(IAtomContainer, IDoubleBondStereochemistry)} + * + * @param container structure to label + */ + public static CIP_CHIRALITY getCIPChirality(IAtomContainer container, IDoubleBondStereochemistry stereoCenter) { + + IBond stereoBond = stereoCenter.getStereoBond(); + IBond leftBond = stereoCenter.getBonds()[0]; + IBond rightBond = stereoCenter.getBonds()[1]; + + // the following variables are usd to label the atoms - makes things + // a little more concise + // + // x y x + // \ / \ + // u = v or u = v + // \ + // y + // + IAtom u = stereoBond.getBegin(); + IAtom v = stereoBond.getEnd(); + IAtom x = leftBond.getOther(u); + IAtom y = rightBond.getOther(v); + + Conformation conformation = stereoCenter.getStereo(); + + ILigand[] leftLigands = getLigands(u, container, v); + ILigand[] rightLigands = getLigands(v, container, u); + + if (leftLigands.length > 2 || rightLigands.length > 2) return CIP_CHIRALITY.NONE; + + // invert if x/y aren't in the first position + if (!leftLigands[0].getLigandAtom().equals(x)) conformation = conformation.invert(); + if (!rightLigands[0].getLigandAtom().equals(y)) conformation = conformation.invert(); + + int p = permParity(leftLigands) * permParity(rightLigands); + + if (p == 0) return CIP_CHIRALITY.NONE; + + if (p < 0) conformation = conformation.invert(); + + if (conformation == Conformation.TOGETHER) return CIP_CHIRALITY.Z; + if (conformation == Conformation.OPPOSITE) return CIP_CHIRALITY.E; + + return CIP_CHIRALITY.NONE; + } + + + /** + * GSRS-MODIFIED: Temporary bug fix + * + * @param atom + * @param container + * @param exclude + * @return + */ + private static ILigand[] getLigands(IAtom atom, IAtomContainer container, IAtom exclude) { + + List neighbors = container.getConnectedAtomsList(atom); + + ILigand[] ligands = new ILigand[neighbors.size() - 1]; + + int i = 0; + for (IAtom neighbor : neighbors) { + if (!neighbor.equals(exclude)) ligands[i++] = new Ligand(container, new VisitedAtoms(), atom, neighbor); + } + + return ligands; + } + + + + + + + /** + * Obtain the permutation parity (-1,0,+1) to put the ligands in descending + * order (highest first). A parity of 0 indicates two or more ligands were + * equivalent. + * + * @param ligands the ligands to sort + * @return parity, odd (-1), even (+1) or none (0) + */ + private static int permParity(final ILigand[] ligands) { + + // count the number of swaps made by insertion sort - if duplicates + // are fount the parity is 0 + int swaps = 0; + + for (int j = 1, hi = ligands.length; j < hi; j++) { + ILigand ligand = ligands[j]; + int i = j - 1; + int cmp = 0; + while ((i >= 0) && (cmp = cipRule.compare(ligand, ligands[i])) > 0) { + ligands[i + 1] = ligands[i--]; + swaps++; + } + if (cmp == 0) // identical entries + return 0; + ligands[i + 1] = ligand; + } + + // odd (-1) or even (+1) + return (swaps & 0x1) == 0x1 ? -1 : +1; + + } + + + + +} diff --git a/src/main/java/org/openscience/cdk/geometry/cip/rules/CIPLigandRule2.java b/src/main/java/org/openscience/cdk/geometry/cip/rules/CIPLigandRule2.java new file mode 100644 index 0000000..8c0ba94 --- /dev/null +++ b/src/main/java/org/openscience/cdk/geometry/cip/rules/CIPLigandRule2.java @@ -0,0 +1,80 @@ +package org.openscience.cdk.geometry.cip.rules; + +import java.util.Arrays; + +import org.openscience.cdk.geometry.cip.CIPTool; +import org.openscience.cdk.geometry.cip.CIPToolMod; +import org.openscience.cdk.geometry.cip.ILigand; +/** + * This class does the same as {@link CIPLigandRule2} only it also orders + * sub-ligands based on its own rule rather than based on the {@link CombinedAtomicMassNumberRule} + * order. This fixes a CDK bug detailed in {@link CIPToolMod}. + * @author tyler + * + */ +public class CIPLigandRule2 implements ISequenceSubRule { + + CombinedAtomicMassNumberRule numberRule = new CombinedAtomicMassNumberRule(); + + /** {@inheritDoc} */ + @Override + public int compare(ILigand ligand1, ILigand ligand2) { + int numberComp = numberRule.compare(ligand1, ligand2); + if (numberComp != 0) return numberComp; + + // OK, now I need to recurse... + ILigand[] ligand1Ligands = CIPTool.getLigandLigands(ligand1); + ILigand[] ligand2Ligands = CIPTool.getLigandLigands(ligand2); + // if neither have ligands: + if (ligand1Ligands.length == 0 && ligand2Ligands.length == 0) return 0; + // else if one has no ligands + if (ligand1Ligands.length == 0) return -1; + if (ligand2Ligands.length == 0) return 1; + // ok, both have at least one ligand + int minLigandCount = Math.min(ligand1Ligands.length, ligand2Ligands.length); + if (ligand1Ligands.length > 1) ligand1Ligands = order(ligand1Ligands); + if (ligand2Ligands.length > 1) ligand2Ligands = order(ligand2Ligands); + // first do a basic number rule + for (int i = 0; i < minLigandCount; i++) { + int comparison = numberRule.compare(ligand1Ligands[i], ligand2Ligands[i]); + if (comparison != 0) return comparison; + } + if (ligand1Ligands.length == ligand2Ligands.length) { + // it that does not resolve it, do a full, recursive compare + for (int i = 0; i < minLigandCount; i++) { + int comparison = compare(ligand1Ligands[i], ligand2Ligands[i]); + if (comparison != 0) return comparison; + } + } + // OK, if we reached this point, then the ligands they 'share' are all equals, so the one + // with more ligands wins + if (ligand1Ligands.length > ligand2Ligands.length) + return 1; + else if (ligand1Ligands.length < ligand2Ligands.length) + return -1; + else + return 0; + } + + /** + * Order the ligands from high to low precedence according to atomic and mass numbers. + */ + private ILigand[] order(ILigand[] ligands) { + ILigand[] newLigands = new ILigand[ligands.length]; + System.arraycopy(ligands, 0, newLigands, 0, ligands.length); + + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + //THIS IS THE ONLY LINE OF CODE THAT NEEDS TO BE CHANGED + //FOR CDK CIP TO WORK + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + Arrays.sort(newLigands, this); + // this above list is from low to high precendence, so we need to revert the array + ILigand[] reverseLigands = new ILigand[newLigands.length]; + for (int i = 0; i < newLigands.length; i++) { + reverseLigands[(newLigands.length - 1) - i] = newLigands[i]; + } + return reverseLigands; + } + + } \ No newline at end of file From aae01f1e9ba9568c9ecf07b1ac091f0ecba908c4 Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Thu, 7 Dec 2023 22:14:04 -0500 Subject: [PATCH 3/9] updated to use siMolecules CIP rules --- pom.xml | 27 + .../gov/nih/ncats/molwitch/cdk/CdkAtom.java | 61 +- .../gov/nih/ncats/molwitch/cdk/CdkBond.java | 6 +- .../ncats/molwitch/cdk/CdkChemicalImpl.java | 136 ++++- .../cdk/geometry/cip/CIPToolMod.java | 30 +- src/test/java/TestChiralRead.java | 564 ++++++++++++++++-- 6 files changed, 724 insertions(+), 100 deletions(-) diff --git a/pom.xml b/pom.xml index 59b8a7f..a1c76d9 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ 2.9 + 1.2.1 @@ -30,6 +31,16 @@ true + + oss.sonatype.org + https://repo1.maven.org/maven2/ + + true + + + false + + @@ -112,6 +123,22 @@ cdk-jniinchi-support ${cdk.version} + + + + com.simolecule.centres + centres-core + ${centres.version} + + + + com.simolecule.centres + centres-cdk + ${centres.version} + + + + diff --git a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkAtom.java b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkAtom.java index b10eedc..5bcc119 100644 --- a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkAtom.java +++ b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkAtom.java @@ -306,16 +306,31 @@ public void setAtomCoordinates(AtomCoordinates atomCoordinates) { public Chirality getChirality() { if(!parent.cahnIngoldPrelogSupplier.hasRun()) { //forces running CIP rules + parent.getTetrahedrals(); } - String value = atom.getProperty(CDKConstants.CIP_DESCRIPTOR); + String value= Optional.ofNullable(atom.getProperty(CDKConstants.CIP_DESCRIPTOR)) + .map(t->t.toString()) + .orElse(null); - if("R".equals(value)) { +// if(dd!=nu) +// String value = atom.getProperty(CDKConstants.CIP_DESCRIPTOR); +// + if("R".equals(value) || "M".equals(value)) { return Chirality.R; } - if("S".equals(value)) { + if("r".equals(value)) { + return Chirality.r; + } + + if("S".equals(value) || "P".equals(value)) { return Chirality.S; } + + if("s".equals(value)) { + return Chirality.s; + } + if("EITHER".equals(value)) { return Chirality.Parity_Either; } @@ -327,8 +342,10 @@ public Chirality getChirality() { public void setChirality(Chirality chirality) { Chirality chir=getChirality(); if(chir==chirality)return; - if((chirality==Chirality.R && chir==Chirality.S) || - (chirality==Chirality.S && chir==Chirality.R) + + //simple inversion + if(((chirality==Chirality.R || chirality==Chirality.r) && (chir==Chirality.S||chir==Chirality.s)) || + ((chirality==Chirality.S || chirality==Chirality.s) && (chir==Chirality.R||chir==Chirality.r)) ) { this.getBonds().stream() .filter(b->b.getBondType().equals(BondType.SINGLE)) @@ -345,6 +362,8 @@ public void setChirality(Chirality chirality) { atom.setProperty(CDKConstants.CIP_DESCRIPTOR,chirality.toString()); // atom.setStereoParity((atom.getStereoParity()+1)%2); // parent.getContainer().setStereoElements(new ArrayList<>()); + + //simple removal }else if(chirality.equals(Chirality.Parity_Either)) { this.getBonds().stream() .filter(b->b.getBondType().equals(BondType.SINGLE)) @@ -359,7 +378,39 @@ public void setChirality(Chirality chirality) { }); atom.setProperty(CDKConstants.CIP_DESCRIPTOR,"EITHER"); + }else if(chirality.isDefined() && (chir.isEither() || chir == Chirality.Non_Chiral)) { + + Optional sBond = this.getBonds().stream() + .filter(b->b.getBondType().equals(BondType.SINGLE)) + .filter(b->b.getStereo().equals(Stereo.NONE)) + .findFirst(); + + + sBond.ifPresent(b->{ + if(b.getAtom1().getAtomIndexInParent()==this.getAtomIndexInParent()){ + b.setStereo(Stereo.UP); + }else { + b.setStereo(Stereo.UP_INVERTED); + } + }); + + + parent.cahnIngoldPrelogSupplier.resetCache(); + Chirality co=this.getChirality(); + if((co.isRForm() && chirality.isRForm()) || + (co.isSForm() && chirality.isSForm()) + ) { + //do nothing + }else if((co.isSForm() && chirality.isRForm()) || + (co.isRForm() && chirality.isSForm()) + ) { + setChirality(chirality); + }else { + //could not set + } + } + // parent.cahnIngoldPrelogSupplier.resetCache(); } diff --git a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkBond.java b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkBond.java index da7297d..23a7b66 100644 --- a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkBond.java +++ b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkBond.java @@ -22,15 +22,13 @@ package gov.nih.ncats.molwitch.cdk; -import java.util.ArrayList; -import java.util.List; +import java.util.Optional; import org.openscience.cdk.BondRef; import org.openscience.cdk.CDKConstants; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IBond; import org.openscience.cdk.interfaces.IBond.Order; -import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.isomorphism.matchers.IQueryBond; import gov.nih.ncats.common.sneak.Sneak; @@ -224,7 +222,7 @@ public DoubleBondStereo getDoubleBondStereo() { return null; } parent.cahnIngoldPrelogSupplier.get(); - String value = bond.getProperty(CDKConstants.CIP_DESCRIPTOR); + String value = Optional.ofNullable(bond.getProperty(CDKConstants.CIP_DESCRIPTOR)).map(bt->bt.toString()).orElse(null); if("Z".equals(value)) { return DoubleBondStereo.Z_CIS; } diff --git a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java index 3469012..2fdcc31 100644 --- a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java +++ b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java @@ -21,7 +21,6 @@ package gov.nih.ncats.molwitch.cdk; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; @@ -48,22 +47,12 @@ import org.openscience.cdk.AtomRef; import org.openscience.cdk.BondRef; import org.openscience.cdk.CDKConstants; -import org.openscience.cdk.PseudoAtom; import org.openscience.cdk.aromaticity.Aromaticity; import org.openscience.cdk.aromaticity.ElectronDonation; import org.openscience.cdk.aromaticity.Kekulization; import org.openscience.cdk.atomtype.CDKAtomTypeMatcher; -import org.openscience.cdk.config.IsotopeFactory; -import org.openscience.cdk.config.Isotopes; import org.openscience.cdk.exception.CDKException; -import org.openscience.cdk.geometry.cip.CIPTool; -import org.openscience.cdk.geometry.cip.ILigand; -import org.openscience.cdk.geometry.cip.ImplicitHydrogenLigand; -import org.openscience.cdk.geometry.cip.Ligand; -import org.openscience.cdk.geometry.cip.VisitedAtoms; -import org.openscience.cdk.geometry.cip.CIPTool.CIP_CHIRALITY; import org.openscience.cdk.geometry.cip.CIPToolMod; -import org.openscience.cdk.geometry.cip.rules.ISequenceSubRule; import org.openscience.cdk.graph.ConnectivityChecker; import org.openscience.cdk.graph.Cycles; import org.openscience.cdk.graph.GraphUtil; @@ -76,7 +65,6 @@ import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IDoubleBondStereochemistry; -import org.openscience.cdk.interfaces.IIsotope; import org.openscience.cdk.interfaces.IMolecularFormula; import org.openscience.cdk.interfaces.IRing; import org.openscience.cdk.interfaces.IRingSet; @@ -101,8 +89,6 @@ import org.openscience.cdk.stereo.StereoElementFactory; import org.openscience.cdk.stereo.Stereocenters; import org.openscience.cdk.tools.CDKHydrogenAdder; -import org.openscience.cdk.tools.ILoggingTool; -import org.openscience.cdk.tools.LoggingToolFactory; import org.openscience.cdk.tools.manipulator.AtomContainerManipulator; import org.openscience.cdk.tools.manipulator.AtomTypeManipulator; import org.openscience.cdk.tools.manipulator.MolecularFormulaManipulator; @@ -119,11 +105,11 @@ import gov.nih.ncats.molwitch.BondTable; import gov.nih.ncats.molwitch.Chemical; import gov.nih.ncats.molwitch.ChemicalSource; -import gov.nih.ncats.molwitch.MolwitchException; import gov.nih.ncats.molwitch.Chirality; import gov.nih.ncats.molwitch.DoubleBondStereochemistry; import gov.nih.ncats.molwitch.ExtendedTetrahedralChirality; import gov.nih.ncats.molwitch.GraphInvariant; +import gov.nih.ncats.molwitch.MolwitchException; import gov.nih.ncats.molwitch.SGroup; import gov.nih.ncats.molwitch.SGroup.SGroupBracket; import gov.nih.ncats.molwitch.SGroup.SGroupType; @@ -152,6 +138,8 @@ public class CdkChemicalImpl implements ChemicalImpl{ private final static int[] mostStable = new int[119]; private final static BitSet cdkMissing = new BitSet(); + + private boolean deepChirality = true; static{ @@ -240,6 +228,21 @@ public class CdkChemicalImpl implements ChemicalImpl{ } } + + for (int i = 0; i < container.getBondCount(); i++) { + IBond bi =container.getBond(i); + IBond bin =cimp.getContainer().getBond(i); + Object p = bin.getProperty(CDKConstants.CIP_DESCRIPTOR); + + bi.removeProperty(CDKConstants.CIP_DESCRIPTOR); + if(p!=null) { + //For atropisomers + bi.atoms().forEach(aa->aa.setProperty(CDKConstants.CIP_DESCRIPTOR, p)); + bi.setProperty(CDKConstants.CIP_DESCRIPTOR, p); + } + + } + return null; }); @@ -248,12 +251,40 @@ public class CdkChemicalImpl implements ChemicalImpl{ this.doWithQueryFixes(()->{ Stereocenters centers = Stereocenters.of(container); + List potentialSet = new ArrayList<>(); + List undefinedSet = new ArrayList<>(); for (int i = 0; i < container.getAtomCount(); i++) { switch(centers.stereocenterType(i)){ case Non: break; case Para: +// System.out.println("H"); +// break; case Potential: + IAtom ai3=container.getAtom(i); + // This is a weird kind of case where it really depends + // on the circumstance. In general we care about any case where + // if a wedge/hash were added this would change the + // meaning of the molecule to something distinct. + // + // However this isn't perfect because sometimes adding a wedge or + // dash in isolation won't change the meaning, but adding 2 or 3 + // will. For example 1,4-dimethylcyclohexane, or certain other + // meso compounds. For those, we would be better off capturing + // all potential as of yet undefined stereo centers and enumerating + // the possibilities. If at least this specific center has more than one + // possible R/S or r/s result from that enumerated set, then it's a + // real stereocenter. If not, it's not a real stereocenter. + + if(ai3.getProperty(CDKConstants.CIP_DESCRIPTOR) == null){ + + potentialSet.add(i); + undefinedSet.add(i); + if(!deepChirality) { + container.getAtom(i).setProperty(CDKConstants.CIP_DESCRIPTOR, "EITHER"); + } + } + break; case True: IAtom ai=container.getAtom(i); @@ -264,15 +295,22 @@ public class CdkChemicalImpl implements ChemicalImpl{ //we have to go through the container because some atom implementations //throw unsupport operation exceptions if we ask them for their bonds for(IBond ib:container.getConnectedBondsList(ai)){ - if(!Order.SINGLE.equals(ib.getOrder())){ + if(!Order.SINGLE.equals(ib.getOrder()) + +// && !Order.DOUBLE.equals(ib.getOrder()) + ){ bailout=true; break; } } if(bailout){ + // axial cases are a little weird here + // in general CDK marks all SP2-hybrid entries in rings + // of < 9 as true stereocenters. I don't know why. + // System.out.println("It's real but ..."); -// System.out.println(centers.elementType(i)); +// System.out.println(centers.elementType(i) + ":" + centers.stereocenterType(i) + ":" + ai.getSymbol()); continue; } @@ -284,13 +322,59 @@ public class CdkChemicalImpl implements ChemicalImpl{ } container.getAtom(i).setProperty(CDKConstants.CIP_DESCRIPTOR, "EITHER"); - + undefinedSet.add(i); } break; default: break; } } + + //TODO fix for potential cases +// container.getAtom(i); + +// BitSet.valueOf(null); + + + if(deepChirality && !potentialSet.isEmpty()) { + CdkChemicalImpl cimp2=this.deepCopy(); + cimp2.setDeepChirality(false); + + Chemical c22 = new Chemical(cimp2); + + Set isDefinable = new HashSet<>(); + for(long ii=0;ii{ }); private final CachedSupplierGroup cachedSupplierGroup = new CachedSupplierGroup(); private final ChemicalSource source; + + public CdkChemicalImpl(IAtomContainer container, Supplier source) { this(container, source.get()); } @@ -400,9 +486,13 @@ public void flipChirality(Stereocenter s) { b.setStereo(newStereo); } } - } - + } + } + + public void setDeepChirality(boolean chir) { + this.deepChirality=chir; } + @Override public ChemicalSource getSource() { return source; @@ -1329,6 +1419,8 @@ public List getTetrahedrals1() { case Parity_Either: case R: case S: + case r: + case s: return true; case Unknown: break; @@ -1815,7 +1907,9 @@ public boolean isDefined() { // TODO: really, it can be defined and not be R/S, // as in some rings. Should fix. - return Chirality.R.equals(c) || Chirality.S.equals(c); + return Chirality.R.equals(c) || Chirality.S.equals(c) || + Chirality.r.equals(c) || Chirality.s.equals(c) + ; } @Override diff --git a/src/main/java/org/openscience/cdk/geometry/cip/CIPToolMod.java b/src/main/java/org/openscience/cdk/geometry/cip/CIPToolMod.java index be6ff1d..bc5ad12 100644 --- a/src/main/java/org/openscience/cdk/geometry/cip/CIPToolMod.java +++ b/src/main/java/org/openscience/cdk/geometry/cip/CIPToolMod.java @@ -109,6 +109,9 @@ * */ public class CIPToolMod { + + public static boolean USE_NEW_CENTRES=true; + private static ISequenceSubRule cipRule = new CIPLigandRule2(); @@ -118,17 +121,22 @@ public class CIPToolMod { * @param container structure to label */ public static void label(IAtomContainer container) { - - for (IStereoElement stereoElement : container.stereoElements()) { - if (stereoElement instanceof ITetrahedralChirality) { - ITetrahedralChirality tc = (ITetrahedralChirality) stereoElement; - tc.getChiralAtom().setProperty(CDKConstants.CIP_DESCRIPTOR, getCIPChirality(container, tc).toString()); - } else if (stereoElement instanceof IDoubleBondStereochemistry) { - IDoubleBondStereochemistry dbs = (IDoubleBondStereochemistry) stereoElement; - dbs.getStereoBond() - .setProperty(CDKConstants.CIP_DESCRIPTOR, getCIPChirality(container, dbs).toString()); - } - } + //Experimental new labeller + if(USE_NEW_CENTRES) { + com.simolecule.centres.CdkLabeller.label(container); + return; + }else { + for (IStereoElement stereoElement : container.stereoElements()) { + if (stereoElement instanceof ITetrahedralChirality) { + ITetrahedralChirality tc = (ITetrahedralChirality) stereoElement; + tc.getChiralAtom().setProperty(CDKConstants.CIP_DESCRIPTOR, getCIPChirality(container, tc).toString()); + } else if (stereoElement instanceof IDoubleBondStereochemistry) { + IDoubleBondStereochemistry dbs = (IDoubleBondStereochemistry) stereoElement; + dbs.getStereoBond() + .setProperty(CDKConstants.CIP_DESCRIPTOR, getCIPChirality(container, dbs).toString()); + } + } + } } diff --git a/src/test/java/TestChiralRead.java b/src/test/java/TestChiralRead.java index 23014fa..6bd1410 100644 --- a/src/test/java/TestChiralRead.java +++ b/src/test/java/TestChiralRead.java @@ -20,8 +20,10 @@ */ import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.BitSet; import java.util.Optional; import java.util.stream.Collectors; @@ -29,7 +31,7 @@ import gov.nih.ncats.molwitch.Chemical; import gov.nih.ncats.molwitch.Chirality; -import gov.nih.ncats.molwitch.TetrahedralChirality; +import gov.nih.ncats.molwitch.Stereocenter; import gov.nih.ncats.molwitch.io.ChemicalReaderFactory; public class TestChiralRead { @@ -213,6 +215,142 @@ public void ensureChiralityIsTheSameRegardlessOfSDFOrMolOrAgnosticRead() throws } + @Test + public void testAxialStereoMarkedR() throws Exception { + Chemical c1=Chemical.parse("\n" + + " ChemDraw12062311172D\n" + + "\n" + + " 19 20 0 0 0 0 0 0 0 0999 V2000\n" + + " -0.2855 -1.7339 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.4969 -1.7128 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.8881 -2.3895 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.1525 -0.5075 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.7189 0.2114 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.9348 -0.4863 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6344 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.1102 0.9305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2.3260 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.0679 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.0679 -0.4440 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.6766 1.6494 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.8925 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6767 1.6706 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.8926 0.9728 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6767 -1.1207 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.8926 -0.4229 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.1102 2.3895 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -2.3260 0.2960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 2 0 \n" + + " 2 3 1 0 \n" + + " 2 4 1 0 \n" + + " 4 5 2 0 \n" + + " 4 6 1 0 \n" + + " 5 7 1 0 \n" + + " 5 8 1 6 \n" + + " 6 9 2 0 \n" + + " 7 10 2 0 \n" + + " 7 11 1 0 \n" + + " 8 12 1 0 \n" + + " 8 13 2 0 \n" + + " 9 13 1 0 \n" + + " 10 14 1 0 \n" + + " 10 15 1 0 \n" + + " 11 16 1 0 \n" + + " 11 17 2 0 \n" + + " 14 18 1 0 \n" + + " 15 19 2 0 \n" + + " 17 19 1 0 \n" + + "M END"); + System.out.println(c1.toMol()); + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.R, opChi.get()); + } + @Test + public void testAxialStereoMarkedS() throws Exception { + Chemical c1=Chemical.parse("\n" + + " ChemDraw12062311172D\n" + + "\n" + + " 19 20 0 0 0 0 0 0 0 0999 V2000\n" + + " -0.2855 -1.7339 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.4969 -1.7128 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.8881 -2.3895 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.1525 -0.5075 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.7189 0.2114 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.9348 -0.4863 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6344 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.1102 0.9305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2.3260 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.0679 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.0679 -0.4440 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.6766 1.6494 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.8925 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6767 1.6706 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.8926 0.9728 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6767 -1.1207 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.8926 -0.4229 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.1102 2.3895 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -2.3260 0.2960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 2 0 \n" + + " 2 3 1 0 \n" + + " 2 4 1 0 \n" + + " 4 5 2 0 \n" + + " 4 6 1 0 \n" + + " 5 7 1 0 \n" + + " 5 8 1 1 \n" + + " 6 9 2 0 \n" + + " 7 10 2 0 \n" + + " 7 11 1 0 \n" + + " 8 12 1 0 \n" + + " 8 13 2 0 \n" + + " 9 13 1 0 \n" + + " 10 14 1 0 \n" + + " 10 15 1 0 \n" + + " 11 16 1 0 \n" + + " 11 17 2 0 \n" + + " 14 18 1 0 \n" + + " 15 19 2 0 \n" + + " 17 19 1 0 \n" + + "M END"); + System.out.println(c1.toMol()); + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.S, opChi.get()); + } + + @Test + public void testAxialStereoUndefinedMarkedAsCenter() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212072312182D\n" + + "\n" + + " 6 6 0 0 0 0 999 V2000\n" + + " 17.4720 -8.8400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.1210 -8.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.1210 -6.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.8230 -8.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.8230 -6.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.4720 -5.7200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 2 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 1 4 1 0 0 0 0\n" + + " 4 5 2 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 3 2 0 0 0 0\n" + + "M END"); + System.out.println(c1.toMol()); + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.Parity_Either, opChi.get()); + } @Test public void testSimpleTetrahedralStereoMarked() throws Exception { Chemical c1=Chemical.parse("\n" + @@ -238,6 +376,82 @@ public void testSimpleTetrahedralStereoMarked() throws Exception { assertTrue(opChi.isPresent()); assertEquals(Chirality.Parity_Either, opChi.get()); } + + + @Test + public void testSimpleCisTransRingStereoMarked() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212062312582D\n" + + "\n" + + " 8 8 0 0 1 0 999 V2000\n" + + " 24.4925 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -4.9660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -9.6460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -3.4060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 1 1 0 0 0 0\n" + + " 1 7 1 1 0 0 0\n" + + " 4 8 1 1 0 0 0\n" + + "M END"); + + assertEquals(2,c1.getAllStereocenters().size()); + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.s, opChi.get()); + } + + @Test + public void testSimpleCisTransRingStereoDetected() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212062312582D\n" + + "\n" + + " 8 8 0 0 1 0 999 V2000\n" + + " 24.4925 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -4.9660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -9.6460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -3.4060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 1 1 0 0 0 0\n" + + " 1 7 1 0 0 0 0\n" + + " 4 8 1 0 0 0 0\n" + + "M END"); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("Parity_EitherParity_Either", sdfChiral); + assertEquals(2,c1.getAllStereocenters().size()); +// String sdfChiral = c1.atoms() +// .map(ca->ca.getChirality()) +// .filter(ch->!ch.equals(Chirality.Non_Chiral)) +// .map(ch->ch.toString()) +// .collect(Collectors.joining()); +// +// assertEquals("SSSR", sdfChiral); + } + + @Test public void testSimpleTetrahedralStereoMarkedAsCenter() throws Exception { Chemical c1=Chemical.parse("\n" + @@ -265,63 +479,96 @@ public void testSimpleTetrahedralStereoMarkedAsCenter() throws Exception { @Test public void testSimpleTetrahedralStereoMarked2() throws Exception { - Chemical c1=Chemical.parse("\n" + - " JSDraw209282010292D\n" + - "\n" + - " 26 26 0 0 1 0 999 V2000\n" + - " 41.5969 -8.3170 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 40.0369 -8.3170 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 39.2569 -9.6679 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 40.0369 -11.0188 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 37.6969 -9.6679 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 36.9169 -11.0199 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 37.6969 -12.3614 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 39.2569 -12.3588 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 36.9169 -13.7134 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 37.6971 -15.0642 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 39.2571 -15.0640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 40.0302 -13.7090 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 41.5640 -13.6862 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 42.3968 -15.0595 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 43.9567 -15.0387 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 41.6237 -16.4143 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 40.0177 -16.3960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 35.3570 -13.7134 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 34.5770 -15.0654 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 35.3572 -16.4162 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 33.0170 -15.0654 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 32.2368 -16.4162 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 32.2370 -13.7134 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 30.6771 -13.7134 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 36.9169 -8.3159 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 37.6971 -6.9651 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 0 0 0 0\n" + - " 3 4 1 6 0 0 0\n" + - " 3 5 1 0 0 0 0\n" + - " 5 6 1 6 0 0 0\n" + - " 6 7 1 0 0 0 0\n" + - " 7 8 2 0 0 0 0\n" + - " 7 9 1 0 0 0 0\n" + - " 9 10 1 6 0 0 0\n" + - " 10 11 1 0 0 0 0\n" + - " 11 12 2 0 0 0 0\n" + - " 12 13 1 0 0 0 0\n" + - " 13 14 2 0 0 0 0\n" + - " 14 15 1 0 0 0 0\n" + - " 14 16 1 0 0 0 0\n" + - " 16 17 2 0 0 0 0\n" + - " 11 17 1 0 0 0 0\n" + - " 9 18 1 0 0 0 0\n" + - " 18 19 1 0 0 0 0\n" + - " 19 20 2 0 0 0 0\n" + - " 19 21 1 0 0 0 0\n" + - " 21 22 1 1 0 0 0\n" + - " 21 23 1 0 0 0 0\n" + - " 23 24 1 0 0 0 0\n" + - " 5 25 1 0 0 0 0\n" + - " 25 26 2 0 0 0 0\n" + - "M END"); + Chemical c1=Chemical.parse("\n" + + " JSDraw212072312292D\n" + + "\n" + + " 42 42 0 0 1 0 999 V2000\n" + + " 33.4515 -13.1881 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 32.1004 -13.9682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 30.7493 -13.1881 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.1857 -26.0176 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.4483 -25.1011 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.5559 -23.5448 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.2082 -22.7591 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 41.9607 -22.8654 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 42.1324 -21.3146 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.5022 -20.5673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 44.8574 -21.3399 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.3492 -19.0159 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 42.1023 -18.0774 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 41.7950 -16.5527 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.1529 -15.7973 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.1828 -14.2274 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 41.8398 -13.4353 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 41.9900 -11.8924 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.4817 -14.1926 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.4545 -15.7495 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.1482 -13.3918 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.2963 -11.8491 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.9520 -11.0842 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.8735 -9.5499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 36.5716 -8.7179 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 36.6213 -7.1692 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.9730 -6.4054 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.0516 -7.5281 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.5290 -8.0258 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 42.0698 -7.7805 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 38.8419 -2.1710 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.8550 -3.3778 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.5422 -4.9049 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 44.6029 -18.0888 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 44.9199 -16.5603 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 44.6823 -15.0152 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 46.2997 -15.8321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 47.6046 -16.6791 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 46.3490 -14.2696 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 47.5823 -13.3194 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.2388 -23.7596 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.3766 -25.3138 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 7 1 6 0 0 0\n" + + " 6 8 1 0 0 0 0\n" + + " 8 9 1 6 0 0 0\n" + + " 9 10 1 0 0 0 0\n" + + " 10 11 2 0 0 0 0\n" + + " 10 12 1 0 0 0 0\n" + + " 12 13 1 0 0 0 0\n" + + " 13 14 1 0 0 0 0\n" + + " 14 15 1 0 0 0 0\n" + + " 15 16 1 0 0 0 0\n" + + " 16 17 1 0 0 0 0\n" + + " 17 18 2 0 0 0 0\n" + + " 17 19 1 0 0 0 0\n" + + " 19 20 1 0 0 0 0\n" + + " 14 20 1 0 0 0 0\n" + + " 19 21 1 0 0 0 0\n" + + " 21 22 2 0 0 0 0\n" + + " 22 23 1 0 0 0 0\n" + + " 23 24 1 0 0 0 0\n" + + " 24 25 1 0 0 0 0\n" + + " 25 26 2 0 0 0 0\n" + + " 26 27 1 0 0 0 0\n" + + " 27 28 1 0 0 0 0\n" + + " 28 29 1 0 0 0 0\n" + + " 29 30 1 0 0 0 0\n" + + " 32 31 1 0 0 0 0\n" + + " 32 33 1 0 0 0 0\n" + + " 27 33 1 0 0 0 0\n" + + " 12 34 1 6 0 0 0\n" + + " 34 35 1 0 0 0 0\n" + + " 35 36 2 0 0 0 0\n" + + " 35 37 1 0 0 0 0\n" + + " 37 38 1 6 0 0 0\n" + + " 37 39 1 0 0 0 0\n" + + " 39 40 1 0 0 0 0\n" + + " 8 41 1 0 0 0 0\n" + + " 41 42 2 0 0 0 0\n" + + " 31 30 2 0 0 0 0\n" + + "M END"); + System.out.println(c1.toMol()); String sdfChiral = c1.atoms() .map(ca->ca.getChirality()) .filter(ch->!ch.equals(Chirality.Non_Chiral)) @@ -329,6 +576,87 @@ public void testSimpleTetrahedralStereoMarked2() throws Exception { .collect(Collectors.joining()); assertEquals("SSSR", sdfChiral); + } + @Test + public void testSetChiralityOnUnsetCaseWorksS() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212062317442D\n" + + "\n" + + " 6 5 0 0 0 0 999 V2000\n" + + " 10.6080 -5.5640 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.9590 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.3100 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.6610 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.0120 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.9590 -3.2240 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 2 6 1 0 0 0 0\n" + + "M END"); +// c1.generateCoordinates(); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("Parity_Either", sdfChiral); + c1.atoms() + .filter(ch->!ch.getChirality().equals(Chirality.Non_Chiral)) + .forEach(ch->ch.setChirality(Chirality.S)) + ; + sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("S", sdfChiral); + + + } + @Test + public void testSetChiralityOnUnsetCaseWorksR() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212062317442D\n" + + "\n" + + " 6 5 0 0 0 0 999 V2000\n" + + " 10.6080 -5.5640 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.9590 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.3100 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.6610 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.0120 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.9590 -3.2240 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 2 6 1 0 0 0 0\n" + + "M END"); +// c1.generateCoordinates(); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("Parity_Either", sdfChiral); + c1.atoms() + .filter(ch->!ch.getChirality().equals(Chirality.Non_Chiral)) + .forEach(ch->ch.setChirality(Chirality.R)) + ; + sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("R", sdfChiral); + + + } @Test @@ -423,6 +751,124 @@ public void testRemoveNonDescriptHydrogensDoesntRemoveStereoInformationOnMol() t assertEquals("SS", sdfChiral); } + @Test + public void testPsuedoStereocenterIsLowerCase() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212062315202D\n" + + "\n" + + " 10 9 0 0 1 0 999 V2000\n" + + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 1 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 1 6 1 1 0 0 0\n" + + " 1 7 1 0 0 0 0\n" + + " 4 8 1 1 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 7 10 1 0 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + assertEquals(3,mol.getAllStereocenters().size()); + String sdfChiral =mol.getAllStereocenters() + .stream() + .filter(Stereocenter::isDefined) + .map(Stereocenter::getCenterAtom) + .filter(a -> a.getChirality() != null) + .map(a->a.getChirality()) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("SrR", sdfChiral); + } + + @Test + public void testPsuedoStereocenterOnNonMesoNotFound() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212062315202D\n" + + "\n" + + " 10 9 0 0 1 0 999 V2000\n" + + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 1 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 1 6 1 1 0 0 0\n" + + " 1 7 1 0 0 0 0\n" + + " 4 8 1 6 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 7 10 1 0 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + assertEquals(2,mol.getAllStereocenters().size()); + String sdfChiral =mol.getAllStereocenters() + .stream() + .filter(Stereocenter::isDefined) + .map(Stereocenter::getCenterAtom) + .filter(a -> a.getChirality() != null) + .map(a->a.getChirality()) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("SS", sdfChiral); + } + + @Test + public void testPsuedoStereocenterIsDetected() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212062315202D\n" + + "\n" + + " 10 9 0 0 1 0 999 V2000\n" + + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 1 6 1 0 0 0 0\n" + + " 1 7 1 0 0 0 0\n" + + " 4 8 1 0 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 7 10 1 0 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); +// String sdfChiral = mol.atoms() +// .map(ca->ca.getChirality()) +// .filter(ch->!ch.equals(Chirality.Non_Chiral)) +// .map(ch->ch.toString()) +// .collect(Collectors.joining()); + assertEquals(3,mol.getAllStereocenters().size()); + } + @Test public void testHavingExplicitHydrogenOnStereoCenterDoesNotInvalidatePhosphateCenter() throws Exception { From cfaa46267f2d0d62e7caebb6ed8be31f2a9abab7 Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Thu, 7 Dec 2023 22:14:35 -0500 Subject: [PATCH 4/9] removed accidental file --- src/test/java/TestChiralRead.java | 1149 ----------------------------- 1 file changed, 1149 deletions(-) delete mode 100644 src/test/java/TestChiralRead.java diff --git a/src/test/java/TestChiralRead.java b/src/test/java/TestChiralRead.java deleted file mode 100644 index 6bd1410..0000000 --- a/src/test/java/TestChiralRead.java +++ /dev/null @@ -1,1149 +0,0 @@ -/* - * NCATS-MOLWITCH-CDK - * - * Copyright (c) 2023. - * - * This work is free software; you can redistribute it and/or modify it under the terms of the - * GNU Lesser General Public License as published by the Free Software Foundation; - * either version 2.1 of the License, or (at your option) any later version. - * - * This work is distributed in the hope that it will be useful, but without any warranty; - * without even the implied warranty of merchantability or fitness for a particular purpose. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with this library; - * if not, write to: - * - * the Free Software Foundation, Inc. - * 59 Temple Place, Suite 330 - * Boston, MA 02111-1307 USA - */ - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.BitSet; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.junit.Test; - -import gov.nih.ncats.molwitch.Chemical; -import gov.nih.ncats.molwitch.Chirality; -import gov.nih.ncats.molwitch.Stereocenter; -import gov.nih.ncats.molwitch.io.ChemicalReaderFactory; - -public class TestChiralRead { - @Test - public void ensureChiralityIsTheSameRegardlessOfSDFOrMolOrAgnosticRead() throws Exception{ - - String mm="\n" + - " CDK 09262014552D\n" + - "\n" + - " 69 71 0 0 1 0 0 0 0 0999 V2000\n" + - " 7.4100 3.6690 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 5.9100 3.6690 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 5.1600 2.3700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 5.9100 1.0710 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 3.6600 2.3700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 2.9100 1.0700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 3.6600 -0.2200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 5.1600 -0.2175 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 2.9100 -1.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 3.6602 -2.8189 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 5.1602 -2.8187 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 5.9036 -1.5158 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 7.3784 -1.4938 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 8.1792 -2.8143 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 9.6791 -2.7943 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 7.4358 -4.1171 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 5.8916 -4.0995 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1.4100 -1.5200 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 0.6600 -2.8200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1.4102 -4.1189 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -0.8400 -2.8200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -1.5902 -4.1189 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -1.5900 -1.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -3.0900 -1.5200 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -3.8400 -0.2200 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -5.3400 -0.2200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -6.0900 1.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -5.3400 2.3700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -3.8400 2.3700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -3.0898 1.0711 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -3.0900 3.6700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -3.8402 4.9689 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -5.3402 4.9687 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -6.0904 6.2676 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -6.0900 3.6695 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -1.5900 3.6700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -0.8400 4.9700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -1.5902 6.2689 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 0.6600 4.9700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1.4102 6.2689 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 0.6604 7.5681 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1.4106 8.8670 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 0.6608 10.1662 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 2.9106 8.8668 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1.4100 3.6700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 2.9100 3.6700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 3.6602 4.9689 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -7.5900 1.0675 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -8.3422 2.3653 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -8.3378 -0.2328 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -7.7250 -1.5977 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -8.8347 -2.6101 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -10.1364 -1.8649 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -9.8338 -0.3903 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -10.8415 0.7208 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -10.3831 2.1490 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -12.3076 0.4036 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -13.3153 1.5147 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -12.8569 2.9429 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -13.8647 4.0540 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -15.3307 3.7369 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -13.4063 5.4823 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -14.7814 1.1975 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -15.2398 -0.2307 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -15.7891 2.3086 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -17.2552 1.9915 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -18.2629 3.1025 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -19.7290 2.7854 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " -17.8045 4.5308 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 0 0 0 0\n" + - " 3 4 1 6 0 0 0\n" + - " 3 5 1 0 0 0 0\n" + - " 5 6 1 6 0 0 0\n" + - " 6 7 1 0 0 0 0\n" + - " 7 8 2 0 0 0 0\n" + - " 7 9 1 0 0 0 0\n" + - " 9 10 1 6 0 0 0\n" + - " 10 11 1 0 0 0 0\n" + - " 11 12 2 0 0 0 0\n" + - " 12 13 1 0 0 0 0\n" + - " 13 14 2 0 0 0 0\n" + - " 14 15 1 0 0 0 0\n" + - " 14 16 1 0 0 0 0\n" + - " 16 17 2 0 0 0 0\n" + - " 11 17 1 0 0 0 0\n" + - " 9 18 1 0 0 0 0\n" + - " 18 19 1 0 0 0 0\n" + - " 19 20 2 0 0 0 0\n" + - " 19 21 1 0 0 0 0\n" + - " 21 22 1 1 0 0 0\n" + - " 21 23 1 0 0 0 0\n" + - " 23 24 1 0 0 0 0\n" + - " 24 25 1 0 0 0 0\n" + - " 25 26 1 0 0 0 0\n" + - " 26 27 1 0 0 0 0\n" + - " 27 28 1 0 0 0 0\n" + - " 28 29 1 0 0 0 0\n" + - " 29 30 2 0 0 0 0\n" + - " 29 31 1 0 0 0 0\n" + - " 31 32 1 6 0 0 0\n" + - " 32 33 1 0 0 0 0\n" + - " 33 34 1 0 0 0 0\n" + - " 33 35 2 0 0 0 0\n" + - " 31 36 1 0 0 0 0\n" + - " 36 37 1 0 0 0 0\n" + - " 37 38 2 0 0 0 0\n" + - " 37 39 1 0 0 0 0\n" + - " 39 40 1 6 0 0 0\n" + - " 40 41 1 0 0 0 0\n" + - " 41 42 1 0 0 0 0\n" + - " 42 43 1 0 0 0 0\n" + - " 42 44 2 0 0 0 0\n" + - " 39 45 1 0 0 0 0\n" + - " 45 46 1 0 0 0 0\n" + - " 5 46 1 0 0 0 0\n" + - " 46 47 2 0 0 0 0\n" + - " 27 48 1 1 0 0 0\n" + - " 48 49 2 0 0 0 0\n" + - " 48 50 1 0 0 0 0\n" + - " 50 51 1 0 0 0 0\n" + - " 51 52 1 0 0 0 0\n" + - " 52 53 1 0 0 0 0\n" + - " 53 54 1 0 0 0 0\n" + - " 50 54 1 0 0 0 0\n" + - " 54 55 1 1 0 0 0\n" + - " 55 56 2 0 0 0 0\n" + - " 55 57 1 0 0 0 0\n" + - " 58 57 1 6 0 0 0\n" + - " 58 59 1 0 0 0 0\n" + - " 59 60 1 0 0 0 0\n" + - " 60 61 1 0 0 0 0\n" + - " 60 62 1 0 0 0 0\n" + - " 58 63 1 0 0 0 0\n" + - " 63 64 2 0 0 0 0\n" + - " 63 65 1 0 0 0 0\n" + - " 65 66 1 0 0 0 0\n" + - " 66 67 1 0 0 0 0\n" + - " 67 68 1 0 0 0 0\n" + - " 67 69 2 0 0 0 0\n" + - "M END"; - Chemical c=Chemical.parse(mm); - - - String genChiral = c.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - - c=Chemical.parseMol(mm); - String molChiral = c.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - - c=new Chemical(ChemicalReaderFactory.read("sdf", mm + "\n$$$$")); - - String sdfChiral = c.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - - assertEquals(genChiral,molChiral); - assertEquals(genChiral,sdfChiral); - - } - - @Test - public void testAxialStereoMarkedR() throws Exception { - Chemical c1=Chemical.parse("\n" - + " ChemDraw12062311172D\n" - + "\n" - + " 19 20 0 0 0 0 0 0 0 0999 V2000\n" - + " -0.2855 -1.7339 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 0.4969 -1.7128 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 0.8881 -2.3895 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1.1525 -0.5075 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 0.7189 0.2114 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1.9348 -0.4863 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -0.6344 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1.1102 0.9305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 2.3260 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.0679 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.0679 -0.4440 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 0.6766 1.6494 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1.8925 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -0.6767 1.6706 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.8926 0.9728 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -0.6767 -1.1207 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.8926 -0.4229 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.1102 2.3895 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -2.3260 0.2960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 2 0 \n" - + " 2 3 1 0 \n" - + " 2 4 1 0 \n" - + " 4 5 2 0 \n" - + " 4 6 1 0 \n" - + " 5 7 1 0 \n" - + " 5 8 1 6 \n" - + " 6 9 2 0 \n" - + " 7 10 2 0 \n" - + " 7 11 1 0 \n" - + " 8 12 1 0 \n" - + " 8 13 2 0 \n" - + " 9 13 1 0 \n" - + " 10 14 1 0 \n" - + " 10 15 1 0 \n" - + " 11 16 1 0 \n" - + " 11 17 2 0 \n" - + " 14 18 1 0 \n" - + " 15 19 2 0 \n" - + " 17 19 1 0 \n" - + "M END"); - System.out.println(c1.toMol()); - Optional opChi=c1.atoms() - .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) - .map(ca->ca.getChirality()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.R, opChi.get()); - } - @Test - public void testAxialStereoMarkedS() throws Exception { - Chemical c1=Chemical.parse("\n" - + " ChemDraw12062311172D\n" - + "\n" - + " 19 20 0 0 0 0 0 0 0 0999 V2000\n" - + " -0.2855 -1.7339 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 0.4969 -1.7128 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 0.8881 -2.3895 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1.1525 -0.5075 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 0.7189 0.2114 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1.9348 -0.4863 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -0.6344 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1.1102 0.9305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 2.3260 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.0679 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.0679 -0.4440 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 0.6766 1.6494 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1.8925 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -0.6767 1.6706 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.8926 0.9728 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -0.6767 -1.1207 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.8926 -0.4229 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -1.1102 2.3895 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " -2.3260 0.2960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 2 0 \n" - + " 2 3 1 0 \n" - + " 2 4 1 0 \n" - + " 4 5 2 0 \n" - + " 4 6 1 0 \n" - + " 5 7 1 0 \n" - + " 5 8 1 1 \n" - + " 6 9 2 0 \n" - + " 7 10 2 0 \n" - + " 7 11 1 0 \n" - + " 8 12 1 0 \n" - + " 8 13 2 0 \n" - + " 9 13 1 0 \n" - + " 10 14 1 0 \n" - + " 10 15 1 0 \n" - + " 11 16 1 0 \n" - + " 11 17 2 0 \n" - + " 14 18 1 0 \n" - + " 15 19 2 0 \n" - + " 17 19 1 0 \n" - + "M END"); - System.out.println(c1.toMol()); - Optional opChi=c1.atoms() - .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) - .map(ca->ca.getChirality()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.S, opChi.get()); - } - - @Test - public void testAxialStereoUndefinedMarkedAsCenter() throws Exception { - Chemical c1=Chemical.parse("\n" - + " JSDraw212072312182D\n" - + "\n" - + " 6 6 0 0 0 0 999 V2000\n" - + " 17.4720 -8.8400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 16.1210 -8.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 16.1210 -6.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 18.8230 -8.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 18.8230 -6.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 17.4720 -5.7200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 2 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 1 4 1 0 0 0 0\n" - + " 4 5 2 0 0 0 0\n" - + " 5 6 1 0 0 0 0\n" - + " 6 3 2 0 0 0 0\n" - + "M END"); - System.out.println(c1.toMol()); - Optional opChi=c1.atoms() - .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) - .map(ca->ca.getChirality()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.Parity_Either, opChi.get()); - } - @Test - public void testSimpleTetrahedralStereoMarked() throws Exception { - Chemical c1=Chemical.parse("\n" + - " JSDraw209282010112D\n" + - "\n" + - " 5 4 0 0 0 0 0 V2000\n" + - " 23.6688 -9.1798 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 25.1766 -9.2022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 26.5285 -9.1725 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 25.1766 -7.6422 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 25.1766 -10.7622 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 0 0 0 0\n" + - " 2 4 1 0 0 0 0\n" + - " 2 5 1 0 0 0 0\n" + - "M END\n" + - ""); - - Optional opChi=c1.atoms() - .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) - .map(ca->ca.getChirality()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.Parity_Either, opChi.get()); - } - - - @Test - public void testSimpleCisTransRingStereoMarked() throws Exception { - Chemical c1=Chemical.parse("\n" - + " JSDraw212062312582D\n" - + "\n" - + " 8 8 0 0 1 0 999 V2000\n" - + " 24.4925 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.1415 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.1415 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4925 -4.9660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.8435 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.8435 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4925 -9.6460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4925 -3.4060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 3 4 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 5 6 1 0 0 0 0\n" - + " 6 1 1 0 0 0 0\n" - + " 1 7 1 1 0 0 0\n" - + " 4 8 1 1 0 0 0\n" - + "M END"); - - assertEquals(2,c1.getAllStereocenters().size()); - Optional opChi=c1.atoms() - .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) - .map(ca->ca.getChirality()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.s, opChi.get()); - } - - @Test - public void testSimpleCisTransRingStereoDetected() throws Exception { - Chemical c1=Chemical.parse("\n" - + " JSDraw212062312582D\n" - + "\n" - + " 8 8 0 0 1 0 999 V2000\n" - + " 24.4925 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.1415 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.1415 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4925 -4.9660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.8435 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.8435 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4925 -9.6460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4925 -3.4060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 3 4 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 5 6 1 0 0 0 0\n" - + " 6 1 1 0 0 0 0\n" - + " 1 7 1 0 0 0 0\n" - + " 4 8 1 0 0 0 0\n" - + "M END"); - String sdfChiral = c1.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("Parity_EitherParity_Either", sdfChiral); - assertEquals(2,c1.getAllStereocenters().size()); -// String sdfChiral = c1.atoms() -// .map(ca->ca.getChirality()) -// .filter(ch->!ch.equals(Chirality.Non_Chiral)) -// .map(ch->ch.toString()) -// .collect(Collectors.joining()); -// -// assertEquals("SSSR", sdfChiral); - } - - - @Test - public void testSimpleTetrahedralStereoMarkedAsCenter() throws Exception { - Chemical c1=Chemical.parse("\n" + - " JSDraw209282010112D\n" + - "\n" + - " 5 4 0 0 0 0 0 V2000\n" + - " 23.6688 -9.1798 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 25.1766 -9.2022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 26.5285 -9.1725 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 25.1766 -7.6422 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 25.1766 -10.7622 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 0 0 0 0\n" + - " 2 4 1 0 0 0 0\n" + - " 2 5 1 0 0 0 0\n" + - "M END\n" + - ""); - - Optional opChi=c1.getAllStereocenters().stream() - .map(ca->ca.getChirality()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.Parity_Either, opChi.get()); - } - - @Test - public void testSimpleTetrahedralStereoMarked2() throws Exception { - Chemical c1=Chemical.parse("\n" - + " JSDraw212072312292D\n" - + "\n" - + " 42 42 0 0 1 0 999 V2000\n" - + " 33.4515 -13.1881 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 32.1004 -13.9682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 30.7493 -13.1881 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 39.1857 -26.0176 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 40.4483 -25.1011 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 40.5559 -23.5448 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 39.2082 -22.7591 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 41.9607 -22.8654 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 42.1324 -21.3146 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 43.5022 -20.5673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 44.8574 -21.3399 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 43.3492 -19.0159 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 42.1023 -18.0774 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 41.7950 -16.5527 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 43.1529 -15.7973 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 43.1828 -14.2274 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 41.8398 -13.4353 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 41.9900 -11.8924 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 40.4817 -14.1926 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 40.4545 -15.7495 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 39.1482 -13.3918 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 39.2963 -11.8491 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 37.9520 -11.0842 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 37.8735 -9.5499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 36.5716 -8.7179 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 36.6213 -7.1692 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 37.9730 -6.4054 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 39.0516 -7.5281 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 40.5290 -8.0258 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 42.0698 -7.7805 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 38.8419 -2.1710 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 37.8550 -3.3778 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 37.5422 -4.9049 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 44.6029 -18.0888 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 44.9199 -16.5603 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 44.6823 -15.0152 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 46.2997 -15.8321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 47.6046 -16.6791 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 46.3490 -14.2696 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 47.5823 -13.3194 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 43.2388 -23.7596 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 43.3766 -25.3138 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 5 6 1 0 0 0 0\n" - + " 6 7 1 6 0 0 0\n" - + " 6 8 1 0 0 0 0\n" - + " 8 9 1 6 0 0 0\n" - + " 9 10 1 0 0 0 0\n" - + " 10 11 2 0 0 0 0\n" - + " 10 12 1 0 0 0 0\n" - + " 12 13 1 0 0 0 0\n" - + " 13 14 1 0 0 0 0\n" - + " 14 15 1 0 0 0 0\n" - + " 15 16 1 0 0 0 0\n" - + " 16 17 1 0 0 0 0\n" - + " 17 18 2 0 0 0 0\n" - + " 17 19 1 0 0 0 0\n" - + " 19 20 1 0 0 0 0\n" - + " 14 20 1 0 0 0 0\n" - + " 19 21 1 0 0 0 0\n" - + " 21 22 2 0 0 0 0\n" - + " 22 23 1 0 0 0 0\n" - + " 23 24 1 0 0 0 0\n" - + " 24 25 1 0 0 0 0\n" - + " 25 26 2 0 0 0 0\n" - + " 26 27 1 0 0 0 0\n" - + " 27 28 1 0 0 0 0\n" - + " 28 29 1 0 0 0 0\n" - + " 29 30 1 0 0 0 0\n" - + " 32 31 1 0 0 0 0\n" - + " 32 33 1 0 0 0 0\n" - + " 27 33 1 0 0 0 0\n" - + " 12 34 1 6 0 0 0\n" - + " 34 35 1 0 0 0 0\n" - + " 35 36 2 0 0 0 0\n" - + " 35 37 1 0 0 0 0\n" - + " 37 38 1 6 0 0 0\n" - + " 37 39 1 0 0 0 0\n" - + " 39 40 1 0 0 0 0\n" - + " 8 41 1 0 0 0 0\n" - + " 41 42 2 0 0 0 0\n" - + " 31 30 2 0 0 0 0\n" - + "M END"); - System.out.println(c1.toMol()); - String sdfChiral = c1.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("SSSR", sdfChiral); - } - @Test - public void testSetChiralityOnUnsetCaseWorksS() throws Exception { - Chemical c1=Chemical.parse("\n" - + " JSDraw212062317442D\n" - + "\n" - + " 6 5 0 0 0 0 999 V2000\n" - + " 10.6080 -5.5640 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 11.9590 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 13.3100 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 14.6610 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 16.0120 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 11.9590 -3.2240 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 3 4 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 2 6 1 0 0 0 0\n" - + "M END"); -// c1.generateCoordinates(); - String sdfChiral = c1.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("Parity_Either", sdfChiral); - c1.atoms() - .filter(ch->!ch.getChirality().equals(Chirality.Non_Chiral)) - .forEach(ch->ch.setChirality(Chirality.S)) - ; - sdfChiral = c1.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("S", sdfChiral); - - - } - @Test - public void testSetChiralityOnUnsetCaseWorksR() throws Exception { - Chemical c1=Chemical.parse("\n" - + " JSDraw212062317442D\n" - + "\n" - + " 6 5 0 0 0 0 999 V2000\n" - + " 10.6080 -5.5640 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 11.9590 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 13.3100 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 14.6610 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 16.0120 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 11.9590 -3.2240 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 3 4 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 2 6 1 0 0 0 0\n" - + "M END"); -// c1.generateCoordinates(); - String sdfChiral = c1.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("Parity_Either", sdfChiral); - c1.atoms() - .filter(ch->!ch.getChirality().equals(Chirality.Non_Chiral)) - .forEach(ch->ch.setChirality(Chirality.R)) - ; - sdfChiral = c1.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("R", sdfChiral); - - - - } - - @Test - public void testSulfoxideStereo() throws Exception { - Chemical c1=Chemical.parse("\n" + - " JSDraw209282010442D\n" + - "\n" + - " 5 4 0 0 1 0 999 V2000\n" + - " 16.7440 -8.8731 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 18.0950 -8.0931 0.0000 S 0 3 0 0 0 0 0 0 0 0 0 0\n" + - " 19.4460 -8.8731 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 20.7970 -8.0931 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 18.0950 -6.5331 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 0 0 0 0\n" + - " 3 4 1 0 0 0 0\n" + - " 2 5 1 1 0 0 0\n" + - "M CHG 2 2 1 5 -1\n" + - "M END"); - String sdfChiral = c1.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("R", sdfChiral); - } - @Test - public void testSulfoxideStereoPossible() throws Exception { - Chemical c1=Chemical.parse("\n" + - " JSDraw209282010462D\n" + - "\n" + - " 5 4 0 0 0 0 999 V2000\n" + - " 16.7440 -8.8731 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 18.0950 -8.0931 0.0000 S 0 3 0 0 0 0 0 0 0 0 0 0\n" + - " 19.4460 -8.8731 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 20.7970 -8.0931 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 18.0950 -6.5331 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 0 0 0 0\n" + - " 3 4 1 0 0 0 0\n" + - " 2 5 1 0 0 0 0\n" + - "M CHG 2 2 1 5 -1\n" + - "M END"); - String sdfChiral = c1.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("Parity_Either", sdfChiral); - } - @Test - public void testRemoveNonDescriptHydrogensDoesntRemoveStereoInformationOnMol() throws Exception { - - Chemical mol=Chemical.parse("\n" + - " JSDraw209282016242D\n" + - "\n" + - " 8 7 0 0 1 0 999 V2000\n" + - " 28.5600 -9.6110 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 28.0990 -8.1210 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 27.6380 -9.6110 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 29.4510 -7.3410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 30.9720 -7.6870 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 30.5110 -8.4850 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 29.4510 -5.7810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 26.7480 -7.3410 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 1 0 0 0\n" + - " 2 4 1 0 0 0 0\n" + - " 4 5 1 6 0 0 0\n" + - " 4 6 1 0 0 0 0\n" + - " 4 7 1 0 0 0 0\n" + - " 2 8 1 0 0 0 0\n" + - "M END"); - mol= Chemical.parse(mol.toMol()); - Chemical mol2= Chemical.createFromSmiles(mol.toSmiles()); - if(!mol2.hasCoordinates()){ - mol2.generateCoordinates(); - } - - mol2.removeNonDescriptHydrogens(); - mol2.generateCoordinates(); - mol2=Chemical.parse(mol2.toMol()); - - String sdfChiral = mol2.atoms() - .map(ca->ca.getChirality()) - .filter(ch->!ch.equals(Chirality.Non_Chiral)) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("SS", sdfChiral); - } - - @Test - public void testPsuedoStereocenterIsLowerCase() throws Exception { - - Chemical mol=Chemical.parse("\n" - + " JSDraw212062315202D\n" - + "\n" - + " 10 9 0 0 1 0 999 V2000\n" - + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 1 0 0 0\n" - + " 2 4 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 1 6 1 1 0 0 0\n" - + " 1 7 1 0 0 0 0\n" - + " 4 8 1 1 0 0 0\n" - + " 5 9 1 0 0 0 0\n" - + " 7 10 1 0 0 0 0\n" - + "M END"); - mol= Chemical.parse(mol.toMol()); - assertEquals(3,mol.getAllStereocenters().size()); - String sdfChiral =mol.getAllStereocenters() - .stream() - .filter(Stereocenter::isDefined) - .map(Stereocenter::getCenterAtom) - .filter(a -> a.getChirality() != null) - .map(a->a.getChirality()) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("SrR", sdfChiral); - } - - @Test - public void testPsuedoStereocenterOnNonMesoNotFound() throws Exception { - - Chemical mol=Chemical.parse("\n" - + " JSDraw212062315202D\n" - + "\n" - + " 10 9 0 0 1 0 999 V2000\n" - + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 1 0 0 0\n" - + " 2 4 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 1 6 1 1 0 0 0\n" - + " 1 7 1 0 0 0 0\n" - + " 4 8 1 6 0 0 0\n" - + " 5 9 1 0 0 0 0\n" - + " 7 10 1 0 0 0 0\n" - + "M END"); - mol= Chemical.parse(mol.toMol()); - assertEquals(2,mol.getAllStereocenters().size()); - String sdfChiral =mol.getAllStereocenters() - .stream() - .filter(Stereocenter::isDefined) - .map(Stereocenter::getCenterAtom) - .filter(a -> a.getChirality() != null) - .map(a->a.getChirality()) - .map(ch->ch.toString()) - .collect(Collectors.joining()); - - assertEquals("SS", sdfChiral); - } - - @Test - public void testPsuedoStereocenterIsDetected() throws Exception { - - Chemical mol=Chemical.parse("\n" - + " JSDraw212062315202D\n" - + "\n" - + " 10 9 0 0 1 0 999 V2000\n" - + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 2 4 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 1 6 1 0 0 0 0\n" - + " 1 7 1 0 0 0 0\n" - + " 4 8 1 0 0 0 0\n" - + " 5 9 1 0 0 0 0\n" - + " 7 10 1 0 0 0 0\n" - + "M END"); - mol= Chemical.parse(mol.toMol()); -// String sdfChiral = mol.atoms() -// .map(ca->ca.getChirality()) -// .filter(ch->!ch.equals(Chirality.Non_Chiral)) -// .map(ch->ch.toString()) -// .collect(Collectors.joining()); - assertEquals(3,mol.getAllStereocenters().size()); - } - - @Test - public void testHavingExplicitHydrogenOnStereoCenterDoesNotInvalidatePhosphateCenter() throws Exception { - - Chemical mol=Chemical.parse("\n" - + " JSDraw210312314162D\n" - + "\n" - + " 12 12 0 0 0 0 999 V2000\n" - + " 23.1415 -8.0860 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4925 -8.8660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.1415 -6.5260 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.8435 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.1415 -9.6460 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.8435 -6.5260 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 27.1945 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 28.5455 -6.5260 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 28.5455 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 27.1945 -8.8660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 21.7905 -8.8660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.8435 -9.6460 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 1 3 2 0 0 0 0\n" - + " 2 4 1 0 0 0 0\n" - + " 1 5 1 0 0 0 0\n" - + " 4 6 1 0 0 0 0\n" - + " 6 7 1 0 0 0 0\n" - + " 7 8 1 0 0 0 0\n" - + " 8 9 1 0 0 0 0\n" - + " 9 10 1 0 0 0 0\n" - + " 10 4 1 0 0 0 0\n" - + " 1 11 1 0 0 0 0\n" - + " 4 12 1 0 0 0 0\n" - + "M END"); - mol= Chemical.parse(mol.toMol()); - mol.removeNonDescriptHydrogens(); - System.out.println(mol.toMol()); - assertEquals(2,mol.getTetrahedrals().size()); - } - - @Test - public void testHavingBondTableOrderChangedShouldKeepSameStereo() throws Exception { - - - Chemical mol=Chemical.parse("\n" - + " JSDraw212042310502D\n" - + "\n" - + " 14 14 0 0 1 0 999 V2000\n" - + " 21.4047 -8.8605 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.0654 -9.2811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4188 -8.5056 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.1278 -7.7212 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.9094 -6.8325 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 26.0050 -8.5767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 26.6898 -5.7439 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 28.1943 -6.0199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4240 -6.9456 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.5922 -5.3944 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 21.7756 -6.0051 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 26.5338 -4.4447 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 20.6247 -10.2116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.0654 -10.8412 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 3 6 1 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 5 7 1 0 0 0 0\n" - + " 7 8 1 0 0 0 0\n" - + " 3 9 1 0 0 0 0\n" - + " 9 4 1 0 0 0 0\n" - + " 5 9 1 0 0 0 0\n" - + " 9 10 1 1 0 0 0\n" - + " 4 11 1 0 0 0 0\n" - + " 7 12 1 0 0 0 0\n" - + " 5 6 1 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 1 13 1 0 0 0 0\n" - + " 2 14 1 0 0 0 0\n" - + "M END"); - Optional opChi=mol.getTetrahedrals().stream() - .map(ca->ca.getChirality()) - .filter(ca->!ca.isEither()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.R, opChi.get()); - - - mol=Chemical.parse("\n" - + " JSDraw212042310502D\n" - + "\n" - + " 14 14 0 0 1 0 999 V2000\n" - + " 21.4047 -8.8605 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.0654 -9.2811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4188 -8.5056 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.1278 -7.7212 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 25.9094 -6.8325 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 26.0050 -8.5767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 26.6898 -5.7439 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 28.1943 -6.0199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.4240 -6.9456 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 24.5922 -5.3944 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 21.7756 -6.0051 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 26.5338 -4.4447 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 20.6247 -10.2116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 23.0654 -10.8412 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 3 6 1 0 0 0 0\n" - + " 5 7 1 0 0 0 0\n" - + " 7 8 1 0 0 0 0\n" - + " 3 9 1 0 0 0 0\n" - + " 9 4 1 0 0 0 0\n" - + " 5 9 1 0 0 0 0\n" - + " 9 10 1 1 0 0 0\n" - + " 4 11 1 0 0 0 0\n" - + " 7 12 1 0 0 0 0\n" - + " 5 6 1 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 1 13 1 0 0 0 0\n" - + " 2 14 1 0 0 0 0\n" - + "M END"); - opChi=mol.getTetrahedrals().stream() - .map(ca->ca.getChirality()) - .filter(ca->!ca.isEither()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.R, opChi.get()); - } - - @Test - public void testReadingSmilesShouldNotGenerateCoordinates() throws Exception { - - Chemical mol=Chemical.parse("\n" + - " JSDraw209282016242D\n" + - "\n" + - " 8 7 0 0 1 0 999 V2000\n" + - " 28.5600 -9.6110 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 28.0990 -8.1210 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 27.6380 -9.6110 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 29.4510 -7.3410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 30.9720 -7.6870 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 30.5110 -8.4850 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 29.4510 -5.7810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 26.7480 -7.3410 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 1 0 0 0\n" + - " 2 4 1 0 0 0 0\n" + - " 4 5 1 6 0 0 0\n" + - " 4 6 1 0 0 0 0\n" + - " 4 7 1 0 0 0 0\n" + - " 2 8 1 0 0 0 0\n" + - "M END"); - Chemical mol2= Chemical.createFromSmiles(mol.toSmiles()); - - - assertFalse(mol2.hasCoordinates()); - } - - - @Test - public void testMethaneRemoveNonDescriptHydrogensMakesRightSmiles() throws Exception { - Chemical mol=Chemical.parse("\n" + - " JSDraw209282013552D\n" + - "\n" + - " 4 3 0 0 0 0 999 V2000\n" + - " 18.7200 -10.7328 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 20.0710 -9.9528 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 18.7200 -12.2928 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 17.3690 -9.9528 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 1 3 1 0 0 0 0\n" + - " 1 4 1 0 0 0 0\n" + - "M END"); - mol=Chemical.parse(mol.toSmiles()); - mol.removeNonDescriptHydrogens(); - assertEquals("C", mol.toSmiles()); - } - - @Test - public void testSimpleExtendedTetrahedralStereoMarkedAsCenter() throws Exception { - Chemical c1=Chemical.parse("\n" + - " JSDraw209282018142D\n" + - "\n" + - " 7 6 0 0 1 0 999 V2000\n" + - " 10.0360 -7.4984 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 11.3870 -6.7184 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 13.0510 -5.7824 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 10.0360 -9.0584 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 8.6850 -6.7184 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 13.0510 -4.2224 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 14.4540 -6.5624 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 2 0 0 0 0\n" + - " 2 3 2 0 0 0 0\n" + - " 1 4 1 0 0 0 0\n" + - " 1 5 1 0 0 0 0\n" + - " 3 6 1 6 0 0 0\n" + - " 3 7 1 1 0 0 0\n" + - "M END"); - - - Optional opChi=c1.getAllStereocenters().stream() - .map(ca->ca.getChirality()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.S, opChi.get()); - } - - @Test - public void testSimpleTetrahedralStereoOnQuatAmineMarkedAsCenter() throws Exception { - Chemical c1=Chemical.parse("\n" + - " JSDraw209282021202D\n" + - "\n" + - " 8 7 0 0 0 0 0 V2000\n" + - " 14.8200 -10.2960 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 16.1710 -9.5160 0.0000 N 0 3 0 0 0 0 0 0 0 0 0 0\n" + - " 16.1710 -7.9560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 17.5220 -10.2960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 14.8200 -7.1760 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 18.8730 -9.5160 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 18.8730 -7.9560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 16.1710 -11.0760 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + - " 1 2 1 0 0 0 0\n" + - " 2 3 1 0 0 0 0\n" + - " 2 4 1 0 0 0 0\n" + - " 3 5 1 0 0 0 0\n" + - " 4 6 1 0 0 0 0\n" + - " 6 7 1 0 0 0 0\n" + - " 2 8 1 0 0 0 0\n" + - "M CHG 1 2 1\n" + - "M END\n" + - ""); - - Optional opChi=c1.getAllStereocenters().stream() - .map(ca->ca.getChirality()) - .findFirst(); - assertTrue(opChi.isPresent()); - assertEquals(Chirality.Parity_Either, opChi.get()); - } - - @Test - public void testSingleStereoBondBetweenTwoChiralCentersOnlyDefinesOneCenter() throws Exception { - Chemical c1=Chemical.parse("\n" - + " JSDraw210312313582D\n" - + "\n" - + " 9 9 0 0 1 0 0 V2000\n" - + " 17.6280 -11.3880 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 16.2770 -10.6080 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 16.2770 -9.0480 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 17.6280 -8.2680 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 18.9790 -9.0480 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 18.9790 -10.6080 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 20.3300 -8.2680 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 20.3300 -6.7080 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 21.6810 -9.0480 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" - + " 1 2 1 0 0 0 0\n" - + " 2 3 1 0 0 0 0\n" - + " 3 4 1 0 0 0 0\n" - + " 4 5 1 0 0 0 0\n" - + " 5 6 1 0 0 0 0\n" - + " 6 1 1 0 0 0 0\n" - + " 5 7 1 6 0 0 0\n" - + " 7 8 1 0 0 0 0\n" - + " 7 9 1 0 0 0 0\n" - + "M END\n" - + ""); - - assertEquals(2, c1.getAllStereocenters().size()); - assertEquals(Chirality.R, c1.getAllStereocenters().get(0).getChirality()); - assertEquals(Chirality.Parity_Either, c1.getAllStereocenters().get(1).getChirality()); - - } - - @Test - public void testQueryStructureSimpleTetrahedralStereoDoesntError() throws Exception { - Chemical c1=Chemical.parse("S(=O)(=O)(O)O-C-[#6]"); - - Optional opChi=c1.getAllStereocenters().stream() - .map(ca->ca.getChirality()) - .findFirst(); - assertFalse(opChi.isPresent()); - } - -} From 2fdfa0717b02a7d56d3112314cb7f06632c0c36a Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Thu, 7 Dec 2023 22:17:47 -0500 Subject: [PATCH 5/9] incremented version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a1c76d9..c3b2e46 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ gov.nih.ncats molwitch-cdk - 1.0.14-SNAPSHOT + 1.0.15-SNAPSHOT molwitch-cdk https://github.com/ncats/molwitch-cdk/ From e1f1cf3ccd92d9c9569770524a0d976cc4be06dc Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Thu, 7 Dec 2023 22:18:24 -0500 Subject: [PATCH 6/9] incremented molwitch core version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c3b2e46..4d92da4 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ gov.nih.ncats molwitch - 0.6.5-SNAPSHOT + 0.6.6-SNAPSHOT org.apache.logging.log4j From 2c964b139a34a6e6b1f35bc886822273e6266fb0 Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Fri, 8 Dec 2023 10:47:38 -0500 Subject: [PATCH 7/9] added missing file back --- src/test/java/TestChiralRead.java | 1149 +++++++++++++++++++++++++++++ 1 file changed, 1149 insertions(+) create mode 100644 src/test/java/TestChiralRead.java diff --git a/src/test/java/TestChiralRead.java b/src/test/java/TestChiralRead.java new file mode 100644 index 0000000..6bd1410 --- /dev/null +++ b/src/test/java/TestChiralRead.java @@ -0,0 +1,1149 @@ +/* + * NCATS-MOLWITCH-CDK + * + * Copyright (c) 2023. + * + * This work is free software; you can redistribute it and/or modify it under the terms of the + * GNU Lesser General Public License as published by the Free Software Foundation; + * either version 2.1 of the License, or (at your option) any later version. + * + * This work is distributed in the hope that it will be useful, but without any warranty; + * without even the implied warranty of merchantability or fitness for a particular purpose. + * See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library; + * if not, write to: + * + * the Free Software Foundation, Inc. + * 59 Temple Place, Suite 330 + * Boston, MA 02111-1307 USA + */ + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.BitSet; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.junit.Test; + +import gov.nih.ncats.molwitch.Chemical; +import gov.nih.ncats.molwitch.Chirality; +import gov.nih.ncats.molwitch.Stereocenter; +import gov.nih.ncats.molwitch.io.ChemicalReaderFactory; + +public class TestChiralRead { + @Test + public void ensureChiralityIsTheSameRegardlessOfSDFOrMolOrAgnosticRead() throws Exception{ + + String mm="\n" + + " CDK 09262014552D\n" + + "\n" + + " 69 71 0 0 1 0 0 0 0 0999 V2000\n" + + " 7.4100 3.6690 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 5.9100 3.6690 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 5.1600 2.3700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 5.9100 1.0710 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 3.6600 2.3700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2.9100 1.0700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 3.6600 -0.2200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 5.1600 -0.2175 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2.9100 -1.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 3.6602 -2.8189 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 5.1602 -2.8187 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 5.9036 -1.5158 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 7.3784 -1.4938 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 8.1792 -2.8143 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 9.6791 -2.7943 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 7.4358 -4.1171 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 5.8916 -4.0995 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.4100 -1.5200 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.6600 -2.8200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.4102 -4.1189 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.8400 -2.8200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.5902 -4.1189 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.5900 -1.5200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -3.0900 -1.5200 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -3.8400 -0.2200 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -5.3400 -0.2200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -6.0900 1.0700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -5.3400 2.3700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -3.8400 2.3700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -3.0898 1.0711 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -3.0900 3.6700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -3.8402 4.9689 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -5.3402 4.9687 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -6.0904 6.2676 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -6.0900 3.6695 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.5900 3.6700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.8400 4.9700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.5902 6.2689 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.6600 4.9700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.4102 6.2689 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.6604 7.5681 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.4106 8.8670 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.6608 10.1662 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2.9106 8.8668 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.4100 3.6700 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2.9100 3.6700 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 3.6602 4.9689 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -7.5900 1.0675 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -8.3422 2.3653 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -8.3378 -0.2328 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -7.7250 -1.5977 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -8.8347 -2.6101 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -10.1364 -1.8649 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -9.8338 -0.3903 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -10.8415 0.7208 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -10.3831 2.1490 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -12.3076 0.4036 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -13.3153 1.5147 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -12.8569 2.9429 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -13.8647 4.0540 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -15.3307 3.7369 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -13.4063 5.4823 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -14.7814 1.1975 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -15.2398 -0.2307 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -15.7891 2.3086 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -17.2552 1.9915 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -18.2629 3.1025 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -19.7290 2.7854 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -17.8045 4.5308 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 6 0 0 0\n" + + " 3 5 1 0 0 0 0\n" + + " 5 6 1 6 0 0 0\n" + + " 6 7 1 0 0 0 0\n" + + " 7 8 2 0 0 0 0\n" + + " 7 9 1 0 0 0 0\n" + + " 9 10 1 6 0 0 0\n" + + " 10 11 1 0 0 0 0\n" + + " 11 12 2 0 0 0 0\n" + + " 12 13 1 0 0 0 0\n" + + " 13 14 2 0 0 0 0\n" + + " 14 15 1 0 0 0 0\n" + + " 14 16 1 0 0 0 0\n" + + " 16 17 2 0 0 0 0\n" + + " 11 17 1 0 0 0 0\n" + + " 9 18 1 0 0 0 0\n" + + " 18 19 1 0 0 0 0\n" + + " 19 20 2 0 0 0 0\n" + + " 19 21 1 0 0 0 0\n" + + " 21 22 1 1 0 0 0\n" + + " 21 23 1 0 0 0 0\n" + + " 23 24 1 0 0 0 0\n" + + " 24 25 1 0 0 0 0\n" + + " 25 26 1 0 0 0 0\n" + + " 26 27 1 0 0 0 0\n" + + " 27 28 1 0 0 0 0\n" + + " 28 29 1 0 0 0 0\n" + + " 29 30 2 0 0 0 0\n" + + " 29 31 1 0 0 0 0\n" + + " 31 32 1 6 0 0 0\n" + + " 32 33 1 0 0 0 0\n" + + " 33 34 1 0 0 0 0\n" + + " 33 35 2 0 0 0 0\n" + + " 31 36 1 0 0 0 0\n" + + " 36 37 1 0 0 0 0\n" + + " 37 38 2 0 0 0 0\n" + + " 37 39 1 0 0 0 0\n" + + " 39 40 1 6 0 0 0\n" + + " 40 41 1 0 0 0 0\n" + + " 41 42 1 0 0 0 0\n" + + " 42 43 1 0 0 0 0\n" + + " 42 44 2 0 0 0 0\n" + + " 39 45 1 0 0 0 0\n" + + " 45 46 1 0 0 0 0\n" + + " 5 46 1 0 0 0 0\n" + + " 46 47 2 0 0 0 0\n" + + " 27 48 1 1 0 0 0\n" + + " 48 49 2 0 0 0 0\n" + + " 48 50 1 0 0 0 0\n" + + " 50 51 1 0 0 0 0\n" + + " 51 52 1 0 0 0 0\n" + + " 52 53 1 0 0 0 0\n" + + " 53 54 1 0 0 0 0\n" + + " 50 54 1 0 0 0 0\n" + + " 54 55 1 1 0 0 0\n" + + " 55 56 2 0 0 0 0\n" + + " 55 57 1 0 0 0 0\n" + + " 58 57 1 6 0 0 0\n" + + " 58 59 1 0 0 0 0\n" + + " 59 60 1 0 0 0 0\n" + + " 60 61 1 0 0 0 0\n" + + " 60 62 1 0 0 0 0\n" + + " 58 63 1 0 0 0 0\n" + + " 63 64 2 0 0 0 0\n" + + " 63 65 1 0 0 0 0\n" + + " 65 66 1 0 0 0 0\n" + + " 66 67 1 0 0 0 0\n" + + " 67 68 1 0 0 0 0\n" + + " 67 69 2 0 0 0 0\n" + + "M END"; + Chemical c=Chemical.parse(mm); + + + String genChiral = c.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + + c=Chemical.parseMol(mm); + String molChiral = c.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + + c=new Chemical(ChemicalReaderFactory.read("sdf", mm + "\n$$$$")); + + String sdfChiral = c.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + + assertEquals(genChiral,molChiral); + assertEquals(genChiral,sdfChiral); + + } + + @Test + public void testAxialStereoMarkedR() throws Exception { + Chemical c1=Chemical.parse("\n" + + " ChemDraw12062311172D\n" + + "\n" + + " 19 20 0 0 0 0 0 0 0 0999 V2000\n" + + " -0.2855 -1.7339 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.4969 -1.7128 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.8881 -2.3895 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.1525 -0.5075 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.7189 0.2114 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.9348 -0.4863 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6344 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.1102 0.9305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2.3260 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.0679 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.0679 -0.4440 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.6766 1.6494 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.8925 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6767 1.6706 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.8926 0.9728 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6767 -1.1207 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.8926 -0.4229 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.1102 2.3895 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -2.3260 0.2960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 2 0 \n" + + " 2 3 1 0 \n" + + " 2 4 1 0 \n" + + " 4 5 2 0 \n" + + " 4 6 1 0 \n" + + " 5 7 1 0 \n" + + " 5 8 1 6 \n" + + " 6 9 2 0 \n" + + " 7 10 2 0 \n" + + " 7 11 1 0 \n" + + " 8 12 1 0 \n" + + " 8 13 2 0 \n" + + " 9 13 1 0 \n" + + " 10 14 1 0 \n" + + " 10 15 1 0 \n" + + " 11 16 1 0 \n" + + " 11 17 2 0 \n" + + " 14 18 1 0 \n" + + " 15 19 2 0 \n" + + " 17 19 1 0 \n" + + "M END"); + System.out.println(c1.toMol()); + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.R, opChi.get()); + } + @Test + public void testAxialStereoMarkedS() throws Exception { + Chemical c1=Chemical.parse("\n" + + " ChemDraw12062311172D\n" + + "\n" + + " 19 20 0 0 0 0 0 0 0 0999 V2000\n" + + " -0.2855 -1.7339 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.4969 -1.7128 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.8881 -2.3895 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.1525 -0.5075 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.7189 0.2114 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.9348 -0.4863 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6344 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.1102 0.9305 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2.3260 0.2326 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.0679 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.0679 -0.4440 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 0.6766 1.6494 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1.8925 0.9516 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6767 1.6706 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.8926 0.9728 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -0.6767 -1.1207 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.8926 -0.4229 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -1.1102 2.3895 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " -2.3260 0.2960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 2 0 \n" + + " 2 3 1 0 \n" + + " 2 4 1 0 \n" + + " 4 5 2 0 \n" + + " 4 6 1 0 \n" + + " 5 7 1 0 \n" + + " 5 8 1 1 \n" + + " 6 9 2 0 \n" + + " 7 10 2 0 \n" + + " 7 11 1 0 \n" + + " 8 12 1 0 \n" + + " 8 13 2 0 \n" + + " 9 13 1 0 \n" + + " 10 14 1 0 \n" + + " 10 15 1 0 \n" + + " 11 16 1 0 \n" + + " 11 17 2 0 \n" + + " 14 18 1 0 \n" + + " 15 19 2 0 \n" + + " 17 19 1 0 \n" + + "M END"); + System.out.println(c1.toMol()); + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.S, opChi.get()); + } + + @Test + public void testAxialStereoUndefinedMarkedAsCenter() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212072312182D\n" + + "\n" + + " 6 6 0 0 0 0 999 V2000\n" + + " 17.4720 -8.8400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.1210 -8.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.1210 -6.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.8230 -8.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.8230 -6.5000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.4720 -5.7200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 2 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 1 4 1 0 0 0 0\n" + + " 4 5 2 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 3 2 0 0 0 0\n" + + "M END"); + System.out.println(c1.toMol()); + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.Parity_Either, opChi.get()); + } + @Test + public void testSimpleTetrahedralStereoMarked() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw209282010112D\n" + + "\n" + + " 5 4 0 0 0 0 0 V2000\n" + + " 23.6688 -9.1798 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.1766 -9.2022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.5285 -9.1725 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.1766 -7.6422 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.1766 -10.7622 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 2 5 1 0 0 0 0\n" + + "M END\n" + + ""); + + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.Parity_Either, opChi.get()); + } + + + @Test + public void testSimpleCisTransRingStereoMarked() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212062312582D\n" + + "\n" + + " 8 8 0 0 1 0 999 V2000\n" + + " 24.4925 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -4.9660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -9.6460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -3.4060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 1 1 0 0 0 0\n" + + " 1 7 1 1 0 0 0\n" + + " 4 8 1 1 0 0 0\n" + + "M END"); + + assertEquals(2,c1.getAllStereocenters().size()); + Optional opChi=c1.atoms() + .filter(ca->ca.getChirality()!=Chirality.Non_Chiral) + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.s, opChi.get()); + } + + @Test + public void testSimpleCisTransRingStereoDetected() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212062312582D\n" + + "\n" + + " 8 8 0 0 1 0 999 V2000\n" + + " 24.4925 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -4.9660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -7.3060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -9.6460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -3.4060 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 1 1 0 0 0 0\n" + + " 1 7 1 0 0 0 0\n" + + " 4 8 1 0 0 0 0\n" + + "M END"); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("Parity_EitherParity_Either", sdfChiral); + assertEquals(2,c1.getAllStereocenters().size()); +// String sdfChiral = c1.atoms() +// .map(ca->ca.getChirality()) +// .filter(ch->!ch.equals(Chirality.Non_Chiral)) +// .map(ch->ch.toString()) +// .collect(Collectors.joining()); +// +// assertEquals("SSSR", sdfChiral); + } + + + @Test + public void testSimpleTetrahedralStereoMarkedAsCenter() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw209282010112D\n" + + "\n" + + " 5 4 0 0 0 0 0 V2000\n" + + " 23.6688 -9.1798 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.1766 -9.2022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.5285 -9.1725 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.1766 -7.6422 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.1766 -10.7622 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 2 5 1 0 0 0 0\n" + + "M END\n" + + ""); + + Optional opChi=c1.getAllStereocenters().stream() + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.Parity_Either, opChi.get()); + } + + @Test + public void testSimpleTetrahedralStereoMarked2() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212072312292D\n" + + "\n" + + " 42 42 0 0 1 0 999 V2000\n" + + " 33.4515 -13.1881 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 32.1004 -13.9682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 30.7493 -13.1881 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.1857 -26.0176 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.4483 -25.1011 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.5559 -23.5448 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.2082 -22.7591 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 41.9607 -22.8654 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 42.1324 -21.3146 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.5022 -20.5673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 44.8574 -21.3399 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.3492 -19.0159 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 42.1023 -18.0774 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 41.7950 -16.5527 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.1529 -15.7973 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.1828 -14.2274 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 41.8398 -13.4353 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 41.9900 -11.8924 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.4817 -14.1926 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.4545 -15.7495 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.1482 -13.3918 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.2963 -11.8491 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.9520 -11.0842 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.8735 -9.5499 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 36.5716 -8.7179 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 36.6213 -7.1692 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.9730 -6.4054 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 39.0516 -7.5281 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 40.5290 -8.0258 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 42.0698 -7.7805 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 38.8419 -2.1710 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.8550 -3.3778 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 37.5422 -4.9049 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 44.6029 -18.0888 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 44.9199 -16.5603 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 44.6823 -15.0152 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 46.2997 -15.8321 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 47.6046 -16.6791 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 46.3490 -14.2696 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 47.5823 -13.3194 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.2388 -23.7596 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 43.3766 -25.3138 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 7 1 6 0 0 0\n" + + " 6 8 1 0 0 0 0\n" + + " 8 9 1 6 0 0 0\n" + + " 9 10 1 0 0 0 0\n" + + " 10 11 2 0 0 0 0\n" + + " 10 12 1 0 0 0 0\n" + + " 12 13 1 0 0 0 0\n" + + " 13 14 1 0 0 0 0\n" + + " 14 15 1 0 0 0 0\n" + + " 15 16 1 0 0 0 0\n" + + " 16 17 1 0 0 0 0\n" + + " 17 18 2 0 0 0 0\n" + + " 17 19 1 0 0 0 0\n" + + " 19 20 1 0 0 0 0\n" + + " 14 20 1 0 0 0 0\n" + + " 19 21 1 0 0 0 0\n" + + " 21 22 2 0 0 0 0\n" + + " 22 23 1 0 0 0 0\n" + + " 23 24 1 0 0 0 0\n" + + " 24 25 1 0 0 0 0\n" + + " 25 26 2 0 0 0 0\n" + + " 26 27 1 0 0 0 0\n" + + " 27 28 1 0 0 0 0\n" + + " 28 29 1 0 0 0 0\n" + + " 29 30 1 0 0 0 0\n" + + " 32 31 1 0 0 0 0\n" + + " 32 33 1 0 0 0 0\n" + + " 27 33 1 0 0 0 0\n" + + " 12 34 1 6 0 0 0\n" + + " 34 35 1 0 0 0 0\n" + + " 35 36 2 0 0 0 0\n" + + " 35 37 1 0 0 0 0\n" + + " 37 38 1 6 0 0 0\n" + + " 37 39 1 0 0 0 0\n" + + " 39 40 1 0 0 0 0\n" + + " 8 41 1 0 0 0 0\n" + + " 41 42 2 0 0 0 0\n" + + " 31 30 2 0 0 0 0\n" + + "M END"); + System.out.println(c1.toMol()); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("SSSR", sdfChiral); + } + @Test + public void testSetChiralityOnUnsetCaseWorksS() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212062317442D\n" + + "\n" + + " 6 5 0 0 0 0 999 V2000\n" + + " 10.6080 -5.5640 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.9590 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.3100 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.6610 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.0120 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.9590 -3.2240 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 2 6 1 0 0 0 0\n" + + "M END"); +// c1.generateCoordinates(); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("Parity_Either", sdfChiral); + c1.atoms() + .filter(ch->!ch.getChirality().equals(Chirality.Non_Chiral)) + .forEach(ch->ch.setChirality(Chirality.S)) + ; + sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("S", sdfChiral); + + + } + @Test + public void testSetChiralityOnUnsetCaseWorksR() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw212062317442D\n" + + "\n" + + " 6 5 0 0 0 0 999 V2000\n" + + " 10.6080 -5.5640 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.9590 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.3100 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.6610 -4.7840 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.0120 -5.5640 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.9590 -3.2240 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 2 6 1 0 0 0 0\n" + + "M END"); +// c1.generateCoordinates(); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("Parity_Either", sdfChiral); + c1.atoms() + .filter(ch->!ch.getChirality().equals(Chirality.Non_Chiral)) + .forEach(ch->ch.setChirality(Chirality.R)) + ; + sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("R", sdfChiral); + + + + } + + @Test + public void testSulfoxideStereo() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw209282010442D\n" + + "\n" + + " 5 4 0 0 1 0 999 V2000\n" + + " 16.7440 -8.8731 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.0950 -8.0931 0.0000 S 0 3 0 0 0 0 0 0 0 0 0 0\n" + + " 19.4460 -8.8731 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.7970 -8.0931 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.0950 -6.5331 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 2 5 1 1 0 0 0\n" + + "M CHG 2 2 1 5 -1\n" + + "M END"); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("R", sdfChiral); + } + @Test + public void testSulfoxideStereoPossible() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw209282010462D\n" + + "\n" + + " 5 4 0 0 0 0 999 V2000\n" + + " 16.7440 -8.8731 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.0950 -8.0931 0.0000 S 0 3 0 0 0 0 0 0 0 0 0 0\n" + + " 19.4460 -8.8731 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.7970 -8.0931 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.0950 -6.5331 0.0000 O 0 5 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 2 5 1 0 0 0 0\n" + + "M CHG 2 2 1 5 -1\n" + + "M END"); + String sdfChiral = c1.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("Parity_Either", sdfChiral); + } + @Test + public void testRemoveNonDescriptHydrogensDoesntRemoveStereoInformationOnMol() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw209282016242D\n" + + "\n" + + " 8 7 0 0 1 0 999 V2000\n" + + " 28.5600 -9.6110 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 28.0990 -8.1210 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 27.6380 -9.6110 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 29.4510 -7.3410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 30.9720 -7.6870 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 30.5110 -8.4850 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 29.4510 -5.7810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.7480 -7.3410 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 1 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 4 5 1 6 0 0 0\n" + + " 4 6 1 0 0 0 0\n" + + " 4 7 1 0 0 0 0\n" + + " 2 8 1 0 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + Chemical mol2= Chemical.createFromSmiles(mol.toSmiles()); + if(!mol2.hasCoordinates()){ + mol2.generateCoordinates(); + } + + mol2.removeNonDescriptHydrogens(); + mol2.generateCoordinates(); + mol2=Chemical.parse(mol2.toMol()); + + String sdfChiral = mol2.atoms() + .map(ca->ca.getChirality()) + .filter(ch->!ch.equals(Chirality.Non_Chiral)) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("SS", sdfChiral); + } + + @Test + public void testPsuedoStereocenterIsLowerCase() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212062315202D\n" + + "\n" + + " 10 9 0 0 1 0 999 V2000\n" + + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 1 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 1 6 1 1 0 0 0\n" + + " 1 7 1 0 0 0 0\n" + + " 4 8 1 1 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 7 10 1 0 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + assertEquals(3,mol.getAllStereocenters().size()); + String sdfChiral =mol.getAllStereocenters() + .stream() + .filter(Stereocenter::isDefined) + .map(Stereocenter::getCenterAtom) + .filter(a -> a.getChirality() != null) + .map(a->a.getChirality()) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("SrR", sdfChiral); + } + + @Test + public void testPsuedoStereocenterOnNonMesoNotFound() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212062315202D\n" + + "\n" + + " 10 9 0 0 1 0 999 V2000\n" + + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 1 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 1 6 1 1 0 0 0\n" + + " 1 7 1 0 0 0 0\n" + + " 4 8 1 6 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 7 10 1 0 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + assertEquals(2,mol.getAllStereocenters().size()); + String sdfChiral =mol.getAllStereocenters() + .stream() + .filter(Stereocenter::isDefined) + .map(Stereocenter::getCenterAtom) + .filter(a -> a.getChirality() != null) + .map(a->a.getChirality()) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("SS", sdfChiral); + } + + @Test + public void testPsuedoStereocenterIsDetected() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212062315202D\n" + + "\n" + + " 10 9 0 0 1 0 999 V2000\n" + + " 14.4560 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 15.8070 -5.7720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.5090 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.4560 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.1050 -7.3320 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.1580 -9.6720 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.0690 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.7540 -8.1120 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 1 6 1 0 0 0 0\n" + + " 1 7 1 0 0 0 0\n" + + " 4 8 1 0 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 7 10 1 0 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); +// String sdfChiral = mol.atoms() +// .map(ca->ca.getChirality()) +// .filter(ch->!ch.equals(Chirality.Non_Chiral)) +// .map(ch->ch.toString()) +// .collect(Collectors.joining()); + assertEquals(3,mol.getAllStereocenters().size()); + } + + @Test + public void testHavingExplicitHydrogenOnStereoCenterDoesNotInvalidatePhosphateCenter() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw210312314162D\n" + + "\n" + + " 12 12 0 0 0 0 999 V2000\n" + + " 23.1415 -8.0860 0.0000 P 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4925 -8.8660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -6.5260 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1415 -9.6460 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -6.5260 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 27.1945 -5.7460 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 28.5455 -6.5260 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 28.5455 -8.0860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 27.1945 -8.8660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.7905 -8.8660 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8435 -9.6460 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 1 3 2 0 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 1 5 1 0 0 0 0\n" + + " 4 6 1 0 0 0 0\n" + + " 6 7 1 0 0 0 0\n" + + " 7 8 1 0 0 0 0\n" + + " 8 9 1 0 0 0 0\n" + + " 9 10 1 0 0 0 0\n" + + " 10 4 1 0 0 0 0\n" + + " 1 11 1 0 0 0 0\n" + + " 4 12 1 0 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + mol.removeNonDescriptHydrogens(); + System.out.println(mol.toMol()); + assertEquals(2,mol.getTetrahedrals().size()); + } + + @Test + public void testHavingBondTableOrderChangedShouldKeepSameStereo() throws Exception { + + + Chemical mol=Chemical.parse("\n" + + " JSDraw212042310502D\n" + + "\n" + + " 14 14 0 0 1 0 999 V2000\n" + + " 21.4047 -8.8605 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.0654 -9.2811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4188 -8.5056 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1278 -7.7212 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.9094 -6.8325 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.0050 -8.5767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.6898 -5.7439 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 28.1943 -6.0199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4240 -6.9456 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.5922 -5.3944 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.7756 -6.0051 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.5338 -4.4447 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.6247 -10.2116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.0654 -10.8412 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 3 6 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 5 7 1 0 0 0 0\n" + + " 7 8 1 0 0 0 0\n" + + " 3 9 1 0 0 0 0\n" + + " 9 4 1 0 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 9 10 1 1 0 0 0\n" + + " 4 11 1 0 0 0 0\n" + + " 7 12 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 1 13 1 0 0 0 0\n" + + " 2 14 1 0 0 0 0\n" + + "M END"); + Optional opChi=mol.getTetrahedrals().stream() + .map(ca->ca.getChirality()) + .filter(ca->!ca.isEither()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.R, opChi.get()); + + + mol=Chemical.parse("\n" + + " JSDraw212042310502D\n" + + "\n" + + " 14 14 0 0 1 0 999 V2000\n" + + " 21.4047 -8.8605 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.0654 -9.2811 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4188 -8.5056 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1278 -7.7212 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.9094 -6.8325 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.0050 -8.5767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.6898 -5.7439 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 28.1943 -6.0199 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.4240 -6.9456 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.5922 -5.3944 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.7756 -6.0051 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.5338 -4.4447 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.6247 -10.2116 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.0654 -10.8412 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 6 1 0 0 0 0\n" + + " 5 7 1 0 0 0 0\n" + + " 7 8 1 0 0 0 0\n" + + " 3 9 1 0 0 0 0\n" + + " 9 4 1 0 0 0 0\n" + + " 5 9 1 0 0 0 0\n" + + " 9 10 1 1 0 0 0\n" + + " 4 11 1 0 0 0 0\n" + + " 7 12 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 1 13 1 0 0 0 0\n" + + " 2 14 1 0 0 0 0\n" + + "M END"); + opChi=mol.getTetrahedrals().stream() + .map(ca->ca.getChirality()) + .filter(ca->!ca.isEither()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.R, opChi.get()); + } + + @Test + public void testReadingSmilesShouldNotGenerateCoordinates() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw209282016242D\n" + + "\n" + + " 8 7 0 0 1 0 999 V2000\n" + + " 28.5600 -9.6110 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 28.0990 -8.1210 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 27.6380 -9.6110 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 29.4510 -7.3410 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 30.9720 -7.6870 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 30.5110 -8.4850 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 29.4510 -5.7810 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 26.7480 -7.3410 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 1 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 4 5 1 6 0 0 0\n" + + " 4 6 1 0 0 0 0\n" + + " 4 7 1 0 0 0 0\n" + + " 2 8 1 0 0 0 0\n" + + "M END"); + Chemical mol2= Chemical.createFromSmiles(mol.toSmiles()); + + + assertFalse(mol2.hasCoordinates()); + } + + + @Test + public void testMethaneRemoveNonDescriptHydrogensMakesRightSmiles() throws Exception { + Chemical mol=Chemical.parse("\n" + + " JSDraw209282013552D\n" + + "\n" + + " 4 3 0 0 0 0 999 V2000\n" + + " 18.7200 -10.7328 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.0710 -9.9528 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.7200 -12.2928 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.3690 -9.9528 0.0000 H 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 1 3 1 0 0 0 0\n" + + " 1 4 1 0 0 0 0\n" + + "M END"); + mol=Chemical.parse(mol.toSmiles()); + mol.removeNonDescriptHydrogens(); + assertEquals("C", mol.toSmiles()); + } + + @Test + public void testSimpleExtendedTetrahedralStereoMarkedAsCenter() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw209282018142D\n" + + "\n" + + " 7 6 0 0 1 0 999 V2000\n" + + " 10.0360 -7.4984 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 11.3870 -6.7184 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.0510 -5.7824 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 10.0360 -9.0584 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 8.6850 -6.7184 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 13.0510 -4.2224 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.4540 -6.5624 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 2 0 0 0 0\n" + + " 2 3 2 0 0 0 0\n" + + " 1 4 1 0 0 0 0\n" + + " 1 5 1 0 0 0 0\n" + + " 3 6 1 6 0 0 0\n" + + " 3 7 1 1 0 0 0\n" + + "M END"); + + + Optional opChi=c1.getAllStereocenters().stream() + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.S, opChi.get()); + } + + @Test + public void testSimpleTetrahedralStereoOnQuatAmineMarkedAsCenter() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw209282021202D\n" + + "\n" + + " 8 7 0 0 0 0 0 V2000\n" + + " 14.8200 -10.2960 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.1710 -9.5160 0.0000 N 0 3 0 0 0 0 0 0 0 0 0 0\n" + + " 16.1710 -7.9560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.5220 -10.2960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 14.8200 -7.1760 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.8730 -9.5160 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.8730 -7.9560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.1710 -11.0760 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 2 4 1 0 0 0 0\n" + + " 3 5 1 0 0 0 0\n" + + " 4 6 1 0 0 0 0\n" + + " 6 7 1 0 0 0 0\n" + + " 2 8 1 0 0 0 0\n" + + "M CHG 1 2 1\n" + + "M END\n" + + ""); + + Optional opChi=c1.getAllStereocenters().stream() + .map(ca->ca.getChirality()) + .findFirst(); + assertTrue(opChi.isPresent()); + assertEquals(Chirality.Parity_Either, opChi.get()); + } + + @Test + public void testSingleStereoBondBetweenTwoChiralCentersOnlyDefinesOneCenter() throws Exception { + Chemical c1=Chemical.parse("\n" + + " JSDraw210312313582D\n" + + "\n" + + " 9 9 0 0 1 0 0 V2000\n" + + " 17.6280 -11.3880 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.2770 -10.6080 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 16.2770 -9.0480 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 17.6280 -8.2680 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.9790 -9.0480 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.9790 -10.6080 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.3300 -8.2680 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 20.3300 -6.7080 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.6810 -9.0480 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 1 1 0 0 0 0\n" + + " 5 7 1 6 0 0 0\n" + + " 7 8 1 0 0 0 0\n" + + " 7 9 1 0 0 0 0\n" + + "M END\n" + + ""); + + assertEquals(2, c1.getAllStereocenters().size()); + assertEquals(Chirality.R, c1.getAllStereocenters().get(0).getChirality()); + assertEquals(Chirality.Parity_Either, c1.getAllStereocenters().get(1).getChirality()); + + } + + @Test + public void testQueryStructureSimpleTetrahedralStereoDoesntError() throws Exception { + Chemical c1=Chemical.parse("S(=O)(=O)(O)O-C-[#6]"); + + Optional opChi=c1.getAllStereocenters().stream() + .map(ca->ca.getChirality()) + .findFirst(); + assertFalse(opChi.isPresent()); + } + +} From f72c2b00c548f6d5a3ebb14e3513f1b04aa9fd47 Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Fri, 8 Dec 2023 10:49:53 -0500 Subject: [PATCH 8/9] ignore test that doesn't work yet --- src/test/java/TestChiralRead.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/TestChiralRead.java b/src/test/java/TestChiralRead.java index 6bd1410..9546f3a 100644 --- a/src/test/java/TestChiralRead.java +++ b/src/test/java/TestChiralRead.java @@ -27,6 +27,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import org.junit.Ignore; import org.junit.Test; import gov.nih.ncats.molwitch.Chemical; @@ -324,6 +325,7 @@ public void testAxialStereoMarkedS() throws Exception { assertEquals(Chirality.S, opChi.get()); } + @Ignore @Test public void testAxialStereoUndefinedMarkedAsCenter() throws Exception { Chemical c1=Chemical.parse("\n" From e6b37ee29b18af5708e987301fc46a8667e3c225 Mon Sep 17 00:00:00 2001 From: Tyler Peryea Date: Mon, 11 Dec 2023 09:07:31 -0500 Subject: [PATCH 9/9] upodated stereo detector --- .../ncats/molwitch/cdk/CdkChemicalImpl.java | 17 ++- src/test/java/TestChiralRead.java | 121 ++++++++++++++++++ 2 files changed, 134 insertions(+), 4 deletions(-) diff --git a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java index 2fdcc31..e20e9e1 100644 --- a/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java +++ b/src/main/java/gov/nih/ncats/molwitch/cdk/CdkChemicalImpl.java @@ -277,11 +277,20 @@ public class CdkChemicalImpl implements ChemicalImpl{ // real stereocenter. If not, it's not a real stereocenter. if(ai3.getProperty(CDKConstants.CIP_DESCRIPTOR) == null){ + //The problem here is, if there IS a defined wedge/dash + //it shouldn't be considered a potential center + CdkAtom cat=new CdkAtom(container.getAtom(i),this); - potentialSet.add(i); - undefinedSet.add(i); - if(!deepChirality) { - container.getAtom(i).setProperty(CDKConstants.CIP_DESCRIPTOR, "EITHER"); + boolean hasStereo = cat.getBonds().stream() + .filter(b->b.getBondType().equals(BondType.SINGLE)) + .filter(b->!b.getStereo().equals(Bond.Stereo.NONE)) + .findAny().isPresent(); + if(!hasStereo) { + potentialSet.add(i); + undefinedSet.add(i); + if(!deepChirality) { + container.getAtom(i).setProperty(CDKConstants.CIP_DESCRIPTOR, "EITHER"); + } } } diff --git a/src/test/java/TestChiralRead.java b/src/test/java/TestChiralRead.java index 9546f3a..5cd5876 100644 --- a/src/test/java/TestChiralRead.java +++ b/src/test/java/TestChiralRead.java @@ -794,6 +794,127 @@ public void testPsuedoStereocenterIsLowerCase() throws Exception { assertEquals("SrR", sdfChiral); } + + @Test + public void testPsuedoStereocenterIn135trimethylcyclohexaneIsLowerCase() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212082315262D\n" + + "\n" + + " 9 9 0 0 1 0 999 V2000\n" + + " 24.5440 -10.0360 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1930 -9.2560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1930 -7.6960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.5440 -6.9160 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8950 -7.6960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8950 -9.2560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.5440 -5.3560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.8420 -10.0360 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 27.2460 -10.0360 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 1 1 0 0 0 0\n" + + " 4 7 1 1 0 0 0\n" + + " 2 8 1 1 0 0 0\n" + + " 6 9 1 6 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + assertEquals(1,mol.getAllStereocenters().size()); + String sdfChiral =mol.getAllStereocenters() + .stream() + .filter(Stereocenter::isDefined) + .map(Stereocenter::getCenterAtom) + .filter(a -> a.getChirality() != null) + .map(a->a.getChirality()) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("r", sdfChiral); + } + + @Test + public void testPsuedoStereocenterIn135trimethylcyclohexaneIsLowerCaseC() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212082315262D\n" + + "\n" + + " 9 9 0 0 1 0 999 V2000\n" + + " 24.5440 -10.0360 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1930 -9.2560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.1930 -7.6960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.5440 -6.9160 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8950 -7.6960 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 25.8950 -9.2560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 24.5440 -5.3560 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.8420 -10.0360 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 27.2460 -10.0360 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 1 1 0 0 0 0\n" + + " 4 7 1 1 0 0 0\n" + + " 2 8 1 6 0 0 0\n" + + " 6 9 1 6 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + assertEquals(1,mol.getAllStereocenters().size()); + String sdfChiral =mol.getAllStereocenters() + .stream() + .filter(Stereocenter::isDefined) + .map(Stereocenter::getCenterAtom) + .filter(a -> a.getChirality() != null) + .map(a->a.getChirality()) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("r", sdfChiral); + } + + @Test + public void testPsuedoStereocenterIn135trimethylcyclohexaneIsLowerCaseB() throws Exception { + + Chemical mol=Chemical.parse("\n" + + " JSDraw212082315262D\n" + + "\n" + + " 9 9 0 0 1 0 999 V2000\n" + + " 21.1640 -11.4400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 19.8130 -10.6600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 19.8130 -9.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.1640 -8.3200 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 22.5150 -9.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 22.5150 -10.6600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 21.1640 -6.7600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 18.4620 -11.4400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 23.8660 -11.4400 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n" + + " 1 2 1 0 0 0 0\n" + + " 2 3 1 0 0 0 0\n" + + " 3 4 1 0 0 0 0\n" + + " 4 5 1 0 0 0 0\n" + + " 5 6 1 0 0 0 0\n" + + " 6 1 1 0 0 0 0\n" + + " 4 7 1 1 0 0 0\n" + + " 2 8 1 1 0 0 0\n" + + " 6 9 1 1 0 0 0\n" + + "M END"); + mol= Chemical.parse(mol.toMol()); + assertEquals(3,mol.getAllStereocenters().size()); + String sdfChiral =mol.getAllStereocenters() + .stream() + .filter(Stereocenter::isDefined) + .map(Stereocenter::getCenterAtom) + .filter(a -> a.getChirality() != null) + .map(a->a.getChirality()) + .map(ch->ch.toString()) + .collect(Collectors.joining()); + + assertEquals("sss", sdfChiral); + } + @Test public void testPsuedoStereocenterOnNonMesoNotFound() throws Exception {