示例#1
0
文件: geop.py 项目: tomspur/i-pi
    def step(self, step=None):
        """ Does one simulation time step
            Attributes:
            ttime: The time taken in applying the thermostat steps.
        """

        self.qtime = -time.time()

        info("\nMD STEP %d" % step, verbosity.debug)

        if step == 0:
            info(" @GEOP: Initializing L-BFGS", verbosity.debug)
            print self.d
            self.d += dstrip(self.forces.f) / np.sqrt(np.dot(self.forces.f.flatten(), self.forces.f.flatten()))

        self.old_x[:] = self.beads.q
        self.old_u[:] = self.forces.pot
        self.old_f[:] = self.forces.f

        if len(self.fixatoms) > 0:
            for dqb in self.old_f:
                dqb[self.fixatoms * 3] = 0.0
                dqb[self.fixatoms * 3 + 1] = 0.0
                dqb[self.fixatoms * 3 + 2] = 0.0

            # Reduce the dimensionality
            masked_old_x = self.old_x[:, self.gm.fixatoms_mask]
            masked_d = self.d[:, self.gm.fixatoms_mask]
            # self.gm is reduced inside its __init__() and __call__() functions
            masked_qlist = self.qlist[:, self.gm.fixatoms_mask]
            masked_glist = self.glist[:, self.gm.fixatoms_mask]
            fdf0 = (self.old_u, -self.old_f[:, self.gm.fixatoms_mask])

            # We update everything within L_BFGS (and all other calls).
            L_BFGS(masked_old_x, masked_d, self.gm, masked_qlist, masked_glist, fdf0,
                   self.big_step, self.ls_options["tolerance"] * self.tolerances["energy"],
                   self.ls_options["iter"], self.corrections, self.scale, step)

            # Restore the dimensionality
            self.d[:, self.gm.fixatoms_mask] = masked_d
            self.qlist[:, self.gm.fixatoms_mask] = masked_qlist
            self.glist[:, self.gm.fixatoms_mask] = masked_glist

        else:
            fdf0 = (self.old_u, -self.old_f)

            # We update everything  within L_BFGS (and all other calls).
            L_BFGS(self.old_x, self.d, self.gm, self.qlist, self.glist, fdf0,
                   self.big_step, self.ls_options["tolerance"] * self.tolerances["energy"],
                   self.ls_options["iter"], self.corrections, self.scale, step)

        info("   Number of force calls: %d" % (self.gm.fcount)); self.gm.fcount = 0

        # Update positions and forces
        self.beads.q = self.gm.dbeads.q
        self.forces.transfer_forces(self.gm.dforces)  # This forces the update of the forces

        # Exit simulation step
        d_x_max = np.amax(np.absolute(np.subtract(self.beads.q, self.old_x)))
        self.exitstep(self.forces.pot, self.old_u, d_x_max)
示例#2
0
    def step(self, step=None):
        """ Does one simulation time step
            Attributes:
            ttime: The time taken in applying the thermostat steps.
        """

        self.qtime = -time.time()

        info("\nMD STEP %d" % step, verbosity.debug)

        if step == 0:
            info(" @GEOP: Initializing L-BFGS", verbosity.debug)
            self.d += depstrip(self.forces.f) / np.sqrt(
                np.dot(self.forces.f.flatten(), self.forces.f.flatten()))

        self.old_x[:] = self.beads.q
        self.old_u[:] = self.forces.pot
        self.old_f[:] = self.forces.f
        if len(self.fixatoms) > 0:

            for dqb in self.old_f:
                dqb[self.fixatoms * 3] = 0.0
                dqb[self.fixatoms * 3 + 1] = 0.0
                dqb[self.fixatoms * 3 + 2] = 0.0

        fdf0 = (self.old_u, -self.old_f)
        #d_x,new_d, new_qlist, new_glist = L_BFGS(self.old_x,
        # Note that the line above is not needed anymore because we update everything
        # within L_BFGS (and all other calls).
        L_BFGS(self.old_x, self.d, self.gm, self.qlist, self.glist, fdf0,
               self.big_step,
               self.ls_options["tolerance"] * self.tolerances["energy"],
               self.ls_options["iter"], self.corrections, self.scale, step)

        info("   Number of force calls: %d" % (self.gm.fcount))
        self.gm.fcount = 0
        #Update positions and forces
        self.beads.q = self.gm.dbeads.q
        self.forces.transfer_forces(
            self.gm.dforces)  #This forces the update of the forces

        # Exit simulation step
        d_x_max = np.amax(np.absolute(np.subtract(self.beads.q, self.old_x)))
        self.exitstep(self.forces.pot, self.old_u, d_x_max)
