読み取りにくい SI の座標を変換するプログラム

計算化学の論文では、SI の座標情報を読み取りづらくしている場合が多く見受けられます。
計算化学は、座標情報さえあれば簡単に論文を出せてしまうため仕方のない対策のように思われますが、先行研究を参考にしたい時に手間がかかります。まだ、小さな分子である場合は手作業で SI の座標情報を input ファイルに直すことができますが、巨大分子系ではそうも行きません。
そこで、今回は、読み取りにくい SI の座標を変換するプログラムを紹介したいと思います。

今回は、例としてこちらの論文の SI を用います。約 500 原子からなる系です。
“Mechanism of Formation of the Internal Aldimine in Pyridoxal 5’-Phosphate-Dependent Enzymes”
Eduardo F. Oliveira, Nuno M. F. S. A. Cerqueira, Pedro A. Fernandes and Maria J. Ramos
J. Am. Chem. Soc. 2011, 133, 15496–15505. DOI: dx.doi.org/10.1021/ja204229m

まず、SI の座標を読み取りテキストエディターに貼り付けますと以下のようになります。

N 0.7665 -0.7973 10.6922 C 0.6365 -1.9674 9.8508 C 0.1587 -1.6366 8.4152 O -0.3826 -0.5454 8.1474 C -0.3178 -3.0079 10.4353 H -0.1280 -0.3643 10.8258 H 1.3794 -0.1315 10.2598 H 1.6698 -2.4252 9.7785 H -0.2801 -3.9415 9.8248 H -1.3666 -2.6257 10.4411 H -0.0221 -3.2561 11.4832 N 0.3437 -2.6123 7.4567 C 0.1762 -2.3525 6.0515 C -1.0865 -3.0566 5.4892 O -2.0097 -2.3798 4.9987 C 1.3984 -2.7172 5.2301 S 2.1810 -4.3331 5.6932 H 0.8392 -3.4454 7.6944 H -0.0248 -1.2401 5.9116 H 1.1542 -2.7115 4.1598 H 2.1801 -1.9630 5.3960 H 1.5436 -5.1171 4.7961 N -1.1076 -4.4379 5.5082 C -2.3233 -5.1858 5.2813 C -2.8060 -5.8316 6.6052 O -1.9950 -6.1393 7.5080 C -2.1440 -6.3069 4.2382 C -3.4156 -6.6044 3.4587 O -3.3356 -6.9426 2.2333 O -4.5627 -6.5116 3.9975 H -0.4120 -4.9094 6.0500 H -3.1161 -4.4679 4.9052 H -1.3561 -6.0122 3.4947 H -1.7905 -7.2458 4.7396 N -4.1651 -6.0404 6.7644 C -4.6238 -6.9421 7.7806 C -3.9515 -8.3253 7.8260 O -3.9764 -8.9907 8.8791 H -4.7269 -5.9803 5.9323 H -4.4249 -6.4828 8.7933 H -5.7310 -7.1037 7.6596 N -3.2896 -8.7739 6.6976 C -2.4367 -9.9327 6.7174 C -1.0136 -9.6265 6.2440 O -0.3213 -10.3817 5.5586 C -2.9772 -11.1004 5.8888 H -2.2459 -11.9436 5.9325 H -3.1092 -10.8057 4.8204 H -3.9574 -11.4414 6.2978 H -3.4928 -8.3749 5.8084 H -2.3381 -10.2779 7.7960 O -0.3796 -8.4786 6.5993 H -0.9338 -7.9357 7.1843 N 4.6918 4.0845 -1.5677 C 4.9815 4.5365 -0.2314 C 6.3263 4.0237 0.3483 O 6.8772 2.9927 -0.0994 C 3.8860 4.1680 0.7699 H 4.5110 3.0993 -1.5908 H 5.4460 4.2869 -2.1977 H 5.0450 5.6670 -0.2880 H 4.1308 4.5821 1.7779 H 3.7744 3.0596 0.8530 H 2.9084 4.5983 0.4421 N 6.8882 4.7513 1.3725 C 8.1172 4.3699 2.0230 C 8.0651 2.9615 2.6696 O 9.0658 2.2165 2.5893 C 8.5730 5.3993 3.0820 C 9.7894 4.8826 3.8210 C 8.8851 6.7264 2.4208 H 6.3790 (以下略)

ご覧の通り、一行ごとの改行が全くありません。このままでは Gauss View で読み取ることができません。
そこで、以下のようなプログラムを作成しました。プログラムは C++ で記述してあります。

