def move(self, ro, bests): """Move atoms by a random step.""" atoms = self.atoms velocity = copy.deepcopy(self.velocity) best_to_use = bests[-1] best_dist = 1e32 for i in bests: d = i.get_bcm() - self.get_bcm() di = np.sqrt(np.vdot(d,d)) if(di<best_dist): best_to_use = i best_dist = di print "using best: ", best_to_use.get_bcm() # PSO heuristic for i in range(len(ro)): for j in range(3): velocity[i][j] = self.inertia_weight*velocity[i][j] + random.uniform(0,2)*(self.rmin[i][j]-ro[i][j]) + random.uniform(0,2)*(best_to_use.positions[i][j]-ro[i][j]) rn = ro + velocity rn = self.push_apart(rn) atoms.set_positions(rn) En = self.get_energy(rn) cm = atoms.get_center_of_mass() atoms.translate(self.cm - cm) rn = atoms.get_positions() world.broadcast(rn, 0) atoms.set_positions(rn) return En,atoms.get_positions(),velocity
def _startup(self): """Initiates a run, and determines if running from previous data or a fresh run.""" status = np.array(-1.) exists = self._read_minima() if world.rank == 0: if not exists: # Fresh run with new minima file. status = np.array(0.) elif not os.path.exists(self._logfile): # Fresh run with existing or shared minima file. status = np.array(1.) else: # Must be resuming from within a working directory. status = np.array(2.) world.barrier() world.broadcast(status, 0) if status == 2.: self._resume() else: self._counter = 0 self._log('init') self._log('msg', 'Performing initial optimization.') if status == 1.: self._log( 'msg', 'Using existing minima file with %i prior ' 'minima: %s' % (len(self._minima), self._minima_traj)) self._optimize() self._check_results() self._counter += 1
def _startup(self): """Initiates a run, and determines if running from previous data or a fresh run.""" status = np.array(-1.) exists = self._read_minima() if rank == 0: if not exists: # Fresh run with new minima file. status = np.array(0.) elif not os.path.exists(self._logfile): # Fresh run with existing or shared minima file. status = np.array(1.) else: # Must be resuming from within a working directory. status = np.array(2.) world.barrier() world.broadcast(status, 0) if status == 2.: self._resume() else: self._counter = 0 self._log('init') self._log('msg', 'Performing initial optimization.') if status == 1.: self._log('msg', 'Using existing minima file with %i prior ' 'minima: %s' % (len(self._minima), self._minima_traj)) self._optimize() self._check_results() self._counter += 1
def move(self, step, ro, distribution): """Move atoms by a random step or MD""" # random move (BH move) if distribution != 'molecular_dynamics': if distribution == 'uniform': disp = np.random.uniform(-self.dr, self.dr, (len(self.atoms), 3)) elif distribution == 'gaussian': disp = np.random.normal(0, self.dr, size=(len(self.atoms), 3)) elif distribution == 'linear': distgeo = self.get_dist_geo_center() disp = np.zeros(np.shape(self.atoms.get_positions())) for i in range(len(disp)): maxdist = self.dr * distgeo[i] disp[i] = np.random.uniform(-maxdist, maxdist, 3) elif distribution == 'quadratic': distgeo = self.get_dist_geo_center() disp = np.zeros(np.shape(self.atoms.get_positions())) for i in range(len(disp)): maxdist = self.dr * distgeo[i] * distgeo[i] disp[i] = np.random.uniform(-maxdist, maxdist, 3) # there is a typo in distribution or jump distribution else: print 'distribution flag has typo' sys.exit() disp = np.random.uniform(-1 * self.dr, self.dr, (len(self.atoms), 3)) # update atoms positions by the random move rn = ro + disp rn = self.push_apart(rn) self.atoms.set_positions(rn) # refix the center of mass after random move if self.cm is not None: cm = self.atoms.get_center_of_mass() self.atoms.translate(self.cm - cm) # MD move (MH move) else: N = None # use the dimer method to create an initial velocity vector for MD if self.dimer_method: dimer = ModifiedDimer() N = dimer(self.atoms, self.dimer_a, self.dimer_d, self.dimer_steps) self._molecular_dynamics(step, N) rn = self.atoms.get_positions() world.broadcast(rn, 0) return rn
def calculate_energies_and_forces(self, all=False): """Calculate and store the forces and energies for the band.""" images = self.images if all: self.forces['real'][0] = images[0].get_forces() self.forces['real'][-1] = images[-1].get_forces() if not self.integrate_forces: self.energies[0] = images[0].get_potential_energy() self.energies[-1] = images[-1].get_potential_energy() if not self.parallel: # Do all images - one at a time: for i in range(1, self.nimages - 1): self.calculate_image_forces(i) for i in range(1, self.nimages - 1): self.calculate_image_energies(i) else: # Parallelize over images: first the forces ... i = rank * (self.nimages - 2) // size + 1 try: self.calculate_image_forces(i) except: # Make sure other images also fail: error = world.sum(1.0) raise else: error = world.sum(0.0) if error: raise RuntimeError('Parallel NEB failed') for i in range(1, self.nimages - 1): root = (i - 1) * size // (self.nimages - 2) world.broadcast(self.forces['real'][i], root) # ... and now the energies try: self.calculate_image_energies(i) except: # Make sure other images also fail: error = world.sum(1.0) raise else: error = world.sum(0.0) if error: raise RuntimeError('Parallel NEB failed') for i in range(1, self.nimages - 1): root = (i - 1) * size // (self.nimages - 2) world.broadcast(self.energies[i : i + 1], root) if all and self.integrate_forces: # fill in the first and last energies by force integration self.energies[0] = 0. self.calculate_image_energies(len(self.images)-1)
def move(self, ro): """Move atoms by a random step.""" atoms = self.atoms disp = np.zeros(np.shape(atoms.get_positions())) while np.alltrue(disp == np.zeros(np.shape(atoms.get_positions()))): if self.distribution == 'uniform': disp = np.random.uniform(-self.dr, self.dr, (len(atoms), 3)) elif self.distribution == 'gaussian': disp = np.random.normal(0, self.dr, size=(len(atoms), 3)) elif self.distribution == 'linear': distgeo = self.get_dist_geo_center() disp = np.zeros(np.shape(atoms.get_positions())) for i in range(len(disp)): maxdist = self.dr * distgeo[i] # disp[i] = np.random.normal(0,maxdist,3) disp[i] = np.random.uniform(-maxdist, maxdist, 3) elif self.distribution == 'quadratic': distgeo = self.get_dist_geo_center() disp = np.zeros(np.shape(atoms.get_positions())) for i in range(len(disp)): maxdist = self.dr * distgeo[i] * distgeo[i] # disp[i] = np.random.normal(0,maxdist,3) disp[i] = np.random.uniform(-maxdist, maxdist, 3) else: disp = np.random.uniform(-1 * self.dr, self.dr, (len(atoms), 3)) #Lei: set all other disp to zero except those selected to move # the number of atoms that can be moved is defined by int(active_ratio * len(atoms)) if self.active_ratio is not None: fix_space = len(atoms) - int(self.active_ratio * len(atoms)) fix_atoms = random.sample(range(len(atoms)), fix_space) for i in range(len(fix_atoms)): disp[fix_atoms[i]] = (0.0, 0.0, 0.0) #Lei: suppose to only update 'ro' with local minimum when accept == true # if self.significant_structure == True: # rn = self.local_min_pos + disp # if self.significant_structure2 == True: # ro,reng = self.get_minimum() # rn = ro + disp # else: rn = ro + disp rn = self.push_apart(rn) atoms.set_positions(rn) if self.cm is not None: cm = atoms.get_center_of_mass() atoms.translate(self.cm - cm) rn = atoms.get_positions() world.broadcast(rn, 0) atoms.set_positions(rn) return atoms.get_positions()
def move(self, ro): """Move atoms by a random step.""" atoms = self.atoms # displace coordinates disp = np.random.uniform(-1., 1., (len(atoms), 3)) rn = ro + self.dr * disp atoms.set_positions(rn) if self.cm is not None: cm = atoms.get_center_of_mass() atoms.translate(self.cm - cm) rn = atoms.get_positions() world.broadcast(rn, 0) atoms.set_positions(rn) return atoms.get_positions()
def get_forces(self): images = self.images forces = np.empty(((self.nimages - 2), self.natoms, 3)) energies = np.empty(self.nimages - 2) if not self.parallel: # Do all images - one at a time: for i in range(1, self.nimages - 1): energies[i - 1] = images[i].get_potential_energy() forces[i - 1] = images[i].get_forces() else: # Parallelize over images: i = rank * (self.nimages - 2) // size + 1 energies[i - 1] = images[i].get_potential_energy() forces[i - 1] = images[i].get_forces() for i in range(1, self.nimages - 1): root = (i - 1) * size // (self.nimages - 2) world.broadcast(energies[i - 1:i], root) world.broadcast(forces[i - 1], root) imax = 1 + np.argsort(energies)[-1] self.emax = energies[imax - 1] tangent1 = images[1].get_positions() - images[0].get_positions() for i in range(1, self.nimages - 1): tangent2 = (images[i + 1].get_positions() - images[i].get_positions()) if i < imax: tangent = tangent2 elif i > imax: tangent = tangent1 else: tangent = tangent1 + tangent2 tt = np.vdot(tangent, tangent) f = forces[i - 1] ft = np.vdot(f, tangent) if i == imax and self.climb: f -= 2 * ft / tt * tangent else: f -= ft / tt * tangent f -= (np.vdot(tangent1 - tangent2, tangent) * self.k / tt * tangent) tangent1 = tangent2 return forces.reshape((-1, 3))
def move(self, ro): """Move atoms by a random step.""" atoms = self.atoms if self.distribution == 'uniform': disp = np.random.uniform(-self.dr, self.dr, (len(atoms), 3)) elif self.distribution == 'gaussian': disp = np.random.normal(0,self.dr,size=(len(atoms), 3)) elif self.distribution == 'linear': distgeo = self.get_dist_geo_center() disp = np.zeros(np.shape(atoms.get_positions())) for i in range(len(disp)): maxdist = self.dr*distgeo[i] # disp[i] = np.random.normal(0,maxdist,3) disp[i] = np.random.uniform(-maxdist,maxdist,3) elif self.distribution == 'quadratic': distgeo = self.get_dist_geo_center() disp = np.zeros(np.shape(atoms.get_positions())) for i in range(len(disp)): maxdist = self.dr*distgeo[i]*distgeo[i] # disp[i] = np.random.normal(0,maxdist,3) disp[i] = np.random.uniform(-maxdist,maxdist,3) ### EDIT CODE FOR PROBLEM 5 HERE ########################################### elif self.distribution == 'your_move': ## an example of distribution to pick is as follows: a fixed size move arr = np.random.rand(len(atoms), 3) for y in range(len(atoms)): for x in range(3): arr[y][x] = self.my_distribution(arr[y][x]) disp = self.dr * arr ############################################################################ else: disp = np.random.uniform(-1*self.dr, self.dr, (len(atoms), 3)) if self.significant_structure == True: ro,reng = self.get_minimum() rn = ro +disp else: rn = ro + disp rn = self.push_apart(rn) atoms.set_positions(rn) if self.cm is not None: cm = atoms.get_center_of_mass() atoms.translate(self.cm - cm) rn = atoms.get_positions() world.broadcast(rn, 0) atoms.set_positions(rn) return atoms.get_positions()
def move_del(self, ro, vectors): """Displace atoms by randomly selected delocalized 'normal mode' """ atoms = self.atoms[self.adsorbate[0]:self.adsorbate[1]] atms = self.atoms numvec = len(vectors) numcomb = self.numdelmodes while True: disp = np.zeros((len(ro), 3)) start = 0 #find way for start to be number of stretches if self.constr: mm = atoms.get_masses() x0 = atoms.get_positions().flatten() vv = VCG(atoms.get_chemical_symbols(), masses=mm) start = len( icSystem(vv(x0), len(atoms), masses=mm, xyz=x0).getStretchBendTorsOop()[0][0]) if numcomb > len(range(start, numvec)): numcomb = len(range(start, numvec)) w = np.random.choice(range(start, numvec), size=numcomb, replace=False) for i in w: disp[self.adsorbate[0]:( self.adsorbate[1]), :3] += vectors[i] * np.random.uniform( -1., 1.) #this is important if there is an adsorbate. disp /= np.max(np.abs(disp)) #from here on, everything is JUST COPIED from self.move(); should be sane rn = ro + self.dr * disp atms.set_positions(rn) if self.cm is not None: cm = atms.get_center_of_mass() atms.translate(self.cm - cm) rn = atms.get_positions() world.broadcast(rn, 0) atms.set_positions(rn) if self.check_distances(atoms): break else: print 'HIIIIGHWAY TO THE DANGERZONE!' atoms.write('Maverick.xyz') return atms.get_positions()
def get_forces(self): """Evaluate and return the forces.""" if self.parallel and self.images[1].minmode_init: propagate_initial_values = True else: propagate_initial_values = False # Update the clean forces and energies self.calculate_energies_and_forces() if self.parallel and propagate_initial_values: for i in range(1, self.nimages - 1): if self.images[i].eigenmodes is None: self.images[i].eigenmodes = [np.zeros(self.images[i].get_positions().shape)] self.images[i].minmode_init = False self.images[i].rotation_required = True self.images[i].check_atoms = self.images[i].atoms.copy() root = (i - 1) * size // (self.nimages - 2) world.broadcast(self.images[i].eigenmodes[0], root) # Update the highest energy image self.imax = 1 + np.argsort(self.energies[1:-1])[-1] self.emax = self.energies[self.imax] # BUG: self.imax can be an endimage. # Calculate the tangents of all the images self.update_tangents() # IDEA: If f_c_perp is small force dimer rotation? # Calculate the modes self.calculate_eigenmodes() # Prjoect the forces for each image self.invert_eigenmode_forces() self.project_forces(sort = 'dimer') if self.plot_devplot: self.plot_pseudo_3d_pes() self.control.increment_counter('optcount') return self.forces['neb'][1:self.nimages-1].reshape((-1, 3))
def move(self, ro): """Move atoms by a random step.""" atoms = self.atoms # displace coordinates disp = np.random.uniform(-1., 1., (len(atoms), 3)) rn = ro + self.dr * disp # exchange two atoms from numpy.random import randint ind = randint(0,12, size=2) postemp = rn[ind[0]].copy() rn[ind[0]] = rn[ind[1]] rn[ind[1]] = postemp # atoms.set_positions(rn) if self.cm is not None: cm = atoms.get_center_of_mass() atoms.translate(self.cm - cm) rn = atoms.get_positions() world.broadcast(rn, 0) atoms.set_positions(rn) return atoms.get_positions()
def move(self, ro, bests): """Move atoms by a random step.""" atoms = self.atoms velocity = copy.deepcopy(self.velocity) # PSO heuristic for i in range(len(ro)): for j in range(3): velocity[i][j] = self.inertia_weight*velocity[i][j] + random.uniform(0,2)*(self.rmin[i][j]-ro[i][j]) + random.uniform(0,2)*(bests[-1].positions[i][j]-ro[i][j]) rn = ro + velocity rn = self.push_apart(rn) atoms.set_positions(rn) En = self.get_energy(rn) cm = atoms.get_center_of_mass() atoms.translate(self.cm - cm) rn = atoms.get_positions() world.broadcast(rn, 0) atoms.set_positions(rn) return En,atoms.get_positions(),velocity
def calculate_eigenmodes(self): if self.parallel: i = rank * (self.nimages - 2) // size + 1 try: self.calculate_image_eigenmode(i) except: # Make sure other images also fail: error = world.sum(1.0) raise else: error = world.sum(0.0) if error: raise RuntimeError('Parallel ERM failed during eigenmode calculations.') for i in range(1, self.nimages - 1): if self.images[i].eigenmodes is None: self.images[i].eigenmodes = [np.zeros(self.images[i].get_positions().shape)] root = (i - 1) * size // (self.nimages - 2) world.broadcast(self.images[i].eigenmodes[0], root) # world.broadcast(self.images[i : i + 1].curvatures, root) else: for i in range(1, self.nimages - 1): self.calculate_image_eigenmode(i)
def move(self, ro): """Move atoms by a random step.""" atoms = self.atoms # displace coordinates #disp = np.random.uniform(-1., 1., (len(atoms), 3)) disp = np.random.uniform(-1.0, 1.0, (int(len(atoms) / 3), 3)) final_dis = [] for i in range(int(len(atoms) / 3)): d = disp[i].tolist() for i in range(3): final_dis.append(d) disp = np.array(final_dis) rn = ro + self.dr * disp atoms.set_positions(rn) if self.cm is not None: cm = atoms.get_center_of_mass() atoms.translate(self.cm - cm) print('ajusted') rn = atoms.get_positions() world.broadcast(rn, 0) atoms.set_positions(rn) return atoms.get_positions()
def calculate_energies_and_forces(self): images = self.images if not self.parallel: # Do all images - one at a time: for i in range(1, self.nimages - 1): self.calculate_image_energies_and_forces(i) else: # Parallelize over images: i = rank * (self.nimages - 2) // size + 1 try: self.calculate_image_energies_and_forces(i) except: # Make sure other images also fail: error = world.sum(1.0) raise else: error = world.sum(0.0) if error: raise RuntimeError('Parallel NEB failed') for i in range(1, self.nimages - 1): root = (i - 1) * size // (self.nimages - 2) world.broadcast(self.energies[i : i + 1], root) world.broadcast(self.forces['real'][i], root)
def test_attach_randomly(): """Attach two molecules in random orientation.""" m1 = molecule('C6H6') m2 = molecule('CF4') distance = 2.5 if world.size > 1: "Check that the coordinates are correctly distributed from master." rng = np.random.RandomState(world.rank) # ensure different seed atoms = attach_randomly_and_broadcast(m1, m2, distance, rng) p0 = 1. * atoms[-1].position world.broadcast(p0, 0) for i in range(1, world.size): pi = 1. * atoms[-1].position world.broadcast(pi, i) assert pi == pytest.approx(p0, 1e-8) "Check that every core has its own structure" rng = np.random.RandomState(world.rank) # ensure different seed atoms = attach_randomly(m1, m2, distance, rng) p0 = 1. * atoms[-1].position world.broadcast(p0, 0) for i in range(1, world.size): pi = 1. * atoms[-1].position world.broadcast(pi, i) assert pi != pytest.approx(p0, 1e-8) rng = np.random.RandomState(42) # ensure the same seed pos2_ac = np.zeros((5, 3)) N = 25 for i in range(N): atoms = attach_randomly(m1, m2, distance, rng=rng) pos2_ac += atoms.get_positions()[12:, :] # the average position should be "zero" approximately assert (np.abs(pos2_ac / N) <= 1).all()
def move(self, ro, bests): """Move atoms by a random step.""" atoms = self.atoms velocity = copy.deepcopy(self.velocity) do_pso = True if self.method == 'firefly': do_pso = False elif self.method == 'PSO_split': best_to_use = bests[-1] best_dist = 1e32 for i in bests: d = i.get_bcm() - self.get_bcm() di = np.sqrt(np.vdot(d,d)) if(di<best_dist): best_to_use = i best_dist = di do_pso = True else: do_pso = True best_to_use = bests[-1] # PSO heuristic if (not do_pso): r_arr = [None] * len(bests) r_sum = 0 pe_sum = 0 for i in range(len(bests)): d = self.get_bcm() - bests[i].get_bcm() r_arr[i] = np.sqrt(np.vdot(d,d)) r_sum += r_arr[i] pe_sum += bests[i].get_energy() r_mean = r_sum / len(bests) pe_mean = abs(pe_sum / len(bests)) denom = math.sqrt(r_mean*pe_mean) attract_arr = [None] * len(bests) for i in range(len(bests)): numer = bests[i].get_energy() * r_arr[i] numer *= numer attract_arr[i] = math.e**(-1*numer/denom) sort_attract = sorted(attract_arr) velocity = self.inertia_weight*velocity E = np.random.normal(1,.01*min(15,sort_attract[-2]/max(0.0001,sort_attract[-1])), size=(len(atoms),3)) for i in range(len(bests)): velocity += attract_arr[i]*(bests[i].positions-ro)*E/sort_attract[-1] else: print "using best: ", best_to_use.get_bcm() for i in range(len(ro)): for j in range(3): velocity[i][j] = self.inertia_weight*velocity[i][j] + random.uniform(0,2)*(self.rmin[i][j]-ro[i][j]) + random.uniform(0,2)*(best_to_use.positions[i][j]-ro[i][j]) rn = ro + velocity rn = self.push_apart(rn) atoms.set_positions(rn) En = self.get_energy(rn) cm = atoms.get_center_of_mass() atoms.translate(self.cm - cm) rn = atoms.get_positions() world.broadcast(rn, 0) atoms.set_positions(rn) return En,atoms.get_positions(),velocity