整理用Fortran读取Wannier90拟合的hr数据,后续设计到极化率以及响应之类的计算还是用Fortran的计算速度是最快的。
{:.info}

前言

在之前博客利用Wannier90的hr数据构建动量空间能带并计算高对称点宇称中用Python实现过读取Wannier90_hr.dat这个数据,当时只是涉及到计算一下能带以及拓扑不变量,此时不会遇到一些计算瓶颈。在涉及到一些响应系数或者RPA极化率计算
的时候Python用起来就有点慢了,所以干脆也就用Fortran写一个读取Wannier90_hr.dat的程序,方面以后自己使用。

代码

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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
module param
implicit none
integer,parameter::dp = kind(1.0)
integer numk_bz,num_wann,nrpts,numk_FS,kn
real(dp) mu
parameter(kn = 100,mu = 0.0)
real(dp),parameter::pi = 3.1415926535897
real(dp),parameter::deltaE = 0.01 ! 费米面展宽
complex(dp),parameter::im = (0.,1.) !Imagine unit
real(dp),allocatable::ones_ham(:,:) ! 为了后续考虑化学势
complex(dp),allocatable::HmnR(:,:,:) ! hr中的hopping
integer,allocatable::irvec(:,:) ! hr中的位置矢量
integer,allocatable::indorbit(:,:,:,:)
real(dp),allocatable::BZklist(:,:)
real(dp),allocatable::FS_points(:,:)
integer FS_index(-kn:kn - 1,-kn:kn - 1)
!------------------------------------------
integer,allocatable::FSindex(:,:) ! 费米点索引指标
end module
!==============================================================================================================================================================
program main
use param
use mpi
implicit none
integer numcore,indcore,ierr
!-------------------------------------------------
real(dp) code_time_start,code_time_end,code_time
integer nki,nkf
character(len = 20)::filename,char1,char2,char3,char4
!-------------------------------------------------------------------
call MPI_INIT(ierr) ! 初始化进程
call MPI_COMM_RANK(MPI_COMM_WORLD, indcore, ierr) ! 得到本进程在通信空间中的rank值,即在组中的逻辑编号(该indcore为0到numcore-1间的整数,相当于进程的ID。)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numcore, ierr) !获得进程数量,用numcoer保存
! 循环分拆
nki = floor(indcore * (2.0 * kn)/numcore) - kn
nkf = floor((indcore + 1) * (2.0 * kn)/numcore) - kn - 1
if(indcore.eq.0)then
call CPU_TIME(code_time_start)
write(*,*)"Start calcation: ",code_time_start
write(*,*)"Number of CPU = ",numcore
write(*,*)"Number of nk = ",2 * kn
end if
! 输出程序的基本参数信息
if(indcore.eq.0)then
write(*,*)"Number of Fermi points = ",numk_FS
write(*,*)"Number of BZ points = ",numk_bz

call squareBZ()
call read_hr()
call fermisurface() ! 确定体系的费米面,其中会给出所有费米点的位置

call CPU_TIME(code_time_end)
write(*,*)"Calcation finished",code_time_end
write(*,*)"Code execution time:",abs(code_time_end - code_time_start),"second"
end if
call MPI_Finalize(ierr)
stop
end program main
!================================================================================================================================================================================================
subroutine fermisurface()
use param
integer ibz,ie,ikx,iky
real(dp) kx,ky,mateigval(num_wann)
complex(dp) Ham_temp(num_wann,num_wann),matvec(num_wann,num_wann)
! call honeycomyBZ()
open(13,file = "FS.dat")
! numk_FS = 0 ! 全局变量,共计费米点的数量
do ibz = 1,numk_bz
kx = BZklist(1,ibz)
ky = BZklist(2,ibz)
call HamR_to_K(kx,ky,0.0,Ham_temp)
call diagonalize_Hermitian_matrix(num_wann,Ham_temp,matvec,mateigval)
do ie = 1,num_wann
if (abs(mateigval(ie)) < deltaE)then
write(13,"(3F12.6)")kx,ky,1.0
numk_FS = numk_FS + 1 ! 统计费米点的数量
end if
end do
end do
close(13)
!--------------------------------------------------------------
!确定费米面点的数量后就可以确定相互作用矩阵的维度
if(numk_FS.eq.0)then
write(*,*)"The Number of Fermi surface points = ",numk_FS
write(*,*)"----------------------------------------------"
write(*,*)" Warnning "
write(*,*)"----------------------------------------------"
stop
else
allocate(FS_points(2,numk_FS))
FS_points = 0.0
end if
!-----------------------------------------------
! 根据动量坐标记录这是第几个费米点
numk_FS = 0
do iky = -kn,kn - 1
ky = 2.0 * pi * iky/kn
do ikx = -kn,kn - 1
kx = 2.0 * pi * ikx/kn
call HamR_to_K(kx,ky,0.0,Ham_temp)
call diagonalize_Hermitian_matrix(num_wann,Ham_temp,matvec,mateigval)
do ie = 1,num_wann
if (abs(mateigval(ie)) < deltaE)then
numk_FS = numk_FS + 1
FS_index(ikx,iky) = numk_FS
FS_points(1,numk_FS) = kx
FS_points(2,numk_FS) = ky
end if
end do
end do
end do
return
end subroutine

