def alignRotation(XA, XB): """ Align structure XB with XA Align structure XB to be as similar as possible to structure XA. To be precise, rotate XB, so as to minimize the distance |XA - XB|. Rotations will be done around the origin, not the center of mass """ nsites = len(XA)/3 dist, Q2 = getAlignRotation(XA, XB) ################################################################### # Q2 contains the quaternion which rotates XB to best align with X1. # rotate XB according to Q2 ################################################################### rot_mx = rot.q2mx( Q2 ) #print rot_mx for j in range(nsites): i = 3*j XB[i:i+3] = np.dot( rot_mx, XB[i:i+3] ) dist = np.linalg.norm(XA - XB) #more precise than what it returned return dist, XB
def test_invert3x3(self): q = rotations.random_q() mx = rotations.q2mx(q) mxi1 = invert3x3(mx) mxi2 = np.linalg.inv(mx) self.assertEqual(mxi1.shape, mxi2.shape) for v1, v2 in izip(mxi1.reshape(-1), mxi2.reshape(-1)): self.assertAlmostEqual(v1, v2, places=5)
def test_invert3x3(self): q = rotations.random_q() mx = rotations.q2mx(q) mxi1 = invert3x3(mx) mxi2 = np.linalg.inv(mx) self.assertEqual(mxi1.shape, mxi2.shape) for v1, v2 in zip(mxi1.reshape(-1), mxi2.reshape(-1)): self.assertAlmostEqual(v1, v2, places=5)
def test1(self): rot = q2mx(random_q()) x2 = self.x1.copy() self.transform.rotate(x2, rot) x1 = self.x1 dist, mx = self.findrot(x1, x2) self.assertLess(dist, 1e-4) self.transform.translate(x2, -self.measure.get_com(x2)) self.transform.rotate(x2, mx) self.transform.translate(x2, self.measure.get_com(x1)) assert_arrays_almost_equal(self, x1, x2)
def test(): # pragma: no cover natoms = 35 from pele.utils import rotations for i in xrange(100): xx1 = np.random.random(3 * natoms) * 5 xx1 = xx1.reshape([-1, 3]) mx = rotations.q2mx(rotations.random_q()) xx2 = -np.dot(mx, xx1.transpose()).transpose() xx2 += 2.0 * (np.random.random(xx2.shape) - 0.5) * 0.001 # xx2 = xx1.copy() tmp = xx2[1].copy() xx2[1] = xx2[4] xx2[4] = tmp print i, ExactMatchCluster()(xx1.flatten(), xx2.flatten())
def test(): # pragma: no cover natoms = 35 from pele.utils import rotations for i in range(100): xx1 = np.random.random(3 * natoms) * 5 xx1 = xx1.reshape([-1, 3]) mx = rotations.q2mx(rotations.random_q()) xx2 = -np.dot(mx, xx1.transpose()).transpose() xx2 += 2. * (np.random.random(xx2.shape) - 0.5) * 0.001 #xx2 = xx1.copy() tmp = xx2[1].copy() xx2[1] = xx2[4] xx2[4] = tmp print(i, ExactMatchCluster()(xx1.flatten(), xx2.flatten()))
def test2(self): rot = q2mx(random_q()) dx = .01 x2 = self.x1.copy() x2[0] += .01 self.transform.rotate(x2, rot) x1old = self.x1.copy() x2old = x2.copy() dist, mx = self.findrot(self.x1, x2) # check it didn't change the arrays assert_arrays_almost_equal(self, x1old, self.x1) assert_arrays_almost_equal(self, x2old, x2) self.assertLess(dist, dx)
def test(): natoms = 35 from pele.utils import rotations for i in xrange(100): xx1 = np.random.random(3*natoms)*5 xx1 = xx1.reshape([-1,3]) mx = rotations.q2mx(rotations.random_q()) xx2 = -np.dot(mx, xx1.transpose()).transpose() xx2 +=2.*(np.random.random(xx2.shape)-0.5)*0.001 #xx2 = xx1.copy() tmp = xx2[1].copy() xx2[1] = xx2[4] xx2[4] = tmp #dist, x1n, x2n = findBestPermutation(xx1.flatten(), xx2.flatten()) #print dist print i,ExactMatchCluster()(xx1.flatten(), xx2.flatten())
def _optimizePermRot(X1, X2, niter, permlist, verbose=False, use_quench=True): if use_quench: pot = MinPermDistPotential(X1, X2.copy(), permlist=permlist) distbest = getDistxyz(X1, X2) mxbest = np.identity(3) X20 = X2.copy() for i in range(niter): #get and apply a random rotation aa = random_aa() if not use_quench: mx = aa2mx(aa) mxtot = mx #print "X2.shape", X2.shape else: #optimize the rotation using a permutationally invariand distance metric ret = defaults.quenchRoutine(aa, pot.getEnergyGradient, tol=0.01) aa1 = ret[0] mx1 = aa2mx(aa1) mxtot = mx1 X2 = applyRotation(mxtot, X20) #optimize the permutations dist, X1, X2 = findBestPermutation(X1, X2, permlist) if verbose: print "dist", dist, "distbest", distbest #print "X2.shape", X2.shape #optimize the rotation dist, Q2 = getAlignRotation(X1, X2) # print "dist", dist, "Q2", Q2 mx2 = q2mx(Q2) mxtot = np.dot(mx2, mxtot) if dist < distbest: distbest = dist mxbest = mxtot return distbest, mxbest
def findrotation_kearsley(coords1, coords2, align_com=True): """ Return the quaternion which aligns XB with XA Return the matrix which aligns structure XB to be as similar as possible to structure XA. To be precise, rotate XB, so as to minimize the distance |XA - XB|. Rotations will be done around the origin, not the center of mass Rotational alignment follows the prescription of Kearsley, Acta Cryst. A, 45, 208-210, 1989 http://dx.doi.org/10.1107/S0108767388010128 """ if(coords1.size != coords2.size): raise BaseException("dimension of arrays does not match") # reshape the arrays x1 = coords1.flatten() x2 = coords2.flatten() x1 = x1.reshape([-1,3]) x2 = x2.reshape([-1,3]) # # # determine number of atoms natoms = x1.shape[0] # set both com to zero if(align_com): com1 = np.sum(x1,axis=0) / float(natoms) com2 = np.sum(x2,axis=0) / float(natoms) x1 = x1.copy() - com1 x2 = x2.copy() - com2 x1 = x1.flatten() x2 = x2.flatten() # TODO: this is very dirty! ######################################### #Create matrix QMAT ######################################### QMAT = np.zeros([4,4], np.float64) for J1 in xrange(natoms): J2 = 3*(J1) -1 XM = x1[J2+1] - x2[J2+1] YM = x1[J2+2] - x2[J2+2] ZM = x1[J2+3] - x2[J2+3] XP = x1[J2+1] + x2[J2+1] YP = x1[J2+2] + x2[J2+2] ZP = x1[J2+3] + x2[J2+3] QMAT[0,0] = QMAT[0,0] + XM**2 + YM**2 + ZM**2 QMAT[0,1] = QMAT[0,1] - YP*ZM + YM*ZP QMAT[0,2] = QMAT[0,2] - XM*ZP + XP*ZM QMAT[0,3] = QMAT[0,3] - XP*YM + XM*YP QMAT[1,1] = QMAT[1,1] + YP**2 + ZP**2 + XM**2 QMAT[1,2] = QMAT[1,2] + XM*YM - XP*YP QMAT[1,3] = QMAT[1,3] + XM*ZM - XP*ZP QMAT[2,2] = QMAT[2,2] + XP**2 + ZP**2 + YM**2 QMAT[2,3] = QMAT[2,3] + YM*ZM - YP*ZP QMAT[3,3] = QMAT[3,3] + XP**2 + YP**2 + ZM**2 QMAT[1,0] = QMAT[0,1] QMAT[2,0] = QMAT[0,2] QMAT[2,1] = QMAT[1,2] QMAT[3,0] = QMAT[0,3] QMAT[3,1] = QMAT[1,3] QMAT[3,2] = QMAT[2,3] ########################################### """ Find eigenvalues and eigenvectors of QMAT. The eigenvector corresponding to the smallest eigenvalue is the quaternion which rotates XB into best alignment with XA. The smallest eigenvalue is the squared distance between the resulting structures. """ ########################################### (eigs, vecs) = np.linalg.eig(QMAT) #print "eigenvalues", eigs imin = np.argmin(eigs) eigmin = eigs[imin] #the minimum eigenvector Q2 = vecs[:,imin] #the eigenvector corresponding to the minimum eigenvalue if eigmin < 0.: if abs(eigmin) < 1e-6: eigmin = 0. else: print 'minDist> WARNING minimum eigenvalue is ',eigmin,' change to absolute value' eigmin = -eigmin dist = np.sqrt(eigmin) #this is the minimized distance between the two structures #print "dist from eigenvalue", dist #print "Q2", Q2, "norm", np.linalg.norm(Q2) #aa = rot.q2aa( Q2) #print "aa ", aa, "norm", np.linalg.norm(aa) return dist, rotations.q2mx(Q2)
imin = np.argmin(eigs) eigmin = eigs[imin] #the minimum eigenvector Q2 = vecs[:,imin] #the eigenvector corresponding to the minimum eigenvalue if eigmin < 0.: if abs(eigmin) < 1e-6: eigmin = 0. else: print 'minDist> WARNING minimum eigenvalue is ',eigmin,' change to absolute value' eigmin = -eigmin dist = np.sqrt(eigmin) #this is the minimized distance between the two structures #print "dist from eigenvalue", dist #print "Q2", Q2, "norm", np.linalg.norm(Q2) #aa = rot.q2aa( Q2) #print "aa ", aa, "norm", np.linalg.norm(aa) return dist, rotations.q2mx(Q2) findrotation = findrotation_kearsley if __name__ == "__main__": from pele.utils import rotations x1 = np.random.random(24) mx = rotations.q2mx(rotations.random_q()) x2 = np.dot(mx,x1.reshape(-1,3).transpose()).transpose().reshape(-1) print x2-x1 print mx-findrotation_kabsch(x1,x2) print findrotation_kabsch(x1,x2) print findrotation_kearsley(x1,x2)[1]
def rrot(self, x): q = rotations.random_q() mx = rotations.q2mx(q) self.transform.rotate(x, mx)
eigmin = eigs[imin] # the minimum eigenvector Q2 = vecs[:, imin] # the eigenvector corresponding to the minimum eigenvalue if eigmin < 0.: if abs(eigmin) < 1e-6: eigmin = 0. else: print 'minDist> WARNING minimum eigenvalue is ', eigmin, ' change to absolute value' eigmin = -eigmin dist = np.sqrt( eigmin) # this is the minimized distance between the two structures Q2 = np.real_if_close(Q2, 1e-10) if np.iscomplexobj(Q2): raise ValueError("Q2 is complex") return dist, rotations.q2mx(Q2) findrotation = findrotation_kearsley if __name__ == "__main__": x1 = np.random.random(24) mx = rotations.q2mx(rotations.random_q()) x2 = np.dot(mx, x1.reshape(-1, 3).transpose()).transpose().reshape(-1) print x2 - x1 print mx - findrotation_kabsch(x1, x2) print findrotation_kabsch(x1, x2) print findrotation_kearsley(x1, x2)[1]
def test_mx2aa(self): mx = rotations.q2mx(random_q()) p1 = mx2aa(mx) p2 = rotations.mx2aa(mx) self.arrays_equal(p1, p2)
def aa2mx( p ): return q2mx( aa2q( p ) )
def findrotation_kearsley(x1, x2, align_com=True): """Return the rotation matrix which aligns XB with XA Return the matrix which aligns structure XB to be as similar as possible to structure XA. To be precise, rotate XB, so as to minimize the distance |XA - XB|. Rotations will be done around the origin, not the center of mass Rotational alignment follows the prescription of Kearsley, Acta Cryst. A, 45, 208-210, 1989 http://dx.doi.org/10.1107/S0108767388010128 """ if x1.size != x2.size: raise ValueError("dimension of arrays does not match") # reshape the arrays x1 = x1.reshape([-1, 3]).copy() x2 = x2.reshape([-1, 3]).copy() # determine number of atoms natoms = x1.shape[0] # set both com to zero if align_com: com1 = np.sum(x1, axis=0) / float(natoms) com2 = np.sum(x2, axis=0) / float(natoms) x1 -= com1 x2 -= com2 x1 = x1.ravel() x2 = x2.ravel() # TODO: this is very dirty! ######################################### # Create matrix QMAT ######################################### QMAT = np.zeros([4, 4], np.float64) for J1 in xrange(natoms): J2 = 3 * J1 - 1 XM = x1[J2 + 1] - x2[J2 + 1] YM = x1[J2 + 2] - x2[J2 + 2] ZM = x1[J2 + 3] - x2[J2 + 3] XP = x1[J2 + 1] + x2[J2 + 1] YP = x1[J2 + 2] + x2[J2 + 2] ZP = x1[J2 + 3] + x2[J2 + 3] QMAT[0, 0] = QMAT[0, 0] + XM**2 + YM**2 + ZM**2 QMAT[0, 1] = QMAT[0, 1] - YP * ZM + YM * ZP QMAT[0, 2] = QMAT[0, 2] - XM * ZP + XP * ZM QMAT[0, 3] = QMAT[0, 3] - XP * YM + XM * YP QMAT[1, 1] = QMAT[1, 1] + YP**2 + ZP**2 + XM**2 QMAT[1, 2] = QMAT[1, 2] + XM * YM - XP * YP QMAT[1, 3] = QMAT[1, 3] + XM * ZM - XP * ZP QMAT[2, 2] = QMAT[2, 2] + XP**2 + ZP**2 + YM**2 QMAT[2, 3] = QMAT[2, 3] + YM * ZM - YP * ZP QMAT[3, 3] = QMAT[3, 3] + XP**2 + YP**2 + ZM**2 QMAT[1, 0] = QMAT[0, 1] QMAT[2, 0] = QMAT[0, 2] QMAT[2, 1] = QMAT[1, 2] QMAT[3, 0] = QMAT[0, 3] QMAT[3, 1] = QMAT[1, 3] QMAT[3, 2] = QMAT[2, 3] ########################################### """ Find eigenvalues and eigenvectors of QMAT. The eigenvector corresponding to the smallest eigenvalue is the quaternion which rotates XB into best alignment with XA. The smallest eigenvalue is the squared distance between the resulting structures. """ ########################################### (eigs, vecs) = np.linalg.eig(QMAT) imin = np.argmin(eigs) eigmin = eigs[imin] # the minimum eigenvector Q2 = vecs[:, imin] # the eigenvector corresponding to the minimum eigenvalue if eigmin < 0.: if abs(eigmin) < 1e-6: eigmin = 0. else: print 'minDist> WARNING minimum eigenvalue is ', eigmin, ' change to absolute value' eigmin = -eigmin dist = np.sqrt( eigmin) # this is the minimized distance between the two structures Q2 = np.real_if_close(Q2, 1e-10) if np.iscomplexobj(Q2): raise ValueError("Q2 is complex") return dist, rotations.q2mx(Q2)
def aa2mx(p): return q2mx(aa2q(p))