def prepare_opt(self): if self.is_cos and self.align: procrustes(self.geometry) # Calculate initial forces before the first iteration self.coords.append(self.geometry.coords) self.forces.append(self.geometry.forces) self.energies.append(self.geometry.energy)
def optimize(self): if self.is_cos and self.align: procrustes(self.geometry) self.forces.append(self.geometry.forces) step = self.alpha*self.forces[-1] step = self.scale_by_max_step(step) return step
def optimize(self): if self.is_cos and self.align: procrustes(self.geometry) self.forces.append(self.geometry.forces) self.energies.append(self.geometry.energy) if self.cur_cycle > 0: self.skip = self.backtrack(self.forces[-1], self.forces[-2]) step = self.alpha*self.forces[-1] step = self.scale_by_max_step(step) return step
def align(geoms): """Align all geometries onto the first using partical procrustes.""" cos = ChainOfStates.ChainOfStates(geoms) procrustes(cos) return [geom for geom in cos.images]
def optimize(self): new_image_inds = self.geometry.new_image_inds string_size_changed = len(new_image_inds) > 0 if self.align and string_size_changed and self.is_cart_opt: procrustes(self.geometry) self.log("Aligned string.") forces = self.geometry.forces self.energies.append(self.geometry.energy) self.forces.append(forces) cur_size = self.geometry.string_size add_to_list = ( self.keep_last > 0 # Only add to s_list and y_list if we want to keep and self.cur_cycle > 0 # cycles and if we can actually calculate differences. and (not self. lbfgs_when_full # Add when LBFGS is allowed before fully grown. or self.lbfgs_when_full and self.geometry.fully_grown and not string_size_changed # Don't add when string has to be fully grown # but grew fully in this cycle. )) if add_to_list: inds = list(range(cur_size)) try: y = self.forces[-2] - forces s = self.coords[-1] - self.coords[-2] # Will be raised when the string grew in the previous cycle. except ValueError: cur_forces = np.delete(forces.reshape(cur_size, -1), new_image_inds, axis=0).flatten() y = self.forces[-2] - cur_forces cur_coords = np.delete(self.coords[-1].reshape(cur_size, -1), new_image_inds, axis=0).flatten() s = self.coords[-2] - cur_coords inds = np.delete(inds, new_image_inds) if self.double_damp: s, y = double_damp(s, y, s_list=self.s_list, y_list=self.y_list) self.s_list.append(s) self.y_list.append(y) self.inds.append(inds) # Drop oldest vectors self.s_list = self.s_list[-self.keep_last:] self.y_list = self.y_list[-self.keep_last:] self.inds = self.inds[-self.keep_last:] # Results in steepest descent step for empty s_list & y_list step = bfgs_multiply(self.s_list, self.y_list, forces, gamma_mult=self.gamma_mult, inds=self.inds, cur_size=cur_size, logger=self.logger) # When keep_last == 0 or LBFGS is not yet enabled then s_list and y_list will # be empty and step will be a simple SD step. We try to improve it via CG. if ((self.keep_last == 0 and self.cur_cycle > 0 and not string_size_changed) and (len(self.s_list) == 0 and len(self.y_list) == 0)): prev_forces = self.forces[-2] # Fletcher-Reeves beta = forces.dot(forces) / prev_forces.dot(prev_forces) # Polar-Ribiere # beta = forces.dot(forces - prev_forces) / prev_forces.dot(prev_forces) beta = min(beta, 1) step = forces + beta * self.steps[-1] self.log(f"Conjugate gradient correction, β={beta:.6f}") if self.scale_step == "global": step = scale_by_max_step(step, self.max_step) elif self.scale_step == "per_image": for image_step in step.reshape(len(self.geometry.images), -1): scale_by_max_step(image_step, self.max_step) else: raise Exception("Invalid scale_step={self.scale_step}!") return step
def prepare_opt(self): if self.align and self.is_cart_opt: procrustes(self.geometry)