!================================================================================================================================================================================================
subroutine squareBZ()
use param
integer ikx,iky,i0
! 对于四方点阵,BZ的点数可以直接确定
numk_bz = (2 * kn)**2
allocate(BZklist(2,numk_bz))
i0 = 0
do ikx = -kn,kn - 1
do iky = -kn,kn - 1
i0 = i0 + 1
BZklist(1,i0) = 2.0 * pi * ikx/kn
BZklist(2,i0) = 2.0 * pi * iky/kn
end do
end do
return
end subroutine
!==============================================================================================================================================================
subroutine HamR_to_K(kx,ky,kz,Ham_temp)
! 将hr变成动量空间
use param
implicit none
real(dp) kx,ky,kz
integer i1,i2,i3,w1,w2,r1,r2,r3
complex(dp) Ham_temp(num_wann,num_wann)

ones_ham = 0.0 ! 对于具有allocatable属性的变量,一定要先赋值为零
! 设置单位矩阵
do i1 = 1,num_wann
ones_ham(i1,i1) = 1.0
end do


Ham_temp = 0.0
do i1 = 1,nrpts
do i2 = 1,num_wann
do i3 = 1,num_wann
r1 = irvec(1,i1)
r2 = irvec(2,i1)
r3 = irvec(3,i1)
w1 = indorbit(1,i1,i2,i3)
w2 = indorbit(2,i1,i2,i3)
Ham_temp(w1,w2) = Ham_temp(w1,w2) + (cos(kx * r1 + ky * r2 + kz * r3) + im * sin(kx * r1 + ky * r2 + kz * r3)) * HmnR(w1,w2,i1)
end do
end do
end do
Ham_temp = Ham_temp - mu * ones_ham ! 在Wannier90_hr的基础上考虑体系的化学势
end subroutine
!==============================================================================================================================================================
subroutine read_hr()
! 读取DFT的hr数据,并返回Hr以及
use param
implicit none
integer :: i,j,k
integer :: r1,r2,r3,w1,w2
real(dp) :: hr,hi
real(dp),allocatable::ndegen(:)
logical stat

inquire(file = 'wannier90_hr.dat', exist = stat)
if(stat)then
open(12,file = 'wannier90_hr.dat',action = 'read')
read(12,*)
read(12,*) num_wann ! 轨道数量,也决定了动量空间哈密顿量维度,这是一个全局变量
! read(12,*)r1
read(12,*) nrpts

allocate(ndegen(nrpts))
! 全局变量
allocate(HmnR(num_wann,num_wann,nrpts),irvec(3,nrpts))
allocate(indorbit(2,nrpts,num_wann,num_wann))
read(12,*) (ndegen(i),i = 1,nrpts)

