Example #1
0
   def get_all(self):
      """Driver routine.

      When one of the force, potential or virial are called, this sends the
      atoms and cell to the driver through the interface, requesting that the
      driver does the calculation. This then waits until the driver is finished,
      and then returns the ufvx list.

      Returns:
         A list of the form [potential, force, virial, extra].
      """

      # this is converting the distribution library requests into [ u, f, v ]  lists
      if self.request is None:
         self.request = self.socket.queue(self.atoms, self.cell, pars=self.pars, reqid=-1)
      while self.request["status"] != "Done":
         if self.request["status"] == "Exit":
            break
         time.sleep(self.socket.latency)
      if self.request["status"] == "Exit":
         softexit.trigger(" @Force: Requested returned a Exit status")

      # data has been collected, so the request can be released and a slot
      #freed up for new calculations
      self.socket.release(self.request)
      result = self.request["result"]
      self.request = None

      return result
Example #2
0
    def pre_step(self, step=None, adaptative=False):
        """ Todo before actual step"""

        if self.exit:
            softexit.trigger("Geometry optimization converged. Exiting simulation")

        func = lambda x: 2 * np.sum(x) - x[0] - x[-1] - 2 * self.im.dbeads.nbeads
        if not self.init:
            self.initialize(step)
            # print('old_coef',func(self.im.coef))
            #cons = scipy.optimize.NonlinearConstraint(func,-0.1,0.1)
            #cons=({'type':'eq','fun':lambda x: 2*np.sum(x)-x[0]-x[1]-2*self.im.dbeads.nbeads})

        if adaptative:
            import scipy.optimize
            new_coef = scipy.optimize.minimize(self.opt_coef, self.im.coef, method='L-BFGS-B', options={'gtol': 1e-8, 'disp': False})

            func = lambda x: 2 * np.sum(x) - x[0] - x[-1]
            coef = np.absolute(new_coef.x)
            s = func(coef)
            coef *= 2 * self.im.dbeads.nbeads / s
            self.im.set_coef(coef)
            self.gm.set_coef(coef)

        self.qtime = -time.time()
        info("\n Instanton optimization STEP {}".format(step), verbosity.low)

        activearrays = self.fix.get_active_array(self.optarrays)

        return activearrays
Example #3
0
    def exitstep(self, fx, u0, x):
        """ Exits the simulation step. Computes time, checks for convergence. """

        info(" @GEOP: Updating bead positions", verbosity.debug)
        self.qtime += time.time()

        f = np.amax(np.absolute(self.forces.f))
        e = np.absolute((fx - u0) / self.beads.natoms)
        info("@GEOP", verbosity.medium)
        self.tolerances["position"]
        info("   Current energy             %e" % (fx))
        info(
            "   Position displacement      %e  Tolerance %e" %
            (x, self.tolerances["position"]), verbosity.medium)
        info(
            "   Max force component        %e  Tolerance %e" %
            (f, self.tolerances["force"]), verbosity.medium)
        info(
            "   Energy difference per atom %e  Tolerance %e" %
            (e, self.tolerances["energy"]), verbosity.medium)

        if (np.linalg.norm(self.forces.f.flatten() - self.old_f.flatten()) <=
                1e-20):
            softexit.trigger(
                "Something went wrong, the forces are not changing anymore."
                " This could be due to an overly small tolerance threshold "
                "that makes no physical sense. Please check if you are able "
                "to reach such accuracy with your force evaluation"
                " code (client).")

        if (np.absolute((fx - u0) / self.beads.natoms) <= self.tolerances["energy"])   \
            and ( ( np.amax(np.absolute(self.forces.f)) <= self.tolerances["force"]))  \
            and (x <= self.tolerances["position"]):
            softexit.trigger(
                "Geometry optimization converged. Exiting simulation")
Example #4
0
    def exitstep(self, fx, u0, x):
        """ Exits the simulation step. Computes time, checks for convergence. """

        info(" @GEOP: Updating bead positions", verbosity.debug)
        self.qtime += time.time()

        if len(self.fixatoms) > 0:
            ftmp = self.forces.f.copy()
            for dqb in ftmp:
                dqb[self.fixatoms * 3] = 0.0
                dqb[self.fixatoms * 3 + 1] = 0.0
                dqb[self.fixatoms * 3 + 2] = 0.0
            fmax = np.amax(np.absolute(ftmp))
        else:
            fmax = np.amax(np.absolute(self.forces.f))

        e = np.absolute((fx - u0) / self.beads.natoms)
        info("@GEOP", verbosity.medium)
        self.tolerances["position"]
        info("   Current energy             %e" % (fx))
        info("   Position displacement      %e  Tolerance %e" % (x, self.tolerances["position"]), verbosity.medium)
        info("   Max force component        %e  Tolerance %e" % (fmax, self.tolerances["force"]), verbosity.medium)
        info("   Energy difference per atom %e  Tolerance %e" % (e, self.tolerances["energy"]), verbosity.medium)

        if (np.linalg.norm(self.forces.f.flatten() - self.old_f.flatten()) <= 1e-20):
            softexit.trigger("Something went wrong, the forces are not changing anymore."
                             " This could be due to an overly small tolerance threshold "
                             "that makes no physical sense. Please check if you are able "
                             "to reach such accuracy with your force evaluation"
                             " code (client).")

        if (np.absolute((fx - u0) / self.beads.natoms) <= self.tolerances["energy"])   \
                and (fmax <= self.tolerances["force"])  \
                and (x <= self.tolerances["position"]):
            softexit.trigger("Geometry optimization converged. Exiting simulation")
Example #5
0
   def _kill_handler(self, signal, frame):
      """Deals with handling a kill call gracefully.

      Prevents any of the threads becoming zombies, by intercepting a
      kill signal using the standard python function signal.signal() and
      then closing the socket and the spawned threads before closing the main
      thread. Called when signals SIG_INT and SIG_TERM are received.

      Args:
         signal: An integer giving the signal number of the signal received
            from the socket.
         frame: Current stack frame.
      """

      warning(" @SOCKET:   Kill signal. Trying to make a clean exit.", verbosity.low)
      self.end_thread()

      softexit.trigger(" @SOCKET: Kill signal received")

      try:
         self.__del__()
      except:
         pass
      if signal in self._prev_kill:
         self._prev_kill[signal](signal, frame)
Example #6
0
    def _kill_handler(self, signal, frame):
        """Deals with handling a kill call gracefully.

      Prevents any of the threads becoming zombies, by intercepting a
      kill signal using the standard python function signal.signal() and
      then closing the socket and the spawned threads before closing the main
      thread. Called when signals SIG_INT and SIG_TERM are received.

      Args:
         signal: An integer giving the signal number of the signal received
            from the socket.
         frame: Current stack frame.
      """

        warning(" @SOCKET:   Kill signal. Trying to make a clean exit.",
                verbosity.low)
        self.end_thread()

        softexit.trigger(" @SOCKET: Kill signal received")

        try:
            self.__del__()
        except:
            pass
        if signal in self._prev_kill:
            self._prev_kill[signal](signal, frame)
