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 件のコメント:
コメントを投稿