From 55a80e738e91cf8da9fdbf6e2a1a3dc2011a4974 Mon Sep 17 00:00:00 2001 From: John May Date: Tue, 14 Feb 2017 11:00:15 +0000 Subject: [PATCH] Still quite slow but improved API to allow InChI options to be passed in. We can't remove the old method that forces slow execution but it has now be deprecated. New tests added to demonstrate correct exectution. --- .../cdk/tautomers/InChITautomerGenerator.java | 54 +++++++++++++++++-- .../tautomers/InChITautomerGeneratorTest.java | 41 ++++++++++++++ 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/tool/tautomer/src/main/java/org/openscience/cdk/tautomers/InChITautomerGenerator.java b/tool/tautomer/src/main/java/org/openscience/cdk/tautomers/InChITautomerGenerator.java index 7ed022aa39..7f78366778 100644 --- a/tool/tautomer/src/main/java/org/openscience/cdk/tautomers/InChITautomerGenerator.java +++ b/tool/tautomer/src/main/java/org/openscience/cdk/tautomers/InChITautomerGenerator.java @@ -31,7 +31,6 @@ import org.openscience.cdk.graph.invariant.InChINumbersTools; import org.openscience.cdk.inchi.InChIGenerator; import org.openscience.cdk.inchi.InChIGeneratorFactory; -import org.openscience.cdk.inchi.InChIToStructure; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IAtomType; @@ -56,12 +55,43 @@ * @cdk.module tautomer * @cdk.githash */ -public class InChITautomerGenerator { +public final class InChITautomerGenerator { private final static ILoggingTool LOGGER = LoggingToolFactory.createLoggingTool(InChITautomerGenerator.class); private static final SmilesGenerator CANSMI = new SmilesGenerator(SmiFlavor.Canonical); + /** Generate InChI with -KET (keto-enol tautomers) option. */ + public static final int KETO_ENOL = 0x1; + + /** Generate InChI with -15T (1,5-shift tautomers) option. */ + public static final int ONE_FIVE_SHIFT = 0x2; + + private final int flags; + + /** + * Create a tautomer generator specifygin whether to enable, keto-enol (-KET) and 1,5-shifts (-15T). + * + *
{@code
+     * // enabled -KET option
+     * InChITautomerGenerator tautgen = new InChITautomerGenerator(InChITautomerGenerator.KETO_ENOL);
+     * // enabled both -KET and -15T
+     * InChITautomerGenerator tautgen = new InChITautomerGenerator(InChITautomerGenerator.KETO_ENOL | InChITautomerGenerator.ONE_FIVE_SHIFT);
+     * }
+ * + * @param flags the options + */ + public InChITautomerGenerator(int flags) { + this.flags = flags; + } + + /** + * Create a tautomer generator, keto-enol (-KET) and 1,5-shifts (-15T) are disabled. + */ + public InChITautomerGenerator() { + this(0); + } + /** * Public method to get tautomers for an input molecule, based on the InChI which will be calculated by JNI-InChI. * @param mol molecule for which to generate tautomers @@ -71,7 +101,13 @@ public class InChITautomerGenerator { */ public List getTautomers(IAtomContainer mol) throws CDKException, CloneNotSupportedException { - InChIGenerator gen = InChIGeneratorFactory.getInstance().getInChIGenerator(mol, ""); + String opt = ""; + if ((flags & KETO_ENOL) != 0) + opt += " -KET"; + if ((flags & ONE_FIVE_SHIFT) != 0) + opt += " -15T"; + + InChIGenerator gen = InChIGeneratorFactory.getInstance().getInChIGenerator(mol, opt); String inchi = gen.getInchi(); String aux = gen.getAuxInfo(); @@ -84,6 +120,18 @@ public List getTautomers(IAtomContainer mol) throws CDKException return getTautomers(mol, inchi, amap); } + /** + * This method is slower than recalculating the InChI with {@link #getTautomers(IAtomContainer)} as the mapping + * between the two can be found more efficiently. + * + * @param mol + * @param inchi + * @return + * @throws CDKException + * @throws CloneNotSupportedException + * @deprecated use {@link #getTautomers(IAtomContainer)} directly + */ + @Deprecated public List getTautomers(IAtomContainer mol, String inchi) throws CDKException, CloneNotSupportedException { return getTautomers(mol, inchi, null); } diff --git a/tool/tautomer/src/test/java/org/openscience/cdk/tautomers/InChITautomerGeneratorTest.java b/tool/tautomer/src/test/java/org/openscience/cdk/tautomers/InChITautomerGeneratorTest.java index a31a594008..0733138167 100644 --- a/tool/tautomer/src/test/java/org/openscience/cdk/tautomers/InChITautomerGeneratorTest.java +++ b/tool/tautomer/src/test/java/org/openscience/cdk/tautomers/InChITautomerGeneratorTest.java @@ -71,6 +71,16 @@ private List unitTestWithInchiProvided(String smiles, String inc return tautomers; } + private List unitTestWithoutInchiProvided(String smiles, int flags, int tautCountExpected) + throws Exception { + IAtomContainer container = smilesParser.parseSmiles(smiles); + AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(container); + InChITautomerGenerator tautegen = new InChITautomerGenerator(flags); + List tautomers = tautegen.getTautomers(container); + Assert.assertEquals(tautCountExpected, tautomers.size()); + return tautomers; + } + @Test public void test1() throws Exception { unitTestWithInchiProvided("NC1=CC(N)=NC(O)=N1", "InChI=1S/C4H6N4O/c5-2-1-3(6)8-4(9)7-2/h1H,(H5,5,6,7,8,9)", 5); @@ -108,6 +118,37 @@ public void test6() throws Exception { + "h2-10,15H,1H3,(H2,11,20)(H,17,21,22)", 6); } + @Test + public void test1_fast() throws Exception { + unitTestWithoutInchiProvided("NC1=CC(N)=NC(O)=N1", 0, 5); + } + + @Test + public void test2_fast() throws Exception { + unitTestWithoutInchiProvided("CCCN1C2=C(NC=N2)C(=O)NC1=O", 0, 8); + } + + @Test + public void test3_fast() throws Exception { + unitTestWithoutInchiProvided("CCNC(=N)NC", 0, 3); + } + + @Test + public void test4_fast() throws Exception { + unitTestWithoutInchiProvided("O=C1NC=CC(=O)N1", 0, 6); + } + + @Test + public void test5_fast() throws Exception { + unitTestWithoutInchiProvided("CCN1CCOC2=CC(NC3=NCCN3)=CC=C12", 0, 2); + } + + @Test + public void test6_fast() throws Exception { + //Warfarin: not you need to create the InChI with option KET to get the ketone/hydroxyl tautomerism + unitTestWithoutInchiProvided("CC(=O)CC(C1=CC=CC=C1)C1=C(O)C2=C(OC1=O)C=CC=C2", InChITautomerGenerator.KETO_ENOL, 6); + } + @Test(expected = CDKException.class) // bail out on dots in formula public void testFail1() throws Exception {