以下内容全部参考EPW: Superconducting gap on the Fermi surface (需要梯子)
首先需要算出费米面,官方提供了两个脚本,一个是用来画出三维的费米面,一个是后处理费米面上每个点对应的gap。原版是python2的,可以在这里找到Fermi,我平时用python3,所以就转换了一下贴在下面
fermi_surf.py
#
# Script developed by H. Lambert and S. Ponce [2016]
#
import sys
import re
import numpy as np
def parse_args(args):
extra = []
vars = []
current_var = None
for arg in args:
if arg.startswith('--'):
current_var = arg[2:]
else:
if current_var is not None:
vars.append((current_var, arg))
current_var = None
else:
extra.append(arg)
return (extra, vars)
def split_vars(vars):
vars_values = []
for var_name, values in vars:
values = values.split(",")
try:
if any(['.' in value for value in values]):
values = list(map(float, values))
else:
values = list(map(int, values))
except ValueError:
pass
vars_values.append((var_name, values))
vars_dict = dict(vars_values)
return vars_dict
#f is a string with the contents of the file
class FermiSurface(object):
def __init__(self):
self.nx = 60
self.ny = 60
self.nz = 60
self.dimvec = np.array([float(self.nx), float(self.ny), float(self.nz)])
self.fermixyz = {}
self.gap = {}
self.prefix = 'MgB2'
self.nbndmin = 2
self.nbndmax = 4
def __repr__(self):
return 'Fermi Surface/Mu Tensor Object'
def cryst_to_cart(self, kvec):
#MgB2 crystal axes
at1 = np.array([ 1.000000, 0.000000, 0.000000])
at2 = np.array([-0.500000, 0.866025, 0.000000])
at3 = np.array([ 0.000000, 0.000000, 1.142069])
at = np.array([at1, at2, at3])
outvec = np.dot(at, kvec)
return outvec
def pull_fermi(self,f):
fermi_regex = re.compile(r'k\s=\s?(\-?[0-9\.]+)\s?(\-?[0-9\.]+)\s?(\-?[0-9\.]+).*?:\n\n\s+([0-9\.\-\s]+)')
print(len(fermi_regex.findall(f)))
for a, b, c, d in fermi_regex.findall(f):
a = float(a)
b = float(b)
c = float(c)
kvec = np.array([a,b,c])
d = list(map(float, d.split()))
kvec = self.cryst_to_cart(kvec)
#Fold into first brillouin zone:
for i, a in enumerate(kvec):
if (a< -0.001): kvec[i] = kvec[i] + 1.0
index = [round(a) for a in np.multiply(kvec, self.dimvec)]
# Rescale the energy so that the Fermi level = 0
d[:] = [x - 7.4272 for x in d]
for i, a in enumerate(index):
if index[i] == 61.0:
index[i] = 0.0
print(index)
self.fermixyz[tuple(index)] = d
#returns dictionary keys:xyz coordinates, values:eigenvalues.
def print_xsf(self, surf, title='band', band1=2, band2=3, band3=4):
for ibnd in range(band1, band3+1):
f1 = open('{0}.band{1}.xsf'.format(self.prefix, ibnd), 'w')
print("BEGIN_BLOCK_DATAGRID_3D", file=f1)
print("{0}_band_{1}".format(self.prefix, ibnd), file=f1)
print(" BEGIN_DATAGRID_3D_{0}".format(self.prefix), file=f1)
print(" {0} {1} {2} ".format(self.nx, self.ny, self.nz), file=f1)
print("0.000000 0.000000 0.000000", file=f1)
#MgB2:
print("1.000000 0.577350 0.000000", file=f1)
print("0.000000 1.154701 0.000000", file=f1)
print("0.000000 0.000000 0.875604", file=f1)
print("", file=f1)
total = 0
for z in range(self.nz):
for y in range(self.ny):
for x in range(self.nx):
try:
print(surf[x,y,z][ibnd], " ", end=' ', file=f1)
#print>>f1, "0.05", " ",
total = total+ 1
except TypeError:
print(surf[x,y,z], " ", end=' ', file=f1)
print('Missing key')
print("0.0", " ", end=' ', file=f1)
except KeyError:
print('Missing key')
print("0.0", " ", end=' ', file=f1)
print("", file=f1)
print("", file=f1)
print("END_DATAGRID_3D", file=f1)
print("END_BLOCK_DATAGRID_3D", file=f1)
f1.close()
print('Total number of data ',total)
if __name__=="__main__":
# run as:
# python --fs y ./nscf.out to parse band file and make fermiplot
# else run as:
# python --gap y name to parse gap plot.
extra, vars = parse_args(sys.argv[1:])
vars_values = []
vars = split_vars(vars)
print(vars, extra)
f = open(extra[0]).read()
fs = FermiSurface()
if 'fs' in list(vars.keys()):
fs.pull_fermi(f)
fs.print_xsf(fs.fermixyz, band1=2, band2=3, band3=4)
fermi_gap.py
#
# Script developed by H. Lambert and S. Ponce [2016]
#
import sys
import re
import numpy as np
def parse_args(args):
extra = []
vars = []
current_var = None
for arg in args:
if arg.startswith('--'):
current_var = arg[2:]
else:
if current_var is not None:
vars.append((current_var, arg))
current_var = None
else:
extra.append(arg)
return (extra, vars)
def split_vars(vars):
vars_values = []
for var_name, values in vars:
values = values.split(",")
try:
if any(['.' in value for value in values]):
values = list(map(float, values))
else:
values = list(map(int, values))
except ValueError:
pass
vars_values.append((var_name, values))
vars_dict = dict(vars_values)
return vars_dict
#f is a string with the contents of the file
class FermiSurface(object):
def __init__(self):
self.nx = 60
self.ny = 60
self.nz = 60
self.dimvec = np.array([float(self.nx), float(self.ny), float(self.nz)])
self.fermixyz = {}
self.gap = {}
self.prefix = 'MgB2'
self.nbndmin = 2
self.nbndmax = 4
def __repr__(self):
return 'Fermi Surface/Mu Tensor Object'
def cryst_to_cart(self, kvec):
#MgB2 crystal axes
at1 = np.array([ 1.000000, 0.000000, 0.000000])
at2 = np.array([-0.500000, 0.866025, 0.000000])
at3 = np.array([ 0.000000, 0.000000, 1.142069])
at = np.array([at1, at2, at3])
outvec = np.dot( kvec,at)
return outvec
def cart_to_cryst(self, kvec):
#crystal to cart BG MgB2
at1 = np.array([ 1.000000, -0.500000, 0.000000])
at2 = np.array([ 0.000000, 0.866025, 0.000000])
at3 = np.array([ 0.000000, 0.000000, 1.142069])
at = np.array([at1, at2, at3])
outvec = np.dot(kvec,at)
return outvec
def pull_fermi(self,f):
fermi_regex = re.compile(r'k\s=\s?(\-?[0-9\.]+)\s?(\-?[0-9\.]+)\s?(\-?[0-9\.]+).*?:\n\n\s+([0-9\.\-\s]+)')
print(len(fermi_regex.findall(f)))
for a, b, c, d in fermi_regex.findall(f):
a = float(a)
b = float(b)
c = float(c)
kvec = np.array([a,b,c])
d = list(map(float, d.split()))
kvec = self.cryst_to_cart(kvec)
#Fold into first brillouin zone:
for i, a in enumerate(kvec):
if (a< -0.001): kvec[i] = kvec[i] + 1.0
index = [round(a) for a in np.multiply(kvec, self.dimvec)]
# Rescale the energy so that the Fermi level = 0
d[:] = [x - 7.4272 for x in d]
for i, a in enumerate(index):
if index[i] == 61.0:
index[i] = 0.0
print(index)
self.fermixyz[tuple(index)] = d
def pull_fermi_xy(self,f):
fermi_regex = re.compile(r'k\s=\s?(\-?[0-9\.]+)\s?(\-?[0-9\.]+)\s?(\-?[0-9\.]+).*?:\n\n\s+([0-9\.\-\s]+)')
print(len(fermi_regex.findall(f)))
for a, b, c, d in fermi_regex.findall(f):
a = float(a)
b = float(b)
c = float(c)
kvec = np.array([a,b,c])
d = list(map(float, d.split()))
# Turn kpoint coordinates into integer indices
# and fold back into the first Brillouin zone.
kvec = self.cryst_to_cart(kvec)
# Fold into first Brillouin zone:
for i, a in enumerate(kvec):
if (a<0.0): kvec[i] = kvec[i] + 1.0
index = [round(a) for a in np.multiply(kvec, self.dimvec)]
for i, a in enumerate(index):
if index[i] == 61.0:
index[i] = 0.0
#returns dictionary keys:xyz coordinates, values:eigenvalues.
def print_xsf(self, surf, title='band', band1=1):
for ibnd in range(band1):
f1 = open('{0}.col.band{1}.xsf'.format(self.prefix, ibnd), 'w')
print("BEGIN_BLOCK_DATAGRID_3D", file=f1)
print("{0}_band_{1}".format(self.prefix, ibnd), file=f1)
print(" BEGIN_DATAGRID_3D_{0}".format(self.prefix), file=f1)
print(" {0} {1} {2} ".format(self.nx, self.ny, self.nz), file=f1)
print("0.000000 0.000000 0.000000", file=f1)
#MgB2:
print("1.000000 0.577350 0.000000", file=f1)
print("0.000000 1.154701 0.000000", file=f1)
print("0.000000 0.000000 0.875604", file=f1)
print("", file=f1)
total = 0
for z in range(self.nz):
for y in range(self.ny):
for x in range(self.nx):
try:
print(surf[x,y,z], " ", end=' ', file=f1)
#print>>f1, "0.05", " ",
total = total+ 1
except TypeError:
print(surf[x,y,z], " ", end=' ', file=f1)
print('Missing key')
print("0.0", " ", end=' ', file=f1)
except KeyError:
print('Missing key')
print("0.0", " ", end=' ', file=f1)
print("", file=f1)
print("", file=f1)
print("END_DATAGRID_3D", file=f1)
print("END_BLOCK_DATAGRID_3D", file=f1)
f1.close()
print('Total number of data ',total)
def pull_muk(self, f):
total = 0
for line in f.split('\n'):
try:
a,b,c,d,e,f = list(map(float, line.split()))
# Do one band d manually
if d == 2:
kvec = np.array([a,b,c])
kvec = self.cart_to_cryst(kvec)
index = [round(ii) for ii in np.multiply(kvec, self.dimvec)]
print(index)
self.gap[tuple(index)] = f
total += 1
except:
print("Couldn't read the following line:")
print(line)
print('Total number of lines extracted ',total)
if __name__=="__main__":
# run as:
# python --fs y ./nscf.out to parse band file and make fermiplot
# else run as:
# python --gap y name to parse gap plot.
extra, vars = parse_args(sys.argv[1:])
vars_values = []
vars = split_vars(vars)
print(vars, extra)
f = open(extra[0]).read()
fs = FermiSurface()
if 'fs' in list(vars.keys()):
fs.pull_fermi(f)
fs.print_xsf(fs.fermixyz, band1=2, band2=3, band3=4)
if 'gap' in list(vars.keys()):
fs.pull_muk(f)
fs.print_xsf(fs.gap, 'gap')
然后第一步是算出费米面,通过nscf
计算得到
srun --mpi=pmi2 $EXE/pw.x <nscf.in> nscf.out
nscf输入文件如下,有两个点需要注意,首先nosym
,noinv
需要打开,要不然画出来费米面是约化之后的,只有一部分费米面。第二点是需要设置QE的Modules/parameters.f90
中改一下npk
,改的大一些,比你要算费米面用到的k点个数大,否则会报错,改完之后重新编译pw
,nscf.in的输入文件我贴在这里
&control
calculation='nscf',
prefix='MgB2',
pseudo_dir = '../../pp/',
outdir='./',
tprnfor = .true.,
tstress = .true.,
etot_conv_thr = 1.0d-5
forc_conv_thr = 1.0d-4
verbosity = 'high'
disk_io = 'none'
/
&system
ibrav = 4,
celldm(1) = 5.8260252227888,
celldm(3) = 1.1420694129095,
nat= 3,
ntyp = 2,
ecutwfc = 40
smearing = 'mp'
occupations = 'smearing'
degauss = 0.02
nosym = .t.
noinv = .t.
/
&electrons
diagonalization = 'david'
mixing_mode = 'plain'
mixing_beta = 0.7
conv_thr = 1.0d-9
/
ATOMIC_SPECIES
Mg 24.305 Mg.pz-n-vbc.UPF
B 10.811 B.pz-vbc.UPF
ATOMIC_POSITIONS crystal
Mg 0.000000000 0.000000000 0.000000000
B 0.333333333 0.666666667 0.500000000
B 0.666666667 0.333333333 0.500000000
K_POINTS AUTOMATIC
60 60 60 0 0 0
这时会输出一个很大的nscf.out文件,然后用python脚本处理
python fermi_surf.py --fs -y nsfcf.out
会产生几个费米面的文件
MgB2.band2.xsf
,MgB2.band3.xsf
,MgB2.band4.xsf
然后用VESTA画出来就行了。
直接把MgB2.band2.xsf
拖进VESTA,另外两个import进去,Eidt
-Edit data
-volumetric data
在上面的isosurface import进去就得到费米面了。Operation选Multiply to current data,其余默认
再做两个调整
1、Properties
-Isosurface
里面isosurface level
改成0,
2、Properties
-Sections
中Opacity of isosurfaces' sections
改成0
然后第二步,后处理超导能隙。信息是从EPW计算的MgB2.imag_aniso_gap_FS_XX.00
文件中提取,XX对应你计算的时候选定的温度,注意自己修改。
命令是
python fermi_gap.py --gap -y MgB2.imag_aniso_gap_FS_XX.00
然后会生成MgB2.col.band0.xsf
文件,就是对应的gap的信息,先随便改成另一个文件名,然后更改fermi_gap.py
中的第160行,if d == 2:
改成if d == 1:
,再执行一遍,生成另一个费米面上的gap(MgB2是双带超导,所以这里有两个)生成两条带上的gap以后,同样的方法导入到VESTA中,Eidt
-Edit data
-volumetric data
,这一次是导入到下面那个Surface Coloring中。Operation直接选默认。然后就得到费米面上的gap图了。
这里做个演示计算量限制,选取的k点网格是20x20x20,所以跟官网上不太一样,用60x60x60计算得到的gap就能和官网上类似了。