怎么画EPW计算里面3维的gap

以下内容全部参考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.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-SectionsOpacity of isosurfaces' sections改成0

MgB2.band.png

然后第二步,后处理超导能隙。信息是从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图了。

MgB2.band_gap.png

这里做个演示计算量限制,选取的k点网格是20x20x20,所以跟官网上不太一样,用60x60x60计算得到的gap就能和官网上类似了。

你可能感兴趣的:(怎么画EPW计算里面3维的gap)