Example #7
0
   def get_all(self):
      """Driver routine.

      When one of the force, potential or virial are called, this sends the
      atoms and cell to the driver through the interface, requesting that the
      driver does the calculation. This then waits until the driver is finished,
      and then returns the ufvx list.

      Returns:
         A list of the form [potential, force, virial, extra].
      """

      # this is converting the distribution library requests into [ u, f, v ]  lists
      if self.request is None:
         self.request = self.socket.queue(self.atoms, self.cell, pars=self.pars, reqid=-1)
      while self.request["status"] != "Done":
         if self.request["status"] == "Exit":
            break
         time.sleep(self.socket.latency)
      if self.request["status"] == "Exit":
         softexit.trigger(" @Force: Requested returned a Exit status")

      # data has been collected, so the request can be released and a slot
      #freed up for new calculations
      self.socket.release(self.request)
      result = self.request["result"]
      self.request = None

      return result
Example #8
0
    def get_all(self):
        """Driver routine.

      When one of the force, potential or virial are called, this sends the
      atoms and cell to the client code, requesting that it calculates the
      potential, forces and virial tensor. This then waits until the
      driver is finished, and then returns the ufvx list.

      Returns:
         A list of the form [potential, force, virial, extra].
      """

        # because we thread over many systems and outputs, we might get called
        # more than once. keep track of how many times we are called so we
        # can make sure to wait until the last call has returned before we release
        self._threadlock.acquire()
        try:
            self._getallcount += 1
        finally:
            self._threadlock.release()

        # this is converting the distribution library requests into [ u, f, v ]  lists
        if self.request is None:
            self.request = self.ff.queue(self.atoms, self.cell)

        # sleeps until the request has been evaluated
        while self.request["status"] != "Done":
            if self.request["status"] == "Exit" or softexit.triggered:
                # now, this is tricky. we are stuck here and we cannot return meaningful results.
                # if we return, we may as well output wrong numbers, or mess up things.
                # so we can only call soft-exit and wait until that is done. then kill the thread
                # we are in.
                softexit.trigger(
                    " @ FORCES : cannot return so will die off here")
                while softexit.exiting:
                    time.sleep(self.ff.latencyt)
                sys.exit()
            time.sleep(self.ff.latency)

        # data has been collected, so the request can be released and a slot
        # freed up for new calculations
        result = self.request["result"]

        # reduce the reservation count (and wait for all calls to return)
        self._threadlock.acquire()
        try:
            self._getallcount -= 1
        finally:
            self._threadlock.release()

        # releases just once, but wait for all requests to be complete
        if self._getallcount == 0:
            self.ff.release(self.request)
            self.request = None
        else:
            while self._getallcount > 0:
                time.sleep(self.ff.latency)

        return result
Example #9
0
File: phonons.py Project: i-pi/i-pi
 def step(self, step=None):
     """Executes one step of phonon computation. """
     if (step < 3 * self.beads.natoms):
         self.phcalc.step(step)
     else:
         self.phcalc.transform()
         self.refdynmatrix = self.apply_asr(self.refdynmatrix.copy())
         self.printall(self.prefix, self.refdynmatrix.copy())
         softexit.trigger("Dynamic matrix is calculated. Exiting simulation")
Example #10
0
File: geop.py Project: tomspur/i-pi
 def step(self, step=None):
     if self.optimizer.converged:
         # if required, exit upon convergence. otherwise just return without action
         if self.conv_exit:
             softexit.trigger("Geometry optimization converged. Exiting simulation")
         else:
             info("Convergence threshold met. Will carry on but do nothing.", verbosity.high)
     else:
         self.optimizer.step(step)
Example #11
0
 def step(self, step=None):
     """Executes one step of phonon computation. """
     if (step < 3 * self.beads.natoms):
         self.phcalc.step(step)
     else:
         self.phcalc.transform()
         self.refdynmatrix = self.apply_asr(self.refdynmatrix.copy())
         self.printall(self.prefix, self.refdynmatrix.copy())
         softexit.trigger("Dynamic matrix is calculated. Exiting simulation")
Example #12
0
    def get_all(self):
        """Driver routine.

        When one of the force, potential or virial are called, this sends the
        atoms and cell to the client code, requesting that it calculates the
        potential, forces and virial tensor. This then waits until the
        driver is finished, and then returns the ufvx list.

        Returns:
           A list of the form [potential, force, virial, extra].
        """

        # because we thread over many systems and outputs, we might get called
        # more than once. keep track of how many times we are called so we
        # can make sure to wait until the last call has returned before we release
        with self._threadlock:
            self._getallcount += 1

        # this is converting the distribution library requests into [ u, f, v ]  lists
        if self.request is None:
            self.request = self.queue()

        # sleeps until the request has been evaluated
        while self.request["status"] != "Done":
            if self.request["status"] == "Exit" or softexit.triggered:
                # now, this is tricky. we are stuck here and we cannot return meaningful results.
                # if we return, we may as well output wrong numbers, or mess up things.
                # so we can only call soft-exit and wait until that is done. then kill the thread
                # we are in.
                softexit.trigger(" @ FORCES : cannot return so will die off here")
                while softexit.exiting:
                    time.sleep(self.ff.latencyt)
                sys.exit()
            time.sleep(self.ff.latency)

        # print diagnostics about the elapsed time
        info("# forcefield %s evaluated in %f (queue) and %f (dispatched) sec." % (self.ff.name, self.request["t_finished"] - self.request["t_queued"], self.request["t_finished"] - self.request["t_dispatched"]), verbosity.debug)

        # data has been collected, so the request can be released and a slot
        # freed up for new calculations
        result = self.request["result"]

        # reduce the reservation count (and wait for all calls to return)
        with self._threadlock:
            self._getallcount -= 1

        # releases just once, but wait for all requests to be complete
        if self._getallcount == 0:
            self.ff.release(self.request)
            self.request = None
        else:
            while self._getallcount > 0:
                time.sleep(self.ff.latency)

        return result
Example #13
0
 def step(self, step=None):
     if self.isc == self.max_iter:
         softexit.trigger(
             " @SCP: Reached maximum iterations. Terminating the SCP calculation."
         )
     if self.imc == 0:
         self.phononator.reset()
     elif self.imc >= 1 and self.imc <= self.max_steps:
         self.phononator.step(step)
     elif self.imc > self.max_steps:
         self.phononator.print_energetics()
         self.phononator.displace()
