Skip to content

Commit

Permalink
Use newer SMARTS/Substructure API calls.
Browse files Browse the repository at this point in the history
Signed-off-by: Egon Willighagen <egonw@users.sourceforge.net>
  • Loading branch information
johnmay authored and egonw committed May 4, 2015
1 parent b0c9468 commit 1d76286
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.openscience.cdk.pharmacophore;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -29,14 +30,21 @@

import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.DefaultChemObjectBuilder;
import org.openscience.cdk.aromaticity.Aromaticity;
import org.openscience.cdk.aromaticity.ElectronDonation;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.geometry.GeometryUtil;
import org.openscience.cdk.graph.Cycles;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.isomorphism.Mappings;
import org.openscience.cdk.isomorphism.Pattern;
import org.openscience.cdk.isomorphism.UniversalIsomorphismTester;
import org.openscience.cdk.isomorphism.VentoFoggia;
import org.openscience.cdk.isomorphism.matchers.IQueryAtom;
import org.openscience.cdk.isomorphism.matchers.IQueryAtomContainer;
import org.openscience.cdk.isomorphism.matchers.smarts.SmartsMatchers;
import org.openscience.cdk.isomorphism.mcss.RMap;
import org.openscience.cdk.smiles.smarts.SMARTSQueryTool;
import org.openscience.cdk.tools.ILoggingTool;
Expand Down Expand Up @@ -146,6 +154,9 @@ public class PharmacophoreMatcher {
private IAtomContainer pharmacophoreMolecule = null;

private List<HashMap<IBond, IBond>> bondMapHash = null;

private final Aromaticity arom = new Aromaticity(ElectronDonation.daylight(),
Cycles.or(Cycles.all(), Cycles.relevant()));

/**
* An empty constructor.
Expand Down Expand Up @@ -373,18 +384,20 @@ public void setPharmacophoreQuery(PharmacophoreQuery query) {
*/
private IAtomContainer getPharmacophoreMolecule(IAtomContainer input) throws CDKException {

SMARTSQueryTool sqt = new SMARTSQueryTool("C", input.getBuilder());
// XXX: prepare query, to be moved
prepareInput(input);

IAtomContainer pharmacophoreMolecule = input.getBuilder().newInstance(IAtomContainer.class);

// lets loop over each pcore query atom
Set<String> matched = new HashSet<>();
final Set<String> matched = new HashSet<>();

logger.debug("Converting [" + input.getProperty(CDKConstants.TITLE) + "] to a pcore molecule");


// lets loop over each pcore query atom
for (IAtom atom : pharmacophoreQuery.atoms()) {
PharmacophoreQueryAtom qatom = (PharmacophoreQueryAtom) atom;
String smarts = qatom.getSmarts();

final PharmacophoreQueryAtom qatom = (PharmacophoreQueryAtom) atom;
final String smarts = qatom.getSmarts();
// a pcore query might have multiple instances of a given pcore atom (say
// 2 hydrophobic groups separated by X unit). In such a case we want to find
// the atoms matching the pgroup SMARTS just once, rather than redoing the
Expand All @@ -393,28 +406,28 @@ private IAtomContainer getPharmacophoreMolecule(IAtomContainer input) throws CDK
continue;

// see if the smarts for this pcore query atom gets any matches
// in our query molecule. If so, then cllect each set of
// in our query molecule. If so, then collect each set of
// matching atoms and for each set make a new pcore atom and
// add it to the pcore atom container object

// Note that we allow a special form of SMARTS where the | operator
// represents logical or of multi-atom groups (as opposed to ','
// which is for single atom matches)
String[] subSmarts = smarts.split("\\|");

for (String subSmart : subSmarts) {
sqt.setSmarts(subSmart);
if (sqt.matches(input)) {
List<List<Integer>> mappings = sqt.getUniqueMatchingAtoms();
for (List<Integer> atomIndices : mappings) {
Point3d coords = getEffectiveCoordinates(input, atomIndices);
PharmacophoreAtom patom = new PharmacophoreAtom(smarts, qatom.getSymbol(), coords);
patom.setMatchingAtoms(intIndices(atomIndices));
if (!pharmacophoreMolecule.contains(patom)) pharmacophoreMolecule.addAtom(patom);
}
int count = 0;
for (final IQueryAtomContainer query : qatom.getCompiledSmarts()) {
// create the lazy mappings iterator
final Mappings mappings = Pattern.findSubstructure(query)
.matchAll(input)
.uniqueAtoms();

for (final int[] mapping : mappings) {
final Point3d coords = getEffectiveCoordinates(input, mapping);
PharmacophoreAtom patom = new PharmacophoreAtom(smarts, qatom.getSymbol(), coords);
// n.b. mapping[] is reusued for efficient to need to make an explict copy
patom.setMatchingAtoms(Arrays.copyOf(mapping, mapping.length));
if (!pharmacophoreMolecule.contains(patom))
pharmacophoreMolecule.addAtom(patom);
count++;
}
}
logger.debug("\tFound " + sqt.getUniqueMatchingAtoms().size() + " unique matches for " + smarts);
logger.debug("\tFound " + count + " unique matches for " + smarts);
}

// now that we have added all the pcore atoms to the container
Expand Down Expand Up @@ -498,6 +511,11 @@ private IAtomContainer getPharmacophoreMolecule(IAtomContainer input) throws CDK
return pharmacophoreMolecule;
}

private void prepareInput(IAtomContainer input) throws CDKException {
SmartsMatchers.prepare(input, true);
arom.apply(input);
}

private boolean hasDistanceConstraints(IQueryAtomContainer query) {
for (IBond bond : query.bonds()) {
if (bond instanceof PharmacophoreQueryBond) return true;
Expand Down Expand Up @@ -533,6 +551,20 @@ private Point3d getEffectiveCoordinates(IAtomContainer atomContainer, List<Integ
ret.z /= atomIndices.size();
return ret;
}

private Point3d getEffectiveCoordinates(IAtomContainer atomContainer, int[] atomIndices) {
Point3d ret = new Point3d(0, 0, 0);
for (int i : atomIndices) {
Point3d coord = atomContainer.getAtom(i).getPoint3d();
ret.x += coord.x;
ret.y += coord.y;
ret.z += coord.z;
}
ret.x /= atomIndices.length;
ret.y /= atomIndices.length;
ret.z /= atomIndices.length;
return ret;
}

private List<List<PharmacophoreAtom>> getAtomMappings(List<List<RMap>> bondMapping, IAtomContainer atomContainer) {
List<List<PharmacophoreAtom>> atomMapping = new ArrayList<List<PharmacophoreAtom>>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import org.openscience.cdk.Atom;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.isomorphism.matchers.IQueryAtom;
import org.openscience.cdk.isomorphism.matchers.IQueryAtomContainer;
import org.openscience.cdk.smiles.smarts.parser.SMARTSParser;

/**
* Represents a query pharmacophore group.
Expand All @@ -41,6 +43,7 @@
public class PharmacophoreQueryAtom extends Atom implements IQueryAtom {

private String smarts;
private IQueryAtomContainer[] compiledSmarts;

/**
* Creat a new query pharmacophore group
Expand All @@ -51,6 +54,13 @@ public class PharmacophoreQueryAtom extends Atom implements IQueryAtom {
public PharmacophoreQueryAtom(String symbol, String smarts) {
setSymbol(symbol);
this.smarts = smarts;
// Note that we allow a special form of SMARTS where the | operator
// represents logical or of multi-atom groups (as opposed to ','
// which is for single atom matches)
String[] subSmarts = smarts.split("\\|");
this.compiledSmarts = new IQueryAtomContainer[subSmarts.length];
for (int i = 0; i < compiledSmarts.length; i++)
compiledSmarts[i] = SMARTSParser.parse(subSmarts[i], null);
}

/**
Expand All @@ -62,6 +72,14 @@ public String getSmarts() {
return smarts;
}

/**
* Accessed the compiled SMARTS for this pcore query atom.
* @return compiled SMARTS
*/
IQueryAtomContainer[] getCompiledSmarts() {
return compiledSmarts;
}

/**
* Checks whether this query atom matches a target atom.
* <p/>
Expand Down

0 comments on commit 1d76286

Please sign in to comment.