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

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

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

 前回から引き続き屈折率自動算出アプリの紹介です。
 具体的なコードですが、基本的なところは以前に紹介した分子軌道情報(HOMO/LUMO)の自動算出アプリと同じです。
 最初にライブラリーのインポートと各種関数の設定を行っています。
 屈折率はローレンツローレンツ式から分子の分極率と分子体積の情報をあれば求めることができるので、今回は分極率計算を'Pol_calc()'の関数で定義しています。分極率は基本的には分散関数を用いた計算で行うことでより正確な値が得られますが、計算コストの関係で、より簡便な計算手法(分散関数を用いないレベル)でも計算できるように設定しています。
 分子体積の方はRdkitのモジュール(AllChem.ComputeMolVolume)で計算したものを用いています。ここで得られる分子体積については、ローレンツローレンツ式で一般的に用いられる数値よりも小さめになっていますが、分子の構造変化に伴う「傾向」を掴むという意味では使える数値ではないかということで採用でしています。
 最終的に計算された分極率と分子体積から「# 屈折率計算の部分」のコードに基づき、屈折率を計算しています。
 上記説明以外の部分は分子軌道情報(HOMO/LUMO)の自動算出アプリとほぼ同じかと思います。

import customtkinter as ctk
import tkinter as tk
from tkinter import ttk
from tkinter import StringVar, messagebox
from turtle import onclick
from tkinter import filedialog
import numpy as np
import pandas as pd
from numpy import matlib
from tkinter.ttk import Entry
import psi4
from  rdkit import rdBase, Chem
from rdkit.Chem import AllChem
import re

# Smiles file select by filedialog 
def data_import(self):
    type=[('smi file','*.smi'), ('text file', '*.txt')]
    file=filedialog.askopenfilename(filetypes=type)
    filename_sv.set(file)
    global fname_smi
    fname_smi=filename_sv.get()

    return fname_smi

def start_calc_button(self):
    Labelex_1=ctk.CTkLabel(master=root, text='Calculation was started',font=("Times",12))
    Labelex_1.place(x=50, y=370)
    
    root.after(100, calc_run)
    
def Geom_Opt():
    # Geometry optimization
    # getting meth(calculation method), func(function), base(basis set) 
    meth=method_sv.get()
    func=function_sv.get()
    base=baseset_sv.get()
    
    psi4.set_options({'geom_maxiter': 50,
    'optking__g_convergence': 'gau_loose',})
    
    # geometry optimize calculation (method in HF and MP2, function in DFT)
    if meth=='HF':
        psi4.optimize(meth+'/'+base, molecule=molgeom)
        
    elif meth=='DFT':
        
        psi4.optimize(func+'/'+base, molecule=molgeom)
        
    elif meth=='MP2':
        psi4.optimize(meth+'/'+base, molecule=molgeom)
    
    optimized_geom = molgeom.save_string_xyz_file()
                  
def Vib_Calc():
    # Frequency calculation
    meth=method_sv.get()
    func=function_sv.get()
    base=baseset_sv.get()
    
    # Frequency calculation (method in HF and MP2, function in DFT)
    if meth=='HF':        
        energy, wfn = psi4.frequency(meth+'/'+base, molecule=molgeom, return_wfn=True)
        
    elif meth=='DFT':
        energy, wfn = psi4.frequency(func+'/'+base, molecule=molgeom, return_wfn=True)
        
    elif meth=='MP2':
        energy, wfn = psi4.frequency(meth+'/'+base, molecule=molgeom, return_wfn=True)
    
    # making frequency list

    freqlist = np.array(wfn.frequencies())
    freqposi=freqlist[(freqlist>1)&(freqlist<5000)]
    global freqnega
    freqnega=freqlist[(freqlist<0)]

    return freqposi, freqnega

def Pol_calc():
    meth_pol=method_sv_pol.get()
    base=baseset_sv.get()
          
    polar = psi4.properties(meth_pol+'/'+base,properties=['polarizability'], molecule=molgeom)
        

