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 {