do i = 1,nrpts
do j = 1,num_wann
do k = 1,num_wann
read(12,*) r1,r2,r3,w1,w2,hr,hi
irvec(1,i) = r1
irvec(2,i) = r2
irvec(3,i) = r3
indorbit(1,i,j,k) = w1 ! 哈密顿量中的轨道索引,后续构建动量空间哈密顿量使用
indorbit(2,i,j,k) = w2
HmnR(w1,w2,i) = hr + im * hi
enddo
end do
end do
close(12)
allocate(ones_ham(num_wann,num_wann))
else
write(*,*)"**************** Error *********************"
write(*,*)"Tight-binding dat is not exist"
write(*,*)"**************** Error *********************"
end if
return
end subroutine read_hr
!==============================================================================================================================================================
function delta(x)
!> Lorentz or gaussian expansion of the Delta function
use param, only : dp, pi
implicit none
! real(dp), intent(in) :: eta
real(dp), intent(in) :: x
real(dp) :: delta, y
real(dp) :: eta = 0.001

!> Lorentz expansion
!delta= 1d0/pi*eta/(eta*eta+x*x)

y= x*x/eta/eta/2d0

!> Gaussian broadening
!> exp(-60) = 8.75651076269652e-27
if (y>60d0) then
delta = 0d0
else
delta= exp(-y)/sqrt(2d0*pi)/eta
endif

return
end function delta
!==============================================================================================================================================================
subroutine diagonalize_complex_matrix(matdim,matin,matout,mateigval)
! 对角化一般复数矩阵,这里的本征值是个复数
! matin 输入矩阵 matout 本征矢量 mateigval 本征值
implicit none
integer,parameter::dp = kind(1.0)
integer matdim,LDA,LDVL,LDVR,LWMAX,INFO,LWORK
complex(dp),intent(in)::matin(matdim,matdim)
complex(dp),intent(out)::matout(matdim,matdim)
complex(dp),intent(out)::mateigval(matdim)
real(dp),allocatable::RWORK(:)
complex(dp),allocatable::WORK(:)
complex(dp),allocatable::VL(:,:)
complex(dp),allocatable::VR(:,:)
LDA = matdim
LDVL = matdim
LDVR = matdim
LWMAX = 2 * matdim + matdim**2
! write(*,*)matin
allocate(RWORK(2 * matdim))
allocate(VL(LDVL,matdim))
allocate(VR(LDVR, matdim))
allocate(WORK(LWMAX))
matout = matin

LWORK = -1
call cgeev( 'V', 'N', matdim, matout, LDA, mateigval, VL, LDVL,VR, LDVR, WORK, LWORK, RWORK, INFO)
LWORK = MIN( LWMAX, INT( WORK( 1 ) ) )
call cgeev( 'V', 'N', matdim, matout, LDA, mateigval, VL, LDVL,VR, LDVR, WORK, LWORK, RWORK, INFO )
IF( INFO.GT.0 ) THEN
WRITE(*,*)'The algorithm failed to compute eigenvalues.'
! STOP
END IF
end subroutine diagonalize_complex_matrix
!================================================================================================================================================================================================
subroutine Matrix_Inv(matdim,matin,matout)
! 矩阵求逆
implicit none
integer,parameter::dp = kind(1.0)
integer matdim,info
complex(dp),intent(in) :: matin(matdim,matdim)
complex(dp):: matout(size(matin,1),size(matin,2))
real(dp):: work2(size(matin,1)) ! work2 array for LAPACK
integer::ipiv(size(matin,1)) ! pivot indices
! Store matin in matout to prevent it from being overwritten by LAPACK
matout = matin
! SGETRF computes an LU factorization of a general M - by - N matrix A
! using partial pivoting with row interchanges .
call CGETRF(matdim,matdim,matout,matdim,ipiv,info)
! if (info.ne.0) stop 'Matrix is numerically singular!'
if (info.ne.0) write(*,*)'Matrix is numerically singular!'
! SGETRI computes the inverse of a matrix using the LU factorization
! computed by SGETRF.
call CGETRI(matdim,matout,matdim,ipiv,work2,matdim,info)
! if (info.ne.0) stop 'Matrix inversion failed!'
if (info.ne.0) write(*,*)'Matrix inversion failed!'
return
end subroutine Matrix_Inv
!================================================================================================================================================================================================
subroutine diagonalize_Hermitian_matrix(matdim,matin,matout,mateigval)
! 厄米矩阵对角化
! matin 输入矩阵 matout 本征矢量 mateigval 本征值
implicit none
integer,parameter::dp = kind(1.0)
integer matdim
integer lda0,lwmax0,lwork,lrwork,liwork,info
complex(dp) matin(matdim,matdim),matout(matdim,matdim)
real(dp) mateigval(matdim)
complex(dp),allocatable::work(:)
real(dp),allocatable::rwork(:)
integer,allocatable::iwork(:)
!-----------------
lda0 = matdim
lwmax0 = 2 * matdim + matdim**2
allocate(work(lwmax0))
allocate(rwork(1 + 5 * matdim + 2 * matdim**2))
allocate(iwork(3 + 5 * matdim))
matout = matin
lwork = -1
liwork = -1
lrwork = -1
call cheevd('V','U',matdim,matout,lda0,mateigval,work,lwork ,rwork,lrwork,iwork,liwork,info)
lwork = min(2 * matdim + matdim**2, int( work( 1 ) ) )
lrwork = min(1 + 5 * matdim + 2 * matdim**2, int( rwork( 1 ) ) )
liwork = min(3 + 5 * matdim, iwork( 1 ) )
call cheevd('V','U',matdim,matout,lda0,mateigval,work,lwork,rwork,lrwork,iwork,liwork,info)
if( info .GT. 0 ) then
open(11,file = "mes.dat",status = "unknown")
write(11,*)'The algorithm failed to compute eigenvalues.'
close(11)
end if
return
end subroutine diagonalize_Hermitian_matrix

