Source code for pysisyphus.cos.FreezingString

import numpy as np

from pysisyphus.Geometry import Geometry


[docs] class FreezingString: def __init__(self, images, calc_getter, max_nodes=10, opt_steps=3): self.images = images self.calc_getter = calc_getter self.opt_steps = opt_steps self.max_nodes = int(max_nodes) assert self.max_nodes % 2 == 0, "max_nodes must be a multiple of 2!" left_frontier, right_frontier = self.images self.left_string = [left_frontier, ] self.right_string = [right_frontier, ] self.opt_steps_left = self.opt_steps self._forces = None self.atoms = left_frontier.atoms coord_diff = np.linalg.norm(right_frontier.coords - left_frontier.coords) self.step_length = coord_diff / (self.max_nodes+1) self.set_new_frontier_nodes() self.coord_type = "cart" @property def left_frontier(self): return self.left_string[-1] @property def right_frontier(self): return self.right_string[0]
[docs] def get_tangent(self): tangent = self.right_frontier.coords - self.left_frontier.coords tangent /= np.linalg.norm(tangent) return tangent
@property def forces(self): left_forces = self.left_frontier.forces right_forces = self.right_frontier.forces forces = (left_forces, right_forces) tangent = self.get_tangent() perp_forces = np.array([f - f.dot(tangent)*tangent for f in forces]).flatten() self._forces = perp_forces self.energies = [self.left_frontier.energy, self.right_frontier.energy] return self._forces
[docs] def as_xyz(self): return ""
@property def fully_grown(self): return (len(self.left_string) + len(self.right_string) == self.max_nodes + 2) @property def energy(self): return 10 # return self.energies
[docs] def set_new_frontier_nodes(self): tangent = self.get_tangent() new_left_coords = self.left_frontier.coords + tangent*self.step_length new_left_frontier = Geometry(self.atoms, new_left_coords) new_left_frontier.set_calculator(self.calc_getter()) self.left_string.append(new_left_frontier) new_right_coords = self.right_frontier.coords - tangent*self.step_length new_right_frontier = Geometry(self.atoms, new_right_coords) new_right_frontier.set_calculator(self.calc_getter()) self.right_string.insert(0, new_right_frontier)
[docs] def get_new_image(self, coords, index): new_image = Geometry(self.left_frontier.atoms, coords) new_image.set_calculator(self.calc_getter()) self.images.insert(index, new_image) self.log(f"Create new image; insert it before index {index}.") return new_image
[docs] def reparametrize(self): self.opt_steps_left -= 1 if not self.fully_grown and self.opt_steps_left == 0: self.set_new_frontier_nodes() self.opt_steps_left = self.opt_steps
@property def allcoords(self): return np.array([img.coords for img in self.left_string + self.right_string]).flatten() @property def coords(self): return np.array((self.left_frontier.coords, self.right_frontier.coords)).flatten() @coords.setter def coords(self, coords): left, right = coords.reshape(2, -1) self.left_frontier.coords = left self.right_frontier.coords = right