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
示例#2
0
def minPermDistLong(X1, X2, max_permutations = 10000):
    """
    Minimize the distance between two clusters.  The following symmetries will be accounted for
    
    Translational symmetry

    Global rotational symmetry

    Permutational symmetry
    
    This routine is deterministic, but ludicrously slow.  Use the minPermDistStochastic instead
    """
    print "This routine is deterministic, but ludicrously slow.  Use the minPermDistStochastic instead"

    X2in = np.copy(X2)

    X2min = np.copy(X2)
    dmin = np.linalg.norm( X2-X1 )

    nsites = len(X1) / 3
    #this is a really dumb way to do this
    nperm = math.factorial(nsites)
    print nperm, "permutations in total. Stopping at ", max_permutations
    count = 0
    for perm in itertools.permutations(range(nsites)):
        #print perm
        X2 = permuteArray( X2in, perm)

        dist, X1, X2 = minDist(X1, X2)

        if dist < dmin:
            dmin = dist
            X2min = np.copy(X2)
            #print dist, np.linalg.norm(X1-X2)
            if dmin < 1e-6:
                print "found exact match (to accuracy 1e-6)"
                break


        count += 1
        if count % 1000 == 0:
            print "finished", count, "permutations out of", min(nperm, max_permutations), " mindist is", dmin, "last try was", dist



        if count == max_permutations:
            print "reached maximum number of perterbations (", max_permutations, ")."  

            use_hungarian = True
            if use_hungarian:
                print "will now fix alignment and calculate the best permutation using the Hungarian algorithm"
                #print "dist before hungarian algorithm", dmin
                ret = findBestPermutation( X1, X2min )
                if ret != None:
                    dmin, X1, X2min = findBestPermutation( X1, X2min )
                #print "dist after hungarian algorithm", dmin


            break


    return dmin, X1, X2min
def minPermDistStochastic(X1, X2, niter=100, permlist=None, verbose=False, accuracy=0.01,
                      check_inversion=True, use_quench=False):
    """
    Minimize the distance between two clusters.  
    
    Parameters
    ----------
    X1, X2 : 
        the structures to align.  X2 will be aligned with X1, both
        the center of masses will be shifted to the origin
    niter : int
        the number of basinhopping iterations to perform
    permlist : a list of lists of atoms 
        A list of lists of atoms which are interchangable.
        e.g. if all the atoms are interchangable
        
            permlist = [range(natoms)]
        
        For a 50/50 binary mixture, 
        
            permlist = [range(1,natoms/2), range(natoms/2,natoms)]
    verbose : 
        whether to print status information
    accuracy : 
        accuracy for determining if the structures are identical
    check_inversion :
        if true, account for point inversion symmetry
    use_quench : 
        for each step of the iteration, minimize a permutationally invariant
        distance metric.  This slows the algorithm, but can potentially make
        it more accurate.

    Notes
    -----

    The following symmetries will be accounted for::
    
    1. Translational symmetry
    #. Global rotational symmetry
    #. Permutational symmetry
    #. Point inversion symmetry

    
    The algorithm here to find the best distance is
    
    for i in range(niter):    
        random_rotation(coords)
        findBestPermutation(coords)
        alignRotation(coords)
    """
    natoms = len(X1) / 3
    if permlist is None:
        permlist = [range(natoms)]

    X1init = X1
    X2init = X2
    X1 = np.copy(X1)
    X2 = np.copy(X2)

    #first check for exact match
    exactmatch = ExactMatchCluster(accuracy=accuracy, permlist=permlist)
    if exactmatch(X1, X2):
        #this is kind of cheating, I would prefer to return
        #X2 in best alignment and the actual (small) distance
        return 0.0, X1, X1.copy() 
    
    #bring center of mass of x1 and x2 to the origin
    #save the center of mass of X1 for later
    X1com = X1.reshape([-1,3]).sum(0) / natoms
    X1 = CoMToOrigin(X1)
    X2 = CoMToOrigin(X2)
    #print "X2.shape", X2.shape
    
    #find the best rotation stochastically
    X20 = X2.copy()
    distbest, mxbest = _optimizePermRot(X1, X2, niter, permlist, verbose=verbose, use_quench=use_quench)
    use_inversion = False
    if check_inversion:
        X20i = -X20.copy()
        X2 = X20i.copy()
        distbest1, mxbest1 = _optimizePermRot(X1, X2, niter, permlist, verbose=verbose, use_quench=use_quench)
        if distbest1 < distbest:
            if verbose:
                print "using inversion in minpermdist"
            use_inversion = True
            distbest = distbest1
            mxbest = mxbest1

    #now we know the best rotation
    if use_inversion: X20 = X20i
    X2 = applyRotation(mxbest, X20)
    dist, X1, X2 = findBestPermutation(X1, X2, permlist)
    dist, X2 = alignRotation(X1, X2)
    if dist > distbest+0.001:
        print "ERROR: minPermDistRanRot: dist is different from distbest %f %f" % (dist, distbest)
    if verbose:
        print "finaldist", dist, "distmin", distbest
    
    #add back in the center of mass of X1
    X1 = X1.reshape([-1,3])
    X2 = X2.reshape([-1,3])
    X1 += X1com
    X2 += X1com
    X1 = X1.reshape(-1)
    X2 = X2.reshape(-1)
    
    return dist, X1, X2