QUANTUM ESPRESSO:bands.x
采用scf计算得到电荷密度和波函数进行bands计算,非自洽(bands)计算能带
设置nscf-bands.in
文件,需要修改的参数包括:calculation
,nbnd
,K_POINTS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
&CONTROL
calculation = "bands"
restart_mode = "from_scratch"
prefix = "carbyne"
outdir = "./outdir/"
pseudo_dir = "./pseudo/"
verbosity = "high"
tprnfor = .true.
tstress = .true.
etot_conv_thr = 1.0d-6
/
&SYSTEM
ibrav = 6
celldm(1) = 18.89726125
celldm(3) = 0.256551169
nat = 2
ntyp = 1
nbnd = 22
occupations = 'fixed'
ecutwfc = 50
ecutrho = 400
/
&ELECTRONS
conv_thr = 1.000e-9
electron_maxstep = 200
mixing_beta = 0.7
startingpot = "atomic"
startingwfc = "atomic+random"
/
K_POINTS crystal_b
2
0.0 0.0 -0.5 400
0.0 0.0 0.5 1
ATOMIC_SPECIES
C 12.01070 C.pbe-n-kjpaw_psl.1.0.0.UPF
ATOMIC_POSITIONS (angstrom)
C 5.0000000000 5.0000000000 0.0000000000 0 0 0
C 5.0000000000 5.0000000000 1.2640744811 0 0 1
NSCF-bands计算完成后,使用bands.x程序来处理得到态密度,输入文件bands.in
如下
1
2
3
4
5
6
&bands
prefix = 'carbyne'
outdir = './outdir'
filband = 'carbyne.bands.dat'
lsym = .true.
/
对文件carbyne.bands.dat使用Originlab作图,并将能量减去VBM值,使得VBM=0 ,能带结构如下:
计算完能带后使用projwfc.x计算投影能带(Pbands)进行fatband处理,用来得到Wannier拟合的初始函数指定
依次运行pw.x、projwfc.x,在能带计算之后,用projwfc.x生成的fatband.projwfs_up文件,可以和bands.x生成的文件carbyne.bands.dat结合画出各个能带的原子轨道投影,画图脚本如下:
输入文件projwfc.in如下:
1
2
3
4
5
6
&projwfc
prefix = 'carbyne'
outdir = './outdir'
lsym = .false.
filproj = 'fatband'
/
画图脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: yyyu200@163.com
"""
import numpy as np
# plot range for y-axis
ymin=-23
ymax=10
dline=30 # vertical line intervals
lw=0.5 # line width
nband=26 # highest valence band
feig=open('bd.dat')
l=feig.readline()
nbnd=int(l.split(',')[0].split('=')[1])
nks=int(l.split(',')[1].split('=')[1].split('/')[0])
eig=np.zeros((nks,nbnd),dtype=float)
for i in range(nks):
l=feig.readline()
count=0
if nbnd%10==0:
n=nbnd//10
else:
n=nbnd//10+1
for j in range(n):
l=feig.readline()
for k in range(len(l.split())):
eig[i][count]=l.split()[k]
count=count+1
feig.close()
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
F=plt.gcf()
F.set_size_inches([4,5])
p1=plt.subplot(1, 1, 1)
eig_vbm=max(eig[:, nband-1])
#eig_vbm= 0.00 # fermi energy level in scf output for metals
for i in range(nbnd):
line1=plt.plot(np.arange(0,nks), eig[:,i]-eig_vbm,color='grey',linewidth=lw )
vline=dline
while vline<nks-1:
plt.axvline(x=vline, ymin=ymin, ymax=ymax,linewidth=lw,color='black')
vline=vline+dline
elem=['Sn','O']
ielem=np.array([2,4],dtype=np.int32) # number of atoms for each element
orb=[['s','p','d'],['s','p']] # projectors for each element
N=len(elem)
iorb=np.zeros([N,],dtype=np.int32) # number of projectors for each element
for i in range(N):
iorb[i]=len(orb[i])
lorb=np.zeros([N,],dtype=np.int32) # number of local orbital for each element
for i in range(N):
for j in orb[i]:
if j is 's':
lorb[i]+=1
elif j is 'p':
lorb[i]+=3
elif j is 'd':
lorb[i]+=5
elif j is 'f':
lorb[i]+=7
else:
print("unexpect: ",j)
assert False
nlorb=np.dot(ielem,lorb)
pjsum=np.zeros([nlorb, nks, nbnd], dtype=np.float32)
filproj=open('sno.projwfc_up')
nline_io_header=14 # line number at ' F F'
for i in range(nline_io_header):
filproj.readline()
for i in range(nlorb):
filproj.readline()
for j in range(nks):
for k in range(nbnd):
pjsum[i,j,k]=float(filproj.readline().split()[2])
nplotline=np.sum(iorb)
# oo, orbital index for each kind of color, oo can be generated by the following commands
#grep '[a-zA-Z]' sno.projwfc_up |grep 2P|awk '{printf( $1-1",")}'
oo=[[0,9],
[1,2,3,10,11,12],
[4,5,6,7,8,13,14,15,16,17],
[18,22,26,30],
[19,20,21,23,24,25,27,28,29,31,32,33]]
s_of_o=np.zeros([nks,],dtype=np.float32)
color=['r','g','orange','cyan','blue']
label=['Sn s','Sn p','Sn d','O s','O p']
scale=90.0
st=[]
for i in range(len(oo)):
for k in range(nbnd):
s_of_o=np.zeros([nks,],dtype=np.float32)
for j in oo[i]:
s_of_o[:]+=pjsum[j,:,k]
if k == 0:
st.append(plt.scatter(-1, ymin-1, 20, c=color[i], alpha=0.5, label=label[i],marker='.',edgecolor='none'))
st.append(plt.scatter(np.arange(0,nks), eig[:,k]-eig_vbm, s=scale*s_of_o, c=color[i], alpha=0.5, marker='.',edgecolor='none'))
plt.xlim([0,nks-1]) # 201 points
plt.ylim([ymin,ymax])
plt.ylabel(r'E (eV)',fontsize=16)
plt.xticks((0,30,60), ('M', r'${\Gamma}$', 'Z') )
plt.subplots_adjust(left=0.20, right=0.75, top=0.95, bottom=0.1)
p1.legend(scatterpoints =1, numpoints=1,markerscale=2.0, bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.savefig('pjband.png',dpi=400)
得到投影能带(Pjbands)如下:
脚本使用说明,见Link
(1) 首先在终端运行:grep ‘[a-zA-Z]’ sno.projwfc_up
输出了文件中所有包含字母的行,可以看出,Sn有5S,5P,4D轨道,O有2S,2P轨道,轨道的种类5类(当然还可以细分为P的3个小类Pz,Px,Py,和D轨道的5类,顺序见这里[2]),这里选择5类颜色作投影能带。
(2) 再运行grep '[a-zA-Z]' sno.projwfc_up |grep 'Sn 5S'|awk '{printf( $1-1",")}END{print("");}'
得到Sn 5S是哪些序号的,依次找到Sn的5S,5P,4D轨道,O的2S,2P轨道共5种,所以oo设置成:
1
2
3
4
5
oo=[[0,9],
[1,2,3,10,11,12],
[4,5,6,7,8,13,14,15,16,17],
[18,22,26,30],
[19,20,21,23,24,25,27,28,29,31,32,33]]
(3) 导体根据scf输出费米能级
eig_vbm = 0.0
绝缘体设置nband为最高价带,以下两行保留一行注释另一行
1
2
eig_vbm=max(eig[:, nband-1])
#eig_vbm= 0.00 # fermi energy level in scf output for metals
ymin,ymax,画图中y坐标范围
(4) 设置元素名,顺序不限
1
elem=['Sn','O']
每种元素的原子个数,顺序与下面orb保持一致
ielem=np.array([32,1],dtype=np.int32) # number of atoms for each element
每种原子的轨道类型,限s、p、d、f,每个元素一个list,要确保赝势含有对应轨道。
orb=[['s','p'],['s','p','s','d']] # projectors for each element
(5) 指定文件名,projwfc.x中由filproj设置的文件
filproj=open('sno.projwfc_up')
(6) 指定数据开始位置
运行grep -n ' F F' sno.projwfc_up
得到行号是41。设置如下:
1
nline_io_header=41
(7) 投影能带的颜色
1
2
color=['r','g','orange','cyan','blue']
label=['Sn s','Sn p','Sn d','O s','O p']
,更多颜色名称见(https://matplotlib.org/3.1.0/gallery/color/named_colors.html)。相应轨道名称,在画图图例中显示。
(8) 投影能带点的大小
1
scale=30.0
(9) k点路径名称
1
plt.xticks(vline, ('M',r'${\Gamma}$', 'Z') )
k点横坐标
1
vline=(0,30,60)
(10) 输出图片文件名,分辨率
1
plt.savefig('pjband.png',dpi=400)
使用自写fortran脚本进行fatband画图
脚本下载1(需要能上GitHub):https://github.com/xh125/QE-changecode/tree/main/bandfat
脚本下载2(Onedrive共享):bandfat.f90 bandfat.in
脚本使用说明:
依次运行pw.x、projwfc.x,在能带计算之后,用projwfc.x生成的fatband.projwfs_up文件,可以和bands.x生成的文件carbyne.bands.dat和carbyne.bands.dat.gnu结合画出各个能带的原子轨道投影.将fortran代码编译生成可执行文件bandfat.x
.输入文件使用bandfat.in
,其输入文件如下:
1
2
3
4
5
&fatinput
filband = "Si.bands.dat"
filproj = "fatband"
bandfatfile = "fatband.dat.gnu"
/
其中输入参数需要满足
filband = Si.bands.dat
filband need to set as the input of bands.x
filproj = fatband
filproj need to set as the input of projwfc.x
bandfatfile = fatband.dat.gnu the fatband are write to file: fatband.dat.gnu
能带投影文件名为:
1
2
3
4
5
6
7
8
9
10
11
12
13
DO is=1,nspin
IF (nspin==2) THEN
IF (is==1) filename=trim(filproj)//'.projwfc_up'
IF (is==2) filename=trim(filproj)//'.projwfc_down'
nksinit=(nkstot/2)*(is-1)+1
nkslast=(nkstot/2)*is
nk_ = nkstot/2
ELSE
filename=trim(filproj)//'.projwfc_up'
nksinit=1
nkslast=nkstot
nk_ = nkstot
ENDIF
投影能带中的内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
WRITE (iunplot, '(a)') title
WRITE (iunplot, '(8i8)') nr1x, nr2x, nr3x, nr1, nr2, nr3, nat, ntyp
WRITE (iunplot, '(i6,6f12.8)') ibrav, celldm
IF (ibrav == 0) THEN
WRITE ( iunplot, * ) at(:,1)
WRITE ( iunplot, * ) at(:,2)
WRITE ( iunplot, * ) at(:,3)
ENDIF
WRITE (iunplot, '(3f20.10,i6)') gcutm, dual, ecutwfc, 9
WRITE (iunplot, '(i4,3x,a2,3x,f5.2)') &
(nt, atm (nt), zv (nt), nt=1, ntyp)
WRITE (iunplot, '(i4,3x,3f15.9,3x,i2)') (na, &
(tau (i, na), i = 1, 3), ityp (na), na = 1, nat)
WRITE (iunplot, '(3i8)') natomwfc, nkstot, nbnd
WRITE (iunplot, '(2l5)') noncolin, lspinorb
DO nwfc = 1, natomwfc
IF (lspinorb) THEN
WRITE(iunproj,'(2i5,1x,a4,1x,a2,1x,2i5,f5.1,1x,f5.1)') &
nwfc, nlmchi(nwfc)%na, atm(ityp(nlmchi(nwfc)%na)), &
nlmchi(nwfc)%els, nlmchi(nwfc)%n, nlmchi(nwfc)%l, &
nlmchi(nwfc)%jj, &
compute_mj(nlmchi(nwfc)%jj,nlmchi(nwfc)%l, nlmchi(nwfc)%m)
ELSE IF (noncolin) THEN
WRITE(iunproj,'(2i5,1x,a4,1x,a2,1x,3i5,1x,f4.1)') &
nwfc, nlmchi(nwfc)%na, atm(ityp(nlmchi(nwfc)%na)), &
nlmchi(nwfc)%els, nlmchi(nwfc)%n, nlmchi(nwfc)%l, &
nlmchi(nwfc)%m, &
0.5d0-int(nlmchi(nwfc)%ind/(2*nlmchi(nwfc)%l+2))
ELSE
WRITE(iunproj,'(2i5,1x,a4,1x,a2,1x,3i5)') &
nwfc, nlmchi(nwfc)%na, atm(ityp(nlmchi(nwfc)%na)), &
nlmchi(nwfc)%els, nlmchi(nwfc)%n, nlmchi(nwfc)%l, &
nlmchi(nwfc)%m
END IF
DO ik=nksinit,nkslast
DO ibnd=1,nbnd
WRITE(iunproj,'(2i8,f20.10)') ik,ibnd, abs(proj(nwfc,ibnd,ik))
ENDDO
ENDDO
ENDDO
首先运行:grep "[a-zA-Z]" fatband.projwfc_up
,得到的每一个投影轨道的信息:
具体投影轨道的波函数可以参考Wannier90 User Guide中53页的projector的相关波函数。分别对应于轨道n,l,m好量子数。投影轨道,与晶格的取向有关。
输出了文件中所有包含字母的行,可以看出,C有2S,2P 轨道,轨道的种类4类,这里选择4类颜色作投影能带。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
module kinds
implicit none
integer,parameter :: dp= kind(1.0d0)
end module
module constants
implicit none
integer,parameter :: maxlen = 86
end module
module io
use kinds
use constants
implicit none
integer,public,save :: stdout,stdin
character(len=maxlen) :: stdout_name="bandfat.out"
character(len=maxlen) :: stdin_name = "bandfat.in"
character(len=maxlen) :: msg
integer :: ierr
contains
function io_file_unit() !得到一个当前未使用的unit,用于打开文件
!===========================================
!! Returns an unused unit number
!! so we can later open a file on that unit.
!===========================================
implicit none
integer :: io_file_unit,unit_index
logical :: file_open
unit_index = 9
file_open = .true.
do while ( file_open )
unit_index = unit_index + 1
inquire( unit=unit_index, OPENED = file_open ) !用于检查文件状态,参考P.536
end do
io_file_unit = unit_index
return
end function io_file_unit
subroutine open_file(file_name,file_unit)
implicit none
character(len=*),intent(in) :: file_name
integer,intent(in) :: file_unit
open(unit=file_unit, file=file_name,iostat=ierr,iomsg=msg)
if(ierr /= 0 ) then
call io_error('Error: Problem opening "'//trim(adjustl(file_name))//' " file')
call io_error(msg)
endif
end subroutine open_file
subroutine close_file(file_name,file_unit)
implicit none
integer,intent(in) :: file_unit
character(len=*),intent(in) :: file_name
close(file_unit,iostat=ierr,iomsg=msg)
if(ierr /= 0 ) then
call io_error('Error: Problem close "'//trim(adjustl(file_name))//' " file')
call io_error(msg)
endif
end subroutine close_file
!========================================
subroutine io_error ( error_msg )
!========================================
!! Abort the code giving an error message
!========================================
implicit none
character(len=*), intent(in) :: error_msg
write(stdout,*) 'Exiting.......'
write(stdout, '(1x,a)') trim(error_msg)
close(stdout)
write(*, '(1x,a)') trim(error_msg)
write(*,'(A)') "Error: examine the output/error file for details"
STOP
end subroutine io_error
subroutine findkline(funit,kline,indexi,indexe)
implicit none
integer,intent(in):: funit
character(len=*),intent(in) :: kline
integer,intent(in)::indexi,indexe
logical :: lfindkline
character(len=maxlen) :: ctmp
lfindkline = .FAlSE.
do while(.NOT. lfindkline)
read(funit,"(A)") ctmp
if (ctmp(indexi:indexe)==kline) then
lfindkline = .TRUE.
backspace(unit=funit)
endif
enddo
end subroutine findkline
end module
module parameters
use kinds
use constants
use io
implicit none
character(len=maxlen) :: filband,filband0
character(len=maxlen) :: filproj
character(len=maxlen) :: bandfatfile
integer :: bandsunit,projsunit,bandfatunit,bands0unit
namelist /fatinput/ filband,filproj,bandfatfile
contains
subroutine readinput()
implicit none
stdin = io_file_unit()
call open_file(stdin_name,stdin)
filband="bands.dat"
filproj="fatband"
bandfatfile="fatband.dat.gnu"
read(UNIT=stdin,nml=fatinput,iostat=ierr,iomsg=msg)
if(ierr /= 0) then
call io_error('Error: Problem reading namelist file fatinput')
call io_error(msg)
endif
close(stdin)
write(stdout,"(1X,A13,1X,A)") "filband =", trim(filband)
write(stdout,*) "filband need to set as the input of bands.x "
write(stdout,"(/,1X,A13,1X,A)") "filproj =", trim(filproj)
write(stdout,*) "filproj need to set as the input of projwfc.x "
write(stdout,"(/,1X,A13,1X,A)") "bandfatfile =", trim(bandfatfile)
write(stdout,*) "the fatband are write to file: ",trim(bandfatfile)
end subroutine readinput
end module parameters
program main
use kinds
use constants
use parameters
use io
implicit none
integer :: nbnd,nks,natomwfc
integer :: ik,iband,ipol,iwfc
character(len=maxlen) :: ctmp,cformat
real(kind=dp),allocatable :: kpoints(:,:),Enk(:,:),proj(:,:,:)
character(len=13),allocatable :: nameatomwfc(:)
real(kind=dp),allocatable :: lkline(:)
stdout = io_file_unit()
call open_file(stdout_name,stdout)
call readinput()
bandfatunit = io_file_unit()
call open_file(bandfatfile,bandfatunit)
bandsunit = io_file_unit()
call open_file(filband,bandsunit)
read(bandsunit,"(12X,I4,6X,I6)") nbnd,nks
allocate(kpoints(3,nks),Enk(nbnd,nks))
write(ctmp,*) nbnd
do ik=1,nks
read(bandsunit,'(10x,3f10.6)') (kpoints(ipol,ik),ipol=1,3)
read(bandsunit,"(10f9.3)") (Enk(iband,ik),iband=1,nbnd)
enddo
allocate(lkline(nks))
lkline = 0.0
filband0 = trim(filband)//".gnu"
bands0unit = io_file_unit()
call open_file(filband0,bands0unit)
do ik =1,nks
read(bands0unit,"(f10.4)") lkline(ik)
enddo
call close_file(filband0,bands0unit)
!WRITE (iunplot, '(3i8)') natomwfc, nkstot, nbnd
!WRITE (iunplot, '(2l5)') noncolin, lspinorb
projsunit = io_file_unit()
filproj = trim(filproj)//".projwfc_up"
call open_file(filproj,projsunit)
call findkline(projsunit," F F",1,10)
backspace(projsunit)
read(projsunit,"(3i8)") natomwfc,nks,nbnd
allocate(proj(natomwfc,nbnd,nks))
allocate(nameatomwfc(natomwfc))
read(projsunit,*)
do iwfc=1,natomwfc
read(projsunit,"(5X,A13)") nameatomwfc(iwfc)
do ik=1,nks
do iband=1,nbnd
read(projsunit,"(16X,F20.10)") proj(iwfc,iband,ik)
enddo
enddo
enddo
write(ctmp,*) natomwfc
cformat = "(A10,1X,A10,"//trim(adjustl(ctmp))//"(1X,A13))"
write(bandfatunit,cformat) "longkpoint","Energy(eV)",(nameatomwfc(iwfc),iwfc=1,natomwfc)
cformat = "(F10.5,1X,F10.5,"//trim(adjustl(ctmp))//"(1X,F13.5))"
do iband=1,nbnd
do ik=1,nks
write(bandfatunit,cformat) lkline(ik),Enk(iband,ik),(proj(iwfc,iband,ik),iwfc=1,natomwfc)
enddo
write(bandfatunit,*)
enddo
end program
采用Originlab作图得到的fatband的图如下所示:其中红色为pz轨道,蓝色为sp2轨道。使用命令:grep high bands.out
得到高对称点在线性模式下的坐标:
1
2
3
4
high-symmetry point: 0.0000 0.0000 0.0000 x coordinate 0.0000
high-symmetry point: 0.5000 0.2887 0.0000 x coordinate 0.5774
high-symmetry point: 0.6667 0.0000 0.0000 x coordinate 0.9107
high-symmetry point: 0.0000 0.0000 0.0000 x coordinate 1.5774