Introduction

JNI-InChI is a library indended for use by developers of other projects. It does not enable users to generate InChIs from molecule file formats such as .mol, .cml, .mol2, or SMILES strings. If you want to do any of these, you should take a look at the Chemistry Development Kit (CDK), or JUMBO which includes InChI generation powered by the JNI-InChI. If, however, you are a software developer and you want want to generate the InChI for a molecule that you already hold in memory, JNI-InChI is what you need.

InChI Generation

The main aim of the JNI-InChI is to enable the generation of InChIs from within Java. The InChI libaray's functionality is accessed through the net.sf.jniinchi.JniInchiWrapper class. To generate an InChI, first a representation of the molecule must be constructed that the InChI library can recognise. This is achieved by creating JniInchiAtoms, JniInchiBonds and JniInchiStereo0Ds, and adding them to a JniInchiInput object. This is illustrated in the examples below:

// Example input - 2D E-1,2-dichloroethene
JniInchiInput input = new JniInchiInput();
//
// Generate atoms
JniInchiAtom a1 = input.addAtom(new JniInchiAtom(2.866, -0.250, 0.000, "C"));
JniInchiAtom a2 = input.addAtom(new JniInchiAtom(3.732, 0.250, 0.000, "C"));
JniInchiAtom a3 = input.addAtom(new JniInchiAtom(2.000, 2.500, 0.000, "Cl"));
JniInchiAtom a4 = input.addAtom(new JniInchiAtom(4.598, -0.250, 0.000, "Cl"));
a1.setImplicitH(1);
a2.setImplicitH(1);
//
// Add bond
input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.DOUBLE));
input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
input.addBond(new JniInchiBond(a2, a4, INCHI_BOND_TYPE.SINGLE));
JniInchiOutput output = JniInchiWrapper.getInchi(input);
// Example input - 0D D-Alanine
JniInchiInput input = new JniInchiInput();
//
// Generate atoms
JniInchiAtom a1 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
JniInchiAtom a2 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
JniInchiAtom a3 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "N"));
JniInchiAtom a4 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "C"));
JniInchiAtom a5 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "O"));
JniInchiAtom a6 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "O"));
JniInchiAtom a7 = input.addAtom(new JniInchiAtom(0.0, 0.0, 0.0, "H"));
a3.setImplicitH(2);
a4.setImplicitH(3);
a5.setImplicitH(1);
//
// Add bonds
input.addBond(new JniInchiBond(a1, a2, INCHI_BOND_TYPE.SINGLE));
input.addBond(new JniInchiBond(a1, a3, INCHI_BOND_TYPE.SINGLE));
input.addBond(new JniInchiBond(a1, a4, INCHI_BOND_TYPE.SINGLE));
input.addBond(new JniInchiBond(a2, a5, INCHI_BOND_TYPE.SINGLE));
input.addBond(new JniInchiBond(a2, a6, INCHI_BOND_TYPE.DOUBLE));
input.addBond(new JniInchiBond(a1, a7, INCHI_BOND_TYPE.SINGLE));
//
// Add stereo parities
input.addStereo0D(JniInchiStereo0D
        .createNewTetrahedralStereo0D(a1, a3, a4, a7, a2, INCHI_PARITY.EVEN));
//
JniInchiOutput output = JniInchiWrapper.getInchi(input);

Further examples can be found in the TestJniInchiWrapper class, the CDK, and JUMBO.

Output

The JniInchiOutput object returned contains the results of the InChI generation:

INCHI_RET getReturnStatus()Returns the status code (see below)
String getInchi()Returns the generated InChI
String getAuxInfo()Returns the generated AuxInfo
String getMessage()Returns warning or error message
String getLog()Returns log messages from InChI generation

Return status codes

The InChI generation process returns a status code which describes how successful the process was:

SKIPNot used
EOFNo structural data has been provided
OKAYSuccess, no errors or warnings
WARNINGSuccess, warning(s) issued
ERRORError: no InChI has been created
FATALSevere error: no InChI has been created (typically, memory allocation failure)
UNKNOWNUnknown program error
BUSYPrevious call to InChI has not returned yet

(Documentation from inchi_api.h)

Options

JNI-InChI supports the full range of options that InChI generation takes:

SUCFUse Chiral Flag
ChiralFlagONSet Chiral Flag
ChiralFlagOFFSet Not-Chiral Flag
OptionsEquivalent toChiral Flag Information stored in AuxInfo
SUCF ChiralFlagONSABSChiral Flag
SUCF ChiralFlagOFFSRELNot-Chiral Flag
SUCFSRELnone
ChiralFlagONnoneChiral Flag
ChiralFlagOFFnoneNot-Chiral Flag

Other options:

SNonExclude stereo (Default: Include Absolute stereo)
SRelRelative stereo
SRacRacemic stereo
SUUInclude omitted unknown/undefined stereo
NEWPSNarrow end of wedge points to stereocenter (default: both)
RecMetInclude reconnected bond to metal results
FixedHMobile H Perception Off (Default: On)
AuxNoneOmit auxiliary information (default: Include)
NoADPDisable Aggressive Deprotonation (for testing only)
CompressCompressed output
DoNotAddHOverrides inchi_Atom::num_iso_H[0] == -1
WnumberSet time-out per structure in seconds; W0 means unlimited In InChI library the default value is unlimited
OutputSDFOutput SDfile instead of InChI
WarnOnEmptyStructureWarn and produce empty InChI for empty structure

(Documentation from inchi_api.h)

InChI-to-Structure

JNI-InChI also supports InChI-to-Structure conversion:

JniInchiInputInchi input = new JniInchiInputInchi("InChI=1/C2H6/c1-2/h1-2H3");
JniInchiOutputStructure output = JniInchiWrapper.getStructureFromInchi(input);
//
INCHI_RET retStatus = output.getReturnStatus();
int nat = output.getNumAtoms();
int nbo = output.getNumBonds();
int nst = output.getNumStereo0D();
//
JniInchiAtom at0 = output.getAtom(0);

InChI-to-InChI

The InChI libary also provides an option to convert InChI-to-InChI. This may be of use if you wish to remove layers from an InChI:

// Input InChI with fixed-hydrogen layer
String inchiIn = "InChI=1/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/"
    + "t2-/m0/s1/f/h5H";
//
JniInchiOutput output = JniInchiWrapper.getInchiFromInchi(
        new JniInchiInputInchi(inchiIn));
String inchiOut = output.getInchi();
// Output InChI:
//   InChI=1/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1

Or if you wish to convert between compressed and uncompressed InChIs:

String inchi = "InChI=1/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)";
//
// Compress InChI
JniInchiOutput cout = JniInchiWrapper.getInchiFromInchi(
        new JniInchiInputInchi(inchi, "-compress"));
String compressedInchi = cout.getInchi();
// compressedInchi = InChI=1/C3H7NO2/cABBCC/hB1D2A3,1EF
//
// Uncompress InChI
JniInchiOutput ucout = JniInchiWrapper.getInchiFromInchi(
        new JniInchiInputInchi(compressedInchi));
String uncompressedInchi = ucout.getInchi();
// uncompressedInchi = InChI=1/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)

InChI-to-InChIKey

JniInchiOutputKey output = JniInchiWrapper.getInchiKey("InChI=1S/C2H6/c1-2/h1-2H3");
String key = output.getKey();

Check InChI

boolean strict = true;
INCHI_STATUS status = JniInchiWrapper.checkInchi("InChI=1S/C2H6/c1-2/h1-2H3", strict);

Check InChIKey

INCHI_KEY_STATUS status = JniInchiWrapper.checkInchiKey("OTMSDBZUPAUEDD-UHFFFAOYSA-N");

AuxInfo-to-InChI Input

JniInchiInputData data = JniInchiWrapper.getInputFromAuxInfo("AuxInfo=1/1/N:4,1,2,3,5,6/"
        +"E:(5,6)/it:im/rA:6CCNCOO/rB:s1;N1;s1;s2;d2;/rC:264,968,0;295,985,0;233,986,0;"
        +"264,932,0;326,967,0;295,1021,0;");
INCHI_RET ret = data.getReturnValue();
JniInchiInput input = data.getInput();

Native Code

JNI-InChI does not contain a Java version of the InChI algorithm, it wraps up the InChI library distributed by IUPAC, making its functionality available to Java programmers. The InChI library is only available in C, and is not sufficiently well documented for it to be easy to produce an implementation in another language, without first reverse engineering the existing code.

The problem with using native code is that the cross-platform benefits of java are lost. In an attempt to overcome this the JNI-InChI contains a mechanism package the native files with the java code, to deploy the appropriate ones on a system, as required. This is all handled by the net.sf.jniinchi.JniInchiNativeCodeLoader class.