ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/applications/utilities/principalAxisCalculator
Revision: 1877
Committed: Thu Jun 6 15:43:35 2013 UTC (11 years, 11 months ago) by gezelter
File size: 8477 byte(s)
Log Message:
New electrostatic method, starting to do some performance tuning.

File Contents

# Content
1 #!@PYTHON_EXECUTABLE@
2 """principalAxisCalculator
3
4 Opens an XYZ file and computes the moments of inertia and principal axes
5 for the structure in the XYZ file. Optionally rotate the structure so that
6 the long axis (that with the smallest eigenvalue) is pointing along the
7 z-axis.
8
9 Usage: principalAxisCalculator
10
11 Options:
12 -h, --help show this help
13 -x, --xyz=... use specified XYZ (.xyz) file for the structure
14 -o, --out=... rotate the structure so that the smallest eigenvalue
15 of the rotation matrix points along the z-axis.
16
17 Example:
18 principalAxisCalculator -x junk.xyz -o rot.xyz
19
20 """
21
22 __author__ = "Dan Gezelter (gezelter@nd.edu)"
23 __version__ = "$Revision$"
24 __date__ = "$Date$"
25 __copyright__ = "Copyright (c) 2006 by the University of Notre Dame"
26 __license__ = "OpenMD"
27
28 import sys
29 import getopt
30 import string
31 import math
32 import random
33 from sets import *
34 import numpy
35
36
37 _haveXYZFileName = 0
38 _haveOutFileName = 0
39
40 positions = []
41 indices = []
42 atypes = []
43 Hmass = 1.0079
44 Cmass = 12.011
45 Omass = 15.999
46 Nmass = 14.007
47 Smass = 32.066
48 Aumass = 196.466569
49 Au1mass = 196.466569
50 Au2mass = 0.5
51
52 def usage():
53 print __doc__
54
55 def add(x,y):
56 return x+y
57
58 def sum(seq):
59 return reduce(add, seq)
60
61 def readFile(XYZFileName):
62 print "reading XYZ file"
63
64 XYZFile = open(XYZFileName, 'r')
65 # Find number of atoms first
66 line = XYZFile.readline()
67 L = line.split()
68 nAtoms = int(L[0])
69 # skip comment line
70 line = XYZFile.readline()
71 for i in range(nAtoms):
72 line = XYZFile.readline()
73 L = line.split()
74 myIndex = i
75 indices.append(myIndex)
76 atomType = L[0]
77 atypes.append(atomType)
78 x = float(L[1])
79 y = float(L[2])
80 z = float(L[3])
81 positions.append([x, y, z])
82 XYZFile.close()
83
84
85 def findCOM():
86 #find center of mass
87 Xcom = 0.0
88 Ycom = 0.0
89 Zcom = 0.0
90 totalMass = 0.0
91
92 for i in range(0,len(indices)):
93 if (atypes[i] == "H"):
94 myMass = Hmass
95 elif (atypes[i] == "C"):
96 myMass = Cmass
97 elif (atypes[i] == "O"):
98 myMass = Omass
99 elif (atypes[i] == "N"):
100 myMass = Nmass
101 elif (atypes[i] == "S"):
102 myMass = Smass
103 elif (atypes[i] == "Au1"):
104 myMass = Au1mass
105 elif (atypes[i] == "Au2"):
106 myMass = Au2mass
107 elif (atypes[i] == "Au"):
108 myMass = Aumass
109 else:
110 print "unknown atom type! %s" % (atypes[i])
111
112 Xcom = Xcom + myMass * positions[i][0]
113 Ycom = Ycom + myMass * positions[i][1]
114 Zcom = Zcom + myMass * positions[i][2]
115 totalMass = totalMass + myMass
116
117 Xcom = Xcom / totalMass
118 Ycom = Ycom / totalMass
119 Zcom = Zcom / totalMass
120
121 COM = [Xcom, Ycom, Zcom]
122
123 return COM
124
125 def findMoments():
126
127 COM = findCOM()
128
129 #find inertia tensor matrix elements
130
131 I = numpy.zeros((3,3), numpy.float)
132
133 for i in range(0,len(indices)):
134 if (atypes[i] == "H"):
135 myMass = Hmass
136 elif (atypes[i] == "C"):
137 myMass = Cmass
138 elif (atypes[i] == "O"):
139 myMass = Omass
140 elif (atypes[i] == "N"):
141 myMass = Nmass
142 elif (atypes[i] == "S"):
143 myMass = Smass
144 elif (atypes[i] == "Au1"):
145 myMass = Au1mass
146 elif (atypes[i] == "Au2"):
147 myMass = Au2mass
148 elif (atypes[i] == "Au"):
149 myMass = Aumass
150 else:
151 print "unknown atom type!"
152
153 dx = positions[i][0] - COM[0]
154 dy = positions[i][1] - COM[1]
155 dz = positions[i][2] - COM[2]
156
157 I[0,0] = I[0,0] + myMass * ( dy * dy + dz * dz )
158 I[1,1] = I[1,1] + myMass * ( dx * dx + dz * dz )
159 I[2,2] = I[2,2] + myMass * ( dx * dx + dy * dy )
160
161 I[0,1] = I[0,1] - myMass * ( dx * dy )
162 I[0,2] = I[0,2] - myMass * ( dx * dz )
163
164 I[1,2] = I[1,2] - myMass * ( dy * dz )
165
166 I[1,0] = I[0,1]
167 I[2,0] = I[0,2]
168 I[2,1] = I[1,2]
169
170 print "Inertia Tensor:"
171 print I
172 print
173
174 (evals, evects) = numpy.linalg.eig(I)
175 print "evals:"
176 print evals
177 print
178 print "evects:"
179 print evects
180 print
181
182 return (COM, evals, evects)
183
184 def writeFile(OutFileName):
185
186 (COM, evals, evects) = findMoments()
187
188 # we need to re-order the axes so that the smallest moment of inertia
189 # (which corresponds to the long axis of the molecule) is along the z-axis
190 # we'll just reverse the order of the three axes:
191
192 axOrder = numpy.argsort(evals)
193 RotMat = numpy.zeros((3,3), numpy.float)
194 RotMat[0] = evects[axOrder[2]]
195 RotMat[1] = evects[axOrder[1]]
196 RotMat[2] = evects[axOrder[0]]
197
198 q = [0.0, 0.0, 0.0, 0.0]
199 myEuler = [0.0, 0.0, 0.0]
200
201 # RotMat to Quat code is out of OpenMD's SquareMatrix3.hpp code:
202
203 t = RotMat[0][0] + RotMat[1][1] + RotMat[2][2] + 1.0
204
205 if( t > 1e-6 ):
206 s = 0.5 / math.sqrt( t )
207 q[0] = 0.25 / s
208 q[1] = (RotMat[1][2] - RotMat[2][1]) * s
209 q[2] = (RotMat[2][0] - RotMat[0][2]) * s
210 q[3] = (RotMat[0][1] - RotMat[1][0]) * s
211 else:
212 ad1 = RotMat[0][0]
213 ad2 = RotMat[1][1]
214 ad3 = RotMat[2][2]
215
216 if( ad1 >= ad2 and ad1 >= ad3 ):
217 s = 0.5 / math.sqrt( 1.0 + RotMat[0][0] - RotMat[1][1] - RotMat[2][2] )
218 q[0] = (RotMat[1][2] - RotMat[2][1]) * s
219 q[1] = 0.25 / s
220 q[2] = (RotMat[0][1] + RotMat[1][0]) * s
221 q[3] = (RotMat[0][2] + RotMat[2][0]) * s
222 elif ( ad2 >= ad1 and ad2 >= ad3 ):
223 s = 0.5 / math.sqrt( 1.0 + RotMat[1][1] - RotMat[0][0] - RotMat[2][2] )
224 q[0] = (RotMat[2][0] - RotMat[0][2] ) * s
225 q[1] = (RotMat[0][1] + RotMat[1][0]) * s
226 q[2] = 0.25 / s
227 q[3] = (RotMat[1][2] + RotMat[2][1]) * s
228 else:
229 s = 0.5 / math.sqrt( 1.0 + RotMat[2][2] - RotMat[0][0] - RotMat[1][1] )
230 q[0] = (RotMat[0][1] - RotMat[1][0]) * s
231 q[1] = (RotMat[0][2] + RotMat[2][0]) * s
232 q[2] = (RotMat[1][2] + RotMat[2][1]) * s
233
234 print "Quaternions:"
235 print q
236
237 theta = math.acos(RotMat[2][2])
238 ctheta = RotMat[2][2]
239 stheta = math.sqrt(1.0 - ctheta * ctheta)
240
241 if (math.fabs(stheta) < 1e-6):
242 psi = 0.0
243 phi = math.atan2(-RotMat[1][0], RotMat[0][0])
244 else:
245 phi = math.atan2(RotMat[2][0], -RotMat[2][1])
246 psi = math.atan2(RotMat[0][2], RotMat[1][2])
247
248 if (phi < 0):
249 phi = phi + 2.0 * math.pi;
250
251 if (psi < 0):
252 psi = psi + 2.0 * math.pi;
253
254 myEuler[0] = phi * 180.0 / math.pi;
255 myEuler[1] = theta * 180.0 / math.pi;
256 myEuler[2] = psi * 180.0 / math.pi;
257
258 print "Euler Angles:"
259 print myEuler
260
261 nAtoms = len(indices)
262
263 print "writing output XYZ file"
264
265 OutFile = open(OutFileName, 'w')
266
267 OutFile.write('%10d\n' % (nAtoms))
268 OutFile.write('\n')
269
270 for i in range(nAtoms):
271
272 dx = positions[i][0] - COM[0]
273 dy = positions[i][1] - COM[1]
274 dz = positions[i][2] - COM[2]
275
276 r = numpy.array([dx,dy,dz])
277 rnew = numpy.dot(RotMat, r)
278
279 OutFile.write('%s\t%f\t%f\t%f\t%d\n' % (atypes[i], rnew[0], rnew[1], rnew[2], i))
280 OutFile.close()
281
282 def main(argv):
283 try:
284 opts, args = getopt.getopt(argv, "hx:o:", ["help", "xyz=", "out="])
285 except getopt.GetoptError:
286 usage()
287 sys.exit(2)
288 for opt, arg in opts:
289 if opt in ("-h", "--help"):
290 usage()
291 sys.exit()
292 elif opt in ("-x", "--xyz"):
293 XYZFileName = arg
294 global _haveXYZFileName
295 _haveXYZFileName = 1
296 elif opt in ("-o", "--out"):
297 OutFileName = arg
298 global _haveOutFileName
299 _haveOutFileName = 1
300
301
302 if (_haveXYZFileName != 1):
303 usage()
304 print "No xyz file was specified"
305 sys.exit()
306
307 readFile(XYZFileName)
308
309 if (_haveOutFileName == 1):
310 writeFile(OutFileName)
311 else:
312 findMoments()
313
314 if __name__ == "__main__":
315 if len(sys.argv) == 1:
316 usage()
317 sys.exit()
318 main(sys.argv[1:])

Properties

Name Value
svn:keywords Author Id Revision Date