def calc_run():
    global fname_smi
    chr=charge.get()
    mul=multi.get()
    
    with open (fname_smi) as f:
        readsmiles=f.read()
    
    smiles=readsmiles.split()
    
    # 振動計算の結果のリスト
    freq_results=[]
    # Smile Index のリスト 
    smiIndex=[]
    
    # 各データのリスト
    polar_list=[]
    volume_list=[]
    refIndex_list=[]
      
    #  Conformer search by rdkit then make xyz file
    for i, smi in enumerate(smiles): 

        mol = Chem.MolFromSmiles(smi)
        mol_H = Chem.AddHs(mol)
            
        confs = AllChem.EmbedMultipleConfs(mol_H, 10, pruneRmsThresh=1)
        prop = AllChem.MMFFGetMoleculeProperties(mol_H)

        energy=[]
        
        for conf in confs:
            mmff = AllChem.MMFFGetMoleculeForceField(mol_H, prop,confId=conf)
            mmff.Minimize()
            energy.append((mmff.CalcEnergy(), conf))
    
            conflist = np.array(energy)
            sortconf=conflist[np.argsort(conflist[:,0]) ]

            stconfid=sortconf[0,1]
            stconfid2=int(stconfid)
            stconfgeom=mol_H.GetConformer(stconfid2)

        xyz = f'{chr} {mul}'
        for atom, (x,y,z) in zip(mol_H.GetAtoms(), stconfgeom.GetPositions()):
            xyz += '\n'
            xyz += '{}\t{}\t{}\t{}'.format(atom.GetSymbol(), x, y, z)
                  
        #  Setting input file
        global molgeom
        molgeom = psi4.geometry(xyz)
               
    # Set calculation method
        thre=threads.get()
        mem=memory.get()
        psi4.set_num_threads(nthread=thre)
        psi4.set_memory(mem*1000000)
       
        psi4.core.clean()
        # Set output files
        psi4.set_output_file(str(i)+smi+'-molgeom.txt')

        # 計算経過の表示
        # global root, Labelex_2
        Labelex_2=ctk.CTkLabel(master=root, text='No'+str(i)+'  '+smi+' Calc was started',font=("Times",10))
        Labelex_2.place(x=50, y=390)
       
        Labelex_2.update()
        
        # 構造最適化ー収束エラー時の対応も含む
        try:
            Geom_Opt()
            root.update()
        except  psi4.driver.p4util.exceptions.OptimizationConvergenceError as err:
            print (err)
       
            continue
        
        optimized_geom = molgeom.save_string_xyz_file()
        with open (str(i)+smi+'-optgeom.xyz','w') as f:
            f.write(optimized_geom)
        
        # 振動計算
        Vib_Calc()
        root.update()
        if freqnega:
            freq_data='True'         
        else:
            freq_data='False'
            
        freq_results.append(freq_data)  
        
        # 分極率計算
        Pol_calc()
        root.update()
        
        path = '/home/winmori/'+str(i)+smi+'-molgeom.txt'
        with open (path) as f:
            alltext= f.readlines()
        endgyou = len(alltext)
        endtxt = alltext[endgyou-1].strip()
        print (endtxt)

        polar_base=re.findall(r"[\d\.\d]+",endtxt)
        
        polar_result=float(polar_base[1])
        
        
        # 分子体積計算(rdkit)
        try:
            AllChem.EmbedMolecule(mol_H)
            rdvdwvol=AllChem.ComputeMolVolume(mol_H)
        except ValueError:
            pass
        
        # 屈折率計算
        vol=(1/(rdvdwvol*(10**-30)))
        fai=(4*3.14159/3)*vol*(polar_result*0.148185*10**-30)
        refindex=((1+2*fai)/(1-fai))**0.5

        # データのまとめ

        refIndex_list.append(refindex)
        polar_list.append(polar_result)
        volume_list.append(rdvdwvol)
        
        smiIndex.append(smi)
        
        Data_RI=pd.DataFrame(list(zip(smiIndex, polar_list, volume_list, refIndex_list)) , columns=['Smiles','polarizability/a.u', 'VdwVolume/Angstrom3/mol', 'Refractive Index']) 
       
        Data_RI['FreqNega']=freq_results
    
        Data_RI.to_csv('Calcd_RI_List.csv')     
    
    Labelex_4=ctk.CTkLabel(master=root, text='Calculation was finished', font=("Times",12,"bold"))
    Labelex_4.place(x=50, y=410)
                
# finish program

