forked from benwmcdowell/monitor_VASP_convergence
-
Notifications
You must be signed in to change notification settings - Fork 0
/
show_forces.py
158 lines (146 loc) · 5.86 KB
/
show_forces.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import matplotlib.pyplot as plt
import sys
import getopt
from numpy import array,dot
from numpy.linalg import norm
from mpl_toolkits.mplot3d import Axes3D
def show_forces(outcar,poscar,**args):
if 'show_all' in args and args['show_all']:
show_all=True
else:
show_all=False
try:
lv,coord,atomtypes,atomnums,seldyn = parse_poscar(poscar)
except ValueError:
lv,coord,atomtypes,atomnums = parse_poscar(poscar)
seldyn=['TTT' for i in range(sum(atomnums))]
forces,time,tol=parse_forces(outcar,seldyn=seldyn)
forces=[i[-1] for i in forces]
fig=plt.figure()
ax=fig.add_subplot(111, projection='3d')
#plots atom coordinates
for i in range(len(atomtypes)):
tempvar=[[],[],[]]
for j in range(atomnums[i]):
for k in range(3):
tempvar[k].append(coord[j+sum(atomnums[:i])][k])
ax.scatter(tempvar[0],tempvar[1],tempvar[2],s=2000/max([norm(lv[j]) for j in range(3)]),label=atomtypes[i])
#plots force vectors
for i in range(len(atomtypes)):
tempo=[[],[],[]]
tempv=[[],[],[]]
for j in range(atomnums[i]):
for k in range(3):
if forces[-1][j+sum(atomnums[:i])]>tol or show_all:
tempo[k].append(coord[j+sum(atomnums[:i])][k])
tempv[k].append(forces[k][j+sum(atomnums[:i])]/max(forces[-1])*3)
ax.quiver(tempo[0],tempo[1],tempo[2],tempv[0],tempv[1],tempv[2])
ax.set_xlim(0,norm(dot(array([1.0,0.0,0.0]),lv)))
ax.set_ylim(0,norm(dot(array([0.0,1.0,0.0]),lv)))
ax.set_zlim(0,norm(dot(array([0.0,0.0,1.0]),lv)))
fig.legend()
plt.show()
def parse_forces(ifile,**args):
if 'seldyn' in args:
seldyn=args['seldyn']
else:
seldyn='none'
time=[]
forces=[[],[],[],[]]
try:
with open(outcar,'r') as file:
searching=True
while searching:
line=file.readline()
if not line:
break
if 'EDIFFG' in line:
line=line.split()
tol=abs(float(line[line.index('EDIFFG')+2]))
if 'POTIM' in line:
line=line.split()
potim=float(line[line.index('POTIM')+2])
if potim==0.0:
potim=-1.0
if 'NIONS' in line:
line=line.split()
atomnum=int(line[line.index('NIONS')+2])
if seldyn=='none':
seldyn=['TTT' for i in range(atomnum)]
elif 'TOTAL-FORCE' in line:
line=file.readline()
temp_forces=[[],[],[],[]]
for i in range(atomnum):
line=file.readline().split()
tempvar=[]
for j in range(3,6):
if seldyn[i][j-3]=='T':
temp_forces[j-3].append(abs(float(line[j])))
tempvar.append(abs(float(line[j])))
else:
temp_forces[j-3].append(0.0)
tempvar.append(0.0)
if len(tempvar)>0:
temp_forces[3].append(norm(array(tempvar)))
for i in range(4):
forces[i].append(temp_forces[i])
if len(time)==0:
time.append(0.0)
else:
time.append(time[-1]+abs(potim))
except:
print('error reading OUTCAR')
sys.exit(1)
if len(time)==0:
print('zero ionic steps read from OUTCAR')
sys.exit()
return forces,time,tol
def parse_poscar(ifile):
with open(ifile, 'r') as file:
lines=file.readlines()
sf=float(lines[1])
latticevectors=[float(lines[i].split()[j])*sf for i in range(2,5) for j in range(3)]
latticevectors=array(latticevectors).reshape(3,3)
atomtypes=lines[5].split()
atomnums=[int(i) for i in lines[6].split()]
if lines[7].split()[0] == 'Direct':
start=8
else:
start=9
seldyn=[''.join(lines[i].split()[-3:]) for i in range(start,sum(atomnums)+start)]
coord=array([[float(lines[i].split()[j]) for j in range(3)] for i in range(start,sum(atomnums)+start)])
for i in range(sum(atomnums)):
coord[i]=dot(latticevectors,coord[i])
#latticevectors formatted as a 3x3 array
#coord holds the atomic coordinates with shape ()
try:
return latticevectors, coord, atomtypes, atomnums, seldyn
except NameError:
return latticevectors, coord, atomtypes, atomnums
if __name__=='__main__':
outcar='./OUTCAR'
poscar='./POSCAR'
show_all=False
try:
opts,args=getopt.getopt(sys.argv[1:],'ho:p:a',['help','outcar=','poscar','all'])
except getopt.GetoptError:
print('error in command line syntax')
sys.exit(2)
for i,j in opts:
if i in ['-h','--help']:
print('''
input options:
-o, --outcar specify a path to the OUTCAR file other than ./OUTCAR
-p, --poscar specify an path to the POTCAR file other than ./POSCAR
-a, --all all forces are plotted, as opposed to just those larger than EDIFFG
help options:
-h, --help display this help message
''')
sys.exit()
if i in ['-o','--outcar']:
outcar=j
if i in ['-p','--poscar']:
poscar=j
if i in ['-a','--all']:
show_all=True
show_forces(outcar,poscar,show_all=show_all)