def test(coords1, coords2, mysys, permlist): printlist = [] printlist.append((coords1.copy(), "after quench")) printlist.append((coords2.copy(), "after quench")) coords2in = coords2.copy() coords1in = coords1.copy() distinit = getDistaa(coords1, coords2, mysys) print "distinit", distinit (dist, coords1, coords2) = minPermDistRBMol(coords1, coords2, mysys, permlist=permlist) distfinal = getDistaa(coords1, coords2, mysys) print "dist returned ", dist print "dist from coords ", distfinal print "coords2 initial energy", mysys.getEnergy(coords2in) print "coords2 final energy ", mysys.getEnergy(coords2) print "coords1 initial energy", mysys.getEnergy(coords1in) print "coords1 final energy ", mysys.getEnergy(coords1) printlist.append((coords1.copy(), "coords1 after mindist")) printlist.append((coords2.copy(), "coords2 after mindist")) import pygmin.printing.print_atoms_xyz as printxyz with open("otp.xyz", "w") as fout: for coords, line2 in printlist: xyz = mysys.getxyz(coords) printxyz.printAtomsXYZ(fout, xyz, line2=line2, atom_type=["N", "O", "O"]) return dist, coords1, coords2
def runtest(self, X1, X2): X1i = np.copy(X1) X2i = np.copy(X2) (distreturned, X1, X2) = minPermDistRBMol(X1, X2, mysys=self.pot, permlist=self.permlist) distinit = getDistaa(X1i, X2i, self.pot) distfinal = getDistaa(X1, X2, self.pot) self.assertTrue( abs(distfinal - distreturned) < 1e-14, "returned distance is wrong: %g != %g" % (distfinal, distreturned)) self.assertTrue(distfinal <= distinit) #test if the energies have changed Ei = self.pot.getEnergy(X1i) Ef = self.pot.getEnergy(X1) self.assertTrue( abs(Ei - Ef) < 1e-12, "Energy of X1 changed: %g - %g = %g" % (Ei, Ef, Ei - Ef)) Ei = self.pot.getEnergy(X2i) Ef = self.pot.getEnergy(X2) self.assertTrue( abs(Ei - Ef) < 1e-12, "Energy of X2 changed: %g - %g = %g" % (Ei, Ef, Ei - Ef)) return distreturned, X1, X2
def test(coords1, coords2, mysys, permlist): printlist = [] printlist.append((coords1.copy(), "after quench")) printlist.append((coords2.copy(), "after quench")) coords2in = coords2.copy() coords1in = coords1.copy() distinit = getDistaa(coords1, coords2, mysys) print "distinit", distinit (dist, coords1, coords2) = minPermDistRBMol(coords1,coords2, mysys, permlist=permlist) distfinal = getDistaa(coords1, coords2, mysys) print "dist returned ", dist print "dist from coords ", distfinal print "coords2 initial energy", mysys.getEnergy(coords2in) print "coords2 final energy ", mysys.getEnergy(coords2) print "coords1 initial energy", mysys.getEnergy(coords1in) print "coords1 final energy ", mysys.getEnergy(coords1) printlist.append((coords1.copy(), "coords1 after mindist")) printlist.append((coords2.copy(), "coords2 after mindist")) import pygmin.printing.print_atoms_xyz as printxyz with open("otp.xyz", "w") as fout: for coords, line2 in printlist: xyz = mysys.getxyz(coords) printxyz.printAtomsXYZ(fout, xyz, line2=line2, atom_type = ["N", "O", "O"]) return dist, coords1, coords2
def runtest(self, X1, X2): X1i = np.copy(X1) X2i = np.copy(X2) (distreturned, X1, X2) = minPermDistRBMol(X1, X2, mysys=self.pot, permlist=self.permlist) distinit = getDistaa(X1i, X2i, self.pot) distfinal = getDistaa(X1 , X2, self.pot) self.assertTrue( abs(distfinal- distreturned) < 1e-14, "returned distance is wrong: %g != %g" % (distfinal, distreturned) ) self.assertTrue( distfinal <= distinit ) #test if the energies have changed Ei = self.pot.getEnergy(X1i) Ef = self.pot.getEnergy(X1) self.assertTrue( abs(Ei- Ef) < 1e-12, "Energy of X1 changed: %g - %g = %g" % (Ei, Ef, Ei - Ef) ) Ei = self.pot.getEnergy(X2i) Ef = self.pot.getEnergy(X2) self.assertTrue( abs(Ei- Ef) < 1e-12, "Energy of X2 changed: %g - %g = %g" % (Ei, Ef, Ei - Ef) ) return distreturned, X1, X2
def minPermDistRBMol(coords1, coords2, mysys, niter=100, permlist=None, verbose=False): """ Minimize the distance between two clusters. The following symmetries will be accounted for Translational symmetry Global rotational symmetry Permutational symmetry This method uses basin hopping to find the rotation of X2 which best optimizes the overlap (an effective energy) between X1 and X2. The overlap is chosen to be permutation independent. Once the rotation is optimized, the correct permutation of rigid bodies can be determined deterministically using the Hungarian algorithm. Finally input: coords1, coords2: the structures for which to minimize the distance in com + angle-axis format permlist ([range(natoms)]) A list of lists of atoms which are interchangable. e.g. for a 50/50 binary mixture, permlist = [ range(1,natoms/2), range(natoms/2,natoms) ] """ nmol = mysys.nmol if permlist == None: permlist = [range(nmol)] ############################################### # move the centers of mass to the origin ############################################### #warning: this assumes all molecules have the same mass coords1[0:3 * nmol] = CoMToOrigin(coords1[0:3 * nmol]) coords2[0:3 * nmol] = CoMToOrigin(coords2[0:3 * nmol]) coords1in = coords1.copy() coords2in = coords2.copy() comcoords1 = copy.copy(coords1[0:3 * nmol]) comcoords2 = copy.copy(coords2[0:3 * nmol]) ############################################### # set initial conditions ############################################### aamin = np.array([0., 0., 0.]) ###################################### # set up potential, dependent only on the center of mass coords ###################################### pot = distpot.MinPermDistPotential(comcoords1, comcoords2, 0.4, permlist) #if False: #print some stuff. not necessary #Emin = pot.getEnergy(aamin) #dist, X11, X22 = findBestPermutationRBMol(coords1, aa2xyz(X2in, aamin), permlist ) #print "initial energy", Emin, "dist", dist saveit = storage.SaveN(20) takestep = distpot.RandomRotationTakeStep() bh = basinhopping.BasinHopping(aamin, pot, takestep, storage=saveit.insert, outstream=None) Eminglobal = pot.globalEnergyMin() #condition for determining isomer if verbose: print "global Emin", Eminglobal ########################################################################## # run basin hopping for ninter steps or until the global minimum is found # (i.e. determine they are isomers) ########################################################################## if verbose: print "using basin hopping to optimize rotations + permutations" for i in range(niter): bh.run(1) Emin = saveit.data[0].energy if abs(Emin - Eminglobal) < 1e-6: print "isomer found" break """ Lower energies generally mean smaller distances, but it's not guaranteed. Check a number of the lowest energy structures. To ensure get the correct minimum distance structure. """ if verbose: print "lowest structures found" aamin = saveit.data[0].coords dmin = 1000. for min in saveit.data: aa = min.coords coords2 = coordsApplyRotation(coords2in, aa) dist, X11, X22 = findBestPermutationRBMol(coords1, coords2, mysys, permlist) if verbose: print "E %11.5g dist %11.5g" % (min.energy, dist) if dist < dmin: dmin = dist aamin = aa.copy() ################################################################### #we've optimized the rotation in a permutation independent manner #now optimize the permutation ################################################################### dbefore = getDistaa(coords1, coords2in, mysys) coords2 = coordsApplyRotation(coords2in, aamin) dafter = getDistaa(coords1, coords2, mysys) if verbose: print "dist before, after applying rotation from basin hopping", dbefore, dafter, mysys.getEnergy( coords2in), mysys.getEnergy(coords2) dmin, coords1, coords2min = findBestPermutationRBMol( coords1, coords2, mysys, permlist) #dafter = getDistaa(coords1, coords2min, mysys) if verbose: print "dist findBestPerm", dmin, mysys.getEnergy(coords2min) ################################################################### # permutations are set, do one final mindist improve accuracy #of rotation optimization ################################################################### #dmin, X2min = alignRotation( X1, X2min ) ################################################################### #minimize the cartesian distance between the angle axis coords #by applying symmetry operations. ################################################################### for i in range(3 * nmol, 2 * 3 * nmol, 3): aadistance(coords1[i:i + 3], coords2min[i:i + 3]) return dmin, coords1, coords2min
def minPermDistRBMol(coords1, coords2, mysys, niter = 100, permlist = None, verbose=False): """ Minimize the distance between two clusters. The following symmetries will be accounted for Translational symmetry Global rotational symmetry Permutational symmetry This method uses basin hopping to find the rotation of X2 which best optimizes the overlap (an effective energy) between X1 and X2. The overlap is chosen to be permutation independent. Once the rotation is optimized, the correct permutation of rigid bodies can be determined deterministically using the Hungarian algorithm. Finally input: coords1, coords2: the structures for which to minimize the distance in com + angle-axis format permlist ([range(natoms)]) A list of lists of atoms which are interchangable. e.g. for a 50/50 binary mixture, permlist = [ range(1,natoms/2), range(natoms/2,natoms) ] """ nmol = mysys.nmol if permlist == None: permlist = [range(nmol)] ############################################### # move the centers of mass to the origin ############################################### #warning: this assumes all molecules have the same mass coords1[0:3*nmol] = CoMToOrigin(coords1[0:3*nmol]) coords2[0:3*nmol] = CoMToOrigin(coords2[0:3*nmol]) coords1in = coords1.copy() coords2in = coords2.copy() comcoords1 = copy.copy(coords1[0:3*nmol]) comcoords2 = copy.copy(coords2[0:3*nmol]) ############################################### # set initial conditions ############################################### aamin = np.array([0.,0.,0.]) ###################################### # set up potential, dependent only on the center of mass coords ###################################### pot = distpot.MinPermDistPotential( comcoords1, comcoords2, 0.4, permlist ) #if False: #print some stuff. not necessary #Emin = pot.getEnergy(aamin) #dist, X11, X22 = findBestPermutationRBMol(coords1, aa2xyz(X2in, aamin), permlist ) #print "initial energy", Emin, "dist", dist saveit = storage.SaveN( 20 ) takestep = distpot.RandomRotationTakeStep() bh = basinhopping.BasinHopping( aamin, pot, takestep, storage=saveit.insert, outstream=None) Eminglobal = pot.globalEnergyMin() #condition for determining isomer if verbose: print "global Emin", Eminglobal ########################################################################## # run basin hopping for ninter steps or until the global minimum is found # (i.e. determine they are isomers) ########################################################################## if verbose: print "using basin hopping to optimize rotations + permutations" for i in range(niter): bh.run(1) Emin = saveit.data[0].energy if abs(Emin-Eminglobal) < 1e-6: print "isomer found" break """ Lower energies generally mean smaller distances, but it's not guaranteed. Check a number of the lowest energy structures. To ensure get the correct minimum distance structure. """ if verbose: print "lowest structures found" aamin = saveit.data[0].coords dmin = 1000. for min in saveit.data: aa = min.coords coords2 = coordsApplyRotation(coords2in, aa) dist, X11, X22 = findBestPermutationRBMol(coords1, coords2, mysys, permlist ) if verbose: print "E %11.5g dist %11.5g" % (min.energy, dist) if dist < dmin: dmin = dist aamin = aa.copy() ################################################################### #we've optimized the rotation in a permutation independent manner #now optimize the permutation ################################################################### dbefore = getDistaa(coords1, coords2in, mysys) coords2 = coordsApplyRotation(coords2in, aamin) dafter = getDistaa(coords1, coords2, mysys) if verbose: print "dist before, after applying rotation from basin hopping", dbefore, dafter, mysys.getEnergy(coords2in), mysys.getEnergy(coords2) dmin, coords1, coords2min = findBestPermutationRBMol(coords1, coords2, mysys, permlist ) #dafter = getDistaa(coords1, coords2min, mysys) if verbose: print "dist findBestPerm", dmin, mysys.getEnergy(coords2min) ################################################################### # permutations are set, do one final mindist improve accuracy #of rotation optimization ################################################################### #dmin, X2min = alignRotation( X1, X2min ) ################################################################### #minimize the cartesian distance between the angle axis coords #by applying symmetry operations. ################################################################### for i in range(3*nmol,2*3*nmol,3): aadistance( coords1[i:i+3], coords2min[i:i+3] ) return dmin, coords1, coords2min