def scry_finish():
    exit()        

 以上、屈折率自動算出アプリのコード(関数設定、屈折率計算方法等)について紹介させていただきました。
 次回はCustumTkinterのパートについて紹介したいと思います。

 

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

 データサイエンスの活用が進むにつれて、機械学習用のデータの入手、作成の重要性が増してきているように思います。最近では学習用データとして、実験データだけでなく計算機シミュレーションの活用が進められてきています。このような背景から、先の記事までに分子軌道情報(HOMO/LUMO)の自動算出アプリについて紹介してきました。
 今回以降、別の物性値として屈折率の自動算出アプリについて紹介してゆきたいと思います。基本的な入力項目は分子軌道情報のアプリと同じですが、屈折率の算出のところが少し変わっていますので、皆さんの参考になれば幸いです。
 アプリの起動画面は以下のような感じになります。今回もCustumTkinterで作成しています。

屈折率算出アプリの立ち上げ画面

 このアプリでは化学物質のSMILESリストから屈折率のリストを自動作成し、csvファイルに保存できるようになっています。画面的には前述のように、分子軌道情報のアプリとほぼ同じですが、屈折率計算用の計算の設定の部分が少し変わっています。
 次回以降具体的なコードについて紹介してゆきたいと思います。

 

分子軌道情報(HOMO/LUMO)自動算出アプリ(CustumTkinter) その8

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

github.com


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

分子軌道情報(HOMO/LUMO)自動算出アプリ(CustumTkinter) その7

 これまでのシリーズでは軌道情報の自動計算アプリのコードの紹介をしてきました。今回はアプリの利用方法について簡単に紹介したいと思います。
 以下はこのシリーズの最初の回にも紹介したアプリの起動画面になります。

分子軌道情報自動算出アプリ 起動画面

 画面構成ですが、ファイルの選択、計算方法の設定、算出する軌道レベルの設定からなっています。
 一番上はSMILES記載ファイルの選択部で、右端の「select」ボタンを押すことで、ファイル選択が画面が現れますので、必要なファイルを選択してOKを押すことで読み込みファイルの設定が行なえます。ファイル形式は基本的にはテキスト形式ですが拡張子として「.txt」と「.smi」が読み込み可能です。
 例えば以下のようなSMILESリストを読み込んで連続的に計算させることが可能です。
 

 量子化学計算はMethod(計算手法:HF, DFTなど)、Function (汎関数B3LYP, PBEなど)、基底関数(3-21G, 6-31G(d)など)をプルダウンメニューから選択することができます。選択できる汎関数や基底関数を増やしたい場合はコード内のリストに付け加えることで実施できるようになるかと思います。
 Options設定として、計算機側の設定(Thred数、メモリ)と分子の状態(電荷、スピン多重度)の設定も行えるようにしています。こちらは直接数値を入力する形です。

 あと、算出する軌道レベルの数を右側の「HOMO/LUMO Level」の箇所で設定します。デフォルトでは5となっており、HOMO-5、LUMO+5まで計算する設定になっています。

 すべての設定が終えたらアプリ下部の「Quantum Calculation Start」ボタンを押すことで計算がスタートします。アプリを終了したい場合は右下の「Quit」から終了できます。

 計算結果はそれぞれ「Calcd_HOMO_List.csv」、「Calcd_LUNO_List.csv」に保存されます。
 実際の結果は以下のような形で保存されています。

分子軌道リスト計算結果 1
<>
分子軌道リスト結果 2

 それぞれのSMILESに対して、各軌道のエネルギー情報のリストが自動的に作成されてきています。また右端には振動計算(FreqNega)の結果も追加されており、「FALSE」は負の振動数がない、すなわち一応安定構造で計算は実施されているであろうという目安の結果も示しています。

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

 

分子軌道情報(HOMO/LUMO)自動算出アプリ(CustumTkinter) その6

 前回に引き続きCustumTkinterを利用した軌道情報の自動計算アプリの紹介です。
今回もCustumTkinter関連のコードの設定コードの紹介の続きです。
計算手法のoption設定の表示ですが、数値入力がメインですのてtextBoxのウィジェットを使用しています。このウィジェットも基本的にはtkinterと同様の設定で利用できますので、それぞれ、スレッド数、メモリ、電荷、多重度、さらには表示させるHOMO/LUMOレベルの入力のウィジェットを設置しています。
 
 後はプログラム終了用にQuitのボタンのウィジェットを右下に設置しています。

# 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 HOMO/LUMO level

Label5=ctk.CTkLabel(master=root, fg_color='blue',corner_radius=10, text='HOMO/LUMO Level', font=("Arial",14,"bold","italic"))
Label5.place(x=400, y=100)

Label5_1=ctk.CTkLabel(master=root, text='Orbital level',font=("Times",12))
Label5_1.place(x=420, y=130)
orb_input=tk.IntVar(value=5)
textBox5_1=ctk.CTkEntry(master=root, width=50, textvariable=orb_input)
textBox5_1.place(x=420, y=150)


