vasp_correction_bandfilling.py ダウンロード/コピー

vasp_correction_bandfilling.py をダウンロード

vasp_correction_bandfilling.py
vasp_correction_bandfilling.py
  1"""
  2概要:
  3    VASP計算結果から欠陥モデルのバンドフィリング補正を推定します。
  4
  5詳細説明:
  6    本スクリプトは、欠陥モデルの形成エネルギー計算において必要となるバンドフィリング補正 dE_BF を算出します。
  7    理想結晶と欠陥結晶のVASP計算結果 (OUTCAR, DOSCAR, EIGENVAL) を比較し、
  8    dEVBMによるバンドアラインメント後の状態占有率から電子と正孔によるエネルギー補正量を評価します。
  9    また、計算結果のDOSとバンド構造をグラフとして可視化し、サマリーファイルに結果を保存します。
 10
 11関連リンク:
 12    vasp_correction_bandfilling_usage
 13"""
 14import os
 15import sys
 16import shutil
 17import glob
 18import csv
 19import re
 20import numpy as np
 21from numpy import exp, log, sin, cos, tan, arcsin, arccos, arctan, pi
 22from scipy.interpolate import interp1d
 23from pprint import pprint
 24from matplotlib import pyplot as plt
 25
 26
 27from tklib.tkfile import tkFile
 28from tklib.tkinifile import tkIniFile
 29import tklib.tkre as tkre
 30from tklib.tkutils import save_csv
 31from tklib.tkapplication import tkApplication
 32from tklib.tkutils import IsDir, IsFile, SplitFilePath
 33from tklib.tkutils import terminate, pint, pfloat, getarg, getintarg, getfloatarg
 34from tklib.tksci.tksci import Reduce01, Round
 35from tklib.tksci.tkconvolution import convolution, convolve_func
 36from tklib.tksci.tkconvolution import convolve_xydata
 37from tklib.tksci.tkmatrix import make_matrix1, make_matrix2, make_matrix3
 38from tklib.tkcrystal.tkcif import tkCIF, tkCIFData
 39from tklib.tkcrystal.tkcrystal import tkCrystal
 40from tklib.tkcrystal.tkatomtype import tkAtomType
 41from tklib.tkcrystal.tkvasp import tkVASP
 42from tklib.tkcrystal.tkbandstructure import plot_band
 43from tklib.tksci import tkequation
 44import tklib.tkcsv
 45
 46
 47#================================
 48# global parameters
 49#================================
 50debug = 0
 51
 52validmodes = ['BF']
 53mode = 'BF'
 54
 55CAR_dir1 = '.'
 56CAR_dir2 = '.'
 57summaryfile = None
 58
 59# dEVBM obtained by VBM correction
 60dEVBM = ''
 61
 62# FWHM of Gaussian smearing function for DOS
 63WG_DOS = 0.1 # eV
 64
 65
 66# Energy to search edge energies
 67EF0  = 0.1
 68# occupancy threthold to separate HOMO and LUMO
 69occ_th = 0.5
 70
 71# Critera DOS value to search band edges
 72DOSth = 1.0e-5
 73
 74# Max number of electrons occupies one state
 75Nemax = 1.0
 76
 77# Plot configuration
 78band_marker_size       = 4
 79band_marker_edge_width = 0.5
 80
 81Emin = -10.0  # eV
 82Emax =  10.0  # eV
 83
 84#colors = ['#000000', '#ff0000', '#00aa00', '#0000ff', '#aaaa00', '#ff00ff', '#00ffff', '#aa0000', '#00aa00', '#0000aa']
 85#colors = ['k', 'r', 'g', 'b', 'y', 'm', 'c']
 86figsize = (10, 8)
 87fontsize        = 16
 88titlefontsize   = 12
 89labelfontsize   = 12
 90legend_fontsize = 12
 91
 92
 93app = tkApplication()
 94
 95
 96#=============================
 97# Treat argments
 98#=============================
 99def usage():
