Skip to content

Commit

Permalink
Using the new aromaticity model.
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 Dec 10, 2013
1 parent 4f83c28 commit 59bf1a8
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 19 deletions.
66 changes: 55 additions & 11 deletions src/main/org/openscience/cdk/smiles/smarts/SMARTSQueryTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@
import java.util.Set;
import java.util.TreeSet;

import com.google.common.base.Preconditions;
import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.annotations.TestClass;
import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.aromaticity.Aromaticity;
import org.openscience.cdk.aromaticity.CDKHueckelAromaticityDetector;
import org.openscience.cdk.aromaticity.ElectronDonation;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.graph.Cycles;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
Expand All @@ -55,6 +59,8 @@
import org.openscience.cdk.tools.LoggingToolFactory;
import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* This class provides a easy to use wrapper around SMARTS matching functionality. <p/> User code that wants to do
* SMARTS matching should use this rather than using SMARTSParser (and UniversalIsomorphismTester) directly. Example
Expand Down Expand Up @@ -173,6 +179,22 @@ private enum RingSet {

private List<Set<Integer>> matchingAtoms = null;

/**
* Aromaticity perception - dealing with SMARTS we should use the Daylight
* model. This can be set to a different model using {@link #setAromaticity(Aromaticity)}.
*/
private Aromaticity aromaticity = new Aromaticity(ElectronDonation.daylight(),
Cycles.allOrVertexShort());

/**
* Logical flag indicates whether the aromaticity model should be skipped.
* Generally this should be left as false to ensure the structures being
* matched are all treated the same. The flag can however be turned off if
* the molecules being tests are known to all have the same aromaticity
* model.
*/
private boolean skipAromaticity = false;

// a simplistic cache to store parsed SMARTS queries
private int MAX_ENTRIES = 20;
Map<String, QueryAtomContainer> cache = new LinkedHashMap<String, QueryAtomContainer>(MAX_ENTRIES + 1, .75F, true) {
Expand Down Expand Up @@ -245,12 +267,31 @@ public void useEssentialRings() {
}

/**
* Set the aromaticity perception to use.
* Set the aromaticity perception to use. Different aromaticity models
* may required certain attributes to be set (e.g. atom typing). These
* will not be automatically configured and should be preset before matching.
*
* <blockquote><pre>
* SMARTSQueryTool sqt = new SMARTSQueryTool(...);
* sqt.setAromaticity(new Aromaticity(ElectronDonation.cdk(),
* Cycles.cdkAromaticSet));
* for (IAtomContainer molecule : molecules) {
*
* // CDK Aromatic model needs atom types
* AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(molecule);
*
* sqt.matches(molecule);
* }
* </pre></blockquote>
*
* @param aromaticity the new aromaticity perception
* @see ElectronDonation
* @see Cycles
*/
@TestMethod("setAromaticity,nullAromaticity")
public void setAromaticity(Aromaticity aromaticity) {
this.aromaticity = aromaticity;
this.aromaticity = checkNotNull(aromaticity,
"aromaticity was not provided");
}

/**
Expand Down Expand Up @@ -317,7 +358,8 @@ public boolean matches(IAtomContainer atomContainer, boolean forceInitialization

if (this.atomContainer == atomContainer) {
if (forceInitialization) initializeMolecule();
} else {
}
else {
this.atomContainer = atomContainer;
initializeMolecule();
}
Expand All @@ -338,7 +380,8 @@ public boolean matches(IAtomContainer atomContainer, boolean forceInitialization
matchingAtoms.add(tmp);
}
}
} else {
}
else {
List<List<RMap>> bondMapping = new UniversalIsomorphismTester().getSubgraphMaps(this.atomContainer, query);
matchingAtoms = matchedAtoms(bondMapping, this.atomContainer);
}
Expand Down Expand Up @@ -368,7 +411,7 @@ public int countMatches() {
public List<List<Integer>> getMatchingAtoms() {
return copyOf(matchingAtoms);
}

/**
* Get the atoms in the target molecule that match the query pattern. <p/> Since there may be multiple matches, the
* return value is a List of List objects. Each List object contains the unique set of indices of the atoms in the
Expand All @@ -378,13 +421,13 @@ public List<List<Integer>> getMatchingAtoms() {
*/
@TestMethod("testUniqueQueries")
public List<List<Integer>> getUniqueMatchingAtoms() {
return copyOf(new HashSet<Collection<Integer>>(matchingAtoms));
return copyOf(new HashSet<Collection<Integer>>(matchingAtoms));
}

/**
* Copy the matched atoms to a List or Lists. Allows us to keep our matching
* without others changing it.
*
*
* @param org original matching
* @return matching which is the list or lists
*/
Expand All @@ -411,11 +454,12 @@ private void initializeMolecule() throws CDKException {
SmartsMatchers.prepare(atomContainer,
query.getFlag(CDKConstants.ISINRING));

// check for aromaticity
// providing skip aromaticity has not be set apply the desired
// aromaticity model
try {
AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(atomContainer);
CDKHueckelAromaticityDetector.detectAromaticity(atomContainer);

if (!skipAromaticity) {
aromaticity.apply(atomContainer);
}
} catch (CDKException e) {
logger.debug(e.toString());
throw new CDKException(e.toString(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
package org.openscience.cdk.smiles.smarts;

import static java.util.Collections.sort;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -29,10 +31,13 @@
import org.junit.Test;
import org.openscience.cdk.CDKTestCase;
import org.openscience.cdk.DefaultChemObjectBuilder;
import org.openscience.cdk.aromaticity.Aromaticity;
import org.openscience.cdk.aromaticity.CDKHueckelAromaticityDetector;
import org.openscience.cdk.aromaticity.DoubleBondAcceptingAromaticityDetector;
import org.openscience.cdk.aromaticity.ElectronDonation;
import org.openscience.cdk.config.Elements;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.graph.Cycles;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IAtomContainer;
Expand Down Expand Up @@ -67,7 +72,7 @@ public void testQueryTool() throws Exception {
SMARTSQueryTool querytool = new SMARTSQueryTool("O=CO", DefaultChemObjectBuilder.getInstance());

boolean status = querytool.matches(atomContainer);
Assert.assertTrue(status);
assertTrue(status);

int nmatch = querytool.countMatches();
Assert.assertEquals(2, nmatch);
Expand Down Expand Up @@ -103,7 +108,7 @@ public void testQueryToolSingleAtomCase() throws Exception {
SMARTSQueryTool querytool = new SMARTSQueryTool("C", DefaultChemObjectBuilder.getInstance());

boolean status = querytool.matches(atomContainer);
Assert.assertTrue(status);
assertTrue(status);

int nmatch = querytool.countMatches();
Assert.assertEquals(8, nmatch);
Expand All @@ -116,14 +121,14 @@ public void testQueryToolResetSmarts() throws Exception {
SMARTSQueryTool querytool = new SMARTSQueryTool("C", DefaultChemObjectBuilder.getInstance());

boolean status = querytool.matches(atomContainer);
Assert.assertTrue(status);
assertTrue(status);

int nmatch = querytool.countMatches();
Assert.assertEquals(8, nmatch);

querytool.setSmarts("CC");
status = querytool.matches(atomContainer);
Assert.assertTrue(status);
assertTrue(status);

nmatch = querytool.countMatches();
Assert.assertEquals(18, nmatch);
Expand All @@ -140,7 +145,7 @@ public void testUniqueQueries() throws Exception {
SMARTSQueryTool querytool = new SMARTSQueryTool("c1ccccc1", DefaultChemObjectBuilder.getInstance());

boolean status = querytool.matches(atomContainer);
Assert.assertTrue(status);
assertTrue(status);

int nmatch = querytool.countMatches();
Assert.assertEquals(24, nmatch);
Expand All @@ -157,7 +162,7 @@ public void testQuery() throws Exception {
SMARTSQueryTool querytool = new SMARTSQueryTool("c12ccccc1cccc2", DefaultChemObjectBuilder.getInstance());

boolean status = querytool.matches(atomContainer);
Assert.assertTrue(status);
assertTrue(status);

int nmatch = querytool.countMatches();
Assert.assertEquals(4, nmatch);
Expand Down Expand Up @@ -187,7 +192,7 @@ public void testIndoleAgainstItself() throws Exception {
indole = smilesParser.parseSmiles(indoleSmiles);

SMARTSQueryTool querytool = new SMARTSQueryTool(indoleSmiles, DefaultChemObjectBuilder.getInstance());
Assert.assertTrue(querytool.matches(indole));
assertTrue(querytool.matches(indole));
}

/**
Expand All @@ -203,7 +208,34 @@ public void testMethane() throws Exception {

SMARTSQueryTool sqt = new SMARTSQueryTool("CC", DefaultChemObjectBuilder.getInstance());
boolean matches = sqt.matches(methane);
Assert.assertFalse(matches);
assertFalse(matches);

}

@Test(expected = NullPointerException.class)
public void nullAromaticity() {
SMARTSQueryTool sqt = new SMARTSQueryTool("CC", DefaultChemObjectBuilder.getInstance());
sqt.setAromaticity(null);
}

@Test
public void setAromaticity() throws Exception {
SMARTSQueryTool sqt = new SMARTSQueryTool("[a]", DefaultChemObjectBuilder.getInstance());

IAtomContainer furan = smiles("O1C=CC=C1");

AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(furan);

sqt.setAromaticity(new Aromaticity(ElectronDonation.cdk(),
Cycles.mcb()));
assertTrue(sqt.matches(furan, true));

sqt.setAromaticity(new Aromaticity(ElectronDonation.piBonds(),
Cycles.mcb()));
assertFalse(sqt.matches(furan, true));
}

static IAtomContainer smiles(String smi) throws Exception {
return new SmilesParser(SilentChemObjectBuilder.getInstance()).parseSmiles(smi);
}
}

0 comments on commit 59bf1a8

Please sign in to comment.