示例#1
0
def read_json(filedesc, **kwargs):
    """Reads a JSON-style file with i-pi style comments and creates an Atoms and Cell object.

    Args:
        filedesc: An open readable file object from a json formatted file with i-PI header comments.

    Returns:
        An Atoms object with the appropriate atom labels, masses and positions.
        A Cell object.
    """

    try:
        line = json.loads(filedesc.readline())
    except ValueError:
        raise EOFError("The file descriptor hit EOF.")
    atoms = Atoms(line[0])
    atoms.q = np.asarray(line[8])
    atoms.names = np.asarray(line[9], dtype='|S4')
    atoms.m = np.asarray(map(Elements.mass, atoms.names))

    a = float(line[1])
    b = float(line[2])
    c = float(line[3])
    alpha = float(line[4]) * np.pi / 180
    beta = float(line[5]) * np.pi / 180
    gamma = float(line[6]) * np.pi / 180
    h = mt.abc2h(a, b, c, alpha, beta, gamma)
    cell = Cell(h)

    return {"atoms": atoms, "cell": cell}
示例#2
0
def create_random_xyz_traj_to_write(request):

    natoms, frames, comment, expected_cell, precision = request.param

    a, b, c, alpha, beta, gamma = mt.h2abc_deg(expected_cell)

    fmt_header = "# CELL(abcABC): %10.5f  %10.5f  %10.5f  %10.5f  %10.5f  %10.5f  %s"

    comment = fmt_header % (a, b, c, alpha, beta, gamma, comment)

    filedesc, xyz, atom_names = xyz_gen.xyz_traj_filedesc(natoms, frames, comment)
    filedesc.seek(0)

    masses = [Elements.mass(_am) for _am in atom_names]

    cell_list = []
    atoms_list = []

    for _fr in xrange(frames):
        cell = Cell(expected_cell)
        atoms = Atoms(natoms)
        atoms.q[:] = xyz[_fr * natoms * 3:(_fr + 1) * natoms * 3]
        atoms.names = atom_names[_fr * natoms:(_fr + 1) * natoms]
        atoms.m[:] = masses[_fr * natoms:(_fr + 1) * natoms]
        atoms_list.append(atoms)
        cell_list.append(cell)

    return (filedesc, atoms_list, cell_list, comment, precision)
示例#3
0
def create_xyz_sample_file(request):
    """ Create a fake xyz file and build the atoms and cell object from it.
    """

    natoms, frames, comment, expected_cell, units_conv_at, units_conv_cell = request.param

    filedesc, xyz, atoms_names = xyz_gen.xyz_traj_filedesc(natoms, frames, comment)

    # init_file needs to read from a real file...
    tmp_file = tmp.NamedTemporaryFile(mode='wr', prefix='ipi_testing-tmp', delete=False)
    tmp_file.seek(0)
    tmp_file.write(filedesc.read())
    tmp_file.close()
    filedesc.close()

    masses = np.zeros(natoms * frames)
    for _ii, _at in enumerate(atoms_names):
        masses[_ii] = Elements.mass(_at)

    ratoms = []
    for _fr in range(frames):
        ratoms.append(Atoms(natoms))
        ratoms[-1].q = xyz[_fr * natoms * 3:3 * (_fr + 1) * natoms] * units_conv_at
        ratoms[-1].m = masses[_fr * natoms:(_fr + 1) * natoms]
        ratoms[-1].names = atoms_names[_fr * natoms:(_fr + 1) * natoms]

    cell = Cell(expected_cell * units_conv_cell)

    # remove temp file created during this test
    def delete_files_after_testing():
        if os.path.isfile(tmp_file.name):
            os.remove(tmp_file.name)

    request.addfinalizer(delete_files_after_testing)
    return tmp_file, cell, ratoms
示例#4
0
    def __init__(self,
                 dt=None,
                 temp=None,
                 tau=None,
                 ebaro=None,
                 thermostat=None,
                 stressext=None,
                 h0=None,
                 p=None):
        """Initializes BZP barostat.

         Args:
         dt: Optional float giving the time step for the algorithms. Defaults
         to the simulation dt.
         temp: Optional float giving the temperature for the thermostat.
         Defaults to the simulation temp.
         stressext: Optional float giving the external pressure.
         tau: Optional float giving the time scale associated with the barostat.
         ebaro: Optional float giving the conserved quantity already stored
         in the barostat initially. Used on restart.
         thermostat: The thermostat connected to the barostat degree of freedom.
         p: Optional initial volume conjugate momentum. Defaults to 0.
         """

        super(BaroRGB, self).__init__(dt, temp, tau, ebaro, thermostat)

        # non-zero elements of the cell momentum are only
        # pxx pyy pzz pxy pxz pyz, but we want to access it either as a
        # 6-vector or as a 3x3 upper triangular tensor.
        # we use a synchronizer to achieve that

        sync_baro = synchronizer()
        dset(
            self, "p6",
            depend_array(name='p6',
                         value=np.zeros(6, float),
                         synchro=sync_baro,
                         func={"p": self.get_3x3to6}))
        dset(
            self, "p",
            depend_array(name='p',
                         value=np.zeros((3, 3), float),
                         synchro=sync_baro,
                         func={"p6": self.get_6to3x3}))

        if not p is None:
            self.p = p
        else:
            self.p = 0.0

        if not h0 is None:
            self.h0 = h0
        else:
            self.h0 = Cell()

        if not stressext is None:
            self.stressext = stressext
        else:
            self.stressext[:] = -1.0
