Calculate carrier densities and Fermi level based on DOSCAR of VASP.
Download script from .\EF-T-DOS.py
import os
import sys
from math import exp, sqrt
import numpy as np
from math import log, exp
from numpy import arange
from scipy import integrate # 数値積分関数 integrateを読み込む
from scipy import optimize # newton関数はscipy.optimizeモジュールに入っている
from scipy.interpolate import interp1d
from matplotlib import pyplot as plt
"""
Calculate carrier densities and Fermi level based on DOSCAR of VASP.
"""
# constants
pi = 3.14159265358979323846
h = 6.6260755e-34 # Js";
hbar = 1.05459e-34 # "Js";
c = 2.99792458e8 # m/s";
e = 1.60218e-19 # C";
kB = 1.380658e-23 # JK-1";
me = 9.1093897e-31 # kg";
Debug = 0
#mode: 'EF', 'T'
mode = 'T'
# EF range for mode = 'EF'
T0 = 300 # K
dEFmin = -0.2 # measured from EV, eV
dEFmax = 0.2 # measured from EC, eV
nEF = 50
EFmin = None
EFmax = None
EFstep = None
# Temperature range for mode = 'T'
Tmin = 300 # K
Tmax = 600
nT = 11
Tstep = None
# Sample information (DOS.data is converted to states/eV/Vcell)
Vcell = 212.309 # A^3
# read from DOSCAR
file = "DOS.dat"
E_raw = None
dos_raw = None
nDOS = None
Emin = None
Emax = None
Estep = None
EV = None
EC = None
dEA = 0.32 # Acceptor level measured from EV, eV
NA = 0.8e17
dED = -0.28 # Donor level measured from EC, eV
ND = 0.5e17
EA = None # Acceptor states are not considered if EA = None
ED = None # Donor states are not considered if ED = None
# other parameters
EF0 = 0.4 # EF at charge neutral
Egth = 0.01 # Critera DOS value to search band edges
# integration parameters
# Integration range w.r.t. kBT
Einteg0 = -3.0
Einteg1 = 3.0
nrange = 6.0
# Relative accuracy of the quad functin
eps = 1.0e-5
nmaxdiv = 150
# Bisection method parameters
# Initial search range
dEbisec = 0.4
# EPS
epsbisec = 1.0e-7
# max iteration number
nmaxiter = 200
# Output cycle
iprintiterval = 1
# graph configuration
fontsize = 16
legend_fontsize = 12
#=============================
# Treat argments
#=============================
def pfloat(str):
try:
return float(str)
except:
return None
def pint(str):
try:
return int(str)
except:
return None
def getarg(position, defval = None):
try:
return sys.argv[position]
except:
return defval
def getfloatarg(position, defval = None):
return pfloat(getarg(position, defval))
def getintarg(position, defval = None):
return pint(getarg(position, defval))
def usage():
global mode
global Vcell, T0, EF0
global file, E_raw, dos_raw, nDOS, Emin, Emax, Estep
global dEFmin, dEFmax, EFmin, EFmax, nEF, EFstep
print("")
print("Usage: Variables in () are optional")
print(" python {} mode (file args)".format(sys.argv[0], ))
print(" (i) python {} T file Tmin Tmax nT)".format(sys.argv[0]))
print(" ex: {} T {} {} {} {}".format(sys.argv[0], file, Tmin, Tmax, nT))
print(" (ii) python {} EF file nEF)".format(sys.argv[0]))
print(" ex: {} EF {} {}".format(sys.argv[0], file, nEF))
def updatevars():
global mode
global Vcell, T0, EF0
global file, E_raw, dos_raw, nDOS, Emin, Emax, Estep
global dEFmin, dEFmax, EFmin, EFmax, nEF, EFstep
global Tmin, Tmax, nT, Tstep
argv = sys.argv
if len(argv) == 1:
usage()
exit()
mode = getarg( 1, mode)
file = getarg( 2, file)
if mode == 'EF':
nEF = getintarg(3, nEF)
if mode == 'T':
Tmin = getintarg(3, Tmin)
Tmax = getintarg(4, Tmax)
nT = getintarg(5, nT)
Tstep = (Tmax - Tmin) / (nT - 1)
#=============================
# other functions
#=============================
def savecsv(outfile, header, datalist):
try:
print("Write to [{}]".format(outfile))
f = open(outfile, 'w')
except:
# except IOError:
print("Error: Can not write to [{}]".format(outfile))
else:
fout = csv.writer(f, lineterminator='\n')
fout.writerow(header)
# fout.writerows(data)
for i in range(0, len(datalist[0])):
a = []
for j in range(len(datalist)):
a.append(datalist[j][i])
fout.writerow(a)
f.close()
def read_csv(infile, xmin = None, xmax = None, delimiter = ','):
print("xrange=", xmin, xmax)
data = []
try:
infp = open(infile, "r")
f = csv.reader(infp, delimiter = delimiter)
header = next(f)
print("header=", header)
for j in range(len(header)):
data.append([])
for row in f:
x = pfloat(row[0])
if xmin is not None and xmin <= x <= xmax:
y = pfloat(row[1])
data[0].append(x)
data[1].append(y)
except:
print("Error: Can not read [{}]".format(infile))
exit()
return header, data[0], data[1]
def FindBandEdges(E, DOS, EF0, Egth):
EV = 1.0e30
EC = 1.0e30
i0 = -1
for i in range(len(E)):
if E[i] >= EF0:
i0 = i
break
for i in range(i0, 0, -1):
if DOS[i] > Egth:
EV = E[i+1]
break
for i in range(i0, len(E), +1):
if DOS[i] > Egth:
EC = E[i-1]
break
return EV, EC
def rieman(x0, dx, y, xmin, xmax):
S = 0.0
for i in range(len(y)):
x = x0 + i * dx
if x < xmin or xmax < x:
continue
S += y[i]
return S * dx
# define the DOS function
def DOS(E):
global E_raw, dos_raw
global Emin, Emax, Estep, nDOS
if E < Emin or Emax < E:
print("Error in f_dos: Given E={} exceeds the DOS E range [{}, {}]".format(E, Emin, Emax))
exit()
fdos = interp1d(E_raw, dos_raw, kind = 'cubic')
return fdos(E)
# Fermi-Dirac distribution function
def fe(E, T, EF):
global e, kB
if T == 0.0:
if E < EF:
return 1.0
else:
return 0.0
return 1.0 / (exp((E - EF) * e / kB / T) + 1.0)
def fh(E, T, EF):
return 1.0 - fe(E, T, EF)
# Define the function to be integrated
def DOSfe(E, T, EF):
return DOS(E) * fe(E, T, EF)
def DOSfh(E, T, EF):
return DOS(E) * fh(E, T, EF)
def integrate(func, E0, E1, h):
n = int((E1 - E0) / h + 1.000001)
h = (E1 - E0) / (n - 1)
y = [func(E0 + i * h) for i in range(n)]
S = 0.5 * (y[0] + y[n-1]) + sum(y[1:n-1])
return [h * S, -1.0]
# Calculate the number of electrons from E0 to E1 with the Fermi level EF at T
def Ne(T, EF, E0, E1):
global Estep
# N = integrate.quad(lambda E: DOSfe(E, T, EF), E0, E1, limit = nmaxdiv, epsrel = eps)
N = integrate(lambda E: DOSfe(E, T, EF), E0, E1, Estep)
if Debug:
print(" Ne integ error: {}".format(N[1]))
return N[0]
def Nh(T, EF, E0, E1):
global Estep
# N = integrate.quad(lambda E: DOSfh(E, T, EF), E0, E1, limit = nmaxdiv, epsrel = eps)
N = integrate(lambda E: DOSfh(E, T, EF), E0, E1, Estep)
if Debug:
print(" Nh integ error: {}".format(N[1]))
return N[0]
# ionized donor density
def NDp(EF, T):
global ND, ED, kB
return ND * (1.0 - fe(ED, T, EF))
# ionized acceptor density
def NAm(EF, T):
global NA, EA, kB
n = NA * fe(EA, T, EF)
# print("n=", EF, T, NA, EA, n)
return n
# Calculate EF base on
# the charge neutrality (electron number) condition, Ne(T, EF, dE) - N = 0,
# using the Newton method with the initial value EF0
def CalEF(T, EF0, E0, E1, totNe):
EF = optimize.newton(lambda EF: Ne(T, EF, E0, E1) - totNe, EF0)
return EF
def exec_T():
global mode, T0, EF0
global file, E_raw, dos_raw
global nDOS, Emin, Emax, Estep
global EV, EC
global dEFmin, dEFmax, EFmin, EFmax, nEF, EFstep
global dEA, NA, dED, ND, EA, ND
xT = []
xTinv = []
yEF = []
yEint = []
yEentropy = []
yEFa = []
yNe = []
yNh = []
yNDp = []
yNAm = []
yRH = []
EFprev = EF0
#初期範囲
EFmin = EF0 - dEbisec
EFmax = EF0 + dEbisec
dEFbisec = 0.1
print ("%5s\t%8s\t%14s" % ("T(K)", "EF(eV)", "Ne(0 K) (check)"))
for iT in range(nT):
T = Tmin + iT * Tstep
print("")
print("iT {:03d}: {} K".format(iT, T))
kBTe = kB * T / e
dE = nrange * kBTe
E0 = EV - dE
E1 = EC + dE
if E0 < Emin or Emax < E1:
print("*** Integration range error: [{}, {}] exceeds DOS E range [{}, {}]".format(E0, E1, Emin, Emax))
exit()
Ne0K = Ne(0.0, EF0, E0, EF0)
# まず、EFmin,EFmaxにおけるΔQを計算し、それぞれが正・負あるいは負・生となっていることを確認する
print("E range:", EF0, E1)
# Nemin = Ne(T, EFmin, EF0, E1)
Nemin = Ne(T, EFmin, EC - Estep, E1)
# Nhmin = Nh(T, EFmin, E0, EF0)
Nhmin = Nh(T, EFmin, E0, EV + Estep)
NAmmin = NAm(EFmin, T)
NDpmin = NDp(EFmin, T)
dQmin = Nemin + NAmmin - Nhmin - NDpmin
# Nemax = Ne(T, EFmax, EF0, E1)
Nemax = Ne(T, EFmax, EC - Estep, E1)
# Nhmax = Nh(T, EFmax, E0, EF0)
Nhmax = Nh(T, EFmax, E0, EV + Estep)
NAmmax = NAm(EFmax, T)
NDpmax = NDp(EFmax, T)
dQmax = Nemax + NAmmax - Nhmax - NDpmax
print(" min (EF,Ne,Nh,NDp,NAm,dQ)=({:6.4f},{:10.4g},{:10.4g},{:10.4g},{:10.4g},{:10.4g})"
.format(iT, EFmin, Nemin, Nhmin, NDpmin, NAmmin, dQmin))
print(" max (EF,Ne,Nh,NDp,NAm,dQ)=({:6.4f},{:10.4g},{:10.4g},{:10.4g},{:10.4g},{:10.4g})"
.format(EFmax, Nemax, Nhmax, NDpmax, NAmmax, dQmax))
# dQmin = Ne(EFmin, T) + NAm(EFmin, T) - Nh(EFmin, T) - NDp(EFmin, T)
# dQmax = Ne(EFmax, T) + NAm(EFmax, T) - Nh(EFmax, T) - NDp(EFmax, T)
# print(" EFmin = {:12.8f} dQmin = {:12.4g}".format(EFmin, dQmin))
# print(" EFmax = {:12.8f} dQmax = {:12.4g}".format(EFmax, dQmax))
print(" dQ=", dQmin, dQmax)
print(" dQmin*dQmax=", dQmin * dQmax)
if dQmin * dQmax > 0.0:
print("Error: Initial Emin and Emax should be chosen as dQmin * dQmax < 0")
return 0
# 2分法開始
for i in range(nmaxiter):
EFhalf = (EFmin + EFmax) / 2.0
# Neh = Ne(T, EFhalf, EF0, E1)
Neh = Ne(T, EFhalf, EC - Estep, E1)
# Nhh = Nh(T, EFhalf, E0, EF0)
Nhh = Nh(T, EFhalf, E0, EV + Estep)
NAmh = NAm(EFhalf, T)
NDph = NDp(EFhalf, T)
dQhalf = Neh + NAmh - Nhh - NDph
print(" iter {:03d}: half (EF,Ne,Nh,NDp,NAm,dQ)=({:6.4f},{:10.4g},{:10.4g},{:10.4g},{:10.4g},{:10.4g})"
.format(i, EFhalf, Neh, Nhh, NDph, NAmh, dQhalf))
# EFの精度がepsより小さくなったら計算終了
if abs(EFmin - EFhalf) < epsbisec and abs(EFmax - EFhalf) < epsbisec:
# print(" Success: Convergence reached at EF = {}".format(EFhalf))
break
if dQmin * dQhalf < 0.0:
EFmax = EFhalf
dQmax = dQhalf
else:
EFmin = EFhalf
dQmin = dQhalf
else:
print(" Failed: Convergence did not reach")
return 0
EF = EFhalf
RH = 1.0 / e * (Nhh - Neh) / pow(Nhh + Neh, 2.0)
xT.append(T)
xTinv.append(1000.0 / T)
yEF.append(EF)
yNe.append(Neh)
yNh.append(Nhh)
yNDp.append(NDph)
yNAm.append(NAmh)
yRH.append(RH)
print(" ***(T,EF,Ne,Nh,NDp,NAm,RH)=({:6.4f},{:6.4g},{:10.4g},{:10.4g},{:10.4g},{:10.4g},{:10.4g})"
.format(T, EF, Neh, Nhh, NDph, NAmh, RH))
EFprev = EF
EFmin = EF - dEFbisec
EFmax = EF + dEFbisec
print ("%5.0f\t%12.6g" % (T, EF))
print("")
yEaNe = []
yEaNeTh = []
yEaNh = []
yEaNhTh = []
print ("%8s %8s %8s %8s %8s %8s %12s %10s %12s %12s %12s"
% ("T(K)", "EF(eV)", "Ea(Ne,meV)", "Ea(Ne,T1/2)", "Ea(Nh,meV)", "Ea(Nh,T1/2)", "Ne", "Nh", "ND+", "NA-", "RH"))
for i in range(nT):
if i == 0:
i1 = i
i2 = i+1
elif i == nT - 1:
i1 = i-1
i2 = i
else:
i1 = i-1
i2 = i+1
Th1 = sqrt(xT[i1])
Th2 = sqrt(xT[i2])
dT = 1.0 / (xTinv[i2] - xTinv[i1])
EaNe = (log(yNe[i2]) - log(yNe[i1])) * dT # meV
EaNeTh = (log(yNe[i2]/Th2) - log(yNe[i1]/Th1)) * dT # meV
EaNh = (log(yNh[i2]) - log(yNh[i1])) * dT # meV
EaNhTh = (log(yNh[i2]/Th2) - log(yNh[i1]/Th1)) * dT # meV
yEaNe.append (-1000.0 * 1000.0 * kB / e * EaNe)
yEaNeTh.append(-1000.0 * 1000.0 * kB / e * EaNeTh)
yEaNh.append (-1000.0 * 1000.0 * kB / e * EaNh)
yEaNhTh.append(-1000.0 * 1000.0 * kB / e * EaNhTh)
print("%5.3f %8.3f %8.3g %8.3g %8.3g %8.3g " % (xT[i], yEF[i], yEaNe[i], yEaNeTh[i], yEaNh[i], yEaNhTh[i])
+ "%12g %12g %12g %12g %12g" % (yNe[i], yNh[i], yNDp[i], yNAm[i], yRH[i]))
#=============================
# Plot graphs
#=============================
fig = plt.figure(figsize = (12, 8))
ax1 = fig.add_subplot(2, 3, 1)
ax2 = fig.add_subplot(2, 3, 2)
ax3 = fig.add_subplot(2, 3, 4)
ax4 = fig.add_subplot(2, 3, 3)
ax5 = fig.add_subplot(2, 3, 6)
ax1.plot(xT, yEF, label = 'EF', color = 'black')
ax1.set_xlabel("T (K)", fontsize = fontsize)
ax1.set_ylabel("E$_F$ (eV)", fontsize = fontsize)
ax1.legend(fontsize = legend_fontsize)
ax2.plot(E_raw, dos_raw, label = 'DOS', color = 'black')
ax2.plot([EF0, EF0], [min(dos_raw), max(dos_raw)], color = 'red', linestyle = 'dashed')
ax2.set_xlabel("E (eV)", fontsize = fontsize)
ax2.set_ylabel("DOS (states/cm$^3$)", fontsize = fontsize)
ax2.legend(fontsize = legend_fontsize)
ax3.plot(xT, yRH, label = 'RH', color = 'black', marker = 'o')
ax3.set_xlabel("T (K)", fontsize = fontsize)
ax3.set_ylabel("R$_H$ (C$^{-1}$cm$^{-3}$)", fontsize = fontsize)
ax3.legend(fontsize = legend_fontsize)
ax4.plot(xTinv, yNe, label = 'Ne', color = 'black', marker = 'o')
ax4.plot(xTinv, yNh, label = 'Nh', color = 'red', marker = 'o')
ax4.plot(xTinv, yNDp, label = 'ND$^+$', color = 'blue', marker = 'x')
ax4.plot(xTinv, yNAm, label = 'NA$^-$', color = 'green', marker = 'x')
ax4.set_yscale('log')
# ax4.plot([0, 0], ax3.get_ylim(), color = 'red', linestyle = 'dashed', linewidth = 0.5)
ax4.set_xlabel("1000/T (K$^{-1}$)", fontsize = fontsize)
ax4.set_ylabel("N (cm$^{-3}$)", fontsize = fontsize)
ax4.legend(fontsize = legend_fontsize)
ax5.plot(xTinv, yEaNe, label = 'Ea(Ne)', color = 'black', marker = 'o')
ax5.plot(xTinv, yEaNeTh, label = 'Ea(Ne*T$^{-0.5}$)', color = 'black', marker = 'o')
ax5.plot(xTinv, yEaNh, label = 'Ea(Nh)', color = 'red', marker = 'o')
ax5.plot(xTinv, yEaNhTh, label = 'Ea(Nh*T$^{-0.5})', color = 'red', marker = 'o')
ax5.set_xlabel("1000/T (K$^{-1}$)", fontsize = fontsize)
ax5.set_ylabel("Ea (meV)", fontsize = fontsize)
ax5.legend(fontsize = legend_fontsize)
ax1.tick_params(labelsize = fontsize)
ax2.tick_params(labelsize = fontsize)
ax3.tick_params(labelsize = fontsize)
ax4.tick_params(labelsize = fontsize)
ax5.tick_params(labelsize = fontsize)
# Rearange the graph axes so that they are not overlapped
plt.tight_layout()
# plt.pause(0.1)
print("Close the graph window to terminate this program")
plt.show()
print("")
usage()
print("")
# print("Press ENTER to exit>>", end = '')
# input()
def exec_EF():
global mode, T0, EF0
global file, E_raw, dos_raw
global nDOS, Emin, Emax, Estep
global EV, EC
global dEFmin, dEFmax, EFmin, EFmax, nEF, EFstep
global dEA, NA, dED, ND, EA, ND
kBTe = kB * T0 / e
dE = nrange * kBTe
E0 = EV - dE
E1 = EC + dE
xEF = []
yNe = []
yNh = []
yNDp = []
yNAm = []
yRH = []
EFprev = EF0
print("at {} K".format(T0))
print ("%5s\t%8s\t%14s\t%14s\t%14s\t%14s" % ("EF(eV)", "Ne", "Nh", "ND+", "NA-", "RH"))
for iEF in range(nEF):
EF = EFmin + iEF * EFstep
dE = nrange * kBTe
# Ne1 = Ne(T0, EF, EF0, E1)
Ne1 = Ne(T0, EF, EC - Estep, E1)
# Nh1 = Nh(T0, EF, E0, EF0)
Nh1 = Nh(T0, EF, E0, EV + Estep)
NDp1 = NDp(EF, T0)
NAm1 = NAm(EF, T0)
RH = 1.0 / e * (Nh1 - Ne1) / pow(Nh1 + Ne1, 2.0)
xEF.append(EF)
yNe.append(Ne1)
yNh.append(Nh1)
yNDp.append(NDp1)
yNAm.append(NAm1)
yRH.append(RH)
print ("%10.4f\t%12.6g\t%12.6g\t%12.6g\t%12.6g\t%12.6g" % (EF, Ne1, Nh1, NDp1, NAm1, RH))
yT0Ne = []
yT0Nh = []
print("")
print ("%5s\t%8s\t%12s\t%12s\t%12s\t%12s\t%12s\t%12s" % ("EF(eV)", "Ne", "Nh", "ND+", "NA-", "RH", "T0(Ne)", "T0(Nh)"))
for i in range(nEF):
if i == 0:
i1 = i
i2 = i+1
elif i == nEF - 1:
i1 = i-1
i2 = i
else:
i1 = i-1
i2 = i+1
dEF = xEF[i2] - xEF[i1]
dlnNedEF = (log(yNe[i2]) - log(yNe[i1])) / dEF
dlnNhdEF = (log(yNh[i2]) - log(yNh[i1])) / dEF
T0Ne = 1.0 / kB / dlnNedEF * e
T0Nh = -1.0 / kB / dlnNhdEF * e
yT0Ne.append(T0Ne)
yT0Nh.append(T0Nh)
print ("%10.4f\t%10.4g\t%10.4g\t%10.4g\t%10.4g\t%10.4g\t%10.4g\t%10.4g" % (EF, Ne1, Nh1, NDp1, NAm1, RH, T0Ne, T0Nh))
print("")
Emid = (EV + EC) / 2.0
print("Effective density of states at the mid gap {} eV:".format(Emid))
fNe = interp1d(xEF, yNe, kind = 'cubic')
fNh = interp1d(xEF, yNh, kind = 'cubic')
dlnNedEF = (log(fNe(Emid + Estep)) - log(fNe(Emid - Estep))) / 2.0 / Estep
dlnNhdEF = (log(fNh(Emid + Estep)) - log(fNh(Emid - Estep))) / 2.0 / Estep
T0Ne = 1.0 / kB / dlnNedEF * e
T0Nh = -1.0 / kB / dlnNhdEF * e
NC = fNe(Emid) * exp((EC - Emid) * e / kB / T0Ne)
NV = fNh(Emid) * exp((Emid - EV) * e / kB / T0Nh)
print(" NC = {} cm-3 (T0 = {} K)".format(NC, T0Nh))
print(" NV = {} cm-3 (T0 = {} K)".format(NV, T0Nh))
xEFapprox = [EFmin + i * EFstep for i in range(nEF)]
yNeapprox = [NC * exp(-(EC - xEFapprox[i]) * e / kB / T0) for i in range(nEF)]
yNhapprox = [NV * exp(-(xEFapprox[i] - EV) * e / kB / T0) for i in range(nEF)]
# calculate DC(E)*fe(E), DV(E)*(1-fe(E))
print("")
print("Calculate fe(E), fh(E)=1-fe(E), DC(E)*fe(E), DV(E)*fh(E) at EF={} eV, T={} K".format(EF0, T0))
yfe = []
yfh = []
yDOSfe = []
yDOSfh = []
for i in range(len(E_raw)):
E = E_raw[i]
yfe.append(fe(E, T0, EF0))
yfh.append(fh(E, T0, EF0))
if E >= EC:
yDOSfe.append(DOSfe(E, T0, EF0))
else:
yDOSfe.append(0.0)
if E <= EV:
yDOSfh.append(DOSfh(E, T0, EF0))
else:
yDOSfh.append(0.0)
#=============================
# Plot graphs
#=============================
fig = plt.figure(figsize = (12, 8))
ax2 = fig.add_subplot(2, 2, 1)
ax2r = ax2.twinx()
ax3 = fig.add_subplot(2, 2, 2)
ax4 = fig.add_subplot(2, 2, 3)
ax1 = fig.add_subplot(2, 2, 4)
ax2.plot(E_raw, dos_raw, label = 'DOS', color = 'black')
ax2.plot(E_raw, yDOSfe, label = 'D(E)fe', color = 'blue', linewidth = 0.5)
ax2.plot(E_raw, yDOSfh, label = 'D(E)fh', color = 'red', linewidth = 0.5)
ax2.plot([EF0, EF0], [min(dos_raw), max(dos_raw)], color = 'red', linestyle = 'dashed')
ax2r.plot(E_raw, yfe, label = 'fe', color = 'blue', linewidth = 0.5, linestyle = 'dashed')
ax2r.plot(E_raw, yfh, label = 'fh', color = 'red', linewidth = 0.5, linestyle = 'dashed')
ax2.set_ylim([0.0, max(dos_raw) * 1.1])
ax2r.set_ylim([0.0, 2.0])
ax2.set_xlabel("E (eV)", fontsize = fontsize)
ax2.set_ylabel("DOS (states/cm$^3$)", fontsize = fontsize)
ax2r.set_ylabel("fe, fh", fontsize = fontsize)
# ax2.legend()
h2l, l2l = ax2.get_legend_handles_labels()
h2r, l2r = ax2r.get_legend_handles_labels()
ax2.legend(h2l + h2r, l2l + l2r, fontsize = legend_fontsize)
ax3.plot(xEF, yNe, label = 'Ne', color = 'black') #, marker = 'o')
ax3.plot(xEF, yNh, label = 'Nh', color = 'red') #, marker = 'x')
ax3.plot(xEF, yNDp, label = 'ND$^+$', color = 'blue') #, marker = 'x')
ax3.plot(xEF, yNAm, label = 'NA$^-$', color = 'green') #, marker = 'x')
ax3.plot(xEFapprox, yNeapprox, label = 'Ne(Boltz)', color = 'gray', linewidth = 0.5) #, marker = 'x')
ax3.plot(xEFapprox, yNhapprox, label = 'Nh(Boltz)', color = 'purple', linewidth = 0.5) #, marker = 'x')
ax3.plot([EV, EV], ax3.get_ylim(), color = 'red', linestyle = 'dashed', linewidth = 0.5)
ax3.plot([EC, EC], ax3.get_ylim(), color = 'red', linestyle = 'dashed', linewidth = 0.5)
ax3.set_yscale('log')
ax3.set_xlabel("EF (eV)", fontsize = fontsize)
ax3.set_ylabel("N (cm$^{-3}$)", fontsize = fontsize)
ax3.legend(fontsize = legend_fontsize)
ax4.plot(xEF, yRH, label = 'R$_H$', color = 'black', marker = 'o')
ax4.set_xlabel("EF (eV)", fontsize = fontsize)
ax4.set_ylabel("R$_H$ (C$^{-1}$cm$^{-3}$)", fontsize = fontsize)
ax4.legend(fontsize = legend_fontsize)
ax1.plot(xEF, yT0Ne, label = 'T$_0$(Ne)', color = 'black') #, marker = 'o')
ax1.plot(xEF, yT0Nh, label = 'T$_0$(Nh)', color = 'red') #, marker = 'x')
ax1.plot([EV, EV], ax3.get_ylim(), color = 'red', linestyle = 'dashed', linewidth = 0.5)
ax1.plot([EC, EC], ax3.get_ylim(), color = 'red', linestyle = 'dashed', linewidth = 0.5)
ax1.set_ylim([0.0, 2.0*T0])
ax1.set_xlabel("EF (eV)", fontsize = fontsize)
ax1.set_ylabel("T$_0$ (K)", fontsize = fontsize)
ax1.legend(fontsize = legend_fontsize)
ax1.tick_params(labelsize = fontsize)
ax2.tick_params(labelsize = fontsize)
ax2r.tick_params(labelsize = fontsize)
ax3.tick_params(labelsize = fontsize)
ax4.tick_params(labelsize = fontsize)
# Rearange the graph axes so that they are not overlapped
plt.tight_layout()
# plt.pause(0.1)
print("Close the graph window to terminate this program")
plt.show()
print("")
usage()
print("")
# print("Press ENTER to exit>>", end = '')
# input()
def main():
global mode, T0, EF0
global Vcell, file, E_raw, dos_raw
global nDOS, Emin, Emax, Estep
global EV, EC
global dEFmin, dEFmax, EFmin, EFmax, nEF, EFstep
global dEA, NA, dED, ND, EA, ED
updatevars()
print("mode: ", mode)
print("DOS configuration")
print(" Read from [{}]".format(file))
E_raw, dos_raw = np.genfromtxt(file, skip_header=1, usecols=(0,1), unpack=True)
nDOS = len(E_raw)
for i in range(len(E_raw)):
dos_raw[i] *= 1.0 / (Vcell * 1.0e-24)
Emin = E_raw[0]
Emax = E_raw[nDOS-1]
Estep = E_raw[1] - E_raw[0]
print(" E range: {} - {}, {} eV step".format(Emin, Emax, Estep))
print("")
EV, EC = FindBandEdges(E_raw, dos_raw, EF0, Egth)
Eg = EC - EV
print(" Band edge: EV={} EC={} Eg={} eV".format(EV, EC, Eg))
EFmin = EV + dEFmin
EFmax = EC + dEFmax
EFstep = (EFmax - EFmin) / (nEF - 1)
ED = EC + dED
EA = EV + dEA
print(" Donor level : {} eV, {} cm^-3".format(ED, ND))
print(" Acceptor level: {} eV, {} cm^-3".format(EA, NA))
print("")
print("EF dependence")
print(" EF range: {} - {}, {} eV step".format(EFmin, EFmax, EFstep))
print("")
print("T dependence")
print(" Temperature range: {} - {}, {} K step".format(Tmin, Tmax, Tstep))
print("")
print("Integration configuration")
print(" Integration E range: {} - {} eV, or EF+-{}*kBT eV".format(Einteg0, Einteg1, nrange))
print(" quad() parameters")
print(" releps=", eps)
print(" nmaxdiv=", nmaxdiv)
print("")
print("EF at 0 K = ", EF0, " eV")
Ne0K = Ne(0.0, EF0, -5.0, EF0)
# Ne0K = Ne(0.0, EF0, Einteg0, EF0)
print(" Ne at 0 K = ", Ne0K, " /u.c.")
print("")
if mode == 'T':
exec_T()
elif mode == 'EF':
exec_EF()
else:
print("")
print("Error: Invalid mode [{}]".format(mode))
if __name__ == '__main__':
main()