diff --git a/build.xml b/build.xml index 1d1eb02cb4f..53c6271f800 100644 --- a/build.xml +++ b/build.xml @@ -293,14 +293,16 @@ depends="init, check, runDoclet"/> + depends="check, dist.init"> + + + @@ -619,6 +621,7 @@ + @@ -667,6 +670,7 @@ + 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/CDKConstants.java b/src/main/org/openscience/cdk/CDKConstants.java index 199cb49a14b..3bd62a40c4d 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. */ @@ -295,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/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/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/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/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/main/org/openscience/cdk/io/MDLReader.java b/src/main/org/openscience/cdk/io/MDLReader.java index b4a43fd3d30..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."); @@ -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..c8625292139 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."); @@ -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"); @@ -619,7 +623,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..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(); } @@ -322,7 +330,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 +357,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; 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); /* 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/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(); 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..e653e1ba7d6 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.VFMapper; 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); - 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/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++; + } + } + } +} diff --git a/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java b/src/main/org/openscience/cdk/smsd/factory/SubStructureSearchAlgorithms.java index 18eab6cfc58..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; } } @@ -202,7 +205,6 @@ private void vfTurboHandler() { VFlibTurboHandler subGraphTurboSearch = null; subGraphTurboSearch = new VFlibTurboHandler(); subGraphTurboSearch.set(rMol, pMol); - clearMaps(); if (subGraphTurboSearch.isSubgraph()) { firstSolution.putAll(subGraphTurboSearch.getFirstMapping()); @@ -226,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; @@ -293,7 +309,7 @@ private void defaultAlgorithm() { } private void subStructureAlgorithm(int rBondCount, int pBondCount) { - if (rBondCount > 1 && pBondCount > 1) { + if (rBondCount > 0 && pBondCount > 0) { vfTurboHandler(); } else { singleMapping(); @@ -308,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(); @@ -358,7 +382,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,12 +396,13 @@ 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); 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; 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/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/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/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-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/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/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/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/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 { diff --git a/src/test/org/openscience/cdk/io/MDLReaderTest.java b/src/test/org/openscience/cdk/io/MDLReaderTest.java index 526e5087478..48ff5936a4b 100644 --- a/src/test/org/openscience/cdk/io/MDLReaderTest.java +++ b/src/test/org/openscience/cdk/io/MDLReaderTest.java @@ -31,10 +31,13 @@ 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.exception.CDKException; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IBond; @@ -193,4 +196,40 @@ 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()); + } + + + @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)); + } + + @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 217120a1ca2..ebe95e00566 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()); } /** @@ -754,4 +755,45 @@ 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); + } + + @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)); + } + + @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()); + } + } 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 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/smiles/SmilesParserTest.java b/src/test/org/openscience/cdk/smiles/SmilesParserTest.java index d8a5823468a..0a08a7a3251 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; @@ -943,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 @@ -1845,5 +1861,263 @@ 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() 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"); + 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()); + } + + @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()); + } + } + } } 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()); - - } } 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