Canonical label その1
前回のつづき。
Canonical SMILES文字列を生成するためには、
まず、文字列の開始点となる原子を決定しなければなりません。
そのために、それぞれの原子がどのような環境にいるかを数値化して、
その順番に原子を並べ替える、というのがひとつの方法です。
Weiningerら*1は、以下の6種類の基準で数値化し、それらの数値を連結して
8桁の整数を生成して昇順に並べました。
こうすることで、たとえば、エーテル分子(C-C-O-C-C)の場合、
10106003--20206002--20208000--20206002--10106003
という数値列に置き換えられるので、
最小値の"10106003"に対応する原子から始めれば良いということになります。
ただし、最小値が2ヶ所以上にある場合は、
Morgan法のように、隣接原子の順位を反映させつつ並び替えを繰り返します。
(この話は長くなりそうなので、今回は一旦ここで止めておきます)
さて、CDKでは、CanonicalLabelerクラスとして、一連のラベル付け機能が実装されています。
Weiningerらの表現が曖昧なので、実装によって結果も変わってきます。
CDKとOpenBabelの出力結果の違いも、この辺に原因がありそうです。
以下は、CDKを土台としたサンプルコードですが、少し変更を加えています。
/* inv_label.java */import java.io.*;
import org.openscience.cdk.interfaces.*;
import org.openscience.cdk.io.iterator.IteratingMDLReader;
import org.openscience.cdk.DefaultChemObjectBuilder;import org.openscience.cdk.smiles.SmilesGenerator;
import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;import org.openscience.cdk.smiles.InvPair;
import org.openscience.cdk.tools.periodictable.PeriodicTable;
import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;import java.util.*;
class inv_label {
public static void main(String args[]){
if(args.length!=1){
System.err.println("inv_label <sd-file>");
System.exit(1);
}
FileInputStream fis = null;
IteratingMDLReader isr = null;
try{
fis = new FileInputStream(new File(args[0]) );
isr = new IteratingMDLReader(fis, DefaultChemObjectBuilder.getInstance() );
} catch (Exception e) {
e.printStackTrace();
}while( isr.hasNext() ){
IMolecule imol = (IMolecule)isr.next();
String id = (String)imol.getProperty("cdk:Title");StringBuffer inv;
ArrayList vect = new ArrayList();
IAtomContainer ac;try {
AtomContainerManipulator acm = new AtomContainerManipulator();
ac = acm.removeHydrogens(imol);
for (int i = 0 ; i < ac.getAtomCount(); i++){
IAtom a = ac.getAtom(i);
inv = new StringBuffer();
Integer ddd = a.getImplicitHydrogenCount();// 1. Num connections (incl H)
inv.append( ac.getConnectedAtomsList(a).size() +
(a.getImplicitHydrogenCount() == CDKConstants.UNSET ?
0 : a.getImplicitHydrogenCount()) );// 2. Num of non H bonds
inv.append( String.format("%02d",
ac.getConnectedAtomsList(a).size()) );// 3. Atomic num
inv.append( String.format("%02d",
PeriodicTable.getAtomicNumber(a.getSymbol()) ) );// 4. Sign of charge
Integer fcharge = a.getFormalCharge();
if (fcharge == CDKConstants.UNSET) fcharge = 0;
if (fcharge < 0){
inv.append(1);
} else {
inv.append(0);
}// 5. Absolute charge
inv.append( (int)Math.abs( (a.getFormalCharge() ==
CDKConstants.UNSET ? 0.0 : a.getFormalCharge()) ) );// 6. Hydrogen count
inv.append( (a.getImplicitHydrogenCount() == CDKConstants.UNSET ?
0 : a.getImplicitHydrogenCount()));vect.add(new InvPair(Long.parseLong(inv.toString()), a));
}
}catch (Exception e1) {
e1.printStackTrace();
}
for (int i = 0 ; i < vect.size() ; i++){
System.out.printf("%s\t%d\t%s\n", id, i, vect.get(i));
}
}
}
}
*1: Weininger et al. SMILES. 2. Algorithm for Generation of Unique SMILES Notation. J. Chem. Inf. Comput. Sci. (1989) 29, 97-101