Example #14
0
    def step(self, step=None):
        """Does one replay time step."""

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

        while True:
            self.rstep += 1
            try:
                if self.intraj.mode == "xyz":
                    for b in self.beads:
                        myframe = read_file("xyz", self.rfile)
                        myatoms = myframe["atoms"]
                        mycell = myframe["cell"]
                        myatoms.q *= unit_to_internal("length",
                                                      self.intraj.units, 1.0)
                        mycell.h *= unit_to_internal("length",
                                                     self.intraj.units, 1.0)
                        b.q[:] = myatoms.q
                    self.cell.h[:] = mycell.h
                elif self.intraj.mode == "pdb":
                    for b in self.beads:
                        myatoms, mycell = read_file("pdb", self.rfile)
                        myatoms.q *= unit_to_internal("length",
                                                      self.intraj.units, 1.0)
                        mycell.h *= unit_to_internal("length",
                                                     self.intraj.units, 1.0)
                        b.q[:] = myatoms.q
                    self.cell.h[:] = mycell.h
                elif self.intraj.mode == "chk" or self.intraj.mode == "checkpoint":

                    # TODO: Adapt the new `Simulation.load_from_xml`?

                    # reads configuration from a checkpoint file
                    xmlchk = xml_parse_file(self.rfile)  # Parses the file.

                    from ipi.inputs.simulation import InputSimulation

                    simchk = InputSimulation()
                    simchk.parse(xmlchk.fields[0][1])
                    mycell = simchk.cell.fetch()
                    mybeads = simchk.beads.fetch()
                    self.cell.h[:] = mycell.h
                    self.beads.q[:] = mybeads.q
                    softexit.trigger(" # Read single checkpoint")
            except EOFError:
                softexit.trigger(" # Finished reading re-run trajectory")
            if (step is None) or (self.rstep > step):
                break

        self.qtime += time.time()
Example #15
0
File: geop.py Project: tomspur/i-pi
    def bind(self, ens, beads, nm, cell, bforce, prng, omaker):
        """Binds beads, cell, bforce and prng to GeopMotion

            Args:
            beads: The beads object from which the bead positions are taken.
            nm: A normal modes object used to do the normal modes transformation.
            cell: The cell object from which the system box is taken.
            bforce: The forcefield object from which the force and virial are taken.
            prng: The random number generator object which controls random number generation.
        """

        super(GeopMotion, self).bind(ens, beads, nm, cell, bforce, prng, omaker)
        # Binds optimizer
        self.optimizer.bind(self)

        if len(self.fixatoms) == len(self.beads[0]):
            softexit.trigger("WARNING: all atoms are fixed, geometry won't change. Exiting simulation")
Example #16
0
    def step(self):
        """Does one simulation time step."""

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

        try:
            if (self.intraj.mode == "xyz"):
                for b in self.beads:
                    myatoms = read_xyz(self.rfile)
                    myatoms.q *= unit_to_internal("length", self.intraj.units,
                                                  1.0)
                    b.q[:] = myatoms.q
            elif (self.intraj.mode == "pdb"):
                for b in self.beads:
                    myatoms, mycell = read_pdb(self.rfile)
                    myatoms.q *= unit_to_internal("length", self.intraj.units,
                                                  1.0)
                    mycell.h *= unit_to_internal("length", self.intraj.units,
                                                 1.0)
                    b.q[:] = myatoms.q
                self.cell.h[:] = mycell.h
            elif (self.intraj.mode == "chk"
                  or self.intraj.mode == "checkpoint"):
                # reads configuration from a checkpoint file
                xmlchk = xml_parse_file(self.rfile)  # Parses the file.

                from ipi.inputs.simulation import InputSimulation
                simchk = InputSimulation()
                simchk.parse(xmlchk.fields[0][1])
                mycell = simchk.cell.fetch()
                mybeads = simchk.beads.fetch()
                self.cell.h[:] = mycell.h
                self.beads.q[:] = mybeads.q
                softexit.trigger(" # Read single checkpoint")
        except EOFError:
            softexit.trigger(" # Finished reading re-run trajectory")

        self.qtime += time.time()
Example #17
0
    def step(self):
        """Does one simulation time step."""

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

        try:
            if self.intraj.mode == "xyz":
                for b in self.beads:
                    myatoms = read_xyz(self.rfile)
                    myatoms.q *= unit_to_internal("length", self.intraj.units, 1.0)
                    b.q[:] = myatoms.q
            elif self.intraj.mode == "pdb":
                for b in self.beads:
                    myatoms, mycell = read_pdb(self.rfile)
                    myatoms.q *= unit_to_internal("length", self.intraj.units, 1.0)
                    mycell.h *= unit_to_internal("length", self.intraj.units, 1.0)
                    b.q[:] = myatoms.q
                self.cell.h[:] = mycell.h
            elif self.intraj.mode == "chk" or self.intraj.mode == "checkpoint":
                # reads configuration from a checkpoint file
                xmlchk = xml_parse_file(self.rfile)  # Parses the file.

                from ipi.inputs.simulation import InputSimulation

                simchk = InputSimulation()
                simchk.parse(xmlchk.fields[0][1])
                mycell = simchk.cell.fetch()
                mybeads = simchk.beads.fetch()
                self.cell.h[:] = mycell.h
                self.beads.q[:] = mybeads.q
                softexit.trigger(" # Read single checkpoint")
        except EOFError:
            softexit.trigger(" # Finished reading re-run trajectory")

        self.qtime += time.time()
Example #18
0
    def pool_update(self):
        """Deals with keeping the pool of client drivers up-to-date during a
      force calculation step.

      Deals with maintaining the client list. Clients that have
      disconnected are removed and their jobs removed from the list of
      running jobs and new clients are connected to the server.
      """

        for c in self.clients[:]:
            if not (c.status & Status.Up):
                try:
                    warning(
                        " @SOCKET:   Client " + str(c.peername) +
                        " died or got unresponsive(C). Removing from the list.",
                        verbosity.low)

                    softexit.trigger(
                        "Error: One client has died unexpectedly. Exiting i-PI..."
                    )  # c*g
                    eprint(
                        "Error: One client has died unexpectedly. Exiting i-PI..."
                    )  # c*g
                    c.shutdown(socket.SHUT_RDWR)
                    c.close()
                except socket.error:
                    pass
                c.status = Status.Disconnected
                self.clients.remove(c)
                for [k, j] in self.jobs[:]:
                    if j is c:
                        self.jobs = [
                            w for w in self.jobs
                            if not (w[0] is k and w[1] is j)
                        ]  # removes pair in a robust way
                        #self.jobs.remove([k,j])
                        k["status"] = "Queued"
                        k["start"] = -1

        if len(self.clients) == 0:
            searchtimeout = SERVERTIMEOUT
        else:
            searchtimeout = 0.0

        keepsearch = True
        while keepsearch:
            readable, writable, errored = select.select([self.server], [], [],
                                                        searchtimeout)
            if self.server in readable:
                client, address = self.server.accept()
                client.settimeout(TIMEOUT)
                driver = Driver(client)
                info(
                    " @SOCKET:   Client asked for connection from " +
                    str(address) + ". Now hand-shaking.", verbosity.low)
                driver.poll()
                if (driver.status | Status.Up):
                    self.clients.append(driver)
                    info(
                        " @SOCKET:   Handshaking was successful. Added to the client list.",
                        verbosity.low)

                    self.poll_iter = UPDATEFREQ  # if a new client was found, will try again a harder next time
                    searchtimeout = SERVERTIMEOUT
                else:
                    warning(
                        " @SOCKET:   Handshaking failed. Dropping connection.",
                        verbosity.low)
                    client.shutdown(socket.SHUT_RDWR)
                    client.close()
            else:
                keepsearch = False
