├── 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 | 
85 | 
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