From e36983b16502519905578a7a07b00a9e7fd1cf3b Mon Sep 17 00:00:00 2001 From: Stefan Kuhn Date: Tue, 13 Oct 2009 11:57:35 +0100 Subject: [PATCH 01/21] MDL reading and writing UP_OR_DOWN Signed-off-by: Rajarshi Guha --- src/main/org/openscience/cdk/io/MDLReader.java | 7 +++++-- src/main/org/openscience/cdk/io/MDLV2000Reader.java | 2 +- src/main/org/openscience/cdk/io/MDLWriter.java | 6 +++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/org/openscience/cdk/io/MDLReader.java b/src/main/org/openscience/cdk/io/MDLReader.java index b4a43fd3d30..e295fc0f764 100644 --- a/src/main/org/openscience/cdk/io/MDLReader.java +++ b/src/main/org/openscience/cdk/io/MDLReader.java @@ -525,8 +525,11 @@ private IMolecule readMolecule(IMolecule molecule) throws CDKException { // bond has no stereochemistry stereo = IBond.Stereo.NONE; } else if (mdlStereo == 4) { - //MDL bond undefined - stereo = (IBond.Stereo)CDKConstants.UNSET; + //MDL up or down bond + stereo = IBond.Stereo.UP_OR_DOWN; + } else if (mdlStereo == 3) { + //MDL e or z undefined + stereo = IBond.Stereo.E_OR_Z; } } else { logger.warn("Missing expected stereo field at line: " + line); diff --git a/src/main/org/openscience/cdk/io/MDLV2000Reader.java b/src/main/org/openscience/cdk/io/MDLV2000Reader.java index 88e0f2923e8..65ef0ff26b6 100644 --- a/src/main/org/openscience/cdk/io/MDLV2000Reader.java +++ b/src/main/org/openscience/cdk/io/MDLV2000Reader.java @@ -619,7 +619,7 @@ private IMolecule readMolecule(IMolecule molecule) throws CDKException { stereo = IBond.Stereo.E_OR_Z; } else if (mdlStereo == 4) { //MDL bond undefined - stereo = (IBond.Stereo)CDKConstants.UNSET; + stereo = IBond.Stereo.UP_OR_DOWN; } } else { handleError( diff --git a/src/main/org/openscience/cdk/io/MDLWriter.java b/src/main/org/openscience/cdk/io/MDLWriter.java index 98512314ace..a141be9f01a 100644 --- a/src/main/org/openscience/cdk/io/MDLWriter.java +++ b/src/main/org/openscience/cdk/io/MDLWriter.java @@ -322,7 +322,8 @@ else if(atom.getValency()==0) logger.warn("Skipping bond with more/less than two atoms: " + bond); } else { if (bond.getStereo() == IBond.Stereo.UP_INVERTED || - bond.getStereo() == IBond.Stereo.DOWN_INVERTED) { + bond.getStereo() == IBond.Stereo.DOWN_INVERTED || + bond.getStereo() == IBond.Stereo.UP_OR_DOWN_INVERTED) { // turn around atom coding to correct for inv stereo line = formatMDLInt(container.getAtomNumber(bond.getAtom(1)) + 1,3); line += formatMDLInt(container.getAtomNumber(bond.getAtom(0)) + 1,3); @@ -348,6 +349,9 @@ else if(atom.getValency()==0) case UP_OR_DOWN: line += "4"; break; + case UP_OR_DOWN_INVERTED: + line += "4"; + break; case E_OR_Z: line += "3"; break; From c4ea1d843f8eb3c8c7c1ac5e4ac27e09d0ae8ab6 Mon Sep 17 00:00:00 2001 From: Stefan Kuhn Date: Mon, 23 Nov 2009 16:44:21 +0000 Subject: [PATCH 02/21] Added a test case for short line mol files. Patch by S.Kuhn, reworked by M.Rijnbeek. Signed-off-by: Rajarshi Guha --- src/test/data/mdl/glycine-short-lines.mol | 14 ++++++++++++++ .../openscience/cdk/io/MDLV2000ReaderTest.java | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/test/data/mdl/glycine-short-lines.mol diff --git a/src/test/data/mdl/glycine-short-lines.mol b/src/test/data/mdl/glycine-short-lines.mol new file mode 100644 index 00000000000..01778eb6e02 --- /dev/null +++ b/src/test/data/mdl/glycine-short-lines.mol @@ -0,0 +1,14 @@ + + OpenBabel11190809032D + + 5 4 0 0 0 0 0 0 0 0999 V2000 + 206.0000 126.0000 0.0000 C 0 0 0 0 0 + 227.0075 113.8713 0.0000 C 0 0 0 0 0 + 227.0075 89.6139 0.0000 O 0 0 0 0 0 + 248.0151 126.0000 0.0000 O 0 0 0 0 0 + 184.9925 113.8713 0.0000 N 0 0 0 0 0 + 1 2 1 0 0 0 + 1 5 1 0 0 0 + 2 3 2 0 0 0 + 2 4 1 0 0 0 +M END \ No newline at end of file diff --git a/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java b/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java index 217120a1ca2..9fc176f0fd3 100644 --- a/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java @@ -754,4 +754,21 @@ public void testQueryBondTypes() throws Exception { Assert.assertNull(mol.getAtom(2).getValency()); Assert.assertEquals(0, mol.getAtom(3).getValency().intValue()); } + + @Test public void testShortLines() throws Exception { + logger.info("Testing short lines Mode.RELAXED"); + testShortLinesForMode(Mode.RELAXED); + logger.info("Testing short lines Mode.STRICT"); + testShortLinesForMode(Mode.STRICT); + } + + private void testShortLinesForMode (IChemObjectReader.Mode mode) throws Exception { + String filename = "data/mdl/glycine-short-lines.mol"; + InputStream ins = this.getClass().getClassLoader().getResourceAsStream(filename); + MDLV2000Reader reader = new MDLV2000Reader(ins, mode); + Molecule mol = reader.read(new Molecule()); + Assert.assertNotNull(mol); + Assert.assertEquals(mol.getAtomCount(), 5); + Assert.assertEquals(mol.getBondCount(), 4); + } } From 3b974e6238da35e745807c94ff1c964eb18d8c29 Mon Sep 17 00:00:00 2001 From: Stefan Kuhn Date: Mon, 10 May 2010 10:44:39 +0100 Subject: [PATCH 03/21] Revert "Additional constant" This reverts commit 856197c02328369333f0442d664a02f33a7175bf. the move arrows are no longer needed, mouse pointer is changed the move arrows are no longer needed, mouse pointer is changed Signed-off-by: Rajarshi Guha --- src/main/org/openscience/cdk/CDKConstants.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/org/openscience/cdk/CDKConstants.java b/src/main/org/openscience/cdk/CDKConstants.java index 199cb49a14b..0634c696806 100644 --- a/src/main/org/openscience/cdk/CDKConstants.java +++ b/src/main/org/openscience/cdk/CDKConstants.java @@ -168,14 +168,10 @@ public class CDKConstants { /** Flag is set if an atom could be typed. */ public static final int IS_TYPEABLE = 11; - /** Flag is set in JCP if an arrow indicating move - * should be shown. - */ - public static final int SHOW_MOVE_ARRAY = 12; /** * Maximum flags array index. */ - public final static int MAX_FLAG_INDEX = 13; + public final static int MAX_FLAG_INDEX = 12; /** * Flag used for JUnit testing the pointer functionality. */ From 353f938852add95dbab92e67322bb44117ec7480 Mon Sep 17 00:00:00 2001 From: Stefan Kuhn Date: Thu, 26 Nov 2009 15:26:57 +0000 Subject: [PATCH 04/21] more mdl reader writer tests Signed-off-by: Rajarshi Guha --- src/test/data/mdl/ChEBI_26120.mol | 2 +- .../mdl/a-pinene-with-undefined-stereo.mol | 26 +++++++++++++++++++ .../org/openscience/cdk/io/MDLReaderTest.java | 13 ++++++++++ .../cdk/io/MDLV2000ReaderTest.java | 1 + 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/test/data/mdl/a-pinene-with-undefined-stereo.mol diff --git a/src/test/data/mdl/ChEBI_26120.mol b/src/test/data/mdl/ChEBI_26120.mol index 00981281164..8296e8aa25d 100644 --- a/src/test/data/mdl/ChEBI_26120.mol +++ b/src/test/data/mdl/ChEBI_26120.mol @@ -53,7 +53,7 @@ 8 10 1 0 0 0 0 9 11 1 0 0 0 0 9 12 1 0 0 0 0 - 10 13 2 3 0 0 0 + 10 13 2 4 0 0 0 10 14 1 0 0 0 0 11 15 1 0 0 0 0 13 16 1 0 0 0 0 diff --git a/src/test/data/mdl/a-pinene-with-undefined-stereo.mol b/src/test/data/mdl/a-pinene-with-undefined-stereo.mol new file mode 100644 index 00000000000..7e1056e61d2 --- /dev/null +++ b/src/test/data/mdl/a-pinene-with-undefined-stereo.mol @@ -0,0 +1,26 @@ +a-pinen.mol + ChemDraw08319810042D + + 10 11 0 0 0 0 0 0 0 0 1 V2000 + -2.0500 -1.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.7500 -0.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.5500 -1.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -0.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8100 -1.4100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.3625 1.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0500 0.4000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.9375 1.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.6625 1.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 3 0 0 0 + 1 3 1 4 0 0 0 + 3 4 1 0 0 0 0 + 2 5 1 0 0 0 0 + 5 6 2 0 0 0 0 + 4 6 1 0 0 0 0 + 2 7 1 0 0 0 0 + 3 7 1 0 0 0 0 + 5 8 1 0 0 0 0 + 7 9 1 0 0 0 0 + 7 10 1 0 0 0 0 +M END diff --git a/src/test/org/openscience/cdk/io/MDLReaderTest.java b/src/test/org/openscience/cdk/io/MDLReaderTest.java index 526e5087478..e7a72860829 100644 --- a/src/test/org/openscience/cdk/io/MDLReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLReaderTest.java @@ -193,4 +193,17 @@ public class MDLReaderTest extends SimpleChemObjectReaderTest { Assert.assertNull(mol); } + + @Test public void testUndefinedStereo() throws Exception { + String filename = "data/mdl/ChEBI_26120.mol"; + logger.info("Testing: " + filename); + InputStream ins = this.getClass().getClassLoader().getResourceAsStream(filename); + MDLReader reader = new MDLReader(ins, Mode.RELAXED); + IMolecule mol = (IMolecule)reader.read(new NNMolecule()); + Assert.assertEquals(IBond.Stereo.E_OR_Z,mol.getBond(1).getStereo()); + Assert.assertEquals(IBond.Stereo.E_OR_Z,mol.getBond(6).getStereo()); + Assert.assertEquals(IBond.Stereo.E_OR_Z,mol.getBond(7).getStereo()); + Assert.assertEquals(IBond.Stereo.UP_OR_DOWN,mol.getBond(11).getStereo()); + } + } diff --git a/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java b/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java index 9fc176f0fd3..44c037d2403 100644 --- a/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java @@ -575,6 +575,7 @@ public class MDLV2000ReaderTest extends SimpleChemObjectReaderTest { Assert.assertEquals(IBond.Stereo.E_OR_Z,mol.getBond(1).getStereo()); Assert.assertEquals(IBond.Stereo.E_OR_Z,mol.getBond(6).getStereo()); Assert.assertEquals(IBond.Stereo.E_OR_Z,mol.getBond(7).getStereo()); + Assert.assertEquals(IBond.Stereo.UP_OR_DOWN,mol.getBond(11).getStereo()); } /** From d6d6ab0022b667d7f93db9b2ecf3d551ccf158fa Mon Sep 17 00:00:00 2001 From: mark_rynbeek Date: Fri, 8 Jan 2010 15:28:36 +0000 Subject: [PATCH 05/21] Flexibility for ring start angles. Signed-off-by: Rajarshi Guha --- .../openscience/cdk/layout/RingPlacer.java | 68 +++++++++++++------ 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/src/main/org/openscience/cdk/layout/RingPlacer.java b/src/main/org/openscience/cdk/layout/RingPlacer.java index 8a6e0a3a8f6..d0cf76c8d1c 100644 --- a/src/main/org/openscience/cdk/layout/RingPlacer.java +++ b/src/main/org/openscience/cdk/layout/RingPlacer.java @@ -26,7 +26,9 @@ */ package org.openscience.cdk.layout; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Vector; import javax.vecmath.Point2d; @@ -67,6 +69,30 @@ public class RingPlacer static int BRIDGED = 1; static int SPIRO = 2; + /** + * Default ring start angles. Map contains pairs: ring size with start angle. + */ + public static final Map defaultAngles = new HashMap(); + static { + defaultAngles.put(3,Math.PI*(0.1666667)); + defaultAngles.put(4,Math.PI*(0.25)); + defaultAngles.put(5,Math.PI*(0.3)); + defaultAngles.put(7,Math.PI*(0.07)); + defaultAngles.put(8,Math.PI*(0.125)); + } + + /** + * Suggested ring start angles for JChempaint, different due to Y inversion of canvas. + */ + public static final Map jcpAngles = new HashMap(); + static { + jcpAngles.put(3,Math.PI*(0.5)); + jcpAngles.put(4,Math.PI*(0.25)); + jcpAngles.put(5,Math.PI*(0.5)); + jcpAngles.put(7,Math.PI*(0.07)); + jcpAngles.put(8,Math.PI*(0.125)); + } + /** * The empty constructor. */ @@ -101,10 +127,27 @@ else if (sharedAtomCount == 1) { placeSpiroRing(ring, sharedAtoms, sharedAtomsCenter, ringCenterVector, bondLength); } - } - - public void placeRing(IRing ring, Point2d ringCenter, double bondLength) { + + /** + * Place ring with default start angles, using {@link #defaultAngles}. + * @param ring the ring to place. + * @param ringCenter center coordinates of the ring. + * @param bondLength given bond length. + */ + public void placeRing(IRing ring, Point2d ringCenter, double bondLength) { + placeRing(ring, ringCenter, bondLength, defaultAngles); + } + + /** + * Place ring with user provided angles. + * + * @param ring the ring to place. + * @param ringCenter center coordinates of the ring. + * @param bondLength given bond length. + * @param startAngles a map with start angles when drawing the ring. + */ + public void placeRing(IRing ring, Point2d ringCenter, double bondLength, Map startAngles ) { double radius = this.getNativeRingRadius(ring, bondLength); double addAngle = 2 * Math.PI / ring.getRingSize(); @@ -116,23 +159,8 @@ public void placeRing(IRing ring, Point2d ringCenter, double bondLength) { /* Different ring sizes get different start angles to have * visually correct placement */ int ringSize=ring.getRingSize(); - switch (ringSize) { - case 3: - startAngle=Math.PI*(0.1666667); - break; - case 4: - startAngle=Math.PI*0.25; - break; - case 5: - startAngle=Math.PI*0.3; - break; - case 7: - startAngle=Math.PI*0.07; - break; - case 8: - startAngle=Math.PI*0.125; - break; - } + if (startAngles.get(ringSize) != null) + startAngle = startAngles.get(ringSize); List bonds = ring.getConnectedBondsList(startAtom); /* From 6b787c2fd6df73c8643644fb2364aa2d030776f9 Mon Sep 17 00:00:00 2001 From: Stefan Kuhn Date: Wed, 31 Mar 2010 10:38:47 +0100 Subject: [PATCH 06/21] Atom-Atom-Mapping is now read and written in MDL files. Note the reading until now was into ID field, which is not in line with description of ID field in ChemObject (Returns the identifier (ID) of this object). Also added tests for MDLWriter/Reader/2000Reader. Signed-off-by: Rajarshi Guha --- .../org/openscience/cdk/CDKConstants.java | 2 ++ .../org/openscience/cdk/io/MDLReader.java | 2 +- .../openscience/cdk/io/MDLV2000Reader.java | 2 +- .../org/openscience/cdk/io/MDLWriter.java | 10 ++++++- .../mdl/a-pinene-with-atom-atom-mapping.mol | 26 +++++++++++++++++++ .../org/openscience/cdk/io/MDLReaderTest.java | 15 +++++++++++ .../cdk/io/MDLV2000ReaderTest.java | 12 +++++++++ .../org/openscience/cdk/io/MDLWriterTest.java | 12 +++++++++ 8 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/test/data/mdl/a-pinene-with-atom-atom-mapping.mol diff --git a/src/main/org/openscience/cdk/CDKConstants.java b/src/main/org/openscience/cdk/CDKConstants.java index 0634c696806..3bd62a40c4d 100644 --- a/src/main/org/openscience/cdk/CDKConstants.java +++ b/src/main/org/openscience/cdk/CDKConstants.java @@ -291,6 +291,8 @@ public class CDKConstants { */ public static final String REST_H = "cdk:RestH"; + public static final String ATOM_ATOM_MAPPING = "cdk:AtomAtomMapping"; + /* ************************************** * Some predefined property names for * diff --git a/src/main/org/openscience/cdk/io/MDLReader.java b/src/main/org/openscience/cdk/io/MDLReader.java index e295fc0f764..47847371537 100644 --- a/src/main/org/openscience/cdk/io/MDLReader.java +++ b/src/main/org/openscience/cdk/io/MDLReader.java @@ -465,7 +465,7 @@ private IMolecule readMolecule(IMolecule molecule) throws CDKException { try { int reactionAtomID = Integer.parseInt(reactionAtomIDString); if (reactionAtomID != 0) { - atom.setID(reactionAtomIDString); + atom.setProperty(CDKConstants.ATOM_ATOM_MAPPING, reactionAtomIDString); } } catch (Exception exception) { logger.error("Mapping number ", reactionAtomIDString, " is not an integer."); diff --git a/src/main/org/openscience/cdk/io/MDLV2000Reader.java b/src/main/org/openscience/cdk/io/MDLV2000Reader.java index 65ef0ff26b6..791fd879c33 100644 --- a/src/main/org/openscience/cdk/io/MDLV2000Reader.java +++ b/src/main/org/openscience/cdk/io/MDLV2000Reader.java @@ -545,7 +545,7 @@ private IMolecule readMolecule(IMolecule molecule) throws CDKException { try { int reactionAtomID = Integer.parseInt(reactionAtomIDString); if (reactionAtomID != 0) { - atom.setID(reactionAtomIDString); + atom.setProperty(CDKConstants.ATOM_ATOM_MAPPING, reactionAtomID); } } catch (Exception exception) { logger.error("Mapping number ", reactionAtomIDString, " is not an integer."); diff --git a/src/main/org/openscience/cdk/io/MDLWriter.java b/src/main/org/openscience/cdk/io/MDLWriter.java index a141be9f01a..d043fe92977 100644 --- a/src/main/org/openscience/cdk/io/MDLWriter.java +++ b/src/main/org/openscience/cdk/io/MDLWriter.java @@ -308,7 +308,15 @@ else if(atom.getValency()==0) line += formatMDLInt(15, 3); else line += formatMDLInt(atom.getValency(), 3); - line += " 0 0 0 0 0 0"; + line += " 0 0 0"; + + if (container.getAtom(f).getProperty(CDKConstants.ATOM_ATOM_MAPPING) != null) { + int value = ((Integer)container.getAtom(f).getProperty(CDKConstants.ATOM_ATOM_MAPPING)).intValue(); + line += formatMDLInt(value, 3); + } else { + line += formatMDLInt(0, 3); + } + line += " 0 0"; writer.write(line); writer.newLine(); } diff --git a/src/test/data/mdl/a-pinene-with-atom-atom-mapping.mol b/src/test/data/mdl/a-pinene-with-atom-atom-mapping.mol new file mode 100644 index 00000000000..227e9a019e7 --- /dev/null +++ b/src/test/data/mdl/a-pinene-with-atom-atom-mapping.mol @@ -0,0 +1,26 @@ +a-pinen.mol + ChemDraw08319810042D + + 10 11 0 0 0 0 0 0 0 0 1 V2000 + -2.0500 -1.1000 0.0000 C 0 0 0 0 0 0 0 0 0 1 0 0 + -0.7500 -0.3500 0.0000 C 0 0 0 0 0 0 0 0 0 15 0 0 + -0.5500 -1.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -1.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.7500 -0.3500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1.8100 -1.4100 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.3625 1.1000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2.0500 0.4000 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.9375 1.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.6625 1.8500 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 1 0 0 0 0 + 1 3 1 0 0 0 0 + 3 4 1 0 0 0 0 + 2 5 1 0 0 0 0 + 5 6 2 0 0 0 0 + 4 6 1 0 0 0 0 + 2 7 1 0 0 0 0 + 3 7 1 0 0 0 0 + 5 8 1 0 0 0 0 + 7 9 1 0 0 0 0 + 7 10 1 0 0 0 0 +M END diff --git a/src/test/org/openscience/cdk/io/MDLReaderTest.java b/src/test/org/openscience/cdk/io/MDLReaderTest.java index e7a72860829..7e6117ec7e0 100644 --- a/src/test/org/openscience/cdk/io/MDLReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLReaderTest.java @@ -31,9 +31,11 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import org.openscience.cdk.CDKConstants; import org.openscience.cdk.ChemFile; import org.openscience.cdk.ChemModel; import org.openscience.cdk.ChemObject; +import org.openscience.cdk.DefaultChemObjectBuilder; import org.openscience.cdk.Molecule; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; @@ -205,5 +207,18 @@ public class MDLReaderTest extends SimpleChemObjectReaderTest { Assert.assertEquals(IBond.Stereo.E_OR_Z,mol.getBond(7).getStereo()); Assert.assertEquals(IBond.Stereo.UP_OR_DOWN,mol.getBond(11).getStereo()); } + + @Test public void testReadAtomAtomMapping() throws Exception { + String filename = "data/mdl/a-pinene-with-atom-atom-mapping.mol"; + logger.info("Testing: " + filename); + InputStream ins = this.getClass().getClassLoader().getResourceAsStream(filename); + MDLV2000Reader reader = new MDLV2000Reader(ins); + + IMolecule mol = reader.read(new Molecule()); + Assert.assertNotNull(mol); + Assert.assertEquals(1, ((Integer)mol.getAtom(0).getProperty(CDKConstants.ATOM_ATOM_MAPPING)).intValue()); + Assert.assertEquals(15, ((Integer)mol.getAtom(1).getProperty(CDKConstants.ATOM_ATOM_MAPPING)).intValue()); + Assert.assertNull(mol.getAtom(2).getProperty(CDKConstants.ATOM_ATOM_MAPPING)); + } } diff --git a/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java b/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java index 44c037d2403..a2692786dbe 100644 --- a/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java @@ -772,4 +772,16 @@ private void testShortLinesForMode (IChemObjectReader.Mode mode) throws Exceptio Assert.assertEquals(mol.getAtomCount(), 5); Assert.assertEquals(mol.getBondCount(), 4); } + + @Test public void testReadAtomAtomMapping() throws Exception { + String filename = "data/mdl/a-pinene-with-atom-atom-mapping.mol"; + logger.info("Testing: " + filename); + InputStream ins = this.getClass().getClassLoader().getResourceAsStream(filename); + MDLV2000Reader reader = new MDLV2000Reader(ins); + IMolecule mol = reader.read(new Molecule()); + Assert.assertNotNull(mol); + Assert.assertEquals(1, ((Integer)mol.getAtom(0).getProperty(CDKConstants.ATOM_ATOM_MAPPING)).intValue()); + Assert.assertEquals(15, ((Integer)mol.getAtom(1).getProperty(CDKConstants.ATOM_ATOM_MAPPING)).intValue()); + Assert.assertNull(mol.getAtom(2).getProperty(CDKConstants.ATOM_ATOM_MAPPING)); + } } diff --git a/src/test/org/openscience/cdk/io/MDLWriterTest.java b/src/test/org/openscience/cdk/io/MDLWriterTest.java index f4a0f44a5c6..1c87f86071e 100644 --- a/src/test/org/openscience/cdk/io/MDLWriterTest.java +++ b/src/test/org/openscience/cdk/io/MDLWriterTest.java @@ -120,6 +120,18 @@ public class MDLWriterTest extends ChemObjectIOTest { Assert.assertTrue(output.indexOf("0 0 0 0 0 15 0 0 0 0 0 0") != -1); } + @Test public void testWriteAtomAtomMapping() throws Exception { + StringWriter writer = new StringWriter(); + Molecule molecule = MoleculeFactory.makeAlphaPinene(); + molecule.getAtom(0).setProperty(CDKConstants.ATOM_ATOM_MAPPING,1); + molecule.getAtom(1).setProperty(CDKConstants.ATOM_ATOM_MAPPING,15); + MDLWriter mdlWriter = new MDLWriter(writer); + mdlWriter.write(molecule); + String output = writer.toString(); + Assert.assertTrue(output.indexOf("0 0 0 0 0 0 0 0 0 1 0 0") != -1); + Assert.assertTrue(output.indexOf("0 0 0 0 0 0 0 0 0 15 0 0") != -1); + } + /** * Test for bug #1778479 "MDLWriter writes empty PseudoAtom label string". * When a molecule contains an IPseudoAtom without specifying the atom label From 6ff55baf51313dd57dd2489173c783bee1c5aef4 Mon Sep 17 00:00:00 2001 From: Stefan Kuhn Date: Wed, 27 Jan 2010 11:56:33 +0000 Subject: [PATCH 07/21] The RXNReaders/Writers now all handle Atom-Atom-Mappings. This was only done in the MDLRXNReader till now Signed-off-by: Rajarshi Guha --- src/main/org/openscience/cdk/io/MDLRXNReader.java | 5 +++-- .../org/openscience/cdk/io/MDLRXNV2000Reader.java | 5 +++-- src/main/org/openscience/cdk/io/MDLRXNWriter.java | 8 ++++++++ .../openscience/cdk/io/MDLRXNV2000ReaderTest.java | 15 +++++++++++++++ .../org/openscience/cdk/io/MDLRXNWriterTest.java | 4 ++++ 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/org/openscience/cdk/io/MDLRXNReader.java b/src/main/org/openscience/cdk/io/MDLRXNReader.java index 265180841ae..7d3559ebb6a 100644 --- a/src/main/org/openscience/cdk/io/MDLRXNReader.java +++ b/src/main/org/openscience/cdk/io/MDLRXNReader.java @@ -36,6 +36,7 @@ import java.util.Iterator; import java.util.StringTokenizer; +import org.openscience.cdk.CDKConstants; import org.openscience.cdk.annotations.TestClass; import org.openscience.cdk.annotations.TestMethod; import org.openscience.cdk.exception.CDKException; @@ -410,8 +411,8 @@ private IReaction readReaction(IChemObjectBuilder builder) throws CDKException { for (int j=0; j it = mapping.relatedChemObjects().iterator(); + it.next().setProperty(CDKConstants.ATOM_ATOM_MAPPING, i+1); + it.next().setProperty(CDKConstants.ATOM_ATOM_MAPPING, i+1); + i++; + } writeMoleculeSet(reaction.getReactants()); writeMoleculeSet(reaction.getProducts()); diff --git a/src/test/org/openscience/cdk/io/MDLRXNV2000ReaderTest.java b/src/test/org/openscience/cdk/io/MDLRXNV2000ReaderTest.java index 53ac9fd64cc..55124cc5b01 100644 --- a/src/test/org/openscience/cdk/io/MDLRXNV2000ReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLRXNV2000ReaderTest.java @@ -35,6 +35,7 @@ import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IReaction; import org.openscience.cdk.io.IChemObjectReader.Mode; +import org.openscience.cdk.nonotify.NNReaction; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -113,4 +114,18 @@ public class MDLRXNV2000ReaderTest extends SimpleChemObjectReaderTest { } + @Test public void testReadMapping() throws Exception { + String filename2 = "data/mdl/mappingTest.rxn"; + logger.info("Testing: " + filename2); + InputStream ins2 = this.getClass().getClassLoader().getResourceAsStream(filename2); + MDLRXNV2000Reader reader2 = new MDLRXNV2000Reader(ins2); + IReaction reaction2 = new NNReaction(); + reaction2 = (IReaction)reader2.read(reaction2); + reader2.close(); + + Assert.assertNotNull(reaction2); + java.util.Iterator maps = reaction2.mappings().iterator(); + maps.next(); + Assert.assertTrue(maps.hasNext()); + } } diff --git a/src/test/org/openscience/cdk/io/MDLRXNWriterTest.java b/src/test/org/openscience/cdk/io/MDLRXNWriterTest.java index 439a0b7442e..ce6e35f6e8b 100644 --- a/src/test/org/openscience/cdk/io/MDLRXNWriterTest.java +++ b/src/test/org/openscience/cdk/io/MDLRXNWriterTest.java @@ -33,6 +33,7 @@ import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import org.openscience.cdk.CDKConstants; import org.openscience.cdk.DefaultChemObjectBuilder; import org.openscience.cdk.Reaction; import org.openscience.cdk.interfaces.IAtom; @@ -42,6 +43,7 @@ import org.openscience.cdk.interfaces.IReaction; import org.openscience.cdk.interfaces.IReactionSet; import org.openscience.cdk.nonotify.NNReactionSet; +import org.openscience.cdk.Mapping; /** * TestCase for the writer MDL rxn files using one test file. @@ -75,6 +77,7 @@ public class MDLRXNWriterTest extends ChemObjectIOTest { IMolecule water = builder.newInstance(IMolecule.class); water.addAtom(builder.newInstance(IAtom.class,"O")); reaction.addProduct(water); + reaction.addMapping(new Mapping(hydroxide.getAtom(0),water.getAtom(0))); // now serialize to MDL RXN StringWriter writer = new StringWriter(10000); @@ -94,6 +97,7 @@ public class MDLRXNWriterTest extends ChemObjectIOTest { Assert.assertEquals(2, reaction2.getReactantCount()); Assert.assertEquals(1, reaction2.getProductCount()); + Assert.assertEquals(1, reaction2.getMappingCount()); } @Test public void testReactionSet_1() throws Exception { From 42b64e1341ab52d7251d75b7485a269b9c2798bd Mon Sep 17 00:00:00 2001 From: Stefan Kuhn Date: Fri, 29 Jan 2010 12:23:40 +0000 Subject: [PATCH 08/21] I made sure the MDLV2000Reader considers 0,0,0 coordinates in files with a single atom as 2d and 3d coordinates. The MDLReader does not handle the 0,0,0 case explicitly, so I just added a test for 2d. It might be better to have uniforma handling, but I will file a bug report for that. Signed-off-by: Rajarshi Guha --- src/main/org/openscience/cdk/io/MDLV2000Reader.java | 8 ++++++-- src/test/org/openscience/cdk/io/MDLReaderTest.java | 11 +++++++++++ .../org/openscience/cdk/io/MDLV2000ReaderTest.java | 12 ++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/main/org/openscience/cdk/io/MDLV2000Reader.java b/src/main/org/openscience/cdk/io/MDLV2000Reader.java index 791fd879c33..c8625292139 100644 --- a/src/main/org/openscience/cdk/io/MDLV2000Reader.java +++ b/src/main/org/openscience/cdk/io/MDLV2000Reader.java @@ -573,8 +573,12 @@ private IMolecule readMolecule(IMolecule molecule) throws CDKException { // convert to 2D, if totalZ == 0 if (totalX == 0.0 && totalY == 0.0 && totalZ == 0.0) { logger.info("All coordinates are 0.0"); - for (IAtom atomToUpdate : molecule.atoms()) { - atomToUpdate.setPoint3d(null); + if (molecule.getAtomCount()==1){ + molecule.getAtom(0).setPoint2d(new Point2d(x,y)); + }else{ + for (IAtom atomToUpdate : molecule.atoms()) { + atomToUpdate.setPoint3d(null); + } } } else if (totalZ == 0.0 && !forceReadAs3DCoords.isSet()) { logger.info("Total 3D Z is 0.0, interpreting it as a 2D structure"); diff --git a/src/test/org/openscience/cdk/io/MDLReaderTest.java b/src/test/org/openscience/cdk/io/MDLReaderTest.java index 7e6117ec7e0..48ff5936a4b 100644 --- a/src/test/org/openscience/cdk/io/MDLReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLReaderTest.java @@ -37,6 +37,7 @@ import org.openscience.cdk.ChemObject; import org.openscience.cdk.DefaultChemObjectBuilder; import org.openscience.cdk.Molecule; +import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IBond; @@ -221,4 +222,14 @@ public class MDLReaderTest extends SimpleChemObjectReaderTest { Assert.assertEquals(15, ((Integer)mol.getAtom(1).getProperty(CDKConstants.ATOM_ATOM_MAPPING)).intValue()); Assert.assertNull(mol.getAtom(2).getProperty(CDKConstants.ATOM_ATOM_MAPPING)); } + + @Test(expected=AssertionError.class) + public void testHas2DCoordinates_With000() throws CDKException { + String filenameMol = "data/mdl/with000coordinate.mol"; + InputStream ins = this.getClass().getClassLoader().getResourceAsStream(filenameMol); + Molecule molOne=null; + MDLReader reader = new MDLReader(ins, Mode.RELAXED); + molOne = (Molecule)reader.read(new Molecule()); + Assert.assertNotNull(molOne.getAtom(0).getPoint2d()); + } } diff --git a/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java b/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java index a2692786dbe..ebe95e00566 100644 --- a/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLV2000ReaderTest.java @@ -784,4 +784,16 @@ private void testShortLinesForMode (IChemObjectReader.Mode mode) throws Exceptio Assert.assertEquals(15, ((Integer)mol.getAtom(1).getProperty(CDKConstants.ATOM_ATOM_MAPPING)).intValue()); Assert.assertNull(mol.getAtom(2).getProperty(CDKConstants.ATOM_ATOM_MAPPING)); } + + @Test public void testHas2DCoordinates_With000() throws CDKException { + String filenameMol = "data/mdl/with000coordinate.mol"; + InputStream ins = this.getClass().getClassLoader().getResourceAsStream(filenameMol); + Molecule molOne=null; + MDLV2000Reader reader = new MDLV2000Reader(ins, Mode.STRICT); + molOne = (Molecule)reader.read(new Molecule()); + System.out.println(molOne.getAtomCount()); + Assert.assertNotNull(molOne.getAtom(0).getPoint2d()); + Assert.assertNotNull(molOne.getAtom(0).getPoint3d()); + } + } From a1e1f1b78f2fd722a446cb1c0478434844005daa Mon Sep 17 00:00:00 2001 From: Egon Willighagen Date: Fri, 14 May 2010 13:59:39 +0200 Subject: [PATCH 09/21] Added JavaDoc testing to the QA task; removed module-uptodate which checked if the module was already compiled causing the target to be skipped --- build.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build.xml b/build.xml index 1d1eb02cb4f..fc40db6ac8c 100644 --- a/build.xml +++ b/build.xml @@ -293,14 +293,16 @@ depends="init, check, runDoclet"/> + depends="check, dist.init"> + + + From ee5e0a21c307bfc9513cc3b2367e9c96517d80fb Mon Sep 17 00:00:00 2001 From: Rajarshi Guha Date: Sat, 15 May 2010 15:55:42 -0400 Subject: [PATCH 10/21] Minor fix to build.xml to ensure that SMSD code gets included in the large jar file --- build.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.xml b/build.xml index 1d1eb02cb4f..28b03e3e805 100644 --- a/build.xml +++ b/build.xml @@ -619,6 +619,7 @@ + @@ -667,6 +668,7 @@ + From be1b70ac152061560fe831d2cae5aeec01793913 Mon Sep 17 00:00:00 2001 From: Egon Willighagen Date: Mon, 3 May 2010 11:40:09 +0200 Subject: [PATCH 11/21] Patch to generalize the stereo chemistry handling. * introducing IStereoElement, a super class indicating some form of molecular stereo chemistry * IAtomParity extends IStereoElement * IAtomContainer no longer has get/set of IAtomParity * IAtomContainer now takes a list of IStereoElement's * Added the helper method AtomContainerManipulator.getAtomParity(IAtomContainer, IAtom) to ease transition Signed-off-by: Rajarshi Guha --- src/META-INF/test-interfaces.cdkdepends | 1 + .../org/openscience/cdk/AtomContainer.java | 55 +++++++------------ .../openscience/cdk/debug/DebugAminoAcid.java | 16 +++--- .../cdk/debug/DebugAtomContainer.java | 20 +++---- .../cdk/debug/DebugBioPolymer.java | 20 +++---- .../openscience/cdk/debug/DebugCrystal.java | 20 +++---- .../openscience/cdk/debug/DebugMolecule.java | 20 +++---- .../openscience/cdk/debug/DebugMonomer.java | 20 +++---- .../openscience/cdk/debug/DebugPolymer.java | 20 +++---- .../org/openscience/cdk/debug/DebugRing.java | 20 +++---- .../openscience/cdk/debug/DebugStrand.java | 20 +++---- .../openscience/cdk/inchi/InChIGenerator.java | 34 +++++++++--- .../cdk/inchi/InChIToStructure.java | 2 +- .../cdk/interfaces/IAtomContainer.java | 26 ++++----- .../cdk/interfaces/IAtomParity.java | 9 +-- .../cdk/interfaces/IStereoElement.java | 43 +++++++++++++++ .../cdk/normalize/SMSDNormalizer.java | 6 +- .../tools/ExtAtomContainerManipulator.java | 6 +- .../manipulator/AtomContainerManipulator.java | 21 +++++++ .../interfaces/AbstractAtomContainerTest.java | 21 ++++--- .../AtomContainerManipulatorTest.java | 29 +++++++++- 21 files changed, 258 insertions(+), 171 deletions(-) create mode 100644 src/main/org/openscience/cdk/interfaces/IStereoElement.java diff --git a/src/META-INF/test-interfaces.cdkdepends b/src/META-INF/test-interfaces.cdkdepends index 40477b75c6e..fa49fb2f100 100644 --- a/src/META-INF/test-interfaces.cdkdepends +++ b/src/META-INF/test-interfaces.cdkdepends @@ -2,4 +2,5 @@ cdk-annotation.jar cdk-interfaces.jar cdk-core.jar cdk-diff.jar +cdk-standard.jar cdk-test.jar diff --git a/src/main/org/openscience/cdk/AtomContainer.java b/src/main/org/openscience/cdk/AtomContainer.java index 6febccdc28b..0c41a2b672e 100644 --- a/src/main/org/openscience/cdk/AtomContainer.java +++ b/src/main/org/openscience/cdk/AtomContainer.java @@ -25,20 +25,18 @@ import java.io.Serializable; import java.util.ArrayList; -import java.util.Hashtable; import java.util.Iterator; import java.util.List; -import java.util.Map; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IBond.Order; /** @@ -118,10 +116,10 @@ public class AtomContainer extends ChemObject */ protected ISingleElectron[] singleElectrons; - /** - * Internal list of atom parities. - */ - protected Map atomParities; + /** + * Internal list of atom parities. + */ + protected List stereoElements; /** @@ -150,7 +148,7 @@ public AtomContainer(IAtomContainer container) this.lonePairs = new ILonePair[this.lonePairCount]; this.singleElectrons = new ISingleElectron[this.singleElectronCount]; - atomParities = new Hashtable(atomCount/2); + stereoElements = new ArrayList(atomCount/2); for (int f = 0; f < container.getAtomCount(); f++) { atoms[f] = container.getAtom(f); @@ -192,33 +190,22 @@ public AtomContainer(int atomCount, int bondCount, int lpCount, int seCount) bonds = new IBond[bondCount]; lonePairs = new ILonePair[lpCount]; singleElectrons = new ISingleElectron[seCount]; - atomParities = new Hashtable(atomCount/2); + stereoElements = new ArrayList(atomCount/2); } - /** - * Adds an AtomParity to this container. If a parity is already given for the - * affected Atom, it is overwritten. - * - * @param parity The new AtomParity for this container - * @see #getAtomParity - */ - public void addAtomParity(IAtomParity parity) { - atomParities.put(parity.getAtom(), parity); + /** {@inheritDoc} */ + public void addStereoElement(IStereoElement element) { + stereoElements.add(element); } - /** - * Returns the atom parity for the given Atom. If no parity is associated - * with the given Atom, it returns null. - * - * @param atom Atom for which the parity must be returned - * @return The AtomParity for the given Atom, or null if that Atom does - * not have an associated AtomParity - * @see #addAtomParity - */ - public IAtomParity getAtomParity(IAtom atom) { - return atomParities.get(atom); + /** {@inheritDoc} */ + public Iterable stereoElements() { + return new Iterable() { + public Iterator iterator() { + return stereoElements.iterator(); + } + }; } - /** * Sets the array of atoms of this AtomContainer. * @@ -1568,10 +1555,10 @@ public String toString() stringContent.append(", ").append(getSingleElectron(i).toString()); } } - if (atomParities.size() > 0) { - stringContent.append(", AP:[#").append(atomParities.size()); - for (IAtomParity iAtomParity : atomParities.values()) { - stringContent.append(", ").append(iAtomParity.toString()); + if (stereoElements.size() > 0) { + stringContent.append(", ST:[#").append(stereoElements.size()); + for (IStereoElement elements : stereoElements) { + stringContent.append(", ").append(elements.toString()); } stringContent.append(']'); } diff --git a/src/main/org/openscience/cdk/debug/DebugAminoAcid.java b/src/main/org/openscience/cdk/debug/DebugAminoAcid.java index 9f2144b3707..ba635471014 100644 --- a/src/main/org/openscience/cdk/debug/DebugAminoAcid.java +++ b/src/main/org/openscience/cdk/debug/DebugAminoAcid.java @@ -27,14 +27,14 @@ import org.openscience.cdk.interfaces.IAminoAcid; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -54,14 +54,14 @@ public class DebugAminoAcid extends AminoAcid ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugAtomContainer.class); - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); } public void setAtoms(IAtom[] atoms) { diff --git a/src/main/org/openscience/cdk/debug/DebugAtomContainer.java b/src/main/org/openscience/cdk/debug/DebugAtomContainer.java index 8a961ddb326..541f4a8c36e 100644 --- a/src/main/org/openscience/cdk/debug/DebugAtomContainer.java +++ b/src/main/org/openscience/cdk/debug/DebugAtomContainer.java @@ -26,14 +26,14 @@ import org.openscience.cdk.AtomContainer; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -65,15 +65,15 @@ public DebugAtomContainer(IAtomContainer container) { super(container); } - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); - } + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); + } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); - } + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); + } public void setAtoms(IAtom[] atoms) { logger.debug("Setting atoms: ", atoms.length); diff --git a/src/main/org/openscience/cdk/debug/DebugBioPolymer.java b/src/main/org/openscience/cdk/debug/DebugBioPolymer.java index 2ab866e36cc..066106648b2 100644 --- a/src/main/org/openscience/cdk/debug/DebugBioPolymer.java +++ b/src/main/org/openscience/cdk/debug/DebugBioPolymer.java @@ -27,16 +27,16 @@ import org.openscience.cdk.BioPolymer; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBioPolymer; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; import org.openscience.cdk.interfaces.IMonomer; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IStrand; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; @@ -57,15 +57,15 @@ public class DebugBioPolymer extends BioPolymer ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugAtomContainer.class); - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); - } + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); + } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); - } + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); + } public void setAtoms(IAtom[] atoms) { logger.debug("Setting atoms: ", atoms.length); diff --git a/src/main/org/openscience/cdk/debug/DebugCrystal.java b/src/main/org/openscience/cdk/debug/DebugCrystal.java index 3e5642de865..7422ad901ea 100644 --- a/src/main/org/openscience/cdk/debug/DebugCrystal.java +++ b/src/main/org/openscience/cdk/debug/DebugCrystal.java @@ -28,15 +28,15 @@ import org.openscience.cdk.Crystal; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.ICrystal; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -64,15 +64,15 @@ public DebugCrystal(IAtomContainer container) { super(container); } - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); - } + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); + } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); - } + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); + } public void setAtoms(IAtom[] atoms) { logger.debug("Setting atoms: ", atoms.length); diff --git a/src/main/org/openscience/cdk/debug/DebugMolecule.java b/src/main/org/openscience/cdk/debug/DebugMolecule.java index b83cd20353e..2804bad4613 100644 --- a/src/main/org/openscience/cdk/debug/DebugMolecule.java +++ b/src/main/org/openscience/cdk/debug/DebugMolecule.java @@ -26,15 +26,15 @@ import org.openscience.cdk.Molecule; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; import org.openscience.cdk.interfaces.IMolecule; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -66,15 +66,15 @@ public DebugMolecule(IAtomContainer container) { super(container); } - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); - } + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); + } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); - } + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); + } public void setAtoms(IAtom[] atoms) { logger.debug("Setting atoms: ", atoms.length); diff --git a/src/main/org/openscience/cdk/debug/DebugMonomer.java b/src/main/org/openscience/cdk/debug/DebugMonomer.java index 07fb6cf945c..8de3174ebba 100644 --- a/src/main/org/openscience/cdk/debug/DebugMonomer.java +++ b/src/main/org/openscience/cdk/debug/DebugMonomer.java @@ -26,15 +26,15 @@ import org.openscience.cdk.Monomer; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; import org.openscience.cdk.interfaces.IMonomer; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -54,15 +54,15 @@ public class DebugMonomer extends Monomer ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugAtomContainer.class); - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); - } + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); + } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); - } + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); + } public void setAtoms(IAtom[] atoms) { logger.debug("Setting atoms: ", atoms.length); diff --git a/src/main/org/openscience/cdk/debug/DebugPolymer.java b/src/main/org/openscience/cdk/debug/DebugPolymer.java index a519eda92a3..d7ebe25b951 100644 --- a/src/main/org/openscience/cdk/debug/DebugPolymer.java +++ b/src/main/org/openscience/cdk/debug/DebugPolymer.java @@ -27,16 +27,16 @@ import org.openscience.cdk.Polymer; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; import org.openscience.cdk.interfaces.IMonomer; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IPolymer; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -56,15 +56,15 @@ public class DebugPolymer extends Polymer ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugAtomContainer.class); - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); - } + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); + } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); - } + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); + } public void setAtoms(IAtom[] atoms) { logger.debug("Setting atoms: ", atoms.length); diff --git a/src/main/org/openscience/cdk/debug/DebugRing.java b/src/main/org/openscience/cdk/debug/DebugRing.java index 8c89b17e656..ace6009f635 100644 --- a/src/main/org/openscience/cdk/debug/DebugRing.java +++ b/src/main/org/openscience/cdk/debug/DebugRing.java @@ -27,15 +27,15 @@ import org.openscience.cdk.Ring; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IRing; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -79,15 +79,15 @@ public DebugRing(IAtomContainer container) { super(container); } - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); - } + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); + } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); - } + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); + } public void setAtoms(IAtom[] atoms) { logger.debug("Setting atoms: ", atoms.length); diff --git a/src/main/org/openscience/cdk/debug/DebugStrand.java b/src/main/org/openscience/cdk/debug/DebugStrand.java index d3117453e2a..6f7564c7f00 100644 --- a/src/main/org/openscience/cdk/debug/DebugStrand.java +++ b/src/main/org/openscience/cdk/debug/DebugStrand.java @@ -27,15 +27,15 @@ import org.openscience.cdk.Strand; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IChemObjectChangeEvent; import org.openscience.cdk.interfaces.IChemObjectListener; import org.openscience.cdk.interfaces.IElectronContainer; import org.openscience.cdk.interfaces.ILonePair; import org.openscience.cdk.interfaces.IMonomer; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.ISingleElectron; +import org.openscience.cdk.interfaces.IStereoElement; import org.openscience.cdk.interfaces.IStrand; import org.openscience.cdk.interfaces.IBond.Order; import org.openscience.cdk.tools.ILoggingTool; @@ -56,15 +56,15 @@ public class DebugStrand extends Strand ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugAtomContainer.class); - public void addAtomParity(IAtomParity parity) { - logger.debug("Adding atom parity: ", parity); - super.addAtomParity(parity); - } + public void addStereoElement(IStereoElement parity) { + logger.debug("Adding stereo element: ", parity); + super.addStereoElement(parity); + } - public IAtomParity getAtomParity(IAtom atom) { - logger.debug("Getting atom parity: ", atom); - return super.getAtomParity(atom); - } + public Iterable stereoElements() { + logger.debug("Getting stereo elements."); + return super.stereoElements(); + } public void setAtoms(IAtom[] atoms) { logger.debug("Setting atoms: ", atoms.length); diff --git a/src/main/org/openscience/cdk/inchi/InChIGenerator.java b/src/main/org/openscience/cdk/inchi/InChIGenerator.java index 49f54437088..fb731fe09b8 100644 --- a/src/main/org/openscience/cdk/inchi/InChIGenerator.java +++ b/src/main/org/openscience/cdk/inchi/InChIGenerator.java @@ -20,7 +20,29 @@ */ package org.openscience.cdk.inchi; -import net.sf.jniinchi.*; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.vecmath.Point2d; +import javax.vecmath.Point3d; + +import net.sf.jniinchi.INCHI_BOND_STEREO; +import net.sf.jniinchi.INCHI_BOND_TYPE; +import net.sf.jniinchi.INCHI_KEY; +import net.sf.jniinchi.INCHI_PARITY; +import net.sf.jniinchi.INCHI_RADICAL; +import net.sf.jniinchi.INCHI_RET; +import net.sf.jniinchi.INCHI_STEREOTYPE; +import net.sf.jniinchi.JniInchiAtom; +import net.sf.jniinchi.JniInchiBond; +import net.sf.jniinchi.JniInchiException; +import net.sf.jniinchi.JniInchiInput; +import net.sf.jniinchi.JniInchiOutput; +import net.sf.jniinchi.JniInchiOutputKey; +import net.sf.jniinchi.JniInchiStereo0D; +import net.sf.jniinchi.JniInchiWrapper; import org.openscience.cdk.CDKConstants; import org.openscience.cdk.annotations.TestClass; @@ -31,13 +53,7 @@ import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IBond; - -import javax.vecmath.Point2d; -import javax.vecmath.Point3d; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import org.openscience.cdk.tools.manipulator.AtomContainerManipulator; /** *

This class generates the IUPAC International Chemical Identifier (InChI) for @@ -326,7 +342,7 @@ else if (stereo == CDKConstants.UNSET) { atoms = atomContainer.atoms().iterator(); while (atoms.hasNext()) { IAtom atom = atoms.next(); - IAtomParity parity = atomContainer.getAtomParity(atom); + IAtomParity parity = AtomContainerManipulator.getAtomParity(atomContainer, atom); if (parity != null) { IAtom[] surroundingAtoms = parity.getSurroundingAtoms(); int sign = parity.getParity(); diff --git a/src/main/org/openscience/cdk/inchi/InChIToStructure.java b/src/main/org/openscience/cdk/inchi/InChIToStructure.java index 965d8c3cabf..fdf2c923946 100644 --- a/src/main/org/openscience/cdk/inchi/InChIToStructure.java +++ b/src/main/org/openscience/cdk/inchi/InChIToStructure.java @@ -253,7 +253,7 @@ else if (stereo == INCHI_BOND_STEREO.SINGLE_1EITHER } IAtomParity parity = builder.newInstance(IAtomParity.class,atC, at0, at1, at2, at3, sign); - molecule.addAtomParity(parity); + molecule.addStereoElement(parity); } else { // TODO - other types of atom parity - double bond, etc } diff --git a/src/main/org/openscience/cdk/interfaces/IAtomContainer.java b/src/main/org/openscience/cdk/interfaces/IAtomContainer.java index fac22ef11a4..f06a258e7ed 100644 --- a/src/main/org/openscience/cdk/interfaces/IAtomContainer.java +++ b/src/main/org/openscience/cdk/interfaces/IAtomContainer.java @@ -1,6 +1,4 @@ -/* $Revision$ $Author$ $Date$ - * - * Copyright (C) 2006-2007 Egon Willighagen +/* Copyright (C) 2006-2007,2010 Egon Willighagen * * Contact: cdk-devel@lists.sourceforge.net * @@ -49,25 +47,21 @@ public interface IAtomContainer extends IChemObject, IChemObjectListener { /** - * Adds an AtomParity to this container. If a parity is already given for the - * affected Atom, it is overwritten. + * Adds a stereo element to this container. * - * @param parity The new AtomParity for this container - * @see #getAtomParity + * @param element The new {@link IStereoElement} for this container + * @see #stereoElements() */ - public void addAtomParity(IAtomParity parity); + public void addStereoElement(IStereoElement element); /** - * Returns the atom parity for the given Atom. If no parity is associated - * with the given Atom, it returns null. + * Returns the stereo elements defined for this atom container. * - * @param atom Atom for which the parity must be returned - * @return The AtomParity for the given Atom, or null if that Atom does - * not have an associated AtomParity - * @see #addAtomParity + * @return An {@link Iterable} of {@link IStereoElement}s. + * @see #addStereoElement(IStereoElement) */ - public IAtomParity getAtomParity(IAtom atom); - + public Iterable stereoElements(); + /** * Sets the array of atoms of this AtomContainer. * diff --git a/src/main/org/openscience/cdk/interfaces/IAtomParity.java b/src/main/org/openscience/cdk/interfaces/IAtomParity.java index c5ae311595c..4d045f1e156 100644 --- a/src/main/org/openscience/cdk/interfaces/IAtomParity.java +++ b/src/main/org/openscience/cdk/interfaces/IAtomParity.java @@ -1,9 +1,4 @@ -/* $RCSfile$ - * $Author$ - * $Date$ - * $Revision$ - * - * Copyright (C) 2006-2007 Egon Willighagen +/* Copyright (C) 2006-2007 Egon Willighagen * * Contact: cdk-devel@lists.sourceforge.net * @@ -39,7 +34,7 @@ * @cdk.keyword atom parity * @cdk.keyword stereochemistry */ -public interface IAtomParity extends ICDKObject { +public interface IAtomParity extends IStereoElement { /** * Returns the atom for which this parity is defined. diff --git a/src/main/org/openscience/cdk/interfaces/IStereoElement.java b/src/main/org/openscience/cdk/interfaces/IStereoElement.java new file mode 100644 index 00000000000..3c1205b6b84 --- /dev/null +++ b/src/main/org/openscience/cdk/interfaces/IStereoElement.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2010 Egon Willighagen + * + * Contact: cdk-devel@lists.sourceforge.net + * + * This program 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. + * All we ask is that proper credit is given for our work, which includes + * - but is not limited to - adding the above copyright notice to the beginning + * of your source code files, and to any copyright notice that you may distribute + * with programs based on this work. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ +package org.openscience.cdk.interfaces; + +/** + * Represents the concept of a stereo element in the molecule. Stereo elements can be + * that of quadrivalent atoms, cis/trans isomerism around double bonds, but also include + * axial and helical stereochemistry. + * + * @cdk.module interfaces + * @cdk.githash + * + * @author egonw + * @cdk.keyword stereochemistry + */ +public interface IStereoElement extends ICDKObject { + +} + + + + + diff --git a/src/main/org/openscience/cdk/normalize/SMSDNormalizer.java b/src/main/org/openscience/cdk/normalize/SMSDNormalizer.java index d1c22cbe386..ecdd01fb5ce 100644 --- a/src/main/org/openscience/cdk/normalize/SMSDNormalizer.java +++ b/src/main/org/openscience/cdk/normalize/SMSDNormalizer.java @@ -509,9 +509,9 @@ private static void setStereoParity(IAtomContainer container, int index, IAtom[] } private static void setAtomParity(IAtomContainer container, int index, IAtomContainer newAtomContainer) { - if (container.getAtomParity(container.getAtom(index)) != null) { - IAtomParity atomParity = container.getAtomParity(container.getAtom(index)); - newAtomContainer.addAtomParity(atomParity); + IAtomParity parity = AtomContainerManipulator.getAtomParity(container, container.getAtom(index)); + if (parity != null) { + newAtomContainer.addStereoElement(parity); } } } diff --git a/src/main/org/openscience/cdk/smsd/tools/ExtAtomContainerManipulator.java b/src/main/org/openscience/cdk/smsd/tools/ExtAtomContainerManipulator.java index 7e6f3d43bd6..1b27c1b302f 100644 --- a/src/main/org/openscience/cdk/smsd/tools/ExtAtomContainerManipulator.java +++ b/src/main/org/openscience/cdk/smsd/tools/ExtAtomContainerManipulator.java @@ -512,9 +512,9 @@ private static void setStereoParity(IAtomContainer container, int index, IAtom[] } private static void setAtomParity(IAtomContainer container, int index, IAtomContainer newAtomContainer) { - if (container.getAtomParity(container.getAtom(index)) != null) { - IAtomParity atomParity = container.getAtomParity(container.getAtom(index)); - newAtomContainer.addAtomParity(atomParity); + IAtomParity parity = AtomContainerManipulator.getAtomParity(container, container.getAtom(index)); + if (parity != null) { + newAtomContainer.addStereoElement(parity); } } } diff --git a/src/main/org/openscience/cdk/tools/manipulator/AtomContainerManipulator.java b/src/main/org/openscience/cdk/tools/manipulator/AtomContainerManipulator.java index 8c2ae74b8c7..39b83e74247 100644 --- a/src/main/org/openscience/cdk/tools/manipulator/AtomContainerManipulator.java +++ b/src/main/org/openscience/cdk/tools/manipulator/AtomContainerManipulator.java @@ -41,6 +41,7 @@ import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; +import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IAtomType; import org.openscience.cdk.interfaces.IBond; import org.openscience.cdk.interfaces.IElectronContainer; @@ -49,6 +50,7 @@ import org.openscience.cdk.interfaces.IMolecularFormula; import org.openscience.cdk.interfaces.IMolecule; import org.openscience.cdk.interfaces.IPseudoAtom; +import org.openscience.cdk.interfaces.IStereoElement; /** * Class with convenience methods that provide methods to manipulate @@ -831,5 +833,24 @@ public static double getBondOrderSum(IAtomContainer container, IAtom atom) { } return count; } + + /** + * Helper methods that works through the stereo elements of the given atom container + * and returns if the atom parity for the given atom, if one is defined. + * + * @param container {@link IAtomContainer} to search the {@link IAtomParity} for. + * @param atom {@link IAtom} for which the {@link IAtomParity} must be defined. + * @return the {@link IAtomParity} or null if none is define for the given atom. + */ + @TestMethod("testGetAtomParity") + public static IAtomParity getAtomParity(IAtomContainer container, IAtom atom) { + for (IStereoElement element : container.stereoElements()) { + if (element instanceof IAtomParity) { + IAtomParity parity = (IAtomParity)element; + if (parity.getAtom() == atom) return parity; + } + } + return null; + } } diff --git a/src/test/org/openscience/cdk/interfaces/AbstractAtomContainerTest.java b/src/test/org/openscience/cdk/interfaces/AbstractAtomContainerTest.java index 8c4ea5a3148..3afedcb5d65 100644 --- a/src/test/org/openscience/cdk/interfaces/AbstractAtomContainerTest.java +++ b/src/test/org/openscience/cdk/interfaces/AbstractAtomContainerTest.java @@ -1666,7 +1666,7 @@ public abstract class AbstractAtomContainerTest extends AbstractChemObjectTest { Assert.assertEquals(1, acetone.getConnectedBondsCount(3)); } - @Test public void testGetAtomParity_IAtom() { + @Test public void testStereoElements() { IAtomContainer container = (IAtomContainer)newChemObject(); IAtom carbon = container.getBuilder().newInstance(IAtom.class,"C"); carbon.setID("central"); @@ -1682,10 +1682,15 @@ public abstract class AbstractAtomContainerTest extends AbstractChemObjectTest { IAtomParity parity = container.getBuilder().newInstance( IAtomParity.class, carbon, carbon1, carbon2, carbon3, carbon4, parityInt ); - container.addAtomParity(parity); - org.openscience.cdk.interfaces.IAtomParity copy = container.getAtomParity(carbon); - Assert.assertNotNull(copy); - Assert.assertEquals(parity, copy); + container.addStereoElement(parity); + + Iterator stereoElements = container.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement element = stereoElements.next(); + Assert.assertNotNull(element); + Assert.assertTrue(element instanceof IAtomParity); + Assert.assertEquals(carbon, ((IAtomParity)element).getAtom()); + Assert.assertFalse(stereoElements.hasNext()); } /** Test for RFC #9 */ @@ -1727,9 +1732,9 @@ private ChemObjectListenerImpl() { changed = false; } } - - @Test public void testAddAtomParity_IAtomParity() { - testGetAtomParity_IAtom(); + + @Test public void testAddStereoElement_IStereoElement() { + testStereoElements(); } @Test public void testGetConnectedSingleElectronsCount_IAtom() { diff --git a/src/test/org/openscience/cdk/tools/manipulator/AtomContainerManipulatorTest.java b/src/test/org/openscience/cdk/tools/manipulator/AtomContainerManipulatorTest.java index e47095fea30..acda41f2957 100644 --- a/src/test/org/openscience/cdk/tools/manipulator/AtomContainerManipulatorTest.java +++ b/src/test/org/openscience/cdk/tools/manipulator/AtomContainerManipulatorTest.java @@ -37,18 +37,19 @@ import org.openscience.cdk.CDKConstants; import org.openscience.cdk.CDKTestCase; import org.openscience.cdk.ChemFile; -import org.openscience.cdk.Molecule; import org.openscience.cdk.DefaultChemObjectBuilder; +import org.openscience.cdk.Molecule; import org.openscience.cdk.config.IsotopeFactory; import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.exception.InvalidSmilesException; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; +import org.openscience.cdk.interfaces.IAtomParity; import org.openscience.cdk.interfaces.IAtomType; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IElement; import org.openscience.cdk.interfaces.IMolecule; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.io.ISimpleChemObjectReader; import org.openscience.cdk.io.MDLV2000Reader; import org.openscience.cdk.isomorphism.UniversalIsomorphismTester; @@ -788,6 +789,30 @@ public void testBondOrderSum() throws InvalidSmilesException { Assert.assertEquals(1.0, bosum, 0.001); } + + @Test + public void testGetAtomParity() { + IAtomContainer container = new AtomContainer(); + IAtom carbon = container.getBuilder().newInstance(IAtom.class,"C"); + carbon.setID("central"); + IAtom carbon1 = container.getBuilder().newInstance(IAtom.class,"C"); + carbon1.setID("c1"); + IAtom carbon2 = container.getBuilder().newInstance(IAtom.class,"C"); + carbon2.setID("c2"); + IAtom carbon3 = container.getBuilder().newInstance(IAtom.class,"C"); + carbon3.setID("c3"); + IAtom carbon4 = container.getBuilder().newInstance(IAtom.class,"C"); + carbon4.setID("c4"); + int parityInt = 1; + IAtomParity parity = container.getBuilder().newInstance( + IAtomParity.class, carbon, carbon1, carbon2, carbon3, carbon4, parityInt + ); + container.addStereoElement(parity); + + parity = AtomContainerManipulator.getAtomParity(container, carbon); + Assert.assertNotNull(parity); + Assert.assertEquals(carbon, parity.getAtom()); + } } From 9abead553dda13068b975af7ef1e0cf263f05ca2 Mon Sep 17 00:00:00 2001 From: Egon Willighagen Date: Mon, 3 May 2010 21:41:12 +0200 Subject: [PATCH 12/21] Implemented stereo chemistry for atoms with four ligands Signed-off-by: Rajarshi Guha --- .../cdk/interfaces/ILigancyFourChirality.java | 65 ++++++++++ .../cdk/stereo/LigancyFourChirality.java | 83 ++++++++++++ .../cdk/modulesuites/MdataTests.java | 3 + .../cdk/stereo/LigancyFourChiralityTest.java | 118 ++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 src/main/org/openscience/cdk/interfaces/ILigancyFourChirality.java create mode 100644 src/main/org/openscience/cdk/stereo/LigancyFourChirality.java create mode 100644 src/test/org/openscience/cdk/stereo/LigancyFourChiralityTest.java diff --git a/src/main/org/openscience/cdk/interfaces/ILigancyFourChirality.java b/src/main/org/openscience/cdk/interfaces/ILigancyFourChirality.java new file mode 100644 index 00000000000..71338abc4f0 --- /dev/null +++ b/src/main/org/openscience/cdk/interfaces/ILigancyFourChirality.java @@ -0,0 +1,65 @@ +/* Copyright (C) 2010 Egon Willighagen + * + * Contact: cdk-devel@lists.sourceforge.net + * + * This program 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. + * All we ask is that proper credit is given for our work, which includes + * - but is not limited to - adding the above copyright notice to the beginning + * of your source code files, and to any copyright notice that you may distribute + * with programs based on this work. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ +package org.openscience.cdk.interfaces; + +/** + * Stereochemistry specification for quadrivalent atoms. The data model defines the central, chiral {@link IAtom}, + * and its four ligand {@link IAtom}s, directly bonded to the chiral atom via an {@link IBond}. The ordering of the + * four ligands is important, and defines together with the {@link Stereo} to spatial geometry around the chiral atom. + * The first ligand points towards to observer, and the three other ligands point away from the observer; the + * {@link Stereo} then defines the order of the second, third, and fourth ligand to be clockwise or anti-clockwise. + * + * @cdk.module interfaces + */ +public interface ILigancyFourChirality extends IStereoElement { + + /** + * Enumeration that defines the two possible chiralities for this stereochemistry type. + */ + public enum Stereo { + CLOCKWISE, + ANTI_CLOCKWISE + } + + /** + * Returns an array of ligand atoms around the chiral atom. + * + * @return an array of four {@link IAtom}s. + */ + public IAtom[] getLigands(); + + /** + * Atom that is the chirality center. + * + * @return the chiral {@link IAtom}. + */ + public IAtom getChiralAtom(); + + /** + * Defines the stereochemistry around the chiral atom. The value depends on the order of ligand atoms. + * + * @return the {@link Stereo} for this stereo element. + */ + public Stereo getStereo(); + +} diff --git a/src/main/org/openscience/cdk/stereo/LigancyFourChirality.java b/src/main/org/openscience/cdk/stereo/LigancyFourChirality.java new file mode 100644 index 00000000000..1ce9d443745 --- /dev/null +++ b/src/main/org/openscience/cdk/stereo/LigancyFourChirality.java @@ -0,0 +1,83 @@ +/* Copyright (C) 2010 Egon Willighagen + * + * Contact: cdk-devel@lists.sourceforge.net + * + * This program 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. + * All we ask is that proper credit is given for our work, which includes + * - but is not limited to - adding the above copyright notice to the beginning + * of your source code files, and to any copyright notice that you may distribute + * with programs based on this work. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ +package org.openscience.cdk.stereo; + +import org.openscience.cdk.DefaultChemObjectBuilder; +import org.openscience.cdk.interfaces.IAtom; +import org.openscience.cdk.interfaces.IChemObjectBuilder; +import org.openscience.cdk.interfaces.ILigancyFourChirality; + +/** + * Stereochemistry specification for quadrivalent atoms. See {@link ILigancyFourChirality} for + * further details. + * + * @cdk.module data + * + * @see ILigancyFourChirality + */ +public class LigancyFourChirality implements ILigancyFourChirality { + + private IAtom chiralAtom; + private IAtom[] ligandAtoms; + private Stereo stereo; + + public LigancyFourChirality(IAtom chiralAtom, IAtom[] ligandAtoms, Stereo chirality) { + this.chiralAtom = chiralAtom; + this.ligandAtoms = ligandAtoms; + this.stereo = chirality; + } + + /** + * Returns an array of ligand atoms around the chiral atom. + * + * @return an array of four {@link IAtom}s. + */ + public IAtom[] getLigands() { + IAtom[] arrayCopy = new IAtom[4]; + System.arraycopy(ligandAtoms, 0, arrayCopy, 0, 4); + return arrayCopy; + } + + /** + * Atom that is the chirality center. + * + * @return the chiral {@link IAtom}. + */ + public IAtom getChiralAtom() { + return chiralAtom; + } + + /** + * Defines the stereochemistry around the chiral atom. The value depends on the order of ligand atoms. + * + * @return the {@link Stereo} for this stereo element. + */ + public Stereo getStereo() { + return stereo; + } + + public IChemObjectBuilder getBuilder() { + return DefaultChemObjectBuilder.getInstance(); + } + +} diff --git a/src/test/org/openscience/cdk/modulesuites/MdataTests.java b/src/test/org/openscience/cdk/modulesuites/MdataTests.java index 430201075b2..1831c685bf7 100644 --- a/src/test/org/openscience/cdk/modulesuites/MdataTests.java +++ b/src/test/org/openscience/cdk/modulesuites/MdataTests.java @@ -68,6 +68,7 @@ import org.openscience.cdk.protein.data.PDBMonomerTest; import org.openscience.cdk.protein.data.PDBPolymerTest; import org.openscience.cdk.protein.data.PDBStructureTest; +import org.openscience.cdk.stereo.LigancyFourChiralityTest; /** * TestSuite that runs all the sample tests. @@ -116,6 +117,8 @@ AdductFormulaTest.class, MolecularFormulaSetTest.class, MolecularFormulaTest.class, + + LigancyFourChiralityTest.class, // test from test.event ChemObjectChangeEventTest.class, diff --git a/src/test/org/openscience/cdk/stereo/LigancyFourChiralityTest.java b/src/test/org/openscience/cdk/stereo/LigancyFourChiralityTest.java new file mode 100644 index 00000000000..e5b04b59331 --- /dev/null +++ b/src/test/org/openscience/cdk/stereo/LigancyFourChiralityTest.java @@ -0,0 +1,118 @@ +/* Copyright (C) 2010 Egon Willighagen + * + * Contact: cdk-devel@lists.sourceforge.net + * + * This program 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. + * All we ask is that proper credit is given for our work, which includes + * - but is not limited to - adding the above copyright notice to the beginning + * of your source code files, and to any copyright notice that you may distribute + * with programs based on this work. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ +package org.openscience.cdk.stereo; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openscience.cdk.Atom; +import org.openscience.cdk.CDKTestCase; +import org.openscience.cdk.DefaultChemObjectBuilder; +import org.openscience.cdk.Molecule; +import org.openscience.cdk.interfaces.IAtom; +import org.openscience.cdk.interfaces.IMolecule; +import org.openscience.cdk.interfaces.IBond.Order; +import org.openscience.cdk.interfaces.ILigancyFourChirality.Stereo; + +/** + * @cdk.module test-data + */ +public class LigancyFourChiralityTest extends CDKTestCase { + + private static IMolecule molecule; + private static IAtom[] ligands; + + @BeforeClass + public static void setup() throws Exception { + molecule = new Molecule(); + molecule.addAtom(new Atom("Cl")); + molecule.addAtom(new Atom("C")); + molecule.addAtom(new Atom("Br")); + molecule.addAtom(new Atom("I")); + molecule.addAtom(new Atom("H")); + molecule.addBond(0, 1, Order.SINGLE); + molecule.addBond(1, 2, Order.SINGLE); + molecule.addBond(1, 3, Order.SINGLE); + molecule.addBond(1, 4, Order.SINGLE); + ligands = new IAtom[] { + molecule.getAtom(4), + molecule.getAtom(3), + molecule.getAtom(2), + molecule.getAtom(0) + }; + } + + @Test + public void testLigancyFourChirality_IAtom_arrayIAtom_ILigancyFourChirality_STEREO() { + LigancyFourChirality chirality = new LigancyFourChirality( + molecule.getAtom(1), ligands, Stereo.CLOCKWISE + ); + Assert.assertNotNull(chirality); + } + + @Test + public void testGetBuilder() { + LigancyFourChirality chirality = new LigancyFourChirality( + molecule.getAtom(1), ligands, Stereo.CLOCKWISE + ); + Assert.assertEquals( + DefaultChemObjectBuilder.getInstance(), + chirality.getBuilder() + ); + } + + @Test + public void testGetChiralAtom() { + LigancyFourChirality chirality = new LigancyFourChirality( + molecule.getAtom(1), ligands, Stereo.CLOCKWISE + ); + Assert.assertNotNull(chirality); + Assert.assertEquals(molecule.getAtom(1), chirality.getChiralAtom()); + } + + @Test + public void testGetStereo() { + LigancyFourChirality chirality = new LigancyFourChirality( + molecule.getAtom(1), ligands, Stereo.CLOCKWISE + ); + Assert.assertNotNull(chirality); + Assert.assertEquals(molecule.getAtom(1), chirality.getChiralAtom()); + for (int i=0; i Date: Tue, 4 May 2010 18:26:02 +0200 Subject: [PATCH 13/21] Added unit tests with various chiral SMILES situations. * ring closures * disconnections * implicit/explicit hydrogens Signed-off-by: Rajarshi Guha --- .../cdk/smiles/SmilesParserTest.java | 200 ++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/src/test/org/openscience/cdk/smiles/SmilesParserTest.java b/src/test/org/openscience/cdk/smiles/SmilesParserTest.java index d8a5823468a..8efaa0faf13 100644 --- a/src/test/org/openscience/cdk/smiles/SmilesParserTest.java +++ b/src/test/org/openscience/cdk/smiles/SmilesParserTest.java @@ -39,10 +39,13 @@ import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IAtomType; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.ILigancyFourChirality; import org.openscience.cdk.interfaces.IMolecule; import org.openscience.cdk.interfaces.IMoleculeSet; import org.openscience.cdk.interfaces.IPseudoAtom; import org.openscience.cdk.interfaces.IReaction; +import org.openscience.cdk.interfaces.IStereoElement; +import org.openscience.cdk.interfaces.ILigancyFourChirality.Stereo; import org.openscience.cdk.isomorphism.IsomorphismTester; import org.openscience.cdk.isomorphism.UniversalIsomorphismTester; import org.openscience.cdk.layout.StructureDiagramGenerator; @@ -1845,5 +1848,202 @@ public void testAromaticity() throws InvalidSmilesException{ Assert.assertTrue(atom.getFlag(CDKConstants.ISAROMATIC)); } } + + /** + * Tests reading stereochemistry from a SMILES with one of the four groups being an implicit hydrogen. + * Per SMILES specification, this hydrogen is the atom towards the viewer, and will therefore end up + * as first atom in the array. + */ + @Test public void testAtAt() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("Br[C@@H](Cl)I"); + Iterator stereoElements = mol.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("Br", ligands[0].getSymbol()); + Assert.assertEquals("H", ligands[1].getSymbol()); + Assert.assertEquals("Cl", ligands[2].getSymbol()); + Assert.assertEquals("I", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.CLOCKWISE, l4Chiral.getStereo()); + } + + /** + * Tests reading stereochemistry from a SMILES with one of the four groups being an implicit hydrogen. + * Per SMILES specification, this hydrogen is the atom towards the viewer, and will therefore end up + * as first atom in the array. + */ + @Test public void testAt() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("Br[C@H](Cl)I"); + Iterator stereoElements = mol.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("Br", ligands[0].getSymbol()); + Assert.assertEquals("H", ligands[1].getSymbol()); + Assert.assertEquals("Cl", ligands[2].getSymbol()); + Assert.assertEquals("I", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + } + + @Test public void testAtAt_ExplicitHydrogen() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("Br[C@@]([H])(Cl)I"); + Iterator stereoElements = mol.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("Br", ligands[0].getSymbol()); + Assert.assertEquals("H", ligands[1].getSymbol()); + Assert.assertEquals("Cl", ligands[2].getSymbol()); + Assert.assertEquals("I", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.CLOCKWISE, l4Chiral.getStereo()); + } + + @Test public void testAt_ExplicitHydrogen() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("Br[C@]([H])(Cl)I"); + Iterator stereoElements = mol.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("Br", ligands[0].getSymbol()); + Assert.assertEquals("H", ligands[1].getSymbol()); + Assert.assertEquals("Cl", ligands[2].getSymbol()); + Assert.assertEquals("I", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + } + + @Test public void testRingClosure_At() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("[C@]12(OC1)NCN2"); + Iterator stereoElements = mol.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("C", ligands[0].getSymbol()); + Assert.assertEquals("N", ligands[1].getSymbol()); + Assert.assertEquals("O", ligands[2].getSymbol()); + Assert.assertEquals("N", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + } + + @Test public void testNeighboringChirality() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("C[C@H](O)[C@H](O)C"); + Iterator stereoElements = mol.stereoElements().iterator(); + // first chiral center + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("C", ligands[0].getSymbol()); + Assert.assertEquals("H", ligands[1].getSymbol()); + Assert.assertEquals("O", ligands[2].getSymbol()); + Assert.assertEquals("C", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + // second chiral center + Assert.assertTrue(stereoElements.hasNext()); + stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("C", ligands[0].getSymbol()); + Assert.assertEquals("H", ligands[1].getSymbol()); + Assert.assertEquals("O", ligands[2].getSymbol()); + Assert.assertEquals("C", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + } + + @Test public void testChiralityInBranch() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("NC([C@H](O)C)Cl"); + Iterator stereoElements = mol.stereoElements().iterator(); + // first chiral center + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("C", ligands[0].getSymbol()); + Assert.assertEquals("H", ligands[1].getSymbol()); + Assert.assertEquals("O", ligands[2].getSymbol()); + Assert.assertEquals("C", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + } + + @Test public void testChiralityWithTonsOfDots() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("I1.Cl2.Br3.[C@]123CCC"); + Iterator stereoElements = mol.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("I", ligands[0].getSymbol()); + Assert.assertEquals("Cl", ligands[1].getSymbol()); + Assert.assertEquals("Br", ligands[2].getSymbol()); + Assert.assertEquals("C", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + } + + @Test public void testChiralAtomWithDisconnectedLastAtom() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("Br1.[C@]1(Cl)(OC)CCC"); + Iterator stereoElements = mol.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("Br", ligands[0].getSymbol()); + Assert.assertEquals("Cl", ligands[1].getSymbol()); + Assert.assertEquals("O", ligands[2].getSymbol()); + Assert.assertEquals("C", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + } } From 2dd575ed564675259eead21ddbf4ee4fc9083680 Mon Sep 17 00:00:00 2001 From: Egon Willighagen Date: Tue, 4 May 2010 18:34:50 +0200 Subject: [PATCH 14/21] SMILES @ and @@ chiralities are now fully read. * takes into account branching * implicit hydrogens on chiral atoms are made explicit Signed-off-by: Rajarshi Guha --- .../openscience/cdk/smiles/SmilesParser.java | 175 ++++++++++++++++-- 1 file changed, 156 insertions(+), 19 deletions(-) diff --git a/src/main/org/openscience/cdk/smiles/SmilesParser.java b/src/main/org/openscience/cdk/smiles/SmilesParser.java index 4a86c221a21..60da400ff00 100644 --- a/src/main/org/openscience/cdk/smiles/SmilesParser.java +++ b/src/main/org/openscience/cdk/smiles/SmilesParser.java @@ -26,7 +26,9 @@ package org.openscience.cdk.smiles; import java.util.Enumeration; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import java.util.Stack; import java.util.StringTokenizer; @@ -41,12 +43,16 @@ import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IAtomType; import org.openscience.cdk.interfaces.IBond; +import org.openscience.cdk.interfaces.IChemObjectBuilder; +import org.openscience.cdk.interfaces.ILigancyFourChirality; import org.openscience.cdk.interfaces.IMolecule; import org.openscience.cdk.interfaces.IMoleculeSet; -import org.openscience.cdk.interfaces.IChemObjectBuilder; import org.openscience.cdk.interfaces.IPseudoAtom; import org.openscience.cdk.interfaces.IReaction; import org.openscience.cdk.interfaces.IAtomType.Hybridization; +import org.openscience.cdk.interfaces.IBond.Order; +import org.openscience.cdk.interfaces.ILigancyFourChirality.Stereo; +import org.openscience.cdk.stereo.LigancyFourChirality; import org.openscience.cdk.tools.CDKHydrogenAdder; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; @@ -93,6 +99,11 @@ public class SmilesParser { private int status = 0; protected IChemObjectBuilder builder; + private enum Chirality { + ANTI_CLOCKWISE, // aka @ + CLOCKWISE // aka @@ + } + /** * Constructor for the SmilesParser object. * @@ -116,11 +127,40 @@ public SmilesParser(IChemObjectBuilder builder) IBond.Order bondStatus = null; IBond.Order bondStatusForRingClosure = IBond.Order.SINGLE; boolean bondIsAromatic = false; + // array of atoms that initiated a ring closure IAtom[] rings = null; + // array of atoms that complete a ring closure + IAtom[] ringOtherAtoms = null; IBond.Order[] ringbonds = null; int thisRing = -1; IMolecule molecule = null; String currentSymbol = null; + Map chiralityInfo = null; + + /** + * Internal storage for temporary stereochemistry info. In particular, the atoms + * involved are generally not known until the full SMILES is processed. + */ + class TemporaryChiralityStorage { + Chirality chiralityValue; + IAtom[] atoms; + int counter; + public TemporaryChiralityStorage() { + chiralityValue = null; + atoms = new IAtom[4]; + counter = 0; + } + public TemporaryChiralityStorage(IAtom atom) { + chiralityValue = null; + atoms = new IAtom[4]; + atoms[0] = atom; + counter = 1; + } + public void addAtom(IAtom atom) { + atoms[counter] = atom; + counter++; + } + } /** * Parse a reaction SMILES. @@ -188,6 +228,22 @@ public IReaction parseReactionSmiles(String smiles) throws InvalidSmilesExceptio public IMolecule parseSmiles(String smiles) throws InvalidSmilesException { IMolecule molecule = this.parseString(smiles); + // analyze the chirality info + for (IAtom atom : chiralityInfo.keySet()) { + TemporaryChiralityStorage chirality = chiralityInfo.get(atom); + logger.debug("Chiral atom found: ", atom); + IAtom[] atoms = chirality.atoms; + ILigancyFourChirality l4Chiral = new LigancyFourChirality( + atom, + new IAtom[]{ + atoms[0], atoms[1], atoms[2], atoms[3] + }, + chirality.chiralityValue == Chirality.CLOCKWISE + ? Stereo.CLOCKWISE : Stereo.ANTI_CLOCKWISE + ); + molecule.addStereoElement(l4Chiral); + } + // perceive atom types CDKAtomTypeMatcher matcher = CDKAtomTypeMatcher.getInstance(molecule.getBuilder()); int i = 0; @@ -225,12 +281,15 @@ private IMolecule parseString(String smiles) throws InvalidSmilesException currentSymbol = null; molecule = builder.newInstance(IMolecule.class); position = 0; + chiralityInfo = new HashMap(); // we don't want more than 1024 rings - rings = new IAtom[1024]; - ringbonds = new IBond.Order[1024]; - for (int f = 0; f < 1024; f++) - { + final int MAX_RING_COUNT = 1024; + rings = new IAtom[MAX_RING_COUNT]; + ringOtherAtoms = new IAtom[MAX_RING_COUNT]; + ringbonds = new IBond.Order[MAX_RING_COUNT]; + for (int f = 0; f < MAX_RING_COUNT; f++) { rings[f] = null; + ringOtherAtoms[f] = null; ringbonds[f] = null; } @@ -290,7 +349,7 @@ private IMolecule parseString(String smiles) throws InvalidSmilesException "use [" + mychar + "]."); } } - + addAtomToActiveChiralities(lastNode, atom); molecule.addAtom(atom); logger.debug("Adding atom ", atom.hashCode()); if ((lastNode != null) && bondExists) @@ -371,7 +430,8 @@ private IMolecule parseString(String smiles) throws InvalidSmilesException } else if (mychar == '[') { currentSymbol = getAtomString(smiles, position); - atom = assembleAtom(currentSymbol); + atom = assembleAtom(currentSymbol, lastNode, bondExists); + addAtomToActiveChiralities(lastNode, atom); molecule.addAtom(atom); logger.debug("Added atom: ", atom); if (lastNode != null && bondExists) @@ -414,11 +474,34 @@ private IMolecule parseString(String smiles) throws InvalidSmilesException position++; } else if (mychar == '@') { + TemporaryChiralityStorage chirality = null; + if (lastNode != null) { + chirality = new TemporaryChiralityStorage(lastNode); + } else { + chirality = new TemporaryChiralityStorage(); + } + // @ or @@ if (position < smiles.length() - 1 && smiles.charAt(position + 1) == '@') { + chirality.chiralityValue = Chirality.CLOCKWISE; position++; + } else { + chirality.chiralityValue = Chirality.ANTI_CLOCKWISE; } - logger.warn("Ignoring stereo information for atom"); + // @H or @@H ? + if (position < smiles.length() - 1 && smiles.charAt(position + 1) == 'H') { + // because the current data model requires a ligancy four chirality to + // have 4 IAtoms, we add an explicit hydrogen + IAtom hydrogen = builder.newInstance(IAtom.class, "H"); + IBond newBond = builder.newInstance(IBond.class, + atom, hydrogen, Order.SINGLE + ); + molecule.addAtom(hydrogen); + molecule.addBond(newBond); + chirality.addAtom(hydrogen); + position++; + } + chiralityInfo.put(lastNode, chirality); position++; } else { @@ -578,6 +661,18 @@ private String getElementSymbol(String s, int pos) return getSymbolForOrganicSubsetElement(s, pos); } + private void addAtomToActiveChiralities(IAtom chiAtom, IAtom atom) { + for (IAtom chiralAtom : chiralityInfo.keySet()) { + if (chiralAtom == atom) + // but not if the new atom is the chiral atom itself + continue; + if (chiAtom != chiralAtom) + // ok, the atom does not belong to this chirality + continue; + TemporaryChiralityStorage chirality = chiralityInfo.get(chiralAtom); + if (chirality.counter < 4) chirality.addAtom(atom); + } + } /** * Gets the ElementSymbol for an element in the 'organic subset' for which @@ -631,7 +726,7 @@ private String getRingNumber(String s, int pos) throws InvalidSmilesException { return retString; } - private IAtom assembleAtom(String s) throws InvalidSmilesException + private IAtom assembleAtom(String s, IAtom lastNode, boolean bondExists) throws InvalidSmilesException { logger.debug("assembleAtom(): Assembling atom from: ", s); IAtom atom = null; @@ -754,12 +849,34 @@ private IAtom assembleAtom(String s) throws InvalidSmilesException atom.setFormalCharge(charge); } else if (mychar == '@') { - if (position < s.length() - 1 && s.charAt(position + 1) == '@') - { - position++; - } - logger.warn("Ignoring stereo information for atom"); - position++; + TemporaryChiralityStorage chirality = null; + if (lastNode != null && bondExists) { + chirality = new TemporaryChiralityStorage(lastNode); + } else { + chirality = new TemporaryChiralityStorage(); + } + if (position < s.length() - 1 && s.charAt(position + 1) == '@') + { + chirality.chiralityValue = Chirality.CLOCKWISE; + position++; + } else { + chirality.chiralityValue = Chirality.ANTI_CLOCKWISE; + } + // @H or @@H ? + if (position < s.length() - 1 && s.charAt(position + 1) == 'H') { + // because the current data model requires a ligancy four chirality to + // have 4 IAtoms, we add an explicit hydrogen + IAtom hydrogen = builder.newInstance(IAtom.class, "H"); + IBond newBond = builder.newInstance(IBond.class, + atom, hydrogen, Order.SINGLE + ); + molecule.addAtom(hydrogen); + molecule.addBond(newBond); + chirality.addAtom(hydrogen); + position++; + } + chiralityInfo.put(atom, chirality); + position++; } else { throw new InvalidSmilesException("Found unexpected char: " + mychar); @@ -792,20 +909,23 @@ private void handleRing(IAtom atom) IBond bond = null; IAtom partner = null; IAtom thisNode = rings[thisRing]; + IAtom templateAtom = ringOtherAtoms[thisRing]; // lookup if (thisNode != null) { partner = thisNode; + replaceTemplateAtomInStereos(templateAtom, atom); + if (chiralityInfo.containsKey(atom)) + addAtomToActiveChiralities(atom, partner); bond = builder.newInstance(IBond.class,atom, partner, bondStat); - if (bondIsAromatic) { - + if (bondIsAromatic) { bond.setFlag(CDKConstants.ISAROMATIC, true); } molecule.addBond(bond); bondIsAromatic = false; rings[thisRing] = null; ringbonds[thisRing] = null; - + ringOtherAtoms[thisRing] = null; } else { /* @@ -813,12 +933,29 @@ private void handleRing(IAtom atom) * - add current atom to list */ rings[thisRing] = atom; + ringOtherAtoms[thisRing] = builder.newInstance(IAtom.class); + addAtomToActiveChiralities(atom, ringOtherAtoms[thisRing]); ringbonds[thisRing] = bondStatusForRingClosure; } bondStatusForRingClosure = IBond.Order.SINGLE; } - private void addImplicitHydrogens(IMolecule container) { + /** + * Replaces the templateAtom by atom in all currently defined stereochemistries. + * + * @param templateAtom {@link IAtom} to replace + * @param atom new {@link IAtom} + */ + private void replaceTemplateAtomInStereos(IAtom templateAtom, IAtom atom) { + for (TemporaryChiralityStorage chirality : chiralityInfo.values()) { + for (int i=0; i<4; i++) { + if (chirality.atoms[i] == templateAtom) + chirality.atoms[i] = atom; + } + } + } + + private void addImplicitHydrogens(IMolecule container) { try { logger.debug("before H-adding: ", container); Iterator atoms = container.atoms().iterator(); From 0f4649c0d0e5709c4fd9e472c3bd6ab51fbdcc77 Mon Sep 17 00:00:00 2001 From: Egon Willighagen Date: Fri, 7 May 2010 16:44:15 +0200 Subject: [PATCH 15/21] Added two more unit tests, related to ring closing Signed-off-by: Rajarshi Guha --- .../cdk/smiles/SmilesParserTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/test/org/openscience/cdk/smiles/SmilesParserTest.java b/src/test/org/openscience/cdk/smiles/SmilesParserTest.java index 8efaa0faf13..dc33adf5c8a 100644 --- a/src/test/org/openscience/cdk/smiles/SmilesParserTest.java +++ b/src/test/org/openscience/cdk/smiles/SmilesParserTest.java @@ -946,6 +946,19 @@ public void testConnectedByRingClosure() throws Exception { Assert.assertEquals(3, mol1.getAtomCount()); } + @Test + public void testConnectedByRingClosure_TwoAtom() throws Exception { + String methanol = "C1.O1"; + IMolecule mol = sp.parseSmiles(methanol); + Assert.assertEquals(2, mol.getAtomCount()); + Assert.assertEquals(1, mol.getBondCount()); + + IMoleculeSet fragments = ConnectivityChecker.partitionIntoMolecules(mol); + int fragmentCount = fragments.getMoleculeCount(); + Assert.assertEquals(1, fragmentCount); + IMolecule mol1 = fragments.getMolecule(0); + Assert.assertEquals(2, mol1.getAtomCount()); + } /** * Example taken from 'Handbook of Chemoinformatics', Gasteiger, 2003, page 89 @@ -1935,6 +1948,18 @@ public void testAromaticity() throws InvalidSmilesException{ Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); } + @Test public void testRingClosure() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("C12(OC1)CCC2"); + Assert.assertEquals(6, mol.getAtomCount()); + Assert.assertEquals("C", mol.getAtom(0).getSymbol()); + Assert.assertEquals("O", mol.getAtom(1).getSymbol()); + Assert.assertEquals("C", mol.getAtom(2).getSymbol()); + Assert.assertEquals(4, mol.getConnectedAtomsCount(mol.getAtom(0))); + Assert.assertEquals(2, mol.getConnectedAtomsCount(mol.getAtom(1))); + Assert.assertEquals(2, mol.getConnectedAtomsCount(mol.getAtom(2))); + } + @Test public void testRingClosure_At() throws Exception { SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); IMolecule mol = sp.parseSmiles("[C@]12(OC1)NCN2"); From 9cbc2424548a627aaadbe41e0b4312990e725b12 Mon Sep 17 00:00:00 2001 From: Egon Willighagen Date: Sat, 8 May 2010 21:56:13 +0200 Subject: [PATCH 16/21] Added two test cases by Daniel from my blog: http://chem-bla-ics.blogspot.com/2010/05/cip-rules-2-parsing-and-from-smiles.html Signed-off-by: Rajarshi Guha --- .../cdk/smiles/SmilesParserTest.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/test/org/openscience/cdk/smiles/SmilesParserTest.java b/src/test/org/openscience/cdk/smiles/SmilesParserTest.java index dc33adf5c8a..0a08a7a3251 100644 --- a/src/test/org/openscience/cdk/smiles/SmilesParserTest.java +++ b/src/test/org/openscience/cdk/smiles/SmilesParserTest.java @@ -2070,5 +2070,54 @@ public void testAromaticity() throws InvalidSmilesException{ Assert.assertEquals("C", ligands[3].getSymbol()); Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); } + + @Test public void testFromBlog1() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("[C@@H]231.C2.N1.F3"); + Iterator stereoElements = mol.stereoElements().iterator(); + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("H", ligands[0].getSymbol()); + Assert.assertEquals("C", ligands[1].getSymbol()); + Assert.assertEquals("F", ligands[2].getSymbol()); + Assert.assertEquals("N", ligands[3].getSymbol()); + Assert.assertEquals(Stereo.CLOCKWISE, l4Chiral.getStereo()); + } + + @Test public void testFromBlog2() throws Exception { + SmilesParser sp = new SmilesParser(DefaultChemObjectBuilder.getInstance()); + IMolecule mol = sp.parseSmiles("[C@@H](Cl)1[C@H](C)(F).Br1"); + Iterator stereoElements = mol.stereoElements().iterator(); + for (int i=0; i<2; i++) { + Assert.assertTrue(stereoElements.hasNext()); + IStereoElement stereoElement = stereoElements.next(); + Assert.assertNotNull(stereoElement); + Assert.assertTrue(stereoElement instanceof ILigancyFourChirality); + ILigancyFourChirality l4Chiral = (ILigancyFourChirality)stereoElement; + Assert.assertEquals("C", l4Chiral.getChiralAtom().getSymbol()); + if (l4Chiral.getStereo() == Stereo.CLOCKWISE) { + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("H", ligands[0].getSymbol()); + Assert.assertEquals("Cl", ligands[1].getSymbol()); + Assert.assertEquals("Br", ligands[2].getSymbol()); + Assert.assertEquals("C", ligands[3].getSymbol()); + } else { + Assert.assertEquals(Stereo.ANTI_CLOCKWISE, l4Chiral.getStereo()); + IAtom[] ligands = l4Chiral.getLigands(); + for (IAtom atom : ligands) Assert.assertNotNull(atom); + Assert.assertEquals("C", ligands[0].getSymbol()); + Assert.assertEquals("H", ligands[1].getSymbol()); + Assert.assertEquals("C", ligands[2].getSymbol()); + Assert.assertEquals("F", ligands[3].getSymbol()); + } + } + } } From f5ccf1bdc83cb821bf7b764912f2c6fa2d0ae08a Mon Sep 17 00:00:00 2001 From: Syed Asad Rahman Date: Mon, 17 May 2010 15:48:34 +0100 Subject: [PATCH 17/21] Updated the SMSD code for turbo mode substructure search Refactored the SMSD class itself Signed-off-by: Syed Asad Rahman Signed-off-by: Rajarshi Guha --- src/main/org/openscience/cdk/smsd/SMSD.java | 271 ------------------ .../algorithm/vflib/VFlibTurboHandler.java | 69 ++--- .../factory/SubStructureSearchAlgorithms.java | 7 +- 3 files changed, 33 insertions(+), 314 deletions(-) diff --git a/src/main/org/openscience/cdk/smsd/SMSD.java b/src/main/org/openscience/cdk/smsd/SMSD.java index 9fb1e6711d9..2cc1281ac82 100644 --- a/src/main/org/openscience/cdk/smsd/SMSD.java +++ b/src/main/org/openscience/cdk/smsd/SMSD.java @@ -22,16 +22,7 @@ */ package org.openscience.cdk.smsd; -import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; import org.openscience.cdk.annotations.TestClass; -import org.openscience.cdk.annotations.TestMethod; -import org.openscience.cdk.exception.CDKException; -import org.openscience.cdk.interfaces.IAtom; -import org.openscience.cdk.interfaces.IAtomContainer; -import org.openscience.cdk.interfaces.IMolecule; import org.openscience.cdk.smsd.factory.SubStructureSearchAlgorithms; import org.openscience.cdk.smsd.interfaces.AbstractMCS; import org.openscience.cdk.smsd.interfaces.Algorithm; @@ -142,10 +133,6 @@ @TestClass("org.openscience.cdk.smsd.SMSDTest") public class SMSD extends SubStructureSearchAlgorithms { - private final static ILoggingTool logger = - LoggingToolFactory.createLoggingTool(SMSD.class); - private AbstractMCS comparison = null; - /** * Algorithm {@link org.openscience.cdk.smsd.interfaces.Algorithm} * choice for find MCS or performing substructure searches @@ -168,263 +155,5 @@ public class SMSD extends SubStructureSearchAlgorithms { */ public SMSD(Algorithm algorithmType, boolean bondSensitiveFlag) { super(algorithmType, bondSensitiveFlag); - comparison = new SubStructureSearchAlgorithms(algorithmType, bondSensitiveFlag); - } - - /** {@inheritDoc} - * - * initialize query and target molecules - * @param Query query molecule - * @param Target target molecule - */ - @Override - @TestMethod("testInit_3args_1") - public synchronized void init(IMolecule Query, IMolecule Target, boolean removeHydrogen) { - - if (Query.getAtomCount() > 0 && Target.getAtomCount() > 0) { - try { - getComparison().init(Query, Target, removeHydrogen); - } catch (CDKException ex) { - logger.error(Level.SEVERE, null, ex); - } - } else { - try { - throw new CDKException("Each molecule should have atleast one atom to compare"); - } catch (CDKException ex) { - logger.error(Level.SEVERE, null, ex); - } - } - } - - /** {@inheritDoc} - * - * initialize query and target molecules - * @param Query Atomcontainer - * @param Target Atomcontainer - */ - @Override - @TestMethod("testInit_3args_2") - public synchronized void init(IAtomContainer Query, IAtomContainer Target, boolean removeHydrogen) { - - if (Query.getAtomCount() > 0 && Target.getAtomCount() > 0) { - try { - getComparison().init(Query, Target, removeHydrogen); - } catch (CDKException ex) { - logger.error(Level.SEVERE, null, ex); - } - } else { - try { - throw new CDKException("Each molecule should have atleast one atom to compare"); - } catch (CDKException ex) { - logger.error(Level.SEVERE, null, ex); - } - } - } - - /** {@inheritDoc} - * - * These are important set of paraments which will refine and rank the - * mcs solutions. The precedence of stereoFilter > fragmentFilter > energyFilter - * @param stereoFilter true if stereo match is considered else false - * @param fragmentFilter true if fragement filter is switched on else false - * @param energyFilter true if bond energy filter is switched on else false - */ - @Override - @TestMethod("testSetChemFilters") - public void setChemFilters(boolean stereoFilter, boolean fragmentFilter, boolean energyFilter) { - getComparison().setChemFilters(stereoFilter, fragmentFilter, energyFilter); - } - - /** {@inheritDoc} - * - * Returns all plausible mappings between query and target molecules - * Each map in the list has atom-atom equivalence of the mappings - * between query and target molecule i.e. map.getKey() for the query - * and map.getValue() for the target molecule - * @return A List of all possible mapped MCS atoms. - * - */ - @Override - @TestMethod("testGetAllAtomMapping") - public List> getAllAtomMapping() { - return getComparison().getAllAtomMapping(); - } - - /** {@inheritDoc} - (* - * Returns all plausible mappings between query and target molecules - * Each map in the list has atom-atom equivalence index of the mappings - * between query and target molecule i.e. map.getKey() for the query - * and map.getValue() for the target molecule - * @return A List of all possible mapped MCS atom index. - * - */ - @Override - @TestMethod("testGetAllMapping") - public List> getAllMapping() { - return getComparison().getAllMapping(); - } - - /** {@inheritDoc} - * - * Returns one of the best matches with atoms mapped - * @return One of the best MCS solution(s) atoms - * - */ - @Override - @TestMethod("testGetFirstAtomMapping") - public Map getFirstAtomMapping() { - return getComparison().getFirstAtomMapping(); - } - - /** {@inheritDoc} - * - * Returns one of the best matches with atom indexes mapped - * @return One of the best MCS solution(s) index - */ - @Override - @TestMethod("testGetFirstMapping") - public Map getFirstMapping() { - return getComparison().getFirstMapping(); - } - - /** {@inheritDoc} - * - * Returns a number which denotes the quality of the mcs. - * A solution with highest stereo score is preferred over other - * scores - * @param Key position - * @return Stereo matching score for the mapped part - * - */ - @Override - @TestMethod("testGetStereoScore") - public Integer getStereoScore(int Key) { - return getComparison().getStereoScore(Key); - } - - /** {@inheritDoc} - * - * Returns number of fragment generated in the solution space, - * if the MCS is removed from the target and query graph. - * Amongst the solutions, a solution with lowest fragment size - * is preferred - * - * @param Key position - * @return Fragment count(s) generated after removing the mapped parts - * - */ - @Override - @TestMethod("testGetFragmentSize") - public Integer getFragmentSize(int Key) { - return getComparison().getFragmentSize(Key); - } - - /** {@inheritDoc} - * - * Returns summation energy score of the disorder if the MCS is removed - * from the target and query graph. Amongst the solutions, a solution - * with lowest energy score is preferred - * - * @param Key position - * @return Total bond breaking energy required to remove the mapped part - * - */ - @Override - @TestMethod("testGetEnergyScore") - public Double getEnergyScore(int Key) { - return getComparison().getEnergyScore(Key); - } - - /** {@inheritDoc} - * - * Returns modified query molecule on which mapping was - * performed - * @return Query Molecule AtomContainer - */ - @Override - @TestMethod("testGetReactantMolecule") - public IAtomContainer getReactantMolecule() { - return getComparison().getReactantMolecule(); - } - - /** {@inheritDoc} - * - * Returns modified target molecule on which mapping was - * performed - * @return Target Molecule AtomContainer - */ - @Override - @TestMethod("testGetProductMolecule") - public IAtomContainer getProductMolecule() { - return getComparison().getProductMolecule(); - } - - /** {@inheritDoc} - * - * Returns Tanimoto similarity between query and target molecules - * (Score is between 0-min and 1-max) - * @return Tanimoto similarity between query and target molecules - * @throws java.io.IOException - */ - @Override - @TestMethod("testGetTanimotoSimilarity") - public double getTanimotoSimilarity() throws IOException { - return getComparison().getTanimotoSimilarity(); - } - - /** {@inheritDoc} - * - * - * @return true if no stereo mismatch occurs - * else false if stereo mismatch occurs - */ - @Override - @TestMethod("testIsStereoMisMatch") - public boolean isStereoMisMatch() { - return getComparison().isStereoMisMatch(); - } - - /** {@inheritDoc} - * - * Checks if query is a subgraph of the target - * @return true if query is a subgraph of the target - * else false - */ - @Override - @TestMethod("testIsSubgraph") - public boolean isSubgraph() { - return getComparison().isSubgraph(); - - } - - /** {@inheritDoc} - * - * Returns Euclidean Distance between query and target molecule - * @return Euclidean Distance between query and target molecule - * @throws IOException - */ - @Override - @TestMethod("testGetEuclideanDistance") - public double getEuclideanDistance() throws IOException { - return getComparison().getEuclideanDistance(); - } - - /** - * Returns algorithm class instance in process - * @return the comparison - */ - @TestMethod("testGetComparison") - public AbstractMCS getComparison() { - return comparison; - } - - /** - * Sets algorithm class initiated for search process - * @param comparison the comparison to set - */ - @TestMethod("testSetComparison") - public void setComparison(AbstractMCS comparison) { - this.comparison = comparison; } } diff --git a/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboHandler.java b/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboHandler.java index de2b7acb195..ce4e3ba98ac 100644 --- a/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboHandler.java +++ b/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboHandler.java @@ -34,13 +34,13 @@ import org.openscience.cdk.smsd.algorithm.vflib.interfaces.IMapper; import org.openscience.cdk.smsd.algorithm.vflib.interfaces.INode; import org.openscience.cdk.smsd.algorithm.vflib.interfaces.IQuery; -import org.openscience.cdk.smsd.algorithm.vflib.map.VFMapper; import org.openscience.cdk.smsd.algorithm.vflib.query.TemplateCompiler; import org.openscience.cdk.smsd.helper.MolHandler; import org.openscience.cdk.smsd.interfaces.AbstractSubGraph; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IMolecule; +import org.openscience.cdk.smsd.algorithm.vflib.map.VFMCSMapper; import org.openscience.cdk.smsd.interfaces.IMCSBase; /** @@ -90,13 +90,9 @@ public VFlibTurboHandler() { public boolean isSubgraph() { IQuery query = TemplateCompiler.compile(source); - - IMapper mapper = new VFMapper(query); - + IMapper mapper = new VFMCSMapper(query); Map vfLibSolution = mapper.getFirstMap(target); - -// System.out.println("Size of the Mapping: " + vfLibSolution.size()); - + Map atomatomMapping = new HashMap(); TreeMap indexindexMapping = new TreeMap(); @@ -120,61 +116,56 @@ public boolean isSubgraph() { atomsMCS.putAll(allAtomMCS.get(0)); firstMCS.putAll(allMCS.get(0)); } - - return (!firstMCS.isEmpty() && firstMCS.size() == source.getAtomCount()) ? true : false; + return !vfLibSolution.isEmpty() ? true : false; } /** {@inheritDoc} * - * @param source - * @param target + * @param reactant + * @param product */ @Override @TestMethod("testSet_IAtomContainer_IAtomContainer") - public void set(IAtomContainer source, IAtomContainer target) { + public void set(IAtomContainer reactant, IAtomContainer product) { - IAtomContainer mol1 = source; - IAtomContainer mol2 = target; + IAtomContainer mol1 = reactant; + IAtomContainer mol2 = product; MolHandler Reactant = new MolHandler(mol1, false); MolHandler Product = new MolHandler(mol2, false); - - set(Reactant, Product); + this.set(Reactant, Product); } /** {@inheritDoc} * - * @param source - * @param target + * + * @param Reactant + * @param Product */ - @TestMethod("testSet_IMolecule_IMolecule") - public void set(IMolecule source, IMolecule target) throws CDKException { - - IMolecule mol1 = source; - IMolecule mol2 = target; - - MolHandler Reactant = new MolHandler(mol1, false); - MolHandler Product = new MolHandler(mol2, false); - - set(Reactant, Product); + @Override + @TestMethod("testSet_MolHandler_MolHandler") + public void set(MolHandler Reactant, MolHandler Product) { + source = Reactant.getMolecule(); + target = Product.getMolecule(); } /** {@inheritDoc} * - * @param sourceMolFileName - * @param targetMolFileName + * Creates atoms new instance of SearchCliques + * @param ReactantMolFileName + * @param ProductMolFileName */ @Override @TestMethod("testSet_String_String") - public void set(String sourceMolFileName, String targetMolFileName) { + public void set(String ReactantMolFileName, String ProductMolFileName) { - String mol1 = sourceMolFileName; - String mol2 = targetMolFileName; + String mol1 = ReactantMolFileName; + String mol2 = ProductMolFileName; MolHandler Reactant = new MolHandler(mol1, false); MolHandler Product = new MolHandler(mol2, false); - set(Reactant, Product); + this.set(Reactant, Product); } /** {@inheritDoc} @@ -182,11 +173,11 @@ public void set(String sourceMolFileName, String targetMolFileName) { * @param source * @param target */ - @Override - @TestMethod("testSet_MolHandler_MolHandler") - public void set(MolHandler source, MolHandler target) { - this.source = source.getMolecule(); - this.target = target.getMolecule(); + @TestMethod("testSet_IMolecule_IMolecule") + public void set(IMolecule source, IMolecule target) throws CDKException { + MolHandler Reactant = new MolHandler(source, false); + MolHandler Product = new MolHandler(target, false); + this.set(Reactant, Product); } /** {@inheritDoc} diff --git a/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java b/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java index 18eab6cfc58..8211340d088 100644 --- a/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java +++ b/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java @@ -202,7 +202,6 @@ private void vfTurboHandler() { VFlibTurboHandler subGraphTurboSearch = null; subGraphTurboSearch = new VFlibTurboHandler(); subGraphTurboSearch.set(rMol, pMol); - clearMaps(); if (subGraphTurboSearch.isSubgraph()) { firstSolution.putAll(subGraphTurboSearch.getFirstMapping()); @@ -293,7 +292,7 @@ private void defaultAlgorithm() { } private void subStructureAlgorithm(int rBondCount, int pBondCount) { - if (rBondCount > 1 && pBondCount > 1) { + if (rBondCount > 0 && pBondCount > 0) { vfTurboHandler(); } else { singleMapping(); @@ -358,7 +357,7 @@ private void init(MolHandler Reactant, MolHandler Product, boolean removeHydroge */ @Override @TestMethod("testInit_3args_1") - public synchronized void init(IMolecule Reactant, IMolecule Product, boolean removeHydrogen) { + public void init(IMolecule Reactant, IMolecule Product, boolean removeHydrogen) { this.removeHydrogen = removeHydrogen; this.rMol = new MolHandler(Reactant, false, removeHydrogen); this.pMol = new MolHandler(Product, false, removeHydrogen); @@ -372,7 +371,7 @@ public synchronized void init(IMolecule Reactant, IMolecule Product, boolean rem */ @Override @TestMethod("testInit_3args_2") - public synchronized void init(IAtomContainer Reactant, IAtomContainer Product, boolean removeHydrogen) { + public void init(IAtomContainer Reactant, IAtomContainer Product, boolean removeHydrogen) { this.removeHydrogen = removeHydrogen; this.rMol = new MolHandler(Reactant, false, removeHydrogen); this.pMol = new MolHandler(Product, false, removeHydrogen); From 5b4f00a63b40007fb34ad941960b3ad0ad0db469 Mon Sep 17 00:00:00 2001 From: Syed Asad Rahman Date: Mon, 17 May 2010 16:09:31 +0100 Subject: [PATCH 18/21] VF Sub search turbo mode Signed-off-by: Syed Asad Rahman Signed-off-by: Rajarshi Guha --- .../cdk/smsd/algorithm/vflib/VFlibTurboHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboHandler.java b/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboHandler.java index ce4e3ba98ac..e653e1ba7d6 100644 --- a/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboHandler.java +++ b/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboHandler.java @@ -40,7 +40,7 @@ import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IMolecule; -import org.openscience.cdk.smsd.algorithm.vflib.map.VFMCSMapper; +import org.openscience.cdk.smsd.algorithm.vflib.map.VFMapper; import org.openscience.cdk.smsd.interfaces.IMCSBase; /** @@ -90,7 +90,7 @@ public VFlibTurboHandler() { public boolean isSubgraph() { IQuery query = TemplateCompiler.compile(source); - IMapper mapper = new VFMCSMapper(query); + IMapper mapper = new VFMapper(query); Map vfLibSolution = mapper.getFirstMap(target); Map atomatomMapping = new HashMap(); From ea4960cda63d4fc437a32ac42032302671144e27 Mon Sep 17 00:00:00 2001 From: Syed Asad Rahman Date: Mon, 17 May 2010 16:24:25 +0100 Subject: [PATCH 19/21] removed unwanted test case Signed-off-by: Syed Asad Rahman Signed-off-by: Rajarshi Guha --- .../org/openscience/cdk/smsd/SMSDTest.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/test/org/openscience/cdk/smsd/SMSDTest.java b/src/test/org/openscience/cdk/smsd/SMSDTest.java index 399bf3507ee..7f3c4eccdb6 100644 --- a/src/test/org/openscience/cdk/smsd/SMSDTest.java +++ b/src/test/org/openscience/cdk/smsd/SMSDTest.java @@ -472,29 +472,4 @@ public void testGetEuclideanDistance() throws Exception { assertEquals(score, smsd2.getEuclideanDistance(), 0.005); } - - /** - * Test of getComparison method, of class SMSD. - */ - @Test - public void testGetComparison() { - System.out.println("getComparison"); - SMSD smsd2 = new SMSD(Algorithm.VFLibMCS, true); - AbstractMCS expResult = new SMSD(Algorithm.CDKMCS, true); - AbstractMCS result = smsd2.getComparison(); - assertNotSame(expResult, result); - } - - /** - * Test of setComparison method, of class SMSD. - */ - @Test - public void testSetComparison() { - System.out.println("setComparison"); - AbstractMCS comparison = new SMSD(Algorithm.VFLibMCS, true); - SMSD instance = new SMSD(Algorithm.VFLibMCS, true); - instance.setComparison(comparison); - assertEquals(comparison, instance.getComparison()); - - } } From 8ac67bf99e408421d67c5bca170138e2fe4fee46 Mon Sep 17 00:00:00 2001 From: Syed Asad Rahman Date: Mon, 17 May 2010 22:09:26 +0100 Subject: [PATCH 20/21] Turbo mode MCS search added Signed-off-by: Syed Asad Rahman Signed-off-by: Rajarshi Guha --- .../factory/SubStructureSearchAlgorithms.java | 26 +++++++++++++++++++ .../cdk/smsd/interfaces/Algorithm.java | 7 +++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java b/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java index 8211340d088..bb8fb9538ff 100644 --- a/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java +++ b/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java @@ -146,6 +146,9 @@ private void chooseAlgorithm(int rBondCount, int pBondCount) { case VFLibMCS: vfLibMCSAlgorithm(rBondCount, pBondCount); break; + case TURBOMCS: + vfLibTurboMCSAlgorithm(rBondCount, pBondCount); + break; } } @@ -225,6 +228,20 @@ private void vfLibMCS() { allAtomMCS.addAll(mcs.getAllAtomMapping()); } + private void vfLibTurboMCS() { + VFlibMCSHandler mcs = null; + mcs = new VFlibMCSHandler(); + mcs.set(rMol, pMol); + mcs.searchMCS(); + + clearMaps(); + firstSolution.putAll(mcs.getFirstMapping()); + allMCS.addAll(mcs.getAllMapping()); + + firstAtomMCS.putAll(mcs.getFirstAtomMapping()); + allAtomMCS.addAll(mcs.getAllAtomMapping()); + } + private void singleMapping() { SingleMappingHandler mcs = null; @@ -307,6 +324,14 @@ private void vfLibMCSAlgorithm(int rBondCount, int pBondCount) { } } + private void vfLibTurboMCSAlgorithm(int rBondCount, int pBondCount) { + if (rBondCount >= 6 && pBondCount >= 6) { + vfLibTurboMCS(); + } else { + mcsPlusAlgorithm(); + } + } + private void setTime(boolean bondTypeFlag) { if (bondTypeFlag) { TimeOut tmo = TimeOut.getInstance(); @@ -377,6 +402,7 @@ public void init(IAtomContainer Reactant, IAtomContainer Product, boolean remove this.pMol = new MolHandler(Product, false, removeHydrogen); init(rMol, pMol, removeHydrogen); } + /** * Initialize the query and target mol via mol files * @param sourceMolFileName diff --git a/src/main/org/openscience/cdk/smsd/interfaces/Algorithm.java b/src/main/org/openscience/cdk/smsd/interfaces/Algorithm.java index 8b9f3884246..c74c1536116 100644 --- a/src/main/org/openscience/cdk/smsd/interfaces/Algorithm.java +++ b/src/main/org/openscience/cdk/smsd/interfaces/Algorithm.java @@ -41,7 +41,6 @@ * @cdk.githash * @author Syed Asad Rahman */ - @TestClass("org.openscience.cdk.smsd.interfaces.AlgorithmTest") public enum Algorithm { @@ -61,10 +60,14 @@ public enum Algorithm { * CDK UIT MCS. */ CDKMCS(3, "CDK UIT MCS"), + /** + * Turbo Mode based MCS search. + */ + TURBOMCS(4, "Turbo Mode based MCS search"), /** * Turbo Mode based Substructure search. */ - SubStructure(4, "Turbo Mode based Substructure search"); + SubStructure(5, "Turbo Mode based Substructure search"); private final int type; private final String description; From f3f809ed50e6df12281a53ca976552e9bd030b79 Mon Sep 17 00:00:00 2001 From: Syed Asad Rahman Date: Mon, 17 May 2010 22:10:38 +0100 Subject: [PATCH 21/21] Turbomode MCS search added Signed-off-by: Rajarshi Guha --- .../algorithm/vflib/VFlibTurboMCSHandler.java | 368 ++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboMCSHandler.java diff --git a/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboMCSHandler.java b/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboMCSHandler.java new file mode 100644 index 00000000000..94ecc731b43 --- /dev/null +++ b/src/main/org/openscience/cdk/smsd/algorithm/vflib/VFlibTurboMCSHandler.java @@ -0,0 +1,368 @@ +/* Copyright (C) 2009-2010 Syed Asad Rahman {asad@ebi.ac.uk} + * + * Contact: cdk-devel@lists.sourceforge.net + * + * This program 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. + * All we ask is that proper credit is given for our work, which includes + * - but is not limited to - adding the above copyright notice to the beginning + * of your source code files, and to any copyright notice that you may distribute + * with programs based on this work. + * + * This program 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 commonAtomList copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ +package org.openscience.cdk.smsd.algorithm.vflib; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.logging.Level; +import org.openscience.cdk.annotations.TestClass; +import org.openscience.cdk.annotations.TestMethod; +import org.openscience.cdk.exception.CDKException; +import org.openscience.cdk.interfaces.IMolecule; +import org.openscience.cdk.smsd.algorithm.mcgregor.McGregor; +import org.openscience.cdk.smsd.algorithm.vflib.interfaces.IMapper; +import org.openscience.cdk.smsd.algorithm.vflib.interfaces.INode; +import org.openscience.cdk.smsd.algorithm.vflib.interfaces.IQuery; +import org.openscience.cdk.smsd.algorithm.vflib.map.VFMCSMapper; +import org.openscience.cdk.smsd.algorithm.vflib.query.TemplateCompiler; +import org.openscience.cdk.smsd.helper.MolHandler; +import org.openscience.cdk.smsd.interfaces.AbstractMCSAlgorithm; +import org.openscience.cdk.interfaces.IAtom; +import org.openscience.cdk.interfaces.IAtomContainer; +import org.openscience.cdk.smsd.interfaces.IMCSBase; +import org.openscience.cdk.tools.ILoggingTool; +import org.openscience.cdk.tools.LoggingToolFactory; + +/** + * This class should be used to find MCS between query + * graph and target graph. + * + * First the algorithm runs VF lib {@link org.openscience.cdk.smsd.algorithm.vflib.map.VFMCSMapper} + * and reports MCS between + * run query and target graphs. Then these solutions are extented + * using McGregor {@link org.openscience.cdk.smsd.algorithm.mcgregor.McGregor} + * algorithm whereever required. + * + * @cdk.module smsd + * @cdk.githash + * @author Syed Asad Rahman + */ +@TestClass("org.openscience.cdk.smsd.algorithm.vflib.VFlibMCSHandlerTest") +public class VFlibTurboMCSHandler extends AbstractMCSAlgorithm implements IMCSBase { + + private static List> allAtomMCS = null; + private static Map atomsMCS = null; + private static List> allAtomMCSCopy = null; + private static Map firstMCS = null; + private static List> allMCS = null; + private static List> allMCSCopy = null; + private IAtomContainer ac1 = null; + private IAtomContainer ac2 = null; + private Map vfLibSolutions = null; + private int vfMCSSize = 0; + private final static ILoggingTool logger = + LoggingToolFactory.createLoggingTool(VFlibTurboMCSHandler.class); + + /** + * Constructor for an extended VF Algorithm for the MCS search + */ + @TestMethod("setMCSAlgorithm") + public VFlibTurboMCSHandler() { + allAtomMCS = new ArrayList>(); + allAtomMCSCopy = new ArrayList>(); + atomsMCS = new HashMap(); + firstMCS = new TreeMap(); + allMCS = new ArrayList>(); + allMCSCopy = new ArrayList>(); + } + + /** + *{@inheritDoc} + * + */ + @Override + @TestMethod("testSearchMCS") + public void searchMCS() { + searchVFMCSMappings(); + boolean flag = mcgregorFlag(); + if (flag) { + try { + searchMcGregorMapping(); + } catch (CDKException ex) { + logger.error(Level.SEVERE, null, ex); + } catch (IOException ex) { + logger.error(Level.SEVERE, null, ex); + } + + } else if (!allAtomMCSCopy.isEmpty()) { + allAtomMCS.addAll(allAtomMCSCopy); + allMCS.addAll(allMCSCopy); + } + setFirstMappings(); + } + + private void setFirstMappings() { + if (!allAtomMCS.isEmpty()) { + atomsMCS.putAll(allAtomMCS.get(0)); + firstMCS.putAll(allMCS.get(0)); + } + + } + + private boolean mcgregorFlag() { + int commonAtomCount = checkCommonAtomCount(ac1, ac2); + if (commonAtomCount > vfMCSSize && commonAtomCount > vfMCSSize) { + return true; + } + return false; + } + + /** {@inheritDoc} + * + * Set the VFLibMCS software + * + * @param reactant + * @param product + */ + @Override + @TestMethod("testSet_IAtomContainer_IAtomContainer") + public void set(IAtomContainer reactant, IAtomContainer product) { + + IAtomContainer mol1 = reactant; + IAtomContainer mol2 = product; + + MolHandler Reactant = new MolHandler(mol1, false); + MolHandler Product = new MolHandler(mol2, false); + this.set(Reactant, Product); + + } + + /** {@inheritDoc} + * + * Set the VFLib MCS software + * + * @param Reactant + * @param Product + */ + @Override + @TestMethod("testSet_MolHandler_MolHandler") + public void set(MolHandler Reactant, MolHandler Product) { + ac1 = Reactant.getMolecule(); + ac2 = Product.getMolecule(); + } + + /** {@inheritDoc} + * + * Creates atoms new instance of SearchCliques + * @param ReactantMolFileName + * @param ProductMolFileName + */ + @Override + @TestMethod("testSet_String_String") + public void set(String ReactantMolFileName, String ProductMolFileName) { + + String mol1 = ReactantMolFileName; + String mol2 = ProductMolFileName; + + MolHandler Reactant = new MolHandler(mol1, false); + MolHandler Product = new MolHandler(mol2, false); + this.set(Reactant, Product); + } + + /** {@inheritDoc} + * + * Set the VFLib MCS software + * + * @param source + * @param target + */ + @TestMethod("testSet_IMolecule_IMolecule") + public void set(IMolecule source, IMolecule target) throws CDKException { + MolHandler Reactant = new MolHandler(source, false); + MolHandler Product = new MolHandler(target, false); + this.set(Reactant, Product); + } + + private boolean hasMap(Map map, List> mapGlobal) { + + for (Map test : mapGlobal) { + if (test.equals(map)) { + return true; + } + } + return false; + } + + /** {@inheritDoc} + * + */ + @Override + @TestMethod("testGetAllAtomMapping") + public List> getAllAtomMapping() { + return Collections.unmodifiableList(allAtomMCS); + } + + /** {@inheritDoc} + */ + @Override + @TestMethod("testGetAllMapping") + public List> getAllMapping() { + return Collections.unmodifiableList(allMCS); + } + + /** {@inheritDoc} + */ + @Override + @TestMethod("testGetFirstAtomMapping") + public Map getFirstAtomMapping() { + return Collections.unmodifiableMap(atomsMCS); + } + + /** {@inheritDoc} + */ + @Override + @TestMethod("testGetFirstMapping") + public Map getFirstMapping() { + return Collections.unmodifiableMap(firstMCS); + } + + private int checkCommonAtomCount(IAtomContainer reactantMolecule, IAtomContainer productMolecule) { + ArrayList atoms = new ArrayList(); + for (int i = 0; i < reactantMolecule.getAtomCount(); i++) { + atoms.add(reactantMolecule.getAtom(i).getSymbol()); + + } + int common = 0; + for (int i = 0; i < productMolecule.getAtomCount(); i++) { + String symbol = productMolecule.getAtom(i).getSymbol(); + if (atoms.contains(symbol)) { + atoms.remove(symbol); + common++; + } + } + return common; + } + + private void searchVFMCSMappings() { + IQuery query = null; + IMapper mapper = null; + boolean RONP = false; + if (ac1.getAtomCount() <= ac2.getAtomCount()) { + query = TemplateCompiler.compile(ac1); + mapper = new VFMCSMapper(query); + vfLibSolutions = new HashMap(mapper.getFirstMap(ac2)); + RONP = true; + + } else { + query = TemplateCompiler.compile(ac2); + mapper = new VFMCSMapper(query); + vfLibSolutions = new HashMap(mapper.getFirstMap(ac1)); + RONP = false; + } + + setVFMCSMappings(RONP, query); + this.vfMCSSize = allMCSCopy.isEmpty() ? 0 : allMCSCopy.get(0).size(); + } + + private void searchMcGregorMapping() throws CDKException, IOException { + List> mappings = new ArrayList>(); + for (Map firstPassMappings : allMCSCopy) { + McGregor mgit = new McGregor(ac1, ac2, mappings); + mgit.startMcGregorIteration(mgit.getMCSSize(), firstPassMappings); //Start McGregor search + mappings = mgit.getMappings(); + mgit = null; + } + setMcGregorMappings(mappings); + } + + private void setVFMCSMappings(boolean RONP, IQuery query) { + int counter = 0; + + + Map atomatomMapping = new HashMap(); + TreeMap indexindexMapping = new TreeMap(); + + for (Map.Entry mapping : vfLibSolutions.entrySet()) { + IAtom qAtom = null; + IAtom tAtom = null; + if (RONP) { + qAtom = query.getAtom(mapping.getKey()); + tAtom = mapping.getValue(); + + } else { + tAtom = query.getAtom(mapping.getKey()); + qAtom = mapping.getValue(); + } + + Integer qIndex = Integer.valueOf(ac1.getAtomNumber(qAtom)); + Integer tIndex = Integer.valueOf(ac2.getAtomNumber(tAtom)); + if (qIndex != null && tIndex != null) { + atomatomMapping.put(qAtom, tAtom); + indexindexMapping.put(qIndex, tIndex); + } else { + try { + throw new CDKException("Atom index pointing to NULL"); + } catch (CDKException ex) { + logger.error(Level.SEVERE, null, ex); + } + } + + } + if (!atomatomMapping.isEmpty()) { + allAtomMCSCopy.add(counter, atomatomMapping); + allMCSCopy.add(counter, indexindexMapping); + counter++; + } + + } + + private void setMcGregorMappings(List> mappings) throws CDKException { + int counter = 0; + for (List mapping : mappings) { + + Map atomatomMapping = new HashMap(); + Map indexindexMapping = new TreeMap(); + + for (int index = 0; index < mapping.size(); index += 2) { + IAtom qAtom = null; + IAtom tAtom = null; + + qAtom = ac1.getAtom(mapping.get(index)); + tAtom = ac2.getAtom(mapping.get(index + 1)); + + + Integer qIndex = mapping.get(index); + Integer tIndex = mapping.get(index + 1); + + + if (qIndex != null && tIndex != null) { + atomatomMapping.put(qAtom, tAtom); + indexindexMapping.put(qIndex, tIndex); + } else { + throw new CDKException("Atom index pointing to NULL"); + } + } + + if (!atomatomMapping.isEmpty() && !hasMap(indexindexMapping, allMCS)) { + allAtomMCS.add(counter, atomatomMapping); + allMCS.add(counter, indexindexMapping); + counter++; + } + } + } +}