あるケミストの独り言(winchemwinの日記)

ケミスト(化学者)の視点で、面白そうな情報(シミュレーション関係など)を発信

Pythonを活用した機械学習用データ作成 その3(誘電率)

 前回の記事で機械学習用データとして屈折率データの算出について紹介してきました。今回はさらに屈折率データを活用した誘電率のデータ作成について紹介します。
 分子の誘電率ですが、オンサガーの式を用いることで屈折率、双極子モーメントデータ等から算出することができます。屈折率は前回の手法で算出でき、またQM9のデータには双極子モーメントの計算データも記載されていますので、これらのデータを活用して誘電率のデータベースを作成してゆきます。

import pandas as pd
import re
from  rdkit import rdBase, Chem
from rdkit.Chem import AllChem
from rdkit.Chem.Draw import IPythonConsole
from rdkit.Chem import Draw
from rdkit.Chem import Descriptors
from rdkit.ML.Descriptors import MoleculeDescriptors
from rdkit.Chem import PandasTools
import numpy as np

# QM9データ読み込み
dfqm9=pd.read_csv("gdb9_prop_smilesN1.csv")
dfqm9N=dfqm9.dropna()
qm9_smi=dfqm9N['Smiles_R']
qm9_pol=dfqm9N['alpha']
qm9_dip=dfqm9N['mu']


Smiles_list=[i for i in qm9_smi]
Mol_list=[Chem.MolFromSmiles(smiles) for smiles in qm9_smi]


Polar_list=[n for n in qm9_pol]
Dip_list=[n for n in qm9_dip]
Volume_list=[]
RefIndex_list=[]
Permit_list=[]

for mol, pol, dip in zip(Mol_list, Polar_list, Dip_list):
    
    # mol = Chem.MolFromSmiles(smi)
    mol_H = Chem.AddHs(mol)
    
    # 分子体積をRdkitで計算
    try:
        AllChem.EmbedMolecule(mol_H)
        vdwvol=AllChem.ComputeMolVolume(mol_H)
    except ValueError:
        pass
        
    Volume_list.append(vdwvol)
    print (vdwvol)
        
    # 屈折率計算(ローレンツ ローレンツ式から)
    vol=(1/(vdwvol*(10**-30)))
    fai=(4*3.14159/3)*vol*(pol*0.148185*10**-30)
    refindex=((1+2*fai)/(1-fai))**0.5

    RefIndex_list.append(refindex)

    
     # 誘電率計算(オンサガー式から) 
    dip_Cm=dip*3.33*10**-30
    ref2=refindex**2
    volm=vdwvol*10**-30*6.02*10**23
    
    Equ_Uhen21=(6.02*10**23*(dip_Cm**2))/(9*(8.852*10**-12)*(1.38*10**-23)*300)
    Permittivity=(((volm+Equ_Uhen21*((ref2+2)**2))+(((volm+Equ_Uhen21*(ref2+2)**2))**2+4*2*volm*volm*ref2*ref2)**0.5))/(2*2*volm)
    Permit_list.append(Permittivity)
    print (f'Per={Permittivity}')
         
print ('calculation finished')

df_Sum_data=pd.DataFrame(list(zip(Smiles_list, Polar_list, Volume_list, RefIndex_list, Permit_list)) ,index=Smiles_list, columns=['Smiles','polarizability/a.u', 'VdwVolume/Angstrom3/mol', 'Refractive Index','Permittivity'])

df_Sum_data.to_csv('Sum_data_Per.csv')

print ('data_save finished')

 分子体積の計算部分はRdkitで算出できる値を用いています。QM9からのデータの読み込みですが、今回はSmilesデータに加えて分極率(alpha)データ、双極子モーメント(mu)も読み込んでいます。
 分子体積の計算値ですが、今回はRdkitから算出される値をそのまま用いています(前回の屈折率の場合は係数処理を実施)。屈折率の計算は「#屈折率計算」以下のコード部分で行っています。また誘電率の計算は「#誘電率計算」以下のコード部分で行っています。算出したデータをリスト化してcsvファイルで保存するのは前回までの紹介と同様です。
 実測値とは必ずしも一致しないデータも多いかと思いますが、データセットを作るという意味で参考になれば幸いです。

