def compare_cells(cell1, cell2, prec=1e-5): '''Compare two spglib cell if they are the same''' lattice_diff = np.linalg.norm(np.asarray(cell1[0]) - np.asarray(cell2[0])) same = False if lattice_diff < prec: pos1 = np.asarray(cell1[1]) pos2 = np.asarray(cell2[1]) if pos1.shape[0] == pos2.shape[0]: if len(cell1[2]) == len(cell2[2]): atom_type = (cell1[2] == cell2[2]).all() if atom_type == True: sym1 = spglib.get_symmetry(cell1, prec) sym2 = spglib.get_symmetry(cell2, prec) rota1 = np.asarray(sym1['rotations']) trans1 = np.asarray(sym1['translations']) rota2 = np.asarray(sym2['rotations']) trans2 = np.asarray(sym2['translations']) equi1 = np.asarray(sym1['equivalent_atoms']) equi2 = np.asarray(sym2['equivalent_atoms']) if rota1.shape[0] == rota2.shape[0]: diff_rotation = np.linalg.norm(rota1 - rota2) < prec if diff_rotation and (trans1.shape[0] == trans2.shape[0]): diff_translation = np.linalg.norm(trans1 - trans2) < prec if diff_translation and (equi1.shape[0] == equi2.shape[0]): diff_equi = np.linalg.norm(equi1 - equi2) < prec if diff_equi: same = True return same
def read_operation(poscar): import spglib [axis, atom_pos] = read_poscar(poscar) L = np.mat(axis) pos = [] atom_type = [] atom_dic = {} type_dic = {} index = 0 for line in atom_pos: pos.append(line[0:3]) if not line[4] in list(atom_dic.keys()): atom_dic[line[4]] = index type_dic[index] = [line[3], line[4]] index = index + 1 atom_type.append(atom_dic[line[4]]) D = np.mat(pos) Cell = (L, D, atom_type) rot_oper = np.ndarray.tolist( spglib.get_symmetry(Cell, symprec=1e-5)['rotations']) trans_oper = np.ndarray.tolist( spglib.get_symmetry(Cell, symprec=1e-5)['translations']) oper = [] for i in range(len(rot_oper)): if sum([abs(x - 0.5) for x in trans_oper[i] ]) > 1.5 - 0.0000001: # considering the PBC (1.0 = 0.0) oper.append(rot_oper[i]) # symmetry opperator according to a,b,c axis (not x,y,z axis) return oper
def test_supercell_replica(): total_path = os.path.dirname(os.path.abspath(__file__)) os.chdir(total_path) # Load the structure struct = CC.Structure.Structure() struct.read_scf("unit_cell_structure.scf") # Generate a supercell super_struct = struct.generate_supercell((2, 2, 1)) print("Space group before:") print(spglib.get_spacegroup(super_struct.get_ase_atoms()), ) print( len(spglib.get_symmetry(super_struct.get_ase_atoms())["translations"])) # Get the symmetries in the supercell using spglib spglib_syms = spglib.get_symmetry(super_struct.get_ase_atoms()) syms = CC.symmetries.GetSymmetriesFromSPGLIB(spglib_syms, False) nsyms = len(syms) # Generate a random distorted super structure d_structure = super_struct.copy() d_structure.coords += np.random.normal(scale=0.1, size=np.shape(d_structure.coords)) # Get the new pool of structures new_d_structures = [] for i in range(nsyms): # Get irt irt = CC.symmetries.GetIRT(super_struct, syms[i]) #print "Symmetry ", i #print len(set(irt)) u_disp = d_structure.coords - super_struct.coords new_u_disp = CC.symmetries.ApplySymmetryToVector( syms[i], u_disp, super_struct.unit_cell, irt[:]) tmp = super_struct.copy() tmp.coords += new_u_disp tmp.save_scf("replica_%d.scf" % i) new_d_structures.append(tmp) # Average all the displacements to see if the symmetries are recovered correctly new_structure = super_struct.copy() new_structure.coords = np.sum([x.coords for x in new_d_structures], axis=0) / nsyms # Get again the symmetries print("Symmetries after the sum:") print(spglib.get_spacegroup(new_structure.get_ase_atoms()), ) print( len( spglib.get_symmetry( new_structure.get_ase_atoms())["translations"])) # Lets check if the structure is the same as before # Should be 0 only if the symmeties are enaugh to have 0 force. print("Difference from the first one:") print(np.sqrt(np.sum((new_structure.coords - super_struct.coords)**2)))
def test_get_symmetry(self): for fname in self._filenames: cell = read_vasp(fname) if 'distorted' in fname: num_sym_dataset = len( get_symmetry_dataset(cell, symprec=1e-1)['rotations']) num_sym = len(get_symmetry(cell, symprec=1e-1)['rotations']) else: num_sym_dataset = len( get_symmetry_dataset(cell, symprec=1e-5)['rotations']) num_sym = len(get_symmetry(cell, symprec=1e-5)['rotations']) self.assertEqual(num_sym_dataset, num_sym)
def test_gen_nodup_cstru(self): c = Specie("Cu") t = Specie("Ti") m = [[-0.5, -0.5, -0.5], [-0.5, 0.5, 0.5], [ 0.5, -0.5, 0.5]] ele_sea = SitesGrid.sea(2, 2, 2, c) cell_mother_stru = CStru(m, ele_sea).get_cell() sym = get_symmetry(cell_mother_stru, symprec=1e-3) ops = [(r, t) for r, t in zip(sym['rotations'], sym['translations'])] sites_0 = [[[c, c], [c, c]], [[c, c], [t, c]]] sg_0 = SitesGrid(sites_0) cstru01 = CStru(m, sg_0) gen_01 = sogen.gen_nodup_cstru(m, c, (2,2,2), t, 1) nodup_01 = [stru for stru in gen_01] self.assertEqual(len(nodup_01), 1) gen_02 = sogen.gen_nodup_cstru(m, c, (1,2,8), t, 4) nodup_02 = [stru for stru in gen_02] # eq_(len(nodup_02), 51) m_tri = [[0, 0, 20], [1, 0, 0], [0.5, 0.8660254, 0]] ele_sea = SitesGrid.sea(1, 3, 3, c) cell_mother_stru = CStru(m, ele_sea).get_cell() sym = get_symmetry(cell_mother_stru, symprec=1e-3) ops = [(r, t) for r, t in zip(sym['rotations'], sym['translations'])] sites_0 = [[[c, c, c], [c, c, c], [c, c, c]]] sg_0 = SitesGrid(sites_0) cstru01 = CStru(m, sg_0) gen_01 = sogen.gen_nodup_cstru(m_tri, c, (1,3,3), t, 2) nodup_01 = [stru for stru in gen_01] self.assertEqual(len(nodup_01), 2) gen_02 = sogen.gen_nodup_cstru(m_tri, c, (1,3,3), t, 3) nodup_02 = [stru for stru in gen_02] self.assertEqual(len(nodup_02), 4) gen_03 = sogen.gen_nodup_cstru(m_tri, c, (1,5,5), t, 2) nodup_03 = [stru for stru in gen_03] self.assertEqual(len(nodup_03), 4)
def test_get_symmetry(self): for fname in self._filenames: spgnum = int(fname.split('-')[1]) cell = read_vasp("./data/%s" % fname) if 'distorted' in fname: num_sym_dataset = len( get_symmetry_dataset(cell, symprec=1e-1)['rotations']) num_sym = len(get_symmetry(cell, symprec=1e-1)['rotations']) else: num_sym_dataset = len( get_symmetry_dataset(cell, symprec=1e-5)['rotations']) num_sym = len(get_symmetry(cell, symprec=1e-5)['rotations']) self.assertEqual(num_sym_dataset, num_sym)
def symmetrically_inequivalent_indices(structure, center=None, species=None, symprec=0.01): cell = trans_pylada_stru_to_ase(structure) symmetry = spg.get_symmetry(cell, symprec=symprec) equivalent_atoms = symmetry['equivalent_atoms'] inequivalent_sites = np.unique(equivalent_atoms) if center is None: if species is None: return inequivalent_sites else: indices = [] for index in inequivalent_sites: if structure[index].type in species: print(structure[index].type) indices.append(index) return np.array(indices) else: center = np.dot(center, structure.cell.T) indices = [] equivalent = {} for index in inequivalent_sites: equivalent[index] = [index, 9999999] for i in range(len(equivalent_atoms)): index = equivalent_atoms[i] atom = structure[i] distance = np.linalg.norm(atom.pos - center) if equivalent[index][1] > distance: equivalent[index][0] = i equivalent[index][1] = distance for index in inequivalent_sites: if species is None: indices.append(equivalent[index][0]) else: if structure[index].type in species: indices.append(equivalent[index][0]) return np.array(indices)
def get_rotations(self, symprec=1e-5): """ dependent on spglib https://atztogo.github.io/spglib/ """ return spglib.get_symmetry( (self._lattice, self._positions, self._atoms), symprec)['rotations']
def _test_get_symmetry(self): """ *************************************************************** This test must be executed with spglib compiled with -DSPGTEST. *************************************************************** """ for fname, dataset, cell, symprec in zip( self._filenames, self._datasets, self._cells, self._symprecs): cell_spin = cell + ([1, ] * len(cell[2]),) symmetry = get_symmetry(cell_spin, symprec=symprec) self.assertEqual(len(dataset['rotations']), len(symmetry['rotations']), msg=("%s" % fname)) for r, t in zip(dataset['rotations'], dataset['translations']): found = False for r_, t_ in zip(symmetry['rotations'], symmetry['translations']): if (r == r_).all(): diff = t - t_ diff -= np.rint(diff) if (abs(diff) < symprec).all(): found = True break self.assertTrue(found, msg="%s" % fname)
def symmetry_operations(self, symprec=1e-2): """ Get the symmetry operations that the crystal unit cell respects. These symmetry operations are expressed in fractional coordinates. Parameters ---------- symprec : float, optional Symmetry-search distance tolerance in Cartesian coordinates [Angstroms]. Returns ------- sym_ops : iterable of 2-tuples Each symmetry operations is a tuple of ``(rotation, translation)``. A rotation matrix is an array of shape (3,3), while ``translation`` is an array of shape (3,). Raises ------ RuntimeError : if symmetry-determination has not succeeded. See also -------- Crystal.reciprocal_symmetry_operations : symmetry operations in reciprocal basis """ dataset = get_symmetry(cell=self._spglib_cell(), symprec=symprec) return [ SymmetryOperation(r, t) for r, t in zip(dataset["rotations"], dataset["translations"]) ]
def space_group_analyse(lattice, pos): numbers = [1, 2] cell = (lattice, pos, numbers) sp = spglib.get_spacegroup(cell, symprec=1e-5) symm = spglib.get_symmetry(cell, symprec=1e-5) #print(spglib.niggli_reduce(lattice, eps=1e-5)) #mesh = [8, 8, 8] #mapping, grid = spglib.get_ir_reciprocal_mesh(mesh, cell, is_shift=[0, 0, 0]) ## All k-points and mapping to ir-grid points #for i, (ir_gp_id, gp) in enumerate(zip(mapping, grid)): # print("%3d ->%3d %s" % (i, ir_gp_id, gp.astype(float) / mesh)) # ## Irreducible k-points #print("Number of ir-kpoints: %d" % len(np.unique(mapping))) #print(grid[np.unique(mapping)] / np.array(mesh, dtype=float)) # ## ## With shift ## #mapping, grid = spglib.get_ir_reciprocal_mesh(mesh, cell, is_shift=[1, 1, 1]) # ## All k-points and mapping to ir-grid points #for i, (ir_gp_id, gp) in enumerate(zip(mapping, grid)): # print("%3d ->%3d %s" % (i, ir_gp_id, (gp + [0.5, 0.5, 0.5]) / mesh)) # ## Irreducible k-points #print("Number of ir-kpoints: %d" % len(np.unique(mapping))) #print((grid[np.unique(mapping)] + [0.5, 0.5, 0.5]) / mesh) return sp, symm
def test_impose_symmetry(): total_path = os.path.dirname(os.path.abspath(__file__)) os.chdir(total_path) # initialize the dynamical matrix dyn = CC.Phonons.Phonons("old_dyn", full_name=True) # Print the symmetry group at high threshold GROUP = spglib.get_spacegroup(dyn.structure.get_ase_atoms(), 0.05) s_group_expected = spglib.get_spacegroup(dyn.structure.get_ase_atoms()) print ("Space group with high threshold:", s_group_expected) print ("Space group with low threshold:", GROUP) # Get the symmetries from the new spacegroup symmetries = spglib.get_symmetry(dyn.structure.get_ase_atoms(), symprec = 0.05) print("Number of symmetries: {}".format(len(symmetries["rotations"]))) # Transform the spglib symmetries into the CellConstructor data type sym_mats = CC.symmetries.GetSymmetriesFromSPGLIB(symmetries, True) # Force the symmetrization dyn.structure.impose_symmetries(sym_mats) # Check once again the symetry s_group_after = spglib.get_spacegroup(dyn.structure.get_ase_atoms()) print ("New space group with high threshold:", s_group_after) assert s_group_after == GROUP
def gulp_opt(stru): gulp_inp = 'opt.gin' tp_inp = 'tp_inp' out = 'out' cif_out = 'final.cif' symprec = 0.01 ccell = standardize_cell((stru.cell, stru.get_scaled_positions(), stru.numbers), symprec=symprec) if ccell: symmetry = get_symmetry(ccell, symprec=symprec) spacegroup = get_spacegroup(ccell, symprec=symprec) else: symmetry = get_symmetry((stru.cell, stru.get_scaled_positions(), stru.numbers), symprec=symprec) spacegroup = get_spacegroup((stru.cell, stru.get_scaled_positions(), stru.numbers), symprec=symprec) asymmetric_atoms = np.unique(symmetry.equivalent_atoms) pass
def get_max_rot_angle(self) -> None: ''' Get the maximum angle of rotation for a given slab that will generate all symmetrically distinct TS estimates. Returns ________ max_rot_angle : float a maximum angle of rotation of TS adducts on the given slab that would generate symmetrically dostinct configurations i.e. once the TS adduct is rotated by bigger angle than max_rot_angle, some of the generated structures will be symetrically equivalent to the others ''' # convert slab to ASE's Atom object slab = read(self.slab) # get all symmetry operations symm = get_symmetry(slab) # count rotations operations nrot = len(symm['rotations']) # the angle of rotation is 360 devided by nrot/2 as thera are equal # number of symmetry operations around the z axis # (e.g. for Cu_111 therea are 6 z and 6 -z operations) max_rot_angle = 360 / (nrot / 2) # max_rot_angle = 360/(nrot/4) # lets try 120 angle return max_rot_angle
def _test_get_symmetry(self): """ *************************************************************** This test must be executed with spglib compiled with -DSPGTEST. *************************************************************** """ for fname, dataset, cell, symprec in zip(self._filenames, self._datasets, self._cells, self._symprecs): cell_spin = cell + ([ 1, ] * len(cell[2]), ) symmetry = get_symmetry(cell_spin, symprec=symprec) self.assertEqual(len(dataset['rotations']), len(symmetry['rotations']), msg=("%s" % fname)) for r, t in zip(dataset['rotations'], dataset['translations']): found = False for r_, t_ in zip(symmetry['rotations'], symmetry['translations']): if (r == r_).all(): diff = t - t_ diff -= np.rint(diff) if (abs(diff) < symprec).all(): found = True break self.assertTrue(found, msg="%s" % fname)
def test_diag_symmetries(): total_path = os.path.dirname(os.path.abspath(__file__)) os.chdir(total_path) # Diagonalize the dynamical matrix in the supercell dyn = CC.Phonons.Phonons("../TestDiagonalizeSupercell/prova", 4) w, p = dyn.DiagonalizeSupercell() view(dyn.structure.get_ase_atoms()) # Get the symmetries supercell_s = dyn.structure.generate_supercell(dyn.GetSupercell()) spglib_syms = spglib.get_symmetry(dyn.structure.get_ase_atoms()) syms = CC.symmetries.GetSymmetriesFromSPGLIB(spglib_syms) # Get the symmetries on the polarization vectors pols_syms = CC.symmetries.GetSymmetriesOnModes(syms, supercell_s, p) # Now complete the diagonalization of the polarization vectors # To fully exploit symmetries new_pols, syms_character = CC.symmetries.get_diagonal_symmetry_polarization_vectors(p, w, pols_syms) # TODO: Test if these new polarization vectors really rebuild the dynamical matrix # write the symmetry character n_modes, n_syms = syms_character.shape for i in range(n_modes): print("Mode {} | ".format(i), np.angle(syms_character[i,:], deg = True))
def analyse_phonopy_equivalent_atoms(atoms, symprec=1e-5, angle_tolerance=-1.0): """ Args: (read phonopy.structure.spglib for more details) symprec: float: Symmetry search tolerance in the unit of length. angle_tolerance: float: Symmetry search tolerance in the unit of angle deg. If the value is negative, an internally optimized routine is used to judge symmetry. """ state.publications.add(publication()) positions = atoms.get_scaled_positions() cell = atoms.cell types = atoms.get_chemical_symbols() types = list(types) natom = len(types) positions = np.reshape(np.array(positions), (natom, 3)) cell = np.reshape(np.array(cell), (3, 3)) unitcell = PhonopyAtoms(symbols=types, cell=cell, scaled_positions=positions) ops = spg.get_symmetry(unitcell, symprec=symprec, angle_tolerance=angle_tolerance) return ops["equivalent_atoms"]
def test_update_isoset(self): c = Specie("Cu") t = Specie("Ti") m = [[-0.5, -0.5, -0.5], [-0.5, 0.5, 0.5], [ 0.5, -0.5, 0.5]] ele_sea = SitesGrid.sea(2, 2, 2, c) cell_mother_stru = CStru(m, ele_sea).get_cell() sym = get_symmetry(cell_mother_stru, symprec=1e-5) ops = [(r, t) for r, t in zip(sym['rotations'], sym['translations'])] sym_perm = sogen.get_permutation_cell(cell_mother_stru) sites_0 = [[[c, c], [c, c]], [[c, c], [t, c]]] sg_0 = SitesGrid(sites_0) cstru01 = CStru(m, sg_0) number01 = cstru01.get_cell()[2] isoset_init = set() isoset_init_copy = isoset_init.copy() isoset_a01 = sogen._update_isoset(isoset_init, number01, sym_perm) self.assertNotEqual(isoset_a01, isoset_init_copy) self.assertIsInstance(isoset_a01, set) isoset_a01_copy = isoset_a01.copy() isoset_a02 = sogen._update_isoset(isoset_a01, number01, sym_perm) self.assertEqual(isoset_a02, isoset_a01_copy) self.assertLessEqual(len(isoset_a01), len(ops))
def get_symmetry(atoms, tol=1e-8): """Atoms object interface with spglib symmetry finder: https://atztogo.github.io/spglib/python-spglib.html#python-spglib Parameters ---------- atoms : object Atoms object to search for symmetric structures of. tol : float Tolerance for floating point rounding errors. Returns ------- symmetry operations: ndarray (n, n) Symmetry operations from spglib. """ lattice = atoms.cell positions = atoms.get_scaled_positions() numbers = atoms.get_atomic_numbers() cell = (lattice, positions, numbers) symmetry = spglib.get_symmetry(cell, symprec=tol) rotations, translations = symmetry['rotations'], symmetry['translations'] return rotations, translations
def matrix_of_equivalent_positions_from_structure(structure: Atoms, cutoff: float, position_tolerance: float, symprec: float, find_primitive: bool = True) \ -> Tuple[np.ndarray, Structure, List]: """Sets up a list of permutation maps from an Atoms object. Parameters ---------- structure input structure cutoff cutoff radius find_primitive if True the symmetries of the primitive structure will be employed symprec tolerance imposed when analyzing the symmetry using spglib position_tolerance tolerance applied when comparing positions in Cartesian coordinates Returns ------- The tuple that is returned comprises the permutation matrix, the primitive structure, and the neighbor list. """ structure = structure.copy() structure_prim = structure if find_primitive: structure_prim = get_primitive_structure(structure, symprec=symprec) logger.debug('Size of primitive structure: {}'.format(len(structure_prim))) # get symmetry information structure_as_tuple = ase_atoms_to_spglib_cell(structure_prim) symmetry = spglib.get_symmetry(structure_as_tuple, symprec=symprec) translations = symmetry['translations'] rotations = symmetry['rotations'] # set up a permutation map object matrix_of_equivalent_positions = MatrixOfEquivalentPositions( translations, rotations) # create neighbor_lists from the different cutoffs prim_icet_structure = Structure.from_atoms(structure_prim) neighbor_list = get_neighbor_lists( prim_icet_structure, [cutoff], position_tolerance=position_tolerance)[0] # get fractional positions for neighbor_list frac_positions = get_fractional_positions_from_neighbor_list( prim_icet_structure, neighbor_list) logger.debug('Number of fractional positions: {}'.format( len(frac_positions))) if frac_positions is not None: matrix_of_equivalent_positions.build(frac_positions) return matrix_of_equivalent_positions, prim_icet_structure, neighbor_list
def __init__(self, unit_gcell, lat_coeff): self.ub = unit_gcell.lattice self.upositions = unit_gcell.positions self.unumbers = unit_gcell.numbers self.lat_coeff = lat_coeff self.unit_cell = unit_gcell.spg_cell self.sym = spglib.get_symmetry(self.unit_cell, symprec=1e-3)
def test_check_fc_symmetry(): total_path = os.path.dirname(os.path.abspath(__file__)) os.chdir(total_path) """ This script check the symmetries of a dynamical matrix. In the end the symmetry is constrained. """ RyToCm = 109691.40235 # Read the dynamical matrix PH = CC.Phonons.Phonons("hydrogen_dyn", nqirr=1) print("Loaded hydrogen_dyn1") print("Symmetry group:", spglib.get_spacegroup(PH.structure.get_ase_atoms(), 0.01)) # Get info about the symmetries of the structure symmetries = spglib.get_symmetry(PH.structure.get_ase_atoms(), 0.01) print("Number of symmetries:", len(symmetries["rotations"])) # Convert the spglib symmetries into the cellconstructor format sym_mats = CC.symmetries.GetSymmetriesFromSPGLIB(symmetries) # Impose the symmetries on the structure PH.structure.fix_coords_in_unit_cell() PH.structure.impose_symmetries(sym_mats) # get a random matrix nat = PH.structure.N_atoms #PH.dynmats[0][:,:] = np.random.uniform(size = (3 * nat, 3*nat)) #PH.dynmats[0] += PH.dynmats[0].T # Get frequencies of the original matrix w, pols = PH.DyagDinQ(0) PH_new = PH.Copy() # Force the symmetrization #PH_new.SymmetrizeSupercell((1,1,1)) qe_sym = CC.symmetries.QE_Symmetry(PH.structure) #qe_sym.SetupQPoint(verbose = True) qe_sym.SetupFromSPGLIB() #qe_sym.SymmetrizeDynQ(PH_new.dynmats[0], np.array([0,0,0])) qe_sym.ApplySymmetriesToV2(PH_new.dynmats[0]) CC.symmetries.CustomASR(PH_new.dynmats[0]) new_w, new_pols = PH_new.DyagDinQ(0) # Symmetrize using the quantum espresso PH.Symmetrize() w_qe, p_qe = PH.DyagDinQ(0) print("Old Matrix | Python Symmetries | QE Symmetries | ") print("\n".join([ "%12.2f\t%12.2f\t%12.2f cm-1" % (w[k] * RyToCm, new_w[k] * RyToCm, w_qe[k] * RyToCm) for k in range(0, len(w)) ]))
def get_sym(cell, symprec=1e-5, print_atom=False, print_analysis=True): '''Giving a cell, return symmetry analysis''' # spglib only work with tuple cell = tuple(cell) #Space group info spg_label, spg_number = spglib.get_spacegroup(cell, symprec).split(' ') spg_number = spg_number.split("(")[1].split(")")[0] Schoenflies_label = spglib.get_spacegroup(cell, symprec, symbol_type=1).split(' ')[0] sym = spglib.get_symmetry(cell, symprec) rotations = sym['rotations'] translations = sym['translations'] equi_atoms = sym['equivalent_atoms'] is_std = is_prim = False std_cell = spglib.refine_cell(cell, symprec) prim_cell = spglib.find_primitive(cell, symprec) if compare_cells(cell, std_cell): is_std = True if compare_cells(cell, prim_cell): is_prim = True atoms = utils.convert_atomtype(cell[2]) if print_analysis == True: #Cell info std_cell = spglib.refine_cell(cell, symprec) prim_cell = spglib.find_primitive(cell, symprec) #Print misc.print_msg("Spacegroup number : %s" % (spg_number)) misc.print_msg("Short International symbol : %s" % (spg_label)) misc.print_msg("Schoenflies symbol : %s" % (Schoenflies_label)) if print_atom == True: misc.print_msg("Atoms list (No. - Sym - Symbol):") for i, atom in enumerate(atoms): misc.print_msg("%3d %3d %s" % (i + 1, equi_atoms[i] + 1, atom)) misc.print_msg("Irreducible atoms:") for i, index in enumerate(np.unique(equi_atoms)): coord = cell[1][index] misc.print_msg( "%3d %3s %7f5 %7f5 %7f5" % (i + 1, atoms[index], coord[0], coord[1], coord[2])) misc.print_msg("Number of irreducible atoms : %d" % (np.unique(equi_atoms).shape[0])) misc.print_msg("Standard cell : %r" % (is_std)) misc.print_msg("Primitive cell : %r" % (is_prim)) else: # Return an standard cell object with irreducible atoms irred_idx = np.unique(equi_atoms) lattice = cell[0] irred_coord = cell[1][irred_idx, :] irred_label = np.array(cell[2])[irred_idx] irred_cell = (lattice, irred_coord, irred_label) return irred_cell, int(spg_number), spg_label, rotations, translations
def get_symmetry(self): """ Symmetry operations are obtained as a dictionary. The key rotation contains a numpy array of integer, which is “number of symmetry operations” x “3x3 matrices”. The key translation contains a numpy array of float, which is “number of symmetry operations” x “vectors”. """ symmetry = spglib.get_symmetry(self._spg_cell, symprec=self.symprec) return symmetry
def setUp(self): """Setup before each test.""" symmetry = spglib.get_symmetry( ase_atoms_to_spglib_cell(self.structure_prim)) self.translations = symmetry['translations'] self.rotations = symmetry['rotations'] self.pm = MatrixOfEquivalentPositions(self.translations, self.rotations) self.pm.build(self.frac_positions)
def get_unique_wyckoff(ats_in): """ Function to find unique wyckoff sites in the primitive cell Args: ats_in(:ase:class:`Atoms`): Atoms object of interface. Returns unique list of lattice sites in primitive cell [[position,"chem_abbrev"],...] """ # compute space group for the given primitive cell using spglib ats = ats_in.copy() #sym = spglib.get_symmetry(ats, 0.1) sym = spglib.get_symmetry(ats) # compute inverce cell of the primitive cell inverse_cell = np.linalg.inv(ats.cell) dummy_list = [] wyckoff_list = [] #args = np.argsort(ats.positions[:, 0]) #ats = ats[args] for i, at in enumerate(ats): print i, '/', len(ats) a = at.position a3 = get_pos_in_prim_cell(ats.copy(), a) frac_a = np.dot(inverse_cell, a3) symm_list = [] for j in range(len(sym['rotations'])): # rotation matrix from sym R = sym['rotations'][j] # translation vector from sym Tt = sym['translations'][j] frac_symm_a = np.dot(R, frac_a) + Tt symm_a = np.dot(ats.cell, frac_symm_a) symm_list.append(symm_a) symm_a2 = get_pos_in_prim_cell(ats.copy(), symm_a) symm_list.append(symm_a2) # loop to find symmetrical equivalent positions for k in range(i + 1, len(ats)): b = ats[k].position b2 = get_pos_in_prim_cell(ats, b) # check distance between positions in pos and symm_list if any(distance.euclidean(b, c) < 0.1 for c in symm_list): ats[k].position = ats[i].position dummy_list = a.tolist() dummy_list.append(ats[i].symbol) wyckoff_list.append(dummy_list) ### getting unique array of positions unique_list = [list(t) for t in set(map(tuple, wyckoff_list))] return unique_list
def spginfo(self): cell = (self.a, self.frac, self.charges) print("[get_spacegroup]") print(" Spacegroup of cell is %s" % spg.get_spacegroup(cell)) print("[get_symmetry]") print(" Symmetry operations of unitcell are") symmetry = spg.get_symmetry(cell) show_symmetry(symmetry) print("[get_pointgroup]") print(" Pointgroup of cell is %s" % spg.get_pointgroup(symmetry['rotations'])[0]) dataset = spg.get_symmetry_dataset(cell) print("[get_symmetry_dataset] ['international']") print(" Spacegroup of cell is %s (%d)" % (dataset['international'], dataset['number'])) print("[get_symmetry_dataset] ['pointgroup']") print(" Pointgroup of cell is %s" % (dataset['pointgroup'])) print("[get_symmetry_dataset] ['hall']") print(" Hall symbol of cell is %s (%d)." % (dataset['hall'], dataset['hall_number'])) print("[get_symmetry_dataset] ['wyckoffs']") alphabet = "abcdefghijklmnopqrstuvwxyz" print(" Wyckoff letters of cell are ", dataset['wyckoffs']) print("[get_symmetry_dataset] ['equivalent_atoms']") print(" Mapping to equivalent atoms of cell ") for i, x in enumerate(dataset['equivalent_atoms']): print(" %d -> %d" % (i + 1, x + 1)) print("[get_symmetry_dataset] ['rotations'], ['translations']") print(" Symmetry operations of unitcell are:") for i, (rot, trans) in enumerate( zip(dataset['rotations'], dataset['translations'])): print(" --------------- %4d ---------------" % (i + 1)) print(" rotation:") for x in rot: print(" [%2d %2d %2d]" % (x[0], x[1], x[2])) print(" translation:") print(" (%8.5f %8.5f %8.5f)" % (trans[0], trans[1], trans[2])) reduced_lattice = spg.niggli_reduce(self.a) print("[niggli_reduce]") print(" Original lattice") show_lattice(self.a) print(" Reduced lattice") show_lattice(reduced_lattice) mapping, grid = spg.get_ir_reciprocal_mesh([11, 11, 11], cell, is_shift=[0, 0, 0]) num_ir_kpt = len(numpy.unique(mapping)) print("[get_ir_reciprocal_mesh]") print(" Number of irreducible k-points of primitive") print(" 11x11x11 Monkhorst-Pack mesh is %d " % num_ir_kpt) return self
def get_permutation_cell(cell): lat, pos, num = cell atom_num = len(cell[2]) numbers = [i for i in range(atom_num)] sym = get_symmetry(cell, symprec=1e-3) ops = [(r, t) for r, t in zip(sym['rotations'], sym['translations'])] sym_perm = [] for r, t in ops: pos_new = np.transpose(np.matmul(r, np.transpose(pos))) + t perm = get_new_id_seq(pos_new, numbers) sym_perm.append(perm) return sym_perm
def get_symmetry( self, symprec: float = 1e-5, angle_tolerance: float = -1) -> Union[Dict[str, np.ndarray], None]: """Return dictionary of symmetry operations :params symprec: distance tolerance in Cartesian coordinates to find crystal symmetry. Default: 1e-5 :params angle_tolerance: tolerance of angle between basis vectors in degrees to be tolerated in the symmetry finding. Default: -1 :return dictionary with keys "rotation", "translation" and "equivalent_atoms" """ import spglib return spglib.get_symmetry(self.spgcell, symprec, angle_tolerance)
def _get_symmetry(self): """ Get the symmetry operations associated with the structure. Returns: Symmetry operations as a tuple of two equal length sequences. (rotations, translations). "rotations" is the numpy integer array of the rotation matrices for scaled positions "translations" gives the numpy float64 array of the translation vectors in scaled positions. """ d = spglib.get_symmetry(self._cell, symprec=self._symprec, angle_tolerance=self._angle_tol) return d["rotations"], d["translations"]
def writeCIF(cell, prec, basename): # Find spacegroup name and number sg = spglib.get_spacegroup(cell, symprec=prec) sg, sgid = sg.split(' (') sgid = sgid.replace(')', '') # Find detailed info about the refined cell lattice, scaled_positions, numbers = spglib.refine_cell(cell, prec) if len(numbers) != len(cell): # create new cell ncell = (lattice, scaled_positions, numbers) else: ncell = copy.deepcopy(cell) sym = spglib.get_symmetry(ncell, prec) uniques = np.unique(sym['equivalent_atoms']) a, b, c, alpha, beta, gamma = cellParameters(lattice) f = open((basename + '_' + sgid + '.cif').replace('/', '|'), 'w') f.write(f'# Symmetrized structure with precision = {prec}\n') f.write(f'data_{basename}{sg}\n'.replace(' ', '_')) f.write('_cell_length_a %.7g\n' % a) f.write('_cell_length_b %.7g\n' % b) f.write('_cell_length_c %.7g\n' % c) f.write('_cell_angle_alpha %.7g\n' % alpha) f.write('_cell_angle_beta %.7g\n' % beta) f.write('_cell_angle_gamma %.7g\n' % gamma) f.write("_symmetry_space_group_name_H-M '" + sg + "'\n") f.write('_symmetry_Int_Tables_number ' + str(sgid) + '\n') # Write out atomic positions f.write(''' loop_ _atom_site_label _atom_site_type_symbol _atom_site_occupancy _atom_site_fract_x _atom_site_fract_y _atom_site_fract_z ''') for pos, at in zip(scaled_positions[uniques], numbers[uniques]): sym = element_symbols[at] f.write('%s %s 1.0 %.7f %.7f %.7f\n' % (sym, sym, pos[0], pos[1], pos[2])) f.close()
print(" Spacegroup of Silicon is %s." % spglib.get_spacegroup(silicon)) print('') print("[get_spacegroup]") print(" Spacegroup of Silicon (ASE Atoms-like format) is %s." % spglib.get_spacegroup(silicon_ase)) print('') print("[get_spacegroup]") print(" Spacegroup of Rutile is %s." % spglib.get_spacegroup(rutile)) print('') print("[get_spacegroup]") print(" Spacegroup of MgB2 is %s." % spglib.get_spacegroup(MgB2)) print('') print("[get_symmetry]") print(" Symmetry operations of Rutile unitcell are:") print('') symmetry = spglib.get_symmetry(rutile) show_symmetry(symmetry) print('') print("[get_symmetry]") print(" Symmetry operations of MgB2 are:") print('') symmetry = spglib.get_symmetry(MgB2) show_symmetry(symmetry) print('') print("[get_pointgroup]") print(" Pointgroup of Rutile is %s." % spglib.get_pointgroup(symmetry['rotations'])[0]) print('') dataset = spglib.get_symmetry_dataset( rutile ) print("[get_symmetry_dataset] ['international']")
def test_get_symmetry_broken_magmoms(self): self._cell[3][0] = 1 self._cell[3][1] = 2 sym = get_symmetry(self._cell) self.assertEqual(48, len(sym['rotations'])) self.assertTrue((sym['equivalent_atoms'] == [0, 1]).all())
def test_get_symmetry_anti_ferro(self): self._cell[3][0] = 1 self._cell[3][1] = -1 sym = get_symmetry(self._cell) self.assertEqual(96, len(sym['rotations'])) self.assertTrue((sym['equivalent_atoms'] == [0, 0]).all())
def get_symmetry(self, symprec=1e-5): return spg.get_symmetry(cell=self.spglib_cell, symprec=symprec)