2"""Water Quaternion Sampler
4Samples water orientations from a list of known good
10 -h, --help show this help
11 -m, --meta-data=... use specified meta-data (.omd) file
12 -o, --output-file=... use specified output (.omd) file
16 waterRotator -m basal.omd -o basal.new.omd
20__author__ = "Dan Gezelter (gezelter@nd.edu)"
21__copyright__ = "Copyright (c) 2004-present The University of Notre Dame. All Rights Reserved."
31_haveOutputFileName = 0
46#Hmat = zeros([3,3],Float)
47#BoxInv = zeros([3],Float)
61def readFile(mdFileName):
62 mdFile = open(mdFileName, 'r')
63 # Find OpenMD version info first
64 line = mdFile.readline()
66 if '<OOPSE version=' in line or '<OpenMD version=' in line:
69 line = mdFile.readline()
71 # Rewind file and find start of MetaData block
74 line = mdFile.readline()
75 print("reading MetaData")
77 if '<MetaData>' in line:
80 line = mdFile.readline()
81 if '</MetaData>' in line:
85 line = mdFile.readline()
88 print("reading Snapshot")
89 line = mdFile.readline()
91 if '<Snapshot>' in line:
92 line = mdFile.readline()
94 print("reading FrameData")
95 if '<FrameData>' in line:
97 frameData.append(line)
100 Hxx = float(L[2].strip(','))
101 Hxy = float(L[3].strip(','))
102 Hxz = float(L[4].strip(','))
103 Hyx = float(L[7].strip(','))
104 Hyy = float(L[8].strip(','))
105 Hyz = float(L[9].strip(','))
106 Hzx = float(L[12].strip(','))
107 Hzy = float(L[13].strip(','))
108 Hzz = float(L[14].strip(','))
109 Hmat.append([Hxx, Hxy, Hxz])
110 Hmat.append([Hyx, Hyy, Hyz])
111 Hmat.append([Hzx, Hzy, Hzz])
113 BoxInv.append(1.0/Hxx)
114 BoxInv.append(1.0/Hyy)
115 BoxInv.append(1.0/Hzz)
117 line = mdFile.readline()
118 if '</FrameData>' in line:
119 frameData.append(line)
123 line = mdFile.readline()
125 if '<StuntDoubles>' in line:
126 line = mdFile.readline()
130 indices.append(myIndex)
135 positions.append([x, y, z])
139 velocities.append([vx, vy, vz])
144 quaternions.append([qw, qx, qy, qz])
148 angVels.append([jx, jy, jz])
149 line = mdFile.readline()
150 if '</StuntDoubles>' in line:
153 line = mdFile.readline()
158def writeFile(outputFileName):
159 outputFile = open(outputFileName, 'w')
161 outputFile.write("<OpenMD version=1>\n");
163 for metaline in metaData:
164 outputFile.write(metaline)
166 outputFile.write(" <Snapshot>\n")
168 for frameline in frameData:
169 outputFile.write(frameline)
171 outputFile.write(" <StuntDoubles>\n")
174 for i in range(len(indices)):
176 outputFile.write("%10d %7s %18.10g %18.10g %18.10g %13e %13e %13e %13e %13e %13e %13e %13e %13e %13e\n" % (indices[i], sdFormat, positions[i][0], positions[i][1], positions[i][2], velocities[i][0], velocities[i][1], velocities[i][2], quaternions[i][0], quaternions[i][1], quaternions[i][2], quaternions[i][3], angVels[i][0], angVels[i][1], angVels[i][2]))
178 outputFile.write(" </StuntDoubles>\n")
179 outputFile.write(" </Snapshot>\n")
180 outputFile.write("</OpenMD>\n")
185 return math.floor(x + 0.5)
187 return math.ceil(x - 0.5)
189def wrapVector(myVect):
190 scaled = [0.0, 0.0, 0.0]
192 scaled[i] = myVect[i] * BoxInv[i]
193 scaled[i] = scaled[i] - roundMe(scaled[i])
194 myVect[i] = scaled[i] * Hmat[i][i]
199 for i in range(len(L1)):
200 myDot = myDot + L1[i]*L2[i]
205 myLength = math.sqrt(dot(L1, L1))
206 for i in range(len(L1)):
207 L2.append(L1[i] / myLength)
211 # don't call this with anything other than length 3 lists please
214 L3[0] = L1[1]*L2[2] - L1[2]*L2[1]
215 L3[1] = L1[2]*L2[0] - L1[0]*L2[2]
216 L3[2] = L1[0]*L2[1] - L1[1]*L2[0]
224 for i in range(len(indices)):
225 neighbors.append(list())
228 for i in range(len(indices)-1):
230 for j in range(i+1, len(indices)):
233 dpos = [jPos[0] - iPos[0], jPos[1]-iPos[1], jPos[2]-iPos[2]]
234 dpos = wrapVector(dpos)
235 dist2 = dot(dpos, dpos)
238 neighbors[i].append(j)
239 neighbors[j].append(i)
241 if (len(neighbors[i]) == 4):
245 for i in range(len(indices)):
246 if (len(neighbors[i]) < 4):
247 neighbors[i].append(-1)
248 surfaceCount = surfaceCount + 1
250 print("surfaceCount = %d" % surfaceCount)
252def randomizeProtons():
254 # do 10 proton bucket brigades:
256 origPoint = random.randint(0, len(indices))
257 protonBucketBrigade(origPoint)
259 # check to make sure everyone has a happy proton set:
261 for j in range(len(indices)):
262 if (len(DonatingTo[j]) != 2):
263 # print "first round to fix molecule %d" % j
264 protonBucketBrigade(j)
266 # check to make sure everyone has a happy proton set:
268 for j in range(len(indices)):
269 if (len(DonatingTo[j]) != 2):
270 print("second round to fix molecule %d" % j)
271 protonBucketBrigade(j)
273 for j in range(len(indices)):
274 if (len(DonatingTo[j]) != 2):
275 print("unfilled proton donor list for molecule %d" % j)
279def protonBucketBrigade(origPoint):
281 for i in range(len(indices)):
282 DonatingTo.append(list())
283 AcceptingFrom.append(list())
284 OldDonor.append(list())
287 # pick unreasonable start values (that don't match surface atom
288 # unreasonable values)
291 for i in range(50000):
292 #while (acceptor != origPoint):
293 myNeighbors = set(neighbors[donor])
295 # can't pick a proton choice from one of my current protons:
296 badChoices = set(DonatingTo[donor]).union(set(OldDonor[acceptor]))
297 # can't send a proton back to guy who sent one to me (no give-backs):
298 #badChoices.add(set(OldDonor[acceptor]))
299 # can't send a proton to anyone who is already taking 2:
300 for j in myNeighbors.difference(surfaceSet):
301 if (len(AcceptingFrom[j]) == 2):
304 nDonors = len(DonatingTo[donor])
308 if (len(myNeighbors.difference(badChoices)) != 0):
309 acceptor = random.choice(list(myNeighbors.difference(badChoices)))
313 DonatingTo[donor].append(acceptor)
316 AcceptingFrom[acceptor].append(donor)
317 OldDonor[acceptor].append(donor)
319 acceptor = random.choice(DonatingTo[donor])
321 print("Whoah! How'd we get here?")
325 # surface atoms all have a -1 neighbor, but that's OK. A proton
326 # is allowed to point out of the surface, but it does break the
327 # proton chain letter
328 # print "surface atom found, starting over from origPoint"
334 for i in range(len(indices)):
335 DonatingTo.append(list())
336 AcceptingFrom.append(list())
337 OldDonor.append(list())
338 # print "Computing Quaternions"
342 RotMat = [ux, uy, uz]
343 totalDipole = [0.0, 0.0, 0.0]
344 for i in range(len(indices)):
345 # print "doing quats for molecule %d" % i
346 # print "Dlen = %d " % len(DonatingTo[i])
347 # print DonatingTo[i]
352 acceptor1 = DonatingTo[i][0]
353 acceptor2 = DonatingTo[i][1]
354 if (acceptor1 == -1 and acceptor2 == -1):
355 donor1 = AcceptingFrom[i][0]
356 donor2 = AcceptingFrom[i][1]
357 npos = positions[donor1]
358 apos1 = [npos[0] - myPos[0], npos[1] - myPos[1], npos[2] - myPos[2]]
359 apos1 = wrapVector(apos1)
360 npos = positions[donor2]
361 apos2 = [npos[0] - myPos[0], npos[1] - myPos[1], npos[2] - myPos[2]]
362 apos2 = wrapVector(apos2)
363 tempX = [0.0, 0.0, 0.0]
364 tempY = [0.0, 0.0, 0.0]
365 tempZ = [0.0, 0.0, 0.0]
366 tempZ[0] = 0.5*(apos1[0] + apos2[0])
367 tempZ[1] = 0.5*(apos1[1] + apos2[1])
368 tempZ[2] = 0.5*(apos1[2] + apos2[2])
369 tempX[0] = (apos2[0] - apos1[0])
370 tempX[1] = (apos2[1] - apos1[1])
371 tempX[2] = (apos2[2] - apos1[2])
372 tempZ = normalize(tempZ)
373 tempX = normalize(tempX)
374 tempY = cross(tempX, tempZ)
375 dpos1[0] = tempZ[0] - 0.5*tempY[0]
376 dpos1[1] = tempZ[1] - 0.5*tempY[1]
377 dpos1[2] = tempZ[2] - 0.5*tempY[2]
378 dpos2[0] = tempZ[0] + 0.5*tempY[0]
379 dpos2[1] = tempZ[1] + 0.5*tempY[1]
380 dpos2[2] = tempZ[2] + 0.5*tempY[2]
383 if (acceptor1 == -1):
384 tempVec = [0.0, 0.0, 0.0]
386 thisNeighbor = neighbors[i][j]
387 npos = positions[thisNeighbor]
388 npos1 = [npos[0] - myPos[0], npos[1] - myPos[1], npos[2] - myPos[2]]
389 npos1 = wrapVector(npos1)
390 tempVec[0] = tempVec[0] + npos1[0]
391 tempVec[1] = tempVec[1] + npos1[1]
392 tempVec[2] = tempVec[2] + npos1[2]
393 dpos1 = [-tempVec[0]/3.0, -tempVec[1]/3.0, -tempVec[2]/3.0]
394 dpos1 = normalize(dpos1)
396 a1pos = positions[acceptor1]
397 dpos1 = [a1pos[0] - myPos[0], a1pos[1] - myPos[1], a1pos[2] - myPos[2]]
398 dpos1 = wrapVector(dpos1)
399 dpos1 = normalize(dpos1)
402 if (acceptor2 == -1):
403 tempVec = [0.0, 0.0, 0.0]
405 thisNeighbor = neighbors[i][j]
406 npos = positions[thisNeighbor]
407 npos1 = [npos[0] - myPos[0], npos[1] - myPos[1], npos[2] - myPos[2]]
408 npos1 = wrapVector(npos1)
409 tempVec[0] = tempVec[0] + npos1[0]
410 tempVec[1] = tempVec[1] + npos1[1]
411 tempVec[2] = tempVec[2] + npos1[2]
412 dpos2 = [-tempVec[0]/3.0, -tempVec[1]/3.0, -tempVec[2]/3.0]
413 dpos2 = normalize(dpos2)
415 a2pos = positions[acceptor2]
416 dpos2 = [a2pos[0] - myPos[0], a2pos[1] - myPos[1], a2pos[2] - myPos[2]]
417 dpos2 = wrapVector(dpos2)
418 dpos2 = normalize(dpos2)
421 uz[j] = (dpos1[j] + dpos2[j])/2.0
424 uy[j] = dpos2[j] - dpos1[j]
429 q = [0.0, 0.0, 0.0, 0.0]
431 # RotMat to Quat code is out of OpenMD's SquareMatrix3.hpp code:
437 t = RotMat[0][0] + RotMat[1][1] + RotMat[2][2] + 1.0
440 s = 0.5 / math.sqrt( t )
442 q[1] = (RotMat[1][2] - RotMat[2][1]) * s
443 q[2] = (RotMat[2][0] - RotMat[0][2]) * s
444 q[3] = (RotMat[0][1] - RotMat[1][0]) * s
450 if( ad1 >= ad2 and ad1 >= ad3 ):
451 s = 0.5 / math.sqrt( 1.0 + RotMat[0][0] - RotMat[1][1] - RotMat[2][2] )
452 q[0] = (RotMat[1][2] - RotMat[2][1]) * s
454 q[2] = (RotMat[0][1] + RotMat[1][0]) * s
455 q[3] = (RotMat[0][2] + RotMat[2][0]) * s
456 elif ( ad2 >= ad1 and ad2 >= ad3 ):
457 s = 0.5 / math.sqrt( 1.0 + RotMat[1][1] - RotMat[0][0] - RotMat[2][2] )
458 q[0] = (RotMat[2][0] - RotMat[0][2] ) * s
459 q[1] = (RotMat[0][1] + RotMat[1][0]) * s
461 q[3] = (RotMat[1][2] + RotMat[2][1]) * s
463 s = 0.5 / math.sqrt( 1.0 + RotMat[2][2] - RotMat[0][0] - RotMat[1][1] )
464 q[0] = (RotMat[0][1] - RotMat[1][0]) * s
465 q[1] = (RotMat[0][2] + RotMat[2][0]) * s
466 q[2] = (RotMat[1][2] + RotMat[2][1]) * s
470 totalDipole = [totalDipole[0] + uz[0], totalDipole[1] + uz[1], totalDipole[2] + uz[2]]
471 totalDipole = [-totalDipole[0], -totalDipole[1], -totalDipole[2]]
473 Dipole = math.sqrt(dot(totalDipole, totalDipole))
474 print('Total Dipole Moment = %d' % Dipole)
475 if (Dipole > 40 or Dipole < -40):
476 print("Bad Dipole, starting over")
477 for i in range(len(indices)):
491 opts, args = getopt.getopt(argv, "hm:o:", ["help", "meta-data=", "output-file="])
492 except getopt.GetoptError:
495 for opt, arg in opts:
496 if opt in ("-h", "--help"):
499 elif opt in ("-m", "--meta-data"):
501 global _haveMDFileName
503 elif opt in ("-o", "--output-file"):
505 global _haveOutputFileName
506 _haveOutputFileName = 1
507 if (_haveMDFileName != 1):
509 print("No meta-data file was specified")
511 if (_haveOutputFileName != 1):
513 print("No output file was specified")
520 writeFile(outputFileName)
522if __name__ == "__main__":
523 if len(sys.argv) == 1: