データ構造と構造検知
libbuilcule で実装している分子を表現するデータ構造を,簡略化して紹介します.
libbuilcule では,系全体を表現するための Unit クラス内に,Atom クラス,Amino_Acid クラス,Molecule クラスの組み合わせからなるデータ構造を構築しています.
現バージョンの libbuilcule は Builcule の非 GUI 部分をライブラリにしただけなので,拡張性に乏しい等々,不都合が出ています.
次期バージョンでは,継承関係を中心に大幅変更する予定です.
目次(ページ内リンク)
Atom クラス:原子を表現するためのデータ構造です.まず考えねばならないのは,編集に大きく係る共有結合の処理でしょうか
Amino_Acid クラス:アミノ酸なのですが,水素付加,水素除去,シークエンス,変異などの編集に係る情報も格納します
Molecule クラス:分子を表現するためのデータ構造です.分子単位の操作が可能になります
Unit クラス:系全体を表現するためのデータ構造です
ペプチドの検知:共有結合情報からどうやって検知しているか,セクションを儲けました
Atom クラス
分子ファイルに記述されたデータ
分子情報を記したファイルには,一般に 1 行に 1 原子の情報が記述されています.
このことから,原子を表現するデータ構造を作成すれば,ファイルの情報を処理しやすそうです.
一例として,下に XYZ 形式で記述したメタンを示します.
1 行に元素とカルテシアン座標(XYZ 座標)が記述されています.
5 This file was creatwd with Builcule. C -0.00000 0.00000 -0.00000 H 1.07000 0.00000 -0.00000 H -0.35667 0.00000 1.00881 H -0.35667 -0.87365 -0.50440 H -0.35667 0.87365 -0.50440
Atom クラスの概略
仮に XYZ 形式のファイルを処理するとするなら,元素と座標がファイルの各 1 行から読み取れます.
座標から,2 原子間の距離を測定し,標準的な共有結合距離と比較すれば検知できます(距離の実測例:タンパク質における共有結合の検知)
libbuilcule では,これらの情報を格納する Atom クラスを定義しています.
下はクラス宣言の一部です.
- コンストラクタでは,元素記号を原子番号に変換し,double x,double y,double z,座標から Eigen::Vector3d を構築しています
- コンストラクタで,原子ごとにユニークなシリアル番号を与えます.ただし変更する場合があるので,const ではありません
- 元素記号ではなく原子番号を使うのは,共有結合半径やファンデルワールス半径などを格納した配列の添字として使いたいからです
- 座標から線形代数ライブラリ Eigen の三次元ベクトル構築しています.これは,回転などの線形代数処理を Eigen に任せるためです
- 共有結合の相手は,Atom クラスへの共有ポインタとして表現しています
#include <Eigen/Dense> #include <memory> #include <vector> class Atom { private: int SerialNum; //原子ごとにユニークな番号を与える int Element; //原子番号(ここには記さないが,元素記号も保持している) Eigen::Vector3d XYZ; //座標を線形代数ライブラリである Eigen のオブジェクトとしている std::vector<std::shared_ptr<Atom>> Bond; //共有結合の相手を格納する可変長配列 public: Atom(const std::string *symbol, double x, double y, double z); //コンストラクタ void push_bond(const std::shared_ptr<Atom> &pair) { Bond.push_back(pair); } //共有結合の形成 };
Amino_Acid クラス
共有結合が検知できたら,後述するペプチドの検知で紹介しているアルゴリズムで,アミノ酸残基やペプチドが検知できます.
libbuilcule では,アミノ酸残基を表すデータ構造として Amino_Acid クラスを定義しています.
下はクラス宣言の一部です.
メンバ変数のみ抜書しました.これらのメンバ変数を操作(== アミノ酸を編集)するメンバ関数は省略しました.
アミノ酸残基を構成する原子は,Atom クラスへの共有ポインタをベクトル型配列に格納したオブジェクトとなっています.
水素付加,水素除去に対応するため,4 種類に分割しています.
PDB 形式での表示記号(CA とか CB とか)をキーとし,原子への共有ポインタを返す連想配列連想配列を作成しています.
アミノ酸の編集用です.
シークエンス用に,配列上前後のアミノ酸へのポインタを保持するオブジェクトも宣言しました.
class Amino_Acid { private: char Code; //アミノ酸 1 文字コード //アミノ酸を構成する原子 std::vector<std::shared_ptr<Atom>> Main; //主鎖の非水素原子 std::vector<std::shared_ptr<Atom>> MainH; //主鎖の水素原子 std::vector<std::shared_ptr<Atom>> Side; //側鎖の非水素原子 std::vector<std::shared_ptr<Atom>> SideH; //側鎖の水素原子 //表示記号をキーとして,原子への共有ポインタを返す連想配列 std::map<AA_Atom, std::shared_ptr<Atom>> MapMain; //キーは表示記号 std::map<AA_Atom, std::shared_ptr<Atom>> MapSide; //同上 //シークエンス用 const Amino_Acid *BeforeAA; //N-末側のアミノ酸へのポインタ const Amino_Acid *NextAA; //C-末側のアミノ酸へのポインタ };
Molecule クラス
libbuilcule では,分子を格納する Molecule クラスを定義しています.
下にクラス言言の一部を示します.
class Molecule { private: std::vector<std::shared_ptr<Atom>> MolAtom; //分子を構成する原子 std::vector<std::vector<Amino_Acid>> PeptVect; //その分子で検知されたペプチド };
原子の結合情報をたどれば全原子を捕獲できます.
Molecule クラスでは,Atom クラスのオブジェクト への共有ポインタをベクトル型配列に格納して,分子を表現するオブジェクト MolAtom としています.
Molecule クラス内ではまた,ペプチドを検知しています.
Amino_Acid クラスを構築し,シークエンス用のポインタに従ってベクトル型配列に格納すればペプチドとなります.
1 分子内に複数のペプチドが検知される場合があるので,ペプチドを表現するオブジェクト PeptVect は二次元配列です.
このクラスを使えば,分子ごと回転や削除といった編集が可能になります.
また,ペプチドの削除等,ペプチドを対象とする編集も可能になります.
Unit クラス
ファイルの情報からは,次の手順で Unit クラスを作成します.
- ファイルから読み取れた原子の情報は,std::shared_ptr<Atom> としてベクトル型配列 AtomVect に格納します
- その際必要に応じて,原子間距離から共有結合情報を作成し,Atom::Bond にプッシュします
- AtomVect から共有結合情報に基づいて分子を検知し,Molecule クラスのオブジェクトを作成し,MolVect にプッシュします
- MolVect の要素(分子)ごとにアミノ酸を検知し Amino_Acid クラスの一時オブジェクトを作成します
- Amino_Acid クラスのシークエンス用のポインタに従って,Amino_Acid オブジェクトを Molecule::VeptVect にプッシュすればペプチドとなります
class Unit { private: std::vector<Atom> AtomVect; //ファイルから読み取れた全原子 std::vector<Mol> MolVect; //検知された分子 };
libbuilcule では,原子(を表現するデータ構造への共有ポインタ)をベクトル型配列に格納しています.
現バージョンでは,原子を管理するために 2 つの方法を使っています.
一つは,共有ポインタを利用する方法です.
もう一つは,原子ごとにユニークなシリアル番号を与え,ベクトル型配列をシリアル番号で関節参照する方法です.
殺ってみたら,どちらの方法にも一長一短があるように思えました.例えば,
- 共有ポインタで管理する場合:分子等のコピー&ペーストの処理でインスタンスの作成が必要となります
- シリアル番号で管理する場合:原子の追加や削除ごとに照合用データのアップデートに注意が必要です
ペプチドの検知
図は,ペプチドの構造式と原子の表示記号の一部を示すものです.上が非末端,下が C-末です.
この記号を使って libbuilcule でペプチドを検知する考え方を簡略化して紹介します.
カルボニル炭素(C)候補
まず,共有結合が 3 個の炭素原子のうち,
- 結合相手が窒素,炭素,および酸素
- 窒素,および 2 個の酸素
であるものを探します.このなかに C が含まれます.
前者が C-末以外の候補,後者が C-末の候補です.
α-炭素(CA)候補
C 候補に結合した炭素は CA 候補です.
CA 候補に共有結合した原子を数え上げます.
- CA なら,窒素と炭素が 1 個ずつ
- 他はあったとしても水素のみ
が結合しているので,この条件に合わないものは,候補から外します.
アミノ窒素(N)候補
CA 候補に結合した炭素は N 候補です.
N 候補に共有結合した原子を数え上げます.
- N-末なら炭素が CA 候補 1 個,あとは結合していたとしても水素のみ
- 非 N-末なら炭素が CA 候補と C 候補 1 個づつ
- ただし,Pro は例外なので,別途検知
ペプチド結合
CB,CA,N の検知が終了した時点で,N-CA-CB-N まで検知できているので,あとはそれらを数珠つなぎしていきます.
側鎖
CA を捜査した時点で Gly は確定済みです.すなわち,Gly の CA には窒素と炭素が 1 個ずつ結合しているだけです.
他のアミノ酸には窒素が 1 個と炭素が 2 個結合しています.その炭素の片方が CB ということになります.
CB を走査すると,Ala,Cys,Ser,Thr,および Val の候補をピックアップできます.
水素を無視して記すと,
- Ala:CB に結合している原子は炭素 1 個
- Cys:CB に結合している原子は炭素 1 個,イオウ 1 個
- Ser:CB に結合している原子は炭素 1 個,酸素 1 個
- Thr:CB に結合している原子は炭素 2 個,酸素 1 個
- Val:CB に結合している原子は炭素 3 個
- 上記アミノ酸以外:CB に結合している原子は炭素 2 個
このような作業を繰り返して,側鎖を確定しています.