绘图程序

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
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
import matplotlib.cm as cm
import os
import re
plt.rc('font', family='Times New Roman')
config = {
"font.size": 30,
"mathtext.fontset":'stix',
"font.serif": ['SimSun'],
}
rcParams.update(config) # Latex 字体设置
#----------------------------------------------------------------------------
def WannierDETband():
path = os.path.abspath('.')
band_file = os.path.join(path,'BAND.dat')
knode_file = os.path.join(path,'KLABELS')
fermi_file = os.path.join(path,'FERMI_ENERGY')
plt.figure(figsize = (10,8))

#******************** DFT band ************************************************************
band_data = np.loadtxt(band_file)
plt.plot(band_data[:,0],band_data[:,1:],color = 'b',linewidth = 2.0,label = "DFT")
xmin = np.min(band_data[:,0])
xmax = np.max(band_data[:,0])
ymin = np.min(band_data[:,1:])
ymax = np.max(band_data[:,1:])
plt.xlim(xmin,xmax)
# plt.ylim(ymin,ymax)
plt.ylim(-6,6)

with open(knode_file,"r",encoding = "utf-8") as f:
lines = f.readlines()
lines = lines[1:-3]
knodes = []
for i in range(len(lines)):
knodes.append(str.split(lines[i]))
knodes[i][1] = float(knodes[i][1])
plt.axvline(x = knodes[i][1],linewidth = 1.5,color = 'silver')
plt.axhline(y = 0,linewidth = 2.0,color = 'b',ls = "-.")
knodes = list(map(list, zip(*knodes)))
plt.xticks(knodes[1],list(knodes[0]),fontproperties='Times New Roman')