Example #19
0
    def step(self, step=None):
        """ Does one simulation time step."""

        self.qtime = -time.time()
        info("\n Instanton optimization STEP %d" % step, verbosity.low)

        if step == 0:
            info(" @GEOP: Initializing instanton", verbosity.low)

            if self.beads.nbeads == 1:
                raise ValueError("We can not perform an splitting calculation with nbeads =1")
                # get_hessian(self.hessian, self.gm, self.beads.q)
            else:
                if ((self.beads.q - self.beads.q[0]) == 0).all():  # If the coordinates in all the imaginary time slices are the same
                    info(" @GEOP: We stretch the initial geometry with an 'amplitud' of %4.2f" % self.delta, verbosity.low)
                    imvector = get_imvector(self.initial_hessian, self.beads.m3[0].flatten())
                    for i in range(self.beads.nbeads):

                        self.beads.q[i, :] += self.delta * np.cos(i * np.pi / float(self.beads.nbeads - 1)) * imvector[:]
                else:
                    info(" @GEOP: Starting from the provided geometry in the extended phase space", verbosity.low)

            # Update positions and forces
            self.old_x[:] = self.beads.q
            self.old_u[:] = self.forces.pots
            self.old_f[:] = self.forces.f

        # This must be done after the stretching and before the self.d.
        if type(self.im.f) == type(None):
            self.im(self.beads.q, ret=False)  # Init instanton mapper

        # Specific for LBFGS
        if np.linalg.norm(self.d) == 0.0:
            f = self.forces.f + self.im.f  # ALBERTO1
            self.d += dstrip(f) / np.sqrt(np.dot(f.flatten(), f.flatten()))

        if (self.old_x == np.zeros((self.beads.nbeads, 3 * self.beads.natoms), float)).all():
            self.old_x[:] = self.beads.q

        if self.exit:
            softexit.trigger("Geometry optimization converged. Exiting simulation")

        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

        e, g = self.fm(self.beads.q)
        fdf0 = (e, g)

        # Do one step. Update hessian for the new position. Update the position and force inside the mapper.
        L_BFGS(self.old_x, self.d, self.fm, self.qlist, self.glist,
               fdf0, self.big_step, self.ls_options["tolerance"] * self.tolerances["energy"],
               self.ls_options["iter"], self.corrections, self.scale, step)
        # ALBERTO2

        # 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.exit = self.exitstep(self.forces.pot, self.old_u.sum(), d_x_max, self.exit, step)

        # Update positions and forces
        self.old_x[:] = self.beads.q
        self.old_u[:] = self.forces.pots
        self.old_f[:] = self.forces.f

        # Print current instanton geometry and hessian
        if (self.save > 0 and np.mod(step, self.save) == 0) or self.exit:
            print_instanton_geo(self.prefix, step, self.im.dbeads.nbeads, self.im.dbeads.natoms, self.im.dbeads.names,
                                self.im.dbeads.q, self.old_u, self.cell, self.energy_shift, self.output_maker)
Example #20
0
   def run(self):
      """Runs the simulation.

      Does all the simulation steps, and outputs data to the appropriate files
      when necessary. Also deals with starting and cleaning up the threads used
      in the communication between the driver and the PIMD code.
      """

      self.forces.run()

      # prints inital configuration -- only if we are not restarting
      if (self.step == 0):
         self.step = -1
         for o in self.outputs:
            o.write()
         self.step = 0

      steptime = 0.0
      simtime =  time.time()

      cstep = 0
      tptime = 0.0
      tqtime = 0.0
      tttime = 0.0
      ttot = 0.0
      # main MD loop
      for self.step in range(self.step,self.tsteps):
         # stores the state before doing a step.
         # this is a bit time-consuming but makes sure that we can honor soft
         # exit requests without screwing the trajectory

         steptime = -time.time()
         self.chk.store()

         self.ensemble.step()

         for o in self.outputs:
            o.write()

         if os.path.exists("EXIT"): # soft-exit
            self.rollback = False
            softexit.trigger()

         steptime += time.time()
         ttot += steptime
         tptime += self.ensemble.ptime
         tqtime += self.ensemble.qtime
         tttime += self.ensemble.ttime
         cstep += 1

         if verbosity.high or (verbosity.medium and self.step%100 == 0) or (verbosity.low and self.step%1000 == 0):
            info(" # Average timings at MD step % 7d. t/step: %10.5e [p: %10.5e  q: %10.5e  t: %10.5e]" %
               ( self.step, ttot/cstep, tptime/cstep, tqtime/cstep, tttime/cstep ) )
            cstep = 0
            tptime = 0.0
            tqtime = 0.0
            tttime = 0.0
            ttot = 0.0
            info(" # MD diagnostics: V: %10.5e    Kcv: %10.5e   Ecns: %10.5e" %
               (self.properties["potential"], self.properties["kinetic_cv"], self.properties["conserved"] ) )

         if (self.ttime > 0 and time.time() - simtime > self.ttime):
            info(" # Wall clock time expired! Bye bye!", verbosity.low )
            break

      info(" # Simulation ran successfully for the prescribed total_step! Bye bye!", verbosity.low )
      self.rollback = False
      softexit.trigger()