Pythonを活用した機械学習用データ作成 その2(屈折率)

 前回までの記事で機械学習用データとして分子体積データの算出について紹介してきました。今回は分子体積データを活用した屈折率のデータ作成について紹介します。
 分子の屈折率ですが、ローレンツローレンツ式を用いることで分子体積と分極率データから算出することができます(Ref 高分子論文集 , Vol. 66, No. 1, pp. 24―30 (Jan., 2009)など)。分子体積は前回までの手法で算出でき、またQM9のデータには分極率の計算データも記載されていますので、これらのデータを活用して屈折率のデータベースを作成してゆきます。

import pandas as pd
import re
from rdkit import Chem
from rdkit.Chem import AllChem

# 分子体積計算関数 (from JOC)

def estimate_volume(molecule):
    """
    Reference is below:
    The Journal of Organic Chemistry, 68(19), 7368--7373, 2003.
    """

    #making atom volume dictionary as a look up table.
    atom_vol = {
        1:   7.24, #H
        6:  20.58, #C
        7:  15.60, #N
        8:  14.71, #O
        9:  13.31, #F
        17: 22.45, #Cl
        35: 26.52, #Br
        53: 32.52, #I
        15: 24.43, #P
        16: 24.43, #S
        33: 26.52, #As
        5:  40.48, #B
        14: 38.79, #Si
        34: 28.73, #Se
        52: 36.62  #Te
    }
    
    vol = 0

    #all atom contributions
    for atom in molecule.GetAtoms():
        vol += atom_vol[atom.GetAtomicNum()];
        
    #5.92Nb
    vol -= molecule.GetNumBonds()*5.92

    #14.7Ra, 3.8Rnr
    ring_info=molecule.GetRingInfo()
    
    rings=ring_info.NumRings()   
    atom_in_rings = ring_info.AtomRings()
    num_aromatic_ring = 0
    for ring in atom_in_rings:
        aromatic_atom_in_ring = 0
        for atom_id in ring:
            ratom = molecule.GetAtomWithIdx(atom_id)
            if ratom.GetIsAromatic():
                aromatic_atom_in_ring +=1
        if aromatic_atom_in_ring==len(ring):
            num_aromatic_ring +=1
            
    vol -=14.7*num_aromatic_ring 
    
    vol -=3.8*(rings-num_aromatic_ring)
    
    return vol;


# QM9データ読み込み
dfqm9=pd.read_csv("Mol_Net_qm9.csv")
qm9_smi=dfqm9['smiles']
qm9_pol=dfqm9['alpha']

Smiles_list=[i for i in qm9_smi]
Mol_list=[Chem.MolFromSmiles(smiles) for smiles in qm9_smi]
Polar_list=[n for n in qm9_pol]
Volume_list=[]
RefIndex_list=[]

for mol, pol in zip(Mol_list, Polar_list):
    
    mol_H = Chem.AddHs(mol)
    
    # 分子体積を関数で計算 (そのままでは実測値よりかなり大きくなるため1.5倍している)
    vdwvol=estimate_volume(mol_H)*1.5
    Volume_list.append(vdwvol)
        
    # 屈折率計算(ローレンツ ローレンツ式から)
    vol=(1/(vdwvol*(10**-30)))
    fai=(4*3.14159/3)*vol*(pol*0.148185*10**-30)
    refindex=((1+2*fai)/(1-fai))**0.5

    RefIndex_list.append(refindex)
    
print ('calculation finished')

df_qm9_RI1=pd.DataFrame(list(zip(Smiles_list, Polar_list, Volume_list, RefIndex_list)) ,index=Smiles_list, columns=['Smiles','polarizability/a.u', 'VdwVolume/Angstrom3/mol', 'Refractive Index'])
df_qm9_RI1.to_csv('qm_RI1.csv')


