def test_subgroup_supergroup(self): with warnings.catch_warnings() as w: warnings.simplefilter("ignore") self.assertTrue(SpaceGroup("Pma2").is_subgroup(SpaceGroup("Pccm"))) self.assertFalse( SpaceGroup.from_int_number(229).is_subgroup( SpaceGroup.from_int_number(230)))
def test_get_slab(self): s = self.get_structure("LiFePO4") gen = SlabGenerator(s, [0, 0, 1], 10, 10) s = gen.get_slab(0.25) self.assertAlmostEqual(s.lattice.abc[2], 20.820740000000001) fcc = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3), ["Fe"], [[0, 0, 0]]) gen = SlabGenerator(fcc, [1, 1, 1], 10, 10) slab = gen.get_slab() gen = SlabGenerator(fcc, [1, 1, 1], 10, 10, primitive=False) slab_non_prim = gen.get_slab() self.assertEqual(len(slab), 6) self.assertEqual(len(slab_non_prim), len(slab) * 4) #Some randomized testing of cell vectors for i in range(1, 231): i = random.randint(1, 230) sg = SpaceGroup.from_int_number(i) if sg.crystal_system == "hexagonal" or (sg.crystal_system == \ "trigonal" and sg.symbol.endswith("H")): latt = Lattice.hexagonal(5, 10) else: #Cubic lattice is compatible with all other space groups. latt = Lattice.cubic(5) s = Structure.from_spacegroup(i, latt, ["H"], [[0, 0, 0]]) miller = (0, 0, 0) while miller == (0, 0, 0): miller = (random.randint(0, 6), random.randint(0, 6), random.randint(0, 6)) gen = SlabGenerator(s, miller, 10, 10) a, b, c = gen.oriented_unit_cell.lattice.matrix self.assertAlmostEqual(np.dot(a, gen._normal), 0) self.assertAlmostEqual(np.dot(b, gen._normal), 0)
def test_point_group_is_set(self): for i in range(1, 231): sg = SpaceGroup.from_int_number(i) self.assertTrue(hasattr(sg, "point_group")) for symbol in _get_symm_data("space_group_encoding"): sg = SpaceGroup(symbol) self.assertTrue(hasattr(sg, "point_group"))
def __init__(self, input_spins = None, npoints=None, space_group = None, angle_range = None): """ Set of unit vector representing the orientation of spin magnetic moments. :param npoints: number of spin vectors [int] :param space_group: space group of material system [int] :param angle_range: angular range of vectors to compute [list or ndarray] ([[phi_min, phi_max], [theta_min, theta_max]]) """ def generate_semi_spin_axes_h(npoints, thet_min, thet_max, phi_min, phi_max): u = np.arange(0,1.0,1/int(np.sqrt(npoints))) thet = (thet_max - thet_min)*(u + thet_min) phi = arccos((cos(phi_max) - cos(phi_min))*u + cos(phi_min)) thetas, phis = np.meshgrid(thet, phi, sparse=False, indexing='xy') x, y, z = cos(thetas) * sin(phis), sin(thetas) * sin(phis), cos(phis) return np.array([x.flatten(),y.flatten(),z.flatten()]), np.array([thetas, phis]) if npoints: assert type(npoints) is int ##change to isinstance self._npoints = npoints if space_group: try: i = int(space_group) sg_obj = SpaceGroup.from_int_number(i) except ValueError: sg_obj = SpaceGroup(space_group) self._crystal_type = sg_obj.crystal_system if self._crystal_type is "triclinic": self._angle_range = np.array([[0, np.pi],[0, 2*np.pi]]) elif self._crystal_type is "monoclinic": self._angle_range = np.array([[0, np.pi],[0, 2*np.pi]]) elif self._crystal_type is "orthorhombic": self._angle_range = np.array([[0, np.pi],[0, np.pi]]) elif self._crystal_type is "tetragonal": self._angle_range = np.array([[0, np.pi],[0, np.pi/2]]) elif self._crystal_type is "trigonal": self._angle_range = np.array([[0, np.pi],[0, 2*np.pi]]) elif self._crystal_type is "hexagonal": self._angle_range = np.array([[0, np.pi],[0, 2*np.pi/3]]) else: self._angle_range = np.array([[0, np.pi/2],[0, np.pi/2]]) else: self._angle_range = np.array([[0, np.pi],[0, 2*np.pi]]) thet_min = self._angle_range[1][0] thet_max = self._angle_range[1][1] phi_min = self._angle_range[0][0] phi_max = self._angle_range[0][1] self._spin_axes, angle_list = generate_semi_spin_axes_h(npoints, thet_min, thet_max, phi_min, phi_max) self._spher_coords = [angle_list[0], angle_list[1], np.ones(npoints)] elif input_spins: ## Add assertions self._spin_axes = np.array(input_spins) self._spher_coords = None
def test_renamed_e_symbols(self): sg = SpaceGroup.from_int_number(64) assert sg.symbol == "Cmce" for sym, num in ( ("Aem2", 39), ("Aea2", 41), ("Cmce", 64), ("Cmme", 67), ("Ccce", 68), ): assert SpaceGroup(sym).int_number == num
def test_is_compatible(self): cubic = Lattice.cubic(1) hexagonal = Lattice.hexagonal(1, 2) rhom = Lattice.rhombohedral(3, 80) tet = Lattice.tetragonal(1, 2) ortho = Lattice.orthorhombic(1, 2, 3) sg = SpaceGroup("Fm-3m") self.assertTrue(sg.is_compatible(cubic)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("R-3m:H") self.assertFalse(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(hexagonal)) sg = SpaceGroup("R-3m:R") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("Pnma") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("P12/c1") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup("P-1") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertTrue(sg.is_compatible(rhom)) self.assertTrue(sg.is_compatible(hexagonal)) sg = SpaceGroup("Pmmn:2") self.assertTrue(sg.is_compatible(cubic)) self.assertTrue(sg.is_compatible(tet)) self.assertTrue(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertFalse(sg.is_compatible(hexagonal)) sg = SpaceGroup.from_int_number(165) self.assertFalse(sg.is_compatible(cubic)) self.assertFalse(sg.is_compatible(tet)) self.assertFalse(sg.is_compatible(ortho)) self.assertFalse(sg.is_compatible(rhom)) self.assertTrue(sg.is_compatible(hexagonal))
def _get_space_group_object(spg, mode): from pymatgen.symmetry.groups import SpaceGroup if spg and mode != 'bradcrack': logging.error("ERROR: Specifying symmetry only supported using " "Bradley and Cracknell path.") sys.exit() elif spg: try: if isinstance(spg, int): spg = SpaceGroup.from_int_number(spg) else: spg = SpaceGroup(spg) logging.error("WARNING: Forcing space group not recommended, the " "path is likely\nincorrect. Use at your own risk.\n") except ValueError: logging.error("ERROR: Space group not recognised.") sys.exit() return spg
def get_symops(self, data): """ In order to generate symmetry equivalent positions, the symmetry operations are parsed. If the symops are not present, the space group symbol is parsed, and symops are generated. """ symops = [] for symmetry_label in [ "_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_" ]: if data.data.get(symmetry_label): try: symops = [ SymmOp.from_xyz_string(s) for s in data.data.get(symmetry_label) ] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in [ "_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_" ]: if data.data.get(symmetry_label): try: spg = space_groups.get( sub_spgrp(data.data.get(symmetry_label))) if spg: symops = SpaceGroup(spg).symmetry_ops break except ValueError: continue if not symops: # Try to parse International number for symmetry_label in [ "_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_" ]: if data.data.get(symmetry_label): try: symops = SpaceGroup.from_int_number( str2float( data.data.get(symmetry_label))).symmetry_ops break except ValueError: continue if not symops: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def test_subgroup_supergroup(self): with warnings.catch_warnings() as w: warnings.simplefilter("ignore") self.assertTrue(SpaceGroup('Pma2').is_subgroup(SpaceGroup('Pccm'))) self.assertFalse(SpaceGroup.from_int_number(229).is_subgroup( SpaceGroup.from_int_number(230)))
def test_subgroup_supergroup(self): self.assertTrue(SpaceGroup('Pma2').is_subgroup(SpaceGroup('Pccm'))) self.assertFalse( SpaceGroup.from_int_number(229).is_subgroup( SpaceGroup.from_int_number(230)))
def get_symops(self, data): """ In order to generate symmetry equivalent positions, the symmetry operations are parsed. If the symops are not present, the space group symbol is parsed, and symops are generated. """ symops = [] for symmetry_label in ["_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_"]: if data.data.get(symmetry_label): xyz = data.data.get(symmetry_label) if isinstance(xyz, six.string_types): warnings.warn("A 1-line symmetry op P1 CIF is detected!") xyz = [xyz] try: symops = [SymmOp.from_xyz_string(s) for s in xyz] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in ["_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_"]: sg = data.data.get(symmetry_label) if sg: sg = sub_spgrp(sg) try: spg = space_groups.get(sg) if spg: symops = SpaceGroup(spg).symmetry_ops warnings.warn( "No _symmetry_equiv_pos_as_xyz type key found. " "Spacegroup from %s used." % symmetry_label) break except ValueError: # Ignore any errors pass try: for d in _get_cod_data(): if sg == re.sub("\s+", "", d["hermann_mauguin"]) : xyz = d["symops"] symops = [SymmOp.from_xyz_string(s) for s in xyz] warnings.warn( "No _symmetry_equiv_pos_as_xyz type key found. " "Spacegroup from %s used." % symmetry_label) break except Exception as ex: continue if symops: break if not symops: # Try to parse International number for symmetry_label in ["_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_"]: if data.data.get(symmetry_label): try: i = int(str2float(data.data.get(symmetry_label))) symops = SpaceGroup.from_int_number(i).symmetry_ops break except ValueError: continue if not symops: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def _generate_ordered_structures(self, sanitized_input_structure, transformations): """ Apply our input structure to our list of transformations and output a list of ordered structures that have been pruned for duplicates and for those with low symmetry (optional). Args: sanitized_input_structure: A sanitized input structure (_sanitize_input_structure) transformations: A dict of transformations (values) and name of enumeration strategy (key), the enumeration strategy name is just for record keeping Returns: None (sets self.ordered_structures and self.ordered_structures_origins instance variables) """ ordered_structures = self.ordered_structures ordered_structures_origins = self.ordered_structure_origins # utility function to combine outputs from several transformations def _add_structures(ordered_structures, ordered_structures_origins, structures_to_add, origin=""): """ Transformations with return_ranked_list can return either just Structures or dicts (or sometimes lists!) -- until this is fixed, we use this function to concat structures given by the transformation. """ if structures_to_add: # type conversion if isinstance(structures_to_add, Structure): structures_to_add = [structures_to_add] structures_to_add = [ s["structure"] if isinstance(s, dict) else s for s in structures_to_add ] # concatenation ordered_structures += structures_to_add ordered_structures_origins += [origin] * len(structures_to_add) self.logger.info("Adding {} ordered structures: {}".format( len(structures_to_add), origin)) return ordered_structures, ordered_structures_origins for origin, trans in self.transformations.items(): structures_to_add = trans.apply_transformation( self.sanitized_structure, return_ranked_list=self.num_orderings) ordered_structures, ordered_structures_origins = _add_structures( ordered_structures, ordered_structures_origins, structures_to_add, origin=origin, ) # in case we've introduced duplicates, let's remove them self.logger.info("Pruning duplicate structures.") structures_to_remove = [] for idx, ordered_structure in enumerate(ordered_structures): if idx not in structures_to_remove: duplicate_checker = CollinearMagneticStructureAnalyzer( ordered_structure, overwrite_magmom_mode="none") for check_idx, check_structure in enumerate( ordered_structures): if check_idx not in structures_to_remove and check_idx != idx: if duplicate_checker.matches_ordering(check_structure): structures_to_remove.append(check_idx) if len(structures_to_remove): self.logger.info("Removing {} duplicate ordered structures".format( len(structures_to_remove))) ordered_structures = [ s for idx, s in enumerate(ordered_structures) if idx not in structures_to_remove ] ordered_structures_origins = [ o for idx, o in enumerate(ordered_structures_origins) if idx not in structures_to_remove ] # also remove low symmetry structures if self.truncate_by_symmetry: # by default, keep structures with 5 most symmetric space groups if not isinstance(self.truncate_by_symmetry, int): self.truncate_by_symmetry = 5 self.logger.info("Pruning low symmetry structures.") # first get a list of symmetries present symmetry_int_numbers = [ s.get_space_group_info()[1] for s in ordered_structures ] # then count the number of symmetry operations for that space group num_sym_ops = [ len(SpaceGroup.from_int_number(n).symmetry_ops) for n in symmetry_int_numbers ] # find the largest values... max_symmetries = sorted(list(set(num_sym_ops)), reverse=True) # ...and decide which ones to keep if len(max_symmetries) > self.truncate_by_symmetry: max_symmetries = max_symmetries[0:5] structs_to_keep = [(idx, num) for idx, num in enumerate(num_sym_ops) if num in max_symmetries] # sort so that highest symmetry structs are first structs_to_keep = sorted(structs_to_keep, key=lambda x: (x[1], -x[0]), reverse=True) self.logger.info("Removing {} low symmetry " "ordered structures".format( len(ordered_structures) - len(structs_to_keep))) ordered_structures = [ ordered_structures[i] for i, _ in structs_to_keep ] ordered_structures_origins = [ ordered_structures_origins[i] for i, _ in structs_to_keep ] # and ensure fm is always at index 0 fm_index = ordered_structures_origins.index("fm") ordered_structures.insert(0, ordered_structures.pop(fm_index)) ordered_structures_origins.insert( 0, ordered_structures_origins.pop(fm_index)) # if our input structure isn't in our generated structures, # let's add it manually and also keep a note of which structure # is our input: this is mostly for book-keeping/benchmarking self.input_index = None self.input_origin = None if self.input_analyzer.ordering != Ordering.NM: matches = [ self.input_analyzer.matches_ordering(s) for s in ordered_structures ] if not any(matches): ordered_structures.append(self.input_analyzer.structure) ordered_structures_origins.append("input") self.logger.info( "Input structure not present in enumerated structures, adding..." ) else: self.logger.info("Input structure was found in enumerated " "structures at index {}".format( matches.index(True))) self.input_index = matches.index(True) self.input_origin = ordered_structures_origins[ self.input_index] self.ordered_structures = ordered_structures self.ordered_structure_origins = ordered_structures_origins
def get_symops(self, data): """ In order to generate symmetry equivalent positions, the symmetry operations are parsed. If the symops are not present, the space group symbol is parsed, and symops are generated. """ symops = [] for symmetry_label in [ "_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_" ]: if data.data.get(symmetry_label): xyz = data.data.get(symmetry_label) if isinstance(xyz, six.string_types): warnings.warn("A 1-line symmetry op P1 CIF is detected!") xyz = [xyz] try: symops = [SymmOp.from_xyz_string(s) for s in xyz] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in [ "_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_" ]: sg = data.data.get(symmetry_label) if sg: sg = sub_spgrp(sg) try: spg = space_groups.get(sg) if spg: symops = SpaceGroup(spg).symmetry_ops warnings.warn( "No _symmetry_equiv_pos_as_xyz type key found. " "Spacegroup from %s used." % symmetry_label) break except ValueError: # Ignore any errors pass try: for d in _get_cod_data(): if sg == re.sub(r"\s+", "", d["hermann_mauguin"]): xyz = d["symops"] symops = [ SymmOp.from_xyz_string(s) for s in xyz ] warnings.warn( "No _symmetry_equiv_pos_as_xyz type key found. " "Spacegroup from %s used." % symmetry_label) break except Exception as ex: continue if symops: break if not symops: # Try to parse International number for symmetry_label in [ "_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_" ]: if data.data.get(symmetry_label): try: i = int(str2float(data.data.get(symmetry_label))) symops = SpaceGroup.from_int_number(i).symmetry_ops break except ValueError: continue if not symops: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def _generate_ordered_structures(self, sanitized_input_structure, transformations): """ Apply our input structure to our list of transformations and output a list of ordered structures that have been pruned for duplicates and for those with low symmetry (optional). Args: sanitized_input_structure: A sanitized input structure (_sanitize_input_structure) transformations: A dict of transformations (values) and name of enumeration strategy (key), the enumeration strategy name is just for record keeping Returns: None (sets self.ordered_structures and self.ordered_structures_origins instance variables) """ ordered_structures = self.ordered_structures ordered_structures_origins = self.ordered_structure_origins # utility function to combine outputs from several transformations def _add_structures( ordered_structures, ordered_structures_origins, structures_to_add, origin="" ): """ Transformations with return_ranked_list can return either just Structures or dicts (or sometimes lists!) -- until this is fixed, we use this function to concat structures given by the transformation. """ if structures_to_add: # type conversion if isinstance(structures_to_add, Structure): structures_to_add = [structures_to_add] structures_to_add = [ s["structure"] if isinstance(s, dict) else s for s in structures_to_add ] # concatenation ordered_structures += structures_to_add ordered_structures_origins += [origin] * len(structures_to_add) self.logger.info( "Adding {} ordered structures: {}".format( len(structures_to_add), origin ) ) return ordered_structures, ordered_structures_origins for origin, trans in self.transformations.items(): structures_to_add = trans.apply_transformation( self.sanitized_structure, return_ranked_list=self.num_orderings ) ordered_structures, ordered_structures_origins = _add_structures( ordered_structures, ordered_structures_origins, structures_to_add, origin=origin, ) # in case we've introduced duplicates, let's remove them self.logger.info("Pruning duplicate structures.") structures_to_remove = [] for idx, ordered_structure in enumerate(ordered_structures): if idx not in structures_to_remove: duplicate_checker = CollinearMagneticStructureAnalyzer( ordered_structure, overwrite_magmom_mode="none" ) for check_idx, check_structure in enumerate(ordered_structures): if check_idx not in structures_to_remove and check_idx != idx: if duplicate_checker.matches_ordering(check_structure): structures_to_remove.append(check_idx) if len(structures_to_remove): self.logger.info( "Removing {} duplicate ordered structures".format( len(structures_to_remove) ) ) ordered_structures = [ s for idx, s in enumerate(ordered_structures) if idx not in structures_to_remove ] ordered_structures_origins = [ o for idx, o in enumerate(ordered_structures_origins) if idx not in structures_to_remove ] # also remove low symmetry structures if self.truncate_by_symmetry: # by default, keep structures with 5 most symmetric space groups if not isinstance(self.truncate_by_symmetry, int): self.truncate_by_symmetry = 5 self.logger.info("Pruning low symmetry structures.") # first get a list of symmetries present symmetry_int_numbers = [ s.get_space_group_info()[1] for s in ordered_structures ] # then count the number of symmetry operations for that space group num_sym_ops = [ len(SpaceGroup.from_int_number(n).symmetry_ops) for n in symmetry_int_numbers ] # find the largest values... max_symmetries = sorted(list(set(num_sym_ops)), reverse=True) # ...and decide which ones to keep if len(max_symmetries) > self.truncate_by_symmetry: max_symmetries = max_symmetries[0:5] structs_to_keep = [ (idx, num) for idx, num in enumerate(num_sym_ops) if num in max_symmetries ] # sort so that highest symmetry structs are first structs_to_keep = sorted( structs_to_keep, key=lambda x: (x[1], -x[0]), reverse=True ) self.logger.info( "Removing {} low symmetry " "ordered structures".format( len(ordered_structures) - len(structs_to_keep) ) ) ordered_structures = [ordered_structures[i] for i, _ in structs_to_keep] ordered_structures_origins = [ ordered_structures_origins[i] for i, _ in structs_to_keep ] # and ensure fm is always at index 0 fm_index = ordered_structures_origins.index("fm") ordered_structures.insert(0, ordered_structures.pop(fm_index)) ordered_structures_origins.insert( 0, ordered_structures_origins.pop(fm_index) ) # if our input structure isn't in our generated structures, # let's add it manually and also keep a note of which structure # is our input: this is mostly for book-keeping/benchmarking self.input_index = None self.input_origin = None if self.input_analyzer.ordering != Ordering.NM: matches = [ self.input_analyzer.matches_ordering(s) for s in ordered_structures ] if not any(matches): ordered_structures.append(self.input_analyzer.structure) ordered_structures_origins.append("input") self.logger.info( "Input structure not present in enumerated structures, adding..." ) else: self.logger.info( "Input structure was found in enumerated " "structures at index {}".format(matches.index(True)) ) self.input_index = matches.index(True) self.input_origin = ordered_structures_origins[self.input_index] self.ordered_structures = ordered_structures self.ordered_structure_origins = ordered_structures_origins
def get_symmop(data): symops = [] for symmetry_label in [ "_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_" ]: if data.get(symmetry_label): xyz = data.get(symmetry_label) if isinstance(xyz, str): msg = "A 1-line symmetry op P1 CIF is detected!" warnings.warn(msg) xyz = [xyz] try: symops = [SymmOp.from_xyz_string(s) for s in xyz] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in [ "_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_" ]: sg = data.get(symmetry_label) if sg: sg = sub_spgrp(sg) try: spg = space_groups.get(sg) if spg: symops = SpaceGroup(spg).symmetry_ops msg = "No _symmetry_equiv_pos_as_xyz type key found. " \ "Spacegroup from %s used." % symmetry_label warnings.warn(msg) break except ValueError: # Ignore any errors pass try: for d in _get_cod_data(): if sg == re.sub(r"\s+", "", d["hermann_mauguin"]): xyz = d["symops"] symops = [SymmOp.from_xyz_string(s) for s in xyz] msg = "No _symmetry_equiv_pos_as_xyz type key found. " \ "Spacegroup from %s used." % symmetry_label warnings.warn(msg) break except Exception: continue if symops: break if not symops: # Try to parse International number for symmetry_label in [ "_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_" ]: if data.get(symmetry_label): try: i = int(braket2float(data.get(symmetry_label))) symops = SpaceGroup.from_int_number(i).symmetry_ops break except ValueError: continue if not symops: msg = "No _symmetry_equiv_pos_as_xyz type key found. " \ "Defaulting to P1." warnings.warn(msg) symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def get_symops(self, data): """ In order to generate symmetry equivalent positions, the symmetry operations are parsed. If the symops are not present, the space group symbol is parsed, and symops are generated. """ symops = [] for symmetry_label in ["_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_"]: if data.data.get(symmetry_label): try: symops = [SymmOp.from_xyz_string(s) for s in data.data.get(symmetry_label)] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in ["_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_"]: if data.data.get(symmetry_label): try: spg = space_groups.get(sub_spgrp( data.data.get(symmetry_label))) if spg: symops = SpaceGroup(spg).symmetry_ops break except ValueError: continue if not symops: # Try to parse International number for symmetry_label in ["_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_"]: if data.data.get(symmetry_label): try: i = int(str2float(data.data.get(symmetry_label))) symops = SpaceGroup.from_int_number(i).symmetry_ops break except ValueError: continue if not symops: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def test_hexagonal(self): sgs = [146, 148, 155, 160, 161, 166, 167] for sg in sgs: s = SpaceGroup.from_int_number(sg, hexagonal=False) self.assertTrue(not s.symbol.endswith("H"))
def test_subgroup_supergroup(self): self.assertTrue(SpaceGroup('Pma2').is_subgroup(SpaceGroup('Pccm'))) self.assertFalse(SpaceGroup.from_int_number(229).is_subgroup( SpaceGroup.from_int_number(230)))