def test_converter(transformation, frac_coords): converter = DerivativeMultiLatticeHash(transformation, frac_coords) index = converter.index num_sites = converter.num_sites all_factors = converter.get_all_factors() assert len({tuple(f) for f in all_factors}) == index all_lattice_points = converter.get_lattice_points() assert len({tuple(f) for f in all_lattice_points}) == index all_periodic_sites = converter.get_canonical_sites_list() assert len(set(all_periodic_sites)) == num_sites all_dsites = converter.get_distinct_derivative_sites_list() for dsite in all_dsites: csite, derivative_jimage = converter.hash_derivative_site(dsite, return_image=True) fcoords1 = converter.get_frac_coords(dsite) fcoords2 = ( converter.displacement_set[dsite.site_index] + np.dot(converter.left_inv, csite.factor) + np.dot(converter.hnf, derivative_jimage) ) assert np.allclose(fcoords1, fcoords2) for csite in all_periodic_sites: ind = converter.ravel_canonical_site(csite) csite2 = converter.unravel_to_canonical_site(ind) assert csite2 == csite
def test_converter(): list_transformations = [ np.diag((2, 2, 2)), np.array([[-1, 1, 1], [1, -1, 1], [1, 1, -1]]), np.array([[-1, 1, 1], [1, -1, 1], [-1, -1, 1]]), # negative determinat ] list_frac_coords = [ np.array([[0, 0, 0]]), np.array([[0, 0, 0], [0.5, 0.5, 0.5]]) ] for transformation in list_transformations: for frac_coords in list_frac_coords: converter = DerivativeMultiLatticeHash(transformation, frac_coords) index = converter.index num_sites = converter.num_sites all_factors = converter.get_all_factors() assert len(set([tuple((f)) for f in all_factors])) == index all_lattice_points = converter.get_lattice_points() assert len(set([tuple(f) for f in all_lattice_points])) == index all_periodic_sites = converter.get_canonical_sites_list() assert len(set(all_periodic_sites)) == num_sites all_dsites = converter.get_distinct_derivative_sites_list() for dsite in all_dsites: csite, derivative_jimage = converter.hash_derivative_site( dsite, return_image=True) fcoords1 = converter.get_frac_coords(dsite) fcoords2 = (converter.displacement_set[dsite.site_index] + np.dot(converter.left_inv, csite.factor) + np.dot(converter.hnf, derivative_jimage)) assert np.allclose(fcoords1, fcoords2) for csite in all_periodic_sites: ind = converter.ravel_canonical_site(csite) csite2 = converter.unravel_to_canonical_site(ind) assert csite2 == csite
def __init__( self, hnf: np.ndarray, displacement_set: np.ndarray, rotations: np.ndarray, translations: np.ndarray, ): self.hnf = hnf self.num_sites_base = len(displacement_set) # TODO: check each site in displacement_set is in [0, 1)^dim self.displacement_set = displacement_set self.dhash = DerivativeMultiLatticeHash(self.hnf, self.displacement_set) self.rotations, self.translations = self._get_superlattice_invariant_subgroup( rotations, translations ) self.list_dsites = self.dhash.get_distinct_derivative_sites_list() self.list_csites = self.dhash.get_canonical_sites_list() self._prm_t = self._get_translation_permutations() self.prm_rigid = self._get_rigid_permutations()
def from_structure(cls, structure: Structure, transformation: np.ndarray, symprec: float = 1e-2): """ create EquivalentPointClusterGenerator from pymatgen.core.Structure Parameters ---------- structure: pymatgen.core.Structure, base structure transformation: transformation matrix of sublattice symprec: float """ frac_coords = structure.frac_coords rotations, translations = get_symmetry_operations(structure, symprec) converter = DerivativeMultiLatticeHash(transformation, frac_coords) return cls( frac_coords=frac_coords, rotations=rotations, translations=translations, converter=converter, )
class DerivativeStructurePermutation: """ Permutation Representation of space group of superlattice Parameters ---------- hnf: array, (dim, dim) Hermite normal form(lower triangular) displacement_set: array, (num_site_parent, dim) fractinal coordinates in primitive cell of base structure rotations: array, (# of symmetry operations, dim, dim) rotations with primitive basis for base structure translations: array, (# of symmetry operations, dim) translations with primitive basis for base structure Attributes ---------- dim : int dimention of lattice index: int # of parent multilattice in super lattice num_site: int # of sites in unit cell of superlattice """ def __init__( self, hnf: np.ndarray, displacement_set: np.ndarray, rotations: np.ndarray, translations: np.ndarray, ): self.hnf = hnf self.num_sites_base = len(displacement_set) # TODO: check each site in displacement_set is in [0, 1)^dim self.displacement_set = displacement_set self.dhash = DerivativeMultiLatticeHash(self.hnf, self.displacement_set) self.rotations, self.translations = self._get_superlattice_invariant_subgroup( rotations, translations ) self.list_dsites = self.dhash.get_distinct_derivative_sites_list() self.list_csites = self.dhash.get_canonical_sites_list() self._prm_t = self._get_translation_permutations() self.prm_rigid = self._get_rigid_permutations() @property def dim(self): return self.dhash.dim @property def index(self): return self.dhash.index @property def num_sites(self): return self.dhash.num_sites @property def prm_t(self): return self._prm_t def _get_superlattice_invariant_subgroup( self, rotations: np.ndarray, translations: np.ndarray ): valid_rotations = [] valid_translations = [] for R, tau in zip(rotations, translations): if not is_same_lattice(np.dot(R, self.hnf), self.hnf): continue valid_rotations.append(R) valid_translations.append(tau) assert len(rotations) % len(valid_rotations) == 0 return np.array(valid_rotations), np.array(valid_translations) def _get_translation_permutations(self): list_permutations = [] for add_factor in self.dhash.get_all_factors(): new_list_csites = [] for csite in self.list_csites: new_factor = self.dhash.modulus_factor( np.array(csite.factor) + np.array(add_factor) ) new_csite = CanonicalSite(csite.site_index, new_factor) new_list_csites.append(new_csite) # permutation represenation perm = [self.dhash.ravel_canonical_site(csite) for csite in new_list_csites] assert is_permutation(perm) list_permutations.append(perm) # assume list_permutations[0] is identity assert is_identity_permutation(list_permutations[0]) return list_permutations def _get_rigid_permutations(self): identity = list(range(self.num_sites)) list_permutations = [ identity, ] for R, tau in zip(self.rotations, self.translations): new_list_csites = [] for dsite in self.list_dsites: frac_coord = self.displacement_set[dsite.site_index] + np.array(dsite.jimage) acted_frac_coord = np.dot(R, frac_coord) + tau new_csite = self.dhash.hash_frac_coords(acted_frac_coord) assert new_csite is not None new_list_csites.append(new_csite) perm = [self.dhash.ravel_canonical_site(csite) for csite in new_list_csites] assert is_permutation(perm) if perm not in list_permutations: list_permutations.append(perm) # this set of permutations is not group! return list_permutations def get_symmetry_operation_permutations(self): """ return permutation representation of the symmetry group of the supercell """ list_permutations = [] for p1 in self.prm_t: for p2 in self.prm_rigid: perm = product_permutations(p1, p2) assert perm not in list_permutations list_permutations.append(perm) # assume list_permutations[0] is identity assert is_identity_permutation(list_permutations[0]) return list_permutations
def __init__( self, base_structure: Structure, dshash: DerivativeMultiLatticeHash, mapping_color_to_species: List[Union[str, Element, Specie, DummySpecie]], additional_species=None, additional_frac_coords=None, ): """ Parameters ---------- base_structure: Structure with only ordering species dshash: mapping_color_to_species: additional_species: list of pymatgen.core.Species, optional species which are nothing to do with ordering additional_frac_coords: np.ndarray, optional fractional coordinates of species which are nothing to do with ordering """ self.base_structure = base_structure self.dshash = dshash self.mapping_color_to_species = mapping_color_to_species self.lattice_matrix = np.dot(self.base_matrix.T, self.dshash.hnf).T # lattice of derivative structure self.lattice = Lattice(self.lattice_matrix) self.canonical_derivative_sites = dshash.get_canonical_and_derivative_sites_list( ) list_coords = [] for _, dsite in self.canonical_derivative_sites: coords = dshash.get_frac_coords(dsite) cart_coords = np.dot(coords, self.base_matrix) list_coords.append(cart_coords) self.list_coords = list_coords self.precomputed_psites = [[ PeriodicSite(sp, coords, self.lattice, coords_are_cartesian=True) for sp in self.mapping_color_to_species ] for coords in self.list_coords] # additional fixed sites self.additional_species = additional_species self.additional_frac_coords = additional_frac_coords if self.additional_species is not None: assert len(self.additional_species) == len( self.additional_frac_coords) self.additional_psites = [] if self.additional_species is not None: lattice_points = self.dshash.get_lattice_points() for sp, disp in zip(self.additional_species, self.additional_frac_coords): cart_coords = [ np.dot(np.array(disp) + np.array(lp), self.base_matrix) for lp in lattice_points ] self.additional_psites.extend([ PeriodicSite(sp, coords, self.lattice, coords_are_cartesian=True) for coords in cart_coords ])