Atom クラス
libbuilcule での Atom クラスは,原子番号,三次元座標,共有結合相手,分子,ペプチド,アミノ酸配列のインデックス,アミノ酸のアノテーション等をメンバ変数としています.
Atom クラスの特徴をいくつか列挙すると,
- 共有ポインタとしてインスタンス化することを前提として設計しています
- 三次元座標は,Eigen::Vector3d を利用しています
- 共有結合は,結合相手への共有ポインタをベクトル型配列に格納して表現しています
考え方
原子の表現
「原子を表現するクラスを作成すれば,分子モデリングライブラリが作れるのではないか」,という考え方を出発点としています.
たたき台として,原子番号と三次元座標を有するクラスを宣言してみます.
#include <array>
class Atom {
private:
int AtomNum; //原子番号
std::array<double, 3> XYZ; //三次元座標
}
ライブラリの目的により,どのようなメンバを定義するかが決まります.
ここでの目的は計算化学用の入力構造を作成することです.
なので,分子構造を変更するために「全経験的」な処理をおこなうメンバ変数や関数をいろいろ追加していきます.
例えば,
- 原子を区別する必要があるので,シリアル番号を保持するオブジェクトを宣言します.ユニークな番号を生成する方法を考える必要があります
- 三次元座標を線形代数ライブラリ Eigen の Vector3d で表現します.四元数や行列算といった数値計算を利用するためです
- 共有結合相手を格納するオブジェクトを宣言します.要素として共有ポインタを格納するベクトルとしています.以前はシリアル番号を格納するベクトルでした
- 分子,ペプチド,アミノ酸に関する情報を保持するオブジェクトを宣言します
- 宣言したオブジェクトを操作する関数を定義します
どのようなインスタンスを生成するか
色々な方法があります.例えば以前は,実体オブジェクト生成して関節参照する手法を採っていました.
現在は以下のような理由から,Atom クラスを共有ポインタとしてインスタンス化しています.
したがって,結合相手を格納するベクトルの要素も共有ポインタということになります.
- ベクトル型配列に格納可能である.すなわち,std::vector<std::shared_ptr<buic::Atom>>
- 直接参照可能である.関節参照用のオブジェクトを作成する手間がなくなる
ただしこの方法が万能というわけではありません.
例えば置換基などは,別途 Atom_Seed というクラスを定義して,実体オブジェクトを格納したベクトル型配列を関節参照する手法を使っています.
private メンバ
const int SerialNum;
原子を区別するためのシリアル番号です.これはシングルトンで生成し,コンストラクタで設定しています.編集するための関数はありません.
int AtomNum;
原子番号です.libbuilcule では,原子種を原子番号で区別しています.
初期値は 0 としています.原子番号としてありえない値ですが,未知の原子に与えられる仮の値としても使えます.
Eigen::Vector3d XYZ;
原子の座標です.Eigen の関数を直接使うために,Eigen の三次元ベクトルとしています.一例を挙げれば,座標の回転は Eigen::Quaterniond インスタンスとの掛け算です.
初期値は原点 {0.0, 0.0, 0.0} としています.
std::vector<std::shared_ptr<buic::Atom>> Bond;
共有結合の相手を格納するオブジェクトその 1 です.
Bond は構造の検知・編集用です.分子視点からは,双方向リンクリストということになります.
std::vector<std::shared_ptr<buic::Atom>> BondUp;
共有結合の相手を格納するオブジェクトその 2 です.
これは描画用のオブジェクトで,二度描き防止用に,自身のシリアル番号より大きい結合相手のみを格納します.
int MolIdx;
その原子が属する分子の通し番号です.初期値(分子の検知前)として,-1 が与えられます.
int PeptIdx;
その原子が属するペプチドの通し番号です.初期値(ペプチドの検知前)あるいはペプチドに属していない場合は,-1 が与えられます.
int SeqIdx;
その原子が属するペプチド上の配列番号です.初期値あるいはペプチドに属していない場合は,-1 が与えられます.
buic::AACode Code;
その原子が属するアミノ酸のコードです.buic::AACode は,global.h で宣言しています.
enum class AACode { A, C, D, E, F, G, H, I, K, L, M, N, P, Q, R, S, T, V, W, Y, c, p, Default };
初期値あるいはペプチドに属していない場合は,buic::AACode::Default が与えられます.
buic::AAAnnot Annot;
その原子が属するアミノ酸上のアノテーションです.buic::AAAnnot は,global.h で宣言しています.
enum class AAAnnot { C, CA, CB, CD, CD1, CD2, CE, CE1, CE2, CG, CG1, CG2, CH2, CZ, CZ2, CZ3, N, ND1, ND2, NE, NE1, NE2, NH1, NH2, NZ, O, OD, OD1, OD2, OE1, OE2, OG, OG1, OH, SD, SG, OXT, Default };
初期値あるいはペプチドに属していない場合は,buic::AAAnnot::Default が与えられます.
buic::AtomFlag Flag;
選択や検知の際のチェック用です.buic::AtomFlag は,global.h で宣言しています.今回のメジャーバージョンアップに際してまだ手つかずで,変更する場合がありす.
enum class AtomFlag { DeleteBA, DeleteA, Region, AddCB, BondSP22, BondSP23, BondSP32, BondSP33, BondSP34, Default };
コンストラクタ
Atom(int atom_num = 0, double x = 0.0, double y = 0.0, double z = 0.0, int mol = -1, int pept = -1, int seq = -1, buic::AACode code = buic::AACode::Default, buic::AAAnnot annot = buic::AAAnnot::Default);
コンストラクタ引数は,原子番号,X 座標,Y 座標,Z 座標,分子番号,ペプチド番号,廃鉄番号,アミノ酸コード,アミノ酸のアノテーションです.
各々デフォルト引数を与えています.
各原子は各々区別できるものとしています.すなわち,コピーコンストラクと代入を禁止しています.
- Atom(const Atom&) = delete;
- Atom& operator=(const Atom&) = delete;
コンストラクタ以外の public 関数
これらは private メンバを編集する関数です.関数宣言を並べるだけで,ほぼ充分と思います.
いくつか列挙体を使っていますが,これらは別途定義しています.
void set_atom_num(int num);
void set_xyz(const Eigen::Vector3d *yz);
void set_x(double x);
void set_y(double y);
void set_z(double z);
void add_x(double x);
void add_y(double y);
void add_z(double z);
void add_xyz(const Eigen::Vector3d *xyz);
void rotate(const Eigen::Quaterniond quat);
void set_mol_idx(int idx);
void set_pept_idx(int idx);
void set_seq_idx(int idx);
void set_code(buic::AACode c);
void set_aa_annot(buic::AAAnnot annot);
void set_flag(buic::AtomFlag flag);
int get_serial() const;
int get_atom_num() const;
int get_bond_cnt() const;
const Eigen::Vector3d *get_xyz() const;
double get_x() const;
double get_y() const;
double get_z() const;
int get_mol_idx() const;
int get_pept_idx() const;
int get_seq_idx() const;
buic::AACode get_code() const;
buic::AAAnnot get_aa_annot() const;
buic::AtomFlag get_flag() const;
const std::vector<std::shared_ptr<buic::Atom>> *get_bond() const;
const std::vector<std::shared_ptr<buic::Atom>> *get_bond_up() const;
フレンド関数
共有結合を編集するための関数です.したがって,引数は 2 個の原子となります.
これは,関数の呼び忘れで片方のみ編集してしまうのを防止するために作成しました.わざわざ作成する必要はないので,残すかどうか迷っています.
friend bool is_bound(const std::shared_ptr<buic::Atom> &atom0, const std::shared_ptr<buic::Atom> &atom1);
friend void create_bond_at_atom(const std::shared_ptr<buic::Atom> &atom0, const std::shared_ptr<buic::Atom> &atom1);
friend void delete_bond_at_atom(const std::shared_ptr<buic::Atom< &atom0, const std::shared_ptr<buic::Atom> &atom1);
利用法
Eigen と libbuilcule はインストール済みとします.
Debian では Eigen のヘッダファイルは /usr/include/eigen3/ にインストールされます.
libbuilcule は,/usr/local/lib/liblb3.so*** という共有ライブラリです.
サンプルコード
原子を 1 個生成して,元素と三次元座標を設定するコードを書いてみました.
#include <builcule/lb3/atom.h>
int main() {
//原子番号 6,三次元座標 {3.0, 2.0, 1.0 } という原子を,共有ポインタとして生成
std::shared_ptr<buic::Atom> atom
= std::make_shared<buic::Atom>(6, 3.0, 2.0, 1.0);
//原子番号と三次元座標を出力
std::cout << atom->get_atom_num() << std::endl;
std::cout << *atom->get_xyz() << std::endl;
return 0;
}
ビルドと実行
コンパイル
Eigen のヘッダファイルを -I オプションで指示してコンパイルします.
$ g++ -c main.cc -I/usr/include/eigen3
リンク
libbuilcule は共有ライブラリなので,-llb3 というオプションをつけてリンクしてください.
また,Eigen はヘッダファイルから成るテンプレートライブラリなので,リンクは不要です.
$ g++ -o atom main.o -llb3
ここでは -o オプションで,実行ファイルの名前を atom としました.
実行
実行ファイルのあるディレクトリで,
$ ./atom
とすると,コンストラクタ引数で与えた値が出力されます.
6 3 2 1