示例#5
0
def read_pdb(filedesc):
    """Takes a pdb-style file and creates an Atoms and Cell object.

   Args:
      filedesc: An open readable file object from a pdb formatted file.

   Returns:
      An Atoms object with the appropriate atom labels, masses and positions,
      and a Cell object with the appropriate cell dimensions and an estimate
      of a reasonable cell mass.
   """

    header = filedesc.readline()
    if "TITLE" in header:
        header = filedesc.readline()  # skip the comment field
    if header == "":
        raise EOFError("End of file or empty header in PDB file")

    a = float(header[6:15])
    b = float(header[15:24])
    c = float(header[24:33])
    alpha = float(header[33:40])
    beta = float(header[40:47])
    gamma = float(header[47:54])
    alpha *= np.pi / 180.0
    beta *= np.pi / 180.0
    gamma *= np.pi / 180.0
    h = mt.abc2h(a, b, c, alpha, beta, gamma)
    cell = Cell(h)

    natoms = 0
    body = filedesc.readline()
    qatoms = []
    names = []
    masses = []
    while (body.strip() != "" and body.strip() != "END"):
        natoms += 1
        name = body[12:16].strip()
        names.append(name)
        masses.append(Elements.mass(name))
        x = float(body[31:39])
        y = float(body[39:47])
        z = float(body[47:55])
        qatoms.append(x)
        qatoms.append(y)
        qatoms.append(z)

        body = filedesc.readline()

    atoms = Atoms(natoms)
    atoms.q = np.asarray(qatoms)
    atoms.names = np.asarray(names, dtype='|S4')
    atoms.m = np.asarray(masses)

    return atoms, cell
示例#6
0
def test_print_xyz():
   """Tests that xyz files are printed correctly."""

   with open(local("test.pos_0.pdb"), "r") as f:
      with open(local("test.pos_1.pdb"), "w") as out:
         for num, (atoms, cell) in enumerate(io_pdb.iter_pdb(f)):
            assert(len(atoms) == 3)
            assert_equal(pos*(num+1), atoms.q)
            io_pdb.print_pdb(atoms, Cell(h=np.identity(3, float)), filedesc=out)

   assert(filecmp.cmp(local("test.pos_0.pdb"), local("test.pos_1.pdb")))
   os.unlink(local("test.pos_1.pdb"))
示例#7
0
def process_units(
    comment,
    cell,
    data,
    names,
    masses,
    natoms,
    dimension="automatic",
    units="automatic",
    cell_units="automatic",
    mode="xyz",
):
    """Convert the data in the file according to the units written in the i-PI format.

    Args:
        comment:
        cell:
        data:
        names:
        masses:
        output:

    Returns:

    """
    dimension, units, cell_units = auto_units(comment, dimension, units,
                                              cell_units, mode)

    info(
        " # Interpreting input with dimension %s, units %s and cell units %s" %
        (dimension, units, cell_units),
        verbosity.high,
    )

    # Units transformation
    cell *= unit_to_internal("length", cell_units,
                             1)  # cell units transformation
    data *= unit_to_internal(dimension, units, 1)  # units transformation

    # Return data as i-PI structures
    cell = Cell(cell)
    atoms = Atoms(natoms)
    atoms.q[:] = data
    atoms.names[:] = names
    atoms.m[:] = masses

    return {
        "atoms": atoms,
        "cell": cell,
    }
示例#8
0
def process_units(comment, cell, qatoms, names, masses, output='objects'):
    """ Converts the data in the file according to the units written in the ipi format.
    """
    # Extracting trajectory units
    family, unit = 'undefined', ''
    is_comment_useful = filter(None, [key.search(comment.strip())
                                      for key in traj_re])
    if len(is_comment_useful) > 0:
        traj = is_comment_useful[0].group()[:-1].split('{')
        family, unit = traj_dict[traj[0]]['dimension'], traj[1]

    # Extracting cell units
    cell_unit = ''
    tmp = cell_unit_re.search(comment)
    if tmp is not None:
        cell_unit = tmp.group(1)

    # Units transformation
    cell *= unit_to_internal('length', cell_unit, 1) # cell units transformation
    qatoms *= unit_to_internal(family, unit, 1) # units transformation
    if output == 'objects':

        cell = Cell(cell)
        atoms = Atoms(len(names))
        atoms.q[:] = qatoms
        atoms.names[:] = names
        atoms.m[:] = masses

        return {
          "atoms": atoms,
          "cell": cell,
        }

    else:

        return {
          "data": qatoms,
          "masses": masses,
          "names": names,
          "natoms": len(names),
          "cell": cell,
        }