100    """
101    概要:
102        スクリプトの正しい使用方法を標準出力に表示します。
103
104    詳細説明:
105        スクリプトの実行に必要なコマンドライン引数のフォーマットと、
106        各引数の意味について説明します。
107
108    戻り値:
109        :returns: なし
110        :rtype: None
111    """
112    global mode
113    
114    if mode not in validmodes:
115        mode = validmodes[0]
116
117    print("")
118    print("Usage:")
119    print("  (a)  python {} mode CAR_dir(ideal) CAR_dir(defect) dEVBM WG Emin Emax EF0".format(sys.argv[0]))
120    print("         mode: {}".format(validmodes))
121    print("     ex: python {} {} {} {} {} {} {} {} {}".format(sys.argv[0], mode, CAR_dir1, CAR_dir2, dEVBM, WG_DOS, Emin, Emax, EF0))
122
123def updatevars():
124    """
125    概要:
126        コマンドライン引数に基づいてグローバル変数を更新します。
127
128    詳細説明:
129        sys.argvから引数を読み込み、mode、CAR_dir1、CAR_dir2、dEVBM、WG_DOS、Emin、Emax、EF0
130        などのグローバルパラメータに値を設定します。不正なモードが指定された場合はエラーで終了します。
131
132    戻り値:
133        :returns: なし
134        :rtype: None
135    """
136    global mode
137    global CAR_dir1, CAR_dir2
138    global EF0, dEVBM
139    global Emin, Emax, WG_DOS
140
141    mode     = getarg     (1, mode)
142    CAR_dir1 = getarg     (2, CAR_dir1)
143    CAR_dir2 = getarg     (3, CAR_dir2)
144    dEVBM    = getarg     (4, dEVBM)
145    WG_DOS   = getfloatarg(5, WG_DOS)
146    Emin     = getfloatarg(6, Emin)
147    Emax     = getfloatarg(7, Emax)
148    EF0      = getfloatarg(8, EF0)
149    if mode == 'BF':
150        pass
151    else:
152        terminate("Error: Invalide mode [{}]".format(mode), usage = usage)
153
154
155#def save_csv(path, headerlist, datalist, is_print = 0):
156
157def BF_correction(mode, CAR_path1, CAR_path2):
158    """
159    概要:
160        バンドフィリング補正を計算し、結果をファイルに保存し、グラフをプロットします。
161
162    詳細説明:
163        理想結晶と欠陥結晶のVASP計算結果ファイル(POSCAR, OUTCAR, DOSCAR, EIGENVAL)を読み込み、
164        それぞれのバンド構造、DOS、フェルミ準位などの情報を取得します。
165        dEVBMを用いて欠陥結晶のエネルギー準位を補正した後、バンドフィリング補正量(dEh, dEe, dEtot)を算出します。
166        計算結果はサマリーファイルに保存され、DOSとバンド構造のグラフが生成されます。
167
168    引数:
169        :param mode: 実行モード。現在 BF のみがサポートされています。
170        :type mode: str
171        :param CAR_path1: 理想結晶のVASP計算結果ディレクトリへのパス。
172        :type CAR_path1: str
173        :param CAR_path2: 欠陥結晶のVASP計算結果ディレクトリへのパス。
174        :type CAR_path2: str
175
176    戻り値:
177        :returns: なし
178        :rtype: None
179    """
180    global dEVBM, EF0
181
182    debug = 0
183    
184    vasp1 = tkVASP()
185    vasp2 = tkVASP()
186
187    base_path1 = vasp1.getdir(CAR_path1)
188    base_path2 = vasp2.getdir(CAR_path2)
189
190    print("")
191    print(f"Summary file: {summaryfile}")
192    INCAR_path1    = vasp1.get_INCAR(base_path1)
193    POSCAR_path1   = vasp1.get_POSCAR(base_path1)
194    OUTCAR_path1   = vasp1.get_OUTCAR(base_path1)
195    DOSCAR_path1   = vasp1.get_VASPPath(base_path1, 'DOSCAR')
196    EIGENVAL_path1 = vasp1.get_VASPPath(base_path1, 'EIGENVAL')
197    INCAR_path2    = vasp2.get_INCAR(base_path2)
198    POSCAR_path2   = vasp2.get_POSCAR(base_path2)
199    OUTCAR_path2   = vasp2.get_OUTCAR(base_path2)
200    DOSCAR_path2   = vasp2.get_VASPPath(base_path2, 'DOSCAR')
201    EIGENVAL_path2 = vasp2.get_VASPPath(base_path2, 'EIGENVAL')
202    print("CAR dir(ideal) : ", CAR_path1)
203    print("  INCAR   : ", INCAR_path1)
204    print("  POSCAR  : ", POSCAR_path1)
205    print("  OUTCAR  : ", OUTCAR_path1)
206    print("  DOSCAR  : ", DOSCAR_path1)
207    print("  EIGENVAL: ", EIGENVAL_path1)
208    print("CAR dir(defect): ", CAR_path2)
209    print("  INCAR   : ", INCAR_path2)
210    print("  POSCAR  : ", POSCAR_path2)
211    print("  OUTCAR  : ", OUTCAR_path2)
212    print("  DOSCAR  : ", DOSCAR_path2)
213    print("  EIGENVAL: ", EIGENVAL_path2)
214
215    print("")
216    print("dEVBM: {} eV".format(dEVBM))
217    print("")
218    print("DOS plot")
219    print(f"  FWHM of Gauss function for convolution: {WG_DOS} eV")
220#    print("")
221#    print("EF0: {} eV".format(EF0))
222    
223    dEVBM = pfloat(dEVBM, '')
224    if dEVBM == '':
225        app.terminate("Error: dEVBM value must be given", pause = True)
226
227    print("")
228    print("Ideal crystal model:")
229    print("Read crystal structure from [{}]".format(POSCAR_path1))
230    cry1 = vasp1.read_poscar(POSCAR_path1)
231    if cry1 is None:
232        terminate("Error: Can not read [{}]".format(POSCAR_path1), usage = usage)
233
234    a1, b1, c1, alpha1, beta1, gamm1 = cry1.LatticeParameters()
235    Vcell1        = cry1.Volume()
236    types1        = cry1.AtomTypeList()
237    ntypes1       = len(types1)
238    sites1        = cry1.ExpandedAtomSiteList()
239    nsites1       = len(sites1)
240    atomnamelist1 = cry1.get_atom_name_list(mode = 'all', NameOnly = True)
241    poslist1      = cry1.get_position_list(mode = 'all', IsReduce01 = True)
242    cry1.PrintInf("cell")
243
244    print("")
245    print("Read OUTCAR from [{}]".format(OUTCAR_path1))
246    outcarinf1 = vasp1.read_outcar_inf(OUTCAR_path1)
247    if outcarinf1 is None:
248        terminate("Error: Can not read [{}]".format(OUTCAR_path1), usage = usage)
249    EF1 = vasp1.outcarinf["EF"]
250    ISPIN1 = outcarinf1["ISPIN"]
251#    ETOT1  = outcarinf1["TOTEN"]
252    ETOT1  = outcarinf1["TOTEN_zero_sigma"]
253    print(f"ISPIN={ISPIN1}")
254    print(f"ETOT(sigma->0)={ETOT1}")
255
256    print("")
257    print("Defect crystal model:")
258    print("Read from [{}]".format(POSCAR_path2))
259    cry2 = vasp2.read_poscar(POSCAR_path2)
260    if cry2 is None:
261        terminate("Error: Can not read [{}]".format(POSCAR_path2), usage = usage)
262
263    a2, b2, c2, alpha2, beta2, gamm2 = cry2.LatticeParameters()
264    Vcell2        = cry2.Volume()
265    types2        = cry2.AtomTypeList()
266    ntypes2       = len(types2)
267    sites2        = cry2.ExpandedAtomSiteList()
268    nsites2       = len(sites2)
269    atomnamelist2 = cry2.get_atom_name_list(mode = 'all', NameOnly = True)
270    poslist2      = cry2.get_position_list(mode = 'all', IsReduce01 = True)
271    cry2.PrintInf("cell")
272
273    print("")
274    print("Read OUTCAR from [{}]".format(OUTCAR_path2))
275    outcarinf2 = vasp2.read_outcar_inf(OUTCAR_path2)
276    if outcarinf2 is None:
277        terminate("Error: Can not read [{}]".format(OUTCAR_path2), usage = usage)
278    EF2 = vasp2.outcarinf["EF"]
279    ISPIN2 = outcarinf2["ISPIN"]
280#    ETOT2  = outcarinf2["TOTEN"]
281    ETOT2  = outcarinf2["TOTEN_zero_sigma"]
282    print(f"ISPIN={ISPIN2}")
283    print(f"ETOT(sigma->0)={ETOT2}")
284
285# Estimate supercell size
286    print("")
287    nx = int(a2 / a1 + 0.2)
288    ny = int(b2 / b1 + 0.2)
289    nz = int(c2 / c1 + 0.2)
290    print("Supercell multipliers of the defect crystal with respect to the ideal crystal")
291    print("  (nx, ny, nz) = ({}, {}, {})".format(nx, ny, nz))
292
293    print("")
294    print(f"Ideal crystal model: Read DOSCAR from [{DOSCAR_path1}]")
295    doscarinf1 = vasp1.read_doscar(DOSCAR_path1, EF = EF1, normalize_E = False, unit = '/cm3')
296    nE1 = doscarinf1["nE"]
297    E1  = doscarinf1["E"]
298    if nE1 == 0:
299        Edmin1 = 0.0
300        Edmax1 = 0.0
301    else:
302        Edmin1  = min(E1)
303        Edmax1  = max(E1)
304    tDOSup1 = doscarinf1["TotalDOSup"]
305    Neup1   = doscarinf1["Neup"]
306    tDOSdn1 = doscarinf1["TotalDOSdn"]
307    Nedn1   = doscarinf1["Nedn"]
308    if nE1 > 0:
309        print(f"EF={EF1} eV")
310        print(f"DOS E range: {Edmin1:10.6g} - {Edmax1:10.6g} eV, {nE1} points")
311        print(f"  Energy is not normalized")
312    else:
313        print("")
314        app.terminate(f"Error: Zero nE for DOS(E) in {DOSCAR_path1}", pause = True)
315
316    print(f"Read EIGENVAL from [{DOSCAR_path1}]")
317    eigenvalinf1 = vasp1.read_eigenval(EIGENVAL_path1, EF = EF1, normalize_E = False)
318    nk1      = eigenvalinf1["nk"]
319    nLevels1 = eigenvalinf1["nLevels"]
320    bandedgeinf1a = vasp1.find_band_edges_from_eigenval(EF0 = EF0, eigenvalinf = eigenvalinf1, ISPIN = ISPIN1, occ_th = occ_th)
321    bandedgeinf1b = vasp1.gbandedges(base_path1, OUTCAR_path1, EIGENVAL_path1, EF1)
322    print("k points in EIGENVAL:")
323    print("nk=", nk1)
324    print("nLevels=", nLevels1)
325    """
326    for i in range(nk1):
327        el = eigenvalinf1['EList'][i]
328        kx, ky, kz, wk, dk, ktot, Eups, occups, Edns, occdns = el
329        print("  ({:8.4f} {:8.4f} {:8.4f}) w={:8.4g}  {:8.4f} {:12.4f}".format(kx, ky, kz, wk, dk, ktot))
330    """
331
332    EV1a   = bandedgeinf1a["EV"]
333    EC1a   = bandedgeinf1a["EC"]
334    Eg1a   = bandedgeinf1a["Eg"]
335    EV1    = bandedgeinf1b["EVBM"]
336    EC1    = bandedgeinf1b["ECBM"]
337    Eg1    = bandedgeinf1b["Eg"]
338    EHOMO1 = bandedgeinf1a["EHOMO"]
339    ELUMO1 = bandedgeinf1a["ELUMO"]
340    print(f"Band edge from EIGENVAL:")
341    print(f"EF0={EF0:10.6f} eV")
342    print(f"  find_band_edges: EV={EV1a:10.6f}  EC={EC1a:10.6f}  Eg={Eg1a:10.6f} eV")
343    print(f"             HOMO:{EHOMO1:10.6f} eV")
344    print(f"             LUMO:{ELUMO1:10.6f} eV")
345    print(f"  gbandedges()   : EV={EV1:10.6f}  EC={EC1:10.6f}  Eg={Eg1:10.6f} eV")
346
347    print("")
348    print(f"Defect crystal model: Read DOSCAR from [{DOSCAR_path2}]")
349    doscarinf2 = vasp2.read_doscar(DOSCAR_path2, EF = EF2, normalize_E = False, unit = '/cm3')
350    nE2 = doscarinf2["nE"]
351    E2  = doscarinf2["E"]
352    if nE2 == 0:
353        Edmin2 = 0.0
354        Edmax2 = 0.0
355    else:
356        Edmin2  = min(E2)
357        Edmax2  = max(E2)
358    tDOSup2 = doscarinf2["TotalDOSup"]
359    Neup2   = doscarinf2["Neup"]
360    tDOSdn2 = doscarinf2["TotalDOSdn"]
361    Nedn2   = doscarinf2["Nedn"]
362    if nE2 > 0:
363        print(f"EF={EF2} eV")
364        print(f"DOS E range: {Edmin2:10.6g} - {Edmax2:10.6g} eV, {nE2} points")
365        print(f"  Energy is not normalized")
366
367    print(f"Read EIGENVAL from [{DOSCAR_path2}]")
368    eigenvalinf2 = vasp2.read_eigenval(EIGENVAL_path2, EF = EF2, normalize_E = False)
369    nk2      = eigenvalinf2["nk"]
370    nLevels2 = eigenvalinf2["nLevels"]
371    bandedgeinf2a = vasp2.find_band_edges_from_eigenval(EF0 = EF0, eigenvalinf = eigenvalinf2, ISPIN = ISPIN2, occ_th = occ_th)
372    bandedgeinf2b = vasp2.gbandedges(base_path2, OUTCAR_path2, EIGENVAL_path2, EF2)
373    print("k points in EIGENVAL:")
374    print("nk=", nk2)
375    print("nLevels=", nLevels2)
376    for i in range(nk2):
377        el = eigenvalinf2['EList'][i]
378        kx, ky, kz, wk, dk, ktot, Eups, occups, Edns, occdns = el
379        print("  ({:8.4f} {:8.4f} {:8.4f}) w={:8.4g}  {:8.4f} {:12.4f}".format(kx, ky, kz, wk, dk, ktot))
380
381    EV2a   = bandedgeinf1a["EV"]
382    EC2a   = bandedgeinf1a["EC"]
383    Eg2a   = bandedgeinf1a["Eg"]
384    EV2    = bandedgeinf1b["EVBM"]
385    EC2    = bandedgeinf1b["ECBM"]
386    Eg2    = bandedgeinf1b["Eg"]
387    EHOMO2 = bandedgeinf1a["EHOMO"]
388    ELUMO2 = bandedgeinf1a["ELUMO"]
389    print(f"Band edge from EIGENVAL:")
390    print(f"EF0={EF0:10.6f} eV")
391    print(f"  find_band_edges: EV={EV2a:10.6f}  EC={EC2a:10.6f}  Eg={Eg2a:10.6f} eV")
392    print(f"             HOMO:{EHOMO2:10.6f} eV")
393    print(f"             LUMO:{ELUMO2:10.6f} eV")
394    print(f"  gbandedges()   : EV={EV2:10.6f}  EC={EC2:10.6f}  Eg={Eg2:10.6f} eV")
395
396    print("")
397    print("DOS plot range")
398    print(f"  Ideal crystal model:")
399    print(f"    EF={EF1} eV")
400    print(f"    E range: {Edmin1:10.6g} - {Edmax1:10.6g} eV, {nE1} points")
401    """
402    print(f"    DOS(E) is scaled for the size of the defect model by {nx}x{ny}x{nz}")
403    k = nx * ny * nz * 1.0
404    for i in range(len(E1)):
405        tDOSup1[i] *= k
406        Neup1[i]   *= k
407        if ISPIN1 == 2:
408            tDOSdn2[i] *= k
409            Nedn1[i]   *= k
410    """
411
412    print(f"  Defect crystal model:")
413    print(f"    Original EF={EF2} eV")
414    print(f"    Original E range: {Edmin2:10.6g} - {Edmax2:10.6g} eV, {nE2} points")
415    EF2 -= dEVBM
416    Edmin2 -= dEVBM
417    Edmax2 -= dEVBM
418    for i in range(len(E2)):
419        E2[i] -= dEVBM
420    for ik in range(nk2):
421        el = eigenvalinf2['EList'][ik]
422        kx, ky, kz, wk, dk, ktot, Eups, occups, Edns, occdns = [*el]
423        Eups[ik] -= dEVBM
424        if ISPIN2 == 2:
425            Edns[ik] -= dEVBM
426    print(f"    Adjusted EF={EF2} eV")
427    print(f"    Adjusted E range: {Edmin2:10.6g} - {Edmax2:10.6g} eV, {nE2} points")
428
429    print("")
430    print("Calculate band filling energy")
431    totalw  = 0.0
432    totalNe = 0.0
433    dEe = 0.0
434    dEh = 0.0
435    for ik in range(nk2):
436        el = eigenvalinf2['EList'][ik]
437        kx, ky, kz, wk, dk, ktot, Eups, occups, Edns, occdns = [*el]
438        totalw += wk
439        print("  k[{:3d}]: ({:8.4f} {:8.4f} {:8.4f})  w={:8.4g}".format(ik, kx, ky, kz, wk))
440        for iE in range(nLevels2):
441            Eup  = Eups[iE]
442            neup = occups[iE]
443            totalNe += neup * wk
444
445            if Eup <= EV1 and abs(neup - Nemax) > 1.0e-6:
446                dEh += wk * (Nemax - neup) * (Eup - EV1)
447                print(f"    dEh: up iE={iE:3d} E={Eup:10.6g} eV dNh={Nemax - neup:10.4g} dEh={dEh:12.6g} eV")
448            if Eup >= EC1 and neup > 1.0e-6:
449                dEe += wk * neup * (Eup - EC1)
450                print(f"    dEe: up iE={iE:3d} E={Eup:10.6g} eV dNe={neup:10.4g} dEe={dEe:12.6g} eV")
451            if ISPIN2 == 2:
452                Edn  = Edns[iE]
453                nedn = occdns[iE]
454                totalNe += nedn * wk
455
456                if Edn <= EV1 and abs(nedn - Nemax) > 1.0e-6:
457                    dEh += wk * (Nemax - nedn) * (Edn - EV1)
458                    print(f"    dEh: dn iE={iE:3d} E={Edn:10.6g} eV dNh={Nemax - nedn:10.4g} dEh={dEh:12.6g} eV")
459                if Edn >= EC1 and nedn > 1.0e-6:
460                    dEe += wk * nedn * (Edn - EC1)
461                    print(f"    dEe: dn iE={iE:3d} E={Edn:10.6g} eV dNe={nedn:10.4g} dEe={dEe:12.6g} eV")
462
463    print("")
464    print("From defect crystal model:")
465    print("  Total weight: ", totalw)
466    print("  NELECT      : ", outcarinf2["NELECT"])
467    dEtot = dEh + dEe
468    if ISPIN2 == 1:
469        totalNe *= 2.0
470        dEh   *= 2.0
471        dEe   *= 2.0
472        dEtot *= 2.0
473    print("  Count spin degeneracy of 2:")
474    print("    Total Ne    : ", totalNe)
475    print("    dEh   = {:12.6g} eV".format(dEh))
476    print("    dEe   = {:12.6g} eV".format(dEe))
477    print("    dEtot = {:12.6g} eV".format(dEtot))
478
479    print("")
480    print(f"Save summary to {summaryfile}")
481    ini = tkIniFile()
482    ini.write_from_scratch(summaryfile, 'results',
483                Car_dir1 = base_path1,
484                Car_dir2 = base_path2,
485                Etot1 = ETOT1 * nx * ny * nz,
486                Etot2 = ETOT2,
487                totalNe = totalNe,
488                dEh = dEh,
489                dEe = dEe,
490                dEtot = dEtot
491                )
492
493
494#=============================
495# Plot graphs
496#=============================
497    print("")
498
499    fig = plt.figure(figsize = figsize)
500    ax1    = fig.add_subplot(2, 2, 1)
501    ax2    = fig.add_subplot(2, 2, 3)
502    axband = fig.add_subplot(1, 2, 2)
503
504    print("E1=", E1)
505    tDOSup_s1 = convolution(E1, tDOSup1, WG_DOS, func_type = 'gauss')
506    ax1.plot(E1, tDOSup_s1, label = 'up(ideal)', linestyle = '-', linewidth = 0.5, color = 'black')
507    if ISPIN1 == 2:
508        tDOSdn_s1 = convolution(E, tDOSdn1, WG_DOS, func_type = 'gauss')
509        ax1.plot(E1, tDOSdn_s1, label = 'dn(ideal)', linestyle = 'dashed', linewidth = 0.5, color = 'black')
510    ylim = ax1.get_ylim()
511    ax1.plot([EV1, EV1],       ylim, label = '$E_V$(ideal)',      linestyle = 'dashed', linewidth = 0.5, color = 'red')
512    ax1.plot([EC1, EC1],       ylim, label = '$E_C$(ideal)',      linestyle = 'dashed', linewidth = 0.5, color = 'red')
513    ax1.plot([EF1, EF1],       ylim, label = '$E_F$(ideal)',      linestyle = 'dashed', linewidth = 0.5, color = 'blue')
514#    ax1.plot([EF0, EF0],     ylim, label = '$E_{F0}$',   linestyle = 'dashed', linewidth = 0.5, color = 'blue')
515#    ax1.plot([EHOMO1, EHOMO1], ylim, label = '$E_{HOMO}$(ideal)', linestyle = 'dashed', linewidth = 0.5, color = 'green')
516#    ax1.plot([ELUMO1, ELUMO1], ylim, label = '$E_{LUMO}$(ideal)', linestyle = 'dashed', linewidth = 0.5, color = 'green')
517#    ax1.set_xlabel("$E$ (eV)",    fontsize = fontsize)
518    ax1.set_ylabel("DOS (states/cm$^3$/eV)", fontsize = fontsize)
519#    ax1.set_xlim([Emin, Emax])
520    ax1.tick_params(labelsize = fontsize)
521
522    tDOSup_s2 = convolution(E2, tDOSup2, WG_DOS, func_type = 'gauss')
523    ax1.plot(E2, tDOSup_s2, label = 'up(defect)', linestyle = '-', linewidth = 1.0, color = 'red')
524    if ISPIN2 == 2:
525        tDOSdn_s2 = convolution(E, tDOSdn2, WG_DOS, func_type = 'gauss')
526        ax1.plot(E2, tDOSdn_s2, label = 'dn(defect)', linestyle = 'dashed', linewidth = 1.0, color = 'red')
527    ax1.plot([EF2, EF2],     ylim, label = '$E_F$(defect)',      linestyle = 'dashed', linewidth = 1.0, color = 'blue')
528    ax1.tick_params(labelsize = fontsize)
529    ax1.set_title(f"{CAR_path1}\n{CAR_path2}", fontsize = titlefontsize)
530    ax1.legend(fontsize = legend_fontsize)
531
532    ax2.plot(E2, Neup2, label = 'up(defect)', linestyle = '-', linewidth = 0.5, color = 'black')
533    if ISPIN2 == 2:
534        ax2.plot(E2, Nedn2, label = 'dn(defect)', linestyle = '-', linewidth = 0.5, color = 'red')
535    ylim = ax2.get_ylim()
536    ax2.plot([EV1, EV1],   ylim,     label = '$E_V$(ideal)',      linestyle = 'dashed', linewidth = 0.5, color = 'red')
537    ax2.plot([EC1, EC1],   ylim,     label = '$E_C$(ideal)',      linestyle = 'dashed', linewidth = 0.5, color = 'red')
538#    ax2.plot([EF0, EF0], ylim,     label = '$E_{F0}$',   linestyle = 'dashed', linewidth = 0.5, color = 'blue')
539#    ax2.plot([EHOMO1, EHOMO1], ylim, label = '$E_{HOMO}$(ideal)', linestyle = 'dashed', linewidth = 0.5, color = 'green')
540#    ax2.plot([ELUMO1, ELUMO1], ylim, label = '$E_{LUMO}$(ideal)', linestyle = 'dashed', linewidth = 0.5, color = 'green')
541    ax2.plot([EF1, EF1],   ylim, label = '$E_F$(ideal)',      linestyle = 'dashed', linewidth = 0.5, color = 'blue')
542    ax2.plot([EF2, EF2],   ylim, label = '$E_F$(defect)',      linestyle = 'dashed', linewidth = 1.0, color = 'blue')
543    ax2.set_xlabel("$E$ (eV)",    fontsize = fontsize)
544    ax2.set_ylabel("$N_e$ (states/unit cell)", fontsize = fontsize)
545#    ax2.set_xlim([Emin, Emax])
546    ax2.legend(fontsize = legend_fontsize)
547    ax2.tick_params(labelsize = fontsize)
548
549    xk   = []
550    yEup = []
551    yNup = []
552    yEdn = []
553    yNdn = []
554    for i in range(nk2):
555        el = eigenvalinf2['EList'][i]
556        kx, ky, kz, wk, dk, ktot, Eups, occups, Edns, occdns = [*el]
557        xk.append(ktot)
558        yEup.append(Eups)
559        yNup.append(occups)
560        if ISPIN2 == 2:
561            yEdn.append(Edns)
562            yNdn.append(occdns)
563
564    plot_band(plt, axband, ISPIN2, xk, yEup, yEdn, [Emin, Emax], occups = yNup, occdns = yNdn, 
565                ktotallist = None, ktotal_namelist = None, 
566                EV = EV1, EC = EC1, EF = EF2, EHOMO = None, ELUMO = None,
567                EFlabel = '$E_{F}$(defect)',
568                markersize = band_marker_size, markeredgewidth = band_marker_edge_width)
569    axband.set_title(f"dEh={dEh:12.6g} eV\ndEe={dEe:12.6g} eV\ndEtot={dEtot:12.6g} eV", fontsize = titlefontsize)
570
571    plt.tight_layout()
572
573
574# Rearange the graph axes so that they are not overlapped
575    plt.tight_layout()
576
577    """
578    plt.show()
579    print("")
580    print("Close graph window to terminate")
581    """
582    
583    plt.pause(0.1)
584
585    app.terminate("", pause = True)
586
587
588def main():
589    """
590    概要:
591        スクリプトのメインエントリポイント。引数の処理とバンドフィリング補正の実行を行います。
592
593    詳細説明:
594        コマンドライン引数をパースしてグローバル変数を更新し、ログファイルをセットアップします。
595        指定されたモードに応じてBF_correction関数を呼び出し、バンドフィリング補正計算を実行します。
596
597    戻り値:
598        :returns: なし
599        :rtype: None
600    """
601    global mode
602    global cifpath, poscarpath
603    global summaryfile
604    
605    updatevars()
606
607    vasp = tkVASP()
608    base_path = vasp.getdir(CAR_dir2)
609    logfile     = os.path.join(base_path, 'BF_correction-out.txt')
610    summaryfile = os.path.join(base_path, 'BF_correction-summary.prm')
611    print("")
612    print(f"Open logfile [{logfile}]")
613    app.redirect(targets = ["stdout", logfile], mode = 'w')
614
615    print("")
616    print("=============== Estimate band filling correction for defect model calculated by VASP ============")
617    print("")
618    print("mode: ", mode)
619
620    if mode == 'BF':
621        BF_correction(mode, CAR_dir1, CAR_dir2)
622    else:
623        terminate(f"Error: Invalide mode [{mode}]", usage = usage)
624
625
626if __name__ == "__main__":
627    main()