Skip to content

Commit

Permalink
Added a 'map' method on all IStereoElements. The map method allows a …
Browse files Browse the repository at this point in the history
…stereo element on one container/molecule to mapped to a stereo element on another. This mapping is achieved using two symbol tables, one for atoms and one for bonds. All methods are null safe and the mapping will not fail if any content in the stereo elements is null. The mapping simplifies the cloning of molecules/atom containers but could also be used when comparing isomorphic graphs.
  • Loading branch information
johnmay committed Nov 1, 2012
1 parent 96d6c1a commit 9c5670b
Show file tree
Hide file tree
Showing 14 changed files with 908 additions and 4 deletions.
29 changes: 28 additions & 1 deletion src/main/org/openscience/cdk/AtomParity.java
Expand Up @@ -28,10 +28,14 @@
package org.openscience.cdk;

import java.io.Serializable;
import java.util.Map;

import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomParity;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IStereoElement;

/**
* Represents the concept of an atom parity identifying the stereochemistry
Expand Down Expand Up @@ -151,7 +155,30 @@ public Object clone() throws CloneNotSupportedException {
clone.neighbors[3] = (IAtom)(neighbors[3].clone());
return clone;
}


/**
* @inheritDoc
*/
@TestMethod("testMap_Map_Map,testMap_Null_Map,testMap_Map_Map_NullElement,testMap_Map_Map_EmptyMapping")
@Override
public IAtomParity map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds) {

if(atoms == null) // not using bond mapping
throw new IllegalArgumentException("null atom mapping provided");

// could map neighbours with a for loop but we need to pull individuals
// atoms for the constructor
return new AtomParity(
centralAtom != null ? atoms.get(centralAtom) : null,
neighbors[0] != null ? atoms.get(neighbors[0]) : null,
neighbors[1] != null ? atoms.get(neighbors[1]) : null,
neighbors[2] != null ? atoms.get(neighbors[2]) : null,
neighbors[3] != null ? atoms.get(neighbors[3]) : null,
parity
);

}

public IChemObjectBuilder getBuilder() {
return DefaultChemObjectBuilder.getInstance();
}
Expand Down
36 changes: 35 additions & 1 deletion src/main/org/openscience/cdk/debug/DebugAtomParity.java
Expand Up @@ -21,11 +21,16 @@
package org.openscience.cdk.debug;

import org.openscience.cdk.AtomParity;
import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomParity;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.tools.ILoggingTool;
import org.openscience.cdk.tools.LoggingToolFactory;

import java.util.Map;
import java.util.regex.Pattern;

/**
* Debugging data class.
*
Expand All @@ -36,6 +41,7 @@
public class DebugAtomParity extends AtomParity
implements IAtomParity {


private static final long serialVersionUID = 6305428844566539948L;

public DebugAtomParity(IAtom centralAtom, IAtom first, IAtom second, IAtom third, IAtom fourth, int parity) {
Expand All @@ -55,7 +61,35 @@ public IAtom[] getSurroundingAtoms() {
return super.getSurroundingAtoms();
}

public int getParity() {
/**
* @inheritDoc
*/
@TestMethod("testMap_Map_Map,testMap_Null_Map,testMap_Map_Map_NullElement,testMap_Map_Map_EmptyMapping")
@Override
public IAtomParity map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds) {

logger.debug("Mapping atom parity: " + atoms);

if(atoms == null) // not using bond mapping
throw new IllegalArgumentException("null atom mapping provided");

IAtom[] neighbors = getSurroundingAtoms();

// could map neighbours with a for loop but we need to pull individuals
// atoms for the constructor
return new DebugAtomParity(
getAtom() != null ? atoms.get(getAtom()) : null,
neighbors[0] != null ? atoms.get(neighbors[0]) : null,
neighbors[1] != null ? atoms.get(neighbors[1]) : null,
neighbors[2] != null ? atoms.get(neighbors[2]) : null,
neighbors[3] != null ? atoms.get(neighbors[3]) : null,
getParity()
);

}


public int getParity() {
logger.debug("Getting atom parity: ", super.getParity());
return super.getParity();
}
Expand Down
11 changes: 10 additions & 1 deletion src/main/org/openscience/cdk/interfaces/IAtomParity.java
Expand Up @@ -22,6 +22,8 @@
*/
package org.openscience.cdk.interfaces;

import java.util.Map;

/**
* Represents the concept of an atom parity identifying the stereochemistry
* around an atom, given four neighbouring atoms.
Expand Down Expand Up @@ -58,7 +60,14 @@ public interface IAtomParity extends IStereoElement {
* @return The parity value
*/
public int getParity();


/**
* @inheritDoc
*/
@Override
public IAtomParity map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds);


}


Expand Down
Expand Up @@ -22,6 +22,8 @@
*/
package org.openscience.cdk.interfaces;

import java.util.Map;

/**
* Stereochemistry specification for double bond stereochemistry. The data model defines the double
* atoms and two ligands attached to those two atoms, linearly connected with the double bond in the
Expand Down Expand Up @@ -65,4 +67,10 @@ public enum Conformation {
* @return the {@link Conformation} for this stereo element.
*/
public Conformation getStereo();

/**
* @inheritDoc
*/
@Override
public IDoubleBondStereochemistry map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds);
}
19 changes: 19 additions & 0 deletions src/main/org/openscience/cdk/interfaces/IStereoElement.java
Expand Up @@ -22,6 +22,8 @@
*/
package org.openscience.cdk.interfaces;

import java.util.Map;