print ('data_save finished')

 分子体積の計算部分は前回紹介した論文(The Journal of Organic Chemistry, 68(19), 7368--7373, 2003.)の方法を用いています。QM9からのデータの読み込みですが、今回はSmilesデータに加えて分極率(alpha)データも読み込んでいます。
 分子体積の計算値ですが、算出したデータをそのまま用いて屈折率を計算すると実測値との一致があまり良くない結果となりましたので、算出したデータを1.5倍したもので屈折率を算出しています(1.5倍程度の係数をかけるのにはそれなりの説明材料はあるのですが、説明が長くなりますのでここでは割愛させていただきます。興味がありましたらご質問などいただければと思います。)屈折率の計算は「#屈折率計算」以下のコード部分で行っています。算出したデータをリスト化してcsvファイルで保存するのは前回までの紹介と同様です。
 実測値とは必ずしも一致しない屈折率データもあるかと思いますが、「ある程度化合物ごとの傾向がつかめる」データセットを作るという意味で参考になれば幸いです。

Pythonを活用した機械学習用データ作成 その1(分子体積2)

 前回の記事で機械学習用のデータとしてQM9のデータを活用した分子体積データの作成について紹介させていただきました。ただ、Rdkitモジュールを利用した場合計算に少し時間がかかってしまいQM9ぐらのデータ数(10万以上)となるとPCのスペックにもよりますが、かなり時間がかかってしまいます。今回は体積計算にRdkitモジュールを利用せずにより短時間で算出できるコードを紹介します。
 分子体積の計算は過去の論文の報告例(The Journal of Organic Chemistry, 68(19), 7368--7373, 2003)を利用しています。各原子の体積を元に結合数や環構造などを考慮しながらvan del waals 体積を算出しているものになります。

import pandas as pd
import re
from rdkit import Chem
from rdkit.Chem import AllChem

# 分子体積計算関数 (from JOC)

def estimate_volume(molecule):
    """
    Reference is below:
    The Journal of Organic Chemistry, 68(19), 7368--7373, 2003.
    """

    #making atom volume dictionary as a look up table.
    atom_vol = {
        1:   7.24, #H
        6:  20.58, #C
        7:  15.60, #N
        8:  14.71, #O
        9:  13.31, #F
        17: 22.45, #Cl
        35: 26.52, #Br
        53: 32.52, #I
        15: 24.43, #P
        16: 24.43, #S
        33: 26.52, #As
        5:  40.48, #B
        14: 38.79, #Si
        34: 28.73, #Se
        52: 36.62  #Te
    }
    
    vol = 0

    #all atom contributions
    for atom in molecule.GetAtoms():
        vol += atom_vol[atom.GetAtomicNum()];
        
    #5.92Nb
    vol -= molecule.GetNumBonds()*5.92

    #14.7Ra, 3.8Rnr
    ring_info=molecule.GetRingInfo()
    
    rings=ring_info.NumRings()   
    atom_in_rings = ring_info.AtomRings()
    num_aromatic_ring = 0
    for ring in atom_in_rings:
        aromatic_atom_in_ring = 0
        for atom_id in ring:
            ratom = molecule.GetAtomWithIdx(atom_id)
            if ratom.GetIsAromatic():
                aromatic_atom_in_ring +=1
        if aromatic_atom_in_ring==len(ring):
            num_aromatic_ring +=1
            
    vol -=14.7*num_aromatic_ring 
    
    vol -=3.8*(rings-num_aromatic_ring)
    
    return vol;


# QM9データ読み込み
dfqm9=pd.read_csv("Mol_Net_qm9.csv")
qm9_smi=dfqm9['smiles']

Smiles_list=[i for i in qm9_smi]
Mol_list=[Chem.MolFromSmiles(smiles) for smiles in qm9_smi]

Volume_list=[]

for mol in Mol_list:
    
    mol_H = Chem.AddHs(mol)
    
    vdwvol=estimate_volume(mol_H)
        
    Volume_list.append(vdwvol)
    # print (rdvdwvol)
            
print ('calculation finished')

df_qm_Vol2=pd.DataFrame(list(zip(Smiles_list, Volume_list)),index=Smiles_list, columns=['Smiles', 'VdwVolume/Angstrom3/mol'])

df_qm_Vol2.to_csv('qm_vol2.csv')

