def get_spacegroup_type(hall_number): """ Get space group information corresponding to the Hall number. Args: hall_number: Integer with the Hall number. Returns: Dictionary with the corresponding space group information. Keys: - `arithmetic_crystal_class_number` - `arithmetic_crystal_class_symbol` - `choice` - `hall_symbol` - 'international` - `international_full` - `international_short` - `number` - `pointgroup_international` - `pointgroup_schoenflies` - `schoenflies` None if `spglib` fails to determine space group type. Raises: ImportError: If `spglib` cannot be imported. """ _check_spglib_install() return spglib.get_spacegroup_type(hall_number)
def get_spgroup_data_realtime(): """ Return a dictionary that has the spacegroup number as key, and a tuple as value, with (crystal family letter, centering, has_inversion), got in real time using spglib methods. """ import json import spglib info = {} for hall_n in range(1, 531): data = spglib.get_spacegroup_type(hall_n) number = data['number'] int_short = data['international_short'] pg_int = data['pointgroup_international'] if number not in info: info[int(number)] = (get_crystal_family(number), # get cyrstal family # centering from the first letter of the first # spacegroup that I encounter int_short[0], pointgroup_has_inversion(pgnum_from_pgint( pg_int)), # pointgroup has inversion ) return info
def test_get_symmetry_dataset(self): for fname, spgnum, reffname in zip(self._filenames, self._spgnum_ref, self._ref_filenames): cell = read_vasp(fname) if 'distorted' in fname: symprec = 1e-1 else: symprec = 1e-5 dataset = get_symmetry_dataset(cell, symprec=symprec) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname)) for i in range(spg_to_hall[spgnum - 1], spg_to_hall[spgnum]): dataset = get_symmetry_dataset(cell, hall_number=i, symprec=symprec) self.assertEqual(type(dataset), dict, msg=("%s/%d" % (fname, i))) self.assertEqual(dataset['hall_number'], i, msg=("%s" % fname)) spg_type = get_spacegroup_type(dataset['hall_number']) self.assertEqual(dataset['international'], spg_type['international_short'], msg=("%s" % fname)) self.assertEqual(dataset['hall'], spg_type['hall_symbol'], msg=("%s" % fname)) self.assertEqual(dataset['choice'], spg_type['choice'], msg=("%s" % fname)) self.assertEqual(dataset['pointgroup'], spg_type['pointgroup_schoenflies'], msg=("%s" % fname)) wyckoffs = dataset['wyckoffs'] with open(reffname) as f: wyckoffs_ref = yaml.load(f, Loader=yaml.FullLoader)['wyckoffs'] for w, w_ref in zip(wyckoffs, wyckoffs_ref): self.assertEqual(w, w_ref, msg=("%s" % fname))
def test_find_primitive(self): for fname in self._filenames: cell = read_vasp(fname) if 'distorted' in fname: symprec = 1e-1 else: symprec = 1e-5 dataset = get_symmetry_dataset(cell, symprec=symprec) primitive = find_primitive(cell, symprec=symprec) spg_type = get_spacegroup_type(dataset['hall_number']) c = spg_type['international_short'][0] if c in ['A', 'B', 'C', 'I']: multiplicity = 2 elif c == 'F': multiplicity = 4 elif c == 'R': self.assertEqual(spg_type['choice'], 'H') if spg_type['choice'] == 'H': multiplicity = 3 else: # spg_type['choice'] == 'R' multiplicity = 1 else: multiplicity = 1 self.assertEqual(len(dataset['std_types']), len(primitive[2]) * multiplicity, msg=("multi: %d, %s" % (multiplicity, fname)))
def test_get_symmetry_dataset(self): for fname, spgnum, reffname in zip(self._filenames, self._spgnum_ref, self._ref_filenames): cell = read_vasp(fname) if 'distorted' in fname: symprec = 1e-1 else: symprec = 1e-5 dataset = get_symmetry_dataset(cell, symprec=symprec) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname)) for i in range(spg_to_hall[spgnum - 1], spg_to_hall[spgnum]): dataset = get_symmetry_dataset(cell, hall_number=i, symprec=symprec) self.assertEqual(dataset['hall_number'], i, msg=("%s" % fname)) spg_type = get_spacegroup_type(dataset['hall_number']) self.assertEqual(dataset['international'], spg_type['international_short'], msg=("%s" % fname)) self.assertEqual(dataset['hall'], spg_type['hall_symbol'], msg=("%s" % fname)) self.assertEqual(dataset['choice'], spg_type['choice'], msg=("%s" % fname)) self.assertEqual(dataset['pointgroup'], spg_type['pointgroup_schoenflies'], msg=("%s" % fname)) wyckoffs = dataset['wyckoffs'] with open(reffname) as f: wyckoffs_ref = yaml.load(f)['wyckoffs'] for w, w_ref in zip(wyckoffs, wyckoffs_ref): self.assertEqual(w, w_ref, msg=("%s" % fname))
def get_spgroup_data_realtime(): """ Return a dictionary that has the spacegroup number as key, and a tuple as value, with content:: (crystal family letter, centering, has_inversion), got in real time using spglib methods. """ import json import spglib info = {} for hall_n in range(1, 531): data = spglib.get_spacegroup_type(hall_n) number = data["number"] int_short = data["international_short"] pg_int = data["pointgroup_international"] if number not in info: info[int(number)] = ( get_crystal_family(number), # get cyrstal family # centering from the first letter of the first # spacegroup that I encounter int_short[0], pointgroup_has_inversion( pgnum_from_pgint(pg_int)), # pointgroup has inversion ) return info
def test_get_symmetry_dataset(self): for fname, spgnum in zip(self._filenames, self._spgnum_ref): cell = read_vasp(fname) if 'distorted' in fname: symprec = 1e-1 else: symprec = 1e-5 dataset = get_symmetry_dataset(cell, symprec=symprec) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname)) for i in range(spg_to_hall[spgnum - 1], spg_to_hall[spgnum]): dataset = get_symmetry_dataset(cell, hall_number=i, symprec=symprec) self.assertEqual(dataset['hall_number'], i, msg=("%s" % fname)) spg_type = get_spacegroup_type(dataset['hall_number']) self.assertEqual(dataset['international'], spg_type['international_short'], msg=("%s" % fname)) self.assertEqual(dataset['hall'], spg_type['hall_symbol'], msg=("%s" % fname)) self.assertEqual(dataset['choice'], spg_type['choice'], msg=("%s" % fname)) self.assertEqual(dataset['pointgroup'], spg_type['pointgroup_schoenflies'], msg=("%s" % fname))
def print_pointgroup(dataset): spacegroup_type = spglib.get_spacegroup_type(dataset['hall_number']) print "\nPOINT GROUP OF CRYSTAL" print "\tPoint group (number) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[0] print "\tPoint group (crystal family) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[1] print "\tPoint group (crystal_system) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[2] print "\tPoint group (crystal_class) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[3] print "\tPoint group (HM_inter_full) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[4] print "\tPoint group (HM_inter_short) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[5] print "\tPoint group (shubnikov) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[6] print "\tPoint group (schoenflies) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[7] print "\tPoint group (orbifold) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[8] print "\tPoint group (coxeter) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[9] print "\tPoint group (order) :: ", pointgroup_database( spacegroup_type['pointgroup_schoenflies'])[10]
def spacegroup_info(self): """Translate Hall number to space group type information. Returned as an attribute dict """ info = spglib.get_spacegroup_type(self.hall_number) if info is None: raise ValueError("the hall number could not be converted") return AttributeDict(info)
def print_dataset(dataset): print('- ' + 'spg_dataset') print(' number', dataset['number']) print(' international', dataset['international']) print(' hall_symbol', dataset['hall']) print(' hall_number', dataset['hall_number']) print(' choice', dataset['choice']) print(' pointgroup', dataset['pointgroup']) print(' trans_matrix\n', dataset['transformation_matrix']) print(' original_shift\n', dataset['origin_shift']) hall_number = dataset['hall_number'] sgtype = spglib.get_spacegroup_type(hall_number)
def get_crystal_type_name(hall_number): """get crystal type code, denoting the crystal system Parameters ---------- hall_number: int Returns ------- crystal_type_name: str """ sg_number = spglib.get_spacegroup_type(hall_number)["number"] return get_crystal_system_name(sg_number)
def get_iso(self, symprec): DG = self.matrices mat_list = [mat.rotation_matrix for mat in DG] vec_list = [mat.translation_vector for mat in DG] h_number = spglib.get_hall_number_from_symmetry(np.around( mat_list, decimals=4), np.around(vec_list, decimals=6), symprec = symprec) sg_type_data=spglib.get_spacegroup_type(h_number) iso_sg=sg_type_data['international_short'] iso_sg_num=sg_type_data['number'] return iso_sg, iso_sg_num
def get_crystal_type_code(hall_number): """get crystal type code, denoting the crystal system Parameters ---------- hall_number: int Returns ------- crystal_type_code: int """ sg_number = spglib.get_spacegroup_type(hall_number)["number"] crystal_type = get_crystal_system_name(sg_number) return CRYSTAL_TYPE_TO_NUM_MAP[crystal_type]
def get_iso(path, iv): DG = path.get_DG() outputfile = open(iv.image_dir + "/../results/output.out", "a") h_number = spglib.get_hall_number_from_symmetry(np.around(DG[0][:], decimals=4), np.around(DG[1][:], decimals=6), symprec=iv.gentol) sg_type_data = spglib.get_spacegroup_type(h_number) iso_sg = sg_type_data['international_short'] iso_sg_num = sg_type_data['number'] return iso_sg, iso_sg_num
def read(self, file): """Read and parse fort.34 file""" if isinstance(file, str): with open(file) as f: data = f.read() else: data = file.read() parsed_data = _parse_string(f34_parser(), data) self.dimensionality, self.centring, self.crystal_type = parsed_data['header'] if self.dimensionality != 3: raise NotImplementedError('Structure with dimensionality < 3 currently not supported') # primitive cell vectors and basis positions in cartesian coordinates abc = np.array(parsed_data['abc'].asList()).reshape((3, 3)) positions = np.array([d[1:] for d in parsed_data['geometry']]) # convert positions to fractional positions = np.dot(np.linalg.inv(abc).T, positions.T).T atomic_numbers = [d[0] for d in parsed_data['geometry']] # convert to conventional cell cell = (abc, positions, atomic_numbers) cell = spglib.standardize_cell(cell, to_primitive=False, no_idealize=False) self.abc, self.positions, atomic_numbers = cell # ECPs self.atomic_numbers = [num if num < 201 else num - 200 for num in atomic_numbers] # get symmetry operations self.n_symops = parsed_data['n_symops'] self.symops = np.array(parsed_data['symops'].asList()).reshape(self.n_symops * 4, 3) rotations = np.zeros((self.n_symops, 3, 3)) for i in range(3): rotations[:, i] = self.symops[i::4] # convert symmetry operations from cartesian to fractional rotations = np.dot(np.dot(np.linalg.inv(abc.T), rotations), abc.T) # have to round rotations matrix as it is used to find symmetry group rotations = np.round(np.swapaxes(rotations, 0, 1), 9) translations = np.dot(self.symops[3::4], np.linalg.inv(abc)) hall = spglib.get_hall_number_from_symmetry(rotations, translations) self.space_group = int(spglib.get_spacegroup_type(hall)['number']) # we have conventional cell now return self
def test_get_symmetry_dataset(self): for fname in self._filenames: spgnum = int(fname.split('-')[1]) cell = read_vasp("./data/%s" % fname) if 'distorted' in fname: dataset = get_symmetry_dataset(cell, symprec=1e-1) else: dataset = get_symmetry_dataset(cell, symprec=1e-5) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname)) spg_type = get_spacegroup_type(dataset['hall_number']) self.assertEqual(dataset['international'], spg_type['international_short'], msg=("%s" % fname)) self.assertEqual(dataset['hall'], spg_type['hall_symbol'], msg=("%s" % fname)) self.assertEqual(dataset['choice'], spg_type['choice'], msg=("%s" % fname)) self.assertEqual(dataset['pointgroup'], spg_type['pointgroup_schoenflies'], msg=("%s" % fname))
def get_centering_code(hall_number): """get crystal centering codes, to convert from primitive to conventional Parameters ---------- hall_number: int Returns ------- centering_code: int """ sg_data = spglib.get_spacegroup_type(hall_number) sg_symbol = sg_data["international"] lattice_type = get_lattice_type_name(sg_data["number"]) crystal_type = get_crystal_system_name(sg_data["number"]) if "P" in sg_symbol or lattice_type == "hexagonal": return 1 elif lattice_type == "rhombohedral": # can also be P_R (if a_length == c_length in conventional cell), # but crystal doesn't appear to use that anyway return 1 elif "I" in sg_symbol: return 6 elif "F" in sg_symbol: return 5 elif "C" in sg_symbol: if crystal_type == "monoclinic": return 4 # TODO this is P_C but don't know what code it is, maybe 3? # [[1.0, -1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0]] return 4 # elif "A" in sg_symbol: # return 2 # TODO check this is always correct (not in original function) return 1
def gui_file_write(structure_data, symmetry_data=None): """Create string of gui file content (for CRYSTAL17). Parameters ---------- structure_data: aiida.StructureData or dict or ase.Atoms dict with keys: 'pbc', 'atomic_numbers', 'ccoords', 'lattice', or ase.Atoms, or any object that has method structure_data.get_ase() symmetry_data: dict or None keys; 'crystal_type_code', 'centring_code', 'space_group', 'operations', 'basis' Returns ------- lines: list[str] list of lines in the file Notes ----- Older versions of CRYSTAL are not compatible, because they only specify symmetrically inequivalent atomic positions (rather than all) Symmetry operations and atomic positions are assumed to be cartesian (rather than fractional) """ structure_dict = convert_structure(structure_data, "dict") dimensionality = sum(structure_dict["pbc"]) atomic_numbers = structure_dict["atomic_numbers"] ccoords = structure_dict["ccoords"] lattice = structure_dict["lattice"] if symmetry_data is None: structure = convert_structure(structure_data, "aiida") symmetry_data = structure_to_symmetry(structure) if isinstance(symmetry_data, dict): crystal_type = symmetry_data["crystal_type_code"] centring_code = symmetry_data["centring_code"] sg_num = symmetry_data["space_group"] symops = symmetry_data["operations"] basis = symmetry_data["basis"] else: # TODO specific test for SymmetryData, and move this to separate function symops = symmetry_data.data.operations basis = symmetry_data.data.basis hall_number = symmetry_data.hall_number if hall_number is None: hall_number = get_hall_number_from_symmetry(symops, basis, lattice) crystal_type = get_crystal_type_code(hall_number) centring_code = get_centering_code(hall_number) sg_num = spglib.get_spacegroup_type(hall_number)["number"] if basis == "fractional": symops = operations_frac_to_cart(symops, lattice) else: if basis != "cartesian": raise AssertionError( "symmetry basis must be fractional or cartesian") # sort the symmetry operations (useful to standardize for testing) # symops = np.sort(symops, axis=0) num_symops = len(symops) sym_lines = [] for symop in symops: sym_lines.append(symop[0:3]) sym_lines.append(symop[3:6]) sym_lines.append(symop[6:9]) sym_lines.append(symop[9:12]) # for all output numbers, we round to 9 dp and add 0, so we don't get -0.0 geom_str_list = [] geom_str_list.append("{0} {1} {2}".format(dimensionality, centring_code, crystal_type)) geom_str_list.append("{0:17.9E} {1:17.9E} {2:17.9E}".format( *(np.round(lattice[0], 9) + 0.0))) geom_str_list.append("{0:17.9E} {1:17.9E} {2:17.9E}".format( *(np.round(lattice[1], 9) + 0.0))) geom_str_list.append("{0:17.9E} {1:17.9E} {2:17.9E}".format( *(np.round(lattice[2], 9) + 0.0))) geom_str_list.append(str(num_symops)) for sym_line in sym_lines: geom_str_list.append("{0:17.9E} {1:17.9E} {2:17.9E}".format( *(np.round(sym_line, 9) + 0.0))) geom_str_list.append(str(len(atomic_numbers))) for anum, coord in zip(atomic_numbers, ccoords): geom_str_list.append("{0:3} {1:17.9E} {2:17.9E} {3:17.9E}".format( anum, *(np.round(coord, 10) + 0.0))) geom_str_list.append("{0} {1}".format(sg_num, num_symops)) geom_str_list.append("") return geom_str_list
def spacegroup_info(self, symprec = 1e-2, angle_tolerance = -1.0): """ Returns a dictionary containing space-group information. This information is computed from the crystal unit cell, and is not taken from records if available. Parameters ---------- symprec : float, optional Symmetry-search distance tolerance in Cartesian coordinates [Angstroms]. angle_tolerance: float, optional Symmetry-search tolerance in degrees. If the value is negative (default), an internally optimized routine is used to judge symmetry. Returns ------- info : dict or None Dictionary of space-group information. The following keys are available: * ``'international_symbol'``: International Tables of Crystallography space-group symbol (short); * ``'international_full'``: International Tables of Crystallography space-group full symbol; * ``'hall_symbol'`` : Hall symbol; * ``'pointgroup'`` : International Tables of Crystallography point-group; * ``'international_number'`` : International Tables of Crystallography space-group number (between 1 and 230); * ``'hall_number'`` : Hall number (between 1 and 531). If symmetry-determination has failed, None is returned. Raises ------ RuntimeError : If symmetry-determination has yielded an error. Notes ----- Note that crystals generated from the Protein Data Bank are often incomplete; in such cases the space-group information will be incorrect. """ dataset = get_symmetry_dataset(cell = self._spglib_cell(), symprec = symprec, angle_tolerance = angle_tolerance) if dataset: spg_type = get_spacegroup_type(dataset['hall_number']) info = {'international_symbol': dataset['international'], 'hall_symbol' : dataset['hall'], 'international_number': dataset['number'], 'hall_number' : dataset['hall_number'], 'international_full' : spg_type['international_full'], 'pointgroup' : spg_type['pointgroup_international']} err_msg = get_error_message() if (err_msg != 'no error'): raise RuntimeError('Symmetry-determination has returned the following error: {}'.format(err_msg)) return info return None
def make_cifdata(cell, atoms, tol=1.0e-5): cifdata = [] scell = spglib.standardize_cell(cell) print('*** scell ***') print_cell(scell) dataset = spglib.get_symmetry_dataset(scell, tol) wyckoffs = dataset['wyckoffs'] equiv_atoms = dataset['equivalent_atoms'] trans_matrix = dataset['transformation_matrix'] origin_shift = dataset['origin_shift'] hall_number = dataset['hall_number'] hall_symbol = dataset['hall'] sg_type = spglib.get_spacegroup_type(hall_number) print('trans_matrix') print(trans_matrix) print('origin_shift') print(origin_shift) lattice = scell[0] positions = scell[1] numbers = scell[2] cifdata.append(('data_', '')) cifdata.append(('', None)) chemform = '' num = [0 for i in range(len(atoms))] for i, a in enumerate(atoms): for n in numbers: if (i == n): num[i] += 1 if ('C' in atoms): chemform += 'C' + str(num[atoms.index('C')]) + ' ' if ('H' in atoms): chemform += 'H' + str(num[atoms.index('H')]) + ' ' for i, a in enumerate(atoms): if (a != 'C' and a != 'H'): chemform += a + str(num[i]) + ' ' chemform = chemform.strip() print('chemical formula', chemform) cifdata.append(('_chemical_formula_sum', chemform)) crystal_system = get_crystal_system(dataset['number']) cifdata.append(('_space_group_crystal_system', crystal_system)) name_HM = sanitize_name_HM(sg_type['international_short']) cifdata.append(('_symmetry_space_group_name_H-M', name_HM)) cifdata.append(('_symmetry_Int_Tables_number', dataset['number'])) cifdata.append(('_symmetry_space_group_name_Hall', hall_symbol)) cifdata.append(('', None)) cifdata_symmetry_list = ('loop_symmetry', []) cifdata_symmetry_list[1].append( ['_symmetry_equiv_pos_site_id', '_symmetry_equiv_pos_as_xyz']) ind = 0 for rot, trans in zip(dataset['rotations'], dataset['translations']): symbols = make_symop(rot, trans) ind += 1 cifdata_symmetry_list[1].append([ind, symbols]) cifdata.append(cifdata_symmetry_list) cifdata.append(("", None)) a, b, c = celllength(lattice) alpha, beta, gamma = cellangle(lattice) cifdata.append(('_cell_length_a', a)) cifdata.append(('_cell_length_b', b)) cifdata.append(('_cell_length_c', c)) cifdata.append(('_cell_angle_alpha', alpha)) cifdata.append(('_cell_angle_beta', beta)) cifdata.append(('_cell_angle_gamma', gamma)) cifdata.append(('', None)) # find inequivalent atoms and calculate their multiplicitis inequiv_atoms = collections.OrderedDict() for num in equiv_atoms: if num not in inequiv_atoms: inequiv_atoms[num] = 1 else: inequiv_atoms[num] += 1 print('space group number %s' % dataset['number']) print('space group %s' % dataset['international']) print('hall symbol %s' % dataset['hall']) print('name wyckoff multiplicity x y z') cifdata_atomlist = ('loop_atom', []) cifdata_atomlist[1].append([ '_atom_site_label', '_atom_site_fract_x', '_atom_site_fract_y', '_atom_site_fract_z', '_atom_site_occupancy', '_atom_site_symmetry_multiplicity', '_atom_site_Wyckoff_symbol', '_atom_site_type_symbol' ]) suffix_list = {} for atom in atoms: suffix_list[atom] = 1 for num in inequiv_atoms: atom_type_number = numbers[num] atom_type = atoms[atom_type_number] atom_label = atom_type + str(suffix_list[atom_type]) suffix_list[atom_type] += 1 cifdata_atomlist[1].append([ atom_label, positions[num][0], positions[num][1], positions[num][2], 1.0, inequiv_atoms[num], wyckoffs[num], atom_type ]) print(atom_label, atom_type, wyckoffs[num], inequiv_atoms[num], positions[num][0], positions[num][1], positions[num][2]) cifdata.append(cifdata_atomlist) cifdata.append(('', None)) return cifdata
""" This script is used to determine the transform from the system specififed by first Hall number in each space group, into the system that correponds to the conventional settings for that space group. This information is needed because the normalizers and Wyckoff positions in Bilbao Crystallographic Server are given in the conventional setttings only by default. """ import spglib from collections import defaultdict space_hall_map = defaultdict(list) for hall_number in range(1, 531): dataset = spglib.get_spacegroup_type(hall_number) number = dataset["number"] space_hall_map[number].append(hall_number) degenerate_spgs = [] for key, value in space_hall_map.items(): if len(value) == 1: continue degenerate_spgs.append(key) first_hall = value[0] dataset = spglib.get_spacegroup_type(first_hall) choice = dataset["choice"] # try: # origin = int(choice)
def get_space_group_type(self, symprec=1e-5): return spg.get_spacegroup_type(self.hall_number(symprec=symprec))
def crystal_space_group(system, symprec=1e-5, to_primitive=False, no_idealize=False): """ Uses spglib to evaluate space group information for a given system. Parameters ---------- system : atomman.System The system to analyze. symprec : float Absolute length tolerance to use in identifying symmetry of atomic sites and system boundaries. to_primitive : bool Indicates if the returned unit cell is conventional (False) or primitive (True). Default value is False. no_idealize : bool Indicates if the atom positions in the returned unit cell are averaged (True) or idealized based on the structure (False). Default value is False. Returns ------- dict Results dictionary containing space group information and an associated unit cell system. """ # Identify the standardized unit cell representation ucell = spglib.standardize_cell(system.dump('spglib_cell'), to_primitive=to_primitive, no_idealize=no_idealize, symprec=symprec) # Convert back to atomman systems and normalize ucell = am.load('spglib_cell', ucell, symbols=system.symbols) ucell.atoms.pos -= ucell.atoms.pos[0] ucell = ucell.normalize() # Get space group metadata sym_data = spglib.get_symmetry_dataset(ucell.dump('spglib_cell')) spg_type = spglib.get_spacegroup_type(sym_data['hall_number']) # Generate Pearson symbol if spg_type['number'] <= 2: crystalclass = 'a' elif spg_type['number'] <= 15: crystalclass = 'm' elif spg_type['number'] <= 74: crystalclass = 'o' elif spg_type['number'] <= 142: crystalclass = 't' elif spg_type['number'] <= 194: crystalclass = 'h' else: crystalclass = 'c' latticetype = spg_type['international'][0] if latticetype in ['A', 'B']: latticetype = 'C' natoms = str(ucell.natoms) pearson = crystalclass + latticetype + natoms # Return results results_dict = spg_type results_dict['ucell'] = ucell results_dict['hall_number'] = sym_data['hall_number'] results_dict['wyckoffs'] = sym_data['wyckoffs'] results_dict['pearson'] = pearson return results_dict
def summary(cry, cell, hallnum_ccell, hallnum_pcell, cif, tol=1.0e-5): f = open('caldata.txt', 'a') # cif f.write(cry.matid + ' ') chemform = cry.chemical_formula_sum chemform = chemform.replace(' ', '') f.write(chemform + ' ') f.write(cry.space_group_crystal_system + ' ') f.write(str(cry.symmetry_Int_Tables_number) + ' ') f.write(cry.symmetry_space_group_name + ' ') la = cry.cell.length_a lb = cry.cell.length_b lc = cry.cell.length_c aa = cry.cell.angle_alpha ab = cry.cell.angle_beta ac = cry.cell.angle_gamma f.write( str(la) + ' ' + str(lb) + ' ' + str(lc) + ' ' + str(aa) + ' ' + str(ab) + ' ' + str(ac) + ' ') #tol = 1.0e-5 # conv cell sgtype = spglib.get_spacegroup_type(hallnum_ccell) spgnum = sgtype['number'] spgname = sgtype['international_short'] f.write(str(spgnum) + ' ' + spgname + ' ') # prim cell sgtype = spglib.get_spacegroup_type(hallnum_pcell) spgnum = sgtype['number'] spgname = sgtype['international_short'] f.write(str(spgnum) + ' ' + spgname + ' ') # calc cell scell = spglib.standardize_cell(cell) dataset = spglib.get_symmetry_dataset(scell, tol) spgnum = dataset['number'] hallnum = dataset['hall_number'] sgtype = spglib.get_spacegroup_type(hallnum) spgname = sgtype['international_short'] f.write(str(spgnum) + ' ' + spgname + ' ') lattice = scell[0] a, b, c = celllength(lattice) alpha, beta, gamma = cellangle(lattice) f.write( str(a) + ' ' + str(b) + ' ' + str(c) + ' ' + str(alpha) + ' ' + str(beta) + ' ' + str(gamma) + ' ') # cif2cell cmd = './cif2cell.sh ' + cif os.system(cmd) cell, atoms = read_structure_vasp('POSCAR.cif2cell') scell = spglib.standardize_cell(cell) dataset = spglib.get_symmetry_dataset(scell, tol) spgnum = dataset['number'] hallnum = dataset['hall_number'] sgtype = spglib.get_spacegroup_type(hallnum) spgname = sgtype['international_short'] f.write(str(spgnum) + ' ' + spgname + ' ') f.write('\n')
def get_HSKP(self, structure): structure_dataset = spglib.get_symmetry_dataset(structure, symprec = 1e-05, angle_tolerance = -1.0) structure_basis = structure_dataset['std_lattice'] sgnum = structure_dataset['number'] hall_num = structure_dataset['hall_number'] pg_international = spglib.get_spacegroup_type(hall_num)['pointgroup_international'] inversion_symmetry = self.pg_inversion(self.get_pgnum(pg_international)) a, b, c, cosalpha, cosbeta, cosgamma = self.get_lattice_constant(structure_basis) time_reversal = True if sgnum in range (195, 231): self.cubic(sgnum) elif sgnum in range (75, 143): self.tetragonal(sgnum, a, b, c) elif sgnum in range (16, 75): self.orthorhombic(sgnum, a, b, c) elif sgnum in range (168, 195): self.hexagonal(sgnum) elif sgnum in range (143, 168): self.trigonal(sgnum, a, b, c) elif sgnum in range(3, 16): self.monoclinic(sgnum, a, b, c, cosbeta) elif sgnum in (1, 3): rec1 = self.rec_real_transf(structure_basis) rec2 = spglib.niggli_reduce(rec1) real2 = self.rec_real_transf(rec2) ka2, kb2, kc2, coskalpha2, coskbeta2, coskgamma2 = self.get_lattice_constant(rec2) conditions = np.array([abs(kb2 * kc2 * coskalpha2), \ abs(kc2 * ka2 * coskbeta2), \ abs(ka2 * kb2 * coskgamma2)]) matrix_M2 = [np.array([[0, 0, 1], [1, 0, 0], [0, 1, 0]]), \ np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]]), \ np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])] smallest_condition = np.argsort(conditions)[0] M2 = matrix_M2[smallest_condition] real3 = np.dot(np.array(real2).T, M2).T rec3 = self.rec_real_transf(real3) ka3, kb3, kc3, coskalpha3, coskbeta3, coskgamma3 = self.get_lattice_constant(rec3) if (coskalpha3 > 0. and coskbeta3 > 0 and coskgamma3 > 0) or \ (coskalpha3 < 0 and coskbeta3 < 0 and coskgamma3 < 0): matrix_M3 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) elif (coskalpha3 > 0 and coskbeta3 < 0 and coskgamma3 < 0) or \ (coskalpha3 < 0 and coskbeta3 > 0 and coskgamma3 > 0): matrix_M3 = np.array([[1, 0, 0], [0, -1, 0], [0, 0, -1]]) elif (coskalpha3 < 0 and coskbeta3 > 0 and coskgamma3 < 0) or \ (coskalpha3 > 0 and coskbeta3 < 0 and coskgamma3 > 0): matrix_M3 = np.array([[-1, 0, 0], [0, 1, 0], [0, 0, -1]]) elif (coskalpha3 < 0 and coskbeta3 < 0 and coskgamma3 > 0) or \ (coskalpha3 > 0 and coskbeta3 > 0 and coskgamma3 < 0): matrix_M3 = np.array([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]) else: print('Error! Can not get M3 matrix for aP lattice') real4 = np.dot(real3.T, matrix_M3).T rec4 = self.rec_real_transf(real4) ka, kb, kc, coskalpha, coskbeta, coskgamma = get_cell_params(rec4) self.triclinic(coskalpha, coskbeta, coskgamma) if not inversion_symmetry and not time_reversal: augmented_path = True else: augmented_path = False if augmented_path: for pointname, coords in list(self.kpath['Kpoints'].items()): if pointname == '\Gamma': continue self.kpath['Kpoints']["{}'".format(pointname)] = \ [-coords[0], -coords[1], -coords[2]] for i in range(0, len(self.kpath['Path'])): path_list = [] old_path = copy.deepcopy(self.kpath['Path'][i - 1]) for path in old_path: if path == '\Gamma': new_path = path else: new_path = "{}'".format(path) path_list.append(new_path) self.kpath['Path'].append(path_list)
# Maintainer: Pengji Zhou # NOTE: this is the code for record that generates the hall number - space group number mapping. # The use of this code is not required to use this package # hall_spacegroup_mapping import spglib as spg import json two_origin_choice_list = [ 48, 50, 59, 68, 70, 85, 86, 88, 125, 126, 129, 130, 133, 134, 137, 138, 141, 142, 201, 203, 222, 224, 227, 228 ] H_R_choice_list = [146, 148, 155, 160, 161, 166, 167] spacegroup_hall_mapping = {} for hall_number in range(1, 531): spacegroup_type = spg.get_spacegroup_type(hall_number) if spacegroup_type['number'] not in spacegroup_hall_mapping: if spacegroup_type[ 'number'] in two_origin_choice_list + H_R_choice_list: shift = 1 else: shift = 0 spacegroup_hall_mapping[ spacegroup_type['number']] = hall_number + shift with open('space_group_hall_mapping.json', 'w') as f: json.dump(spacegroup_hall_mapping, f)
""" Goes through the spglib database for different Hall numbers and extracts space group specific intormation. The results are then written to a python file for later use. """ import spglib import pickle space_groups = {} space_group_database = {} for hall_number in range(1, 531): dataset = spglib.get_spacegroup_type(hall_number) number = dataset["number"] international_short = dataset["international_short"] # Check that the spglib data has no two different international symbols for # the same space group number old = space_groups.get(number) if old is not None: if old != international_short: raise LookupError("Two spacegroups have different point groups!") else: if number not in space_group_database: space_group_database[number] = {} # Point group. There actually seeems to be a bug in spglib 1.9.4, where # the Hermann-Mauguin point group symbol is in the plalce of Schonflies # data and vice versa. pointgroup = dataset["pointgroup_schoenflies"] space_group_database[number]["pointgroup"] = pointgroup
def symmetry(self, symprec=1e-2, angle_tolerance=-1.0): """ Returns a dictionary containing space-group information. This information is computed from the crystal unit cell. Parameters ---------- symprec : float, optional Symmetry-search distance tolerance in Cartesian coordinates [Angstroms]. angle_tolerance: float, optional Symmetry-search tolerance in degrees. If the value is negative (default), an internally optimized routine is used to judge symmetry. Returns ------- info : dict Dictionary of space-group information. The following keys are available: * ``'international_symbol'``: International Tables of Crystallography space-group symbol (short); * ``'international_full'``: International Tables of Crystallography space-group full symbol; * ``'hall_symbol'`` : Hall symbol; * ``'hm_symbol'`` : Hermann-Mauguin symbol; *``'centering'``: Centering-type ("P", "F", etc.); * ``'pointgroup'`` : International Tables of Crystallography point-group; * ``'international_number'`` : International Tables of Crystallography space-group number (between 1 and 230); * ``'hall_number'`` : Hall number (between 1 and 531). Raises ------ RuntimeError : if symmetry-determination has not succeeded. Notes ----- Note that crystals generated from the Protein Data Bank are often incomplete; in such cases the space-group information will be incorrect. """ dataset = get_symmetry_dataset(cell=self._spglib_cell(), symprec=symprec, angle_tolerance=angle_tolerance) if dataset is None: raise RuntimeError( "[SPGLIB] Symmetry-determination has not found a match.") spg_type = get_spacegroup_type(dataset["hall_number"]) hm_symbol = Hall2HM[dataset["hall"]] # We do not distinguish between base-centered "A", "B", and "C" # "A" and "B" are translated to "C" centering = CenteringType(hm_symbol[0] if hm_symbol[0] not in {"A", "B"} else "C") info = { "international_symbol": dataset["international"], "hall_symbol": dataset["hall"], "hm_symbol": hm_symbol, "centering": centering, "international_number": dataset["number"], "hall_number": dataset["hall_number"], "international_full": spg_type["international_full"], "pointgroup": spg_type["pointgroup_international"], } err_msg = get_error_message() if err_msg != "no error": raise RuntimeError( "[SPGLIB] Symmetry-determination has returned the following error: {err_msg}" ) return info
def crystal_space_group(system: am.System, symprec: float = 1e-5, to_primitive: bool = False, no_idealize: bool = False) -> dict: """ Uses spglib to evaluate space group information for a given system. Parameters ---------- system : atomman.System The system to analyze. symprec : float, optional Absolute length tolerance to use in identifying symmetry of atomic sites and system boundaries. Default value is 1e-5 to_primitive : bool, optional Indicates if the returned unit cell is conventional (False) or primitive (True). Default value is False. no_idealize : bool, optional Indicates if the atom positions in the returned unit cell are averaged (True) or idealized based on the structure (False). Default value is False. Returns ------- dict Dictionary of results consisting of keys: - **'number'** (*int*) The spacegroup number. - **'international_short'** (*str*) The short international spacegroup symbol. - **'international_full'** (*str*) The full international spacegroup symbol. - **'international'** (*str*) The international spacegroup symbol. - **'schoenflies'** (*str*) The schoenflies spacegroup symbol. - **'hall_symbol'** (*str*) The Hall symbol. - **'choice'** (*str*) The setting choice if there is one. - **'pointgroup_international'** (*str*) The international pointgroup symbol. - **'pointgroup_schoenflies'** (*str*) The schoenflies pointgroup symbol. - **'arithmetic_crystal_class_number'** (*int*) The arithmetic crystal class number. - **'arithmetic_crystal_class_symbol'** (*str*) The arithmetic crystal class symbol. - **'ucell'** (*am.System*) The spacegroup-processed unit cell. - **'hall_number'** (*int*) The Hall number. - **'wyckoffs'** (*list*) A list of the spacegroup's Wyckoff symbols where atoms are found. - **'equivalent_atoms'** (*list*) A list of indices indicating which atoms are equivalent to others. - **'pearson'** (*str*) The Pearson symbol. - **'wyckoff_fingerprint'** (*str*) The Wyckoff symbols joined together. """ # Identify the standardized unit cell representation sym_data = spglib.get_symmetry_dataset(system.dump('spglib_cell'), symprec=symprec) ucell = spglib.standardize_cell(system.dump('spglib_cell'), to_primitive=to_primitive, no_idealize=no_idealize, symprec=symprec) # Convert back to atomman systems and normalize ucell = am.load('spglib_cell', ucell, symbols=system.symbols) ucell.atoms.pos -= ucell.atoms.pos[0] ucell = ucell.normalize() # Throw error if natoms > 2000 natoms = ucell.natoms if natoms > 2000: raise RuntimeError('too many positions') # Average extra per-atom properties by mappings to primitive for index in np.unique(sym_data['mapping_to_primitive']): for key in system.atoms.prop(): if key in ['atype', 'pos']: continue value = system.atoms.view[key][sym_data['mapping_to_primitive'] == index].mean() if key not in ucell.atoms.prop(): ucell.atoms.view[key] = np.zeros_like(value) ucell.atoms.view[key][sym_data['std_mapping_to_primitive'] == index] = value # Get space group metadata sym_data = spglib.get_symmetry_dataset(ucell.dump('spglib_cell')) spg_type = spglib.get_spacegroup_type(sym_data['hall_number']) # Generate Pearson symbol if spg_type['number'] <= 2: crystalclass = 'a' elif spg_type['number'] <= 15: crystalclass = 'm' elif spg_type['number'] <= 74: crystalclass = 'o' elif spg_type['number'] <= 142: crystalclass = 't' elif spg_type['number'] <= 194: crystalclass = 'h' else: crystalclass = 'c' latticetype = spg_type['international'][0] if latticetype in ['A', 'B']: latticetype = 'C' pearson = crystalclass + latticetype + str(natoms) # Generate Wyckoff fingerprint fingerprint_dict = {} usites, uindices = np.unique(sym_data['equivalent_atoms'], return_index=True) for usite, uindex in zip(usites, uindices): atype = ucell.atoms.atype[uindex] wykoff = sym_data['wyckoffs'][uindex] if atype not in fingerprint_dict: fingerprint_dict[atype] = [wykoff] else: fingerprint_dict[atype].append(wykoff) fingerprint = [] for atype in sorted(fingerprint_dict.keys()): fingerprint.append(''.join(sorted(fingerprint_dict[atype]))) fingerprint = ' '.join(fingerprint) # Return results results_dict = spg_type results_dict['ucell'] = ucell results_dict['hall_number'] = sym_data['hall_number'] results_dict['wyckoffs'] = sym_data['wyckoffs'] results_dict['equivalent_atoms'] = sym_data['equivalent_atoms'] results_dict['pearson'] = pearson results_dict['wyckoff_fingerprint'] = fingerprint return results_dict
print('') dataset = spglib.get_symmetry_dataset( rutile ) print("[get_symmetry_dataset] ['international']") print(" Spacegroup of Rutile is %s (%d)." % (dataset['international'], dataset['number'])) print('') print("[get_symmetry_dataset] ['pointgroup']") print(" Pointgroup of Rutile is %s." % (dataset['pointgroup'])) print('') print("[get_symmetry_dataset] ['hall']") print(" Hall symbol of Rutile is %s (%d)." % (dataset['hall'], dataset['hall_number'])) print('') print '=========================================================' spacegroup_type = spglib.get_spacegroup_type(dataset['hall_number']) print spacegroup_type print("[get_symmetry_dataset] ['wyckoffs']") alphabet = "abcdefghijklmnopqrstuvwxyz" print(" Wyckoff letters of Rutile are: ", dataset['wyckoffs']) print('') print("[get_symmetry_dataset] ['equivalent_atoms']") print(" Mapping to equivalent atoms of Rutile are: ") for i, x in enumerate(dataset['equivalent_atoms']): print(" %d -> %d" % (i + 1, x + 1)) print('') print("[get_symmetry_dataset] ['rotations'], ['translations']") print(" Symmetry operations of Rutile unitcell are:") for i, (rot,trans) in enumerate(zip(dataset['rotations'], dataset['translations'])): print(" --------------- %4d ---------------" % (i + 1))
def crystal_space_group(system, symprec=1e-5, to_primitive=False, no_idealize=False): """ Uses spglib to evaluate space group information for a given system. Parameters ---------- system : atomman.System The system to analyze. symprec : float Absolute length tolerance to use in identifying symmetry of atomic sites and system boundaries. to_primitive : bool Indicates if the returned unit cell is conventional (False) or primitive (True). Default value is False. no_idealize : bool Indicates if the atom positions in the returned unit cell are averaged (True) or idealized based on the structure (False). Default value is False. Returns ------- dict Results dictionary containing space group information and an associated unit cell system. """ # Identify the standardized unit cell representation sym_data = spglib.get_symmetry_dataset(system.dump('spglib_cell'), symprec=symprec) ucell = spglib.standardize_cell(system.dump('spglib_cell'), to_primitive=to_primitive, no_idealize=no_idealize, symprec=symprec) # Convert back to atomman systems and normalize ucell = am.load('spglib_cell', ucell, symbols=system.symbols) ucell.atoms.pos -= ucell.atoms.pos[0] ucell = ucell.normalize() # Average extra per-atom properties by mappings to primitive for index in np.unique(sym_data['mapping_to_primitive']): for key in system.atoms.prop(): if key in ['atype', 'pos']: continue value = system.atoms.view[key][sym_data['mapping_to_primitive'] == index].mean() if key not in ucell.atoms.prop(): ucell.atoms.view[key] = np.zeros_like(value) ucell.atoms.view[key][sym_data['std_mapping_to_primitive'] == index] = value # Get space group metadata sym_data = spglib.get_symmetry_dataset(ucell.dump('spglib_cell')) spg_type = spglib.get_spacegroup_type(sym_data['hall_number']) # Generate Pearson symbol if spg_type['number'] <= 2: crystalclass = 'a' elif spg_type['number'] <= 15: crystalclass = 'm' elif spg_type['number'] <= 74: crystalclass = 'o' elif spg_type['number'] <= 142: crystalclass = 't' elif spg_type['number'] <= 194: crystalclass = 'h' else: crystalclass = 'c' latticetype = spg_type['international'][0] if latticetype in ['A', 'B']: latticetype = 'C' natoms = str(ucell.natoms) pearson = crystalclass + latticetype + natoms # Generate Wyckoff fingerprint fingerprint_dict = {} usites, uindices = np.unique(sym_data['equivalent_atoms'], return_index=True) for usite, uindex in zip(usites, uindices): atype = ucell.atoms.atype[uindex] wykoff = sym_data['wyckoffs'][uindex] if atype not in fingerprint_dict: fingerprint_dict[atype] = [wykoff] else: fingerprint_dict[atype].append(wykoff) fingerprint = [] for atype in sorted(fingerprint_dict.keys()): fingerprint.append(''.join(sorted(fingerprint_dict[atype]))) fingerprint = ' '.join(fingerprint) # Return results results_dict = spg_type results_dict['ucell'] = ucell results_dict['hall_number'] = sym_data['hall_number'] results_dict['wyckoffs'] = sym_data['wyckoffs'] results_dict['equivalent_atoms'] = sym_data['equivalent_atoms'] results_dict['pearson'] = pearson results_dict['wyckoff_fingerprint'] = fingerprint return results_dict
def get_sym(cell, symprec=1e-3, verbose='short', angle_tolerance=-1.0, hall_number=0): '''Giving a spglib cell, return symmetry analysis This is wrapper for spglib.get_symmetry_dataset function ''' #Space group info dataset = spglib.get_symmetry_dataset(cell, symprec=symprec, angle_tolerance=angle_tolerance, hall_number=hall_number) number = dataset['number'] international = dataset['international'] # equil. to international_short hall = dataset['hall'] # equil. to hall_symbol hall_number = dataset['hall_number'] choice = dataset['choice'] transformation_matrix = dataset['transformation_matrix'] origin_shift = dataset['origin_shift'] wyckoffs = dataset['wyckoffs'] site_symmetry_symbols = dataset['site_symmetry_symbols'] equivalent_atoms = dataset['equivalent_atoms'] crystallographic_orbits = dataset['crystallographic_orbits'] mapping_to_primitive = dataset['mapping_to_primitive'] rotations = dataset['rotations'] translations = dataset['translations'] pointgroup = dataset['pointgroup'] # equil. to pointgroup_international primitive_lattice = dataset['primitive_lattice'] std_lattice = dataset['std_lattice'] std_positions = dataset['std_positions'] std_types = dataset['std_types'] std_rotation_matrix = dataset['std_rotation_matrix'] std_mapping_to_primitive = dataset['std_mapping_to_primitive'] # Get full summetry using the Hall number spacegroup_type = spglib.get_spacegroup_type(hall_number) number = spacegroup_type['number'] international_short = spacegroup_type['international_short'] international_full = spacegroup_type['international_full'] international = spacegroup_type['international'] schoenflies = spacegroup_type['schoenflies'] hall_symbol = spacegroup_type['hall_symbol'] pointgroup_schoenflies = spacegroup_type['pointgroup_schoenflies'] pointgroup_international = spacegroup_type['pointgroup_international'] arithmetic_crystal_class_number = spacegroup_type[ 'arithmetic_crystal_class_number'] arithmetic_crystal_class_symbol = spacegroup_type[ 'arithmetic_crystal_class_symbol'] atoms = utils.convert_atomtype(cell[2]) coords = cell[1] std_cell = cell_to_std(dataset, message=False) primitive_cell = cell_to_primitive(dataset, message=False) if verbose == 'short': # Cell info if compare_cells(cell, std_cell) and compare_cells( cell, primitive_cell): misc.print_msg("This is a standard/primitive unit cell") elif compare_cells(cell, std_cell): misc.print_msg("This is a standard unit cell") elif compare_cells(cell, primitive_cell): misc.print_msg("This is a primitive cell") # Basic info misc.print_msg("Space group number : {:d}".format(number)) misc.print_msg( "Short international symbol : {:s}".format(international_short)) misc.print_msg( "Hall symbol : {:s}".format(hall_symbol)) misc.print_msg( "Schoenflies symbol : {:s}".format(schoenflies)) misc.print_msg("International point group : {:s}".format( pointgroup_international)) misc.print_msg( "Origin shift : {:4.3f} {:4.3f} {:4.3f}".format( origin_shift[0], origin_shift[1], origin_shift[2])) # Atoms info # Atoms info misc.print_msg("===== Irreducible atoms list =====") misc.print_msg(" # Atom x y z") unique_atoms_idx = np.unique(equivalent_atoms, return_index=True)[1] for i, index in enumerate(unique_atoms_idx): coord = coords[index] misc.print_msg( "{:>3d} {:>3s} {:>8.5f} {:>8.5f} {:>8.5f}".format( i + 1, atoms[index], coord[0], coord[1], coord[2])) elif verbose == 'full': # Cell info if compare_cells(cell, std_cell) and compare_cells( cell, primitive_cell): misc.print_msg("This is a standard/primitive unit cell") elif compare_cells(cell, std_cell): misc.print_msg("This is a standard unit cell") elif compare_cells(cell, primitive_cell): misc.print_msg("This is a primitive cell") # Basic info misc.print_msg("Space group number : {:d}".format(number)) misc.print_msg( "Short international symbol : {:s}".format(international_short)) misc.print_msg( "Full international symbol : {:s}".format(international_full)) misc.print_msg( "Hall number : {:d}".format(hall_number)) misc.print_msg( "Hall symbol : {:s}".format(hall_symbol)) misc.print_msg( "Schoenflies symbol : {:s}".format(schoenflies)) misc.print_msg("Schoenflies point group : {:s}".format( pointgroup_schoenflies)) misc.print_msg("International point group : {:s}".format( pointgroup_international)) misc.print_msg( "Origin shift : {:4.3f} {:4.3f} {:4.3f}".format( origin_shift[0], origin_shift[1], origin_shift[2])) # Atoms info misc.print_msg("===== Full atoms list =====") misc.print_msg( " # Equil. Atom x y z Wyckoffs Site_symmetry" ) for i, atom in enumerate(atoms): misc.print_msg( "{:>3d} {:>3d} {:>3s} {:>8.5f} {:>8.5f} {:>8.5f} {:>2s} {:>5s}" .format(i + 1, equivalent_atoms[i] + 1, atoms[i], coords[i, 0], coords[i, 1], coords[i, 2], wyckoffs[i], site_symmetry_symbols[i])) elif verbose is None: # Return an standard cell object with irreducible atoms dataset = spglib.get_symmetry_dataset(std_cell, symprec=symprec, angle_tolerance=angle_tolerance, hall_number=hall_number) equivalent_atoms = dataset['equivalent_atoms'] irred_idx = np.unique(equivalent_atoms, return_index=True)[1] lattice = std_lattice irred_coord = std_positions[irred_idx, :] irred_label = std_types[irred_idx] irred_cell = (lattice, irred_coord, irred_label) spacegroup = [number, international_short] # Get symmetry operators using the Hall number: # For some reason, the symmetry operators by dataset doesn't really match its space group number to write cif file symmetry = spglib.get_symmetry_from_database(hall_number) rotations = symmetry['rotations'] translations = symmetry['translations'] return spacegroup, irred_cell, rotations, translations