Example #21
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)
Example #22
0
    def __init__(
        self,
        timestep,
        mode="nve",
        splitting="obabo",
        thermostat=None,
        barostat=None,
        fixcom=False,
        fixatoms=None,
        nmts=None,
    ):
        """Initialises a "dynamics" motion object.

        Args:
            dt: The timestep of the simulation algorithms.
            fixcom: An optional boolean which decides whether the centre of mass
                motion will be constrained or not. Defaults to False.
        """

        super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms)
        dself = dd(self)  # noqa

        # initialize time step. this is the master time step that covers a full time step
        dd(self).dt = depend_value(name="dt", value=timestep)

        if thermostat is None:
            self.thermostat = Thermostat()
        else:
            if (
                thermostat.__class__.__name__ is ("ThermoPILE_G" or "ThermoNMGLEG ")
            ) and (len(fixatoms) > 0):
                softexit.trigger(
                    "!! Sorry, fixed atoms and global thermostat on the centroid not supported. Use a local thermostat. !!"
                )
            self.thermostat = thermostat

        if nmts is None or len(nmts) == 0:
            dd(self).nmts = depend_array(name="nmts", value=np.asarray([1], int))
        else:
            dd(self).nmts = depend_array(name="nmts", value=np.asarray(nmts, int))

        if barostat is None:
            self.barostat = Barostat()
        else:
            self.barostat = barostat
        self.enstype = mode
        if self.enstype == "nve":
            self.integrator = NVEIntegrator()
        elif self.enstype == "nvt":
            self.integrator = NVTIntegrator()
        elif self.enstype == "nvt-cc":
            self.integrator = NVTCCIntegrator()
        elif self.enstype == "npt":
            self.integrator = NPTIntegrator()
        elif self.enstype == "nst":
            self.integrator = NSTIntegrator()
        elif self.enstype == "sc":
            self.integrator = SCIntegrator()
        elif self.enstype == "scnpt":
            self.integrator = SCNPTIntegrator()
        else:
            self.integrator = DummyIntegrator()

        # splitting mode for the integrators
        dd(self).splitting = depend_value(name="splitting", value=splitting)

        # constraints
        self.fixcom = fixcom
        if fixatoms is None:
            self.fixatoms = np.zeros(0, int)
        else:
            self.fixatoms = fixatoms
Example #23
0
   def run(self):
      """Runs the simulation.

      Does all the simulation steps, and outputs data to the appropriate files
      when necessary. Also deals with starting and cleaning up the threads used
      in the communication between the driver and the PIMD code.
      """

      self.forces.run()

      # prints initial configuration -- only if we are not restarting
      if (self.step == 0):
         self.step = -1
         for o in self.outputs:
            o.write()
         self.step = 0

      steptime = 0.0
      simtime =  time.time()

      cstep = 0
      tptime = 0.0
      tqtime = 0.0
      tttime = 0.0
      ttot = 0.0
      # main MD loop
      for self.step in range(self.step,self.tsteps):
         # stores the state before doing a step.
         # this is a bit time-consuming but makes sure that we can honor soft
         # exit requests without screwing the trajectory

         steptime = -time.time()
         self.chk.store()

         self.ensemble.step()

         for o in self.outputs:
            o.write()

         if os.path.exists("EXIT"): # soft-exit
            self.rollback = False
            softexit.trigger()

         steptime += time.time()
         ttot += steptime
         tptime += self.ensemble.ptime
         tqtime += self.ensemble.qtime
         tttime += self.ensemble.ttime
         cstep += 1

         if verbosity.high or (verbosity.medium and self.step%100 == 0) or (verbosity.low and self.step%1000 == 0):
            info(" # Average timings at MD step % 7d. t/step: %10.5e [p: %10.5e  q: %10.5e  t: %10.5e]" %
               ( self.step, ttot/cstep, tptime/cstep, tqtime/cstep, tttime/cstep ) )
            cstep = 0
            tptime = 0.0
            tqtime = 0.0
            tttime = 0.0
            ttot = 0.0
            info(" # MD diagnostics: V: %10.5e    Kcv: %10.5e   Ecns: %10.5e" %
               (self.properties["potential"], self.properties["kinetic_cv"], self.properties["conserved"] ) )

         if (self.ttime > 0 and time.time() - simtime > self.ttime):
            info(" # Wall clock time expired! Bye bye!", verbosity.low )
            break

      info(" # Simulation ran successfully for the prescribed total_step! Bye bye!", verbosity.low )
      self.rollback = False
      softexit.trigger()
Example #24
0
    def step(self, step=None):
        """ Does one simulation time step."""

        self.qtime = -time.time()
        info("\n Instanton optimization STEP %d" % step, verbosity.low)

        if step == 0:
            info(" @GEOP: Initializing INSTANTON", verbosity.low)

            if self.beads.nbeads == 1:
                info(" @GEOP: Classical TS search", verbosity.low)
                if self.hessian_init == 'true':
                    get_hessian(self.hessian, self.gm, self.beads.q)
            else:
                if ((self.beads.q - self.beads.q[0]) == 0).all(
                ):  # If the coordinates in all the imaginary time slices are the same
                    info(
                        " @GEOP: We stretch the initial geometry with an 'amplitud' of %4.2f"
                        % self.delta, verbosity.low)
                    imvector = get_imvector(self.initial_hessian,
                                            self.beads.m3[0].flatten())
                    for i in range(self.beads.nbeads):
                        self.beads.q[i, :] += self.delta * np.cos(
                            i * np.pi /
                            float(self.beads.nbeads - 1)) * imvector[:]
                    if self.hessian_init != 'true':
                        info(
                            " @GEOP: Hessian_init isn't true but we have stretched the polymer so we are going to compute the initial hessian anyway.",
                            verbosity.low)
                        self.hessian_init = 'true'
                else:
                    info(
                        " @GEOP: Starting from the provided geometry in the extended phase space",
                        verbosity.low)
                    if not (self.initial_hessian is None):
                        raise ValueError(
                            " You have to provided a hessian with size (3xnatoms)^2 but also geometry in the extended phase space (nbeads>1). Please check the inputs\n"
                        )

                if self.hessian_init == 'true':
                    info(" @GEOP: We are computing the initial hessian",
                         verbosity.low)
                    get_hessian(self.hessian, self.gm, self.beads.q)

            # Update positions and forces
            self.old_x[:] = self.beads.q
            self.old_u[:] = self.forces.pots
            self.old_f[:] = self.forces.f

        if type(self.im.f) == type(None):
            self.im(self.beads.q, ret=False)  #Init instanton mapper

        if (self.old_x == np.zeros((self.beads.nbeads, 3 * self.beads.natoms),
                                   float)).all():
            self.old_x[:] = self.beads.q
        if self.exit:
            softexit.trigger(
                "Geometry optimization converged. Exiting simulation")

        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

        # Do one step. Update hessian for the new position. Update the position and force inside the mapper.
        Instanton(self.old_x, self.old_f, self.im.f, self.hessian,
                  self.hessian_update, self.hessian_asr, self.im, self.gm,
                  self.big_step, self.opt, self.mode)

        # 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

        # Print current instanton geometry and hessian
        if (self.save > 0 and np.mod(step, self.save) == 0) or self.exit:
            print_instanton_geo(self.prefix, step, self.im.dbeads.nbeads,
                                self.im.dbeads.natoms, self.im.dbeads.names,
                                self.im.dbeads.q, self.old_u, self.cell,
                                self.energy_shift)
            print_instanton_hess(self.prefix, step, self.hessian)

        # Exit simulation step
        d_x_max = np.amax(np.absolute(np.subtract(self.beads.q, self.old_x)))
        self.exit = self.exitstep(self.forces.pot, self.old_u.sum(), d_x_max,
                                  self.exit, step)

        # Update positions and forces
        self.old_x[:] = self.beads.q
        self.old_u[:] = self.forces.pots
        self.old_f[:] = self.forces.f
