2009年12月3日木曜日

OpenBabel : AtomのIndexリストからOBMolオブジェクトを再構築する

OpenBabelでSMARTSを使ったSmilesの部分構造検索をすると、結果がMapListと呼ばれる原子のIndexのリストで帰ってきます。OpenBabelではこのIndexを使うことを推奨していません。なぜならこのIndexは分子をModify(一部構造を切り取る、原子・分子を付加するなど)するとIndexが再作成されてしまうので、永続的に保持されないからです。


といってもこの原子Indexは元の分子をいじらない限りは変更されないので、元の分子の一部分を記憶させるには使いやすいです。検索結果や部分構造を別途Indexとして持っていればいろいろ使えます。ようは元の構造を一切いじらなければOKです。


しかも、これはやってみたのですが、DeleteBondするだけではIndexは変更されずちゃんと保持されます。つまり切断Bondとしての情報をもったままの分子として原子Indexがそのまま保持されます。Separateメソッドで元の分子をばらばらにしてしまうと、各部分構造分子の原子Indexは再作成されて、1から順番に振られます。


で、元の分子をいじらずに、取得した原子Indexから部分構造を再構築したいことはよくあります。なんでお気軽関数を作りました。コードはC#です。


新しいOBMolインスタンスに元の分子から原子をAddしていくのですが、Addしてしまうと新しい分子上のAddした原子のIndexはやはり1から順番に振られてしますので、別途新しいIndexと元のIndexの対応表をHashtableで管理しています。この情報を使ってあとでOBBondをAddしていきます。







using System.Collections.Generic;
using System.Collections;


using OpenBabel;

namespace OpenHabel
{
    static class OHUtil
    {
        /// <summary>
        /// ParentのMolと原子のIndexからMolを再構築
        /// </summary>
        /// <param name="parentMol"></param>
        /// <param name="atomIndex"></param>
        /// <returns></returns>
        public static OBMol GetMol(OBMol parentMol, List<uint> atomIndex)
        {
            Hashtable atomIdxTable = new Hashtable();
            OBMol newMol = new OBMol();
            IEnumerable<OBAtom> atoms = parentMol.Atoms();

            int atomCount = 0;
            foreach (OBAtom oneAtom in atoms)
            {
                if (OHUtil.IsThereItemInList(atomIndex, oneAtom.GetIdx()))
                {
                    OBAtom newAtom = new OBAtom();
                    newAtom.Duplicate(oneAtom);
                    int idx = int.Parse(oneAtom.GetIdx().ToString());
                    atomCount += 1;
                    atomIdxTable[idx.ToString()] = atomCount;

                    newMol.AddAtom(newAtom);

                    //Console.Write(obconv.WriteString(newMol));
                }
            }
            IEnumerable<OBBond> bonds = parentMol.Bonds();
            foreach (OBBond oneBond in bonds)
            {
                if (
                 OHUtil.IsThereItemInList(atomIndex, oneBond.GetBeginAtomIdx()) &&
                 OHUtil.IsThereItemInList(atomIndex, oneBond.GetEndAtomIdx())
                )
                {
                    int startAtomKey = (int)oneBond.GetBeginAtomIdx();
                    int startAtomIdx = (int)atomIdxTable[startAtomKey.ToString()];

                    int endAtomKey = (int)oneBond.GetEndAtomIdx();
                    int endAtomIdx = (int)atomIdxTable[endAtomKey.ToString()];

                    int order = (int)oneBond.GetBondOrder();

                    newMol.AddBond(startAtomIdx, endAtomIdx, order);
                }
            }
            return newMol;
        }

        /// <summary>
        /// atomList中に特定のatomIndexが含まれるかどうか
        /// </summary>
        /// <param name="atomList">List:uint</param>
        /// <param name="atomIndex">uint</param>
        /// <returns>見つかったらTrue</returns>
        public static bool IsThereItemInList(List<uint> atomList, uint atomIndex)
        {
            foreach (uint item in atomList)
            {
                if (item == atomIndex) { return true; }
            }
            return false;
        }
    }
}

0 件のコメント: