def hash_derivative_site( self, dsite: DerivativeSite, return_image: bool = False ) -> Union[CanonicalSite, Tuple[CanonicalSite, np.ndarray]]: """ Returns ------- csite: CanoncalSite derivative_jimage: (Optional), array self.get_frac_coords(dsite) == self.displacement_set[dsite.site_index] + np.dot(self.left_inv, csite.factor) + np.dot(self.hnf, derivative_jimage) """ site_index, jimage = dsite.site_index, dsite.jimage factor_tmp = np.dot(self.left, np.array(jimage, dtype=int)) factor = np.mod(factor_tmp, np.array(self.invariant_factors)) csite = CanonicalSite(site_index, tuple(factor)) if return_image: derivative_jimage = cast_integer_matrix(factor_tmp - factor) / np.array( self.invariant_factors) derivative_jimage = cast_integer_matrix(derivative_jimage) derivative_jimage = np.dot(self.right, derivative_jimage).astype(int) return csite, derivative_jimage else: return csite
def hash_frac_coords(self, frac_coord: np.ndarray) -> Optional[CanonicalSite]: for site_index, fc in enumerate(self.displacement_set): jimage = cast_integer_matrix(frac_coord - fc) if np.allclose(fc + jimage, frac_coord): dsite = DerivativeSite(site_index, jimage) csite = cast(CanonicalSite, self.hash_derivative_site(dsite)) return csite return None
def is_same_lattice(H1: np.ndarray, H2: np.ndarray) -> bool: M = np.linalg.solve(H1, H2) M_int = cast_integer_matrix(M) if np.array_equal(np.dot(H1, M_int), H2): assert is_unimodular(M_int) return True else: return False
def get_lattice_points(self) -> List[np.ndarray]: """ return list of lattice points with the supercell Note that the returned lattice points are not guaranteed to be "within" the supercell """ lattice_points = [] for factor in self.get_all_factors(): lp = cast_integer_matrix(np.dot(self.left_inv, factor)) lattice_points.append(lp) return lattice_points
def __init__(self, hnf: np.ndarray, displacement_set: np.ndarray): self._hnf = hnf self._index = np.around(np.abs(np.linalg.det(self.hnf))).astype(int) assert self.index != 0 self.displacement_set = displacement_set assert self.dim == self.displacement_set.shape[1] self.num_site_base = len(displacement_set) D, L, R = smith_normal_form(self.hnf) self.snf = D self.left = L self.right = R self.left_inv = cast_integer_matrix(np.linalg.inv(self.left)) self.invariant_factors = tuple(self.snf.diagonal()) self.shape = (self.num_site_base, ) + self.invariant_factors
def _get_dsite(self, frac_coord: np.ndarray) -> DerivativeSite: """ return DerivativeSite from fractional coorinates Parameters ---------- frac_coords: (dim, ) Returns ------- dsite: DerivativeSite """ for site_index, fc in enumerate(self.frac_coords): jimage = cast_integer_matrix(frac_coord - fc) if np.allclose(fc + jimage, frac_coord): dsite = DerivativeSite(site_index, tuple(jimage.tolist())) return dsite raise ValueError(f"invalid fractional coordinates: {frac_coord}")
def embed_to_derivative_site(self, csite: CanonicalSite) -> DerivativeSite: jimage_base = cast_integer_matrix(np.dot(self.left_inv, csite.factor)) dsite = DerivativeSite(csite.site_index, tuple(jimage_base.tolist())) return dsite
def test_cast_integer_matrix(): arr = np.array([1.0, 2.0001, 2.9999, -0.9999, -2.0001]) arr_rounded = np.array([1.0, 2.0, 3.0, -1.0, -2.0]) assert np.allclose(cast_integer_matrix(arr), arr_rounded)