Example #25
0
    def run(self):
        """Runs the simulation.

        Does all the simulation steps, and outputs data to the appropriate files
        when necessary. Also deals with starting and cleaning up the threads used
        in the communication between the driver and the PIMD code.
        """

        # registers the softexit routine
        softexit.register_function(self.softexit)
        softexit.start(self.ttime)

        for k, f in self.fflist.iteritems():
            f.run()

        # prints inital configuration -- only if we are not restarting
        info("Step:", self.step)
        if self.step == 0:
            print           # me c*g
            print "Waiting for all CP2K clients to connect before starting the simulation."          # me c*g
            trials_count = 0          # me c*g
            trials_max = 2*self.syslist[0].beads.nbeads + 500          # me c*g
            while self.syslist[0].beads.nbeads != len(self.fflist["cp2k"].socket.clients):          # me c*g
                trials_count += 1          # me c*g
                print " * Currently " + str(len(self.fflist["cp2k"].socket.clients)) + " of " + str(self.syslist[0].beads.nbeads) + " CP2K clients have connected. Sleeping one second... (trial " + str(trials_count) + " of " + str(trials_max) + ")."          # me c*g
                if trials_count == trials_max:          # me c*g
                    softexit.trigger("Sufficiently many CP2K clients failed to connect within the maximum waiting time of " + str(trials_max) + " seconds.")          # me c*g
                time.sleep(1)          # me c*g
            print "All CP2K clients have connected. Continuing..."          # me c*g
            self.step = -1
            # must use multi-threading to avoid blocking in multi-system runs with WTE
            stepthreads = []
            for o in self.outputs:
                o.write()  # threaded output seems to cause random hang-ups. should make things properly thread-safe
                #st = threading.Thread(target=o.write, name=o.filename)
                #st.daemon = True
                #st.start()
                #stepthreads.append(st)

            for st in stepthreads:
                while st.isAlive():
                    # This is necessary as join() without timeout prevents main
                    # from receiving signals.
                    st.join(2.0)

            if self.mode == "paratemp":
                self.paratemp.parafile.write("%10d" % (self.step + 1))
                for i in self.paratemp.temp_index:
                    self.paratemp.parafile.write(" %5d" % i)
                self.paratemp.parafile.write("\n")
                self.paratemp.parafile.flush()
                os.fsync(self.paratemp.parafile)

            self.step = 0

        steptime = 0.0
        simtime = time.time()

        cstep = 0
        #tptime = 0.0
        #tqtime = 0.0
        #tttime = 0.0
        ttot = 0.0
        # main MD loop
        for self.step in range(self.step, self.tsteps):
            # stores the state before doing a step.
            # this is a bit time-consuming but makes sure that we can honor soft
            # exit requests without screwing the trajectory

            # Checking if no CP2K client has disconnected



            steptime = -time.time()
            if softexit.triggered:
                break

            self.chk.store()

            stepthreads = []
            # steps through all the systems
            #for s in self.syslist:
            #   s.motion.step()
            for s in self.syslist:
                # creates separate threads for the different systems
                #st = threading.Thread(target=s.motion.step, name=s.prefix, kwargs={"step":self.step})
                #st.daemon = True
                s.motion.step(step=self.step)
                #st.start()
                #stepthreads.append(st)

            for st in stepthreads:
                while st.isAlive():
                    # This is necessary as join() without timeout prevents main
                    # from receiving signals.
                    st.join(2.0)

            if softexit.triggered:
                # Don't continue if we are about to exit.
                break

            for o in self.outputs:
                o.write()

            # does parallel tempering
            if self.mode == "paratemp":

                # because of where this is in the loop, we must write out BEFORE doing the swaps.
                self.paratemp.parafile.write("%10d" % (self.step + 1))
                for i in self.paratemp.temp_index:
                    self.paratemp.parafile.write(" %5d" % i)
                self.paratemp.parafile.write("\n")
                self.paratemp.parafile.flush()
                os.fsync(self.paratemp.parafile)

                self.paratemp.swap(self.step)

            if softexit.triggered:
                # Don't write if we are about to exit.
                break

            steptime += time.time()
            ttot += steptime
            cstep += 1

            if (verbosity.high or (verbosity.medium and self.step % 100 == 0) or (verbosity.low and self.step % 1000 == 0)):
                info(" # Average timings at MD step % 7d. t/step: %10.5e" % (self.step, ttot / cstep))
                cstep = 0
                ttot = 0.0
                #info(" # MD diagnostics: V: %10.5e    Kcv: %10.5e   Ecns: %10.5e" %
                #     (self.properties["potential"], self.properties["kinetic_cv"], self.properties["conserved"] ) )

            if os.path.exists("EXIT"):
                info(" # EXIT file detected! Bye bye!", verbosity.low)
                break

            if (self.ttime > 0) and (time.time() - simtime > self.ttime):
                info(" # Wall clock time expired! Bye bye!", verbosity.low)
                break

        self.rollback = False
Example #26
0
    def step(self, step=None):
        """ Does one simulation time step."""

        self.qtime = -time.time()
        info("\n Instanton optimization STEP %d" % step, verbosity.low)

        if step == 0:
            info(" @GEOP: Initializing instanton", verbosity.low)

            if self.beads.nbeads == 1:
                info(" @GEOP: Classical TS search", verbosity.low)
                if self.hessian_init == 'true':
                    get_hessian(self.hessian, self.gm, self.beads.q, self.output_maker)
            else:
                if ((self.beads.q - self.beads.q[0]) == 0).all():  # If the coordinates in all the imaginary time slices are the same
                    info(" @GEOP: We stretch the initial geometry with an 'amplitud' of %4.2f" % self.delta, verbosity.low)
                    imvector = get_imvector(self.initial_hessian, self.beads.m3[0].flatten())
                    for i in range(self.beads.nbeads):
                        self.beads.q[i, :] += self.delta * np.cos(i * np.pi / float(self.beads.nbeads - 1)) * imvector[:]
                    if self.hessian_init != 'true':
                        info(" @GEOP: Hessian_init isn't true but we have stretched the polymer so we are going to compute the initial hessian anyway.", verbosity.low)
                        self.hessian_init = 'true'
                else:
                    info(" @GEOP: Starting from the provided geometry in the extended phase space", verbosity.low)
                    if not (self.initial_hessian is None):
                        raise ValueError(" You have to provided a hessian with size (3xnatoms)^2 but also geometry in the extended phase space (nbeads>1). Please check the inputs\n")

                if self.hessian_init == 'true':
                    info(" @GEOP: We are computing the initial hessian", verbosity.low)
                    get_hessian(self.hessian, self.gm, self.beads.q, self.output_maker)

            # Update positions and forces
            self.old_x[:] = self.beads.q
            self.old_u[:] = self.forces.pots
            self.old_f[:] = self.forces.f

        if type(self.im.f) == type(None):
            self.im(self.beads.q, ret=False)  # Init instanton mapper

        if (self.old_x == np.zeros((self.beads.nbeads, 3 * self.beads.natoms), float)).all():
            self.old_x[:] = self.beads.q
        if self.exit:
            softexit.trigger("Geometry optimization converged. Exiting simulation")

        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

        # Do one step. Update hessian for the new position. Update the position and force inside the mapper.
        Instanton(self.old_x, self.old_f, self.im.f, self.hessian, self.hessian_update, self.hessian_asr, self.im, self.gm, self.big_step, self.opt, self.mode, self.output_maker)

        # 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

        # Print current instanton geometry and hessian
        if (self.save > 0 and np.mod(step, self.save) == 0) or self.exit:
            print_instanton_geo(self.prefix, step, self.im.dbeads.nbeads, self.im.dbeads.natoms, self.im.dbeads.names,
                                self.im.dbeads.q, self.old_u, self.cell, self.energy_shift, self.output_maker)
            print_instanton_hess(self.prefix, step, self.hessian, self.output_maker)

        # Exit simulation step
        d_x_max = np.amax(np.absolute(np.subtract(self.beads.q, self.old_x)))
        self.exit = self.exitstep(self.forces.pot, self.old_u.sum(), d_x_max, self.exit, step)

        # Update positions and forces
        self.old_x[:] = self.beads.q
        self.old_u[:] = self.forces.pots
        self.old_f[:] = self.forces.f
