Ejemplo n.º 1
0
def main(inputfile, propertyname="potential", skip="0"):
    skip = int(skip)

    # opens & parses the input file
    ifile = open(inputfile, "r")

    reprop = re.compile(' ([0-9]*) *--> ' + propertyname)
    reunit = re.compile('{(.*)}')

    # now reads the file one frame at a time, and outputs only the required column(s)
    icol = -1
    step = 0
    while True:
        try:
            line = ifile.readline()
            if len(line) == 0: raise EOFError
            while line[0] == "#":  # fast forward if line is a comment
                rm = reprop.search(line)
                if not (rm is None):
                    if icol >= 0:
                        warning("Multiple instances of the specified property " + propertyname + " have been found")
                        raise EOFError
                    icol = int(rm.group(1)) - 1
                line = ifile.readline()
                if len(line) == 0: raise EOFError
            if (icol < 0):
                warning("Could not find " + propertyname + " in file " + inputfile)
                raise EOFError
            line = line.split()
            if (step >= skip): print line[icol]
            step += 1
        except EOFError:
            break
Ejemplo n.º 2
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)
Ejemplo n.º 3
0
def init_chk(filename):
    """Reads a checkpoint file and returns the data contained in it.

    Args:
       filename: A string giving the name of the checkpoint file to be read from.

    Returns:
       A Beads object, Cell object and Thermostat object as read from the
       checkpoint file.
    """

    # reads configuration from a checkpoint file
    rfile = open(filename, "r")
    xmlchk = xml_parse_file(rfile)  # Parses the file.

    from ipi.inputs.simulation import InputSimulation
    simchk = InputSimulation()
    simchk.parse(xmlchk.fields[0][1])
    sim = simchk.fetch()
    if len(sim.syslist) > 1:
        warning("Restart from checkpoint with " + str(len(sim.syslist)) + " systems will fetch data from the first system.")
    rcell = sim.syslist[0].cell
    rbeads = sim.syslist[0].beads
    rmotion = sim.syslist[0].motion

    return (rbeads, rcell, rmotion)
Ejemplo n.º 4
0
def root_herm(A):
    """Computes the square root of a positive-definite hermitian matrix.

    Args:
       A: A Hermitian matrix.

    Returns:
       A matrix such that itself matrix multiplied by its transpose gives the
       original matrix.
    """

    if not (abs(A.T - A) < 1e-10).all():
        raise ValueError("Non-Hermitian matrix passed to root_herm function")
    eigvals, eigvecs = np.linalg.eigh(A)
    ndgrs = len(eigvals)
    diag = np.zeros((ndgrs, ndgrs))
    negev = False
    for i in range(ndgrs):
        if eigvals[i] >= 0:
            diag[i, i] = math.sqrt(eigvals[i])
        else:
            warning("Zeroing negative %d-th element in matrix square root: %e" % (i, eigvals[i]), verbosity.low)
            diag[i, i] = 0
            negev = True
    rv = np.dot(eigvecs, np.dot(diag, eigvecs.T))
    if negev:
        warning("Checking decomposition after negative eigenvalue: \n" + str(A - np.dot(rv, rv.T)), verbosity.low)

    return rv
Ejemplo n.º 5
0
    def get_potssc(self):
        """Obtains Suzuki-Chin contribution to the potential."""
        if self.nbeads % 2 != 0:
            warning("ERROR: Suzuki-Chin factorization requires even number of beads!")
            exit()

        # this evaluates the square forces contribution to the SC potential (only the difference with the Trotter potential is returned)
        return self.coeffsc_part_1.T * dstrip(self.pots) + self.coeffsc_part_2.T * np.sum(dstrip(self.f) / self.beads.m3 * dstrip(self.f), axis=1)
Ejemplo n.º 6
0
   def recvall(self, dest):
      """Gets the potential energy, force and virial from the driver.

      Args:
         dest: Object to be read into.

      Raises:
         Disconnected: Raised if client is disconnected.

      Returns:
         The data read from the socket to be read into dest.
      """

      blen = dest.itemsize*dest.size
      if (blen > len(self._buf)):
         self._buf.resize(blen)
      bpos = 0
      ntimeout = 0

      while bpos < blen:
         timeout = False

#   pre-2.5 version.
         try:
            bpart = ""            
            bpart = self.recv(blen - bpos)
            if len(bpart) == 0: raise socket.timeout  # There is a problem if this returns no data
            self._buf[bpos:bpos + len(bpart)] = np.fromstring(bpart, np.byte)
         except socket.timeout:
            warning(" @SOCKET:   Timeout in status recvall, trying again!", verbosity.low)
            timeout = True
            ntimeout += 1
            if ntimeout > NTIMEOUT:
               warning(" @SOCKET:  Couldn't receive within %5d attempts. Time to give up!" % (NTIMEOUT), verbosity.low)
               raise Disconnected()
            pass
         if (not timeout and bpart == 0):
            raise Disconnected()
         bpos += len(bpart)

#   post-2.5 version: slightly more compact for modern python versions
#         try:
#            bpart = 1
#            bpart = self.recv_into(self._buf[bpos:], blen-bpos)
#         except socket.timeout:
#            print " @SOCKET:   Timeout in status recvall, trying again!"
#            timeout = True
#            pass
#         if (not timeout and bpart == 0):
#            raise Disconnected()
#         bpos += bpart
#TODO this Disconnected() exception currently just causes the program to hang.
#This should do something more graceful

      if np.isscalar(dest):
         return np.fromstring(self._buf[0:blen], dest.dtype)[0]
      else:
         return np.fromstring(self._buf[0:blen], dest.dtype).reshape(dest.shape)
Ejemplo n.º 7
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,
                    )
                    c.shutdown(socket.SHUT_RDWR)
                    c.close()
                except:
                    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

        keepsearch = True
        while keepsearch:
            readable, writable, errored = select.select([self.server], [], [], 0.0)
            if self.server in readable:
                client, address = self.server.accept()
                client.settimeout(TIMEOUT)
                driver = DriverSocket(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)
                else:
                    warning(" @SOCKET:   Handshaking failed. Dropping connection.", verbosity.low)
                    client.shutdown(socket.SHUT_RDWR)
                    client.close()
            else:
                keepsearch = False
Ejemplo n.º 8
0
    def close_stream(self):
        """Closes the output stream."""

        try:
            if hasattr(self.out, "__getitem__"):
                for o in self.out:
                    o.close()
            else:
                self.out.close()
        except AttributeError:
                    # This gets called on softexit. We want to carry on to shut down as cleanly as possible
            warning("Exception while closing output stream " + str(self.out), verbosity.low)
Ejemplo n.º 9
0
   def bind(self, beads=None, atoms=None, pm=None, prng=None, fixdof=None):
      """Binds the appropriate degrees of freedom to the thermostat.

      This takes an object with degrees of freedom, and makes their momentum
      and mass vectors members of the thermostat. It also then creates the
      objects that will hold the data needed in the thermostat algorithms
      and the dependency network.

      Args:
         beads: An optional beads object to take the mass and momentum vectors
            from.
         atoms: An optional atoms object to take the mass and momentum vectors
            from.
         pm: An optional tuple containing a single momentum value and its
            conjugate mass.
         prng: An optional pseudo random number generator object. Defaults to
            Random().
         fixdof: An optional integer which can specify the number of constraints
            applied to the system. Defaults to zero.

      Raises:
         TypeError: Raised if no appropriate degree of freedom or object
            containing a momentum vector is specified for
            the thermostat to couple to.
      """

      if prng is None:
         warning("Initializing thermostat from standard random PRNG", verbosity.medium)
         self.prng = Random()
      else:
         self.prng = prng

      if not beads is None:
         dset(self,"p",beads.p.flatten())
         dset(self,"m",beads.m3.flatten())
      elif not atoms is None:
         dset(self,"p",dget(atoms, "p"))
         dset(self,"m",dget(atoms, "m3"))
      elif not pm is None:
         dset(self,"p",pm[0])
         dset(self,"m",pm[1])
      else:
         raise TypeError("Thermostat.bind expects either Beads, Atoms, NormalModes, or a (p,m) tuple to bind to")

      if fixdof is None:
         self.ndof = len(self.p)
      else:
         self.ndof = float(len(self.p) - fixdof)

      dset(self, "sm",
         depend_array(name="sm", value=np.zeros(len(dget(self,"m"))),
            func=self.get_sm, dependencies=[dget(self,"m")]))
Ejemplo n.º 10
0
   def getforce(self):
      """Gets the potential energy, force and virial from the driver.

      Raises:
         InvalidStatus: Raised if the status is not HasData.
         Disconnected: Raised if the driver has disconnected.

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

      if (self.status & Status.HasData):
         self.sendall(Message("getforce"));
         reply = ""         
         while True:            
            try:
               reply = self.recv(HDRLEN)
            except socket.timeout:
               warning(" @SOCKET:   Timeout in getforce, trying again!", verbosity.low)
               continue
            if reply == Message("forceready"):
               break
            else:
               warning(" @SOCKET:   Unexpected getforce reply: %s" % (reply), verbosity.low)
            if reply == "":
               raise Disconnected()
      else:
         raise InvalidStatus("Status in getforce was " + self.status)
      
      mu = np.float64()
      mu = self.recvall(mu)

      mlen = np.int32()
      mlen = self.recvall(mlen)
      mf = np.zeros(3*mlen,np.float64)
      mf = self.recvall(mf)

      mvir = np.zeros((3,3),np.float64)
      mvir = self.recvall(mvir)
      
      #! Machinery to return a string as an "extra" field. Comment if you are using a old patched driver that does not return anything!
      mlen = np.int32()
      mlen = self.recvall(mlen)
      if mlen > 0 :
         mxtra = np.zeros(mlen,np.character)
         mxtra = self.recvall(mxtra)
         mxtra = "".join(mxtra)
      else:
         mxtra = ""

      #!TODO must set up a machinery to intercept the "extra" return field
      return [mu, mf, mvir, mxtra]
Ejemplo n.º 11
0
def stab_cholesky(M):
    """ A numerically stable version of the Cholesky decomposition.

    Used in the GLE implementation. Since many of the matrices used in this
    algorithm have very large and very small numbers in at once, to handle a
    wide range of frequencies, a naive algorithm can end up having to calculate
    the square root of a negative number, which breaks the algorithm. This is
    due to numerical precision errors turning a very tiny positive eigenvalue
    into a tiny negative value.

    Instead of this, an LDU decomposition is used, and any small negative numbers
    in the diagonal D matrix are assumed to be due to numerical precision errors,
    and so are replaced with zero.

    Args:
       M: The matrix to be decomposed.
    """

    n = M.shape[1]
    D = np.zeros(n, float)
    L = np.zeros(M.shape, float)
    for i in range(n):
        L[i, i] = 1.
        for j in range(i):
            L[i, j] = M[i, j]
            for k in range(j):
                L[i, j] -= L[i, k] * L[j, k] * D[k]
            if (not D[j] == 0.0):
                L[i, j] = L[i, j] / D[j]
        D[i] = M[i, i]
        for k in range(i):
            D[i] -= L[i, k] * L[i, k] * D[k]

    negev = False
    S = np.zeros(M.shape, float)
    for i in range(n):
        if (D[i] > 0):
            D[i] = math.sqrt(D[i])
        else:
            warning("Zeroing negative element in stab-cholesky decomposition: " + str(D[i]), verbosity.low)
            negev = True
            D[i] = 0
        for j in range(i + 1):
            S[i, j] += L[i, j] * D[j]

    if negev:
        warning("Checking decomposition after negative eigenvalue: \n" + str(M - np.dot(S, S.T)), verbosity.low)

    return S
Ejemplo n.º 12
0
   def update_auto(self):
      """Automatic update routine.

      Updates the value when get has been called and self has been tainted.
      """

      if not self._synchro is None:
         if (not self._name == self._synchro.manual):
            self.set(self._func[self._synchro.manual](), manual=False)
         else:
            warning(self._name + " probably shouldn't be tainted (synchro)", verbosity.low)
      elif not self._func is None:
         self.set(self._func(), manual=False)
      else:
         warning(self._name + " probably shouldn't be tainted (value)", verbosity.low)
Ejemplo n.º 13
0
   def trigger(self, message=""):
      """Halts the simulation.

      Prints out a warning message, then runs all the exit functions in flist
      before terminating the simulation.

      Args:
         message: The message to output to standard output.
      """

      if message != "":
         warning("Soft exit has been requested with message: '" + message + "'. Cleaning up.", verbosity.low)
      for f in self.flist:
         f()
      sys.exit()
Ejemplo n.º 14
0
    def check(self):
        """Function that deals with optional arguments."""

        super(InputInterfaceSocket, self).check()
        if self.port.fetch() < 1 or self.port.fetch() > 65535:
            raise ValueError("Port number " + str(self.port.fetch()) + " out of acceptable range.")
        elif self.port.fetch() < 1025:
            warning("Low port number being used, this may interrupt important system processes.", verbosity.low)

        if self.slots.fetch() < 1 or self.slots.fetch() > 5:
            raise ValueError("Slot number " + str(self.slots.fetch()) + " out of acceptable range.")
        if self.latency.fetch() < 0:
            raise ValueError("Negative latency parameter specified.")
        if self.timeout.fetch() < 0.0:
            raise ValueError("Negative timeout parameter specified.")
Ejemplo n.º 15
0
    def __init__(self, mode, syslist, fflist, outputs, prng, smotion=None, step=0, tsteps=1000, ttime=0, threads=False):
        """Initialises Simulation class.

        Args:
            mode: What kind of simulation is this
            syslist: A list of system objects
            fflist: A list of forcefield objects
            prng: A random number object.
            smotion: A "super-motion" class specifying what to do with different system replicas
            outputs: A list of output objects.
            step: An optional integer giving the current simulation time step.
                Defaults to 0.
            tsteps: An optional integer giving the total number of steps. Defaults
                to 1000.
            ttime: The simulation running time. Used on restart, to keep a
                cumulative total.
        """

        info(" # Initializing simulation object ", verbosity.low)
        self.prng = prng
        self.mode = mode
        self.threading = threads
        dself = dd(self)

        self.syslist = syslist
        for s in syslist:
            s.prng = self.prng    # bind the system's prng to self prng
            s.init.init_stage1(s)

        #! TODO - does this have any meaning now that we introduce the smotion class?
        if self.mode == "md" and len(syslist) > 1:
            warning("Multiple systems will evolve independently in a '" + self.mode + "' simulation.")

        self.fflist = {}
        for f in fflist:
            self.fflist[f.name] = f

        self.outtemplate = outputs

        dself.step = depend_value(name="step", value=step)
        self.tsteps = tsteps
        self.ttime = ttime
        self.smotion = smotion

        self.chk = None
        self.rollback = True
Ejemplo n.º 16
0
   def fetch(self):
      """Creates a cell initializer object.

      Note that the cell can be initialized from the lengths of the sides and
      the angles between them instead of by a vector, as specified by the
      'abc' or 'abcABC' modes.
      """

      mode = self.mode.fetch()

      ibase = super(InputInitCell,self).fetch()
      if mode == "abc" or mode == "abcABC":

         h = io_xml.read_array(np.float, ibase.value)

         if mode == "abc":
            if h.size != 3:
               raise ValueError("If you are initializing cell from cell side lengths you must pass the 'cell' tag an array of 3 floats.")
            else:
               h = mt.abc2h(h[0], h[1], h[2], np.pi/2, np.pi/2, np.pi/2)
         elif mode == "abcABC":
            if h.size != 6:
               raise ValueError("If you are initializing cell from cell side lengths and angles you must pass the 'cell' tag an array of 6 floats.")
            else:
               h = mt.abc2h(h[0], h[1], h[2], h[3]*np.pi/180.0, h[4]*np.pi/180.0, h[5]*np.pi/180.0)

         h.shape = (9,)
         ibase.value = h
         mode = "manual"

      if mode == "manual":
         h = ibase.value
         if h.size != 9:
               raise ValueError("Cell objects must contain a 3x3 matrix describing the cell vectors.")

         if not (h[3] == 0.0 and h[6] == 0.0 and h[7] == 0.0):
            warning("Cell vector matrix must be upper triangular, all elements below the diagonal being set to zero.", verbosity.low)
            h[3] = h[6] = h[7] = 0
         ibase.value = h

      return self._initclass(value=ibase.value, mode=mode, units=self.units.fetch())
Ejemplo n.º 17
0
    def bind(self, beads=None, atoms=None, pm=None, nm=None, prng=None, fixdof=None):
        """Binds the appropriate degrees of freedom to the thermostat.

        This takes an object with degrees of freedom, and makes their momentum
        and mass vectors members of the thermostat. It also then creates the
        objects that will hold the data needed in the thermostat algorithms
        and the dependency network.

        Args:
           beads: An optional beads object to take the mass and momentum vectors
              from.
           atoms: An optional atoms object to take the mass and momentum vectors
              from.
           pm: An optional tuple containing a single momentum value and its
              conjugate mass.
           prng: An optional pseudo random number generator object. Defaults to
              Random().
           fixdof: An optional integer which can specify the number of constraints
              applied to the system. Defaults to zero.

        Raises:
           TypeError: Raised if no appropriate degree of freedom or object
              containing a momentum vector is specified for
              the thermostat to couple to.
        """

        super(ThermoGLE, self).bind(beads=beads, atoms=atoms, pm=pm, prng=prng, fixdof=fixdof)
        dself = dd(self)

        # allocates, initializes or restarts an array of s's
        if self.s.shape != (self.ns + 1, len(dself.m)):
            if len(self.s) > 0:
                warning("Mismatch in GLE s array size on restart, will reinitialise to free particle.", verbosity.low)
            self.s = np.zeros((self.ns + 1, len(dself.m)))

            # Initializes the s vector in the free-particle limit
            info(" GLE additional DOFs initialised to the free-particle limit.", verbosity.low)
            SC = stab_cholesky(self.C * Constants.kb)
            self.s[:] = np.dot(SC, self.prng.gvec(self.s.shape))
        else:
            info("GLE additional DOFs initialised from input.", verbosity.medium)
Ejemplo n.º 18
0
def root_herm(A):
   """Gives the square root of a hermitian matrix with real eigenvalues.

   Args:
      A: A Hermitian matrix.

   Returns:
      A matrix such that itself matrix multiplied by its transpose gives the
      original matrix.
   """

   if not (abs(A.T - A) < 1e-10).all():
      raise ValueError("Non-Hermitian matrix passed to root_herm function")
   eigvals, eigvecs = np.linalg.eigh(A)
   ndgrs = len(eigvals)
   diag = np.zeros((ndgrs,ndgrs))
   for i in range(ndgrs):
      if eigvals[i] >= 0:
         diag[i,i] = math.sqrt(eigvals[i])
      else:
         warning("Zeroing negative element in matrix square root: " + str(eigvals[i]), verbosity.low)
         diag[i,i] = 0
   return np.dot(eigvecs, np.dot(diag, eigvecs.T))
Ejemplo n.º 19
0
   def _getstatus(self):
      """Gets driver status.

      Returns:
         An integer labelling the status via bitwise or of the relevant members
         of Status.
      """
            
      if not self.waitstatus:
         try:
            readable, writable, errored = select.select([], [self], [])
            if self in writable:
               self.sendall(Message("status"))
               self.waitstatus = True
         except:
            return Status.Disconnected

      try:
         reply = self.recv(HDRLEN)
         self.waitstatus = False # got status reply         
      except socket.timeout:
         warning(" @SOCKET:   Timeout in status recv!", verbosity.debug )
         return Status.Up | Status.Busy | Status.Timeout
      except:
         return Status.Disconnected
      
      if not len(reply) == HDRLEN:
         return Status.Disconnected
      elif reply == Message("ready"):
         return Status.Up | Status.Ready
      elif reply == Message("needinit"):
         return Status.Up | Status.NeedsInit
      elif reply == Message("havedata"):
         return Status.Up | Status.HasData
      else:
         warning(" @SOCKET:    Unrecognized reply: " + str(reply), verbosity.low )
         return Status.Up
Ejemplo n.º 20
0
Archivo: multi.py Proyecto: i-pi/i-pi
    def bind(self, syslist, prng, omaker):
        """Binds beads, cell, bforce, and prng to the calculator.

        This takes a beads object, a cell object, a forcefield object and a
        random number generator object and makes them members of the atom motion caclulator.
        It also then creates the objects that will hold the data needed in the
        ensemble algorithms and the dependency network. Note that the conserved
        quantity is defined in the init, but as each ensemble has a different
        conserved quantity the dependencies are defined in bind.

        Args:
            beads: The beads object from whcih 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(MultiSmotion, self).bind(syslist, prng, omaker)
        for k, m in enumerate(self.mlist):
            m.bind(syslist,prng, omaker)
            if type(m) is MetaDyn and k!=len(self.mlist)-1 and type(self.mlist[k+1]) != MetaDyn :
                warning("MetaD Smotion should come last in a multi Smotion to avoid a discrepancy between i-PI and PLUMED outputs", verbosity.low)
Ejemplo n.º 21
0
   def get_nmm(self):
      """Returns dynamical mass factors, i.e. the scaling of normal mode
      masses that determine the path dynamics (but not statics)."""

      # also checks that the frequencies and the mode given in init are
      # consistent with the beads and ensemble

      dmf = np.zeros(self.nbeads,float)
      dmf[:] = 1.0
      if self.mode == "rpmd":
         if len(self.nm_freqs) > 0:
            warning("nm.frequencies will be ignored for RPMD mode.", verbosity.low)
      elif self.mode == "manual":
         if len(self.nm_freqs) != self.nbeads-1:
            raise ValueError("Manual path mode requires (nbeads-1) frequencies, one for each internal mode of the path.")
         for b in range(1, self.nbeads):
            sk = self.omegak[b]/self.nm_freqs[b-1]
            dmf[b] = sk**2
      elif self.mode == "pa-cmd":
         if len(self.nm_freqs) > 1:
            warning("Only the first element in nm.frequencies will be considered for PA-CMD mode.", verbosity.low)
         if len(self.nm_freqs) == 0:
            raise ValueError("PA-CMD mode requires the target frequency of all the internal modes.")
         for b in range(1, self.nbeads):
            sk = self.omegak[b]/self.nm_freqs[0]
            info(" ".join(["NM FACTOR", str(b), str(sk), str(self.omegak[b]), str(self.nm_freqs[0])]), verbosity.medium)
            dmf[b] = sk**2
      elif self.mode == "wmax-cmd":
         if len(self.nm_freqs) > 2:
            warning("Only the first two element in nm.frequencies will be considered for WMAX-CMD mode.", verbosity.low)
         if len(self.nm_freqs) < 2:
            raise ValueError("WMAX-CMD mode requires [wmax, wtarget]. The normal modes will be scaled such that the first internal mode is at frequency wtarget and all the normal modes coincide at frequency wmax.")
         wmax = self.nm_freqs[0]
         wt = self.nm_freqs[1]
         for b in range(1, self.nbeads):
            sk = 1.0/np.sqrt((wt)**2*(1+(wmax/self.omegak[1])**2)/(wmax**2+(self.omegak[b])**2))
            dmf[b] = sk**2

      return dmf
Ejemplo n.º 22
0
   def pool_distribute(self):
      """Deals with keeping the list of jobs up-to-date during a force
      calculation step.

      Deals with maintaining the jobs list. Gets data from drivers that have
      finished their calculation and removes that job from the list of running
      jobs, adds jobs to free clients and initialises the forcefields of new
      clients.
      """

      for c in self.clients:
         if c.status == Status.Disconnected : # client disconnected. force a pool_update
            self._poll_iter = UPDATEFREQ
            return
         if not c.status & ( Status.Ready | Status.NeedsInit ):
            c.poll()

      for [r,c] in self.jobs[:]:
         if c.status & Status.HasData:
            try:
               r["result"] = c.getforce()
               if len(r["result"][1]) != len(r["pos"]):
                  raise InvalidSize
            except Disconnected:
               c.status = Status.Disconnected
               continue
            except InvalidSize:
              warning(" @SOCKET:   Client returned an inconsistent number of forces. Will mark as disconnected and try to carry on.", verbosity.low)
              c.status = Status.Disconnected
              continue
            except:
              warning(" @SOCKET:   Client got in a awkward state during getforce. Will mark as disconnected and try to carry on.", verbosity.low)
              c.status = Status.Disconnected
              continue
            c.poll()
            while c.status & Status.Busy: # waits, but check if we got stuck.
               if self.timeout > 0 and r["start"] > 0 and time.time() - r["start"] > self.timeout:
                  warning(" @SOCKET:  Timeout! HASDATA for bead " + str(r["id"]) + " has been running for " + str(time.time() - r["start"]) + " sec.", verbosity.low)
                  warning(" @SOCKET:   Client " + str(c.peername) + " died or got unresponsive(A). Disconnecting.", verbosity.low)
                  try:
                     c.shutdown(socket.SHUT_RDWR)
                  except:
                     pass
                  c.close()
                  c.status = Status.Disconnected
                  continue
               c.poll()
            if not (c.status & Status.Up):
               warning(" @SOCKET:   Client died a horrible death while getting forces. Will try to cleanup.", verbosity.low)
               continue
            r["status"] = "Done"
            c.lastreq = r["id"] # saves the ID of the request that the client has just processed
            self.jobs = [ w for w in self.jobs if not ( w[0] is r and w[1] is c ) ] # removes pair in a robust way

         if self.timeout > 0 and c.status != Status.Disconnected and r["start"] > 0 and time.time() - r["start"] > self.timeout:
            warning(" @SOCKET:  Timeout! Request for bead " + str( r["id"]) + " has been running for " + str(time.time() - r["start"]) + " sec.", verbosity.low)
            warning(" @SOCKET:   Client " + str(c.peername) + " died or got unresponsive(B). Disconnecting.",verbosity.low)
            try:
               c.shutdown(socket.SHUT_RDWR)
            except socket.error:
               e = sys.exc_info()
               warning(" @SOCKET:  could not shut down cleanly the socket. %s: %s in file '%s' on line %d" % (e[0].__name__, e[1], os.path.basename(e[2].tb_frame.f_code.co_filename), e[2].tb_lineno), verbosity.low )
            c.close()
            c.poll()
            c.status = Status.Disconnected

      freec = self.clients[:]
      for [r2, c] in self.jobs:
         freec.remove(c)

      pendr = self.requests[:]
      pendr = [ r for r in self.requests if r["status"] == "Queued" ]

      for fc in freec[:]:
         matched = False
         # first, makes sure that the client is REALLY free
         if not (fc.status & Status.Up):
            self.clients.remove(fc)   # if fc is in freec it can't be associated with a job (we just checked for that above)
            continue
         if fc.status & Status.HasData:
            continue
         if not (fc.status & (Status.Ready | Status.NeedsInit | Status.Busy) ):
            warning(" @SOCKET: Client " + str(fc.peername) + " is in an unexpected status " + str(fc.status) + " at (1). Will try to keep calm and carry on.", verbosity.low)
            continue
         for match_ids in ( "match", "none", "free", "any" ):
            for r in pendr[:]:
               if match_ids == "match" and not fc.lastreq is r["id"]:
                  continue
               elif match_ids == "none" and not fc.lastreq is None:
                  continue
               elif match_ids == "free" and fc.locked:
                  continue

               info(" @SOCKET: Assigning [%5s] request id %4s to client with last-id %4s (% 3d/% 3d : %s)" % (match_ids,  str(r["id"]),  str(fc.lastreq), self.clients.index(fc), len(self.clients), str(fc.peername) ), verbosity.high )

               while fc.status & Status.Busy:
                  fc.poll()
               if fc.status & Status.NeedsInit:
                  fc.initialize(r["id"], r["pars"])
                  fc.poll()
                  while fc.status & Status.Busy: # waits for initialization to finish. hopefully this is fast
                     fc.poll()
               if fc.status & Status.Ready:
                  fc.sendpos(r["pos"], r["cell"])
                  r["status"] = "Running"
                  r["start"] = time.time() # sets start time for the request
                  fc.poll()
                  self.jobs.append([r,fc])
                  fc.locked =  (fc.lastreq is r["id"])
                  matched = True
                  # removes r from the list of pending jobs
                  pendr = [nr for nr in pendr if (not nr is r)]
                  break
               else:
                  warning(" @SOCKET: Client " + str(fc.peername) + " is in an unexpected status " + str(fc.status) + " at (2). Will try to keep calm and carry on.", verbosity.low)
            if matched:
               break # doesn't do a second (or third) round if it managed
Ejemplo n.º 23
0
    def getforce(self):
        """Gets the potential energy, force and virial from the driver.

        Raises:
           InvalidStatus: Raised if the status is not HasData.
           Disconnected: Raised if the driver has disconnected.

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

        if self.status & Status.HasData:
            self.sendall(Message("getforce"))
            reply = ""
            while True:
                try:
                    reply = self.recv_msg()
                except socket.timeout:
                    warning(
                        " @SOCKET:   Timeout in getforce, trying again!", verbosity.low
                    )
                    continue
                except:
                    warning(
                        " @SOCKET:   Error while receiving message: %s" % (reply),
                        verbosity.low,
                    )
                    raise Disconnected()
                if reply == Message("forceready"):
                    break
                else:
                    warning(
                        " @SOCKET:   Unexpected getforce reply: %s" % (reply),
                        verbosity.low,
                    )
                if reply == "":
                    raise Disconnected()
        else:
            raise InvalidStatus("Status in getforce was " + str(self.status))

        mu = np.float64()
        mu = self.recvall(mu)

        mlen = np.int32()
        mlen = self.recvall(mlen)
        mf = np.zeros(3 * mlen, np.float64)
        mf = self.recvall(mf)

        mvir = np.zeros((3, 3), np.float64)
        mvir = self.recvall(mvir)

        # Machinery to return a string as an "extra" field.
        # Comment if you are using a ancient patched driver that does not return anything!
        # Actually, you should really update your driver, you're like half a decade behind.
        mlen = np.int32()
        mlen = self.recvall(mlen)
        if mlen > 0:
            mxtra = np.zeros(mlen, np.character)
            mxtra = self.recvall(mxtra)
            mxtra = bytearray(mxtra).decode("utf-8")
        else:
            mxtra = ""

        return [mu, mf, mvir, mxtra]
Ejemplo n.º 24
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)
                    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 harder next time
                    searchtimeout = SERVERTIMEOUT
                else:
                    warning(
                        " @SOCKET:   Handshaking failed. Dropping connection.",
                        verbosity.low)
                    client.shutdown(socket.SHUT_RDWR)
                    client.close()
            else:
                keepsearch = False
Ejemplo n.º 25
0
    def pool_distribute(self):
        """Deals with keeping the list of jobs up-to-date during a force
        calculation step.

        Deals with maintaining the jobs list. Gets data from drivers that have
        finished their calculation and removes that job from the list of running
        jobs, adds jobs to free clients and initialises the forcefields of new
        clients.
        """

        # get clients that are still free
        freec = self.clients[:]
        for [r2, c] in self.jobs:
            freec.remove(c)

        # fills up list of pending requests if empty
        if len(self.prlist) == 0:
            self.prlist = [r for r in self.requests if r["status"] == "Queued"]

        npend = len(self.prlist)
        ncli = len(self.clients)
        if self.match_mode == "auto":
            match_seq = ["match", "none", "free", "any"]
        elif self.match_mode == "any":
            match_seq = ["any"]

        # first: dispatches jobs to free clients (if any!)
        # tries first to match previous replica<>driver association, then to get new clients, and only finally send the a new replica to old drivers
        if len(freec) > 0 and len(self.prlist) > 0:
            for match_ids in match_seq:
                for fc in freec[:]:
                    # first, makes sure that the client is REALLY free
                    if not (fc.status & Status.Up):
                        self.clients.remove(
                            fc
                        )  # if fc is in freec it can't be associated with a job (we just checked for that above)
                        continue
                    if fc.status & Status.HasData:
                        continue
                    if not (fc.status &
                            (Status.Ready | Status.NeedsInit | Status.Busy)):
                        warning(
                            " @SOCKET: Client " + str(fc.peername) +
                            " is in an unexpected status " + str(fc.status) +
                            " at (1). Will try to keep calm and carry on.",
                            verbosity.low)
                        continue

                    for r in self.prlist[:]:
                        if match_ids == "match" and not fc.lastreq is r["id"]:
                            continue
                        elif match_ids == "none" and not fc.lastreq is None:
                            continue
                        elif match_ids == "free" and fc.locked:
                            continue
                        info(
                            " @SOCKET: %s Assigning [%5s] request id %4s to client with last-id %4s (% 3d/% 3d : %s)"
                            % (time.strftime("%y/%m/%d-%H:%M:%S"), match_ids,
                               str(r["id"]), str(fc.lastreq),
                               self.clients.index(fc), len(self.clients),
                               str(fc.peername)), verbosity.high)

                        while fc.status & Status.Busy:
                            fc.poll()
                        if fc.status & Status.NeedsInit:
                            fc.initialize(r["id"], r["pars"])
                            fc.poll()
                            while fc.status & Status.Busy:  # waits for initialization to finish. hopefully this is fast
                                fc.poll()
                        if fc.status & Status.Ready:
                            fc.sendpos(r["pos"][r["active"]], r["cell"])
                            r["status"] = "Running"
                            r["t_dispatched"] = time.time()
                            r["start"] = time.time(
                            )  # sets start time for the request
                            # fc.poll()
                            fc.status = Status.Up | Status.Busy  # we know that the client is busy at this stage!
                            self.jobs.append([r, fc])
                            fc.locked = (fc.lastreq is r["id"])
                            freec.remove(fc)
                            # removes r from the list of pending jobs
                            self.prlist.remove(r)
                            break
                        else:
                            warning(
                                " @SOCKET: Client " + str(fc.peername) +
                                " is in an unexpected status " +
                                str(fc.status) +
                                " at (2). Will try to keep calm and carry on.",
                                verbosity.low)

        # force a pool_update if there are requests pending
        # if len(pendr)>0:
        #   self.poll_iter = UPDATEFREQ
        # now check for client status
        for c in self.clients:
            if c.status == Status.Disconnected:  # client disconnected. force a pool_update
                self.poll_iter = UPDATEFREQ
                return
            if not c.status & (Status.Ready | Status.NeedsInit):
                c.poll()

        # check for finished jobs
        for [r, c] in self.jobs[:]:
            if c.status & Status.HasData:
                try:
                    r["result"] = c.getforce()
                    if len(r["result"][1]) != len(r["pos"][r["active"]]):
                        raise InvalidSize
                    # If only a piece of the system is active, resize forces and reassign
                    rftemp = r["result"][1]
                    r["result"][1] = np.zeros(len(r["pos"]), dtype=np.float64)
                    r["result"][1][r["active"]] = rftemp
                except Disconnected:
                    c.status = Status.Disconnected
                    continue
                except InvalidSize:
                    warning(
                        " @SOCKET:   Client returned an inconsistent number of forces. Will mark as disconnected and try to carry on.",
                        verbosity.low)
                    c.status = Status.Disconnected
                    continue
                except:
                    warning(
                        " @SOCKET:   Client got in a awkward state during getforce. Will mark as disconnected and try to carry on.",
                        verbosity.low)
                    c.status = Status.Disconnected
                    continue

                c.poll()
                while c.status & Status.Busy:  # waits, but check if we got stuck.
                    if self.timeout > 0 and r["start"] > 0 and time.time(
                    ) - r["start"] > self.timeout:
                        warning(
                            " @SOCKET:  Timeout! HASDATA for bead " +
                            str(r["id"]) + " has been running for " +
                            str(time.time() - r["start"]) + " sec.",
                            verbosity.low)
                        warning(
                            " @SOCKET:   Client " + str(c.peername) +
                            " died or got unresponsive(A). Disconnecting.",
                            verbosity.low)
                        try:
                            c.shutdown(socket.SHUT_RDWR)
                        except socket.error:
                            pass
                        c.close()
                        c.status = Status.Disconnected
                        continue
                    c.poll()
                if not (c.status & Status.Up):
                    warning(
                        " @SOCKET:   Client died a horrible death while getting forces. Will try to cleanup.",
                        verbosity.low)
                    continue
                r["status"] = "Done"
                r["t_finished"] = time.time()
                c.lastreq = r[
                    "id"]  # saves the ID of the request that the client has just processed
                self.jobs = [
                    w for w in self.jobs if not (w[0] is r and w[1] is c)
                ]  # removes pair in a robust way

            if self.timeout > 0 and c.status != Status.Disconnected and r[
                    "start"] > 0 and time.time() - r["start"] > self.timeout:
                warning(
                    " @SOCKET:  Timeout! Request for bead " + str(r["id"]) +
                    " has been running for " + str(time.time() - r["start"]) +
                    " sec.", verbosity.low)
                warning(
                    " @SOCKET:   Client " + str(c.peername) +
                    " died or got unresponsive(B). Disconnecting.",
                    verbosity.low)
                try:
                    c.shutdown(socket.SHUT_RDWR)
                except socket.error:
                    e = sys.exc_info()
                    warning(
                        " @SOCKET:  could not shut down cleanly the socket. %s: %s in file '%s' on line %d"
                        % (e[0].__name__, e[1],
                           os.path.basename(e[2].tb_frame.f_code.co_filename),
                           e[2].tb_lineno), verbosity.low)
                c.close()
                c.poll()
                c.status = Status.Disconnected
Ejemplo n.º 26
0
    def bind(self, beads, nm, cell, bforce, fflist, elist=[], xlpot=[], xlkin=[]):
        self.beads = beads
        self.cell = cell
        self.forces = bforce
        self.nm = nm
        dself = dd(self)

        # this binds just the explicit bias forces
        self.bias.bind(
            self.beads, self.cell, self.bcomp, fflist, open_paths=nm.open_paths
        )

        dself.econs = depend_value(name="econs", func=self.get_econs)
        # dependencies of the conserved quantity
        dself.econs.add_dependency(dd(self.nm).kin)
        dself.econs.add_dependency(dd(self.forces).pot)
        dself.econs.add_dependency(dd(self.bias).pot)
        dself.econs.add_dependency(dd(self.nm).vspring)
        dself.econs.add_dependency(dself.eens)

        # pipes the weights to the list of weight vectors
        i = 0
        for fc in self.bias.mforces:
            if fc.weight != 1:
                warning(
                    "The weight given to forces used in an ensemble bias are given a weight determined by bias_weight"
                )
            dpipe(dself.bweights, dd(fc).weight, i)
            i += 1

        # add Hamiltonian REM bias components
        if len(self.hweights) == 0:
            self.hweights = np.ones(len(self.forces.mforces))

        dself.hweights = depend_array(name="hweights", value=np.asarray(self.hweights))

        # we use ScaledForceComponents to replicate the physical forces without (hopefully) them being actually recomputed
        for ic in range(len(self.forces.mforces)):
            sfc = ScaledForceComponent(self.forces.mforces[ic], 1.0)
            self.bias.add_component(self.forces.mbeads[ic], self.forces.mrpc[ic], sfc)
            dd(sfc).scaling._func = lambda i=ic: self.hweights[i] - 1
            dd(sfc).scaling.add_dependency(dself.hweights)

        self._elist = []

        for e in elist:
            self.add_econs(e)

        dself.lpens = depend_value(
            name="lpens", func=self.get_lpens, dependencies=[dself.temp]
        )
        dself.lpens.add_dependency(dd(self.nm).kin)
        dself.lpens.add_dependency(dd(self.forces).pot)
        dself.lpens.add_dependency(dd(self.bias).pot)
        dself.lpens.add_dependency(dd(self.nm).vspring)

        # extended Lagrangian terms for the ensemble
        self._xlpot = []
        for p in xlpot:
            self.add_xlpot(p)

        self._xlkin = []
        for k in xlkin:
            self.add_xlkin(k)
Ejemplo n.º 27
0
    def bind(self, beads=None, atoms=None, pm=None, nm=None, prng=None, fixdof=None):
        """Binds the appropriate degrees of freedom to the thermostat.

        This takes an object with degrees of freedom, and makes their momentum
        and mass vectors members of the thermostat. It also then creates the
        objects that will hold the data needed in the thermostat algorithms
        and the dependency network. Actually, this specific thermostat requires
        being called on a beads object.

        Args:
           nm: An optional normal modes object to take the mass and momentum
              vectors from.
           prng: An optional pseudo random number generator object. Defaults to
              Random().
           fixdof: An optional integer which can specify the number of constraints
              applied to the system. Defaults to zero.

        Raises:
           TypeError: Raised if no beads object is specified for
              the thermostat to couple to.
        """

        dself = dd(self)
        if nm is None or not type(nm) is NormalModes:
            raise TypeError("ThermoNMGLE.bind expects a NormalModes argument to bind to")

        if prng is None:
            self.prng = Random()
        else:
            self.prng = prng

        if (nm.nbeads != self.nb):
            raise IndexError("The parameters in nm_gle options correspond to a bead number " + str(self.nb) + " which does not match the number of beads in the path" + str(nm.nbeads))

        # allocates, initializes or restarts an array of s's
        if self.s.shape != (self.nb, self.ns + 1, nm.natoms * 3):
            if len(self.s) > 0:
                warning("Mismatch in GLE s array size on restart, will reinitialise to free particle.", verbosity.low)
            self.s = np.zeros((self.nb, self.ns + 1, nm.natoms * 3))

            # Initializes the s vector in the free-particle limit
            info(" GLE additional DOFs initialised to the free-particle limit.", verbosity.low)
            for b in range(self.nb):
                SC = stab_cholesky(self.C[b] * Constants.kb)
                self.s[b] = np.dot(SC, self.prng.gvec(self.s[b].shape))
        else:
            info("GLE additional DOFs initialised from input.", verbosity.medium)

        prev_ethermo = self.ethermo

        # creates a set of thermostats to be applied to individual normal modes
        self._thermos = [ThermoGLE(temp=1, dt=1, A=self.A[b], C=self.C[b]) for b in range(self.nb)]

        # must pipe all the dependencies in such a way that values for the nm
        # thermostats are automatically updated based on the "master" thermostat
        def make_Agetter(k):
            return lambda: self.A[k]

        def make_Cgetter(k):
            return lambda: self.C[k]

        it = 0
        for t in self._thermos:
            t.s = self.s[it]  # gets the s's as a slice of self.s
            t.bind(pm=(nm.pnm[it, :], nm.dynm3[it, :]), prng=self.prng)  # bind thermostat t to the it-th normal mode

            # pipes temp and dt
            dpipe(dself.temp, dd(t).temp)
            dpipe(dself.dt, dd(t).dt)

            # here we pipe the A and C of individual NM to the "master" arrays
            dd(t).A.add_dependency(dself.A)
            dd(t).A._func = make_Agetter(it)
            dd(t).C.add_dependency(dself.C)
            dd(t).C._func = make_Cgetter(it)
            dself.ethermo.add_dependency(dd(t).ethermo)
            it += 1

        # since the ethermo will be "delegated" to the normal modes thermostats,
        # one has to split
        # any previously-stored value between the sub-thermostats
        for t in self._thermos:
            t.ethermo = prev_ethermo / self.nb

        dself.ethermo._func = self.get_ethermo;
Ejemplo n.º 28
0
    def __init__(
        self,
        mode,
        syslist,
        fflist,
        outputs,
        prng,
        smotion=None,
        step=0,
        tsteps=1000,
        ttime=0,
        threads=False,
    ):
        """Initialises Simulation class.

        Args:
            mode: What kind of simulation is this
            syslist: A list of system objects
            fflist: A list of forcefield objects
            prng: A random number object.
            smotion: A "super-motion" class specifying what to do with different system replicas
            outputs: A list of output objects.
            step: An optional integer giving the current simulation time step.
                Defaults to 0.
            tsteps: An optional integer giving the total number of steps. Defaults
                to 1000.
            ttime: The simulation running time. Used on restart, to keep a
                cumulative total.
        """

        info(" # Initializing simulation object ", verbosity.low)
        self.prng = prng
        self.mode = mode
        self.threading = threads
        dself = dd(self)

        self.syslist = syslist
        for s in syslist:
            s.prng = self.prng  # bind the system's prng to self prng
            s.init.init_stage1(s)

        # TODO - does this have any meaning now that we introduce the smotion class?
        if self.mode == "md" and len(syslist) > 1:
            warning(
                "Multiple systems will evolve independently in a '"
                + self.mode
                + "' simulation."
            )

        self.fflist = {}
        for f in fflist:
            self.fflist[f.name] = f

        self.outtemplate = outputs

        dself.step = depend_value(name="step", value=step)
        self.tsteps = tsteps
        self.ttime = ttime
        self.smotion = smotion

        self.chk = None
        self.rollback = True
Ejemplo n.º 29
0
    def init_stage1(self, simul):
        """Initializes the simulation -- first stage.

        Takes a simulation object, and uses all the data in the initialization
        queue to fill up the beads and cell data needed to run the simulation.

        Args:
           simul: A simulation object to be initialized.

        Raises:
           ValueError: Raised if there is a problem with the initialization,
              if something that should have been has not been, or if the objects
              that have been specified are not compatible with each other.
        """

        if simul.beads.nbeads == 0:
            fpos = fmom = fmass = flab = fcell = False  # we don't have an explicitly defined beads object yet
        else:
            fpos = fmom = fmass = flab = fcell = True

        for (k, v) in self.queue:
            info(" # Initializer (stage 1) parsing " + str(k) + " object.",
                 verbosity.high)

            if k == "cell":
                if v.mode == "manual":
                    rh = v.value.reshape(
                        (3, 3)) * unit_to_internal("length", v.units, 1.0)
                elif v.mode == "chk":
                    rh = init_chk(v.value)[1].h
                elif init_file(v.mode, v.value)[1].h.trace() == -3:
                    # In case the file do not contain any
                    #+ cell parameters, the diagonal elements of the cell will be
                    #+set to -1 from the io_units and nothing is read here.
                    continue
                else:
                    rh = init_file(v.mode, v.value, cell_units=v.units)[1].h

                if fcell:
                    warning("Overwriting previous cell parameters",
                            verbosity.low)

                simul.cell.h = rh
                if simul.cell.V == 0.0:
                    ValueError("Cell provided has zero volume")

                fcell = True
            elif k == "masses":
                if simul.beads.nbeads == 0:
                    raise ValueError(
                        "Cannot initialize the masses before the size of the system is known"
                    )
                if fmass:
                    warning("Overwriting previous atomic masses",
                            verbosity.medium)
                if v.mode == "manual":
                    rm = v.value * unit_to_internal("mass", v.units, 1.0)
                else:
                    rm = init_beads(v, self.nbeads).m

                if v.bead < 0:  # we are initializing the path
                    if (fmom and fmass):
                        warning(
                            "Rescaling momenta to make up for changed mass",
                            verbosity.medium)
                        simul.beads.p /= simul.beads.sm3  # go to mass-scaled momenta, that are mass-invariant
                    if v.index < 0:
                        simul.beads.m = rm
                    else:  # we are initializing a specific atom
                        simul.beads.m[v.index:v.index + 1] = rm
                    if (fmom and fmass):  # finishes correcting the momenta
                        simul.beads.p *= simul.beads.sm3  # back to normal momenta
                else:
                    raise ValueError("Cannot change the mass of a single bead")
                fmass = True

            elif k == "labels":
                if simul.beads.nbeads == 0:
                    raise ValueError(
                        "Cannot initialize the labels before the size of the system is known"
                    )
                if flab:
                    warning("Overwriting previous atomic labels",
                            verbosity.medium)
                if v.mode == "manual":
                    rn = v.value
                else:
                    rn = init_beads(v, self.nbeads).names

                if v.bead < 0:  # we are initializing the path
                    if v.index < 0:
                        simul.beads.names = rn
                    else:  # we are initializing a specific atom
                        simul.beads.names[v.index:v.index + 1] = rn
                else:
                    raise ValueError(
                        "Cannot change the label of a single bead")
                flab = True

            elif k == "positions":
                if fpos:
                    warning("Overwriting previous atomic positions",
                            verbosity.medium)
                # read the atomic positions as a vector

                rq = init_vector(v,
                                 self.nbeads,
                                 dimension="length",
                                 units=v.units)

                nbeads, natoms = rq.shape
                natoms /= 3

                # check if we must initialize the simulation beads
                if simul.beads.nbeads == 0:
                    if v.index >= 0:
                        raise ValueError(
                            "Cannot initialize single atoms before the size of the system is known"
                        )
                    simul.beads.resize(natoms, self.nbeads)

                set_vector(v, simul.beads.q, rq)
                fpos = True

            elif (
                    k == "velocities" or k == "momenta"
            ) and v.mode == "thermal":  # intercept here thermal initialization, so we don't need to check further down
                if fmom:
                    warning("Overwriting previous atomic momenta",
                            verbosity.medium)
                if simul.beads.natoms == 0:
                    raise ValueError(
                        "Cannot initialize momenta before the size of the system is known."
                    )
                if not fmass:
                    raise ValueError(
                        "Trying to resample velocities before having masses.")

                rtemp = v.value * unit_to_internal("temperature", v.units, 1.0)
                if rtemp <= 0:
                    warning(
                        "Using the simulation temperature to resample velocities",
                        verbosity.low)
                    rtemp = simul.ensemble.temp
                else:
                    info(
                        " # Resampling velocities at temperature %s %s" %
                        (v.value, v.units), verbosity.low)

                # pull together a mock initialization to get NM masses right
                # without too much code duplication
                if v.bead >= 0:
                    raise ValueError("Cannot thermalize a single bead")
                if v.index >= 0:
                    rnatoms = 1
                else:
                    rnatoms = simul.beads.natoms
                rbeads = Beads(rnatoms, simul.beads.nbeads)
                if v.index < 0:
                    rbeads.m[:] = simul.beads.m
                else:
                    rbeads.m[:] = simul.beads.m[v.index]
                rnm = NormalModes(mode=simul.nm.mode,
                                  transform_method=simul.nm.transform_method,
                                  freqs=simul.nm.nm_freqs)
                rens = Ensemble(temp=simul.ensemble.temp)
                rmv = Motion()
                rnm.bind(rens, rmv, rbeads)
                # then we exploit the sync magic to do a complicated initialization
                # in the NM representation
                # with (possibly) shifted-frequencies NM
                rnm.pnm = simul.prng.gvec(
                    (rbeads.nbeads, 3 * rbeads.natoms)) * np.sqrt(
                        rnm.dynm3) * np.sqrt(
                            rbeads.nbeads * rtemp * Constants.kb)

                if v.index < 0:
                    simul.beads.p = rbeads.p
                else:
                    simul.beads.p[:, 3 * v.index:3 * (v.index + 1)] = rbeads.p
                fmom = True

            elif k == "momenta":
                if fmom:
                    warning("Overwriting previous atomic momenta",
                            verbosity.medium)
                # read the atomic momenta as a vector
                rp = init_vector(v,
                                 self.nbeads,
                                 momenta=True,
                                 dimension="momentum",
                                 units=v.units)
                nbeads, natoms = rp.shape
                natoms /= 3

                # checks if we must initialize the simulation beads
                if simul.beads.nbeads == 0:
                    if v.index >= 0:
                        raise ValueError(
                            "Cannot initialize single atoms before the size of the system is known"
                        )
                    simul.beads.resize(natoms, self.nbeads)

                rp *= np.sqrt(self.nbeads / nbeads)
                set_vector(v, simul.beads.p, rp)
                fmom = True
            elif k == "velocities":
                if fmom:
                    warning("Overwriting previous atomic momenta",
                            verbosity.medium)
                # read the atomic velocities as a vector
                rv = init_vector(v,
                                 self.nbeads,
                                 dimension="velocity",
                                 units=v.units)
                nbeads, natoms = rv.shape
                natoms /= 3

                # checks if we must initialize the simulation beads
                if simul.beads.nbeads == 0 or not fmass:
                    ValueError(
                        "Cannot initialize velocities before the masses of the atoms are known"
                    )
                    simul.beads.resize(natoms, self.nbeads)

                warning(
                    "Initializing from velocities uses the previously defined masses -- not the masses inferred from the file -- to build momenta",
                    verbosity.low)
                if v.index >= 0:
                    rv *= simul.beads.m[v.index]
                else:
                    for ev in rv:
                        ev *= simul.beads.m3[0]
                rv *= np.sqrt(self.nbeads / nbeads)
                set_vector(v, simul.beads.p, rv)
                fmom = True
            elif k == "gle":
                pass  # thermostats must be initialised in a second stage

        if simul.beads.natoms == 0:
            raise ValueError(
                "Initializer could not initialize the atomic positions")
        if simul.cell.V == 0:
            raise ValueError("Initializer could not initialize the cell")
        for i in range(simul.beads.natoms):
            if simul.beads.m[i] <= 0:
                raise ValueError("Initializer could not initialize the masses")
            if simul.beads.names[i] == "":
                raise ValueError(
                    "Initializer could not initialize the atom labels")
        if not fmom:
            warning(
                "Momenta not specified in initialize. Will start with zero velocity if they are not specified in beads.",
                verbosity.low)
Ejemplo n.º 30
0
   def bind(self, nm=None, prng=None, fixdof=None):
      """Binds the appropriate degrees of freedom to the thermostat.

      This takes an object with degrees of freedom, and makes their momentum
      and mass vectors members of the thermostat. It also then creates the
      objects that will hold the data needed in the thermostat algorithms
      and the dependency network. Actually, this specific thermostat requires
      being called on a beads object.

      Args:
         nm: An optional normal modes object to take the mass and momentum
            vectors from.
         prng: An optional pseudo random number generator object. Defaults to
            Random().
         fixdof: An optional integer which can specify the number of constraints
            applied to the system. Defaults to zero.

      Raises:
         TypeError: Raised if no beads object is specified for
            the thermostat to couple to.
      """

      if nm is None or not type(nm) is NormalModes:
         raise TypeError("ThermoNMGLE.bind expects a NormalModes argument to bind to")

      if prng is None:
         self.prng = Random()
      else:
         self.prng = prng

      if (nm.nbeads != self.nb):
         raise IndexError("The parameters in nm_gle options correspond to a bead number "+str(self.nb)+ " which does not match the number of beads in the path" + str(nm.nbeads) )

      # allocates, initializes or restarts an array of s's
      if self.s.shape != (self.nb, self.ns + 1, nm.natoms *3) :
         if len(self.s) > 0:
            warning("Mismatch in GLE s array size on restart, will reinitialise to free particle.", verbosity.low)
         self.s = np.zeros((self.nb, self.ns + 1, nm.natoms*3))

         # Initializes the s vector in the free-particle limit
         info(" GLE additional DOFs initialised to the free-particle limit.", verbosity.low)
         for b in range(self.nb):
            SC = stab_cholesky(self.C[b]*Constants.kb)
            self.s[b] = np.dot(SC, self.prng.gvec(self.s[b].shape))
      else:
         info("GLE additional DOFs initialised from input.", verbosity.medium)

      prev_ethermo = self.ethermo

      # creates a set of thermostats to be applied to individual normal modes
      self._thermos = [ThermoGLE(temp=1, dt=1, A=self.A[b], C=self.C[b]) for b in range(self.nb)]

      # must pipe all the dependencies in such a way that values for the nm
      # thermostats are automatically updated based on the "master" thermostat
      def make_Agetter(k):
         return lambda: self.A[k]
      def make_Cgetter(k):
         return lambda: self.C[k]

      it = 0
      for t in self._thermos:
         t.s = self.s[it]  # gets the s's as a slice of self.s
         t.bind(pm=(nm.pnm[it,:],nm.dynm3[it,:]), prng=self.prng) # bind thermostat t to the it-th normal mode

         # pipes temp and dt
         deppipe(self,"temp", t, "temp")
         deppipe(self,"dt", t, "dt")

         # here we pipe the A and C of individual NM to the "master" arrays
         dget(t,"A").add_dependency(dget(self,"A"))
         dget(t,"A")._func = make_Agetter(it)
         dget(t,"C").add_dependency(dget(self,"C"))
         dget(t,"C")._func = make_Cgetter(it)
         dget(self,"ethermo").add_dependency(dget(t,"ethermo"))
         it += 1

      # since the ethermo will be "delegated" to the normal modes thermostats,
      # one has to split
      # any previously-stored value between the sub-thermostats
      for t in self._thermos:
         t.ethermo = prev_ethermo/self.nb

      dget(self,"ethermo")._func = self.get_ethermo;
Ejemplo n.º 31
0
    def bind(self,
             beads=None,
             atoms=None,
             pm=None,
             nm=None,
             prng=None,
             fixdof=None):
        """Binds the appropriate degrees of freedom to the thermostat.

        This takes an object with degrees of freedom, and makes their momentum
        and mass vectors members of the thermostat. It also then creates the
        objects that will hold the data needed in the thermostat algorithms
        and the dependency network.

        Args:
           beads: An optional beads object to take the mass and momentum vectors
              from.
           atoms: An optional atoms object to take the mass and momentum vectors
              from.
           pm: An optional tuple containing a single momentum value and its
              conjugate mass.
           prng: An optional pseudo random number generator object. Defaults to
              Random().
           fixdof: An optional integer which can specify the number of constraints
              applied to the system. Defaults to zero.

        Raises:
           TypeError: Raised if no appropriate degree of freedom or object
              containing a momentum vector is specified for
              the thermostat to couple to.
        """

        if prng is None:
            warning("Initializing thermostat from standard random PRNG",
                    verbosity.medium)
            self.prng = Random()
        else:
            self.prng = prng

        dself = dd(self)
        if not beads is None:
            dself.p = beads.p.flatten()
            dself.m = beads.m3.flatten()
        elif not atoms is None:
            dself.p = dd(atoms).p
            dself.m = dd(atoms).m3
        elif not pm is None:
            dself.p = pm[0].flatten(
            )  # MR this should allow to simply pass the cell momenta in the anisotropic barostat
            dself.m = pm[1].flatten()
        else:
            raise TypeError(
                "Thermostat.bind expects either Beads, Atoms, NormalModes, or a (p,m) tuple to bind to"
            )

        if fixdof is None:
            self.ndof = len(self.p)
        else:
            self.ndof = float(len(self.p) - fixdof)

        dself.sm = depend_array(name="sm",
                                value=np.zeros(len(dself.m)),
                                func=self.get_sm,
                                dependencies=[dself.m])
Ejemplo n.º 32
0
    def forcesvirs_4th_order(self, index):
        """ Fetches the 4th order |f^2| correction to the force vector and the virial associated with a given component."""

        # gives an error is number of beads is not even.
        if self.nbeads % 2 != 0:
            warning("ERROR: Suzuki-Chin factorization requires even number of beads!")
            exit()

        # calculates the finite displacement.
        fbase = dstrip(self.f)
        eps = self.mforces[index].epsilon
        delta = np.abs(eps) / np.sqrt((fbase / self.beads.m3 * fbase / self.beads.m3).sum() / (self.nbeads * self.natoms))
        dq = delta * fbase / self.beads.m3

        # stores the force component.
        fbase = self.mrpc[index].b2tob1(dstrip(self.mforces[index].f))
        vbase = np.zeros((self.nbeads, 3, 3), float)
        mvirs = dstrip(self.mforces[index].virs)
        for i in range(3):
            for j in range(3):
                vbase[:, i, j] += self.mrpc[index].b2tob1(mvirs[:, i, j])

        # uses a fwd difference if epsilon > 0.
        if self.mforces[index].epsilon > 0.0:

            # gives an error if RPC is used with a fwd difference.
            # The problem is that the finite difference is computed as [f(q + e.f) - f(q)].e^-1,
            # where f(q + e.f) is computed on a smaller rimg polymer of P / 2 beads which is made
            # by displacing the odd beads of the original ring polymer. Upon contraction,  it yields
            # a ring polymer that is different from the contracted one on which f(q) was computed.
            # This makes the FD incorrect. A fix could be to ALWAYS compute the odd and the even
            # beads on two different ring polymers of P / 2 beads, but centered difference + RPC
            # seems to be a neater solution. Anyway, the cost of a CNT-DIFF in comparison to a FWD-DIFF
            # is marginal in when RPC + MTS is used.

            if self.mforces[index].nbeads != self.nbeads:
                warning("ERROR: high order PIMD + RPC works with a centered finite difference only! (Uness you find an elegant solution :))")
                exit()

            # for the case of alpha = 0, only odd beads are displaced.
            if self.alpha == 0:

                # we use an aux force evaluator with half the number of beads.
                if self.dforces is None:
                    self.dbeads = self.beads.copy(self.nbeads / 2)
                    self.dcell = self.cell.copy()
                    self.dforces = self.copy(self.dbeads, self.dcell)

                self.dcell.h = self.cell.h

                f_4th_order = fbase * 0.0
                v_4th_order = vbase * 0.0

                # displaces odd beads only.
                self.dbeads.q = dstrip(self.beads.q)[1::2] - dq[1::2]

                # calculates the force.
                fminus = self.dforces.mrpc[index].b2tob1(dstrip(self.dforces.mforces[index].f))

                # calculates the virial.
                vminus = np.zeros((self.nbeads / 2, 3, 3), float)
                dmvirs = dstrip(self.dforces.mforces[index].virs)
                for i in range(3):
                    for j in range(3):
                        vminus[:, i, j] += self.dforces.mrpc[index].b2tob1(dmvirs[:, i, j])

                # calculates the finite difference.
                f_4th_order[1::2] = 2.0 * (fminus - fbase[1::2]) / delta
                v_4th_order[1::2] = 2.0 * (vminus - vbase[1::2]) / delta

            # For the case of alpha != 0, all the beads are displaced.
            else:

                # we use an aux force evaluator with the same number of beads.
                if self.dforces is None:
                    self.dbeads = self.beads.copy()
                    self.dcell = self.cell.copy()
                    self.dforces = self.copy(self.dbeads, self.dcell)

                self.dcell.h = self.cell.h

                f_4th_order = fbase * 0.0
                v_4th_order = vbase * 0.0

                # displaces the beads.
                self.dbeads.q = self.beads.q + dq

                # calculates the force.
                fplus = self.dforces.mrpc[index].b2tob1((dstrip(self.dforces.mforces[index].f)))

                # calculates the virial.
                vplus = np.zeros((self.nbeads, 3, 3), float)
                dmvirs = dstrip(self.dforces.mforces[index].virs)
                for i in range(3):
                    for j in range(3):
                        vplus[:, i, j] += self.dforces.mrpc[index].b2tob1(dmvirs[:, i, j])

                # calculates the finite difference.
                f_4th_order = 2.0 * (fbase - fplus) / delta
                v_4th_order = 2.0 * (vbase - vplus) / delta

        # uses a centered difference for epsilon  < 0.
        if self.mforces[index].epsilon < 0.0:

                # we use an aux force evaluator with the same number of beads.
            if self.dforces is None:
                self.dbeads = self.beads.copy()
                self.dcell = self.cell.copy()
                self.dforces = self.copy(self.dbeads, self.dcell)

            self.dcell.h = self.cell.h

            f_4th_order = fbase * 0.0
            v_4th_order = vbase * 0.0

            # for the case of alpha = 0, only odd beads are displaced.
            if self.alpha == 0:

                # the first half of the aux beads are fwd displaced while the second half are bkwd displaced configurations.
                self.dbeads.q[:self.nbeads / 2] = dstrip(self.beads.q)[1::2] + dq[1::2]
                self.dbeads.q[-self.nbeads / 2:] = dstrip(self.beads.q)[1::2] - dq[1::2]

                # calculates the forces.
                fplusminus = self.dforces.mrpc[index].b2tob1(dstrip(self.dforces.mforces[index].f))

                # calculates the virial.
                vplusminus = np.zeros((self.nbeads, 3, 3), float)
                dmvirs = dstrip(self.dforces.mforces[index].virs)
                for i in range(3):
                    for j in range(3):
                        vplusminus[:, i, j] += self.dforces.mrpc[index].b2tob1(dmvirs[:, i, j])

                # calculates the finite difference.
                for k in range(self.nbeads / 2):
                    j = 2 * k + 1
                    f_4th_order[j] = 2.0 * (fplusminus[self.nbeads / 2 + k] - fplusminus[k]) / 2.0 / delta
                    v_4th_order[j] = 2.0 * (vplusminus[self.nbeads / 2 + k] - vplusminus[k]) / 2.0 / delta

            # For the case of alpha != 0, all the beads are displaced.
            else:
                # displaces the beads.
                self.dbeads.q = self.beads.q + dq

                # calculates the forces.
                fplus = self.dforces.mrpc[index].b2tob1(dstrip(self.dforces.mforces[index].f))

                # calculates the virial.
                vplus = np.zeros((self.nbeads, 3, 3), float)
                dmvirs = dstrip(self.dforces.mforces[index].virs)
                for i in range(3):
                    for j in range(3):
                        vplus[:, i, j] += self.dforces.mrpc[index].b2tob1(dmvirs[:, i, j])

                # displaces the beads.
                self.dbeads.q = self.beads.q - dq

                # calculates the forces.
                fminus = self.dforces.mrpc[index].b2tob1(dstrip(self.dforces.mforces[index].f))

                # calculates the virial.
                vminus = np.zeros((self.nbeads, 3, 3), float)
                dmvirs = dstrip(self.dforces.mforces[index].virs)
                for i in range(3):
                    for j in range(3):
                        vminus[:, i, j] += self.dforces.mrpc[index].b2tob1(dmvirs[:, i, j])

                # calculates the finite difference.
                f_4th_order = 2.0 * (fminus - fplus) / 2.0 / delta
                v_4th_order = 2.0 * (vminus - vplus) / 2.0 / delta

        # returns the 4th order |f^2| correction.
        return [f_4th_order, v_4th_order]
Ejemplo n.º 33
0
    def get_o_nmm(self):
        """Returns dynamical mass factors, i.e. the scaling of normal mode
        masses that determine the path dynamics (but not statics)."""

        # also checks that the frequencies and the mode given in init are
        # consistent with the beads and ensemble

        dmf = np.ones(self.nbeads, float)
        if self.mode == "rpmd":
            if len(self.nm_freqs) > 0:
                warning("nm.frequencies will be ignored for RPMD mode.",
                        verbosity.low)
        elif self.mode == "manual":
            if len(self.nm_freqs) != self.nbeads - 1:
                raise ValueError(
                    "Manual path mode requires (nbeads-1) frequencies, one for each internal mode of the path."
                )
            for b in range(1, self.nbeads):
                sk = self.o_omegak[b] / self.nm_freqs[b - 1]
                dmf[b] = sk**2
        elif self.mode == "pa-cmd":
            if len(self.nm_freqs) > 1:
                warning(
                    "Only the first element in nm.frequencies will be considered for PA-CMD mode.",
                    verbosity.low,
                )
            if len(self.nm_freqs) == 0:
                raise ValueError(
                    "PA-CMD mode requires the target frequency of all the internal modes."
                )
            for b in range(1, self.nbeads):
                sk = self.o_omegak[b] / self.nm_freqs[0]
                info(
                    " ".join([
                        "NM FACTOR",
                        str(b),
                        str(sk),
                        str(self.o_omegak[b]),
                        str(self.nm_freqs[0]),
                    ]),
                    verbosity.medium,
                )
                dmf[b] = sk**2
        elif self.mode == "wmax-cmd":
            if len(self.nm_freqs) > 2:
                warning(
                    "Only the first two element in nm.frequencies will be considered for WMAX-CMD mode.",
                    verbosity.low,
                )
            if len(self.nm_freqs) < 2:
                raise ValueError(
                    "WMAX-CMD mode requires [wmax, wtarget]. The normal modes will be scaled such that the first internal mode is at frequency wtarget and all the normal modes coincide at frequency wmax."
                )
            wmax = self.nm_freqs[0]
            wt = self.nm_freqs[1]
            for b in range(1, self.nbeads):
                sk = 1.0 / np.sqrt(
                    (wt)**2 * (1 + (wmax / self.o_omegak[1])**2) /
                    (wmax**2 + (self.o_omegak[b])**2))
                dmf[b] = sk**2

        return dmf
Ejemplo n.º 34
0
    def init_stage1(self, simul):
        """Initializes the simulation -- first stage.

        Takes a simulation object, and uses all the data in the initialization
        queue to fill up the beads and cell data needed to run the simulation.

        Args:
           simul: A simulation object to be initialized.

        Raises:
           ValueError: Raised if there is a problem with the initialization,
              if something that should have been has not been, or if the objects
              that have been specified are not compatible with each other.
        """

        if simul.beads.nbeads == 0:
            fpos = fmom = fmass = flab = fcell = False   # we don't have an explicitly defined beads object yet
        else:
            fpos = fmom = fmass = flab = fcell = True

        for (k, v) in self.queue:
            info(" # Initializer (stage 1) parsing " + str(k) + " object.", verbosity.high)

            if k == "cell":
                if v.mode == "manual":
                    rh = v.value.reshape((3, 3)) * unit_to_internal("length", v.units, 1.0)
                elif v.mode == "chk":
                    rh = init_chk(v.value)[1].h
                elif init_file(v.mode, v.value)[1].h.trace() == -3:
                    # In case the file do not contain any
                    # + cell parameters, the diagonal elements of the cell will be
                    # +set to -1 from the io_units and nothing is read here.
                    continue
                else:
                    rh = init_file(v.mode, v.value, cell_units=v.units)[1].h

                if fcell:
                    warning("Overwriting previous cell parameters", verbosity.low)

                simul.cell.h = rh
                if simul.cell.V == 0.0:
                    ValueError("Cell provided has zero volume")

                fcell = True
            elif k == "masses":
                if simul.beads.nbeads == 0:
                    raise ValueError("Cannot initialize the masses before the size of the system is known")
                if fmass:
                    warning("Overwriting previous atomic masses", verbosity.medium)
                if v.mode == "manual":
                    rm = v.value * unit_to_internal("mass", v.units, 1.0)
                else:
                    rm = init_beads(v, self.nbeads).m

                if v.bead < 0:   # we are initializing the path
                    if (fmom and fmass):
                        warning("Rescaling momenta to make up for changed mass", verbosity.medium)
                        simul.beads.p /= simul.beads.sm3   # go to mass-scaled momenta, that are mass-invariant
                    if v.index < 0:
                        simul.beads.m = rm
                    else:  # we are initializing a specific atom
                        simul.beads.m[v.index:v.index + 1] = rm
                    if (fmom and fmass):  # finishes correcting the momenta
                        simul.beads.p *= simul.beads.sm3  # back to normal momenta
                else:
                    raise ValueError("Cannot change the mass of a single bead")
                fmass = True

            elif k == "labels":
                if simul.beads.nbeads == 0:
                    raise ValueError("Cannot initialize the labels before the size of the system is known")
                if flab:
                    warning("Overwriting previous atomic labels", verbosity.medium)
                if v.mode == "manual":
                    rn = v.value
                else:
                    rn = init_beads(v, self.nbeads).names

                if v.bead < 0:   # we are initializing the path
                    if v.index < 0:
                        simul.beads.names = rn
                    else:  # we are initializing a specific atom
                        simul.beads.names[v.index:v.index + 1] = rn
                else:
                    raise ValueError("Cannot change the label of a single bead")
                flab = True

            elif k == "positions":
                if fpos:
                    warning("Overwriting previous atomic positions", verbosity.medium)
                # read the atomic positions as a vector

                rq = init_vector(v, self.nbeads, dimension="length", units=v.units)

                nbeads, natoms = rq.shape
                natoms /= 3

                # check if we must initialize the simulation beads
                if simul.beads.nbeads == 0:
                    if v.index >= 0:
                        raise ValueError("Cannot initialize single atoms before the size of the system is known")
                    simul.beads.resize(natoms, self.nbeads)

                set_vector(v, simul.beads.q, rq)
                fpos = True

            elif (k == "velocities" or k == "momenta") and v.mode == "thermal":   # intercept here thermal initialization, so we don't need to check further down
                if fmom:
                    warning("Overwriting previous atomic momenta", verbosity.medium)
                if simul.beads.natoms == 0:
                    raise ValueError("Cannot initialize momenta before the size of the system is known.")
                if not fmass:
                    raise ValueError("Trying to resample velocities before having masses.")

                rtemp = v.value * unit_to_internal("temperature", v.units, 1.0)
                if rtemp <= 0:
                    warning("Using the simulation temperature to resample velocities", verbosity.low)
                    rtemp = simul.ensemble.temp
                else:
                    info(" # Resampling velocities at temperature %s %s" % (v.value, v.units), verbosity.low)

                # pull together a mock initialization to get NM masses right
                # without too much code duplication
                if v.bead >= 0:
                    raise ValueError("Cannot thermalize a single bead")
                if v.index >= 0:
                    rnatoms = 1
                else:
                    rnatoms = simul.beads.natoms
                rbeads = Beads(rnatoms, simul.beads.nbeads)
                if v.index < 0:
                    rbeads.m[:] = simul.beads.m
                else:
                    rbeads.m[:] = simul.beads.m[v.index]
                rnm = NormalModes(mode=simul.nm.mode, transform_method=simul.nm.transform_method, freqs=simul.nm.nm_freqs)
                rens = Ensemble(temp=simul.ensemble.temp)
                rmv = Motion()
                rnm.bind(rens, rmv, rbeads)
                # then we exploit the sync magic to do a complicated initialization
                # in the NM representation
                # with (possibly) shifted-frequencies NM
                rnm.pnm = simul.prng.gvec((rbeads.nbeads, 3 * rbeads.natoms)) * np.sqrt(rnm.dynm3) * np.sqrt(rbeads.nbeads * rtemp * Constants.kb)

                if v.index < 0:
                    simul.beads.p = rbeads.p
                else:
                    simul.beads.p[:, 3 * v.index:3 * (v.index + 1)] = rbeads.p
                fmom = True

            elif k == "momenta":
                if fmom:
                    warning("Overwriting previous atomic momenta", verbosity.medium)
                # read the atomic momenta as a vector
                rp = init_vector(v, self.nbeads, momenta=True, dimension="momentum", units=v.units)
                nbeads, natoms = rp.shape
                natoms /= 3

                # checks if we must initialize the simulation beads
                if simul.beads.nbeads == 0:
                    if v.index >= 0:
                        raise ValueError("Cannot initialize single atoms before the size of the system is known")
                    simul.beads.resize(natoms, self.nbeads)

                rp *= np.sqrt(self.nbeads / nbeads)
                set_vector(v, simul.beads.p, rp)
                fmom = True
            elif k == "velocities":
                if fmom:
                    warning("Overwriting previous atomic momenta", verbosity.medium)
                # read the atomic velocities as a vector
                rv = init_vector(v, self.nbeads, dimension="velocity", units=v.units)
                nbeads, natoms = rv.shape
                natoms /= 3

                # checks if we must initialize the simulation beads
                if simul.beads.nbeads == 0 or not fmass:
                    ValueError("Cannot initialize velocities before the masses of the atoms are known")
                    simul.beads.resize(natoms, self.nbeads)

                warning("Initializing from velocities uses the previously defined masses -- not the masses inferred from the file -- to build momenta", verbosity.low)
                if v.index >= 0:
                    rv *= simul.beads.m[v.index]
                else:
                    for ev in rv:
                        ev *= simul.beads.m3[0]
                rv *= np.sqrt(self.nbeads / nbeads)
                set_vector(v, simul.beads.p, rv)
                fmom = True
            elif k == "gle": pass   # thermostats must be initialised in a second stage

        if simul.beads.natoms == 0:
            raise ValueError("Initializer could not initialize the atomic positions")
        if simul.cell.V == 0:
            raise ValueError("Initializer could not initialize the cell")
        for i in range(simul.beads.natoms):
            if simul.beads.m[i] <= 0:
                raise ValueError("Initializer could not initialize the masses")
            if simul.beads.names[i] == "":
                raise ValueError("Initializer could not initialize the atom labels")
        if not fmom:
            warning("Momenta not specified in initialize. Will start with zero velocity if they are not specified in beads.", verbosity.low)
Ejemplo n.º 35
0
Archivo: sockets.py Proyecto: i-pi/i-pi
    def getforce(self):
        """Gets the potential energy, force and virial from the driver.

        Raises:
           InvalidStatus: Raised if the status is not HasData.
           Disconnected: Raised if the driver has disconnected.

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

        if self.status & Status.HasData:
            self.sendall(Message("getforce"))
            reply = ""
            while True:
                try:
                    reply = self.recv_msg()
                except socket.timeout:
                    warning(
                        " @SOCKET:   Timeout in getforce, trying again!", verbosity.low
                    )
                    continue
                except:
                    warning(
                        " @SOCKET:   Error while receiving message: %s" % (reply),
                        verbosity.low,
                    )
                    raise Disconnected()
                if reply == Message("forceready"):
                    break
                else:
                    warning(
                        " @SOCKET:   Unexpected getforce reply: %s" % (reply),
                        verbosity.low,
                    )
                if reply == "":
                    raise Disconnected()
        else:
            raise InvalidStatus("Status in getforce was " + str(self.status))

        mu = np.float64()
        mu = self.recvall(mu)

        mlen = np.int32()
        mlen = self.recvall(mlen)
        mf = np.zeros(3 * mlen, np.float64)
        mf = self.recvall(mf)

        mvir = np.zeros((3, 3), np.float64)
        mvir = self.recvall(mvir)

        # Machinery to return a string as an "extra" field.
        # Comment if you are using a ancient patched driver that does not return anything!
        # Actually, you should really update your driver, you're like half a decade behind.
        mlen = np.int32()
        mlen = self.recvall(mlen)
        if mlen > 0:
            mxtra = np.zeros(mlen, np.character)
            mxtra = self.recvall(mxtra)
            mxtra = bytearray(mxtra).decode("utf-8")
        else:
            mxtra = ""
        mxtradict = {}
        if mxtra:
            try:
                mxtradict = json.loads(mxtra)
                info("Extra string JSON has been loaded.", verbosity.debug)
            except:
                # if we can't parse it as a dict, issue a warning and carry on
                info(
                    "Extra string could not be loaded as a dictionary. Extra=" + mxtra,
                    verbosity.debug,
                )
                mxtradict = {}
                pass
            if "raw" in mxtradict:
                raise ValueError(
                    "'raw' cannot be used as a field in a JSON-formatted extra string"
                )

            mxtradict["raw"] = mxtra

        return [mu, mf, mvir, mxtradict]
