CDKで分子の記述子計算をまとめて行うプログラムを作成

# はじめに
CDKで記述子計算を行ったのでメモ。CDKの日本語の情報はRDKitに比べると非常に少ない。PythonとJavaという言語の違いも関係しているように思う。とはいえ、JavaDocや過去のバージョンのプログラムを参考に試行錯誤したところ、分子の記述子(Molecular Descriptor)の計算を行うプログラムを作成することができた。

# 環境
- JDK11
- CDK2.2


# プログラム
実行すると222個の記述子がcsvに出力されるはずである。
4種類のDescriptorクラスでエラーとなるが、おそらく3次元座標を必要とする記述子であるにもかかわらず、SDFに3次元座標がないためであろう。

``` DescriptorEngineTest.java
import org.openscience.cdk.DefaultChemObjectBuilder;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.io.iterator.IteratingSDFReader;
import org.openscience.cdk.qsar.DescriptorEngine;
import org.openscience.cdk.qsar.DescriptorValue;
import org.openscience.cdk.qsar.IMolecularDescriptor;
import org.openscience.cdk.IImplementationSpecification;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;

public class DescriptorEngineTest {

    public static void main(String[] argv) throws Exception{
        FileReader fr_train = null;
        FileWriter fw_train = null;

        // 入力SDFの設定
        String path = "C:\\ChemSyo\\Jupyter\\data\\";
        try {
            fr_train = new FileReader(new File(path + "solubility.train.sdf"));
        } catch (FileNotFoundException e) {
            System.err.println("sdf not found");
            System.exit(1);
        }

        // 出力ファイルの設定
        fw_train = new FileWriter(path + "solubility.train.cdk.csv");

        DescriptorEngine descriptorEngine = new DescriptorEngine(org.openscience.cdk.qsar.IMolecularDescriptor.class, null);

        IteratingSDFReader sdfReaderTrain = new IteratingSDFReader(fr_train, DefaultChemObjectBuilder.getInstance());

        boolean isFirst = true;
        while (sdfReaderTrain.hasNext()) {
            IAtomContainer mol = (IAtomContainer) sdfReaderTrain.next();
            descriptorEngine.process(mol);
            java.util.List<IImplementationSpecification> list = descriptorEngine.getDescriptorSpecifications();
            java.util.ArrayList<String> descriptorList = new java.util.ArrayList<String>();
            java.util.ArrayList<Double> descriptorValues = new java.util.ArrayList<Double>();

            for (IImplementationSpecification descriptorSpecification : list) {
                System.out.println(descriptorSpecification.getImplementationTitle());
                DescriptorValue value = (DescriptorValue)mol.getProperty(descriptorSpecification);
                if(value != null) {
                    for (String name : value.getNames()) {
                        descriptorList.add(name);
                    }
                    if (value.getException() != null) {
                        System.out.println("ERROR!");
                        System.exit(0);
                    }
                    String[] values = value.getValue().toString().split(",");
                    for (String tmpValue : values){
                        tmpValue = tmpValue.trim();
                        descriptorValues.add(Double.parseDouble(tmpValue));
                    }
                }
            }

            if (isFirst) {
                // ヘッダ出力
                for (int i = 0; i < descriptorList.size(); i++) {
                    System.out.println(descriptorList.get(i));
                    if (i > 0) {
                        fw_train.write(",");
                    }
                    fw_train.write("CDK_" + descriptorList.get(i));
                }
                isFirst = false;
            }
            // 記述子計算結果の出力
            fw_train.write("\n");
            for (int i = 0; i < descriptorValues.size(); i++) {
                System.out.println(descriptorValues.get(i));
                if (i > 0) {
                    fw_train.write(",");
                }
                fw_train.write(String.valueOf(descriptorValues.get(i)));
            }
            // break;
        }

        fr_train.close();
        fw_train.close();
    }
}
```

別の機会にAtomDescriptorやBondDescriptor等も出力するプログラムも書く予定である。