示例#9
0
    def __init__(self,
                 mode,
                 geop,
                 nstep,
                 a0,
                 ncell,
                 nvac,
                 nsi,
                 nmg,
                 neval,
                 diffusion_barrier_al,
                 diffusion_prefactor_al,
                 diffusion_barrier_mg,
                 diffusion_prefactor_mg,
                 diffusion_barrier_si,
                 diffusion_prefactor_si,
                 idx=[],
                 tottime=0,
                 ecache_file="",
                 qcache_file="",
                 thermostat=None,
                 barostat=None,
                 fixcom=False,
                 fixatoms=None,
                 nmts=None):
        """Initialises a "dynamics" motion object.

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

        # This will generate a lattice model based on a primitive FCC cell. the lattice is represented in three ways:
        # 1. as a string in which each lattice site is identified by a letter
        # 2. by a list of the lattice sites in 3D space, in 1-1 mapping with the letters
        # 3. by a list of the atoms, whose lattice position is indicated by an integer

        self.nstep = nstep
        self.ncell = ncell
        self.nvac = nvac
        self.nsi = nsi
        self.nmg = nmg
        self.nsites = self.ncell**3
        self.natoms = self.nsites - self.nvac
        self.neval = neval
        self.diffusion_barrier_al = diffusion_barrier_al
        self.diffusion_prefactor_al = diffusion_prefactor_al
        if diffusion_barrier_mg > 0:
            self.diffusion_barrier_mg = diffusion_barrier_mg
        else:
            self.diffusion_barrier_mg = diffusion_barrier_al
        if diffusion_barrier_si > 0:
            self.diffusion_barrier_si = diffusion_barrier_si
        else:
            self.diffusion_barrier_si = diffusion_barrier_al
        if diffusion_prefactor_mg > 0:
            self.diffusion_prefactor_mg = diffusion_prefactor_mg
        else:
            self.diffusion_prefactor_mg = diffusion_prefactor_al
        if diffusion_prefactor_si > 0:
            self.diffusion_prefactor_si = diffusion_prefactor_si
        else:
            self.diffusion_prefactor_si = diffusion_prefactor_al
        self.barriers = {
            "A": self.diffusion_barrier_al,
            "M": self.diffusion_barrier_mg,
            "S": self.diffusion_barrier_si
        }
        self.prefactors = {
            "A": self.diffusion_prefactor_al,
            "M": self.diffusion_prefactor_mg,
            "S": self.diffusion_prefactor_si
        }

        self.a0 = a0
        cell = np.zeros((3, 3))
        cell[0] = [
            0.7071067811865475, 0.35355339059327373, 0.35355339059327373
        ]
        cell[1] = [0., 0.6123724356957945, 0.20412414523193154]
        cell[2] = [0., 0., 0.5773502691896258]
        self.scell = self.a0 * cell
        self.dcell = Cell()
        self.dcell.h = self.scell * self.ncell

        print "LATTICE PARAM ", self.a0
        # this is the list of lattice sites, in 3D coordinates
        ix, iy, iz = np.meshgrid(range(self.ncell),
                                 range(self.ncell),
                                 range(self.ncell),
                                 indexing='ij')
        self.sites = np.dot(
            np.asarray([ix.flatten(), iy.flatten(),
                        iz.flatten()]).T, self.scell.T)
        print len(self.sites), self.nsites, "###"
        # now we build list of nearest neighbors (fcc-lattice hardcoded!)
        self.neigh = np.zeros((self.nsites, 12), int)
        nneigh = np.zeros(self.nsites, int)
        # could be done in a more analytic way but whatever, I'm too lazy
        a02 = 1.01 * 0.5 * self.a0**2  # perhaps 1.01 it is not enough, must check!
        for i in xrange(
                self.nsites):  # determines the connectivity of the lattice
            rij = self.sites.copy().flatten()
            for j in xrange(self.nsites):
                rij[3 * j:3 * j + 3] -= self.sites[i]
            self.dcell.array_pbc(rij)
            rij.shape = (self.nsites, 3)
            for j in xrange(i):
                if np.dot(rij[j], rij[j]) < a02:  # found nearest neighbor
                    self.neigh[i, nneigh[i]] = j
                    self.neigh[j, nneigh[j]] = i
                    nneigh[i] += 1
                    nneigh[j] += 1

        self.idx = idx

        # the KMC step is variable and so it cannot be stored as proper timing
        dd(self).dt = depend_value(name="dt", value=0.0)
        self.fixatoms = np.asarray([])
        self.fixcom = True
        self.geop = [None] * self.neval
        # geop should not trigger exit if there is early convergence, but just carry on.
        # we hard-code this option to avoid early-termination that would be hard to debug for a user
        geop["exit_on_convergence"] = False
        for i in xrange(self.neval):
            # geometry optimizer should not have *any* hystory dependence
            self.geop[i] = GeopMotion(
                fixcom=fixcom, fixatoms=fixatoms, **geop
            )  #mode="cg", ls_options={"tolerance": 1, "iter": 20,  "step": 1e-3, "adaptive": 0.0}, tolerances={"energy": 1e-7, "force": 1e-2, "position": 1e-4}, ) #!TODO: set the geop parameters properly

        # dictionary of previous energy evaluations - kind of tricky to use this with the omaker thingie
        self.ecache_file = ecache_file
        self.qcache_file = qcache_file
        try:
            ff = open(self.ecache_file, "rb")
            self.ecache = pickle.load(ff)
            ff.close()
            ff = open(self.qcache_file, "rb")
            self.qcache = pickle.load(ff)
            ff.close()
            print "Loaded %d cached energies" % (len(self.ecache))
        except:
            print "Couldn't load cache files " + self.ecache_file + "," + self.qcache_file + " - resetting"
            self.ecache = {}
            self.qcache = {}
        self.ncache = len(self.ecache)
        self.ncache_stored = self.ncache

        # no TS evaluation implemented yet
        self.tscache = {}
        self.tottime = tottime
示例#10
0
class AlKMC(Motion):
    """Stepper for a KMC for Al-6xxx alloys.

    Gives the standard methods and attributes needed in all the
    dynamics classes.

    Attributes:
        beads: A beads object giving the atoms positions.
        cell: A cell object giving the system box.
        forces: A forces object giving the virial and the forces acting on
            each bead.
        prng: A random number generator object.
        nm: An object which does the normal modes transformation.

    Depend objects:
        econs: The conserved energy quantity appropriate to the given
            ensemble. Depends on the various energy terms which make it up,
            which are different depending on the ensemble.he
        temp: The system temperature.
        dt: The timestep for the algorithms.
        ntemp: The simulation temperature. Will be nbeads times higher than
            the system temperature as PIMD calculations are done at this
            effective classical temperature.
    """
    def __init__(self,
                 mode,
                 geop,
                 nstep,
                 a0,
                 ncell,
                 nvac,
                 nsi,
                 nmg,
                 neval,
                 diffusion_barrier_al,
                 diffusion_prefactor_al,
                 diffusion_barrier_mg,
                 diffusion_prefactor_mg,
                 diffusion_barrier_si,
                 diffusion_prefactor_si,
                 idx=[],
                 tottime=0,
                 ecache_file="",
                 qcache_file="",
                 thermostat=None,
                 barostat=None,
                 fixcom=False,
                 fixatoms=None,
                 nmts=None):
        """Initialises a "dynamics" motion object.

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

        # This will generate a lattice model based on a primitive FCC cell. the lattice is represented in three ways:
        # 1. as a string in which each lattice site is identified by a letter
        # 2. by a list of the lattice sites in 3D space, in 1-1 mapping with the letters
        # 3. by a list of the atoms, whose lattice position is indicated by an integer

        self.nstep = nstep
        self.ncell = ncell
        self.nvac = nvac
        self.nsi = nsi
        self.nmg = nmg
        self.nsites = self.ncell**3
        self.natoms = self.nsites - self.nvac
        self.neval = neval
        self.diffusion_barrier_al = diffusion_barrier_al
        self.diffusion_prefactor_al = diffusion_prefactor_al
        if diffusion_barrier_mg > 0:
            self.diffusion_barrier_mg = diffusion_barrier_mg
        else:
            self.diffusion_barrier_mg = diffusion_barrier_al
        if diffusion_barrier_si > 0:
            self.diffusion_barrier_si = diffusion_barrier_si
        else:
            self.diffusion_barrier_si = diffusion_barrier_al
        if diffusion_prefactor_mg > 0:
            self.diffusion_prefactor_mg = diffusion_prefactor_mg
        else:
            self.diffusion_prefactor_mg = diffusion_prefactor_al
        if diffusion_prefactor_si > 0:
            self.diffusion_prefactor_si = diffusion_prefactor_si
        else:
            self.diffusion_prefactor_si = diffusion_prefactor_al
        self.barriers = {
            "A": self.diffusion_barrier_al,
            "M": self.diffusion_barrier_mg,
            "S": self.diffusion_barrier_si
        }
        self.prefactors = {
            "A": self.diffusion_prefactor_al,
            "M": self.diffusion_prefactor_mg,
            "S": self.diffusion_prefactor_si
        }

        self.a0 = a0
        cell = np.zeros((3, 3))
        cell[0] = [
            0.7071067811865475, 0.35355339059327373, 0.35355339059327373
        ]
        cell[1] = [0., 0.6123724356957945, 0.20412414523193154]
        cell[2] = [0., 0., 0.5773502691896258]
        self.scell = self.a0 * cell
        self.dcell = Cell()
        self.dcell.h = self.scell * self.ncell

        print "LATTICE PARAM ", self.a0
        # this is the list of lattice sites, in 3D coordinates
        ix, iy, iz = np.meshgrid(range(self.ncell),
                                 range(self.ncell),
                                 range(self.ncell),
                                 indexing='ij')
        self.sites = np.dot(
            np.asarray([ix.flatten(), iy.flatten(),
                        iz.flatten()]).T, self.scell.T)
        print len(self.sites), self.nsites, "###"
        # now we build list of nearest neighbors (fcc-lattice hardcoded!)
        self.neigh = np.zeros((self.nsites, 12), int)
        nneigh = np.zeros(self.nsites, int)
        # could be done in a more analytic way but whatever, I'm too lazy
        a02 = 1.01 * 0.5 * self.a0**2  # perhaps 1.01 it is not enough, must check!
        for i in xrange(
                self.nsites):  # determines the connectivity of the lattice
            rij = self.sites.copy().flatten()
            for j in xrange(self.nsites):
                rij[3 * j:3 * j + 3] -= self.sites[i]
            self.dcell.array_pbc(rij)
            rij.shape = (self.nsites, 3)
            for j in xrange(i):
                if np.dot(rij[j], rij[j]) < a02:  # found nearest neighbor
                    self.neigh[i, nneigh[i]] = j
                    self.neigh[j, nneigh[j]] = i
                    nneigh[i] += 1
                    nneigh[j] += 1

        self.idx = idx

        # the KMC step is variable and so it cannot be stored as proper timing
        dd(self).dt = depend_value(name="dt", value=0.0)
        self.fixatoms = np.asarray([])
        self.fixcom = True
        self.geop = [None] * self.neval
        # geop should not trigger exit if there is early convergence, but just carry on.
        # we hard-code this option to avoid early-termination that would be hard to debug for a user
        geop["exit_on_convergence"] = False
        for i in xrange(self.neval):
            # geometry optimizer should not have *any* hystory dependence
            self.geop[i] = GeopMotion(
                fixcom=fixcom, fixatoms=fixatoms, **geop
            )  #mode="cg", ls_options={"tolerance": 1, "iter": 20,  "step": 1e-3, "adaptive": 0.0}, tolerances={"energy": 1e-7, "force": 1e-2, "position": 1e-4}, ) #!TODO: set the geop parameters properly

        # dictionary of previous energy evaluations - kind of tricky to use this with the omaker thingie
        self.ecache_file = ecache_file
        self.qcache_file = qcache_file
        try:
            ff = open(self.ecache_file, "rb")
            self.ecache = pickle.load(ff)
            ff.close()
            ff = open(self.qcache_file, "rb")
            self.qcache = pickle.load(ff)
            ff.close()
            print "Loaded %d cached energies" % (len(self.ecache))
        except:
            print "Couldn't load cache files " + self.ecache_file + "," + self.qcache_file + " - resetting"
            self.ecache = {}
            self.qcache = {}
        self.ncache = len(self.ecache)
        self.ncache_stored = self.ncache

        # no TS evaluation implemented yet
        self.tscache = {}
        self.tottime = tottime

    def bind(self, ens, beads, nm, cell, bforce, prng, omaker):
        """Binds ensemble beads, cell, bforce, and prng to the dynamics.

        This takes a beads object, a cell object, a forcefield object and a
        random number generator object and makes them members of the ensemble.
        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(AlKMC, self).bind(ens, beads, nm, cell, bforce, prng, omaker)

        # todo make these optional and restarted
        self.kmcfile = self.output_maker.get_output("KMC_AL6XXX")

        # this is the index for the atoms, self.idx[i] indicates the lattice site of atom i.
        # atoms are in the order Si1 Si2 ... Mg1 Mg2 .... Al1 Al2 .... Vac1 Vac2 ...
        f_restart = True
        if self.idx is None or len(self.idx) == 0:
            f_restart = False
            idx = np.asarray(range(self.ncell**3),
                             int)  # initialize random distribution of atoms
            self.prng.rng.shuffle(idx)
            self.idx = idx

        # initialize state based on the index
        # this is a string indicating the state of the system. each character corresponds to a lattice site
        # and can be S=Si, M=Mg, A=Al, V=Vac.
        # create a random string
        names = np.asarray(
            list("S" * self.nsi + "M" * self.nmg +
                 (self.natoms - self.nsi - self.nmg) * "A" + "V" * self.nvac))
        state = names.copy()

        # this maps the string to random sites
        state[self.idx] = names  #backshuffle!
        state = "".join(state)

        # reverse lookup index [i.e. ridx[i] gives the index of the atoms at site i]
        self.ridx = np.zeros(self.nsites, int)
        self.ridx[self.idx] = range(self.nsites)

        self.state = np.asarray(list(state))
        print "".join(self.state)

        print "CHECKING INITIAL ASSIGNMENTS"
        for i in xrange(self.nsites):
            if self.ridx[i] < self.natoms:
                print self.beads.names[self.ridx[i]], self.state[i]
            else:
                print "V", self.state[i]
            if self.idx[self.ridx[i]] != i:
                print "inconsistent site string for atom ", i, " and site ", self.ridx[
                    i]

        if not f_restart:
            self.beads.q[0, :] = self.sites[self.idx].flatten(
            )  # also sets global q so we can use it further down

        self.dbeads = [None] * self.neval
        self.dforces = [None] * self.neval
        self.dnm = [None] * self.neval
        self.dens = [None] * self.neval
        self.dbias = [None] * self.neval
        for i in xrange(self.neval):
            self.dbeads[i] = beads.copy()
            self.dforces[i] = bforce.copy(self.dbeads[i], self.dcell)
            self.dnm[i] = nm.copy()
            self.dens[i] = ens.copy()
            self.dnm[i].bind(self.dens[i],
                             self,
                             beads=self.dbeads[i],
                             forces=self.dforces[i])
            self.dbias[i] = ens.bias.copy(self.dbeads[i], self.dcell)
            self.dens[i].bind(self.dbeads[i], self.dnm[i], self.dcell,
                              self.dforces[i], self.dbias[i])
            self.geop[i].bind(self.dens[i], self.dbeads[i], self.dnm[i],
                              self.dcell, self.dforces[i], prng, omaker)
        self.feval = np.ones(self.neval, int)
        self._threadlock = threading.Lock()

    # threaded geometry optimization
    def geop_thread(self, ieval, nstr, nevent, ostr=None):
        self.geop[ieval].reset()
        ipot = self.dforces[ieval].pot

        for i in xrange(self.nstep):
            # print "geop ", i, self.dforces[ieval].pot
            self.geop[ieval].step(i)
            #if self.geop[ieval].converged[0]: break
        newq = dstrip(self.dbeads[ieval].q[0]).copy()
        newpot = self.dforces[ieval].pot

        # print "geop ", self.nstep, self.dforces[ieval].pot
        with self._threadlock:
            self.ecache[nstr] = newpot
            self.qcache[nstr] = newq
            self.ncache += 1
            nevent[2] = self.ecache[nstr]
            nevent[3] = self.qcache[nstr]

        # launches TS calculation
        #if not ostr is None:
        #    self.ts_thread(ieval, ostr, nstr, nevent)
        #else:
        #    with self._threadlock:
        #        self.feval[ieval] = 1
        with self._threadlock:
            self.feval[ieval] = 1

        with self._threadlock:
            print "Finished ", nstr
            print "Energy, initial - TS - final: ", ipot, nevent[-1], newpot

    # threaded ts evaluation
    def ts_thread(self, ieval, ostr, nstr, nevent, setfev=1):
        # computes TS energy by linearly interpolating initial & final state
        # interpolates between two structures considering PBCs
        qstart = self.qcache[ostr]
        qend = self.qcache[nstr].copy()
        # finds atom matching assuming initial and final states differ only by a vacancy swap and are based on unique_idx lists
        midx = self.unique_idx_match(list(ostr), list(nstr))[0:self.natoms]
        qend.shape = (self.natoms, 3)
        qend[:] = qend[midx]
        qend.shape = (3 * self.natoms)

        qts = qend - qstart
        self.dcell.array_pbc(qts)  # use pbc!
        qts *= 0.5
        qts += qstart
        self.dbeads[ieval].q[0, :] = qts

        tspot = self.dforces[ieval].pot
        io.print_file("xyz",
                      self.beads[0],
                      self.dcell,
                      self.tslist,
                      title=("START  "),
                      key="positions",
                      dimension="length",
                      units="angstrom",
                      cell_units="angstrom")
        io.print_file("xyz",
                      self.dbeads[ieval][0],
                      self.dcell,
                      self.tslist,
                      title=("TS: %s %s  Energy: %15.8e  %15.8e " %
                             (ostr, nstr, tspot, tspot - self.forces.pot)),
                      key="positions",
                      dimension="length",
                      units="angstrom",
                      cell_units="angstrom")
        self.dbeads[ieval].q[0] = qend
        io.print_file("xyz",
                      self.dbeads[ieval][0],
                      self.dcell,
                      self.tslist,
                      title=("END  "),
                      key="positions",
                      dimension="length",
                      units="angstrom",
                      cell_units="angstrom")
        self.tslist.flush()

        with self._threadlock:
            # sets the tscache for both FW and BW transition (uses a dictionary to be super-safe and lazy, although of course this could be just a list)
            self.tscache[ostr][nstr] = tspot
            if not nstr in self.tscache: self.tscache[nstr] = {}
            self.tscache[nstr][ostr] = tspot
            self.feval[ieval] = 1
            nevent[4] = tspot

    def find_eval(self, ethreads):
        # finds first free evaluator
        while self.feval.sum(
        ) == 0:  # if all evaluators are busy, wait for one to get free
            for st in ethreads:
                st.join(1e-2)
                if st is None or not st.isAlive():
                    break
        with self._threadlock:
            # finds free evaluator
            for e in xrange(self.neval):
                if self.feval[e] == 1:
                    ieval = e
                    self.feval[ieval] = 0
                    break
        return ieval

    def unique_idx(self, state):
        # generates a starting lattice configuration that corresponds to a given state vector (a string of atomic types)
        # makes sure that the same occupation string corresponds to the same atom positions,
        # even though the actual atom indices might be different basically, makes the configurations
        # independent of same-atom permutations
        ksi = 0
        kmg = self.nsi
        kal = self.nsi + self.nmg
        kvac = self.natoms
        k = 0
        idx = np.zeros(self.nsites, int)
        for s in state:
            if s == "S":
                idx[ksi] = k
                ksi += 1
            elif s == "M":
                idx[kmg] = k
                kmg += 1
            elif s == "A":
                idx[kal] = k
                kal += 1
            elif s == "V":
                idx[kvac] = k
                kvac += 1
            k += 1
        return idx

    def unique_idx_match(self, state_1, state_2):
        # finds the best matching between the atoms in states state_1 and state_2,
        # assuming there is only one site swap
        # (should raise an error otherwise but it's not trivial without doing too many extra checks)
        # this basically says what is the motion of atoms from state 1 to state 2. This is useful
        # to interpolate between atomic coordinates in the two states, e.g. to get the TS geometry

        # gets the unique mapping of atoms from the state to the site ids
        uid_1 = self.unique_idx(state_1)
        ru1 = np.zeros(self.nsites, int)
        # this is the reverse map. what is the atom index that sits in a given site?
        ru1[uid_1] = np.asarray(range(self.nsites), int)

        uid_2 = self.unique_idx(state_2)
        ru2 = np.zeros(self.nsites, int)
        ru2[uid_2] = np.asarray(range(
            self.nsites), int)  # this says which atom is in a given site in u2

        iu12 = ru2[uid_1]
        iu21 = ru1[uid_2]
        for i in xrange(self.natoms):
            if iu12[i] >= self.natoms:
                #print "found vacancy swap 1->2", i, u1[i], u2[iu12[i]], iu12[i]
                i1vac2 = i
            if iu21[i] >= self.natoms:
                i2vac1 = i
                #print "found vacancy swap 2->1", i, u2[i], u1[iu21[i]], iu21[i]
        iu12[i1vac2] = i2vac1

        return iu12

    def step(self, step=None):

        kT = Constants.kb * self.ensemble.temp
        # computes current energy (if not already stored)
        ostr = "".join(
            self.state
        )  # this is a unique id string that charactrizes the current state
        self.tscache[ostr] = {}
        if not ostr in self.ecache:
            self.dbeads[0].q[0, :] = self.sites[self.unique_idx(
                self.state)].flatten()
            rv = [0, 0, 0, 0, 0]
            self.geop_thread(0, ostr, rv)
            #self.beads.q[0,:] = self.dbeads[0].q[0,:] # also updates current position
            # self.forces.transfer_forces(self.dforces[0]) # forces have already been computed here...

        ecurr = self.ecache[ostr]

        # enumerates possible reactive events (vacancy swaps)
        levents = []
        ethreads = [None] * self.neval
        # loops over the vacancy
        for ivac in xrange(self.natoms, self.natoms + self.nvac):
            svac = self.idx[ivac]  # lattice site associated with this vacancy
            if self.state[svac] != "V":
                raise IndexError(
                    "Something got screwed and a vacancy state is not a vacancy anymore!"
                )
            # loops over the neighbors of the selected vacancy
            for sneigh in self.neigh[svac]:
                # if the neighbor is a vacancy, move on. does not make sense to swap two vacancies!
                if self.state[sneigh] == "V": continue

                # creates a new state vector with swapped atoms-vacancy and the associated label string
                nstate = self.state.copy()
                nstate[svac], nstate[sneigh] = self.state[sneigh], self.state[
                    svac]
                nstr = "".join(
                    nstate
                )  # this is the string that corresponds to the new state
                if not nstr in self.ecache:
                    # new state, must compute!
                    # creates a swapped index
                    nidx = self.idx.copy()
                    if self.ridx[svac] != ivac or self.idx[ivac] != svac:
                        raise IndexError(
                            "Something got screwed and the index does not correspond anymore to site occupancy"
                        )

                    #ivac = self.ridx[svac]
                    ineigh = self.ridx[
                        sneigh]  # gets index of atom associated with the neighboring site
                    nidx[ivac], nidx[ineigh] = self.idx[ineigh], self.idx[ivac]

                    ieval = self.find_eval(ethreads)
                    # launches evaluator
                    self.dbeads[ieval].q[0, :] = self.sites[self.unique_idx(
                        nstate)].flatten()

                    nevent = [svac, sneigh, 0.0, 0.0, 0.0]

                    # runs a geometry optimization
                    #self.geop_thread(ieval=ieval, nstr=nstr, nevent=nevent)
                    st = threading.Thread(target=self.geop_thread,
                                          name=str(ieval),
                                          kwargs={
                                              "ieval": ieval,
                                              "nstr": nstr,
                                              "nevent": nevent,
                                              "ostr": ostr
                                          })
                    st.daemon = True
                    st.start()
                    ethreads[ieval] = st
                else:
                    print "Found state ", nstr, " retrieving cached energy ", self.ecache[
                        nstr]

                    # fetch energy from previous calculation
                    nevent = [
                        svac, sneigh, self.ecache[nstr], self.qcache[nstr], 0.0
                    ]

                    # EVALUATION OF TS ENERGY IS DISABLED FOR THE MOMENT...
                    # we might still need to compute the TS energy!
                    # if not nstr in self.tscache[ostr]:
                    #   print "Computing TS"
                    #   ieval = self.find_eval(ethreads)
                    #    st = threading.Thread(target=self.ts_thread, name=str(ieval), kwargs={"ieval":ieval, "ostr": ostr, "nstr":nstr, "nevent" : nevent})
                    #    st.daemon = True
                    #    st.start()
                    #    ethreads[ieval] = st
                    #else:
                    #    print "Found TS"
                    #    nevent[3] = self.tscache[ostr][nstr]
                nevent[-1] = self.state[sneigh]
                levents.append(nevent)
        # wait for all evaluators to finish
        for st in ethreads:
            while not st is None and st.isAlive():
                st.join(2)

        print "Computed ", len(
            levents), " possible reactions. Cache len ", len(self.ecache)

        # get list of rates
        rates = np.zeros(len(levents), float)
        crates = np.zeros(len(levents), float)
        cdf = 0.0
        for i in xrange(len(levents)):
            #print ("Barrier, naive: %f, static: %f" % (0.5*(ecurr + levents[i][2]) + self.diffusion_barrier_al, levents[i][4]))

            ets = 0.5 * (ecurr + levents[i][2]) + self.barriers[
                levents[i][-1]]  #naive heuristic for the ts energy
            print "Event ", i, levents[i][-1], ecurr, ">>", ets, ">>", levents[
                i][2]
            rates[i] = self.prefactors[levents[i][-1]] * np.exp(
                -(ets - ecurr) / kT)
            cdf += rates[i]
            crates[i] = cdf

        # KMC selection rule based on the rate
        fpick = self.prng.u * cdf
        isel = 0
        while fpick > crates[isel]:
            isel += 1
        dt = -1.0 / cdf * np.log(1.0 - self.prng.u)
        print("Time spent %12.5e at %s nrg %12.5e" % (dt, ostr, ecurr))
        print "Selected event ", isel, " with rate ", rates[isel], " / ", cdf

        iev = levents[isel]  # levents[self.prng.randint(len(levents))]
        svac, sneigh = iev[0], iev[1]
        ivac, ineigh = self.ridx[svac], self.ridx[sneigh]

        # does the swap (never reject, for the moment)
        self.state[svac], self.state[sneigh] = self.state[sneigh], self.state[
            svac]
        self.ridx[svac], self.ridx[sneigh] = self.ridx[sneigh], self.ridx[svac]
        self.idx[ivac], self.idx[ineigh] = self.idx[ineigh], self.idx[ivac]

        # we got a new configuration but the residence time is linked to the previous configuration so we output that
        self.kmcfile.write("%12.5e  %12.5e  %18.11e  %s\n" %
                           (self.tottime, dt, ecurr, ostr))
        self.kmcfile.flush()
        self.tottime += dt
        self.ensemble.time += dt  # updates time counter
        print "Finishing step at ", "".join(self.state)

        # updates the positions
        self.cell.h = self.dcell.h

        uidx = self.unique_idx(self.state)
        ruidx = np.zeros(self.nsites, int)
        ruidx[uidx] = range(self.nsites)

        self.sites[self.unique_idx(self.state)]
        oldq = dstrip(self.beads.q[0]).copy()

        newq = np.zeros(self.nsites * 3, float)
        # we want continuity (modulo PBC jumps, that we'll take care of later...)
        for i in xrange(self.nsites):
            # in which site sits atom i?
            isite = self.idx[i]
            # which atom sits in this site in the unique-mapped structure?
            iuid = ruidx[self.idx[i]]
            newq[3 * i:3 * i + 3] = iev[3][3 * iuid:3 * (iuid + 1)]
        newq -= oldq
        self.cell.array_pbc(newq)
        self.beads.q[0] += newq
示例#11
0
def contract_trajectory(fns_in, fn_out_template, n_new, cell_units_in, cell_units_out):

    verbosity.level = "low"
    n = len(fns_in)

    # Generate output file names.
    if n_new == 1:
        fns_out = [fn_out_template]
    else:
        fns_out = [fn_out_template.format(i) for i in range(n_new)]

    print("Contracting {:d} beads to {:d} beads.".format(n, n_new))
    print()

    print("input file names:")
    for fn in fns_in:
        print(fn)
    print()

    print("output file names:")
    for fn in fns_out:
        print(fn)
    print()

    # Open input trajectory iterators.
    trjs_in = [iter_file_name_raw(fn) for fn in fns_in]
    mode = os.path.splitext(fn)[-1]

    # Open output files.
    fs_out = [open_backup(fn, "w") for fn in fns_out]
    mode_out = os.path.splitext(fn_out_template)[-1]

    # prepare ring polymer rescaler
    rescale = nm_rescale(n, n_new)

    # Loop over all frames.
    i_frame = 0
    while True:
        try:
            # Get the frames for all beads.
            frames = [trj.next() for trj in trjs_in]
        except StopIteration:
            # Stop when any of the trajectories runs out of frames.
            break

        # gets units from first frame
        dimension, units, cell_units = auto_units(comment=frames[0]["comment"], cell_units=cell_units_in)
        if cell_units_out == "automatic": cell_units_out = cell_units  # re-use units unless otherwise specified

        # Consistency check.
        h = frames[0]["cell"]
        natoms = len(frames[0]["data"]) / 3
        for i in range(n):

            # Check that all the cells are the same.
            if (frames[i]["cell"] != h).any():
                msg = "Cell for beads {:d} and {:d} differ in frame {:d}."
                raise ValueError(msg.format(0, i, i_frame))

            # Check that the numbers of atoms are the same.
            if len(frames[i]["data"]) != 3 * natoms:
                msg = "Different numbers of atoms for beads {:d} and {:d} in frame {:d}."
                raise ValueError(msg.format(0, i, i_frame))

        cell = Cell()
        cell.h = frames[0]["cell"]
        atoms = Atoms(natoms)
        atoms.names = frames[0]["names"]

        # Compose the ring polymer.
        q = np.vstack([frame["data"] for frame in frames]) * unit_to_internal(dimension, units, 1)  # units transformation

        # Contract the coordinates to `n_new` beads.
        q_c = rescale.b1tob2(q)

        # Save the output data.
        for i, f_out in enumerate(fs_out):
            atoms.q = q_c[i, :]
            print_file(mode_out, atoms, cell, f_out, dimension=dimension, units=units, cell_units=cell_units_out)

        # Count frames and print information on progress.
        i_frame += 1
        if i_frame % 100 == 0:
            print("\rframe {:d}".format(i_frame), end="")
        sys.stdout.flush()

    for f_out in fs_out:
        f_out.close()

    print()
    print()
    print("Processed {:d} frames.".format(i_frame))
示例#12
0
def contract_trajectory(fns_in, fn_out_template, n_new, cell_units_in,
                        cell_units_out):

    verbosity.level = "low"
    n = len(fns_in)

    # Generate output file names.
    if n_new == 1:
        fns_out = [fn_out_template]
    else:
        fns_out = [fn_out_template.format(i) for i in range(n_new)]

    print("Contracting {:d} beads to {:d} beads.".format(n, n_new))
    print()

    print("input file names:")
    for fn in fns_in:
        print(fn)
    print()

    print("output file names:")
    for fn in fns_out:
        print(fn)
    print()

    # Open input trajectory iterators.
    trjs_in = [iter_file_name_raw(fn) for fn in fns_in]
    mode = os.path.splitext(fn)[-1]

    # Open output files.
    fs_out = [open_backup(fn, "w") for fn in fns_out]
    mode_out = os.path.splitext(fn_out_template)[-1]

    # prepare ring polymer rescaler
    rescale = nm_rescale(n, n_new)

    # Loop over all frames.
    i_frame = 0
    while True:
        try:
            # Get the frames for all beads.
            frames = [trj.next() for trj in trjs_in]
        except StopIteration:
            # Stop when any of the trajectories runs out of frames.
            break

        # gets units from first frame
        dimension, units, cell_units = auto_units(comment=frames[0]["comment"],
                                                  cell_units=cell_units_in)
        if cell_units_out == "automatic":
            cell_units_out = cell_units  # re-use units unless otherwise specified

        # Consistency check.
        h = frames[0]["cell"]
        natoms = len(frames[0]["data"]) / 3
        for i in range(n):

            # Check that all the cells are the same.
            if (frames[i]["cell"] != h).any():
                msg = "Cell for beads {:d} and {:d} differ in frame {:d}."
                raise ValueError(msg.format(0, i, i_frame))

            # Check that the numbers of atoms are the same.
            if len(frames[i]["data"]) != 3 * natoms:
                msg = "Different numbers of atoms for beads {:d} and {:d} in frame {:d}."
                raise ValueError(msg.format(0, i, i_frame))

        cell = Cell()
        cell.h = frames[0]["cell"]
        atoms = Atoms(natoms)
        atoms.names = frames[0]["names"]

        # Compose the ring polymer.
        q = np.vstack([frame["data"] for frame in frames]) * unit_to_internal(
            dimension, units, 1)  # units transformation

        # Contract the coordinates to `n_new` beads.
        q_c = rescale.b1tob2(q)

        # Save the output data.
        for i, f_out in enumerate(fs_out):
            atoms.q = q_c[i, :]
            print_file(mode_out,
                       atoms,
                       cell,
                       f_out,
                       dimension=dimension,
                       units=units,
                       cell_units=cell_units_out)

        # Count frames and print information on progress.
        i_frame += 1
        if i_frame % 100 == 0:
            print("\rframe {:d}".format(i_frame), end="")
        sys.stdout.flush()

    for f_out in fs_out:
        f_out.close()

    print()
    print()
    print("Processed {:d} frames.".format(i_frame))
示例#13
0
    def __init__(
        self,
        dt=None,
        temp=None,
        tau=None,
        ebaro=None,
        thermostat=None,
        stressext=None,
        h0=None,
        p=None,
        hfix=None,
    ):
        """Initializes RGB barostat.

        Args:
        dt: Optional float giving the time step for the algorithms. Defaults
        to the simulation dt.
        temp: Optional float giving the temperature for the thermostat.
        Defaults to the simulation temp.
        stressext: Optional float giving the external pressure.
        tau: Optional float giving the time scale associated with the barostat.
        ebaro: Optional float giving the conserved quantity already stored
        in the barostat initially. Used on restart.
        thermostat: The thermostat connected to the barostat degree of freedom.
        p: Optional initial volume conjugate momentum. Defaults to 0.
        """

        super(BaroRGB, self).__init__(dt, temp, tau, ebaro, thermostat)

        # non-zero elements of the cell momentum are only
        # pxx pyy pzz pxy pxz pyz, but we want to access it either as a
        # 6-vector or as a 3x3 upper triangular tensor.
        # we use a synchronizer to achieve that

        dself = dd(self)

        sync_baro = synchronizer()
        dself.p6 = depend_array(
            name="p6",
            value=np.zeros(6, float),
            synchro=sync_baro,
            func={"p": self.get_3x3to6},
        )
        dself.p = depend_array(
            name="p",
            value=np.zeros((3, 3), float),
            synchro=sync_baro,
            func={"p6": self.get_6to3x3},
        )

        if p is not None:
            self.p = p
        else:
            self.p = 0.0

        if h0 is not None:
            self.h0 = h0
        else:
            self.h0 = Cell()

        if hfix is None:
            hfix = []
        self.hfix = hfix

        hmask = mask_from_fix(self.hfix)

        # mask to zero out components of the cell velocity, to implement cell-boundary constraints
        dself.hmask = depend_array(name="hmask", value=hmask)
        # number of ones in the UT part of the mask
        self.L = np.diag(
            [hmask[0].sum(), hmask[1, 1:].sum(), hmask[2, 2:].sum()])

        if stressext is not None:
            self.stressext = stressext
        else:
            self.stressext[:] = -1.0