예제 #1
0
 def test_in_coord_list_pbc(self):
     coords = [[0, 0, 0], [0.5, 0.5, 0.5]]
     test_coord = [0.1, 0.1, 0.1]
     self.assertFalse(coord.in_coord_list_pbc(coords, test_coord))
     self.assertTrue(coord.in_coord_list_pbc(coords, test_coord, atol=0.15))
     test_coord = [0.99, 0.99, 0.99]
     self.assertFalse(coord.in_coord_list_pbc(coords, test_coord, atol=0.01))
예제 #2
0
    def symm_reduce(self, coords_set, threshold=1e-6):
        """
        Reduces the set of adsorbate sites by finding removing
        symmetrically equivalent duplicates

        Args:
            coords_set: coordinate set in cartesian coordinates
            threshold: tolerance for distance equivalence, used
                as input to in_coord_list_pbc for dupl. checking
        """
        surf_sg = SpacegroupAnalyzer(self.slab, 0.1)
        symm_ops = surf_sg.get_symmetry_operations()
        unique_coords = []
        # Convert to fractional
        coords_set = [
            self.slab.lattice.get_fractional_coords(coords)
            for coords in coords_set
        ]
        for coords in coords_set:
            incoord = False
            for op in symm_ops:
                if in_coord_list_pbc(unique_coords,
                                     op.operate(coords),
                                     atol=threshold):
                    incoord = True
                    break
            if not incoord:
                unique_coords += [coords]
        # convert back to cartesian
        return [
            self.slab.lattice.get_cartesian_coords(coords)
            for coords in unique_coords
        ]
예제 #3
0
    def symm_reduce(self, coords_set, threshold=1e-6):
        """
        Reduces the set of adsorbate sites by finding removing
        symmetrically equivalent duplicates

        Args:
            coords_set: coordinate set in cartesian coordinates
            threshold: tolerance for distance equivalence, used
                as input to in_coord_list_pbc for dupl. checking
        """
        surf_sg = SpacegroupAnalyzer(self.slab, 0.1)
        symm_ops = surf_sg.get_symmetry_operations()
        unique_coords = []
        # Convert to fractional
        coords_set = [self.slab.lattice.get_fractional_coords(coords)
                      for coords in coords_set]
        for coords in coords_set:
            incoord = False
            for op in symm_ops:
                if in_coord_list_pbc(unique_coords, op.operate(coords),
                                     atol=threshold):
                    incoord = True
                    break
            if not incoord:
                unique_coords += [coords]
        # convert back to cartesian
        return [self.slab.lattice.get_cartesian_coords(coords)
                for coords in unique_coords]
예제 #4
0
    def _unique_coords(self, coords_in, magmoms_in=None, lattice=None):
        """
        Generate unique coordinates using coord and symmetry positions
        and also their corresponding magnetic moments, if supplied.
        """
        coords = []
        coords_num = []

        if magmoms_in:
            magmoms = []
            if len(magmoms_in) != len(coords_in):
                raise ValueError
            for tmp_coord, tmp_magmom in zip(coords_in, magmoms_in):
                count = 0
                for op in self.symmetry_operations:
                    coord = op.operate(tmp_coord)
                    coord = np.array([i - math.floor(i) for i in coord])
                    if isinstance(op, MagSymmOp):
                        # Up to this point, magmoms have been defined relative
                        # to crystal axis. Now convert to Cartesian and into
                        # a Magmom object.
                        magmom = Magmom.from_moment_relative_to_crystal_axes(
                            op.operate_magmom(tmp_magmom), lattice=lattice)
                    else:
                        magmom = Magmom(tmp_magmom)
                    if not in_coord_list_pbc(
                            coords, coord, atol=self._site_tolerance):
                        coords.append(coord)
                        magmoms.append(magmom)
                        count = count + 1
                coords_num.append(count)
            return coords, magmoms, coords_num
        else:
            for tmp_coord in coords_in:
                count = 0
                for op in self.symmetry_operations:
                    coord = op.operate(tmp_coord)
                    coord = np.array([i - math.floor(i) for i in coord])
                    if not in_coord_list_pbc(
                            coords, coord, atol=self._site_tolerance):
                        coords.append(coord)
                        count = count + 1
                coords_num.append(count)
            return coords, [Magmom(0)
                            ] * len(coords), coords_num  # return dummy magmoms
