Access RDKit functionality via Java Snippet node

Hi everybody,

apologies in advance if this topic has already been dealt with and I haven't been able to find it.

I have tried to access RDKit functionality not available within existing nodes through the Java Snippet node. I have added org.RDKit.jar to the "Additional Libraries" and I have tried running the following snippet:

//System.load("C:/Program Files/KNIME_3.1.2/plugins/org.rdkit.knime.bin.win32.x86_64_3.0.0.v201606050430/os/win32/x86_64/GraphMolWrap.dll");
ROMol m = RWMol.MolFromMolBlock(c_Molecule, true, false);
if (m != null) {
    RDKFuncs.assignStereochemistry(m, false, true, true);
    out_nChiral_1 = 0;
    for (int i = 0; i < m.getNumAtoms(); ++i) {
        if ((m.getAtomWithIdx(i).getChiralTag() != Atom.ChiralType.CHI_UNSPECIFIED)
            || m.getAtomWithIdx(i).hasProp("_ChiralityPossible"))
            ++out_nChiral_1;
    }
}

This unfortunately fails with the error message:

java.lang.UnsatisfiedLinkError: org.RDKit.RDKFuncsJNI.RWMol_MolFromMolBlock__SWIG_0(Ljava/lang/String;ZZ)J

However, if I attempt to load the DLL uncommenting the first line in the Java Snippet node, I get the following error message:

java.lang.UnsatisfiedLinkError: Native Library C:\Program Files\KNIME_3.1.2\plugins\org.rdkit.knime.bin.win32.x86_64_3.0.0.v201606050430\os\win32\x86_64\GraphMolWrap.dll already loaded in another classloader

Googling for this issue I found a few reports of similar cases, but no solution. In this one:

https://tech.knime.org/forum/knime-users/java-snippet-having-two-java-snippets-using-a-jni-library-causes-unsatisfiedlinker#comment-form

Thorsten seems to suggest that, as long as the DLL is included in a plugin which is loaded when KNIME starts, things should work, but this does not seem to be the case.

What am I doing wrong? Is it possible at all to try to access RDKit functionality within a Java Snippet node? That would be REALLY nice, if it were possible. I know I can use the Python Snippet node for the same purpose, but that requires a local RDKit install, while the Java Snippet could use the KNIME RDKit plugin.

Please do not suggest alternative ways to achieve the above with existing KNIME nodes - this is just an example, and I am aware I can count chiral centres using existing KNIME nodes. I would like to learn, if it is possible, how to access RDKit functionality within the Java Snippet node.

Thanks a lot in advance, kind regards

Paolo
 

Dear Paolo,

what you are trying to do is not possible to my knowledge. I had the same idea a few years ago, but did not succeed either. The Java Snippet node is implemented in an isolated way and does not see the Java classes that come from other plugins. It only sees the classes of plugins it is supposed to see (just a very few) and of course the normal Java classes. Hence, you cannot see the RDKit classes nor the necessary binaries. When you are trying to load them "by hand" via the Library tab, you won't get the native code invoked properly because the library is already active from the RDKit plugin. Other plugins like ErlWood or Vernalis are referencing the RDKit Types plugin which again hosts the proper binaries and provides access to the RDKit code, but that is done with Eclipse mechanisms and not "pure" Java as in the Java snippet node anymore. Hence, you cannot just do that in the Java Snippet node.

The only way to get this to work in my opinion would need KNIME's involvment: If there would be a way to add references to KNIME Plugins additional to JAR path names, there is a chance that this could work. E.g. such a "link" would look in Eclipse syntax like "platform:/plugin/org.rdkit.knime.types/lib/org.RDKit.jar" - this is how the RDKit node reference the RDKit binaries. In the moment such a thing is not supported.

@Thorsten or Bernd, could this be added maybe? I would agree that this would be useful indeed.

-Manuel

This doesn't directly answer your question as what you want is not really possible right now.

There are 2 options (as you already suggested partially)

1. Create your own nodes

You need to install SDK and learn how to create your own KNIME nodes and deploy them. It does have a significant  learning curve (especially if you don't know Eclipse or you do know it but hate it ;) ). The end result can be pretty cool. I would recommend this for actions/nodes you will use very often in pretty much the same way (eg. little configuration).

2. Use python nodes

The python nodes are fully compatible with an installed python version of rdkit. AFAIk this is still only for python 2.7 and not yet python 3 but that doesn't matter much.

Downside here is if not already done you need to install/ create the python envrionment and configure KNIME to use it. And you also need to know Python. The python snippet has the advantge that it can operate on the full table and not just row by row like the Java snippet. So there are a lot more possibilties at cost of higher overhead / boiler plate, eg. you need to always create the output table in code yourself.

Good for quick and dirty experimental / one-time use or proof-of-concept. However IMHO the maintenance side is much worse like debugging, source control etc. is much more difficult than creating your own node. Still probably the best diea to start with this option

 

EDIT: given your username is who you really are, I think neither option should be an issue for you.

Paolo,

As Manuel says: as odd as it seems, this is not currently possibly from within the Java snippet node.

We are working on this already and hope to have support available in the next release of KNIME.

Best,

-greg 

Thanks everybody for your replies. It will be great if support for this functionality will be added in a future KNIME release, I guess that would be useful to a number of users.

Paolo

For the sake of those who will google this in the future, I can confirm that this now works great in KNIME 3.3.0; just add org.RDKit.jar among the "Additional libraries" while configuring the Java Snippet node.

The Java snippet below counts the number of chiral centres in the molecules provided on input, as expected.

Thanks a lot to the KNIME team for making this possible!

Paolo

 

// system imports
import org.knime.base.node.jsnippet.expression.AbstractJSnippet;
import org.knime.base.node.jsnippet.expression.Abort;
import org.knime.base.node.jsnippet.expression.Cell;
import org.knime.base.node.jsnippet.expression.ColumnException;
import org.knime.base.node.jsnippet.expression.TypeException;
import static org.knime.base.node.jsnippet.expression.Type.*;
import java.util.Date;
import java.util.Calendar;
import org.w3c.dom.Document;


// Your custom imports:
import org.RDKit.ROMol;
import org.RDKit.RWMol;
import org.RDKit.Atom;
import org.RDKit.RDKFuncs;

// system variables
public class JSnippet extends AbstractJSnippet {
  // Fields for input columns
/** Input column: "Molecule" */
  public String c_Molecule;

  // Fields for output columns
/** Output column: "nChiral" */
  public Integer out_nChiral;

// Your custom variables:

// expression start
    public void snippet() throws TypeException, ColumnException, Abort {
// Enter your code here:
ROMol m = RWMol.MolFromMolBlock(c_Molecule, true, false);
if (m != null) {
    RDKFuncs.assignStereochemistry(m, false, true, true);
    out_nChiral = 0;
    for (int i = 0; i < m.getNumAtoms(); ++i) {
        if ((m.getAtomWithIdx(i).getChiralTag() != Atom.ChiralType.CHI_UNSPECIFIED)
            || m.getAtomWithIdx(i).hasProp("_ChiralityPossible"))
            ++out_nChiral;
    }
}


// expression end
    }
}

You might need to add an m.delete() call in there before your //expression end if you are not to risk memory leakage - but WOW that this now works!

Steve
 

Yeah, the team did a really nice job on this one. I plan to do a blog post (likely on the RDKit blog since it's very RDKit-specific) on this in the next couple of weeks that will include a bit more information, particularly about the memory consumption thing. I'll link to it here when it's done.

-greg