Chapter 1
Writing CDK scripts 1.1
Groovy
Groovy (http://groovy.codehaus.org/) is a programming language that advertizes itself as is an agile and dynamic language for the Java Virtual Machine. Indeed, like BeanShell is provides an environment to quickly try Java code. However, unlike BeanShell, it provide more linguistic changes and adds quite interesting sugar to that Java language. A simple script may look like: for (IAtom atom : molecule.atoms()) { System.out.println(atom.getSymbol()); } But in Groovy it can also look like: for (atom in molecule.atoms()) { println atom.getSymbol() } Groovy needs to be made aware of the CDK, which uses the common CLASSPATH approach for doing this. To start the GUI console shown in Figure 1.1: $ CLASSPATH=cdk-1.2.0.jar groovyConsole
1.1.1
Closures
However, one of the more interesting features of Groovy is the closures. I have know the programming pattern from R and happily used for a long time, but only recently learned this to be called closures. Closures allow you to pass method as parameter, which can have many applications, and I will show one situation here. Consider the calculation of molecular properties which happen to be a mere summation over atomic properties, such as the total charge, or the molecular weight. Both these calculations require an iteration over all atoms. If we need those properties at the same time, we can combine the calcultion into one iteration. However, let’s generalize the situation a bit and assume they are not. Therefore, we have to slices of code which share a large amount of data: 1
2
CHAPTER 1. WRITING CDK SCRIPTS
Figure 1.1: Screenshot of groovyConsole showing a simple Groovy script. totalCharge = 0.0 for (atom in molecule.atoms()) { totalCharge += atom.getCharge() } and molWeight = 0.0 for (atom in molecule.atoms()) { molWeight += isotopeInfo.getNaturalMass(atom) } In both cases we want to apply a custom bit of code to all atoms. Groovy allows us to share the common code: def forAllAtoms(molecule, block) {
1.1. GROOVY for (atom in molecule.atoms()) { block(atom) } } totalCharge = 0.0 forAllAtoms(molecule, { totalCharge += it.getCharge() } ) totalCharge = String.format(’%.2f’, totalCharge) println "Total charge: ${totalCharge}" molWeight = 0.0 forAllAtoms(molecule, { molWeight += isotopeInfo.getNaturalMass(it) } ) molWeight = String.format(’%.2f’, molWeight) println "Molecular weight: ${molWeight}" which gives the output: Total charge: -0.00 Molecular weight: 16.04
3