# 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()

 今回は短いですが、以上になります。次回はこのアプリの使用方法などについて紹介したいと思います。

分子軌道情報(HOMO/LUMO)自動算出アプリ(CustumTkinter) その5

 前回に引き続きCustumTkinterを利用した軌道情報の自動計算アプリの紹介です。
今回はCustumTkinter関連のコードの設定コードの紹介です。CustumTkinterですが、tkinterと比べてある程度デザイン性に優れた画面を作成することが可能です。画面のモードの設定ですが、set_appearance_modeで設定することができ、'dark'と'light'モードが設定できるようです。lightモードの場合は従来のtkinterに近いイメージとなるかと思います。あと今回のコードでは設定していませんが、set_default_color_themeで色味の設定も行なえます(’bule(default), dark-blue, green)。

 画面の設定ですが、従来のtkinterと同様にtitleとgeometryを設定して、設置することができます。 
 続いて、表示用のLabel, 入力用のButton, ConboBox などを設置してゆきますが、この辺のウィジェットtkinterと同様のコードで設定可能です。ただしウィジェットによって色味の設定も可能でfg_color(テキストの背景の色)、border_color(境界線の色)などの設定も適宜行っています。

 画面の構成ですが、smiles情報を有するファイルの選択、量子化学計算の条件設定、表示させる軌道レベル数からなっており、今回は量子化学計算の基本条件設定までのコードを紹介しています。

# Custon Tkinter main 

ctk.set_appearance_mode('dark')
# global root
root = ctk.CTk()
root.title("HOMO-LUMO 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()

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)

 今回は以上になります。次回は残りのCustumTkinterのコードについての紹介をしたいと思います。

分子軌道情報(HOMO/LUMO)自動算出アプリ(CustumTkinter) その4

 前回に引き続きCustumTkinterを利用した軌道情報の自動計算アプリの紹介です。
 今回は計算実行用の処理関数の設定コードの紹介です。
 始めに入力内容から化合物の情報(charge:電荷, multi:スピン多重度)、表示軌道数(orb)を読み込んでいます。また計算する化合物群のSMILESを読み込み、split()処理を行ってリスト化を行っています。
 ここで作成したSMILESのリストに従って、for文を利用して連続的に計算処理を行っています。
 まずはSMILESのそれぞれの化学構造情報(smi)をもとにRdkitの機能を用いてコンフォマーサーチを行い、初期安定化構造の座標を得られるようにしています。SMILESからのデータですのでmolファイルへの変換後の初期座標はあまりあてになりませんので、このような操作を入れています。この辺りのコードについては下記の過去の記事を参照していただけると助かります。

winchemwin.hatenablog.com

 続いて計算機条件の(threads, memory)の設定です。こちらもそれぞれの入力値をから設定できるようにしています。
 計算経過の表示ですが、CustumTkinter のラベル機能でどのSMILESデータの計算が行われているか表示させるようにしています。最初は一番最初の表示のみが表示され、その後次の計算の経過は表示されなかったのですが、ウィジェットのupdate()の機能を使うことで随時の計算経過の表示ができるようになりました(ご存知の方は当たり前のことかと思いますが・・・)。
 
 構造最適化ですが、化合物によっては所定の回数で計算が収束せずエラー(OptimizationConvergenceError)がでる場合もありますので、その対策としてtry, except での対応を行っています。(エラーで計算が途中で止まってしまうと、SMILESリストの残りの計算が行われず、未計算の部分のみを再計算を行う必要があり、非効率となるための対策です)
 
 構造最適化の次は振動計算(処理関数:Vib_Calc())ですが、ここでは負の振動数が得られた場合(安定構造ではない)場合のチェックを行っており、負の振動数が得られた場合にはfreq_data='True' として記録し、後の結果表示で確認しやすくしています。

 最後は分子軌道計算(処理関数:MO_anal())です。得られた分子軌道の情報(HOMOnp, LUMOnp)はnumpyのarrayの形で処理し、for文の処理で得られるそれぞれのSMILESに対応したデータはnumpyのvstackで蓄積するようにしています。得られたデータはsmilesのIndexを作成した上でpandasのデータフレームの形で整理しています('FreqNega'の情報も追記)。
 ここで都度データフレームを作成して、csvファイルを保存しているのは、まどろっこしいように思われるかもしれませんが、量子化学計算時に化学構造によっては先のOptimizationConvergenceError以外にもトラブルが生じて、止まってしまうことがあるので、そういった事例への対応の意味となります。他に良い方法があるのかもしれませんが、長い時間かけて実施してきた計算結果が最後の計算のエラーのために、また一からというのはなかなか厳しいものがありますので・・・