示例#3
0
    def step(self, step=None):
        """Does one simulation time step."""

        self.ptime = 0.0
        self.ttime = 0.0
        self.qtime = -time.time()

        info("\nMD STEP %d" % step, verbosity.debug)

        if self.mode == "bfgs":

            # BFGS Minimization
            # Initialize approximate Hessian inverse to the identity and direction
            # to the steepest descent direction
            if step == 0:   # or np.sqrt(np.dot(self.bfgsm.d, self.bfgsm.d)) == 0.0: <-- this part for restarting at claimed minimum (optional)
                info(" @GEOP: Initializing BFGS", verbosity.debug)
                self.bfgsm.d = depstrip(self.forces.f) / np.sqrt(np.dot(self.forces.f.flatten(), self.forces.f.flatten()))
                self.bfgsm.xold = self.beads.q.copy()

            # Current energy and forces
            u0 = self.forces.pot.copy()
            du0 = - self.forces.f

            # Store previous forces
            self.cg_old_f[:] = self.forces.f

            # Do one iteration of BFGS, return new point, function value,
            # move direction, and current Hessian to use for next iteration
            self.beads.q, fx, self.bfgsm.d, self.invhessian = BFGS(self.beads.q,
                self.bfgsm.d, self.bfgsm, fdf0=(u0, du0), invhessian=self.invhessian,
                max_step=self.max_step, tol=self.ls_options["tolerance"],
                itmax=self.ls_options["iter"])

            # x = current position - previous position; use for exit tolerance
            x = np.amax(np.absolute(np.subtract(self.beads.q, self.bfgsm.xold)))

            # Store old position
            self.bfgsm.xold[:] = self.beads.q

            info(" @GEOP: Updating bead positions", verbosity.debug)

        elif self.mode == "lbfgs":

            # L-BFGS Minimization
            # Initialize approximate Hessian inverse to the identity and direction
            # to the steepest descent direction
            # Initialize lists of previous positions and gradient
            if step == 0:   # or np.sqrt(np.dot(self.bfgsm.d, self.bfgsm.d)) == 0.0: <-- this part for restarting at claimed minimum (optional)
                info(" @GEOP: Initializing L-BFGS", verbosity.debug)
                self.bfgsm.d = depstrip(self.forces.f) / np.sqrt(np.dot(self.forces.f.flatten(), self.forces.f.flatten()))
                self.bfgsm.xold = self.beads.q.copy()
                self.qlist = np.zeros((self.corrections, len(self.beads.q.flatten())))
                self.glist = np.zeros((self.corrections, len(self.beads.q.flatten())))

            # Current energy and force
            u0, du0 = (self.forces.pot.copy(), - self.forces.f)

            # Store previous forces
            self.cg_old_f[:] = self.forces.f.reshape(len(self.cg_old_f))

            # Do one iteration of L-BFGS, return new point, function value,
            # move direction, and current Hessian to use for next iteration
            self.beads.q, fx, self.bfgsm.d, self.qlist, self.glist = L_BFGS(self.beads.q,
                self.bfgsm.d, self.bfgsm, self.qlist, self.glist,
                fdf0=(u0, du0), max_step=self.max_step, tol=self.ls_options["tolerance"],
                itmax=self.ls_options["iter"],
                m=self.corrections, k=step)

            info(" @GEOP: Updated position list", verbosity.debug)
            info(" @GEOP: Updated gradient list", verbosity.debug)

            # x = current position - old position. Used for convergence tolerance
            x = np.amax(np.absolute(np.subtract(self.beads.q, self.bfgsm.xold)))

            # Store old position
            self.bfgsm.xold[:] = self.beads.q

            info(" @GEOP: Updated bead positions", verbosity.debug)

        # Routine for steepest descent and conjugate gradient
        else:
            if (self.mode == "sd" or step == 0):

                # Steepest descent minimization
                # gradf1 = force at current atom position
                # dq1 = direction of steepest descent
                # dq1_unit = unit vector of dq1
                gradf1 = dq1 = depstrip(self.forces.f)

                # Move direction for steepest descent and 1st conjugate gradient step
                dq1_unit = dq1 / np.sqrt(np.dot(gradf1.flatten(), gradf1.flatten()))
                info(" @GEOP: Determined SD direction", verbosity.debug)

            else:

                # Conjugate gradient, Polak-Ribiere
                # gradf1: force at current atom position
                # gradf0: force at previous atom position
                # dq1 = direction to move
                # dq0 = previous direction
                # dq1_unit = unit vector of dq1
                gradf0 = self.cg_old_f
                dq0 = self.cg_old_d
                gradf1 = depstrip(self.forces.f)
                beta = np.dot((gradf1.flatten() - gradf0.flatten()), gradf1.flatten()) / (np.dot(gradf0.flatten(), gradf0.flatten()))
                dq1 = gradf1 + max(0.0, beta) * dq0
                dq1_unit = dq1 / np.sqrt(np.dot(dq1.flatten(), dq1.flatten()))
                info(" @GEOP: Determined CG direction", verbosity.debug)

            # Store force and direction for next CG step
            self.cg_old_d[:] = dq1
            self.cg_old_f[:] = gradf1

            if len(self.fixatoms) > 0:
                for dqb in dq1_unit:
                    dqb[self.fixatoms*3] = 0.0
                    dqb[self.fixatoms*3+1] = 0.0
                    dqb[self.fixatoms*3+2] = 0.0

            self.lm.set_dir(depstrip(self.beads.q), dq1_unit)

            # Reuse initial value since we have energy and forces already
            u0, du0 = (self.forces.pot.copy(), np.dot(depstrip(self.forces.f.flatten()), dq1_unit.flatten()))

            # Do one SD/CG iteration; return positions and energy
            (x, fx) = min_brent(self.lm, fdf0=(u0, du0), x0=0.0,
                    tol=self.ls_options["tolerance"],
                    itmax=self.ls_options["iter"], init_step=self.ls_options["step"])

            # Automatically adapt the search step for the next iteration.
            # Relaxes better with very small step --> multiply by factor of 0.1 or 0.01
            self.ls_options["step"] = 0.1 * x * self.ls_options["adaptive"] + (1 - self.ls_options["adaptive"]) * self.ls_options["step"]

            self.beads.q += dq1_unit * x
            info(" @GEOP: Updated bead positions", verbosity.debug)

        self.qtime += time.time()

        # Determine conditions for converged relaxation
        if ((fx - u0) / self.beads.natoms <= self.tolerances["energy"])\
                and ((np.amax(np.absolute(self.forces.f)) <= self.tolerances["force"])
                    or (np.sqrt(np.dot(self.forces.f.flatten() - self.cg_old_f.flatten(),
                        self.forces.f.flatten() - self.cg_old_f.flatten())) == 0.0))\
                and (x <= self.tolerances["position"]):
            softexit.trigger("Geometry optimization converged. Exiting simulation")