/**
* 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
Expand All @@ -35,6 +37,23 @@
*/
public interface IStereoElement extends ICDKObject {

/**
* Map the atoms/bonds in this instance to a new stereo element using the
* provided atom/bond mapping. This allows the stereo element to be transferred
* between a cloned or aligned (i.e. isomorphic) chemical graph.
* <p/>
* If no mapping is found for a given atom or bond it is replaced with a null
* reference. However the provided atom and bonds maps must not be null.
*
* @param atoms non-null atom mapping, used to convert the original atoms to their mapped
* counterparts
* @param bonds non-null bond mapping, used to convert the original bonds to their mapped
* counterparts
* @return a new stereo element in the same configuration but with atoms/bonds
* replaced with their mapped equivalence.
*/
public IStereoElement map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds);

}


Expand Down
10 changes: 10 additions & 0 deletions src/main/org/openscience/cdk/interfaces/ITetrahedralChirality.java
Expand Up @@ -22,6 +22,8 @@
*/
package org.openscience.cdk.interfaces;

import java.util.Map;

/**
* 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
Expand Down Expand Up @@ -63,4 +65,12 @@ public enum Stereo {
*/
public Stereo getStereo();


/**
* @inheritDoc
*/
@Override
public ITetrahedralChirality map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds);


}
29 changes: 28 additions & 1 deletion src/main/org/openscience/cdk/silent/AtomParity.java
Expand Up @@ -23,9 +23,12 @@
package org.openscience.cdk.silent;

import java.io.Serializable;
import java.util.Map;

import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomParity;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;

/**
Expand Down Expand Up @@ -146,7 +149,31 @@ public Object clone() throws CloneNotSupportedException {
clone.neighbors[3] = (IAtom)(neighbors[3].clone());
return clone;
}


/**
* @inheritDoc
*/
@TestMethod("testMap_Map_Map,testMap_Null_Map,testMap_Map_Map_NullElement,testMap_Map_Map_EmptyMapping")
@Override
public IAtomParity map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds) {

if(atoms == null) // not using bond mapping
throw new IllegalArgumentException("null atom mapping provided");

// could map neighbours with a for loop but we need to pull individuals
// atoms for the constructor
return new AtomParity(
centralAtom != null ? atoms.get(centralAtom) : null,
neighbors[0] != null ? atoms.get(neighbors[0]) : null,
neighbors[1] != null ? atoms.get(neighbors[1]) : null,
neighbors[2] != null ? atoms.get(neighbors[2]) : null,
neighbors[3] != null ? atoms.get(neighbors[3]) : null,
parity
);

}


public IChemObjectBuilder getBuilder() {
return SilentChemObjectBuilder.getInstance();
}
Expand Down
22 changes: 22 additions & 0 deletions src/main/org/openscience/cdk/stereo/DoubleBondStereochemistry.java
Expand Up @@ -24,9 +24,13 @@

import org.openscience.cdk.annotations.TestClass;
import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IDoubleBondStereochemistry;
import org.openscience.cdk.interfaces.IStereoElement;

import java.util.Map;

/**
* Stereochemistry specification for double bonds. See {@link IDoubleBondStereochemistry} for
Expand Down Expand Up @@ -93,4 +97,22 @@ public Conformation getStereo() {
return this.stereo;
}

@TestMethod("testMap_Map_Map,testMap_Null_Map,testMap_Map_Map_NullElement,testMap_Map_Map_EmptyMapping")
@Override
public IDoubleBondStereochemistry map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds) {

if(bonds == null)
throw new IllegalArgumentException("null bond mapping provided");

// map the double bond and the connected ligand bonds
IBond doubleBond = stereoBond != null ? bonds.get(stereoBond) : null;
IBond[] connected = new IBond[ligandBonds.length];

for(int i = 0; i < connected.length; i++){
if(ligandBonds[i] != null)
connected[i] = bonds.get(ligandBonds[i]);
}

return new DoubleBondStereochemistry(doubleBond, connected, stereo);
}
}
29 changes: 29 additions & 0 deletions src/main/org/openscience/cdk/stereo/TetrahedralChirality.java
Expand Up @@ -25,9 +25,13 @@
import org.openscience.cdk.annotations.TestClass;
import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IStereoElement;
import org.openscience.cdk.interfaces.ITetrahedralChirality;

import java.util.Map;

/**
* Stereochemistry specification for quadrivalent atoms. See {@link ITetrahedralChirality} for
* further details.
Expand Down Expand Up @@ -107,6 +111,31 @@ public IChemObjectBuilder getBuilder() {
return builder;
}

/**
* @inheritDoc
*/
@TestMethod("testMap_Map_Map,testMap_Null_Map,testMap_Map_Map_NullElement,testMap_Map_Map_EmptyMapping")
@Override
public ITetrahedralChirality map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds) {

// don't check bond map as we don't use it
if(atoms == null)
throw new IllegalArgumentException("null atom mapping provided");

// convert the chiral atom and it's ligands to their equivalent
IAtom chiral = chiralAtom != null ? atoms.get(chiralAtom) : null;
IAtom[] ligands = new IAtom[ligandAtoms.length];

for (int i = 0; i < ligands.length; i++) {
if(ligandAtoms[i] != null)
ligands[i] = atoms.get(ligandAtoms[i]);
}

// create a new tetrahedral instance with the mapped chiral atom and ligands
return new TetrahedralChirality(chiral, ligands, stereo);

}

/**
* Returns a {@link String} representation of this chiral element.
*
Expand Down

0 comments on commit 9c5670b

Please sign in to comment.