Example #27
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)
Example #28
0
def force(beads, cell, masses, temp, dt, state):
    global bead_out_files

    nbeads = len(beads.q)
    if len(bead_out_files) == 0:
        bead_out_files = [
            open('CV_' + str(i + 1) + '.out', 'w') for i in range(nbeads)
        ]

    if len(state['modes']['a']) > (nbeads + 1) / 2:
        state['modes']['a'] = np.resize(state['modes']['a'], (nbeads + 1) / 2)

    cv_set = [cv.get_cv_set(q, state['CV'], masses) for q in beads.q]
    if state['ghts'].get('M') is None:
        state['ghts']['M'] = np.average(
            [bead_cv_set.m for bead_cv_set in cv_set], 0) / AMU
        state['ghts']['n'] = np.matmul(state['ghts']['M'], state['ghts']['n'])

    params = convert_params(state['params'])
    modes = convert_modes(state['modes'])
    nmodes = len(modes['a'])
    ghts = convert_ghts(state['ghts'])

    q = rp.get_q(ghts, cv_set)
    r = nm.get_r(q, nmodes)
    sigma = nm.get_sigma(modes, r)
    d = rp.get_d(ghts, cv_set)

    stage = state['stage']
    stage['step'] = stage.get('step', 0)

    step = stage['step']
    print_CV_every = state['output'].get('print_CV_every', 1)

    if step % print_CV_every == 0:
        restraints = [[
            cv.get_cv(bead, restr).value for restr in state['restraints']
        ] for bead in beads.q]
        write_centroid_data(cv_set, sigma, q, d, r, restraints, out_file)
        write_bead_data(cv_set, ghts, restraints, bead_out_files)

    stage['step'] += 1

    if stage['name'] == 'optimize':
        optimizer.move(modes, ghts, cv_set, r, sigma, params,
                       params['K'] / temp, dt)

    if stage['name'] == 'sample':

        if (stage.get('optimizer_data')
                and stage['step'] % stage.get('optimizer_data_step', 1) == 0):
            with open(stage['optimizer_data'], 'a+') as f:
                write_optimizer_data(cv_set, f)

        stage['last_save_step'] = stage.get('last_save_step', stage['step'])
        stage['last_saved'] = stage.get('last_saved', (stage['walker'] - 1) *
                                        stage['structures'])
        if abs(sigma.value * SQAMU) < stage['q_threshold'] and \
           stage['step'] >= stage['last_save_step'] + stage['offset']:
            idx = stage['last_saved'] + 1
            with open(str(idx) + ".xyz", 'w') as f:
                print_file_path('xyz', beads, cell, f, units='angstrom')
            stage['last_saved'] = idx
            stage['last_save_step'] = stage['step']
            if idx == stage['walker'] * stage['structures']:
                softexit.trigger('exit ' + str(stage['walker']))

    if stage['name'] == 'prepare' and stage['step'] <= stage['prepare_steps']:
        params['K'] *= float(stage['step']) / stage['prepare_steps']
        params['K_d'] *= float(stage['step']) / stage['prepare_steps']
        if stage['step'] == stage['prepare_steps']:
            stage['name'] = 'optimize'
            stage['step'] = 0

    sigma_bias = harmonic_bias(rp.get_sigma(sigma, q), params['K'] * nbeads, 0)
    d_bias = side_harmonic_bias(d, params['K_d'] * nbeads, params['d_max'])

    restraint_biases = np.zeros(beads.q.shape, beads.q.dtype)
    for restraint in state.get('restraints', []):
        restraint_biases += np.array(
            [restraint_bias(bead, restraint) for bead in beads.q])

    if stage['name'] == 'committor':
        if abs(sigma.value * SQAMU) > stage['q_threshold']:
            softexit.trigger('q_threshold reached')
        return sigma_bias * 0

    recover_ghts(state, ghts)
    recover_modes(state, modes)

    return sigma_bias + d_bias + restraint_biases
Example #29
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")
Example #30
0
    def store(self, sc):
        """Takes a motion calculation instance and stores a minimal representation of it.

        Args:
           sc: A motion calculation class.
        """

        super(InputMotionBase, self).store(sc)
        tsc = -1
        if type(sc) is Motion:
            self.mode.store("dummy")
        elif type(sc) is Replay:
            self.mode.store("replay")
            tsc = 0
        elif type(sc) is GeopMotion:
            self.mode.store("minimize")
            self.optimizer.store(sc)
            tsc = 1
        elif type(sc) is NEBMover:
            self.mode.store("neb")
            self.neb_optimizer.store(sc)
            tsc = 1
        elif type(sc) is Dynamics:
            self.mode.store("dynamics")
            self.dynamics.store(sc)
            tsc = 1
        elif type(sc) is ConstrainedDynamics:
            self.mode.store("constrained_dynamics")
            self.constrained_dynamics.store(sc)
            tsc = 1
        elif type(sc) is DynMatrixMover:
            self.mode.store("vibrations")
            self.vibrations.store(sc)
            tsc = 1
        elif type(sc) is AlchemyMC:
            self.mode.store("alchemy")
            self.alchemy.store(sc)
            tsc = 1
        elif type(sc) is AtomSwap:
            self.mode.store("atomswap")
            self.atomswap.store(sc)
            tsc = 1
        elif type(sc) is InstantonMotion:
            self.mode.store("instanton")
            self.instanton.store(sc)
            tsc = 1
        elif type(sc) is Planetary:
            self.mode.store("planetary")
            self.planetary.store(sc)
            tsc = 1
        elif type(sc) is TemperatureRamp:
            self.mode.store("t_ramp")
            self.t_ramp.store(sc)
            tsc = 1
        elif type(sc) is PressureRamp:
            self.mode.store("p_ramp")
            self.p_ramp.store(sc)
        elif type(sc) is AlKMC:
            self.mode.store("al-kmc")
            self.al6xxx_kmc.store(sc)
            tsc = 1
        else:
            raise ValueError("Cannot store Mover calculator of type " +
                             str(type(sc)))

        if (sc.fixcom is True) and (len(sc.fixatoms) > 0):
            softexit.trigger(
                "Fixed atoms break translational invariance, and so should be used with <fixcom> False </fixcom>. You can disable this error if you know what you are doing."
            )

        if tsc == 0:
            self.file.store(sc.intraj)
        elif tsc > 0:
            self.fixcom.store(sc.fixcom)
            self.fixatoms.store(sc.fixatoms)