예제 #5
0
    def find_surface_sites_by_height(self,
                                     slab,
                                     height=0.9,
                                     xy_tol=0.05,
                                     bottom=False):
        """
        This method finds surface sites by determining which sites are within
        a threshold value in height from the topmost site in a list of sites

        Args:
            site_list (list): list of sites from which to select surface sites
            height (float): threshold in angstroms of distance from topmost
                site in slab along the slab c-vector to include in surface
                site determination
            xy_tol (float): if supplied, will remove any sites which are
                within a certain distance in the miller plane.
            bottom (bool): if True, identifies surface sites on the bottom of 
                the slab as well as the top

        Returns:
            list of sites selected to be within a threshold of the highest
            (and lowest if bottom=True)
        """

        # Get projection of coordinates along the miller index
        m_projs = np.array(
            [np.dot(site.coords, self.mvec) for site in slab.sites])

        # Mask based on window threshold along the miller index.
        if bottom:
            bot_mask = (m_projs - np.amin(m_projs)) <= height
            top_mask = (m_projs - np.amax(m_projs)) >= -height
            mask = [any(x) for x in zip(bot_mask, top_mask)]
        else:
            mask = (m_projs - np.amax(m_projs)) >= -height
        surf_sites = [slab.sites[n] for n in np.where(mask)[0]]
        if xy_tol:
            # sort surface sites by height
            surf_sites = [s for (h, s) in zip(m_projs[mask], surf_sites)]
            surf_sites.reverse()
            unique_sites, unique_perp_fracs = [], []
            for site in surf_sites:
                this_perp = site.coords - np.dot(site.coords, self.mvec)
                this_perp_frac = slab.lattice.get_fractional_coords(this_perp)
                if not in_coord_list_pbc(unique_perp_fracs, this_perp_frac):
                    unique_sites.append(site)
                    unique_perp_fracs.append(this_perp_frac)
            surf_sites = unique_sites

        return surf_sites
예제 #6
0
    def near_reduce(self, coords_set, threshold=1e-4):
        """
        Prunes coordinate set for coordinates that are within
        threshold

        Args:
            coords_set (Nx3 array-like): list or array of coordinates
            threshold (float): threshold value for distance
        """
        unique_coords = []
        coords_set = [self.slab.lattice.get_fractional_coords(coords) for coords in coords_set]
        for coord in coords_set:
            if not in_coord_list_pbc(unique_coords, coord, threshold):
                unique_coords += [coord]
        return [self.slab.lattice.get_cartesian_coords(coords) for coords in unique_coords]
예제 #7
0
    def near_reduce(self, coords_set, threshold=1e-4):
        """
        Prunes coordinate set for coordinates that are within
        threshold

        Args:
            coords_set (Nx3 array-like): list or array of coordinates
            threshold (float): threshold value for distance
        """
        unique_coords = []
        coords_set = [self.slab.lattice.get_fractional_coords(coords)
                      for coords in coords_set]
        for coord in coords_set:
            if not in_coord_list_pbc(unique_coords, coord, threshold):
                unique_coords += [coord]
        return [self.slab.lattice.get_cartesian_coords(coords)
                for coords in unique_coords]
예제 #8
0
    def find_surface_sites_by_height(self, slab, height=0.9, xy_tol=0.05):
        """
        This method finds surface sites by determining which sites are within
        a threshold value in height from the topmost site in a list of sites

        Args:
            site_list (list): list of sites from which to select surface sites
            height (float): threshold in angstroms of distance from topmost
                site in slab along the slab c-vector to include in surface
                site determination
            xy_tol (float): if supplied, will remove any sites which are
                within a certain distance in the miller plane.

        Returns:
            list of sites selected to be within a threshold of the highest
        """

        # Get projection of coordinates along the miller index
        m_projs = np.array([np.dot(site.coords, self.mvec)
                            for site in slab.sites])

        # Mask based on window threshold along the miller index.
        topmask = (m_projs - np.amax(m_projs)) >= -height
        bottommask = (np.min(m_projs) - m_projs) >= -height
        mask = topmask if self.top_surface else bottommask

        surf_sites = [slab.sites[n] for n in np.where(mask)[0]]
        if xy_tol:
            # sort surface sites by height
            surf_sites = [s for (h, s) in zip(m_projs[mask], surf_sites)]
            surf_sites.reverse()
            unique_sites, unique_perp_fracs = [], []
            for site in surf_sites:
                this_perp = site.coords - np.dot(site.coords, self.mvec)
                this_perp_frac = cart_to_frac(slab.lattice, this_perp)
                if not in_coord_list_pbc(unique_perp_fracs, this_perp_frac):
                    unique_sites.append(site)
                    unique_perp_fracs.append(this_perp_frac)
            surf_sites = unique_sites

        return surf_sites