载流子迁移率
通常指半导体内部电子和空穴整体的运动快慢情况,是衡量半导体器件性能的重要物理量。2004年,石墨烯的成功剥离引起了研究人员对于二维材料性质探索的浓厚兴趣。石墨烯、黑磷等二维材料展现出的高载流子迁移率是其中的一个重要研究课题,科研人员在理论计算方面已经做了大量的工作。由于电子在运动过程中不仅受到外电场力的作用,还会不断的与晶格、杂质、缺陷等发生无规则的碰撞,大大增加了理论计算的难度。
目前
计算载流子迁移率
比较常用的理论是
形变势理论
和
玻尔兹曼输运理论
,前者没有考虑电子和声子(晶格振动)以及电子与电子之间的相互作用等因素,计算结果存在一定的误差,但笔者的计算结果与实验值在数量级上是吻合的;玻尔兹曼输运理论的一种计算考虑了电子-声子的相互作用,基于第一性原理计算和最大局域化 Wannier 函数插值方法,借助于 Quantum-ESPRESSO 和 EPW 软件可以完成载流子迁移率计算。缺点是计算量太大,一般的课题组很难承受起高昂的计算费用,另外 EPW 软件对于二维材料的计算存在部分问题,在其官方论坛也有讨论,计算过程在后续文章中会提到。
本文以形变势理论方法为基础,详细介绍了二维 InSe 的电子和空穴的有效质量与载流子迁移率的计算方法。
基于 Bardeen 和 Shockley 提出的形变势理论,二维材料载流子迁移率可以根据下式计算:
其中,
m
∗
是传输方向上的有效质量,
T
是温度,
k
B
是玻尔兹曼常数。
E
1
表示沿着传输方向上位于价带顶 (VBM) 的空穴或聚于导带底 (CBM) 的电子的形变势常数,由公式
E
1
=Δ
E
/(Δ
l
/
l
0
) 确定,Δ
E
为在压缩或拉伸应变下 CBM 或 VBM 的能量变化,
l
0
是传输方向上的晶格常数,Δ
l
是
l
0
的变形量。
m
d
是载流子的平均有效质量,由下面公式定义。
C
2D
是均匀变形晶体的弹性模量,对于 2D 材料,弹性模量可以通过下面公式来计算,
其中
E
是总能量,
S
0
是优化后的面积。
下面对公式中的单位(量纲)做一个简单换算,具体如下:
换算过程:
http://muchong.com/bbs/viewthread.php?tid=7149817&fpage=1
#! /usr/bin/python
# This program reads in base vectors from a given file, calculates reciprocal
vectors
# then writes to outfile in different units
# LinuxUsage: crecip.py infile outfile
# Note: the infile must be in the form below:
# inunit ang/bohr
# _begin_vectors
# 46.300000000 0.000000000 0.000000000
# 0.000000000 40.500000000 0.000000000
# 0.000000000 0.000000000 10.000000000
# _end_vectors
#
# Note: LATTICE VECTORS ARE SPECIFIED IN ROWS !
def GetInUnit( incontent ):
inunit = ""
for line in incontent:
if line.find("inunit") == 0:
inunit = line.split()[1]
break
return inunit
def GetVectors( incontent ):
indstart = 0
indend = 0
for s in incontent:
if s.find("_begin_vectors") != -1:
indstart = incontent.index(s)
else:
if s.find("_end_vectors") != -1:
indend = incontent.index(s)
result = []
for i in range( indstart + 1, indend ):
line = incontent[i].split()
result.append( [ float(line[0]), float(line[1]), float(line[2]) ] )
return result
def Ang2Bohr( LattVecAng ):
LattVecBohr = LattVecAng
for i in range(0,3):
for j in range(0,3):
LattVecBohr[i][j] = LattVecAng[i][j] * 1.8897261246
return LattVecBohr
def DotProduct( v1, v2 ):
dotproduct = 0.0
for i in range(0,3):
dotproduct = dotproduct + v1[i] * v2[i]
return dotproduct
def CrossProduct( v1, v2 ):
# v3 = v1 WILL LEAD TO WRONG RESULT
v3 = []
v3.append( v1[1] * v2[2] - v1[2] * v2[1] )
v3.append( v1[2] * v2[0] - v1[0] * v2[2] )
v3.append( v1[0] * v2[1] - v1[1] * v2[0] )
return v3
def CalcRecVectors( lattvec ):
pi = 3.141592653589793
a1 = lattvec[0]
a2 = lattvec[1]
a3 = lattvec[2]
b1 = CrossProduct( a2, a3 )
b2 = CrossProduct( a3, a1 )
b3 = CrossProduct( a1, a2 )
volume = DotProduct( a1, CrossProduct( a2, a3 ) )
RecVec = [ b1, b2, b3 ]
# it follows the definition for b_j: a_i * b_j = 2pi * delta(i,j)
for i in range(0,3):
for j in range(0,3):
RecVec[i][j] = RecVec[i][j] * 2 * pi / volume
return RecVec
def main(argv = None):
argv = sys.argv
infilename = argv[1]
outfilename = argv[2]
pi = 3.141592653589793
bohr2ang = 0.5291772109253
ang2bohr = 1.889726124546
infile = open(infilename,"r")
incontent = infile.readlines()
infile.close()
inunit = GetInUnit( incontent )
LattVectors = GetVectors( incontent )
# convert units from ang to bohr
if inunit == "ang":
LattVectors = Ang2Bohr( LattVectors )
# calculate reciprocal vectors in 1/bohr
RecVectors = CalcRecVectors( LattVectors )
# open outfile for output
ofile = open(outfilename,"w")
# output lattice vectors in bohr
ofile.write("lattice vectors in bohr:\n")
for vi in LattVectors:
ofile.write("%14.9f%14.9f%14.9f\n" % (vi[0], vi[1], vi[2]))
ofile.write("\n")
# output lattice vectors in ang
convfac = bohr2ang
ofile.write("lattice vectors in ang:\n")
for vi in LattVectors:
ofile.write("%14.9f%14.9f%14.9f\n" % (vi[0]*convfac, vi[1]*convfac,
vi[2]*
convfac))
ofile.write("\n")
# output reciprocal vectors in 1/bohr
ofile.write("reciprocal vectors in 1/bohr:\n")
for vi in RecVectors:
ofile.write("%14.9f%14.9f%14.9f\n" % (vi[0], vi[1], vi[2]))
ofile.write("\n")
# output reciprocal vectors in 1/ang
convfac = ang2bohr
ofile.write("reciprocal vectors in 1/ang:\n")
for vi in RecVectors:
ofile.write("%14.9f%14.9f%14.9f\n" % (vi[0]*convfac, vi[1]*convfac, vi[2]*
convfac))
ofile.write("\n")
# output reciprocal vectors in 2pi/bohr
convfac = 1.0/(2.0*pi)
ofile.write("reciprocal vectors in 2pi/bohr:\n")
for vi in RecVectors:
ofile.write("%14.9f%14.9f%14.9f\n" % (vi[0]*convfac, vi[1]*convfac, vi[2]*convfac))
ofile.write("\n")
# output reciprocal vectors in 2pi/ang
convfac = ang2bohr/(2.0*pi)
ofile.write("reciprocal vectors in 2pi/ang:\n")
for vi in RecVectors:
ofile.write("%14.9f%14.9f%14.9f\n" % (vi[0]*convfac, vi[1]*convfac, vi[2]*convfac))
# close
ofile.close()
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
4.1 建模
由于计算过程中需要对二维 InSe 施加应变,但二维 InSe 原胞是六角结构,不容易施加应变。但是侯柱峰老师讲了对石墨烯原胞施加应变的方法,笔者认为虽然可行,但过于繁琐,故不采用此法。我们可以利用根号建模的方法讲六角结构 InSe原胞变为方形结构的 InSe 超胞,然后施加应变可大大提高操作效率,但计算量的增加再可接受范围之内。下面给出关键的建模步骤,更多的根号建模部分可参考我的往期博客文章。
-
切面并构建二维InSe原胞,同时调整晶格基矢,使其变为方形结构:
4.2 结构优化
INCAR
SYSTEM = InSe
ISTART = 0
NWRITE = 2
PREC = Accurate
ENCUT = 500
GGA = PE
NSW = 200
ISIF = 3
ISYM = 2
IBRION = 2
NELM = 80
EDIFF = 1E-05
EDIFFG = -0.01
ALGO = Normal
LDIAG = .TRUE.
LREAL = .FALSE.
ISMEAR = 0
SIGMA = 0.05
ICHARG = 2
LWAVE = .FALSE.
LCHARG = .FALSE.
NPAR = 4
KPOINTS
Monkhorst Pack
0
Gamma
11 7 1
.0 .0 .0
POSCAR
Se In
1.000
4.083622259999999 -0.000000000000001 0.000000000000000
0.000000000000000 7.073041233239241 0.000000000000000
0.000000000000000 0.000000000000000 25.377516849029359
Se In
4 4
Direct
0.5000005000000000 0.1666665000000000 0.5271404971815050 !Se
0.0000004999999997 0.6666665000000004 0.5271404971815050 !Se
0.5000005000000000 0.1666665000000000 0.3152396685456632 !Se
0.0000004999999997 0.6666665000000004 0.3152396685456632 !Se
0.4999995000000003 0.8333335000000002 0.4767849697227853 !In
-0.0000005000000000 0.3333335000000000 0.4767849697227853 !In
0.4999995000000003 0.8333335000000002 0.3655951960043828 !In
-0.0000005000000000 0.3333335000000000 0.3655951960043828 !In
OPTCELL
POTCAR
cat Se/POTCAR In_d/POTCAR > POTCAR
4.3 静态自洽
INCAR
SYSTEM = InSe
ISTART = 0
NWRITE = 2
PREC = Accurate
ENCUT = 500
GGA = PE
NSW = 0
ISIF = 2
ISYM = 2
IBRION = -1
NELM = 80
EDIFF = 1E-05
EDIFFG = -0.01
ALGO = Normal
LDIAG = .TRUE.
LREAL = .FALSE.
ISMEAR = 0
SIGMA = 0.05
ICHARG = 2
NPAR = 4
KPOINTS
Monkhorst Pack
0
Gamma
21 13 1
.0 .0 .0
POSCAR
4.4 能带计算
INCAR
SYSTEM = InSe
ISTART = 1
NWRITE = 2
PREC = Accurate
ENCUT = 500
GGA = PE
NSW = 0
ISIF = 2
ISYM = 2
IBRION = -1
NELM = 80
EDIFF = 1E-05
EDIFFG = -0.01
ALGO = Normal
LDIAG = .TRUE.
LREAL = .FALSE.
ISMEAR = 0
SIGMA = 0.05
ICHARG = 2
LORBIT = 11
LWAVE = .FALSE.
LCHARG = .FALSE.
NPAR = 4
KPOINTS
k-points along high symmetry lines
80
Line-mode
Rec
0 0.5 0 !Y
0 0 0 !gamma
0 0 0 !gamma
0.5 0 0 !X
0.5 0 0 !X
0.5 0.5 0 !S
0.5 0.5 0 !S
0 0.5 0 !Y
4.5 有效质量计算
计算说明:对于包含了晶格周期性的有效质量的表达式如下所示:
在带入物理量进行有效质量计算时,涉及单位制问题。一般写输入文件时,长度单位为 Å;而程序输出的能带结构中,能量单位为 eV,计算起来比较繁琐。
原子单位制有两种,一种为 Hartree 原子单位制,另一种为 Rydberg 单位制。这两种单位制的区别在于,Hartree 单位制下基本物理量简单,电子电荷和质量都为1;而 Rydberg 单位制下薛定谔方程简单,系数为1。Hartree 单位制下,一个长度单位等于1L bohr = 0.5292 Å,一个能量单位1E Hartree = 27.21 eV,约化普朗克常数 ℏ=1。这样有效质量表达式中的约化普朗克常数就没了。
-
将 VASP 计算 band 时的 k 点坐标(分数坐标)转变为笛卡尔坐标:
-
根据两点间的距离公式,计算出各 K 点之间的距离:
4.6 求每个 K 点的位置值
根据 VASP 计算能带时各高对称点间均匀撒点,求出每个点的位置值,第一个点设为 0,本例中为 80 个点,在 excel 中进行操作。
因计算时均匀撒点 80 个,故有 79 个小间隔,对于 |YΓ| 来说,每个小间隔为 0.002975210683544,故1-80个点的坐标值都可算出,以此类推,后面的点的坐标在前面点的基础上加上间隔即可(注意:在 80 个点结束处和 81 个点开始处的值是一样的,后面的点类似)。
4.7 画出价带顶和导带底的能带
在 origin 中找出能带数据的价带顶 (VBM) 和导带底 (CBM) 的数据,把上面计算得到的 K 点路径做为 X 轴,VBM 和 CBM 作为 Y 轴,在 origin 中画图如下:
4.8 计算有效质量(以x方向电子的有效质量为例)
首先换算能量单位,由 eV 换算为原子单位制下的能量 CBM/27.21 然后选取 Γ-X 方向上以 Γ 开始的 4-8 个点的数据画能带图,如下:
用 y = a+bx+cx^2 函数拟合,操作如下:
有效质量为 1/2
C
,其中
C
=2.69188,算得有效质量为 0.19 ,为电子沿
x
方向的质量。文献计算结果为 0.19,符合一致。
本文载流子迁移率的计算依据的是形变势理论,因此需要对二维 InSe 的
x
方向和
y
方向施加应变,施加应变的范围是 -2%~2%。为了计算的准确性,计算过程中考虑了泊松效应,即对
x
轴施加应变时,固定
x
轴和
z
轴,优化
y
方向的晶格常数;对
y
轴施加应变时,固定
y
轴和
z
轴,优化
x
方向的晶格常数。
5.1 准备输入文件
首先建立 mobility-x 文件夹,然后在该文件夹下建立初始文件夹,命名为 IS,其结构目录如下:
$ tree mobility
mobility
├── IS
│ ├── 2_scf
│ │ ├── band
│ │ │ ├── INCAR
│ │ │ ├── KPOINTS
│ │ │ └── POTCAR
│ │ ├── INCAR
│ │ ├── KPOINTS
│ │ └── POTCAR
│ ├── INCAR
│ ├── KPOINTS
│ ├── OPTCELL
│ ├── pbs
│ ├── POSCAR
│ └── POTCAR
└── mobility.sh
说明:
#!/bin/bash
#PBS -N mobility
#PBS -l nodes=1:ppn=16
#PBS -m abe
#PBS -j n
##PBS -o job.log
##PBS -e job.err