コード例 #1
0
    def optimize(self):
        forces = self.geometry.forces
        energy = self.geometry.energy
        self.forces.append(forces)
        self.energies.append(energy)

        if self.cur_cycle > 0:
            # Gradient difference
            y = self.forces[-2] - forces
            # Coordinate difference / step
            s = self.steps[-1]
            # Curvature condition
            sy = s.dot(y)
            self.log(f"s·y={sy:.6f} (undamped)")
            # Hessian update
            self.update_func(s, y)

        # Results in simple SD step in the first cycle
        step = self.H.dot(forces)
        self.log(f"Calcualted {self.update} step")

        # Step restriction
        unscaled_norm = np.linalg.norm(step)
        step = scale_by_max_step(step, self.max_step)
        scaled_norm = np.linalg.norm(step)
        self.log(f"Unscaled norm(step)={unscaled_norm:.4f}")
        self.log(f"  Scaled norm(step)={scaled_norm:.4f}")

        return step
コード例 #2
0
ファイル: LBFGS.py プロジェクト: ms860309/pysisyphus
    def optimize(self):
        if self.is_cos and self.align:
            rot_vecs, rot_vec_lists, _ = fit_rigid(
                self.geometry,
                vector_lists=(self.steps, self.forces, self.coord_diffs,
                              self.grad_diffs))
            rot_steps, rot_forces, rot_coord_diffs, rot_grad_diffs = rot_vec_lists
            self.steps = rot_steps
            self.forces = rot_forces
            self.coord_diffs = rot_coord_diffs
            self.grad_diffs = rot_grad_diffs

        forces = self.geometry.forces
        self.forces.append(forces)
        energy = self.geometry.energy
        self.energies.append(energy)
        norm = np.linalg.norm(forces)
        self.log(f"norm(forces)={norm:.6f}")

        if self.cur_cycle > 0:
            y = self.forces[-2] - forces
            s = self.steps[-1]
            if self.double_damp:
                s, y = double_damp(s,
                                   y,
                                   s_list=self.coord_diffs,
                                   y_list=self.grad_diffs)
            self.grad_diffs.append(y)
            self.coord_diffs.append(s)

            # Drop superfluous oldest vectors
            self.coord_diffs = self.coord_diffs[-self.keep_last:]
            self.grad_diffs = self.grad_diffs[-self.keep_last:]

        step = bfgs_multiply(self.coord_diffs,
                             self.grad_diffs,
                             forces,
                             beta=self.beta,
                             gamma_mult=self.gamma_mult,
                             logger=self.logger)
        step = scale_by_max_step(step, self.max_step)

        return step
コード例 #3
0
    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
コード例 #4
0
    def optimize(self):
        gradient = self.geometry.gradient
        energy = self.geometry.energy
        self.forces.append(-gradient)
        self.energies.append(energy)
        self.log(f"norm(forces)={np.linalg.norm(gradient):.4e}")

        if self.bio:
            stretch_gradient, remainder_gradient = self.bio_mode(gradient)
            self.adjust_alpha_stretch()
            # Steepest descent against the stretch_gradient
            stretch_step = -self.alpha_stretch * stretch_gradient
            new_coords = self.geometry.coords + stretch_step
            self.geometry.coords = new_coords
            # Use only the remaining gradient for the rest of this method
            gradient = remainder_gradient

        self.gradients_for_precon.append(gradient)
        self.coords_for_precon.append(self.geometry.coords.copy())

        if len(self.coords_for_precon) > 2:
            steps = np.diff(self.coords_for_precon, axis=0)[-self.hist_max:]
            grad_diffs = np.diff(self.gradients_for_precon,
                                 axis=0)[-self.hist_max:]

            self.log("Preconditioning gradient with information from "
                     f"{len(steps)+1} previous cycles.")
            precon_grad = self.precondition_gradient(gradient, steps,
                                                     grad_diffs, self.eps)
            step = -precon_grad
        else:
            self.log("Took pure steepest descent step.")
            step = self.alpha * -gradient
            scale_by_max_step(step, self.trust_radius)

        if self.linesearch:
            # Calculate energy at new geometry
            new_coords = self.geometry.coords + step
            _ = self.geometry.get_energy_and_forces_at(new_coords)
            new_energy = _["energy"]
            delta_energy = new_energy - energy
            self.log(f"Current energy is {energy:.6f} au. New energy is "
                     f"{new_energy:.6f} au, ΔE={delta_energy:.6f} au.")

            energy_rise_too_big = new_energy > (energy + self.E_thresh)
            alpha_still_big_enough = self.alpha > (self.alpha_start / 10)
            alpha_stre_still_big_enough = self.alpha_stretch > (
                self.alpha_stretch_start / 10)
            if energy_rise_too_big and alpha_still_big_enough and alpha_stre_still_big_enough:
                self.log(f"Energy increased by {delta_energy:.6f} au")
                self.gradients_for_precon = self.gradients_for_precon[-2:-1]
                self.coords_for_precon = self.coords_for_precon[-2:-1]
                self.log("Resetted history.")
                self.alpha /= 2
                self.alpha_stretch /= 2

                self.log(f"Decreased alpha to {self.alpha}")
                self.log("Reverting bad step")
                return None

        return step