示例#4
0
    def step(self, step=None):
        """Does one simulation time step."""

        info("\nMD STEP %d" % step, verbosity.debug)

        # Fetch spring constants
        self.nebbfgsm.kappa = self.spring["kappa"]
        self.neblm.kappa = self.spring["kappa"]

        self.ptime = self.ttime = 0
        self.qtime = -time.time()

        if self.mode == "lbfgs":

            # L-BFGS Minimization
            # Initialize direction to the steepest descent direction
            if step == 0:  # or np.sqrt(np.dot(self.bfgsm.d, self.bfgsm.d)) == 0.0: <-- this part for restarting at claimed minimum
                info(" @GEOP: Initializing L-BFGS", verbosity.debug)
                fx, nebgrad = self.nebbfgsm(self.beads.q)

                # Set direction to direction of NEB forces
                self.nebbfgsm.d = -nebgrad
                self.nebbfgsm.xold = self.beads.q.copy()

                # Initialize lists of previous positions and gradients
                self.qlist = np.zeros(
                    (self.corrections, len(self.beads.q.flatten())))
                self.glist = np.zeros(
                    (self.corrections, len(self.beads.q.flatten())))

            else:
                fx, nebgrad = self.nebbfgsm(self.beads.q)

            # Intial gradient and gradient modulus
            u0, du0 = (fx, nebgrad)

            # Store old force
            self.old_f[:] = -nebgrad

            # Do one iteration of L-BFGS and return positions, gradient modulus,
            # direction, list of positions, list of gradients
            # self.beads.q, fx, self.nebbfgsm.d, self.qlist, self.glist = L_BFGS(self.beads.q,
            L_BFGS(self.beads.q,
                   self.nebbfgsm.d,
                   self.nebbfgsm,
                   self.qlist,
                   self.glist,
                   fdf0=(u0, du0),
                   big_step=self.big_step,
                   tol=self.ls_options["tolerance"],
                   itmax=self.ls_options["iter"],
                   m=self.corrections,
                   scale=self.scale,
                   k=step)

            info(" @GEOP: Updated position list", verbosity.debug)
            info(" @GEOP: Updated gradient list", verbosity.debug)

            # x = current position - previous position. Use to determine converged minimization
            x = np.amax(
                np.absolute(np.subtract(self.beads.q, self.nebbfgsm.xold)))

            # Store old positions
            self.nebbfgsm.xold[:] = self.beads.q
            self.beads.q = self.nebbfgsm.dbeads.q
            self.forces.transfer_forces(self.nebbfgsm.dforces)

            info(" @GEOP: Updated bead positions", verbosity.debug)

        # Routine for steepest descent and conjugate gradient
        # TODO: CURRENTLY DOES NOT WORK. MUST BE ELIMINATED OR DEBUGGED
        else:
            if (self.mode == "sd" or step == 0):

                # Steepest descent minimization
                # gradf1 = force at current atom position
                # dq1 = direction of steepest descent
                # dq1_unit = unit vector of dq1
                nebgrad = self.neblm(self.beads.q)[0]
                gradf1 = dq1 = -nebgrad

                # Move direction for steepest descent and 1st conjugate gradient step
                dq1_unit = dq1 / np.sqrt(
                    np.dot(gradf1.flatten(), gradf1.flatten()))
                info(" @GEOP: Determined SD direction", verbosity.debug)

            else:

                # Conjugate gradient, Polak-Ribiere
                # gradf1: force at current atom position
                # gradf0: force at previous atom position
                # dq1 = direction to move
                # dq0 = previous direction
                # dq1_unit = unit vector of dq1
                gradf0 = self.old_f
                dq0 = self.old_d
                nebgrad = self.neblm(self.beads.q)[0]
                gradf1 = -nebgrad
                beta = np.dot((gradf1.flatten() - gradf0.flatten()),
                              gradf1.flatten()) / (np.dot(
                                  gradf0.flatten(), gradf0.flatten()))
                dq1 = gradf1 + max(0.0, beta) * dq0
                dq1_unit = dq1 / np.sqrt(np.dot(dq1.flatten(), dq1.flatten()))
                info(" @GEOP: Determined CG direction", verbosity.debug)

            # Store force and direction for next CG step
            self.old_d[:] = dq1
            self.old_f[:] = gradf1

            if len(self.fixatoms) > 0:
                for dqb in dq1_unit:
                    dqb[self.fixatoms * 3] = 0.0
                    dqb[self.fixatoms * 3 + 1] = 0.0
                    dqb[self.fixatoms * 3 + 2] = 0.0

            self.neblm.set_dir(dstrip(self.beads.q), dq1_unit)

            # Reuse initial value since we have energy and forces already
            u0 = np.dot(-nebgrad.flatten(), dq1_unit.flatten())
            u0 = np.sqrt(np.dot(u0, u0))

            (x, fx) = min_brent_neb(self.neblm,
                                    fdf0=u0,
                                    x0=0.0,
                                    tol=self.ls_options["tolerance"],
                                    itmax=self.ls_options["iter"],
                                    init_step=self.ls_options["step"])

            # Automatically adapt the search step for the next iteration.
            # Relaxes better with very small step --> multiply by factor of 0.1 or 0.01
            self.ls_options["step"] = 0.1 * x * self.ls_options["adaptive"] + (
                1 - self.ls_options["adaptive"]) * self.ls_options["step"]

            self.beads.q += dq1_unit * x
            info(" @GEOP: Updated bead positions", verbosity.debug)

        self.qtime += time.time()

        # Determine conditions for converged relaxation
        if ((fx - u0) / self.beads.natoms <= self.tolerances["energy"])\
                and ((np.amax(np.absolute(self.forces.f)) <= self.tolerances["force"])
                     or (np.sqrt(np.dot(self.forces.f.flatten() - self.old_f.flatten(),
                                        self.forces.f.flatten() - self.old_f.flatten())) == 0.0))\
                and (x <= self.tolerances["position"]):
            softexit.trigger(
                "Geometry optimization converged. Exiting simulation")
        else:
            info(
                " @GEOP: Not converged, deltaEnergy = %.8f, tol = %.8f" %
                ((fx - u0 / self.beads.natoms), self.tolerances["energy"]),
                verbosity.debug)
            info(
                " @GEOP: Not converged, force = %.8f, tol = %f" % (np.amax(
                    np.absolute(self.forces.f)), self.tolerances["force"]),
                verbosity.debug)
            info(
                " @GEOP: Not converged, deltaForce = %.8f, tol = 0.00000000" %
                (np.sqrt(
                    np.dot(self.forces.f.flatten() - self.old_f.flatten(),
                           self.forces.f.flatten() - self.old_f.flatten()))),
                verbosity.debug)
            info(
                " @GEOP: Not converged, deltaX = %.8f, tol = %.8f" %
                (x, self.tolerances["position"]), verbosity.debug)