├── README.md └── rdf.py /README.md: -------------------------------------------------------------------------------- 1 | # Radial Distribution Function 2 | Radial Distribution Function(rdf) 镜像分布函数计算 3 | 4 | 5 | ## 参考 6 | [[VMD] 径向分布函数求配位数的问题求助@sobereva](http://bbs.keinsci.com/thread-15102-1-1.html)
7 | [9041 周期性 RDF 计算程序 CryRDF](https://zhuanlan.zhihu.com/p/178610319)
8 | 9 | ## 程序内容解释 10 | [镜像分布函数rdf计算方法和程序](https://cndaqiang.github.io//2020/11/29/rdf/) 11 | 12 | ## 环境 13 | - python3 14 | - Module: numpy, matplotlib 15 | 16 | 使用示例 17 | - 查看帮助 18 | ``` 19 | (python37) cndaqiang@mac Desktop$ ./rdf.py 20 | Usage: ./rdf.py [ xxx.xyz | xxx.vasp ] [ none | a | a b c] 21 | ``` 22 | - 计算晶格常数为30Ang的立方晶胞的rdf 23 | ``` 24 | (python37) cndaqiang@mac Desktop$ ./rdf.py 303030.xyz 30 25 | read from 303030.xyz 26 | XYZ: set cell to 27 | a: [30. 0. 0.] 28 | b: [ 0. 30. 0.] 29 | c: [ 0. 0. 30.] 30 | nstep,ntyp,nat 1 ['O' 'H'] [ 884 1768] 31 | Super cell [1. 1. 1.] 32 | ['O-O' 'O-H' 'H-H'] 33 | Save rdf to 303030.xyz.O-O.averagerdf.dat 34 | Save rdf to 303030.xyz.O-H.averagerdf.dat 35 | Save rdf to 303030.xyz.H-H.averagerdf.dat 36 | Save png to 303030.xyz.averagerdf.png 37 | ``` 38 | - 计算晶格常数`a=3.967 b=8.121 c=8.320`的长方型原胞rdf 39 | ``` 40 | (python37) cndaqiang@mac Desktop$ ./rdf.py 123.xyz 3.967 8.121 8.320 41 | read from 123.xyz 42 | XYZ: set cell to 43 | a: [3.967 0. 0. ] 44 | b: [0. 8.121 0. ] 45 | c: [0. 0. 8.32] 46 | nstep,ntyp,nat 1 ['O' 'H'] [12 24] 47 | Super cell [3. 1. 1.] 48 | ['O-O' 'O-H' 'H-H'] 49 | Save rdf to 123.xyz.O-O.averagerdf.dat 50 | Save rdf to 123.xyz.O-H.averagerdf.dat 51 | Save rdf to 123.xyz.H-H.averagerdf.dat 52 | Save png to 123.xyz.averagerdf.png 53 | ``` 54 | - vasp格式 55 | ``` 56 | (python37) cndaqiang@mac Desktop$ ./rdf.py 123.vasp 57 | read from 123.vasp 58 | nstep,ntyp,nat 1 ['H' 'O'] [24 12] 59 | Super cell [3. 1. 1.] 60 | ['H-H' 'H-O' 'O-O'] 61 | Save rdf to 123.vasp.H-H.averagerdf.dat 62 | Save rdf to 123.vasp.H-O.averagerdf.dat 63 | Save rdf to 123.vasp.O-O.averagerdf.dat 64 | Save png to 123.vasp.averagerdf.png 65 | ``` 66 | 67 | ## 结果展示 68 | ``` 69 | (python37) cndaqiang@mac Desktop$ ./rdf.py cubic.xyz 12 12 12 70 | read from cubic.xyz 71 | XYZ: set cell to 72 | a: [12. 0. 0.] 73 | b: [ 0. 12. 0.] 74 | c: [ 0. 0. 12.] 75 | nstep,ntyp,nat 1 ['O' 'H'] [ 61 122] 76 | Super cell [2. 2. 2.] 77 | ['O-O' 'O-H' 'H-H'] 78 | Save rdf to cubic.xyz.O-O.averagerdf.dat 79 | Save rdf to cubic.xyz.O-H.averagerdf.dat 80 | Save rdf to cubic.xyz.H-H.averagerdf.dat 81 | Save png to cubic.xyz.averagerdf.png 82 | ``` 83 | 与VMD计算结果对比 84 | ![](https://cndaqiang.github.io/uploads/2020/11/vmd.png) 85 | ![](https://cndaqiang.github.io/uploads/2020/11/cubic.xyz.averagerdf.png) 86 | -------------------------------------------------------------------------------- /rdf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Time : 2020-11-29 @IOP 5 | @Author : cndaqiang 6 | @Blog : cndaqiang.github.io 7 | @File : 读入含时xyz或POSCAR处理rdf 8 | """ 9 | 10 | import sys 11 | import os 12 | import numpy as np 13 | 14 | #统计的最短最远距离 15 | minr=0 #1e-15 #avoid rdf/0 16 | maxr=10.0 17 | dr=0.1 18 | #因为rdf:g(r)=dN/(4*pi*dr*r^2*\rho_N), 一般仅在r=a_0时取最大值,此时dr就影响计算结果,dr翻倍就减半, dr越大越小,但是积分不变的 19 | # 20 | ngrid=int(np.ceil(maxr-minr)/dr) 21 | #dr=(maxr-minr)/ngrid 22 | ngrid=ngrid+2 23 | grid=np.arange(ngrid)*dr+minr 24 | 25 | #xyz文件时需要 26 | #xyz格式类型,默认beforenum+1行是总原子数,header+1行开始是原子结构 27 | #有的程序输出的格式不规范,在这里定义 28 | beforenum=0 #/3 #beforenum+1行是总原子数 29 | header=2 #/9 #header+1行开始是原子结构 30 | #原胞 31 | cell=np.zeros([3,3]) 32 | cell[0]=np.array([12,0,0]) #a 33 | cell[1]=np.array([0,12,0]) #b 34 | cell[2]=np.array([0,0,12]) #c 35 | 36 | #-----Input File 37 | if len(sys.argv) == 1: 38 | print("Usage: "+str(sys.argv[0])+" [ xxx.xyz | xxx.vasp ] [ none | a | a b c]") 39 | exit() 40 | if len(sys.argv) > 1: 41 | inputfile = str(sys.argv[1]) 42 | else: 43 | inputfile = "./292.xyz" 44 | if os.path.exists(inputfile): 45 | print("read from",inputfile) 46 | else: 47 | print("EXIT: There are not "+inputfile) 48 | exit() 49 | if len(sys.argv) == 3: # 只输入一个晶格参数,视为cubic 50 | cell[:,:]=0 51 | for i in np.arange(3): cell[i,i]=float(sys.argv[2]) 52 | if len(sys.argv) == 5: #输入三个晶格参数,视为长方形 a b c晶胞 53 | cell[:,:]=0 54 | for i in np.arange(3): cell[i,i]=float(sys.argv[2+i]) 55 | 56 | #----- 57 | 58 | 59 | #---- 60 | def readxyz(xyzfile): 61 | f=open(xyzfile,'r') 62 | for i in np.arange(beforenum): f.readline()#原子数前有几行 63 | natoms=int(f.readline())#原子数 64 | ierror=f.seek(0,0) 65 | rownum=len(f.readlines())#总行数 66 | if rownum%(natoms+header) == 0: 67 | nstep=int(rownum/(natoms+header)) #每个xyz单元,2个 68 | else: 69 | print("rownum can't be split by natoms + header",rownum,natoms+header) 70 | nstep=int(rownum/(natoms+header)) #每个xyz单元,2个 71 | #nstep=2 也可以在这里限制总的nstep步数 72 | #收集元素种类和数量 73 | ntyp=np.array([]).astype(np.str) 74 | nat=np.array([]) 75 | ierror=f.seek(0,0) 76 | for i in np.arange(header): f.readline() 77 | for i in np.arange(natoms): 78 | label=f.readline().split()[0] 79 | if np.where(ntyp==label)[0].size == 0: 80 | ntyp = np.append(ntyp,label) 81 | nat = np.append(nat,1) 82 | else: 83 | nat[np.where(ntyp==label)[0][0]]=nat[np.where(ntyp==label)[0][0]]+1 84 | nat=nat.astype(np.int) 85 | #按照原子数排序,画图的顺序和中心原子 86 | ntyp=ntyp[np.argsort(nat)] 87 | nat=nat[np.argsort(nat)] 88 | 89 | natmax=int(np.max(nat)) 90 | totaltype=ntyp.size 91 | #====== 92 | xyz=np.zeros([nstep,totaltype,natmax,3]) #步数,元素,原子编号,xyz 93 | ierror=f.seek(0,0) 94 | for istep in np.arange(nstep): 95 | index=np.zeros(totaltype) 96 | for i in np.arange(header): f.readline() 97 | for iatom in np.arange(natoms): 98 | line=f.readline() 99 | label=line.split()[0] 100 | itype=np.where(ntyp==label)[0][0] 101 | for idir in np.arange(3): 102 | xyz[istep,itype,int(index[itype]),idir]=float(line.split()[idir+1]) 103 | index[itype]=index[itype]+1 104 | f.close() 105 | return nstep,ntyp,nat,xyz 106 | def readposcar(poscar): 107 | f=open(poscar,'r') 108 | f.readline() 109 | alat=np.float(f.readline().split()[0]) 110 | cell=np.zeros([3,3]) 111 | for i in np.arange(3): 112 | cell[i,0:3] = [ float(x) for x in f.readline().split()[0:3] ] 113 | cell=cell*alat 114 | # 115 | nstep=1 116 | #元素 117 | ntyp=np.array(f.readline().split()) 118 | nat=np.array(f.readline().split()) 119 | totaltype=min(ntyp.size,nat.size) 120 | ntyp=ntyp[0:totaltype].copy() 121 | nat=nat[0:totaltype].copy().astype(np.int) 122 | #坐标类型 123 | xyztype=f.readline().split()[0] 124 | #读坐标 125 | natmax=int(np.max(nat)) 126 | #坐标 127 | xyz=np.zeros([nstep,totaltype,natmax,3]) 128 | for istep in np.arange(nstep): 129 | for itype in np.arange(totaltype): 130 | for i in np.arange(nat[itype]): 131 | xyz[istep,itype,i,0:3]=[ float(x) for x in f.readline().split()[0:3] ] 132 | # 133 | # xyz[istep,itype,i,0:3]=[ (xyz[istep,itype,i,0:3]*cell[:,d]).sum() for d in np.arange(3) ] 134 | 135 | 136 | #计算坐标 137 | if xyztype[0] == 'D' or xyztype[0] == 'd': 138 | Dxyz=xyz.copy() 139 | for d in np.arange(3): 140 | xyz[:,:,:,d]=(Dxyz*cell[:,d]).sum(axis=3) 141 | #for d in np.arange(3): 142 | # xyz=xyz[:,:,:,0:3]*cell[0:3,d] 143 | else: 144 | xyz=xyz*alat 145 | return nstep,ntyp,nat,xyz,cell 146 | 147 | def move2cell(nstep,ntyp,nat,xyz,cell): 148 | for istep in np.arange(nstep): 149 | for i in np.arange(ntyp.size): 150 | for j in np.arange(nat[i]): 151 | #下面这套算法不是严格的,暂时没有好的方法 152 | while xyz[istep,i,j,0] > cell[0,0]: 153 | #print("i,j",i,j,"addcell 0") 154 | xyz[istep,i,j,:]=xyz[istep,i,j,:]-cell[0,:] 155 | while xyz[istep,i,j,0] < 0: 156 | #print("i,j",i,j,"delcell 0") 157 | xyz[istep,i,j,:]=xyz[istep,i,j,:]+cell[0,:] 158 | while xyz[istep,i,j,1] > cell[1,1]: 159 | #print("i,j",i,j,"addcell 1") 160 | xyz[istep,i,j,:]=xyz[istep,i,j,:]-cell[1,:] 161 | while xyz[istep,i,j,1] < 0: 162 | #print("i,j",i,j,"delcell 1") 163 | xyz[istep,i,j,:]=xyz[istep,i,j,:]+cell[1,:] 164 | while xyz[istep,i,j,2] > cell[2,2]: 165 | #print("i,j",i,j,"addcell 2") 166 | xyz[istep,i,j,:]=xyz[istep,i,j,:]-cell[2,:] 167 | while xyz[istep,i,j,2] < 0: 168 | #print("i,j",i,j,"delcell 2") 169 | xyz[istep,i,j,:]=xyz[istep,i,j,:]+cell[2,:] 170 | def calV(cell): 171 | V=0 172 | V=V+(cell[0,1]*cell[1,2]-cell[0,2]*cell[1,1])*cell[2,0] 173 | V=V+(cell[0,2]*cell[1,0]-cell[0,0]*cell[1,2])*cell[2,1] 174 | V=V+(cell[0,0]*cell[1,1]-cell[0,1]*cell[1,0])*cell[2,2] 175 | return V 176 | 177 | 178 | def savedata(A,B,filename): 179 | f=open(filename,'w') 180 | for i in np.arange(A.size): 181 | f.write(str(A[i])+"\t"+str(B[i])+'\n') 182 | f.close() 183 | # 184 | 185 | def calrdf(A_in,B_in): 186 | A=A_in.copy() 187 | B=B_in.copy() 188 | rdf=np.zeros(ngrid) 189 | for i in np.arange(A.shape[0]): 190 | dis=np.sqrt(np.square(B-A[i]).sum(axis=1)) 191 | choose=np.floor( ( dis[(dis >= max(minr, 1e-5) )&(dis < maxr+10*dr )] - minr )/dr ).astype(int) 192 | #忽略本身原子 193 | #向下取整,处以体积4/3pi(r^3 -(r-dr)^3) 194 | choose=choose[choose