Exemplo n.º 1
0
def test_gratoms():
    edges = [(0, 1), (0, 2)]
    atoms = Gratoms(edges=edges)

    for n in atoms.edges:
        assert (n in edges)

    mol = molecule('H2O')
    atoms = to_gratoms(mol)
    atoms.graph.add_edges_from([(0, 1), (0, 2)])

    sym_test = atoms.get_neighbor_symbols(0)
    assert (sym_test.tolist() == ['H', 'H'])

    test_tags = atoms.get_chemical_tags(rank=1)
    assert (test_tags == '2,0,0,0,0,0,0,1')

    test_comp, test_bonds = atoms.get_chemical_tags()
    assert (test_comp == '2,0,0,0,0,0,0,1')
    assert (test_bonds == '4,0,0,0,0,0,0,3')

    atoms.set_constraint(FixAtoms(indices=[0]))
    del atoms[2]
    assert (len(atoms) == 2)

    nx.set_node_attributes(atoms.graph, name='valence', values={0: 1, 1: 0})

    test_nodes = atoms.get_unsaturated_nodes(screen=1)
    assert (test_nodes == [0])
Exemplo n.º 2
0
def to_gratoms(atoms):
    """Convert and atom object to a gratoms object."""
    gratoms = Gratoms(numbers=atoms.numbers,
                      positions=atoms.positions,
                      pbc=atoms.pbc,
                      cell=atoms.cell)

    if atoms.constraints:
        gratoms.set_constraint(atoms.constraints)

    return gratoms
Exemplo n.º 3
0
    def get_slab(self, size=(1, 1), root=None, iterm=None, primitive=False):
        """Generate a slab object with a certain number of layers.

        Parameters
        ----------
        size : tuple (2,)
            Repeat the x and y lattice vectors by the indicated
            dimensions
        root : int
            Produce a slab with a primitive a1 basis vector multiplied
            by the square root of a provided value. Uses primitive unit cell.
        iterm : int
            A termination index in reference to the list of possible
            terminations.
        primitive : bool
            Whether to reduce the unit cell to its primitive form.

        Returns
        -------
        slab : atoms object
            The modified basis slab produced based on the layer specifications
            given.
        """
        slab = self._basis.copy()

        if iterm:
            if self.unique_terminations is None:
                terminations = self.get_unique_terminations()
            else:
                terminations = self.unique_terminations
            zshift = terminations[iterm]

            slab.translate([0, 0, -zshift])
            slab.wrap(pbc=True)

        # Get the minimum number of layers needed
        zlayers = utils.get_unique_coordinates(slab,
                                               direct=False,
                                               tol=self.tol)

        if self.min_width:
            width = slab.cell[2][2]
            z_repetitions = np.ceil(width / len(zlayers) * self.min_width)
        else:
            z_repetitions = np.ceil(self.layers / len(zlayers))

        slab *= (1, 1, int(z_repetitions))

        if primitive or root:
            if self.vacuum:
                slab.center(vacuum=self.vacuum, axis=2)
            else:
                raise ValueError('Primitive slab generation requires vacuum')

            nslab = utils.get_primitive_cell(slab)

            if nslab is not None:
                slab = nslab

                # spglib occasionally returns a split slab
                zpos = slab.get_scaled_positions()
                if zpos[:, 2].max() > 0.9 or zpos[:, 2].min() < 0.1:
                    zpos[:, 2] -= 0.5
                    zpos[:, 2] %= 1
                    slab.set_scaled_positions(zpos)
                    slab.center(vacuum=self.vacuum, axis=2)

                # For hcp(1, 1, 0), primitive alters z-axis
                d = norm(slab.cell, axis=0)
                maxd = np.argwhere(d == d.max())[0][0]
                if maxd != 2:
                    slab.rotate(slab.cell[maxd], 'z', rotate_cell=True)
                    slab.cell[[maxd, 2]] = slab.cell[[2, maxd]]
                    slab.cell[maxd] = -slab.cell[maxd]
                    slab.wrap(pbc=True)

                slab.rotate(slab.cell[0], 'x', rotate_cell=True)

        # Orthogonalize the z-coordinate
        # Warning: bulk symmetry is lost at this point
        a, b, c = slab.cell
        nab = np.cross(a, b)
        c = (nab * np.dot(c, nab) / norm(nab)**2)
        slab.cell[2] = c

        # Align the longest remaining basis vector with x
        vdist = norm(slab.cell[:2], axis=1)
        if vdist[1] > vdist[0]:
            slab.rotate(slab.cell[1], 'x', rotate_cell=True)
            slab.cell[0] *= -1
            slab.cell[[0, 1]] = slab.cell[[1, 0]]

        # Enforce that the angle between basis vectors is acute.
        if slab.cell[1][0] < 0:
            slab.rotate(slab.cell[2], '-z')
            slab.cell *= [[1, 0, 0], [-1, 1, 0], [0, 0, 1]]

        if root:
            roots, vectors = root_surface_analysis(slab, return_vectors=True)

            if root not in roots:
                raise ValueError(
                    'Requested root structure unavailable for this system.'
                    'Try: {}'.format(roots))

            vect = vectors[np.where(root == roots)][0]
            slab = self.root_surface(slab, root, vect)

        # Get the direct z-coordinate of the requested layer
        zlayers = utils.get_unique_coordinates(slab,
                                               direct=False,
                                               tag=True,
                                               tol=self.tol)

        if not self.fix_stoichiometry:
            reverse_sort = np.sort(zlayers)[::-1]

            if self.min_width:
                n = np.where(zlayers < self.min_width, 1, 0).sum()
                ncut = reverse_sort[n]
            else:
                ncut = reverse_sort[:self.layers][-1]

            zpos = slab.positions[:, 2]
            index = np.arange(len(slab))
            del slab[index[zpos - ncut < -self.tol]]

            slab.cell[2][2] -= ncut
            slab.translate([0, 0, -ncut])

        slab *= (size[0], size[1], 1)
        tags = slab.get_tags()

        m = np.where(tags == 1)[0][0]
        translation = slab[m].position.copy()
        translation[2] = 0
        slab.translate(-translation)
        slab.wrap()

        ind = np.lexsort(
            (slab.positions[:, 0], slab.positions[:, 1], slab.positions[:, 2]))

        slab = Gratoms(positions=slab.positions[ind],
                       numbers=slab.numbers[ind],
                       cell=slab.cell,
                       pbc=[1, 1, 0],
                       tags=tags[ind])

        fix = tags.max() - self.fixed
        constraints = FixAtoms(indices=[a.index for a in slab if a.tag > fix])
        slab.set_constraint(constraints)

        if self.vacuum:
            slab.center(vacuum=self.vacuum, axis=2)

        self.slab = slab

        return slab