def get_reciprocal_point_group_operations( structure: Structure, symprec: float = defaults["symprec"], time_reversal: bool = True, ): from pymatgen.symmetry.analyzer import SpacegroupAnalyzer sga = SpacegroupAnalyzer(structure, symprec=symprec) if sga.get_symmetry_dataset() is None: # sometimes default angle tolerance doesn't work as expected sga = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=-1) rotations = sga.get_symmetry_dataset()["rotations"].transpose((0, 2, 1)) translations = sga.get_symmetry_dataset()["translations"] is_tr = np.full(len(rotations), False, dtype=bool) if time_reversal: rotations = np.concatenate([rotations, -rotations]) translations = np.concatenate([translations, -translations]) is_tr = np.concatenate([is_tr, ~is_tr]) rotations, unique_ops = np.unique(rotations, axis=0, return_index=True) translations = translations[unique_ops] is_tr = is_tr[unique_ops] # put identity first and time-reversal last sort_idx = np.argsort( np.abs(rotations - np.eye(3)).sum(axis=(1, 2)) + is_tr * 10) return rotations[sort_idx], translations[sort_idx], is_tr[sort_idx]
def get_unique_site_indices(structure): sa = SpacegroupAnalyzer(structure) symm_data = sa.get_symmetry_dataset() # equivalency mapping for the structure # i'th site in the struct equivalent to eq_struct[i]'th site eq_atoms = symm_data["equivalent_atoms"] return np.unique(eq_atoms).tolist()
def cif2geom_sym2(cif): parser=CifParser.from_string(cif) struct=parser.get_structures()[0] sg = SpacegroupAnalyzer(struct) struct = sg.get_conventional_standard_structure() sg = SpacegroupAnalyzer(struct) geomlines=["CRYSTAL"] geomlines += ["0 0 1"] geomlines += [str(sg.get_spacegroup_number())] cry_sys = sg.get_crystal_system() lattice = struct.lattice if cry_sys == 'trigonal' or cry_sys == 'hexagonal' or cry_sys == 'tetragonal': geomlines += ["%s %s" %(lattice.a,lattice.c)] elif cry_sys == 'cubic': geomlines += ["%s" %(lattice.a)] elif cry_sys == 'triclinic': geomlines += ["%s %s %s %s %s %s" %(lattice.a,lattice.b,lattice.c,lattice.alpha,lattice.beta,lattice.gamma)] elif cry_sys == 'monoclinic': geomlines += ["%s %s %s %s" %(lattice.a,lattice.b,lattice.c,lattice.beta)] elif cry_sys == 'orthorhombic': geomlines += ["%s %s %s" %(lattice.a,lattice.b,lattice.c)] else: print('Error printing symmetrized structure.') quit() ds = sg.get_symmetry_dataset() eq_sites = np.unique(ds['equivalent_atoms']) geomlines += [str(len(eq_sites))] for eq_site in eq_sites: site = struct.sites[eq_site] geomlines += ["%s %s %s %s" %(site.specie.Z+200,site.a,site.b,site.c)] return geomlines,struct
def from_structure(cls, structure, has_timerev=True, symprec=1e-5, angle_tolerance=5): """ Takes a :class:`Structure` object. Uses spglib to perform various symmetry finding operations. Args: structure: :class:`Structure` object has_timerev: True is time-reversal symmetry is included. symprec: Tolerance for symmetry finding angle_tolerance: Angle tolerance for symmetry finding. .. warning:: AFM symmetries are not supported. """ # Call spglib to get the list of symmetry operations. spga = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance) data = spga.get_symmetry_dataset() return cls( spgid=data["number"], symrel=data["rotations"], tnons=data["translations"], symafm=len(symrel) * [1], has_timerev=has_timerev, inord="C", )
def __init__(self, structure): self.structure = structure sa = SpacegroupAnalyzer(self.structure) symm_data = sa.get_symmetry_dataset() # equivalency mapping for the structure # i'th site in the input structure equivalent to eq_atoms[i]'th site self.eq_atoms = symm_data["equivalent_atoms"]
def from_structure(cls, structure, has_timerev=True, symprec=1e-5, angle_tolerance=5): """ Takes a |Structure| object. Uses spglib to perform various symmetry finding operations. Args: structure: |Structure| object. has_timerev: True is time-reversal symmetry is included. symprec: Tolerance for symmetry finding. angle_tolerance: Angle tolerance for symmetry finding. .. warning:: AFM symmetries are not supported. """ # Call spglib to get the list of symmetry operations. spga = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance) data = spga.get_symmetry_dataset() symrel = data["rotations"] return cls(spgid=data["number"], symrel=symrel, tnons=data["translations"], symafm=len(symrel) * [1], has_timerev=has_timerev, inord="C")
def from_structure(cls, structure: Structure) -> "SymmetryData": symprec = SETTINGS.SYMPREC sg = SpacegroupAnalyzer(structure, symprec=symprec) symmetry: Dict[str, Any] = {"symprec": symprec} if not sg.get_symmetry_dataset(): sg = SpacegroupAnalyzer(structure, 1e-3, 1) symmetry["symprec"] = 1e-3 symmetry.update({ "source": "spglib", "symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "crystal_system": CrystalSystem(sg.get_crystal_system().title()), "hall": sg.get_hall(), "version": spglib.__version__, }) return SymmetryData(**symmetry)
def determine_symmetry_positions(st, element): """ determine non-equivalent positions for atoms of type *element* element (str) - name of element, for example Li return list of lists - atom numbers for each non-equivalent position """ from pymatgen.symmetry.analyzer import SpacegroupAnalyzer stp = st.convert2pymatgen() spg = SpacegroupAnalyzer(stp) info = spg.get_symmetry_dataset() positions = {} for i, (el, pos) in enumerate(zip(st.get_elements(), info['equivalent_atoms'])): if el == element and pos not in positions: positions[pos] = [] if el == element: positions[pos].append(i) printlog('I have found ', len(positions), 'non-equivalent positions for', element, ':',positions.keys(), imp = 'y', end = '\n') printlog('Atom numbers: ', positions, imp = 'y') sorted_keys = sorted(list(positions.keys())) pos_lists = [positions[key] for key in sorted_keys ] return pos_lists
def set_output_data(self, d_calc, d): """ set the 'output' key """ d["output"] = { "structure": d_calc["output"]["structure"], "density": d_calc.pop("density"), "energy": d_calc["output"]["energy"], "energy_per_atom": d_calc["output"]["energy_per_atom"] } d["output"].update(self.get_basic_processed_data(d)) sg = SpacegroupAnalyzer( Structure.from_dict(d_calc["output"]["structure"]), 0.1) if not sg.get_symmetry_dataset(): sg = SpacegroupAnalyzer( Structure.from_dict(d_calc["output"]["structure"]), 1e-3, 1) d["output"]["spacegroup"] = { "source": "spglib", "symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall() } if d["input"]["parameters"].get("LEPSILON"): for k in [ 'epsilon_static', 'epsilon_static_wolfe', 'epsilon_ionic' ]: d["output"][k] = d_calc["output"][k]
def from_structure(cls, structure, equivalent_wyckoff_sites=None): """ Parameters ---------- structure : pymatgen.Structure equivalent_wyckoff_sites : list of lists List of Wyckoff sites that are treated as the same sublattice, e.g. [['b', 'f']] will give combine Wyckoff site 'b' and Wyckoff site 'f' into one sublattice. Putting the same Wyckoff site in multiple equivalent groups will produce undefined results. Returns ------- PRLStructure """ struct = PRLStructure.from_dict(structure.as_dict()) # normalize the input structure to a pure element to get Wyckoff sites structure = Structure.from_dict(structure.as_dict()) structure.replace_species({sp.name: "H" for sp in structure.species}) sga = SpacegroupAnalyzer(structure) wyckoff_sites = sga.get_symmetry_dataset()['wyckoffs'] true_sublattices = sorted(set(wyckoff_sites)) if equivalent_wyckoff_sites is not None: # transform the true sublattices by combining equivalent sites combined_sublattices = [''.join(sorted(sites)) for sites in equivalent_wyckoff_sites] def match_subl(candidate): for subl in combined_sublattices: # if the candidate site is in the combined sublattice, return the combined sublattice if candidate in subl: return subl # no match found return candidate new_subl_model = sorted(set([match_subl(subl) for subl in true_sublattices])) else: new_subl_model = true_sublattices #ratios = [sum([1 if site in subl else 0 for site in wyckoff_sites]) for subl in new_subl_model] config = [] occ = [] ratios = [] for subl in new_subl_model: species_frequency_dict = {} for site, wyckoff_site in zip(struct.sites, wyckoff_sites): if wyckoff_site in subl: species = site.specie.name species_frequency_dict[species] = species_frequency_dict.get(species, 0) + 1 total_subl_occupation = sum(species_frequency_dict.values()) subl_species = sorted(set(species_frequency_dict.keys())) subl_occpancy = [species_frequency_dict[sp]/total_subl_occupation for sp in subl_species] config.append(subl_species) occ.append(subl_occpancy) ratios.append(total_subl_occupation) #config = [sorted(set([site.specie.name for site, wyckoff in if wyckoff in subl])) for subl in new_subl_model] struct.sublattice_configuration = config struct.sublattice_occupancies = occ struct.sublattice_site_ratios = ratios return struct
def get_equiv_sites(self, s, site): """Find identical sites from analyzing space group symmetry.""" sga = SpacegroupAnalyzer(s, symprec=0.01) sg = sga.get_space_group_operations sym_data = sga.get_symmetry_dataset() equiv_atoms = sym_data["equivalent_atoms"] wyckoffs = sym_data["wyckoffs"] sym_struct = SymmetrizedStructure(s, sg, equiv_atoms, wyckoffs) equivs = sym_struct.find_equivalent_sites(site) return equivs
def analyze_symmetry(args): tolerance = args.symmetry t = [] for filename in args.filenames: s = Structure.from_file(filename, primitive=False) finder = SpacegroupAnalyzer(s, tolerance) dataset = finder.get_symmetry_dataset() t.append([filename, dataset["international"], dataset["number"], dataset["hall"]]) print(tabulate(t, headers=["Filename", "Int Symbol", "Int number", "Hall"]))
def as_dict(self): """ Returns the CTRL as a dictionary. "SITE" and "CLASS" are of the form {'CATEGORY': {'TOKEN': value}}, the rest is of the form 'TOKEN'/'CATEGORY': value. It gets the conventional standard structure because primitive cells use the conventional a-lattice parameter as the scaling factor and not the a-lattice parameter of the primitive cell. """ ctrl_dict = { "@module": self.__class__.__module__, "@class": self.__class__.__name__, } if self.header is not None: ctrl_dict["HEADER"] = self.header if self.version is not None: ctrl_dict["VERS"] = self.version sga = SpacegroupAnalyzer(self.structure) alat = sga.get_conventional_standard_structure().lattice.a plat = self.structure.lattice.matrix / alat """ The following is to find the classes (atoms that are not symmetry equivalent, and create labels. Note that LMTO only attaches numbers with the second atom of the same species, e.g. "Bi", "Bi1", "Bi2", etc. """ eq_atoms = sga.get_symmetry_dataset()["equivalent_atoms"] ineq_sites_index = list(set(eq_atoms)) sites = [] classes = [] num_atoms = {} for s, site in enumerate(self.structure.sites): atom = site.specie label_index = ineq_sites_index.index(eq_atoms[s]) if atom.symbol in num_atoms: if label_index + 1 > sum(num_atoms.values()): num_atoms[atom.symbol] += 1 atom_label = atom.symbol + str(num_atoms[atom.symbol] - 1) classes.append({"ATOM": atom_label, "Z": atom.Z}) else: num_atoms[atom.symbol] = 1 classes.append({"ATOM": atom.symbol, "Z": atom.Z}) sites.append({"ATOM": classes[label_index]["ATOM"], "POS": site.coords / alat}) ctrl_dict.update( { "ALAT": alat / bohr_to_angstrom, "PLAT": plat, "CLASS": classes, "SITE": sites, } ) return ctrl_dict
def __init__(self, struct, source='', comment=''): if struct.is_ordered: self.struct = struct self.source = source sym = SpacegroupAnalyzer(struct) data = sym.get_symmetry_dataset() self.space_number = data["number"] self.space_group = data["international"] self.comment = comment or "None given" else: raise ValueError("Structure with partial occupancies cannot be " "converted into atomic coordinates!")
def parse_symmetry(args): tolerance = float(args.tolerance[0]) for filename in args.filenames: s = Structure.from_file(filename) if args.spacegroup: finder = SpacegroupAnalyzer(s, tolerance) dataset = finder.get_symmetry_dataset() print(filename) print("Spacegroup : {}".format(dataset["international"])) print("Int number : {}".format(dataset["number"])) print("Hall symbol : {}".format(dataset["hall"])) print("")
def parse_symmetry(args): tolerance = float(args.tolerance[0]) for filename in args.filenames: s = Structure.from_file(filename) if args.spacegroup: finder = SpacegroupAnalyzer(s, tolerance) dataset = finder.get_symmetry_dataset() print(filename) print("Spacegroup : {}".format(dataset["international"])) print("Int number : {}".format(dataset["number"])) print("Hall symbol : {}".format(dataset["hall"])) print()
def determine_symmetry_positions(st, element, silent=0): """ determine non-equivalent positions for atoms of type *element* element (str) - name of element, for example Li return list of lists - atom numbers for each non-equivalent position """ from pymatgen.symmetry.analyzer import SpacegroupAnalyzer stp = st.convert2pymatgen() spg = SpacegroupAnalyzer(stp) info = spg.get_symmetry_dataset() positions = {} for i, (el, pos) in enumerate(zip(st.get_elements(), info['equivalent_atoms'])): if el == element and pos not in positions: positions[pos] = [] if el == element: positions[pos].append(i) if not silent: printlog('I have found ', len(positions), 'non-equivalent positions for', element, ':', positions.keys(), imp='y', end='\n') positions_for_print = {} for key in positions: positions_for_print[key] = [p + 1 for p in positions[key]] if not silent: printlog('Atom numbers: ', positions_for_print, imp='y') sorted_keys = sorted(list(positions.keys())) pos_lists = [positions[key] for key in sorted_keys] return pos_lists
def _get_data_from_single_dirc(dirc, src_str="str_relax.out", src_ene='energy'): """ 指定したdircから構造とエネルギーを読み取る """ src = os.path.join(dirc, src_str) strout = StrOut.from_file(src) src = os.path.join(dirc, src_ene) with open(src, 'r') as rfile: lines = rfile.readlines() num_atoms = sum(strout.structure.composition. to_data_dict['unit_cell_composition'].values()) energy = float(lines[0]) / num_atoms analyzer = SpacegroupAnalyzer(strout.structure) #std_prim = analyzer.get_primitive_standard_structure() std_str = analyzer.get_conventional_standard_structure() analyzer = SpacegroupAnalyzer(std_str) wyckoffs = analyzer.get_symmetry_dataset()['wyckoffs'] formula = std_str.composition.to_data_dict['unit_cell_composition'] symbol_spg = analyzer.get_spacegroup_symbol() num_spg = analyzer.get_spacegroup_number() spg = [symbol_spg, num_spg] lattice = std_str.as_dict()['lattice'] equiv_sites = analyzer.get_symmetrized_structure().equivalent_sites equiv_indices = analyzer.get_symmetrized_structure().equivalent_indices # Wycoffs labelと組み合わせたsites_groupのlistを作る sites_and_wyckoffs = [] for eq_s, eq_i in zip(equiv_sites, equiv_indices): sites_and_wyckoffs.append({'wyckoffs': wyckoffs[eq_i[0]], 'site_grp': eq_s}) # check for i in range(len(eq_i)-1): if wyckoffs[eq_i[i]] != wyckoffs[eq_i[i+1]] or \ len(eq_s) != len(eq_i): print("wyckoffs label is wrong !!!!") print(wyckoffs) print(eq_i) print(len(eq_s)) print(dirc) exit() return {'formula': formula, 'lattice': lattice, 'spg': spg, 'sites_and_wyckoffs': sites_and_wyckoffs, 'energy': energy, 'str_id': os.path.basename(dirc)}
def run_task(self, fw_spec): self.user_incar_settings.update({"NPAR": 2}) # Get kpoint density per vol vol = Poscar.from_file("POSCAR").structure.volume kppra_vol = self.kpoints_density / vol new_set = MPStaticSet.from_prev_calc( os.getcwd(), user_incar_settings=self.user_incar_settings, reciprocal_density=kppra_vol) new_set.write_input('.') structure = new_set.structure sga = SpacegroupAnalyzer(structure, 0.1) return FWAction(stored_data={ 'refined_structure': sga.get_refined_structure().as_dict(), 'conventional_standard_structure': sga.get_conventional_standard_structure().as_dict(), 'symmetry_dataset': sga.get_symmetry_dataset(), 'symmetry_operations': [x.as_dict() for x in sga.get_symmetry_operations()]})
def __init__(self, struct, source="", comment=""): """ Args: struct: Structure object, See pymatgen.core.structure.Structure. source: User supplied identifier, i.e. for Materials Project this would be the material ID number comment: Comment for first header line """ if struct.is_ordered: self.struct = struct self.source = source sym = SpacegroupAnalyzer(struct) data = sym.get_symmetry_dataset() self.space_number = data["number"] self.space_group = data["international"] self.comment = comment or "None given" else: raise ValueError("Structure with partial occupancies cannot be converted into atomic coordinates!")
def _make_struc_file(self, file_name): sym = SpacegroupAnalyzer(self._bs._structure, symprec=0.01) with open(file_name, 'w') as f: f.write(self._bs._structure.composition.formula+" " + str(sym.get_spacegroup_symbol())+"\n") for i in range(3): line = '' for j in range(3): line += "%12.5f" % ( Length(self._bs._structure.lattice.matrix[i][j], "ang").to("bohr")) f.write(line+'\n') ops = sym.get_symmetry_dataset()['rotations'] f.write(str(len(ops))+"\n") for c in ops: f.write('\n'.join([' '.join([str(int(i)) for i in row]) for row in c])) f.write('\n')
def get_sym_inequiv_components( components: List[Component], spg_analyzer: SpacegroupAnalyzer) -> List[Component]: """Gets and counts the symmetrically inequivalent components. Component data has to have been generated with ``inc_site_ids=True``. Args: components: A list of structure components, generated using :obj:`pymatgen.analysis.dimensionality.get_structure_components`, with ``inc_site_ids=True``. spg_analyzer: A `pymatgen.symmetry.analyzer.SpacegroupAnalyzer` analyzer object for the structure containing the components. Returns: A list of the symmetrically inequivalent components. Any duplicate components will only be returned once. The component objects are in the same format is given by :obj:`pymatgen.analysis.dimensionality.get_structure_components` but the additional property: - ``"count"`` (:obj:`int`): The number of times this component appears in the structure. """ components = deepcopy(components) sym_inequiv_components = {} equivalent_atoms = spg_analyzer.get_symmetry_dataset()['equivalent_atoms'] for component in components: sym_indices = frozenset(equivalent_atoms[x] for x in component['site_ids']) # if two components are composed of atoms that are symmetrically # equivalent they are the same. if sym_indices in sym_inequiv_components: sym_inequiv_components[sym_indices]['count'] += 1 continue component['count'] = 1 sym_inequiv_components[sym_indices] = component return list(sym_inequiv_components.values())
def sg_pg_compare(mpid='mp-989535'): stru = m.get_structure_by_material_id(mpid) spa = SpacegroupAnalyzer(stru) pg_name = spa.get_symmetry_dataset()['pointgroup'] pg_ops = PointGroup(pg_name).symmetry_ops sp_ops = [] sp_mats = [] pg_mats = [] for op in pg_ops: rotation = op.rotation_matrix pg_mats.append(jsanitize(rotation)) for op in spa.get_symmetry_operations(): rotation = op.rotation_matrix sp_mats.append(jsanitize(rotation)) sp_ops.append(SymmOp.from_rotation_and_translation( rotation, (0, 0, 0))) sp_ops = set(sp_ops) #pg_mats.sort();sp_mats.sort() return pg_mats, sp_mats
def cif2geom_sym2(cif): parser = CifParser.from_string(cif) struct = parser.get_structures()[0] sg = SpacegroupAnalyzer(struct) struct = sg.get_conventional_standard_structure() sg = SpacegroupAnalyzer(struct) geomlines = ["CRYSTAL"] geomlines += ["0 0 1"] geomlines += [str(sg.get_spacegroup_number())] cry_sys = sg.get_crystal_system() lattice = struct.lattice if cry_sys == 'trigonal' or cry_sys == 'hexagonal' or cry_sys == 'tetragonal': geomlines += ["%s %s" % (lattice.a, lattice.c)] elif cry_sys == 'cubic': geomlines += ["%s" % (lattice.a)] elif cry_sys == 'triclinic': geomlines += [ "%s %s %s %s %s %s" % (lattice.a, lattice.b, lattice.c, lattice.alpha, lattice.beta, lattice.gamma) ] elif cry_sys == 'monoclinic': geomlines += [ "%s %s %s %s" % (lattice.a, lattice.b, lattice.c, lattice.beta) ] elif cry_sys == 'orthorhombic': geomlines += ["%s %s %s" % (lattice.a, lattice.b, lattice.c)] else: print('Error printing symmetrized structure.') quit() ds = sg.get_symmetry_dataset() eq_sites = np.unique(ds['equivalent_atoms']) geomlines += [str(len(eq_sites))] for eq_site in eq_sites: site = struct.sites[eq_site] geomlines += [ "%s %s %s %s" % (site.specie.Z + 200, site.a, site.b, site.c) ] return geomlines, struct
def main(): parser = argparse.ArgumentParser() parser.add_argument('-f', '--file', default='POSCAR', type=str, help='path to input file') parser.add_argument('-t', '--tol', default=1e-3, type=float, help='symmetry tolerance (default 1e-3)') parser.add_argument('-o', '--output', default='poscar', help='output file format') args = parser.parse_args() struct = Structure.from_file(args.file) sym = SpacegroupAnalyzer(struct, symprec=args.tol) data = sym.get_symmetry_dataset() print("Initial structure has {} atoms".format(struct.num_sites)) print("\tSpace group number: {}".format(data['number'])) print("\tInternational symbol: {}".format(data['international'])) print("\tLattice type: {}".format(sym.get_lattice_type())) # seekpath conventional cell definition different from spglib std = spglib.refine_cell(sym._cell, symprec=args.tol) seek_data = seekpath.get_path(std) # now remake the structure lattice = seek_data['conv_lattice'] scaled_positions = seek_data['conv_positions'] numbers = seek_data['conv_types'] species = [sym._unique_species[i - 1] for i in numbers] conv = Structure(lattice, species, scaled_positions) conv.get_sorted_structure().to(filename="{}_conv".format(args.file), fmt=args.output) print("Final structure has {} atoms".format(conv.num_sites))
def __init__(self, struct, source='', comment=''): if struct.is_ordered: self._struct = struct self._source = source self._site_symbols = [] self._natoms = [] sym = SpacegroupAnalyzer(struct) data = sym.get_symmetry_dataset() self._space_number = data["number"] self._space_group = data["international"] syms = [site.specie.symbol for site in struct] for (s, data) in itertools.groupby(syms): self._site_symbols.append(s) self._natoms.append(len(tuple(data))) if comment == '': self._comment = 'None Given' else: self._comment = comment else: raise ValueError("Structure with partial occupancies cannot be " "converted into atomic coordinates!")
def symmetry_order_2d(structure, point_group_list): ''' Find symmetry order in a two dimensional structure Args: structure: pymatgen structure point_group_list Return: Number of symmetry operations, and site symmetry order of the input structure ''' s = SpacegroupAnalyzer(structure, symprec=0.1) point_group_symbols = s.get_symmetry_dataset()['site_symmetry_symbols'] point_group_order = 0 for point_group_symbol in point_group_symbols : point_group_order += point_group_list[point_group_symbol.replace('.', '')] # return s.get_space_group_symbol(), s.get_space_group_number(), return len(s.get_space_group_operations()), point_group_order/len(point_group_symbols)
def __init__(self, struct, source='', comment=''): if struct.is_ordered: self._struct = struct self._source = source self._site_symbols = [] self._natoms = [] sym = SpacegroupAnalyzer(struct) data = sym.get_symmetry_dataset() self._space_number = data["number"] self._space_group = data["international"] syms = [site.specie.symbol for site in struct] for (s, data) in itertools.groupby(syms): self._site_symbols.append(s) self._natoms.append(len(tuple(data))) if comment == '': self._comment = 'None Given' else: self._comment = comment else: raise ValueError("Structure with partial occupancies cannot be " "converted into atomic coordinates!")
def main(): parser = argparse.ArgumentParser() parser.add_argument('-f', '--file', type=str, default='POSCAR', help='path to input file') parser.add_argument('-t', '--tol', default=1e-3, type=float, help='symmetry tolerance (default 1e-3)') args = parser.parse_args() struct = Structure.from_file(args.file) sym = SpacegroupAnalyzer(struct, symprec=args.tol) data = sym.get_symmetry_dataset() print("Space group number: {}".format(data['number'])) print("International symbol: {}".format(data['international'])) print("Lattice type: {}".format(sym.get_lattice_type()))
def __init__(self, bonded_structure: StructureGraph, use_symmetry_equivalent_sites: bool = False, symprec: float = 0.01, minimum_geometry_op: float = 0.4, use_iupac_formula: bool = True): self.bonded_structure = bonded_structure self.use_iupac_formula = use_iupac_formula self.minimum_geometry_op = minimum_geometry_op self.site_fingerprints = get_site_fingerprints( bonded_structure.structure) sga = SpacegroupAnalyzer(bonded_structure.structure, symprec=symprec) equivalent_sites = sga.get_symmetry_dataset()['equivalent_atoms'] if use_symmetry_equivalent_sites: self.equivalent_sites = list(equivalent_sites) else: self.equivalent_sites = self._calculate_equivalent_sites() self.symmetry_labels = self._calculate_symmetry_labels( equivalent_sites)
def __init__(self, structure, symprec=1e-3): self.structure = structure # use sym as a quick way to access the cell data sym = SpacegroupAnalyzer(structure, symprec=symprec) self._spg_data = sym.get_symmetry_dataset() # make primitive and conventional cell from seekpath output std = spglib.refine_cell(sym._cell, symprec=symprec) self._seek_data = seekpath.get_path(std) prim_lattice = self._seek_data["primitive_lattice"] prim_scaled_positions = self._seek_data["primitive_positions"] prim_numbers = self._seek_data["primitive_types"] prim_atoms = [sym._unique_species[i - 1] for i in prim_numbers] self.prim = Structure(prim_lattice, prim_atoms, prim_scaled_positions) conv_lattice = self._seek_data["conv_lattice"] conv_scaled_positions = self._seek_data["conv_positions"] conv_numbers = self._seek_data["conv_types"] conv_atoms = [sym._unique_species[i - 1] for i in conv_numbers] self.conv = Structure(conv_lattice, conv_atoms, conv_scaled_positions)
def main( hexagonal_relax_pk: int, group_pk: int, plot_energies: bool = False, vmax: float = None, ): grp = Group.get(id=group_pk) data = [] print("load data: total {} data".format(len(grp.nodes))) for i, node in enumerate(grp.nodes): print("loading data: number {}".format(i + 1)) twinpy = Twinpy.initialize_from_aiida_twinboundary( twinboundary_relax_pk=node.pk, hexagonal_relax_pk=hexagonal_relax_pk, ) pmgstruct = get_pymatgen_structure( twinpy.twinboundary_analyzer.relax_analyzer.final_cell) spg = SpacegroupAnalyzer(pmgstruct, symprec=1e-1) sg = spg.get_symmetry_dataset()['international'] print("pk: %d" % node.pk + " " + node.label + " space group: %s" % sg) tb_analyzer = twinpy.twinboundary_analyzer xshift = tb_analyzer.twinboundary_structure.xshift yshift = tb_analyzer.twinboundary_structure.yshift energy = tb_analyzer.get_formation_energy() data.append([xshift, yshift, energy]) data = np.array(data) # plot plane interval if plot_energies: plt.figure() im = plt.scatter(data[:, 0], data[:, 1], c=data[:, 2], cmap=cm.jet, vmax=vmax) plt.colorbar(im) plt.show()
def num_equivalent_clusters(structure: Structure, inserted_atom_coords: Optional[list], removed_atom_indices: Optional[list], symprec: float = SYMMETRY_TOLERANCE, angle_tolerance: float = ANGLE_TOL ) -> Tuple[int, str]: """Calculate number of equivalent clusters in the structure. Args: structure (Structure): Supercell is assumed to big enough. inserted_atom_coords (list): removed_atom_indices (list): Needs to begin from 0. symprec (float): angle_tolerance (float): Angle tolerance in degree used for identifying the space group. Returns: Tuple of (num_equivalent_clusters (int), point_group (str)) """ inserted_atom_coords = inserted_atom_coords or [] removed_atom_indices = removed_atom_indices or [] sga = SpacegroupAnalyzer(structure, symprec, angle_tolerance) num_symmop = len(sga.get_symmetry_operations()) structure_with_cluster = structure.copy() for i in inserted_atom_coords: structure_with_cluster.append(DummySpecie(), i) structure_with_cluster.remove_sites(removed_atom_indices) sga_with_cluster = \ SpacegroupAnalyzer(structure_with_cluster, symprec, angle_tolerance) sym_dataset = sga_with_cluster.get_symmetry_dataset() point_group = sym_dataset["pointgroup"] return int(num_symmop / num_symmetry_operation(point_group)), point_group
def main(): parser = argparse.ArgumentParser() parser.add_argument('-f', '--file', default='POSCAR', type=str, help='path to input file') parser.add_argument('-t', '--tol', default=1e-3, type=float, help='symmetry tolerance (default 1e-3)') parser.add_argument('-o', '--output', default='poscar', help='output file format') args = parser.parse_args() struct = Structure.from_file(args.file) sym = SpacegroupAnalyzer(struct, symprec=args.tol) data = sym.get_symmetry_dataset() print('Initial structure has {} atoms'.format(struct.num_sites)) print('\tSpace group number: {}'.format(data['number'])) print('\tInternational symbol: {}'.format(data['international'])) print('\tLattice type: {}'.format(sym.get_lattice_type())) # first standardise the cell using the tolerance we want (seekpath has no # tolerance setting) std = spglib.refine_cell(sym._cell, symprec=args.tol) seek_data = seekpath.get_path(std) transform = seek_data['primitive_transformation_matrix'] # now remake the structure lattice = seek_data['primitive_lattice'] scaled_positions = seek_data['primitive_positions'] numbers = seek_data['primitive_types'] species = [sym._unique_species[i - 1] for i in numbers] prim = Structure(lattice, species, scaled_positions) prim.get_sorted_structure().to(filename='{}_prim'.format(args.file), fmt=args.output) print('Final structure has {} atoms'.format(prim.num_sites)) print('Conv -> Prim transformation matrix:') print('\t' + str(transform).replace('\n', '\n\t'))
def set_output_data(self, d_calc, d): """ set the 'output' key """ d["output"] = { "structure": d_calc["output"]["structure"], "density": d_calc.pop("density"), "energy": d_calc["output"]["energy"], "energy_per_atom": d_calc["output"]["energy_per_atom"]} d["output"].update(self.get_basic_processed_data(d)) sg = SpacegroupAnalyzer(Structure.from_dict(d_calc["output"]["structure"]), 0.1) if not sg.get_symmetry_dataset(): sg = SpacegroupAnalyzer(Structure.from_dict(d_calc["output"]["structure"]), 1e-3, 1) d["output"]["spacegroup"] = { "source": "spglib", "symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall()} if d["input"]["parameters"].get("LEPSILON"): for k in ['epsilon_static', 'epsilon_static_wolfe', 'epsilon_ionic']: d["output"][k] = d_calc["output"][k]
def get_uniq_layercoords(struct, nlayers, top=True): """ returns the coordinates of unique sites in the top or bottom nlayers of the given structure. Args: struct: input structure nlayers: number of layers top: top or bottom layers, default is top layer Return: numpy array of unique coordinates """ coords = np.array([site.coords for site in struct]) z = coords[:, 2] z = np.around(z, decimals=4) zu, zuind = np.unique(z, return_index=True) z_nthlayer = z[zuind[-nlayers]] zfilter = (z >= z_nthlayer) if not top: z_nthlayer = z[zuind[nlayers - 1]] zfilter = (z <= z_nthlayer) # site indices in the layers indices_layers = np.argwhere(zfilter).ravel() sa = SpacegroupAnalyzer(struct) symm_data = sa.get_symmetry_dataset() # equivalency mapping for the structure # i'th site in the struct equivalent to eq_struct[i]'th site eq_struct = symm_data["equivalent_atoms"] # equivalency mapping for the layers eq_layers = eq_struct[indices_layers] # site indices of unique atoms in the layers __, ueq_layers_indices = np.unique(eq_layers, return_index=True) # print(ueq_layers_indices) indices_uniq = indices_layers[ueq_layers_indices] # coordinates of the unique atoms in the layers return coords[indices_uniq]
def get_uniq_layercoords(struct, nlayers, top=True): """ returns the coordinates of unique sites in the top or bottom nlayers of the given structure. Args: struct: input structure nlayers: number of layers top: top or bottom layers, default is top layer Return: numpy array of unique coordinates """ coords = np.array([site.coords for site in struct]) z = coords[:, 2] z = np.around(z, decimals=4) zu, zuind = np.unique(z, return_index=True) z_nthlayer = z[zuind[-nlayers]] zfilter = (z >= z_nthlayer) if not top: z_nthlayer = z[zuind[nlayers - 1]] zfilter = (z <= z_nthlayer) # site indices in the layers indices_layers = np.argwhere(zfilter).ravel() sa = SpacegroupAnalyzer(struct) symm_data = sa.get_symmetry_dataset() # equivalency mapping for the structure # i'th site in the struct equivalent to eq_struct[i]'th site eq_struct = symm_data["equivalent_atoms"] # equivalency mapping for the layers eq_layers = eq_struct[indices_layers] # site indices of unique atoms in the layers __, ueq_layers_indices = np.unique(eq_layers, return_index=True) # print(ueq_layers_indices) indices_uniq = indices_layers[ueq_layers_indices] # coordinates of the unique atoms in the layers return coords[indices_uniq]
class SpacegroupAnalyzerTest(PymatgenTest): def setUp(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) self.structure = p.structure self.sg = SpacegroupAnalyzer(self.structure, 0.001) self.disordered_structure = self.get_structure('Li10GeP2S12') self.disordered_sg = SpacegroupAnalyzer(self.disordered_structure, 0.001) s = p.structure.copy() site = s[0] del s[0] s.append(site.species_and_occu, site.frac_coords) self.sg3 = SpacegroupAnalyzer(s, 0.001) graphite = self.get_structure('Graphite') graphite.add_site_property("magmom", [0.1] * len(graphite)) self.sg4 = SpacegroupAnalyzer(graphite, 0.001) self.structure4 = graphite def test_primitive(self): s = Structure.from_spacegroup("Fm-3m", np.eye(3) * 3, ["Cu"], [[0, 0, 0]]) a = SpacegroupAnalyzer(s) self.assertEqual(len(s), 4) self.assertEqual(len(a.find_primitive()), 1) def test_is_laue(self): s = Structure.from_spacegroup("Fm-3m", np.eye(3) * 3, ["Cu"], [[0, 0, 0]]) a = SpacegroupAnalyzer(s) self.assertTrue(a.is_laue()) def test_magnetic(self): lfp = PymatgenTest.get_structure("LiFePO4") sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_space_group_symbol(), "Pnma") magmoms = [0] * len(lfp) magmoms[4] = 1 magmoms[5] = -1 magmoms[6] = 1 magmoms[7] = -1 lfp.add_site_property("magmom", magmoms) sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_space_group_symbol(), "Pnma") def test_get_space_symbol(self): self.assertEqual(self.sg.get_space_group_symbol(), "Pnma") self.assertEqual(self.disordered_sg.get_space_group_symbol(), "P4_2/nmc") self.assertEqual(self.sg3.get_space_group_symbol(), "Pnma") self.assertEqual(self.sg4.get_space_group_symbol(), "P6_3/mmc") def test_get_space_number(self): self.assertEqual(self.sg.get_space_group_number(), 62) self.assertEqual(self.disordered_sg.get_space_group_number(), 137) self.assertEqual(self.sg4.get_space_group_number(), 194) def test_get_hall(self): self.assertEqual(self.sg.get_hall(), '-P 2ac 2n') self.assertEqual(self.disordered_sg.get_hall(), 'P 4n 2n -1n') def test_get_pointgroup(self): self.assertEqual(self.sg.get_point_group_symbol(), 'mmm') self.assertEqual(self.disordered_sg.get_point_group_symbol(), '4/mmm') def test_get_symmetry_dataset(self): ds = self.sg.get_symmetry_dataset() self.assertEqual(ds['international'], 'Pnma') def test_get_crystal_system(self): crystal_system = self.sg.get_crystal_system() self.assertEqual('orthorhombic', crystal_system) self.assertEqual('tetragonal', self.disordered_sg.get_crystal_system()) def test_get_symmetry_operations(self): for sg, structure in [(self.sg, self.structure), (self.sg4, self.structure4)]: pgops = sg.get_point_group_operations() fracsymmops = sg.get_symmetry_operations() symmops = sg.get_symmetry_operations(True) latt = structure.lattice for fop, op, pgop in zip(fracsymmops, symmops, pgops): # translation vector values should all be 0 or 0.5 t = fop.translation_vector * 2 self.assertArrayAlmostEqual(t - np.round(t), 0) self.assertArrayAlmostEqual(fop.rotation_matrix, pgop.rotation_matrix) for site in structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac)) found = False newsite = PeriodicSite(site.species_and_occu, newcart, latt, coords_are_cartesian=True) for testsite in structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) # Make sure this works for any position, not just the atomic # ones. random_fcoord = np.random.uniform(size=(3)) random_ccoord = latt.get_cartesian_coords(random_fcoord) newfrac = fop.operate(random_fcoord) newcart = op.operate(random_ccoord) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac)) def test_get_refined_structure(self): for a in self.sg.get_refined_structure().lattice.angles: self.assertEqual(a, 90) refined = self.disordered_sg.get_refined_structure() for a in refined.lattice.angles: self.assertEqual(a, 90) self.assertEqual(refined.lattice.a, refined.lattice.b) s = self.get_structure('Li2O') sg = SpacegroupAnalyzer(s, 0.01) self.assertEqual(sg.get_refined_structure().num_sites, 4 * s.num_sites) def test_get_symmetrized_structure(self): symm_struct = self.sg.get_symmetrized_structure() for a in symm_struct.lattice.angles: self.assertEqual(a, 90) self.assertEqual(len(symm_struct.equivalent_sites), 5) symm_struct = self.disordered_sg.get_symmetrized_structure() self.assertEqual(len(symm_struct.equivalent_sites), 8) self.assertEqual([len(i) for i in symm_struct.equivalent_sites], [16,4,8,4,2,8,8,8]) s1 = symm_struct.equivalent_sites[1][1] s2 = symm_struct[symm_struct.equivalent_indices[1][1]] self.assertEqual(s1, s2) self.assertEqual(self.sg4.get_symmetrized_structure()[0].magmom, 0.1) self.assertEqual(symm_struct.wyckoff_symbols[0], '16h') # self.assertEqual(symm_struct[0].wyckoff, "16h") def test_find_primitive(self): """ F m -3 m Li2O testing of converting to primitive cell """ parser = CifParser(os.path.join(test_dir, 'Li2O.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive() self.assertEqual(primitive_structure.formula, "Li2 O1") # This isn't what is expected. All the angles should be 60 self.assertAlmostEqual(primitive_structure.lattice.alpha, 60) self.assertAlmostEqual(primitive_structure.lattice.beta, 60) self.assertAlmostEqual(primitive_structure.lattice.gamma, 60) self.assertAlmostEqual(primitive_structure.lattice.volume, structure.lattice.volume / 4.0) def test_get_ir_reciprocal_mesh(self): grid = self.sg.get_ir_reciprocal_mesh() self.assertEqual(len(grid), 216) self.assertAlmostEqual(grid[1][0][0], 0.1) self.assertAlmostEqual(grid[1][0][1], 0.0) self.assertAlmostEqual(grid[1][0][2], 0.0) self.assertAlmostEqual(grid[1][1], 2) def test_get_conventional_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.b, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.c, 9.1980270633769461) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.b, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.c, 4.2327080177761687) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 2.9542233922299999) self.assertAlmostEqual(conv.lattice.b, 4.6330325651443296) self.assertAlmostEqual(conv.lattice.c, 5.373703587040775) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 4.1430033493799998) self.assertAlmostEqual(conv.lattice.b, 31.437979757624728) self.assertAlmostEqual(conv.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'orac_632475.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 3.1790663399999999) self.assertAlmostEqual(conv.lattice.b, 9.9032878699999998) self.assertAlmostEqual(conv.lattice.c, 3.5372412099999999) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 117.53832420192903) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 14.033435583000625) self.assertAlmostEqual(conv.lattice.b, 3.96052850731) self.assertAlmostEqual(conv.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'hex_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 120) self.assertAlmostEqual(conv.lattice.a, 3.699919902005897) self.assertAlmostEqual(conv.lattice.b, 3.699919902005897) self.assertAlmostEqual(conv.lattice.c, 6.9779585500000003) def test_get_primitive_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 109.47122063400001) self.assertAlmostEqual(prim.lattice.beta, 109.47122063400001) self.assertAlmostEqual(prim.lattice.gamma, 109.47122063400001) self.assertAlmostEqual(prim.lattice.a, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.b, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.c, 7.9657251015812145) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 105.015053349) self.assertAlmostEqual(prim.lattice.beta, 105.015053349) self.assertAlmostEqual(prim.lattice.gamma, 118.80658411899999) self.assertAlmostEqual(prim.lattice.a, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.b, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.c, 4.1579321075608791) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 134.78923546600001) self.assertAlmostEqual(prim.lattice.beta, 105.856239333) self.assertAlmostEqual(prim.lattice.gamma, 91.276341676000001) self.assertAlmostEqual(prim.lattice.a, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.b, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.c, 3.8428217771014852) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 164.985257335) self.assertAlmostEqual(prim.lattice.a, 15.854897098324196) self.assertAlmostEqual(prim.lattice.b, 15.854897098324196) self.assertAlmostEqual(prim.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'orac_632475.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 144.40557588533386) self.assertAlmostEqual(prim.lattice.a, 5.2005185662155391) self.assertAlmostEqual(prim.lattice.b, 5.2005185662155391) self.assertAlmostEqual(prim.lattice.c, 3.5372412099999999) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 63.579155761999999) self.assertAlmostEqual(prim.lattice.beta, 116.42084423747779) self.assertAlmostEqual(prim.lattice.gamma, 148.47965136208569) self.assertAlmostEqual(prim.lattice.a, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.b, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'hex_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 120) self.assertAlmostEqual(prim.lattice.a, 3.699919902005897) self.assertAlmostEqual(prim.lattice.b, 3.699919902005897) self.assertAlmostEqual(prim.lattice.c, 6.9779585500000003) parser = CifParser(os.path.join(test_dir, 'rhomb_3478_conv.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 28.049186140546812) self.assertAlmostEqual(prim.lattice.beta, 28.049186140546812) self.assertAlmostEqual(prim.lattice.gamma, 28.049186140546812) self.assertAlmostEqual(prim.lattice.a, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.b, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.c, 5.9352627428399982)
class SpacegroupAnalyzerTest(PymatgenTest): def setUp(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) self.structure = p.structure self.sg = SpacegroupAnalyzer(self.structure, 0.001) self.disordered_structure = self.get_structure('Li10GeP2S12') self.disordered_sg = SpacegroupAnalyzer(self.disordered_structure, 0.001) s = p.structure.copy() site = s[0] del s[0] s.append(site.species_and_occu, site.frac_coords) self.sg3 = SpacegroupAnalyzer(s, 0.001) graphite = self.get_structure('Graphite') graphite.add_site_property("magmom", [0.1] * len(graphite)) self.sg4 = SpacegroupAnalyzer(graphite, 0.001) self.structure4 = graphite def test_primitive(self): s = Structure.from_spacegroup("Fm-3m", np.eye(3) * 3, ["Cu"], [[0, 0, 0]]) a = SpacegroupAnalyzer(s) self.assertEqual(len(s), 4) self.assertEqual(len(a.find_primitive()), 1) def test_is_laue(self): s = Structure.from_spacegroup("Fm-3m", np.eye(3) * 3, ["Cu"], [[0, 0, 0]]) a = SpacegroupAnalyzer(s) self.assertTrue(a.is_laue()) def test_magnetic(self): lfp = PymatgenTest.get_structure("LiFePO4") sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_space_group_symbol(), "Pnma") magmoms = [0] * len(lfp) magmoms[4] = 1 magmoms[5] = -1 magmoms[6] = 1 magmoms[7] = -1 lfp.add_site_property("magmom", magmoms) sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_space_group_symbol(), "Pnma") def test_get_space_symbol(self): self.assertEqual(self.sg.get_space_group_symbol(), "Pnma") self.assertEqual(self.disordered_sg.get_space_group_symbol(), "P4_2/nmc") self.assertEqual(self.sg3.get_space_group_symbol(), "Pnma") self.assertEqual(self.sg4.get_space_group_symbol(), "P6_3/mmc") def test_get_space_number(self): self.assertEqual(self.sg.get_space_group_number(), 62) self.assertEqual(self.disordered_sg.get_space_group_number(), 137) self.assertEqual(self.sg4.get_space_group_number(), 194) def test_get_hall(self): self.assertEqual(self.sg.get_hall(), '-P 2ac 2n') self.assertEqual(self.disordered_sg.get_hall(), 'P 4n 2n -1n') def test_get_pointgroup(self): self.assertEqual(self.sg.get_point_group_symbol(), 'mmm') self.assertEqual(self.disordered_sg.get_point_group_symbol(), '4/mmm') def test_get_symmetry_operations(self): coordinates = np.array([[0.5, 0.0, 0.0], [0.0, 0.5, 0.0], [0.5, 1.0, 0.0], [1.0, 0.5, 0.0]]) species = ['H'] * len(coordinates) molecule = Molecule(species, coordinates) so = PointGroupAnalyzer(molecule, 0.3).get_symmetry_operations() self.assertEqual(len(so), 16) # D4h contains 16 symmetry elements for o in so: self.assertEqual(isinstance(o, SymmOp), True) def test_get_symmetry_dataset(self): ds = self.sg.get_symmetry_dataset() self.assertEqual(ds['international'], 'Pnma') def test_get_crystal_system(self): crystal_system = self.sg.get_crystal_system() self.assertEqual('orthorhombic', crystal_system) self.assertEqual('tetragonal', self.disordered_sg.get_crystal_system()) def test_get_symmetry_operations(self): for sg, structure in [(self.sg, self.structure), (self.sg4, self.structure4)]: pgops = sg.get_point_group_operations() fracsymmops = sg.get_symmetry_operations() symmops = sg.get_symmetry_operations(True) latt = structure.lattice for fop, op, pgop in zip(fracsymmops, symmops, pgops): # translation vector values should all be 0 or 0.5 t = fop.translation_vector * 2 self.assertArrayAlmostEqual(t - np.round(t), 0) self.assertArrayAlmostEqual(fop.rotation_matrix, pgop.rotation_matrix) for site in structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue( np.allclose(latt.get_fractional_coords(newcart), newfrac)) found = False newsite = PeriodicSite(site.species_and_occu, newcart, latt, coords_are_cartesian=True) for testsite in structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) # Make sure this works for any position, not just the atomic # ones. random_fcoord = np.random.uniform(size=(3)) random_ccoord = latt.get_cartesian_coords(random_fcoord) newfrac = fop.operate(random_fcoord) newcart = op.operate(random_ccoord) self.assertTrue( np.allclose(latt.get_fractional_coords(newcart), newfrac)) def test_get_refined_structure(self): for a in self.sg.get_refined_structure().lattice.angles: self.assertEqual(a, 90) refined = self.disordered_sg.get_refined_structure() for a in refined.lattice.angles: self.assertEqual(a, 90) self.assertEqual(refined.lattice.a, refined.lattice.b) s = self.get_structure('Li2O') sg = SpacegroupAnalyzer(s, 0.01) self.assertEqual(sg.get_refined_structure().num_sites, 4 * s.num_sites) def test_get_symmetrized_structure(self): symm_struct = self.sg.get_symmetrized_structure() for a in symm_struct.lattice.angles: self.assertEqual(a, 90) self.assertEqual(len(symm_struct.equivalent_sites), 5) symm_struct = self.disordered_sg.get_symmetrized_structure() self.assertEqual(len(symm_struct.equivalent_sites), 8) self.assertEqual([len(i) for i in symm_struct.equivalent_sites], [16, 4, 8, 4, 2, 8, 8, 8]) s1 = symm_struct.equivalent_sites[1][1] s2 = symm_struct[symm_struct.equivalent_indices[1][1]] self.assertEqual(s1, s2) self.assertEqual(self.sg4.get_symmetrized_structure()[0].magmom, 0.1) self.assertEqual(symm_struct.wyckoff_symbols[0], '16h') # self.assertEqual(symm_struct[0].wyckoff, "16h") def test_find_primitive(self): """ F m -3 m Li2O testing of converting to primitive cell """ parser = CifParser(os.path.join(test_dir, 'Li2O.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive() self.assertEqual(primitive_structure.formula, "Li2 O1") # This isn't what is expected. All the angles should be 60 self.assertAlmostEqual(primitive_structure.lattice.alpha, 60) self.assertAlmostEqual(primitive_structure.lattice.beta, 60) self.assertAlmostEqual(primitive_structure.lattice.gamma, 60) self.assertAlmostEqual(primitive_structure.lattice.volume, structure.lattice.volume / 4.0) def test_get_ir_reciprocal_mesh(self): grid = self.sg.get_ir_reciprocal_mesh() self.assertEqual(len(grid), 216) self.assertAlmostEqual(grid[1][0][0], 0.1) self.assertAlmostEqual(grid[1][0][1], 0.0) self.assertAlmostEqual(grid[1][0][2], 0.0) self.assertAlmostEqual(grid[1][1], 2) def test_get_conventional_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.b, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.c, 9.1980270633769461) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.b, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.c, 4.2327080177761687) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 2.9542233922299999) self.assertAlmostEqual(conv.lattice.b, 4.6330325651443296) self.assertAlmostEqual(conv.lattice.c, 5.373703587040775) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 4.1430033493799998) self.assertAlmostEqual(conv.lattice.b, 31.437979757624728) self.assertAlmostEqual(conv.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'orac_632475.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 3.1790663399999999) self.assertAlmostEqual(conv.lattice.b, 9.9032878699999998) self.assertAlmostEqual(conv.lattice.c, 3.5372412099999999) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 117.53832420192903) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 14.033435583000625) self.assertAlmostEqual(conv.lattice.b, 3.96052850731) self.assertAlmostEqual(conv.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'hex_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 120) self.assertAlmostEqual(conv.lattice.a, 3.699919902005897) self.assertAlmostEqual(conv.lattice.b, 3.699919902005897) self.assertAlmostEqual(conv.lattice.c, 6.9779585500000003) def test_get_primitive_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 109.47122063400001) self.assertAlmostEqual(prim.lattice.beta, 109.47122063400001) self.assertAlmostEqual(prim.lattice.gamma, 109.47122063400001) self.assertAlmostEqual(prim.lattice.a, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.b, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.c, 7.9657251015812145) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 105.015053349) self.assertAlmostEqual(prim.lattice.beta, 105.015053349) self.assertAlmostEqual(prim.lattice.gamma, 118.80658411899999) self.assertAlmostEqual(prim.lattice.a, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.b, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.c, 4.1579321075608791) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 134.78923546600001) self.assertAlmostEqual(prim.lattice.beta, 105.856239333) self.assertAlmostEqual(prim.lattice.gamma, 91.276341676000001) self.assertAlmostEqual(prim.lattice.a, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.b, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.c, 3.8428217771014852) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 164.985257335) self.assertAlmostEqual(prim.lattice.a, 15.854897098324196) self.assertAlmostEqual(prim.lattice.b, 15.854897098324196) self.assertAlmostEqual(prim.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'orac_632475.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 144.40557588533386) self.assertAlmostEqual(prim.lattice.a, 5.2005185662155391) self.assertAlmostEqual(prim.lattice.b, 5.2005185662155391) self.assertAlmostEqual(prim.lattice.c, 3.5372412099999999) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 63.579155761999999) self.assertAlmostEqual(prim.lattice.beta, 116.42084423747779) self.assertAlmostEqual(prim.lattice.gamma, 148.47965136208569) self.assertAlmostEqual(prim.lattice.a, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.b, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'hex_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 120) self.assertAlmostEqual(prim.lattice.a, 3.699919902005897) self.assertAlmostEqual(prim.lattice.b, 3.699919902005897) self.assertAlmostEqual(prim.lattice.c, 6.9779585500000003) parser = CifParser(os.path.join(test_dir, 'rhomb_3478_conv.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 28.049186140546812) self.assertAlmostEqual(prim.lattice.beta, 28.049186140546812) self.assertAlmostEqual(prim.lattice.gamma, 28.049186140546812) self.assertAlmostEqual(prim.lattice.a, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.b, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.c, 5.9352627428399982)
class SpacegroupAnalyzerTest(PymatgenTest): def setUp(self): p = Poscar.from_file( os.path.join(PymatgenTest.TEST_FILES_DIR, "POSCAR")) self.structure = p.structure self.sg = SpacegroupAnalyzer(self.structure, 0.001) self.disordered_structure = self.get_structure("Li10GeP2S12") self.disordered_sg = SpacegroupAnalyzer(self.disordered_structure, 0.001) s = p.structure.copy() site = s[0] del s[0] s.append(site.species, site.frac_coords) self.sg3 = SpacegroupAnalyzer(s, 0.001) graphite = self.get_structure("Graphite") graphite.add_site_property("magmom", [0.1] * len(graphite)) self.sg4 = SpacegroupAnalyzer(graphite, 0.001) self.structure4 = graphite def test_primitive(self): s = Structure.from_spacegroup("Fm-3m", np.eye(3) * 3, ["Cu"], [[0, 0, 0]]) a = SpacegroupAnalyzer(s) self.assertEqual(len(s), 4) self.assertEqual(len(a.find_primitive()), 1) def test_is_laue(self): s = Structure.from_spacegroup("Fm-3m", np.eye(3) * 3, ["Cu"], [[0, 0, 0]]) a = SpacegroupAnalyzer(s) self.assertTrue(a.is_laue()) def test_magnetic(self): lfp = PymatgenTest.get_structure("LiFePO4") sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_space_group_symbol(), "Pnma") magmoms = [0] * len(lfp) magmoms[4] = 1 magmoms[5] = -1 magmoms[6] = 1 magmoms[7] = -1 lfp.add_site_property("magmom", magmoms) sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_space_group_symbol(), "Pnma") def test_get_space_symbol(self): self.assertEqual(self.sg.get_space_group_symbol(), "Pnma") self.assertEqual(self.disordered_sg.get_space_group_symbol(), "P4_2/nmc") self.assertEqual(self.sg3.get_space_group_symbol(), "Pnma") self.assertEqual(self.sg4.get_space_group_symbol(), "P6_3/mmc") def test_get_space_number(self): self.assertEqual(self.sg.get_space_group_number(), 62) self.assertEqual(self.disordered_sg.get_space_group_number(), 137) self.assertEqual(self.sg4.get_space_group_number(), 194) def test_get_hall(self): self.assertEqual(self.sg.get_hall(), "-P 2ac 2n") self.assertEqual(self.disordered_sg.get_hall(), "P 4n 2n -1n") def test_get_pointgroup(self): self.assertEqual(self.sg.get_point_group_symbol(), "mmm") self.assertEqual(self.disordered_sg.get_point_group_symbol(), "4/mmm") def test_get_symmetry_operations(self): for sg, structure in [(self.sg, self.structure), (self.sg4, self.structure4)]: pgops = sg.get_point_group_operations() fracsymmops = sg.get_symmetry_operations() symmops = sg.get_symmetry_operations(True) latt = structure.lattice for fop, op, pgop in zip(fracsymmops, symmops, pgops): # translation vector values should all be 0 or 0.5 t = fop.translation_vector * 2 self.assertArrayAlmostEqual(t - np.round(t), 0) self.assertArrayAlmostEqual(fop.rotation_matrix, pgop.rotation_matrix) for site in structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue( np.allclose(latt.get_fractional_coords(newcart), newfrac)) found = False newsite = PeriodicSite(site.species, newcart, latt, coords_are_cartesian=True) for testsite in structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) # Make sure this works for any position, not just the atomic # ones. random_fcoord = np.random.uniform(size=(3)) random_ccoord = latt.get_cartesian_coords(random_fcoord) newfrac = fop.operate(random_fcoord) newcart = op.operate(random_ccoord) self.assertTrue( np.allclose(latt.get_fractional_coords(newcart), newfrac)) def test_get_symmetry_dataset(self): ds = self.sg.get_symmetry_dataset() self.assertEqual(ds["international"], "Pnma") def test_get_crystal_system(self): crystal_system = self.sg.get_crystal_system() self.assertEqual("orthorhombic", crystal_system) self.assertEqual("tetragonal", self.disordered_sg.get_crystal_system()) orig_spg = self.sg._space_group_data["number"] self.sg._space_group_data["number"] = 0 try: crystal_system = self.sg.get_crystal_system() except ValueError as exc: self.assertEqual(str(exc), "Received invalid space group 0") finally: self.sg._space_group_data["number"] = orig_spg def test_get_refined_structure(self): for a in self.sg.get_refined_structure().lattice.angles: self.assertEqual(a, 90) refined = self.disordered_sg.get_refined_structure() for a in refined.lattice.angles: self.assertEqual(a, 90) self.assertEqual(refined.lattice.a, refined.lattice.b) structure = self.get_structure("Li2O") structure.add_site_property("magmom", [1.0] * len(structure)) sg = SpacegroupAnalyzer(structure, 0.01) refined_struct = sg.get_refined_structure(keep_site_properties=True) self.assertEqual(refined_struct.site_properties["magmom"], [1.0] * len(refined_struct)) structure = self.get_structure("Li2O") structure.add_site_property("magmom", [1.0] * len(structure)) sg = SpacegroupAnalyzer(structure, 0.01) refined_struct = sg.get_refined_structure(keep_site_properties=False) self.assertEqual(refined_struct.site_properties.get("magmom", None), None) def test_get_symmetrized_structure(self): symm_struct = self.sg.get_symmetrized_structure() for a in symm_struct.lattice.angles: self.assertEqual(a, 90) self.assertEqual(len(symm_struct.equivalent_sites), 5) symm_struct = self.disordered_sg.get_symmetrized_structure() self.assertEqual(len(symm_struct.equivalent_sites), 8) self.assertEqual([len(i) for i in symm_struct.equivalent_sites], [16, 4, 8, 4, 2, 8, 8, 8]) s1 = symm_struct.equivalent_sites[1][1] s2 = symm_struct[symm_struct.equivalent_indices[1][1]] self.assertEqual(s1, s2) self.assertEqual(self.sg4.get_symmetrized_structure()[0].magmom, 0.1) self.assertEqual(symm_struct.wyckoff_symbols[0], "16h") # self.assertEqual(symm_struct[0].wyckoff, "16h") # Check copying self.assertEqual(symm_struct.copy(), symm_struct) d = symm_struct.as_dict() from pymatgen.symmetry.structure import SymmetrizedStructure ss = SymmetrizedStructure.from_dict(d) self.assertEqual(ss.wyckoff_symbols[0], "16h") self.assertIn("SymmetrizedStructure", ss.__str__()) def test_find_primitive(self): """ F m -3 m Li2O testing of converting to primitive cell """ parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "Li2O.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive() self.assertEqual(primitive_structure.formula, "Li2 O1") self.assertTrue( primitive_structure.site_properties.get("magmom", None) is None) # This isn't what is expected. All the angles should be 60 self.assertAlmostEqual(primitive_structure.lattice.alpha, 60) self.assertAlmostEqual(primitive_structure.lattice.beta, 60) self.assertAlmostEqual(primitive_structure.lattice.gamma, 60) self.assertAlmostEqual(primitive_structure.lattice.volume, structure.lattice.volume / 4.0) structure = parser.get_structures(False)[0] structure.add_site_property("magmom", [1.0] * len(structure)) s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive(keep_site_properties=True) self.assertEqual(primitive_structure.site_properties["magmom"], [1.0] * len(primitive_structure)) structure = parser.get_structures(False)[0] structure.add_site_property("magmom", [1.0] * len(structure)) s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive(keep_site_properties=False) self.assertEqual( primitive_structure.site_properties.get("magmom", None), None) def test_get_ir_reciprocal_mesh(self): grid = self.sg.get_ir_reciprocal_mesh() self.assertEqual(len(grid), 216) self.assertAlmostEqual(grid[1][0][0], 0.1) self.assertAlmostEqual(grid[1][0][1], 0.0) self.assertAlmostEqual(grid[1][0][2], 0.0) self.assertAlmostEqual(grid[1][1], 2) def test_get_conventional_standard_structure(self): parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "bcc_1927.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.b, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.c, 9.1980270633769461) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "btet_1915.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.b, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.c, 4.2327080177761687) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "orci_1010.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 2.9542233922299999) self.assertAlmostEqual(conv.lattice.b, 4.6330325651443296) self.assertAlmostEqual(conv.lattice.c, 5.373703587040775) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "orcc_1003.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 4.1430033493799998) self.assertAlmostEqual(conv.lattice.b, 31.437979757624728) self.assertAlmostEqual(conv.lattice.c, 3.99648651) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "orac_632475.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 3.1790663399999999) self.assertAlmostEqual(conv.lattice.b, 9.9032878699999998) self.assertAlmostEqual(conv.lattice.c, 3.5372412099999999) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "monoc_1028.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 117.53832420192903) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 14.033435583000625) self.assertAlmostEqual(conv.lattice.b, 3.96052850731) self.assertAlmostEqual(conv.lattice.c, 6.8743926325200002) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "hex_1170.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 120) self.assertAlmostEqual(conv.lattice.a, 3.699919902005897) self.assertAlmostEqual(conv.lattice.b, 3.699919902005897) self.assertAlmostEqual(conv.lattice.c, 6.9779585500000003) structure = Structure.from_file( os.path.join(PymatgenTest.TEST_FILES_DIR, "tric_684654.json")) s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 74.09581916308757) self.assertAlmostEqual(conv.lattice.beta, 75.72817279281173) self.assertAlmostEqual(conv.lattice.gamma, 63.63234318667333) self.assertAlmostEqual(conv.lattice.a, 3.741372924048738) self.assertAlmostEqual(conv.lattice.b, 3.9883228679270686) self.assertAlmostEqual(conv.lattice.c, 7.288495840048958) structure = Structure.from_file( os.path.join(PymatgenTest.TEST_FILES_DIR, "tric_684654.json")) structure.add_site_property("magmom", [1.0] * len(structure)) s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure(keep_site_properties=True) self.assertEqual(conv.site_properties["magmom"], [1.0] * len(conv)) structure = Structure.from_file( os.path.join(PymatgenTest.TEST_FILES_DIR, "tric_684654.json")) structure.add_site_property("magmom", [1.0] * len(structure)) s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure( keep_site_properties=False) self.assertEqual(conv.site_properties.get("magmom", None), None) def test_get_primitive_standard_structure(self): parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "bcc_1927.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 109.47122063400001) self.assertAlmostEqual(prim.lattice.beta, 109.47122063400001) self.assertAlmostEqual(prim.lattice.gamma, 109.47122063400001) self.assertAlmostEqual(prim.lattice.a, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.b, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.c, 7.9657251015812145) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "btet_1915.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 105.015053349) self.assertAlmostEqual(prim.lattice.beta, 105.015053349) self.assertAlmostEqual(prim.lattice.gamma, 118.80658411899999) self.assertAlmostEqual(prim.lattice.a, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.b, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.c, 4.1579321075608791) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "orci_1010.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 134.78923546600001) self.assertAlmostEqual(prim.lattice.beta, 105.856239333) self.assertAlmostEqual(prim.lattice.gamma, 91.276341676000001) self.assertAlmostEqual(prim.lattice.a, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.b, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.c, 3.8428217771014852) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "orcc_1003.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 164.985257335) self.assertAlmostEqual(prim.lattice.a, 15.854897098324196) self.assertAlmostEqual(prim.lattice.b, 15.854897098324196) self.assertAlmostEqual(prim.lattice.c, 3.99648651) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "orac_632475.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 144.40557588533386) self.assertAlmostEqual(prim.lattice.a, 5.2005185662155391) self.assertAlmostEqual(prim.lattice.b, 5.2005185662155391) self.assertAlmostEqual(prim.lattice.c, 3.5372412099999999) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "monoc_1028.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 63.579155761999999) self.assertAlmostEqual(prim.lattice.beta, 116.42084423747779) self.assertAlmostEqual(prim.lattice.gamma, 148.47965136208569) self.assertAlmostEqual(prim.lattice.a, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.b, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.c, 6.8743926325200002) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "hex_1170.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 120) self.assertAlmostEqual(prim.lattice.a, 3.699919902005897) self.assertAlmostEqual(prim.lattice.b, 3.699919902005897) self.assertAlmostEqual(prim.lattice.c, 6.9779585500000003) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "rhomb_3478_conv.cif")) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 28.049186140546812) self.assertAlmostEqual(prim.lattice.beta, 28.049186140546812) self.assertAlmostEqual(prim.lattice.gamma, 28.049186140546812) self.assertAlmostEqual(prim.lattice.a, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.b, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.c, 5.9352627428399982) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "rhomb_3478_conv.cif")) structure = parser.get_structures(False)[0] structure.add_site_property("magmom", [1.0] * len(structure)) s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure(keep_site_properties=True) self.assertEqual(prim.site_properties["magmom"], [1.0] * len(prim)) parser = CifParser( os.path.join(PymatgenTest.TEST_FILES_DIR, "rhomb_3478_conv.cif")) structure = parser.get_structures(False)[0] structure.add_site_property("magmom", [1.0] * len(structure)) s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure(keep_site_properties=False) self.assertEqual(prim.site_properties.get("magmom", None), None) def test_tricky_structure(self): # for some reason this structure kills spglib1.9 # 1.7 can't find symmetry either, but at least doesn't kill python s = Structure.from_file( os.path.join(PymatgenTest.TEST_FILES_DIR, "POSCAR.tricky_symmetry")) sa = SpacegroupAnalyzer(s, 0.1) sa.get_space_group_symbol() sa.get_space_group_number() sa.get_point_group_symbol() sa.get_crystal_system() sa.get_hall()
def convert_to_ieee(self, structure, atol = 0.1, ltol = 0.05): """ Given a structure associated with a tensor, attempts a calculation of the tensor in IEEE format according to the 1987 IEEE standards. Args: structure (Structure): a structure associated with the tensor to be converted to the IEEE standard atol (float): angle tolerance for conversion routines ltol (float): length tolerance for conversion routines """ def get_uvec(vec): """ Gets a unit vector parallel to input vector""" return vec / np.linalg.norm(vec) # Check conventional setting: sga = SpacegroupAnalyzer(structure) dataset = sga.get_symmetry_dataset() trans_mat = dataset['transformation_matrix'] conv_latt = Lattice(np.transpose(np.dot(np.transpose( structure.lattice.matrix), np.linalg.inv(trans_mat)))) xtal_sys = sga.get_crystal_system() vecs = conv_latt.matrix lengths = np.array(conv_latt.abc) angles = np.array(conv_latt.angles) a = b = c = None rotation = np.zeros((3,3)) # IEEE rules: a,b,c || x1,x2,x3 if xtal_sys == "cubic": rotation = [vecs[i]/lengths[i] for i in range(3)] # IEEE rules: a=b in length; c,a || x3, x1 elif xtal_sys == "tetragonal": rotation = np.array([vec/mag for (mag, vec) in sorted(zip(lengths, vecs))]) if abs(lengths[2] - lengths[1]) < ltol: rotation[0], rotation[2] = rotation[2], rotation[0].copy() rotation[1] = get_uvec(np.cross(rotation[2], rotation[0])) # IEEE rules: c<a<b; c,a || x3,x1 elif xtal_sys == "orthorhombic": rotation = [vec/mag for (mag, vec) in sorted(zip(lengths, vecs))] rotation = np.roll(rotation, 2, axis = 0) # IEEE rules: c,a || x3,x1, c is threefold axis # Note this also includes rhombohedral crystal systems elif xtal_sys in ("trigonal", "hexagonal"): # find threefold axis: tf_mask = abs(angles-120.0) < atol non_tf_mask = np.logical_not(tf_mask) rotation[2] = get_uvec(vecs[tf_mask][0]) rotation[0] = get_uvec(vecs[non_tf_mask][0]) rotation[1] = get_uvec(np.cross(rotation[2], rotation[0])) # IEEE rules: b,c || x2,x3; alpha=beta=90, c<a elif xtal_sys == "monoclinic": # Find unique axis umask = abs(angles - 90.0) > atol n_umask = np.logical_not(umask) rotation[1] = get_uvec(vecs[umask]) # Shorter of remaining lattice vectors for c axis c = [vec/mag for (mag, vec) in sorted(zip(lengths[n_umask], vecs[n_umask]))][0] rotation[2] = np.array(c) rotation[0] = np.cross(rotation[1], rotation[2]) # IEEE rules: c || x3 elif xtal_sys == "triclinic": rotation = [vec/mag for (mag, vec) in sorted(zip(lengths, vecs))] rotation = np.roll(rotation, 2, axis = 0) rotation[1] = get_uvec(np.cross(rotation[2], rotation[1])) rotation[0] = np.cross(rotation[1], rotation[2]) return self.rotate(rotation)
def convert_to_ieee(self, structure, initial_fit=True): """ Given a structure associated with a tensor, attempts a calculation of the tensor in IEEE format according to the 1987 IEEE standards. Args: structure (Structure): a structure associated with the tensor to be converted to the IEEE standard initial_fit (bool): flag to indicate whether initial tensor is fit to the symmetry of the structure. Defaults to true. Note that if false, inconsistent results may be obtained due to symmetrically equivalent, but distinct transformations being used in different versions of spglib. """ def get_uvec(v): """ Gets a unit vector parallel to input vector""" l = np.linalg.norm(v) if l < 1e-8: return v return v / l # Check conventional setting: sga = SpacegroupAnalyzer(structure) dataset = sga.get_symmetry_dataset() trans_mat = dataset['transformation_matrix'] conv_latt = Lattice(np.transpose(np.dot(np.transpose( structure.lattice.matrix), np.linalg.inv(trans_mat)))) xtal_sys = sga.get_crystal_system() vecs = conv_latt.matrix lengths = np.array(conv_latt.abc) angles = np.array(conv_latt.angles) rotation = np.zeros((3, 3)) # IEEE rules: a,b,c || x1,x2,x3 if xtal_sys == "cubic": rotation = [vecs[i] / lengths[i] for i in range(3)] # IEEE rules: a=b in length; c,a || x3, x1 elif xtal_sys == "tetragonal": rotation = np.array([vec / mag for (mag, vec) in sorted(zip(lengths, vecs), key=lambda x: x[0])]) if abs(lengths[2] - lengths[1]) < abs(lengths[1] - lengths[0]): rotation[0], rotation[2] = rotation[2], rotation[0].copy() rotation[1] = get_uvec(np.cross(rotation[2], rotation[0])) # IEEE rules: c<a<b; c,a || x3,x1 elif xtal_sys == "orthorhombic": rotation = [vec / mag for (mag, vec) in sorted(zip(lengths, vecs))] rotation = np.roll(rotation, 2, axis=0) # IEEE rules: c,a || x3,x1, c is threefold axis # Note this also includes rhombohedral crystal systems elif xtal_sys in ("trigonal", "hexagonal"): # find threefold axis: tf_index = np.argmin(abs(angles - 120.)) non_tf_mask = np.logical_not(angles == angles[tf_index]) rotation[2] = get_uvec(vecs[tf_index]) rotation[0] = get_uvec(vecs[non_tf_mask][0]) rotation[1] = get_uvec(np.cross(rotation[2], rotation[0])) # IEEE rules: b,c || x2,x3; alpha=beta=90, c<a elif xtal_sys == "monoclinic": # Find unique axis u_index = np.argmax(abs(angles - 90.)) n_umask = np.logical_not(angles == angles[u_index]) rotation[1] = get_uvec(vecs[u_index]) # Shorter of remaining lattice vectors for c axis c = [vec / mag for (mag, vec) in sorted(zip(lengths[n_umask], vecs[n_umask]))][0] rotation[2] = np.array(c) rotation[0] = np.cross(rotation[1], rotation[2]) # IEEE rules: c || x3 elif xtal_sys == "triclinic": rotation = [vec / mag for (mag, vec) in sorted(zip(lengths, vecs))] rotation = np.roll(rotation, 2, axis=0) rotation[1] = get_uvec(np.cross(rotation[2], rotation[1])) rotation[0] = np.cross(rotation[1], rotation[2]) result = self.copy() if initial_fit: result = result.fit_to_structure(structure) return result.rotate(rotation, tol=1e-2)
def get_ieee_rotation(structure, refine_rotation=True): """ Given a structure associated with a tensor, determines the rotation matrix for IEEE conversion according to the 1987 IEEE standards. Args: structure (Structure): a structure associated with the tensor to be converted to the IEEE standard refine_rotation (bool): whether to refine the rotation using SquareTensor.refine_rotation """ # Check conventional setting: sga = SpacegroupAnalyzer(structure) dataset = sga.get_symmetry_dataset() trans_mat = dataset['transformation_matrix'] conv_latt = Lattice(np.transpose(np.dot(np.transpose( structure.lattice.matrix), np.linalg.inv(trans_mat)))) xtal_sys = sga.get_crystal_system() vecs = conv_latt.matrix lengths = np.array(conv_latt.abc) angles = np.array(conv_latt.angles) rotation = np.zeros((3, 3)) # IEEE rules: a,b,c || x1,x2,x3 if xtal_sys == "cubic": rotation = [vecs[i] / lengths[i] for i in range(3)] # IEEE rules: a=b in length; c,a || x3, x1 elif xtal_sys == "tetragonal": rotation = np.array([vec / mag for (mag, vec) in sorted(zip(lengths, vecs), key=lambda x: x[0])]) if abs(lengths[2] - lengths[1]) < abs(lengths[1] - lengths[0]): rotation[0], rotation[2] = rotation[2], rotation[0].copy() rotation[1] = get_uvec(np.cross(rotation[2], rotation[0])) # IEEE rules: c<a<b; c,a || x3,x1 elif xtal_sys == "orthorhombic": rotation = [vec / mag for (mag, vec) in sorted(zip(lengths, vecs))] rotation = np.roll(rotation, 2, axis=0) # IEEE rules: c,a || x3,x1, c is threefold axis # Note this also includes rhombohedral crystal systems elif xtal_sys in ("trigonal", "hexagonal"): # find threefold axis: tf_index = np.argmin(abs(angles - 120.)) non_tf_mask = np.logical_not(angles == angles[tf_index]) rotation[2] = get_uvec(vecs[tf_index]) rotation[0] = get_uvec(vecs[non_tf_mask][0]) rotation[1] = get_uvec(np.cross(rotation[2], rotation[0])) # IEEE rules: b,c || x2,x3; alpha=beta=90, c<a elif xtal_sys == "monoclinic": # Find unique axis u_index = np.argmax(abs(angles - 90.)) n_umask = np.logical_not(angles == angles[u_index]) rotation[1] = get_uvec(vecs[u_index]) # Shorter of remaining lattice vectors for c axis c = [vec / mag for (mag, vec) in sorted(zip(lengths[n_umask], vecs[n_umask]))][0] rotation[2] = np.array(c) rotation[0] = np.cross(rotation[1], rotation[2]) # IEEE rules: c || x3 elif xtal_sys == "triclinic": rotation = [vec / mag for (mag, vec) in sorted(zip(lengths, vecs))] rotation = np.roll(rotation, 2, axis=0) rotation[1] = get_uvec(np.cross(rotation[2], rotation[1])) rotation[0] = np.cross(rotation[1], rotation[2]) rotation = SquareTensor(rotation) if refine_rotation: rotation = rotation.refine_rotation() return rotation
class SpacegroupAnalyzerTest(PymatgenTest): def setUp(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) self.structure = p.structure self.sg = SpacegroupAnalyzer(self.structure, 0.001) self.disordered_structure = self.get_structure('Li10GeP2S12') self.disordered_sg = SpacegroupAnalyzer(self.disordered_structure, 0.001) s = p.structure.copy() site = s[0] del s[0] s.append(site.species_and_occu, site.frac_coords) self.sg3 = SpacegroupAnalyzer(s, 0.001) graphite = self.get_structure('Graphite') graphite.add_site_property("magmom", [0.1] * len(graphite)) self.sg4 = SpacegroupAnalyzer(graphite, 0.001) def test_get_space_symbol(self): self.assertEqual(self.sg.get_spacegroup_symbol(), "Pnma") self.assertEqual(self.disordered_sg.get_spacegroup_symbol(), "P4_2/nmc") self.assertEqual(self.sg3.get_spacegroup_symbol(), "Pnma") self.assertEqual(self.sg4.get_spacegroup_symbol(), "R-3m") def test_get_space_number(self): self.assertEqual(self.sg.get_spacegroup_number(), 62) self.assertEqual(self.disordered_sg.get_spacegroup_number(), 137) self.assertEqual(self.sg4.get_spacegroup_number(), 166) def test_get_hall(self): self.assertEqual(self.sg.get_hall(), '-P 2ac 2n') self.assertEqual(self.disordered_sg.get_hall(), 'P 4n 2n -1n') def test_get_pointgroup(self): self.assertEqual(self.sg.get_point_group(), 'mmm') self.assertEqual(self.disordered_sg.get_point_group(), '4/mmm') def test_get_symmetry_dataset(self): ds = self.sg.get_symmetry_dataset() self.assertEqual(ds['international'], 'Pnma') def test_get_crystal_system(self): crystal_system = self.sg.get_crystal_system() self.assertEqual('orthorhombic', crystal_system) self.assertEqual('tetragonal', self.disordered_sg.get_crystal_system()) def test_get_symmetry_operations(self): fracsymmops = self.sg.get_symmetry_operations() symmops = self.sg.get_symmetry_operations(True) self.assertEqual(len(symmops), 8) latt = self.structure.lattice for fop, op in zip(fracsymmops, symmops): for site in self.structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac)) found = False newsite = PeriodicSite(site.species_and_occu, newcart, latt, coords_are_cartesian=True) for testsite in self.structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) def test_get_refined_structure(self): for a in self.sg.get_refined_structure().lattice.angles: self.assertEqual(a, 90) refined = self.disordered_sg.get_refined_structure() for a in refined.lattice.angles: self.assertEqual(a, 90) self.assertEqual(refined.lattice.a, refined.lattice.b) s = self.get_structure('Li2O') sg = SpacegroupAnalyzer(s, 0.001) self.assertEqual(sg.get_refined_structure().num_sites, 4 * s.num_sites) def test_get_symmetrized_structure(self): symm_struct = self.sg.get_symmetrized_structure() for a in symm_struct.lattice.angles: self.assertEqual(a, 90) self.assertEqual(len(symm_struct.equivalent_sites), 5) symm_struct = self.disordered_sg.get_symmetrized_structure() self.assertEqual(len(symm_struct.equivalent_sites), 8) self.assertEqual([len(i) for i in symm_struct.equivalent_sites], [16,4,8,4,2,8,8,8]) s1 = symm_struct.equivalent_sites[1][1] s2 = symm_struct[symm_struct.equivalent_indices[1][1]] self.assertEqual(s1, s2) self.assertEqual(self.sg4.get_symmetrized_structure()[0].magmom, 0.1) def test_find_primitive(self): """ F m -3 m Li2O testing of converting to primitive cell """ parser = CifParser(os.path.join(test_dir, 'Li2O.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive() self.assertEqual(primitive_structure.formula, "Li2 O1") # This isn't what is expected. All the angles should be 60 self.assertAlmostEqual(primitive_structure.lattice.alpha, 60) self.assertAlmostEqual(primitive_structure.lattice.beta, 60) self.assertAlmostEqual(primitive_structure.lattice.gamma, 60) self.assertAlmostEqual(primitive_structure.lattice.volume, structure.lattice.volume / 4.0) def test_get_ir_reciprocal_mesh(self): grid=self.sg.get_ir_reciprocal_mesh() self.assertEqual(len(grid), 216) self.assertAlmostEquals(grid[1][0][0], 0.1) self.assertAlmostEquals(grid[1][0][1], 0.0) self.assertAlmostEquals(grid[1][0][2], 0.0) self.assertEqual(grid[1][1], 2) def test_get_conventional_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.b, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.c, 9.1980270633769461) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.b, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.c, 4.2327080177761687) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 2.9542233922299999) self.assertAlmostEqual(conv.lattice.b, 4.6330325651443296) self.assertAlmostEqual(conv.lattice.c, 5.373703587040775) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 4.1430033493799998) self.assertAlmostEqual(conv.lattice.b, 31.437979757624728) self.assertAlmostEqual(conv.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 117.53832420192903) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 14.033435583000625) self.assertAlmostEqual(conv.lattice.b, 3.96052850731) self.assertAlmostEqual(conv.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'rhomb_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 120) self.assertAlmostEqual(conv.lattice.a, 3.699919902005897) self.assertAlmostEqual(conv.lattice.b, 3.699919902005897) self.assertAlmostEqual(conv.lattice.c, 6.9779585500000003) def test_get_primitive_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 109.47122063400001) self.assertAlmostEqual(prim.lattice.beta, 109.47122063400001) self.assertAlmostEqual(prim.lattice.gamma, 109.47122063400001) self.assertAlmostEqual(prim.lattice.a, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.b, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.c, 7.9657251015812145) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 105.015053349) self.assertAlmostEqual(prim.lattice.beta, 105.015053349) self.assertAlmostEqual(prim.lattice.gamma, 118.80658411899999) self.assertAlmostEqual(prim.lattice.a, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.b, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.c, 4.1579321075608791) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 134.78923546600001) self.assertAlmostEqual(prim.lattice.beta, 105.856239333) self.assertAlmostEqual(prim.lattice.gamma, 91.276341676000001) self.assertAlmostEqual(prim.lattice.a, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.b, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.c, 3.8428217771014852) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 164.985257335) self.assertAlmostEqual(prim.lattice.a, 15.854897098324196) self.assertAlmostEqual(prim.lattice.b, 15.854897098324196) self.assertAlmostEqual(prim.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 63.579155761999999) self.assertAlmostEqual(prim.lattice.beta, 116.42084423747779) self.assertAlmostEqual(prim.lattice.gamma, 148.47965136208569) self.assertAlmostEqual(prim.lattice.a, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.b, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'rhomb_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 120) self.assertAlmostEqual(prim.lattice.a, 3.699919902005897) self.assertAlmostEqual(prim.lattice.b, 3.699919902005897) self.assertAlmostEqual(prim.lattice.c, 6.9779585500000003)