print ('data_save finished')

 分子体積の計算は最初に関数(estimate_volume(molecule))として定義しています。QM9データの読み込みからmolファイルのリストへの変換は前回市紹介した通りです。今回は得られたモルファイルのリストに対して分子体積計算関数を適応させて体積計算を行い、最終的に算出されたデータをリスト化した後にcsvファイルとして保存しています。
 計算時間ですが、前回のRdkitモジュールAllChem.ComputeMolVolumeでは私のPCで数時間程度かかってしましましたが、今回のコードでは数分程度で終了しました。少ないデータであればRdkitで処理した方が簡単かもしれませんが、大量のデータを処理する際の参考になれば幸いです。
 次回はこれまでの紹介記事で得られたデータをもとに、屈折率の機械学習用データを作成した例について紹介したいと思います。

Pythonを活用した機械学習用データ作成 その1(分子体積1)

 機械学習を活用した材料開発が活発になってきています。機械学習には元になるデータセットが必要ですが、実験データ数には限界もあることから、計算機シュミレーションを活用したデータセットも作成されています。その中でもQMデータセットは数多くの機械学習研究においてベンチマークとして用いられている代表的なデータセットになります。QMデータセットの中でもQM9は10万以上の低分子有機化合物の高レベル量子化学計算のデータが収集されているデータセットで様々な場面で活用されています。ただQM9に収集されていないパラメーターを機械学習に使いたい場面もしばしば遭遇します。そこでQM9のデータを活用して新たに機械学習用のパラメータデータを作成するコードを作成してみましたので紹介したいと思います。今回は分子体積になります(追加できそうなパラメーターが新たにできましたら、随時紹介したいと思います。)

import pandas as pd
import re
from rdkit import Chem
from rdkit.Chem import AllChem

# QM9データ読み込み
dfqm9=pd.read_csv("Mol_Net_qm9.csv")
qm9_smi=dfqm9['smiles']

Smiles_list=[i for i in qm9_smi]
Mol_list=[Chem.MolFromSmiles(smiles) for smiles in qm9_smi]

Volume_list=[]

for mol in Mol_list:
    
    mol_H = Chem.AddHs(mol)
    
    # 分子体積をRdkitで計算
    try:
        AllChem.EmbedMolecule(mol_H)
        rdvdwvol=AllChem.ComputeMolVolume(mol_H)
    except ValueError:
        pass
        
    Volume_list.append(rdvdwvol)
    # print (rdvdwvol)
            
print ('calculation finished')

df_qm_Vol1=pd.DataFrame(list(zip(Smiles_list, Volume_list)),index=Smiles_list, columns=['Smiles', 'VdwVolume/Angstrom3/mol'])

df_qm_Vol1.to_csv('qm_vol1.csv')

print ('data_save finished')

 最初にQM9のデータセット(MoleculeNet等から入手可能)をpandasのデータフレーム(dfqm9)として読み込んでいます。分子体積の計算はRdkitライブラリーの関数でmolファイルから算出可能ですので、QM9のデータセットからmolファイルデータを作成します。
 まず化学構造情報のSMILESデータを取り出した後(qm9_smi)、molファイルに変換しています。分子体積は水素原子を加えた形から計算されますので、molファイルに水素原子を加えた(Chem.AddHs(mol))後にAllChem.EmbedMoleculeで3D構造を発生させています。得られた構造対してAllChem.ComputeMolVolumeの処理を行うことで分子体積を発生させています。最終的に算出されたデータをリスト化したものをデータフレームとした後にcsvファイルとして保存しています。
 以上の処理で分子体積は算出されますが、データ処理にある程度(私のPCでは数時間程度)かかってしまいました。上記の方法でも問題はないかと思いますが、数分程度で終了する別の方法もありますので、次回はその方法を紹介したいと思います。

屈折率自動算出アプリ(CustumTkinter) その5

 前回までに屈折率の自動計算のアプリのコード、利用画面の説明などについて紹介してきました。作成したコードをGitHubに公開していますので、MITライセンスのもとご自由に利用いただければと思います。
 

github.com

 ご利用にあたって、コメント、感想などがあればご連絡ください。

屈折率自動算出アプリ(CustumTkinter) その4

 前回から引き続き屈折率自動算出アプリの紹介です。今回はアプリの利用方法について簡単に紹介したいと思います。
 以下はこのシリーズの最初の回にも紹介したアプリの起動画面になります。

アプリの立ち上げ画面
 画面構成ですが、ファイルの選択、計算方法の設定からなっています。  一番上はSMILES記載ファイルの選択部で、右端の「select」ボタンを押すことで、ファイル選択が画面が現れますので、必要なファイルを選択してOKを押すことで読み込みファイルの設定が行なえます。ファイル形式は基本的にはテキスト形式ですが拡張子として「.txt」と「.smi」が読み込み可能です。  例えば以下のようなSMILESリストを読み込んで連続的に計算させることが可能です。   >
SMILESデータのリスト
 量子化学計算は先の分子軌道情報自動算出アプリと同様でMethod(計算手法:HF, DFTなど)、Function (汎関数B3LYP, PBEなど)、基底関数(3-21G, 6-31G(d)など)をプルダウンメニューから選択することができます。選択できる汎関数や基底関数を増やしたい場合はコード内のリストに付け加えることで実施できるようになるかと思います。  Options設定として、計算機側の設定(Thred数、メモリ)と分子の状態(電荷、スピン多重度)の設定も行えるようにしています。こちらは直接数値を入力する形です。  あと、分極率計算の方法を右側の「Polarizability Calc Set」の箇所で設定します。こちらではcc2法とccsd法を選択できるようになっています。  すべての設定が終えたらアプリ下部の「Quantum Calculation Start」ボタンを押すことで計算がスタートします。アプリを終了したい場合は右下の「Quit」から終了できます。  計算結果は「Calcd_RI_List.csv」に保存されます。  実際の結果は以下のような形で保存されています。 >
分極率の自動計算の結果

それぞれのSMILESに対して、分極率、ファンデルワールス体積、及びそれらの結果から算出される屈折率の値のリストが自動的に作成されてきています。また右端には振動計算(FreqNega)の結果も追加されており、「FALSE」は負の振動数がない、すなわち一応安定構造で計算は実施されているであろうという目安の結果も示しています。

 機械学習等で多くの量子化学計算データを必要とする際にある程度便利に使っていただけるのではないかと思いますので、参考に紹介させていただきました。
 
 屈折率自動算出アプリについては今回で終了としたいと思います。

屈折率自動算出アプリ(CustumTkinter) その3

前回から引き続き屈折率自動算出アプリの紹介です。
前回もコメントさせていただきましたが、基本的なコードは以前に紹介した分子軌道情報(HOMO/LUMO)の自動算出アプリと同じです。
 今回はCustumTkinterのパートの紹介です。
CustumTkinterですが、tkinterと比べてある程度デザイン性に優れた画面を作成することが可能で、設定情報などは以前の分子軌道情報(HOMO/LUMO)の自動算出アプリで紹介させていただきました。
 
 画面の構成ですが、smiles情報を有するファイルの選択、量子化学計算の条件設定
(構造最適化)、分極率の計算方法の設定からなっています。分極率は、cc2法とっccsd法を選択できるようになっています。
 一般的には分極率の計算は量子化学計算において分散関数を使用することが推奨されますが、計算コストの関係から必ずしも対応できない場合もあるので、その辺は量子化学計算の計算手法を適宜選択できるように設定しています。
 

# Custon Tkinter main 

ctk.set_appearance_mode('dark')
# global root
root = ctk.CTk()
root.title("Reflactive Index List Calculator") 
root.geometry('700x450')

# Select main molecule file
Label1=ctk.CTkLabel(master=root, fg_color='blue',corner_radius=10, text='Smiles File Select',font=("Arial",16,"bold","italic"))
Label1.place(x=20, y=20)

filename_sv = tk.StringVar()
filenameEntry = ctk.CTkEntry(master=root, width=500,  textvariable=filename_sv)
filenameEntry.place(x=20, y= 50)

Button1 = ctk.CTkButton(master=root, text='Select',width=30,font=("Times",14,"bold"))
Button1.bind("<Button-1>", data_import) 
Button1.place(x=600, y=50)



# Calculation Run
Button2_3=ctk.CTkButton(master=root, text='Quantum Calculation Start',width=50, font=("Times",14,"bold"))
Button2_3.bind("<Button-1>", start_calc_button) 
Button2_3.place(x=70, y=330)