#******************** Wannier band ********************
wannier_bandfile = os.path.join(path,'wannier90_band.dat')
wannier_kptfile = os.path.join(path,'wannier90_band.kpt')
wannier_labkptfile = os.path.join(path,'wannier90_band.labelinfo.dat')
fermi_file = os.path.join(path,'FERMI_ENERGY')
wannier_print = True
if os.path.exists(wannier_bandfile) is True and wannier_print is True:
wann_k = open(wannier_kptfile,"r",encoding = "utf-8")
wann_l = open(wannier_labkptfile,"r",encoding = "utf-8")
n_k = np.array(int(wann_k.readlines()[0]))
lab = np.array(re.findall('[A-Z]*[A-Z]',wann_l.read()))
fermi_energy = np.loadtxt(fermi_file)
wann_k.close()
wann_l.close()
wb = np.loadtxt(wannier_bandfile)
wj = int(len(wb)/n_k)
for j in range(wj):
if j == wj - 2:
plt.plot(wb[:,0][j*n_k:j*n_k+n_k],wb[:,1][j*n_k:j*n_k+n_k] - fermi_energy,color = 'r',ls = '--',linewidth = 2.0,label = "Wannier")
else:
plt.plot(wb[:,0][j*n_k:j*n_k+n_k],wb[:,1][j*n_k:j*n_k+n_k] - fermi_energy,color = 'r',ls = '--',linewidth = 2.0)
plt.legend(loc='upper right', shadow = True, fancybox = True)
#********************************************************************************
plt.tick_params(axis='x',width = 0,length = 10)
plt.tick_params(axis='y',width = 0,length = 10)
ax = plt.gca()
ax.spines["bottom"].set_linewidth(1.5)
ax.spines["left"].set_linewidth(1.5)
ax.spines["right"].set_linewidth(1.5)
ax.spines["top"].set_linewidth(1.5)
# plt.show()
plt.savefig("bandstructure.png",dpi = 300,bbox_inches = 'tight',transparent=True)
#-----------------------------------------------------------------------------------------------------
def plotfs(mu,numk):
# 费米面以及极化率绘制
dataname = "fermi-mu-" + str(mu) + "-numk-" + str(numk) + ".dat"
dataname = "FS.dat"
# dataname = "Honeycomb-fermi-mu-" + str(mu) + ".dat"
# dataname = "Square-fermi-mu-" + str(mu) + ".dat"
# dataname = "fermi-mu-" + str(mu) + ".dat"
# dataname = "Honeycomb-fermivs-" + str(mu) + ".dat"
# dataname = "maxvals-chi0-" + str(numk) + ".dat"
# picname = os.path.splitext(dataname)[0] + "-" + str(num) + ".png"
picname = os.path.splitext(dataname)[0] + ".png"
da = np.loadtxt(dataname)
plt.figure(figsize = (10,8))
sc = plt.scatter(da[:,0],da[:,1], s = 1, c = da[:,2],cmap = "jet")
#-------------------------------------------------
r0 = 5
hex = [np.sqrt(3)/2 * r0,np.sqrt(3)/4 * r0,-np.sqrt(3)/4 * r0,-np.sqrt(3)/2 * r0,-np.sqrt(3)/4 * r0,np.sqrt(3)/4 * r0,np.sqrt(3)/2 * r0]
hey = [0 * r0 ,3/4 * r0 ,3/4 * r0 ,0 * r0 ,-3/4 * r0 ,-3/4 * r0 ,0 * r0]
plt.plot(hex,hey,c = "black",lw = 2,ls = "--")
#-------------------------------------------------
cb = plt.colorbar(sc,fraction = 0.1,ticks = [np.min(da[:,2]),np.max(da[:,2])]) # 调整colorbar的大小和图之间的间距
# cb.ax.set_yticklabels([r'$d_{3z^2-r^2}$', r'$d_{x^2-y^2}$'])
xtic = [-2 * np.pi,0,2 * np.pi]
xticlab = ["$-2\pi$","$0$","$2\pi$"]
plt.xticks(xtic,list(xticlab),fontproperties='Times New Roman', size = 40)
plt.yticks(xtic,list(xticlab),fontproperties='Times New Roman', size = 40)
xmin = np.min(da[:,0])
xmax = np.max(da[:,0])
ymin = np.min(da[:,1])
ymax = np.max(da[:,1])
# plt.xlim(xmin,xmax)
# plt.ylim(ymin,ymax)
plt.xlim(-2 * np.pi,2 * np.pi)
plt.ylim(-2 * np.pi,2 * np.pi)
plt.tick_params(axis='x',width = 0,length = 10)
plt.tick_params(axis='y',width = 0,length = 10)
ax = plt.gca()
ax.spines["bottom"].set_linewidth(1.5)
ax.spines["left"].set_linewidth(1.5)
ax.spines["right"].set_linewidth(1.5)
ax.spines["top"].set_linewidth(1.5)
# plt.show()
plt.savefig(picname, dpi = 300,bbox_inches = 'tight',transparent=True)
plt.close()

#-----------------------------------------------------------------------------------------------------
# WannierDETband()
numk = 100
mu = -2.15
plotfs(format(mu,".2f"),format(numk,".2f"))

png

上面的所有文件可以点击这里下载

公众号

相关内容均会在公众号进行同步,若对该Blog感兴趣,欢迎关注微信公众号。
{:.info}

QR Code

Email

yxliphy@gmail.com