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 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 _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
# now find best rotational alignment, this is more reliable than just # aligning the 2 reference atoms rot2 = rmsfit.findrotation_kabsch(x1n, x2n) x1n = np.dot(rot2, x1n.transpose()).transpose() # use the maximum distance, not rms as cutoff criterion max_dist = np.sqrt(np.sum((x1n - x2n) * (x1n - x2n), axis=1)).max() if max_dist < self.accuracy: self.best_rotation = np.dot(rot2, rot) return True return False if __name__ == "__main__": natoms = 35 from pygmin.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.003 # 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, xx2)
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)
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 pygmin.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)