# Select calculation methods
Label3=ctk.CTkLabel(master=root, fg_color='blue',corner_radius=10, text='Quantum Calculation Method', font=("Arial",16,"bold","italic"))
Label3.place(x=20, y=100)

Label3_1=ctk.CTkLabel(master=root, text='Method',font=("Times",12))
Label3_1.place(x=70, y=140)
method_sv = tk.StringVar()
methods=('HF','DFT', 'MP2')
comboBox3_1=ctk.CTkComboBox(master=root, height=5, width=80, border_color='blue',state='readonly', values=methods, variable=method_sv)
comboBox3_1.place(x=70, y=160)

Label3_2=ctk.CTkLabel(master=root, text='Function',font=("Times",12))
Label3_2.place(x=170, y=140)
function_sv = tk.StringVar()
functions=('','b3lyp','cam-b3lyp', 'edf2','m06', 'pbe','wb97x-d')
comboBox3_2=ctk.CTkComboBox(master=root, height=5, width=80, border_color='blue',state='readonly', values=functions, variable=function_sv)
comboBox3_2.place(x=170, y=160)

Label3_3=ctk.CTkLabel(master=root, text='Basis set',font=("Times",12))
Label3_3.place(x=270, y=140)
baseset_sv = tk.StringVar()
# sto-3g で計算すると何故か異常に遅くなる(PCがほぼハングアップ状態)ため、削除した
base_sets=('3-21g','6-31g', '6-31g(d)','6-311g', 'aug-cc-pvtz')
comboBox3_3=ctk.CTkComboBox(master=root, height=5, width=80,border_color='blue', state='readonly', values=base_sets, variable=baseset_sv)
comboBox3_3.place(x=270, y=160)

# Select options
Label4=ctk.CTkLabel(master=root, text='Options', font=("Times",14,"bold"))
Label4.place(x=70, y=180)

Label4_1=ctk.CTkLabel(master=root, text='Tread',font=("Times",12))
Label4_1.place(x=80, y=200)
threads=tk.IntVar(value=2)
textBox1_1=ctk.CTkEntry(master=root, width=50, textvariable=threads)
textBox1_1.place(x=80, y=220)

Label4_2=ctk.CTkLabel(master=root, text='Memory/MB',font=("Times",12))
Label4_2.place(x=180, y=200)
memory=tk.IntVar(value=500)
textBox1_2=ctk.CTkEntry(master=root, width=50, textvariable=memory)
textBox1_2.place(x=180, y=220)

Label4_3=ctk.CTkLabel(master=root, text='Charge',font=("Times",12))
Label4_3.place(x=80, y=250)
charge=tk.IntVar(value=0)
textBox2_1=ctk.CTkEntry(master=root, width=50, textvariable=charge)
textBox2_1.place(x=80, y=270)

Label4_4=ctk.CTkLabel(master=root, text='Multiplicity',font=("Times",12))
Label4_4.place(x=180, y=250)
multi=tk.IntVar(value=1)
textBox2_2=ctk.CTkEntry(master=root, width=50, textvariable=multi)
textBox2_2.place(x=180, y=270)

# select Polar calc method

Label5=ctk.CTkLabel(master=root, fg_color='blue',corner_radius=10, text='Polarizability Calc Set', font=("Arial",12,"bold","italic"))
Label5.place(x=400, y=100)

Label5_1=ctk.CTkLabel(master=root, text='Calculation method',font=("Times",12))
Label5_1.place(x=420, y=130)
method_sv_pol = tk.StringVar()
methods=('cc2','ccsd')
comboBox5_1=ctk.CTkComboBox(master=root, height=5, width=80, border_color='blue',state='readonly', values=methods, variable=method_sv_pol)
comboBox5_1.place(x=420, y=160)


# Finish program
Label6=ctk.CTkLabel(master=root, text='Finish the program')
Label6.place(x=550, y=370)
Button3 = ctk.CTkButton(master=root, text='Quit',width=30, command=scry_finish,font=("Times",14,"bold"))
Button3.place(x=550, y=390)


root.mainloop()

 コードは上記の通りで、CustumTkinter特有の設定を少し意識すればそれほど難しいものではありません。アプリの使い方等は次回に紹介したいと思います。