#include<iostream>
#include<fstream>
#include<string>

using namespace std;

int main(int argc, char *argv[]){

    if(argc==1){
        cout << "Input Error\n./SI_Decipher [filename.com]" << endl;
        exit(1);
    }
    
    ifstream ifs(argv[1]);
    string str;
    
    int file_length (0);
    for(int i (0); argv[1][i] !='
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main(int argc, char *argv[]){
if(argc==1){
cout << "Input Error\n./SI_Decipher [filename.com]" << endl;
exit(1);
}
ifstream ifs(argv[1]);
string str;
int file_length (0);
for(int i (0); argv[1][i] !='\0'; ++i)file_length +=1;
for(int i = (file_length-4); i <= file_length-1; i++){
argv[1][i] = '\0';
}
char outputfile[50];
sprintf(outputfile,"%s_converted.com", argv[1]);
ofstream ofs(outputfile);
ofs << "#hf/3-21g\n\ntitle card required \n\n0 1";
while(getline(ifs,str)){
for(int i(0); i < (int)str.size(); ++i){
if(str[i] == 'C'){ ofs << endl ;
}if(str[i] == 'H'){ ofs << endl ;
}if(str[i] == 'O'){ ofs << endl ;
}if(str[i] == 'N'){ ofs << endl ;
}if(str[i] == 'S'){ ofs << endl ;
}if(str[i] == 'P'){ ofs << endl ;
}
ofs << str[i];
}
ofs << "\n\n\n" ;
}
}
'; ++i)file_length +=1; for(int i = (file_length-4); i <= file_length-1; i++){ argv[1][i] = '
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main(int argc, char *argv[]){
if(argc==1){
cout << "Input Error\n./SI_Decipher [filename.com]" << endl;
exit(1);
}
ifstream ifs(argv[1]);
string str;
int file_length (0);
for(int i (0); argv[1][i] !='\0'; ++i)file_length +=1;
for(int i = (file_length-4); i <= file_length-1; i++){
argv[1][i] = '\0';
}
char outputfile[50];
sprintf(outputfile,"%s_converted.com", argv[1]);
ofstream ofs(outputfile);
ofs << "#hf/3-21g\n\ntitle card required \n\n0 1";
while(getline(ifs,str)){
for(int i(0); i < (int)str.size(); ++i){
if(str[i] == 'C'){ ofs << endl ;
}if(str[i] == 'H'){ ofs << endl ;
}if(str[i] == 'O'){ ofs << endl ;
}if(str[i] == 'N'){ ofs << endl ;
}if(str[i] == 'S'){ ofs << endl ;
}if(str[i] == 'P'){ ofs << endl ;
}
ofs << str[i];
}
ofs << "\n\n\n" ;
}
}
'; } char outputfile[50]; sprintf(outputfile,"%s_converted.com", argv[1]); ofstream ofs(outputfile); ofs << "#hf/3-21g\n\ntitle card required \n\n0 1"; while(getline(ifs,str)){ for(int i(0); i < (int)str.size(); ++i){ if(str[i] == 'C'){ ofs << endl ; }if(str[i] == 'H'){ ofs << endl ; }if(str[i] == 'O'){ ofs << endl ; }if(str[i] == 'N'){ ofs << endl ; }if(str[i] == 'S'){ ofs << endl ; }if(str[i] == 'P'){ ofs << endl ; } ofs << str[i]; } ofs << "\n\n\n" ; } }

このプログラムでは、C, H, O, N, S, P という文字を発見したら改行するというものです。
簡易的に作ったものなので、すべての分子に対応しているわけではないですが、あらゆる分子に対応したプログラムに改変することはそれほど難しくないと思います。
重要なのは、問題に直面にした時にササっと自分でプログラムを作れることだと思います。綺麗なプログラムを作ることが目的なのではなくて、研究を円滑に進めることが目的なので時間をかけすぎないよう、いつも心がけています。

このプログラムを実行しますと以下のように変換され、Gauss View で可視化できるようになります。

#hf/3-21g

title card required 

0 1
N 0.7665 -0.7973 10.6922 
C 0.6365 -1.9674 9.8508 
C 0.1587 -1.6366 8.4152 
O -0.3826 -0.5454 8.1474 
C -0.3178 -3.0079 10.4353 
H -0.1280 -0.3643 10.8258 
H 1.3794 -0.1315 10.2598 
H 1.6698 -2.4252 9.7785 
H -0.2801 -3.9415 9.8248 
H -1.3666 -2.6257 10.4411 
H -0.0221 -3.2561 11.4832 
N 0.3437 -2.6123 7.4567 
C 0.1762 -2.3525 6.0515 
C -1.0865 -3.0566 5.4892 
O -2.0097 -2.3798 4.9987 
C 1.3984 -2.7172 5.2301 
S 2.1810 -4.3331 5.6932 
H 0.8392 -3.4454 7.6944 
H -0.0248 -1.2401 5.9116 
H 1.1542 -2.7115 4.1598 
H 2.1801 -1.9630 5.3960 
H 1.5436 -5.1171 4.7961 
N -1.1076 -4.4379 5.5082 
C -2.3233 -5.1858 5.2813 
C -2.8060 -5.8316 6.6052 
O -1.9950 -6.1393 7.5080 
C -2.1440 -6.3069 4.2382 
C -3.4156 -6.6044 3.4587 
O -3.3356 -6.9426 2.2333 
O -4.5627 -6.5116 3.9975 
H -0.4120 -4.9094 6.0500 
H -3.1161 -4.4679 4.9052 
H -1.3561 -6.0122 3.4947 
H -1.7905 -7.2458 4.7396 
N -4.1651 -6.0404 6.7644 
C -4.6238 -6.9421 7.7806 
C -3.9515 -8.3253 7.8260 
O -3.9764 -8.9907 8.8791 
H -4.7269 -5.9803 5.9323 
H -4.4249 -6.4828 8.7933 
H -5.7310 -7.1037 7.6596 
N -3.2896 -8.7739 6.6976 
C -2.4367 -9.9327 6.7174 
C -1.0136 -9.6265 6.2440 
O -0.3213 -10.3817 5.5586 
C -2.9772 -11.1004 5.8888 
H -2.2459 -11.9436 5.9325 
H -3.1092 -10.8057 4.8204 
H -3.9574 -11.4414 6.2978 
H -3.4928 -8.3749 5.8084 
H -2.3381 -10.2779 7.7960 
O -0.3796 -8.4786 6.5993 
H -0.9338 -7.9357 7.1843 
N 4.6918 4.0845 -1.5677 
C 4.9815 4.5365 -0.2314 
C 6.3263 4.0237 0.3483 
O 6.8772 2.9927 -0.0994 
C 3.8860 4.1680 0.7699 
H 4.5110 3.0993 -1.5908 
H 5.4460 4.2869 -2.1977 
H 5.0450 5.6670 -0.2880 
H 4.1308 4.5821 1.7779 
H 3.7744 3.0596 0.8530 
H 2.9084 4.5983 0.4421 
N 6.8882 4.7513 1.3725 
C 8.1172 4.3699 2.0230 
C 8.0651 2.9615 2.6696 
O 9.0658 2.2165 2.5893 
C 8.5730 5.3993 3.0820 
C 9.7894 4.8826 3.8210 
C 8.8851 6.7264 2.4208 
H 6.3790 5.5096 1.7746 
(以下略)

筆者は、プログラムの専門家ではありませんので、より良いコード、間違いなどがありましたら、コメントまたはメール等でご指摘いただければ幸いです。

2 comments

  1. いつも興味深く読ませていただいております。

    数十原子程度の遷移金属錯体を扱っている実験屋です。
    プログラミングについては初心者ですが、
    >for(int i(0); i < (int)str.size(); ++i){
    >……
    >}
    の箇所は繰り返しのたびにstr.size()が評価されてしまうので、
    事前にstr.size()の結果を変数に代入した方がマナーに則った書き方なのではないかと思います。(500原子ほどならそれほど速度は気にしないでもいいと思うので、この書き方でも、よろしいと思いますが。)

    また、この書き方ではCuなどが含まれる場合にCとuの間で改行されてしまうため、
    #include
    #include
    #include

    int main()
    {
    const std::string s = “Cu 1. 2. 3. C 1. 2. 3. Si 1. 2. 3. “;
    const std::regex re(“[A-Z][a-z]?”);
    const std::string fmt = “\n$&”;
    std::cout << std::regex_replace(s, re, fmt) << std::endl;
    }
    のような書き方はいかがでしょうか。

    1. いつも読んでいただきありがとうございます。
      ご指摘の通りだと思います。参考にさせていただきたいと思います。
      私は独学でプログラミングを勉強したため、あまり詳しくありませんので、今回のようなアドバイスはとてもありがたいです。
      今後も、また当サイトを読んでいただければ幸いです。

コメントを残す(投稿者名のみ必須)