Ejemplo n.º 36
0
    def recvall(self, dest):
        """Gets the potential energy, force and virial from the driver.

      Args:
         dest: Object to be read into.

      Raises:
         Disconnected: Raised if client is disconnected.

      Returns:
         The data read from the socket to be read into dest.
      """

        blen = dest.itemsize * dest.size
        if (blen > len(self._buf)):
            self._buf.resize(blen)
        bpos = 0
        ntimeout = 0

        while bpos < blen:
            timeout = False

            #   pre-2.5 version.
            try:
                bpart = ""
                bpart = self.recv(blen - bpos)
                if len(bpart) == 0:
                    raise socket.timeout  # There is a problem if this returns no data
                self._buf[bpos:bpos + len(bpart)] = np.fromstring(
                    bpart, np.byte)
            except socket.timeout:
                warning(" @SOCKET:   Timeout in status recvall, trying again!",
                        verbosity.low)
                timeout = True
                ntimeout += 1
                if ntimeout > NTIMEOUT:
                    warning(
                        " @SOCKET:  Couldn't receive within %5d attempts. Time to give up!"
                        % (NTIMEOUT), verbosity.low)
                    raise Disconnected()
                pass
            if (not timeout and bpart == 0):
                raise Disconnected()
            bpos += len(bpart)


