def _unique_coords(self, coords_in, magmoms_in=None): """ Generate unique coordinates using coord and symmetry positions and also their corresponding magnetic moments, if supplied. """ coords = [] if magmoms_in: magmoms = [] magmoms_in = [Magmom(magmom) for magmom in magmoms_in] if len(magmoms_in) != len(coords_in): raise ValueError for tmp_coord, tmp_magmom in zip(coords_in, magmoms_in): 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): magmom = Magmom(op.operate_magmom(tmp_magmom.moment)) else: magmom = tmp_magmom if not in_coord_list_pbc( coords, coord, atol=self._site_tolerance): coords.append(coord) magmoms.append(magmom) return coords, magmoms else: for tmp_coord in coords_in: 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) return coords, [Magmom(0)] * len(coords) # return dummy magmoms
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(in_coord_list_pbc(coords, test_coord)) self.assertTrue(in_coord_list_pbc(coords, test_coord, atol=0.15)) test_coord = [0.99, 0.99, 0.99] self.assertFalse(in_coord_list_pbc(coords, test_coord, atol=0.01))
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 = [ cart_to_frac(self.slab.lattice, 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 [ frac_to_cart(self.slab.lattice, coords) for coords in unique_coords ]
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 = [cart_to_frac(self.slab.lattice, 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 [frac_to_cart(self.slab.lattice, coords) for coords in unique_coords]
def get_kpoint_weights(self, kpoints, atol=1e-8): """ Calculate the weights for a list of kpoints. Args: kpoints (Sequence): Sequence of kpoints. np.arrays is fine. Note that the code does not check that the list of kpoints provided does not contain duplicates. atol (float): Tolerance for fractional coordinates comparisons. Returns: List of weights, in the SAME order as kpoints. """ latt = self._structure.lattice.reciprocal_lattice grid = Structure(latt, ["H"], [[0, 0, 0]]) a = SpacegroupAnalyzer(grid) recp_ops = a.get_symmetry_operations() weights = [] for k in kpoints: all_k = [] for o in recp_ops: k2 = o.operate(k) if not in_coord_list_pbc(all_k, k2, atol=atol): all_k.append(k2) weights.append(len(all_k)) return weights
def _unique_coords(self, coord_in): """ Generate unique coordinates using coord and symmetry positions. """ coords = [] for op in self.symmetry_operations: coord = op.operate(coord_in) coord = np.array([i - math.floor(i) for i in coord]) if not in_coord_list_pbc(coords, coord, atol=1e-3): coords.append(coord) return coords
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 = [cart_to_frac(self.slab.lattice, 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 [frac_to_cart(self.slab.lattice, coords) for coords in unique_coords]
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
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 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 = 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