|
|
这个python3代码(cube_average_z.py)我随便写写作为一个测试:
- #本程序只能用在正交晶格。
- #非正交晶格理论上可以通过修改本程序实现。
- import numpy as np
- import sys
- def average_cube_z(fname):
- f=open(fname,'r+')
- text=f.read()
- f.close()
- #cube文件按行进行切割。
- text=text.split('\n')
- #第3~6行为网格的轴向上的格点数和间距,两者对应相乘可以得到对应的晶格参数。
- lat_info=np.array([t.split() for t in text[3:6]])
- ngrids=np.array(lat_info[:,0],dtype=int)
- intv=np.array(lat_info[:,1:],dtype=float)
- lat=ngrids*intv
- #第2行为原子数和原点坐标信息,我们只取原子数的信息即可。
- natms=int(text[2].split()[0])
- #第6行起,后续有与原子数相等的行数为原子和原子坐标信息,这里我们不需要跳过去。
- grids=' '.join(text[6+natms:])
- #将数组的形状按照给定的网格尺寸重新排,注意cube格式变化最快的方向是z方向。
- grids=np.array(grids.split(),dtype=float)
- grids=grids.reshape(ngrids)
- #如果要更改为x为最快变化方向可以使用:
- #grids=np.transpose(grids,(2,1,0))
- #这里没必要这么处理。
- #---------------------------------------
- #求某个特定的z下静电势网格在xy面上的平均。
- #这么做可行的原因是,网格为矩形且均匀的情况下,利用矩形积分的公式:
- #∫∫ρ(x,y,z)dxdy/∫∫dxdy=(∑∑ρ_xyz)/n_x/n_y。
- #当然也可以用精度更高的积分方法或用FFT,这里只是定性说明。
- average=np.mean(grids,axis=(0,1))
- #产生Bohr单位下z的坐标网格。
- z=np.linspace(0,np.linalg.norm(lat[2]),ngrids[2],endpoint=False)
- #将数据按照z V_H的格式打印。
- head='%25s %25s\n'%('z','V_H')
- text='\n'.join(['% 16.8f % 16.8f'%(i,a) for i,a in zip(z,average)])
- text=head+text
- return text
- text=average_cube_z(sys.argv[1])
- print(text)
复制代码 执行的方法是:
- python cube_average_z.py Cu_111-v_hartree-1_0.cube > potentials.dat
复制代码 如果对平均静电势取最大得到的结果是:Vh=0.10814 Hartree,
然后按照你前面给的数据:Ef=0.3029-0.3829=-0.08 Hartree,
然后按照eV单位计算功函数:(Vh-Ef)*27.211=5.11947754 eV
其他的说明在代码块部分说的应该也比较明确了,和官网给的程序结果的差异大概率来源于积分的方法,我这边用的是粗糙的矩形积分方法。可以用更高级别的基于插值的数值积分,也可以用FFT,原则上经过修改可以有更高的精度并可用于γ角非90°的单斜结构。至于之前为啥做不对,我也不知道你具体的处理步骤。
|
|