#   post-2.5 version: slightly more compact for modern python versions
#         try:
#            bpart = 1
#            bpart = self.recv_into(self._buf[bpos:], blen-bpos)
#         except socket.timeout:
#            print " @SOCKET:   Timeout in status recvall, trying again!"
#            timeout = True
#            pass
#         if (not timeout and bpart == 0):
#            raise Disconnected()
#         bpos += bpart
#TODO this Disconnected() exception currently just causes the program to hang.
#This should do something more graceful

        if np.isscalar(dest):
            return np.fromstring(self._buf[0:blen], dest.dtype)[0]
        else:
            return np.fromstring(self._buf[0:blen],
                                 dest.dtype).reshape(dest.shape)
Ejemplo n.º 37
0
def getInput():
    """
    Parse command line arguments and return input parameters for Planets class.

    Returns
        prefix : filename prefix
        natoms : number of atoms
        iseed : random number seed
        npl : number of planets to simulate
        npts : number of data points
        stride : number of planetary steps between centroid updates
        dt : planetary time step in fs
        temperature : temperature in K
        estimators : list of modules defining estimators in the required format

    """

    parser = argparse.ArgumentParser(
        description=description,
        formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument("prefix", type=str, help="Filename prefix")

    parser.add_argument(
        "dt",
        type=float,
        help=
        "Time step (fs) for planets. Does NOT have to be the same as for the centroids.",
    )

    parser.add_argument(
        "temperature",
        type=float,
        help=
        "Simulation temperature (K). Best to make sure it is the same as the centroid temperature!",
    )

    parser.add_argument(
        "stride",
        type=int,
        help="""Number of steps to take between centroid updates
                             (so stride*dt should be the time elapsed between centroid positions being RECORDED).""",
    )

    parser.add_argument("npl",
                        type=int,
                        help="Number of planets for each centroid")

    parser.add_argument("npts",
                        type=int,
                        help="Number of points in centroid trajectory")

    parser.add_argument("iseed", type=int, help="Random number seed")

    parser.add_argument(
        "estmods",
        type=str,
        nargs="+",
        help="External modules defining estimators in the required format",
    )

    args = parser.parse_args()

    with open("{}.xc.xyz".format(args.prefix), "r") as f:
        args.natoms = int(f.readline())
        for i in range(args.natoms + 2):
            f.readline()
        stride2 = int(f.readline().split("Step:")[1].split("Bead:")[0])

    if args.stride != stride2:
        warning(
            "Make sure stride*dt = time elapsed between centroid positions being recorded\n"
            + "(this might already be true).")

    estimators = []
    for modname in args.estmods:
        # This might be quite ugly but it works for now
        if "/" in modname:
            path, modname = modname.rsplit("/", 1)
            sys.path.insert(0, path)
        mod = importlib.import_module(modname)
        # estimators.append(mod.est)
        estimators.append(mod)

    args.estmods = ", ".join(args.estmods)
    print("----------------------")
    print("DETERMINED INPUT PARAMETERS")
    print("----------------------")
    for k, v in sorted(args.__dict__.items()):
        print("{:<30s}{}".format(k, v))
    print("----------------------")
    sys.stdout.flush()

    return (
        args.prefix,
        args.natoms,
        args.iseed,
        args.npl,
        args.npts,
        args.stride,
        args.dt,
        args.temperature,
        estimators,
    )
Ejemplo n.º 38
0
    def pool_distribute(self):
        """Deals with keeping the list of jobs up-to-date during a force
      calculation step.

      Deals with maintaining the jobs list. Gets data from drivers that have
      finished their calculation and removes that job from the list of running
      jobs, adds jobs to free clients and initialises the forcefields of new
      clients.
      """

        for c in self.clients:
            if c.status == Status.Disconnected:  # client disconnected. force a pool_update
                self._poll_iter = UPDATEFREQ
                return
            if not c.status & (Status.Ready | Status.NeedsInit):
                c.poll()

        for [r, c] in self.jobs[:]:
            if c.status & Status.HasData:
                try:
                    r["result"] = c.getforce()
                    if len(r["result"][1]) != len(r["pos"]):
                        raise InvalidSize
                except Disconnected:
                    c.status = Status.Disconnected
                    continue
                except InvalidSize:
                    warning(
                        " @SOCKET:   Client returned an inconsistent number of forces. Will mark as disconnected and try to carry on.",
                        verbosity.low)
                    c.status = Status.Disconnected
                    continue
                except:
                    warning(
                        " @SOCKET:   Client got in a awkward state during getforce. Will mark as disconnected and try to carry on.",
                        verbosity.low)
                    c.status = Status.Disconnected
                    continue
                c.poll()
                while c.status & Status.Busy:  # waits, but check if we got stuck.
                    if self.timeout > 0 and r["start"] > 0 and time.time(
                    ) - r["start"] > self.timeout:
                        warning(
                            " @SOCKET:  Timeout! HASDATA for bead " +
                            str(r["id"]) + " has been running for " +
                            str(time.time() - r["start"]) + " sec.",
                            verbosity.low)
                        warning(
                            " @SOCKET:   Client " + str(c.peername) +
                            " died or got unresponsive(A). Disconnecting.",
                            verbosity.low)
                        try:
                            c.shutdown(socket.SHUT_RDWR)
                        except:
                            pass
                        c.close()
                        c.status = Status.Disconnected
                        continue
                    c.poll()
                if not (c.status & Status.Up):
                    warning(
                        " @SOCKET:   Client died a horrible death while getting forces. Will try to cleanup.",
                        verbosity.low)
                    continue
                r["status"] = "Done"
                c.lastreq = r[
                    "id"]  # saves the ID of the request that the client has just processed
                self.jobs = [
                    w for w in self.jobs if not (w[0] is r and w[1] is c)
                ]  # removes pair in a robust way

            if self.timeout > 0 and c.status != Status.Disconnected and r[
                    "start"] > 0 and time.time() - r["start"] > self.timeout:
                warning(
                    " @SOCKET:  Timeout! Request for bead " + str(r["id"]) +
                    " has been running for " + str(time.time() - r["start"]) +
                    " sec.", verbosity.low)
                warning(
                    " @SOCKET:   Client " + str(c.peername) +
                    " died or got unresponsive(B). Disconnecting.",
                    verbosity.low)
                try:
                    c.shutdown(socket.SHUT_RDWR)
                except socket.error:
                    e = sys.exc_info()
                    warning(
                        " @SOCKET:  could not shut down cleanly the socket. %s: %s in file '%s' on line %d"
                        % (e[0].__name__, e[1],
                           os.path.basename(e[2].tb_frame.f_code.co_filename),
                           e[2].tb_lineno), verbosity.low)
                c.close()
                c.poll()
                c.status = Status.Disconnected

        freec = self.clients[:]
        for [r2, c] in self.jobs:
            freec.remove(c)

        pendr = self.requests[:]
        pendr = [r for r in self.requests if r["status"] == "Queued"]

        for fc in freec[:]:
            matched = False
            # first, makes sure that the client is REALLY free
            if not (fc.status & Status.Up):
                self.clients.remove(
                    fc
                )  # if fc is in freec it can't be associated with a job (we just checked for that above)
                continue
            if fc.status & Status.HasData:
                continue
            if not (fc.status &
                    (Status.Ready | Status.NeedsInit | Status.Busy)):
                warning(
                    " @SOCKET: Client " + str(fc.peername) +
                    " is in an unexpected status " + str(fc.status) +
                    " at (1). Will try to keep calm and carry on.",
                    verbosity.low)
                continue
            for match_ids in ("match", "none", "free", "any"):
                for r in pendr[:]:
                    if match_ids == "match" and not fc.lastreq is r["id"]:
                        continue
                    elif match_ids == "none" and not fc.lastreq is None:
                        continue
                    elif match_ids == "free" and fc.locked:
                        continue

                    info(
                        " @SOCKET: Assigning [%5s] request id %4s to client with last-id %4s (% 3d/% 3d : %s)"
                        % (match_ids, str(r["id"]), str(fc.lastreq),
                           self.clients.index(fc), len(self.clients),
                           str(fc.peername)), verbosity.high)

                    while fc.status & Status.Busy:
                        fc.poll()
                    if fc.status & Status.NeedsInit:
                        fc.initialize(r["id"], r["pars"])
                        fc.poll()
                        while fc.status & Status.Busy:  # waits for initialization to finish. hopefully this is fast
                            fc.poll()
                    if fc.status & Status.Ready:
                        fc.sendpos(r["pos"], r["cell"])
                        r["status"] = "Running"
                        r["start"] = time.time(
                        )  # sets start time for the request
                        fc.poll()
                        self.jobs.append([r, fc])
                        fc.locked = (fc.lastreq is r["id"])
                        matched = True
                        # removes r from the list of pending jobs
                        pendr = [nr for nr in pendr if (not nr is r)]
                        break
                    else:
                        warning(
                            " @SOCKET: Client " + str(fc.peername) +
                            " is in an unexpected status " + str(fc.status) +
                            " at (2). Will try to keep calm and carry on.",
                            verbosity.low)
                if matched:
                    break  # doesn't do a second (or third) round if it managed
Ejemplo n.º 39
0
    def forces_4th_order(self, index):
        """ Fetches the 4th order |f^2| correction to the force vector associated with a given component."""

        # gives an error is number of beads is not even.
        if self.nbeads % 2 != 0:
            warning(
                "ERROR: Suzuki-Chin factorization requires even number of beads!"
            )
            exit()

        # calculates the finite displacement.
        fbase = depstrip(self.f)
        eps = self.mforces[index].epsilon
        delta = np.abs(eps) / np.sqrt(
            (fbase / self.beads.m3 * fbase / self.beads.m3).sum() /
            (self.nbeads * self.natoms))
        dq = delta * fbase / self.beads.m3

        # stores the force component.
        fbase = self.mrpc[index].b2tob1(depstrip(self.mforces[index].f))

        # uses a fwd difference if epsilon > 0.
        if self.mforces[index].epsilon > 0.0:

            # gives an error if RPC is used with a fwd difference.
            # The problem is that the finite difference is computed as [f(q + e.f) - f(q)].e^-1,
            # where f(q + e.f) is computed on a smaller rimg polymer of P / 2 beads which is made
            # by displacing the odd beads of the original ring polymer. Upon contraction,  it yields
            # a ring polymer that is different from the contracted one on which f(q) was computed.
            # This makes the FD incorrect. A fix could be to ALWAYS compute the odd and the even
            # beads on two different ring polymers of P / 2 beads, but centered difference + RPC
            # seems to be a neater solution. Anyway, the cost of a CNT-DIFF in comparison to a FWD-DIFF
            # is marginal in when RPC + MTS is used.

            if self.mforces[index].nbeads != self.nbeads:
                warning(
                    "ERROR: high order PIMD + RPC works with a centered finite difference only! (Uness you find an elegant solution :))"
                )
                exit()

            # for the case of alpha = 0, only odd beads are displaced.
            if self.alpha == 0:

                # we use an aux force evaluator with half the number of beads.
                if self.dforces is None:
                    self.dbeads = self.beads.copy(self.nbeads / 2)
                    self.dcell = self.cell.copy()
                    self.dforces = self.copy(self.dbeads, self.dcell)

                f_4th_order = fbase * 0.0

                # displaces odd beads only.
                self.dbeads.q = depstrip(self.beads.q)[1::2] - dq[1::2]

                # calculates the force.
                fminus = self.dforces.mrpc[index].b2tob1(
                    depstrip(self.dforces.mforces[index].f))

                # calculates the finite difference.
                f_4th_order[1::2] = 2.0 * (fminus - fbase[1::2]) / delta

            # For the case of alpha != 0, all the beads are displaced.
            else:

                # we use an aux force evaluator with the same number of beads.
                if self.dforces is None:
                    self.dbeads = self.beads.copy()
                    self.dcell = self.cell.copy()
                    self.dforces = self.copy(self.dbeads, self.dcell)

                f_4th_order = fbase * 0.0

                # displaces the beads.
                self.dbeads.q = self.beads.q + dq

                # calculates the force.
                fplus = self.dforces.mrpc[index].b2tob1(
                    (depstrip(self.dforces.mforces[index].f)))

                # calculates the finite difference.
                f_4th_order = 2.0 * (fbase - fplus) / delta

        # uses a centered difference for epsilon  < 0.
        if self.mforces[index].epsilon < 0.0:

            # we use an aux force evaluator with the same number of beads.
            if self.dforces is None:
                self.dbeads = self.beads.copy()
                self.dcell = self.cell.copy()
                self.dforces = self.copy(self.dbeads, self.dcell)

            f_4th_order = fbase * 0.0

            # for the case of alpha = 0, only odd beads are displaced.
            if self.alpha == 0:

                # the first half of the aux beads are fwd displaced while the second half are bkwd displaced configurations.
                self.dbeads.q[:self.nbeads /
                              2] = depstrip(self.beads.q)[1::2] + dq[1::2]
                self.dbeads.q[-self.nbeads /
                              2:] = depstrip(self.beads.q)[1::2] - dq[1::2]

                # calculates the forces.
                fplusminus = self.dforces.mrpc[index].b2tob1(
                    depstrip(self.dforces.mforces[index].f))

                # calculates the finite difference.
                for k in range(self.nbeads / 2):
                    j = 2 * k + 1
                    f_4th_order[j] = 2.0 * (fplusminus[self.nbeads / 2 + k] -
                                            fplusminus[k]) / 2.0 / delta

            # For the case of alpha != 0, all the beads are displaced.
            else:
                # displaces the beads.
                self.dbeads.q = self.beads.q + dq

                # calculates the forces.
                fplus = self.dforces.mrpc[index].b2tob1(
                    depstrip(self.dforces.mforces[index].f))

                # displaces the beads.
                self.dbeads.q = self.beads.q - dq

                # calculates the forces.
                fminus = self.dforces.mrpc[index].b2tob1(
                    depstrip(self.dforces.mforces[index].f))
                # calculates the finite difference.
                f_4th_order = 2.0 * (fminus - fplus) / 2.0 / delta

        # returns the 4th order |f^2| correction.
        return f_4th_order