def calc_run():
    global fname_smi
    chr=charge.get()
    mul=multi.get()
    orb=orb_input.get()
    with open (fname_smi) as f:
        readsmiles=f.read()
    
    smiles=readsmiles.split()
    
    # Frequency calculations list
    freq_results=[]
    # Smile Index list
    
    smiIndex=[]
      
    #  Conformer search by rdkit then make xyz file
    for i, smi in enumerate(smiles): 

        mol = Chem.MolFromSmiles(smi)
        mol_H = Chem.AddHs(mol)
            
        confs = AllChem.EmbedMultipleConfs(mol_H, 10, pruneRmsThresh=1)
        prop = AllChem.MMFFGetMoleculeProperties(mol_H)

        energy=[]
        
        for conf in confs:
            mmff = AllChem.MMFFGetMoleculeForceField(mol_H, prop,confId=conf)
            mmff.Minimize()
            energy.append((mmff.CalcEnergy(), conf))
    
            conflist = np.array(energy)
            sortconf=conflist[np.argsort(conflist[:,0]) ]

            stconfid=sortconf[0,1]
            stconfid2=int(stconfid)
            stconfgeom=mol_H.GetConformer(stconfid2)

        xyz = f'{chr} {mul}'
        for atom, (x,y,z) in zip(mol_H.GetAtoms(), stconfgeom.GetPositions()):
            xyz += '\n'
            xyz += '{}\t{}\t{}\t{}'.format(atom.GetSymbol(), x, y, z)
                  
        #  Setting input file
        global molgeom
        molgeom = psi4.geometry(xyz)
               
    # Set calculation method
        thre=threads.get()
        mem=memory.get()
        psi4.set_num_threads(nthread=thre)
        psi4.set_memory(mem*1000000)
    
        # Set output files
        psi4.set_output_file(str(i)+smi+'-molgeom.txt')

        # 計算経過の表示
        # global root, Labelex_2
        Labelex_2=ctk.CTkLabel(master=root, text='No'+str(i)+'  '+smi+' Calc was started',font=("Times",10))
        Labelex_2.place(x=50, y=390)
        Labelex_2.update()
        
        # 構造最適化
        try:
            Geom_Opt()
            root.update()
        except  psi4.driver.p4util.exceptions.OptimizationConvergenceError as err:
            print (err)
       
            continue
        
        optimized_geom = molgeom.save_string_xyz_file()
        with open (str(i)+smi+'-optgeom.xyz','w') as f:
            f.write(optimized_geom)
        
        Vib_Calc()
        root.update()
        if freqnega:
            freq_data='True'         
        else:
            freq_data='False'
            
        freq_results.append(freq_data)  
          
        MO_anal()
        root.update()
        psi4.fchk(wfn, str(i)+smi+'fchk')
        
        HOMO_np=np.array(HOMOdata).reshape(1,orb+1)
        LUMO_np=np.array(LUMOdata).reshape(1,orb+1)
        
        if i==0:
            HOMO_nplist=HOMO_np
            LUMO_nplist=LUMO_np
        else:
            HOMO_nplist=np.vstack([HOMO_nplist, HOMO_np])
            LUMO_nplist=np.vstack([LUMO_nplist, LUMO_np])
            
        # smiles Index  の作成
        smiIndex.append(smi)
 
        Data_HOMO=pd.DataFrame(data=HOMO_nplist, index=smiIndex, columns=Hindex)          
        Data_LUMO=pd.DataFrame(data=LUMO_nplist, index=smiIndex, columns=Lindex)  
    
        Data_HOMO['FreqNega']=freq_results
        Data_LUMO['FreqNega']=freq_results
            
        Data_HOMO.to_csv('Calcd_HOMO_List.csv')     
        Data_LUMO.to_csv('Calcd_LUNO_List.csv')
    
    Labelex_4=ctk.CTkLabel(master=root, text='Calculation was finished', font=("Times",12,"bold"))
    Labelex_4.place(x=50, y=410)

 以上、今回は計算実行用の処理関数の紹介をさせていただきました。
 次回はCustumTkinter関連のコードについて紹介したいと思います。