Example #31
0
    def step(self, step=None):
        """Does one replay time step."""

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

        # If wildcard is used, check that it is consistent with Nbeads
        wildcard_used = False
        if any(char in self.intraj.value for char in "*?[]"):
            wildcard_used = True
            if len(self.rfile) != len(self.beads):
                info(
                    "Error: if a wildcard is used for replay, then "
                    "the number of files should be equal to the number of beads.",
                    verbosity.low,
                )
                softexit.trigger(" # Error in replay input.")
        while True:
            self.rstep += 1
            try:
                if self.intraj.mode == "xyz":
                    for bindex, b in enumerate(self.beads):
                        if wildcard_used:
                            myframe = read_file("xyz", self.rfile[bindex])
                        else:
                            myframe = read_file("xyz", self.rfile)
                        myatoms = myframe["atoms"]
                        mycell = myframe["cell"]
                        myatoms.q *= unit_to_internal("length",
                                                      self.intraj.units, 1.0)
                        mycell.h *= unit_to_internal("length",
                                                     self.intraj.units, 1.0)
                        b.q[:] = myatoms.q
                elif self.intraj.mode == "pdb":
                    for bindex, b in enumerate(self.beads):
                        if wildcard_used:
                            myatoms, mycell = read_file(
                                "pdb", self.rfile[bindex])
                        else:
                            myatoms, mycell = read_file("pdb", self.rfile)
                        myatoms.q *= unit_to_internal("length",
                                                      self.intraj.units, 1.0)
                        mycell.h *= unit_to_internal("length",
                                                     self.intraj.units, 1.0)
                        b.q[:] = myatoms.q
                elif self.intraj.mode == "chk" or self.intraj.mode == "checkpoint":
                    # TODO: Adapt the new `Simulation.load_from_xml`?
                    # reads configuration from a checkpoint file
                    xmlchk = xml_parse_file(self.rfile)  # Parses the file.

                    from ipi.inputs.simulation import InputSimulation

                    simchk = InputSimulation()
                    simchk.parse(xmlchk.fields[0][1])
                    mycell = simchk.cell.fetch()
                    mybeads = simchk.beads.fetch()
                    self.beads.q[:] = mybeads.q
                    softexit.trigger(" # Read single checkpoint")
                # do not assign cell if it contains an invalid value (typically missing cell in the input)
                if mycell.V > 0:
                    self.cell.h[:] = mycell.h
            except EOFError:
                softexit.trigger(" # Finished reading re-run trajectory")
            if (step is None) or (self.rstep > step):
                break

        self.qtime += time.time()
Example #32
0
    def step(self, step=None):
        """ Does one simulation time step."""

        self.qtime = -time.time()
        info("\n Instanton optimization STEP %d" % step, verbosity.low)

        if step == 0:
            info(" @GEOP: Initializing INSTANTON", verbosity.low)

            if self.beads.nbeads == 1:
                raise ValueError(
                    "We can not perform an splitting calculation with nbeads =1"
                )
                # get_hessian(self.hessian, self.gm, self.beads.q)
            else:
                if ((self.beads.q - self.beads.q[0]) == 0).all(
                ):  # If the coordinates in all the imaginary time slices are the same
                    info(
                        " @GEOP: We stretch the initial geometry with an 'amplitud' of %4.2f"
                        % self.delta, verbosity.low)
                    imvector = get_imvector(self.initial_hessian,
                                            self.beads.m3[0].flatten())
                    for i in range(self.beads.nbeads):

                        self.beads.q[i, :] += self.delta * np.cos(
                            i * np.pi /
                            float(self.beads.nbeads - 1)) * imvector[:]
                else:
                    info(
                        " @GEOP: Starting from the provided geometry in the extended phase space",
                        verbosity.low)

            # Update positions and forces
            self.old_x[:] = self.beads.q
            self.old_u[:] = self.forces.pots
            self.old_f[:] = self.forces.f

        # This must be done after the stretching and before the self.d.
        if type(self.im.f) == type(None):
            self.im(self.beads.q, ret=False)  # Init instanton mapper

        # Specific for LBFGS
        if np.linalg.norm(self.d) == 0.0:
            f = self.forces.f + self.im.f  #ALBERTO1
            self.d += dstrip(f) / np.sqrt(np.dot(f.flatten(), f.flatten()))

        if (self.old_x == np.zeros((self.beads.nbeads, 3 * self.beads.natoms),
                                   float)).all():
            self.old_x[:] = self.beads.q

        if self.exit:
            softexit.trigger(
                "Geometry optimization converged. Exiting simulation")

        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

        e, g = self.fm(self.beads.q)
        fdf0 = (e, g)

        # Do one step. Update hessian for the new position. Update the position and force inside the mapper.
        L_BFGS(self.old_x, self.d, self.fm, self.qlist, self.glist, fdf0,
               self.big_step,
               self.ls_options["tolerance"] * self.tolerances["energy"],
               self.ls_options["iter"], self.corrections, self.scale, step)
        # ALBERTO2

        # 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.exit = self.exitstep(self.forces.pot, self.old_u.sum(), d_x_max,
                                  self.exit, step)

        # Update positions and forces
        self.old_x[:] = self.beads.q
        self.old_u[:] = self.forces.pots
        self.old_f[:] = self.forces.f

        # Print current instanton geometry and hessian
        if (self.save > 0 and np.mod(step, self.save) == 0) or self.exit:
            print_instanton_geo(self.prefix, step, self.im.dbeads.nbeads,
                                self.im.dbeads.natoms, self.im.dbeads.names,
                                self.im.dbeads.q, self.old_u, self.cell,
                                self.energy_shift)