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 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 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 refine(ase_obj, accuracy=1E-03): """ Refine ASE structure using spglib Args: ase_obj: (object) ASE structure accuracy: (float) spglib tolerance, normally within [1E-02, 1E-04] Returns: Refined ASE structure (object) *or* None None *or* error (str) """ try: symmetry = spglib.get_spacegroup(ase_obj, symprec=accuracy) lattice, positions, numbers = spglib.refine_cell(ase_obj, symprec=accuracy) except: return None, 'Error while structure refinement' try: spacegroup = int(symmetry.split()[1].replace("(", "").replace(")", "")) except (ValueError, IndexError): return None, 'Symmetry error (coinciding atoms?) in structure' try: return crystal(Atoms(numbers=numbers, cell=lattice, scaled_positions=positions, pbc=True), spacegroup=spacegroup, primitive_cell=True, onduplicates='replace'), None except: return None, 'Unrecognized sites or invalid site symmetry in structure'
def symmetrise(self, sbs=[], symprec=1e-2): import spglib if len(sbs) == 0: sbs = range(self.nframes) for i in sbs: frame = self.frames[i] frame.info['space_group'] = spglib.get_spacegroup(frame, symprec=symprec)
def main(fxyz, prefix, verbose, precision): # read frames if fxyz != 'none': frames = read(fxyz, ':') nframes = len(frames) print("read xyz file:", fxyz, ", a total of", nframes, "frames") standardized_frames = [] for frame in frames: space_now = spglib.get_spacegroup( frame, symprec=precision) # spglib.get_symmetry(frame, symprec=1e-1)) print(space_now) lattice, scaled_positions, numbers = spglib.standardize_cell( frame, to_primitive=1, no_idealize=1, symprec=precision) if verbose: show_cell(lattice, scaled_positions, numbers) # output frtemp = atom(numbers=numbers, cell=lattice, scaled_positions=scaled_positions, pbc=frame.get_pbc()) frtemp.info['space_group'] = space_now standardized_frames.append(frtemp) write(prefix + '-standardized.xyz', standardized_frames)
def get_primitive_cell(axis, atom_pos): import spglib import numpy as np 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 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) prim_cell = spglib.find_primitive(Cell, symprec=2e-3) equ_atoms = spglib.get_symmetry_dataset(prim_cell, symprec=2e-3)['equivalent_atoms'] prim_axis = prim_cell[0].tolist() prim_pos = prim_cell[1].tolist() prim_type = prim_cell[2].tolist() prim_atom_pos = [] for i in range(len(prim_pos)): prim_atom_pos.append(prim_pos[i] + type_dic[prim_type[i]]) sym = spglib.get_spacegroup(Cell, symprec=2e-3).split('(')[1].split(')')[0] [new_axis, new_pos, sym_typ] = axis_rotation(prim_axis, prim_atom_pos, sym) return [new_axis, new_pos, sym_typ]
def get_lattice_type(self): ''' Find the symmetry of the crystal using spglib symmetry finder. Assign to sg_name i sg_nr members name of the space group and its number extracted from the result. Based on the group number identify also the lattice type (assigned to sg_type member) and the Bravais lattice of the crystal (assigned to bravais member). The returned value is the lattice type number. The lattice type numbers are (see also Crystal.ls, the numbering starts from 1): Triclinic (1), Monoclinic (2), Orthorombic (3), Tetragonal (4) Trigonal (5), Hexagonal (6), Cubic (7) ''' # Table of lattice types and correcponding group numbers dividing # the ranges. See get_lattice_type method for precise definition. lattice_types = [[3, "Triclinic"], [16, "Monoclinic"], [75, "Orthorombic"], [143, "Tetragonal"], [168, "Trigonal"], [195, "Hexagonal"], [231, "Cubic"]] sg = spg.get_spacegroup(self) m = re.match('([A-Z].*\\b)\s*\(([0-9]*)\)', sg) self.sg_name = m.group(1) self.sg_nr = int(m.group(2)) for n, l in enumerate(lattice_types): if self.sg_nr < l[0]: lattice = l[1] lattype = n + 1 break self.sg_type = lattype self.bravais = lattice return lattype
def write_struct_boltztrap(structure, filename): ao = io.read(structure) spacegroup = spglib.get_spacegroup(ao, symprec=1e-5) ao.info = {'spacegroup': spacegroup} filename = str(filename + ".struct") with open(filename, "w") as out: out.write('HTE output' + '\n') # title latt = ao.get_cell() / 0.5291772083 for i in range(3): line = '' for j in range(3): line = line + "%12.5f" % latt[i][j] out.write(line + '\n') krot = get_kspace_operations(ao) out.write(str(len(krot)) + '\n') for iop in range(len(krot)): for i in range(3): for j in range(3): out.write(str(krot[iop][i][j]) + ' ') out.write('\n') return
def get_interstitials(ats, ttol=0.5): """Function to return unique interstitial sites in the given structure. Args: Atoms(:ase:class:`Atoms`): atoms object. ttol(float): tolerance on distance between interstitials to be considered unique. Returns: list of unique intestital sites (cartesian (x,y,z) as list) in the given structure. """ # s = deepcopy(structure) # prim = primitive(s) spg = spglib.get_spacegroup(ats, 0.1) ### Step 1: get unique sites in the primitive of the given structure uniq_sites = get_unique_wyckoff(ats) ### Step 2: get all interstitial sites from Voronoi method ints2 = get_all_interstitials(ats, uniq_sites) ### get interstital sites within primitive cell ints_prim = get_ints_in_prim_cell(ats, ints2) ### Step 3: get unique interstitials after symmetry analysis ints3 = get_unique_ints(ats, ints_prim, ttol=ttol) return ints3
def mongo_atoms_doc(atoms): """Return a dictionary of an Atoms object.""" d = OrderedDict(atoms=[{ 'symbol': atom.symbol, 'position': json.loads(encode(atom.position)), 'tag': atom.tag, 'index': atom.index, 'charge': atom.charge, 'momentum': json.loads(encode(atom.momentum)), 'magmom': atom.magmom } for atom in atoms], cell=atoms.cell, pbc=atoms.pbc, info=atoms.info, constraints=[c.todict() for c in atoms.constraints]) # redundant information for search convenience. d['natoms'] = len(atoms) cell = atoms.get_cell() if cell is not None and np.linalg.det(cell) > 0: d['volume'] = atoms.get_volume() d['mass'] = sum(atoms.get_masses()) syms = atoms.get_chemical_symbols() d['chemical_symbols'] = list(set(syms)) d['symbol_counts'] = {sym: syms.count(sym) for sym in syms} d['spacegroup'] = spglib.get_spacegroup(atoms) d['hash'] = get_hash(atoms) return json.loads(encode(d))
def _make_atoms_dict(atoms): ''' Convert an ase.Atoms object into a dictionary for json storage. Arg: atoms ase.Atoms object Returns: atoms_dict A dictionary with various atoms information stored ''' atoms_dict = OrderedDict( atoms=[{ 'symbol': atom.symbol, 'position': json.loads(encode(atom.position)), 'tag': atom.tag, 'index': atom.index, 'charge': atom.charge, 'momentum': json.loads(encode(atom.momentum)), 'magmom': atom.magmom } for atom in atoms], cell=atoms.cell, pbc=atoms.pbc, info=atoms.info, constraints=[c.todict() for c in atoms.constraints]) # Redundant information for search convenience. atoms_dict['natoms'] = len(atoms) cell = atoms.get_cell() atoms_dict['mass'] = sum(atoms.get_masses()) syms = atoms.get_chemical_symbols() atoms_dict['chemical_symbols'] = list(set(syms)) atoms_dict['symbol_counts'] = {sym: syms.count(sym) for sym in syms} atoms_dict['spacegroup'] = spglib.get_spacegroup(atoms) if cell is not None and np.linalg.det(cell) > 0: atoms_dict['volume'] = atoms.get_volume() return json.loads(encode(atoms_dict))
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 symmetry(self, symprec=1e-3): """ Compute space group with spglib. """ from matador.utils.cell_utils import doc2spg import spglib as spg print('Refining symmetries...') if self.mode == 'display': print_warning('{}'.format('At symprec: ' + str(symprec))) print_warning("{:^36}{:^16}{:^16}".format('text_id', 'new sg', 'old sg')) for _, doc in enumerate(self.cursor): try: spg_cell = doc2spg(doc) sg = spg.get_spacegroup(spg_cell, symprec=symprec).split(' ')[0] if sg != doc['space_group']: self.changed_count += 1 self.diff_cursor.append(doc) if self.mode == 'display': print_notify("{:^36}{:^16}{:^16}" .format(doc['text_id'][0]+' '+doc['text_id'][1], sg, doc['space_group'])) doc['space_group'] = sg else: if self.mode == 'display': print("{:^36}{:^16}{:^16}" .format(doc['text_id'][0]+' '+doc['text_id'][1], sg, doc['space_group'])) except Exception: self.failed_count += 1 if self.args.get('debug'): print_exc() print_failure('Failed for' + ' '.join(doc['text_id']))
def findsym(fname, prec=None, verbose=True): ''' Reads cif file using ASE parser and extracts symmetry using spglib over different levels of tolerence ''' if prec: assert (type(prec) == type(1e-10)) precs = [prec] else: t = [1, 2, 3, 5, 7] precs = [1e-10, 1e-9, 1e-8, 1e-7, 1e-6] + [ i * j for i in [1e-5, 1e-4, 1e-3, 1e-2, 1e-1] for j in t ] old = '' if verbose: print('# Tolerance\tSpace group') cell = ase.io.read(fname) for prec in precs: s = spglib.get_spacegroup(cell, symprec=prec) if s != old: if verbose: print(f'{prec}\t\t{s}') old = s sg, sgid = old.split(' (') sgid = sgid.replace(')', '') return sg, sgid
def get_spacegroup_and_kpath(structure, symprec=1.0e-9): """ :param: structure is an instance of crystal() """ lattice = structure.cell positions = [] numbers = [] a = np.sqrt(structure.cell[0][0]**2 + structure.cell[0][1]**2 + structure.cell[0][2]**2) b = np.sqrt(structure.cell[1][0]**2 + structure.cell[1][1]**2 + structure.cell[1][2]**2) c = np.sqrt(structure.cell[2][0]**2 + structure.cell[2][1]**2 + structure.cell[2][2]**2) frac_coord = structure.get_fractional() for i in range(len(frac_coord)): positions.append( [frac_coord[i][1], frac_coord[i][2], frac_coord[i][3]]) # must be fractional coordinates numbers.append(element[frac_coord[i][0]].number) cell = (lattice, positions, numbers) return [ spglib.get_spacegroup(cell, symprec=symprec), seekpath.get_path(cell) ]
def mongo_atoms_doc(atoms): """Return a dictionary of an Atoms object.""" d = OrderedDict(atoms=[{'symbol': atom.symbol, 'position': json.loads(encode(atom.position)), 'tag': atom.tag, 'index': atom.index, 'charge': atom.charge, 'momentum': json.loads(encode(atom.momentum)), 'magmom': atom.magmom} for atom in atoms], cell=atoms.cell, pbc=atoms.pbc, info=atoms.info, constraints=[c.todict() for c in atoms.constraints]) # redundant information for search convenience. d['natoms'] = len(atoms) cell = atoms.get_cell() if cell is not None and np.linalg.det(cell) > 0: d['volume'] = atoms.get_volume() d['mass'] = sum(atoms.get_masses()) syms = atoms.get_chemical_symbols() d['chemical_symbols'] = list(set(syms)) d['symbol_counts'] = {sym: syms.count(sym) for sym in syms} d['spacegroup'] = spglib.get_spacegroup(atoms) return json.loads(encode(d))
def get_lattice_type(cryst): '''Find the symmetry of the crystal using spglib symmetry finder. Derive name of the space group and its number extracted from the result. Based on the group number identify also the lattice type and the Bravais lattice of the crystal. The lattice type numbers are (the numbering starts from 1): Triclinic (1), Monoclinic (2), Orthorombic (3), Tetragonal (4), Trigonal (5), Hexagonal (6), Cubic (7) :param cryst: ASE Atoms object :returns: tuple (lattice type number (1-7), lattice name, space group name, space group number) ''' # Table of lattice types and correcponding group numbers dividing # the ranges. See get_lattice_type method for precise definition. lattice_types = [[3, "Triclinic"], [16, "Monoclinic"], [75, "Orthorombic"], [143, "Tetragonal"], [168, "Trigonal"], [195, "Hexagonal"], [231, "Cubic"]] sg = spg.get_spacegroup(cryst) m = re.match(r'([A-Z].*\b)\s*\(([0-9]*)\)', sg) sg_name = m.group(1) sg_nr = int(m.group(2)) for n, l in enumerate(lattice_types): if sg_nr < l[0]: bravais = l[1] lattype = n + 1 break return lattype, bravais, sg_name, sg_nr
def test_spglib_symmetries(self): self.assertTrue(__SPGLIB__) self.assertTrue(__ASE__) if __SPGLIB__ and __ASE__: spacegroup = spglib.get_spacegroup(self.struct_ice.get_ase_atoms()) self.assertEqual(spacegroup, "Cmc2_1 (36)")
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 get_spacegroup(structure): """ returns the spacegorup of a given AiiDA structure """ import spglib s_ase = structure.get_ase() spacegroup = spglib.get_spacegroup(s_ase, symprec=1e-5) return spacegroup
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, export_operator=False): #Space group info intl_label, number = spglib.get_spacegroup(cell, symprec).split(' ') number = 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 export_operator == False: #Cell info std_cell = spglib.refine_cell(cell, symprec) prim_cell = spglib.find_primitive(cell, symprec) #Print misc.print_msg("Spacegroup number : %s" % (number)) misc.print_msg("Short International symbol : %s" % (intl_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)): misc.print_msg("%3d %3s %7f5 %7f5 %7f5" % (i + 1, atoms[index], cell[1][index][0], cell[1][index][1], cell[1][index][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)) return is_std, is_prim else: return (number, intl_label), equi_atoms, rotations, translations
def spacegroup(self, symprec=1e-3): """Get spacegroup of the atoms object.""" import spglib sg = spglib.get_spacegroup( (self.lattice_mat, self.frac_coords, self.atomic_numbers), symprec=symprec, ) return sg
def get_spacegroup(self, tilde_obj): try: symmetry = spg.get_spacegroup(tilde_obj['structures'][-1], symprec=self.accuracy, angle_tolerance=self.angle_tolerance) except Exception as ex: self.error = 'Symmetry finder error: %s' % ex else: symmetry = symmetry.split() self.i = symmetry[0] try: self.n = int( symmetry[1].replace("(", "").replace(")", "") ) except (ValueError, IndexError): self.n = 0 if self.n == 0: self.error = 'Symmetry finder error (probably, coinciding atoms)'
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_spacegroup(self, symprec: float = 1e-5, angle_tolerance: float = -1, symbol_type: int = 0) -> Union[str, None]: """Return International space group short symbol and number or Schoenflies symbol :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 :params symbol_type: 0 - International, 1 - Schoenflies """ import spglib return spglib.get_spacegroup(self.spgcell, symprec, angle_tolerance, symbol_type)
def identify_spacegroup(spg_cell, max_iterations=200, minimum_distance=.9): """This function aims to identify the best spacegroup based on allowing some amount of deviation. Accepts a spglib compatible cell tuple as the argument.""" # Note that while precision to spglib is in cartesian distance, # input positions are fractional coordinates prec = 5 * minimum_distance precs = [] grps = [] grp = 'None' highest_symmetry_group = 'None' max_group = 0 # Try a range of precisions and record the determined spacegroups counter = 0 while grp is None or grp.split()[-1] not in ['(1)', '(2)']: counter += 1 if counter > max_iterations: break grp = spglib.get_spacegroup(spg_cell, symprec=prec) grps.append(grp) precs.append(prec) prec /= 2 if grp is not None: group_num = int(grp.split()[-1].replace('(', '').replace(')', '')) if group_num > max_group: max_group = group_num highest_symmetry_group = grp if all(g is None for g in grps): raise ValueError("No symmetry groups found!") # One measure of best group is the highest symmetry group highest_symmetry_group_prec = precs[::-1][grps[::-1].index( highest_symmetry_group)] # An alternative measure is the most commonly occurring group counts = Counter(grps) if None in counts: del counts[None] most_common_group = counts.most_common(1)[0][0] most_common_group_prec = precs[::-1][grps[::-1].index(most_common_group)] return { 'common': (most_common_group, most_common_group_prec), 'highest': (highest_symmetry_group, highest_symmetry_group_prec), 'histogram': counts }
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()
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 ("# Symmetrized structure with precision = %g\n" % prec) f.write (("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()
def get_spacegroup(self, tilde_obj): try: symmetry = spg.get_spacegroup(tilde_obj['structures'][-1], symprec=self.accuracy, angle_tolerance=self.angle_tolerance) except Exception as ex: self.error = 'Symmetry finder error: %s' % ex else: symmetry = symmetry.split() self.i = symmetry[0] try: self.n = int(symmetry[1].replace("(", "").replace(")", "")) except (ValueError, IndexError): self.n = 0 if self.n == 0: self.error = 'Symmetry finder error (probably, coinciding atoms)'
def _findsym(self,inPOSCAR,cell): if cell is None: cell=self.__cell_vasp(inPOSCAR=inPOSCAR) # cell1=tuple( [cell.lattice,cell.positions,cell.numbers] ) # print (cell) print('') print('\n ----------INFORMATION ABOUT THE UNIT CELL----------- \n') print('') print ('Primitive vectors : \n',cell[0],'\n Atomic positions: \n',cell[1],'\n Atom type indices: \n',cell[2]) symmetries = spglib.get_symmetry( cell ) # print ("symmetriesreturned by spglib : ",symmetries) symmetries = [ SymmetryOperation(rot,symmetries['translations'][i],cell[0],ind=i+1,spinor=self.spinor) for i,rot in enumerate(symmetries['rotations']) ] nsym=len(symmetries) s=spglib.get_spacegroup(cell).split(" ") return symmetries,s[0],int(s[1].strip("()")) ,cell[0]
def get_lattice_type(cryst): '''Find the symmetry of the crystal using spglib symmetry finder. Derive name of the space group and its number extracted from the result. Based on the group number identify also the lattice type and the Bravais lattice of the crystal. The lattice type numbers are (the numbering starts from 1): Triclinic (1), Monoclinic (2), Orthorombic (3), Tetragonal (4), Trigonal (5), Hexagonal (6), Cubic (7) :param cryst: ASE Atoms object :returns: tuple (lattice type number (1-7), lattice name, space group name, space group number) ''' # Table of lattice types and correcponding group numbers dividing # the ranges. See get_lattice_type method for precise definition. lattice_types = [ [3, "Triclinic"], [16, "Monoclinic"], [75, "Orthorombic"], [143, "Tetragonal"], [168, "Trigonal"], [195, "Hexagonal"], [231, "Cubic"] ] sg = spg.get_spacegroup(cryst) m = re.match(r'([A-Z].*\b)\s*\(([0-9]*)\)', sg) sg_name = m.group(1) sg_nr = int(m.group(2)) for n, l in enumerate(lattice_types): if sg_nr < l[0]: bravais = l[1] lattype = n+1 break return lattype, bravais, sg_name, sg_nr
def get_lattice_type(self): ''' Find the symmetry of the crystal using spglib symmetry finder. Assign to sg_name i sg_nr members name of the space group and its number extracted from the result. Based on the group number identify also the lattice type (assigned to sg_type member) and the Bravais lattice of the crystal (assigned to bravais member). The returned value is the lattice type number. The lattice type numbers are (see also Crystal.ls, the numbering starts from 1): Triclinic (1), Monoclinic (2), Orthorombic (3), Tetragonal (4) Trigonal (5), Hexagonal (6), Cubic (7) ''' # Table of lattice types and correcponding group numbers dividing # the ranges. See get_lattice_type method for precise definition. lattice_types=[ [3, "Triclinic"], [16, "Monoclinic"], [75, "Orthorombic"], [143, "Tetragonal"], [168, "Trigonal"], [195, "Hexagonal"], [231, "Cubic"] ] sg=spg.get_spacegroup(self) m=re.match('([A-Z].*\\b)\s*\(([0-9]*)\)',sg) self.sg_name=m.group(1) self.sg_nr=int(m.group(2)) for n,l in enumerate(lattice_types) : if self.sg_nr < l[0] : lattice=l[1] lattype=n+1 break self.sg_type=lattype self.bravais=lattice return lattype
c = 3.52 MgB2 = Atoms( symbols=['Mg']+['B']*2, cell=[ ( a, 0, 0 ), ( -a/2, a/2*np.sqrt(3), 0 ), ( 0, 0, c ) ], scaled_positions=[ ( 0, 0, 0 ), ( 1.0/3, 2.0/3, 0.5 ), ( 2.0/3, 1.0/3, 0.5 ) ], pbc=True ) # For VASP case # import vasp # bulk = vasp.read_vasp(sys.argv[1]) print "[get_spacegroup]" print " Spacegroup of Silicon is ", spglib.get_spacegroup(silicon) print print "[get_spacegroup]" print " Spacegroup of Rutile is ", spglib.get_spacegroup(rutile) print print "[get_spacegroup]" print " Spacegroup of MgB2 is ", 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_pointgroup]"
def write_cell_params(fh, a, p): ''' Write the specification of the cell using a traditional A,B,C, alpha, beta, gamma scheme. The symmetry and parameters are determined from the atoms (a) object. The atoms object is translated into a primitive unit cell but *not* converted. This is just an internal procedure. If you wish to work with primitive unit cells in ASE, you need to make a conversion yourself. The cell params are in angstrom. Input ----- fh file handle of the opened pw.in file a atoms object p parameters dictionary Output ------ Primitive cell tuple of arrays: (lattice, atoms, atomic numbers) ''' assert(p['use_symmetry']) # Get a spacegroup name and number for the a sg,sgn=spglib.get_spacegroup(a).split() # Extract the number sgn=int(sgn[1:-1]) # Extract the lattice type ltyp=sg[0] # Find a primitive unit cell for the system # puc is a tuple of (lattice, atoms, atomic numbers) puc=spglib.find_primitive(a) cell=puc[0] apos=puc[1] anum=puc[2] icell=a.get_cell() A=norm(icell[0]) B=norm(icell[1]) C=norm(icell[2]) # Select appropriate ibrav if sgn >= 195 : # Cubic lattice if ltyp=='P': p['ibrav']=1 # Primitive qepc=array([[1,0,0],[0,1,0],[0,0,1]]) elif ltyp=='F': p['ibrav']=2 # FCC qepc=array([[-1,0,1],[0,1,1],[-1,1,0]])/2.0 elif ltyp=='I': p['ibrav']=3 # BCC qepc=array([[1,1,1],[-1,1,1],[-1,-1,1]])/2.0 else : print 'Impossible lattice symmetry! Contact the author!' raise NotImplementedError #a=sqrt(2)*norm(cell[0]) qepc=A*qepc fh.write(' A = %f,\n' % (A,)) elif sgn >= 143 : # Hexagonal and trigonal if ltyp=='P' : p['ibrav']=4 # Primitive qepc=array([[1,0,0],[-1/2,sqrt(3)/2,0],[0,0,C/A]]) elif ltyp=='R' : p['ibrav']=5 # Trigonal rhombohedral raise NotImplementedError else : print 'Impossible lattice symmetry! Contact the author!' raise NotImplementedError qepc=A*qepc fh.write(' A = %f,\n' % (A,)) fh.write(' C = %f,\n' % (C,)) elif sgn >= 75 : raise NotImplementedError elif sgn ==1 : # P1 symmetry - no special primitive cell signal to the caller p['ibrav']=0 return None else : raise NotImplementedError cp=Atoms(cell=puc[0], scaled_positions=puc[1], numbers=puc[2], pbc=True) qepc=Atoms(cell=qepc, positions=cp.get_positions(), numbers=cp.get_atomic_numbers(), pbc=True) return qepc.get_cell(), qepc.get_scaled_positions(), qepc.get_atomic_numbers()
def get_spacegroup(self, symprec=1e-5): return spg.get_spacegroup(cell=self.spglib_cell, symprec=symprec)
spec.append(a[0]) print("Input data:") print("Cell:") i=0 for v in b: print("a%d= % 9.7f % 9.7f % 9.7f" % (i,v[0],v[1],v[2])) i+=1 print(spec) print('Atomic positions:') print(dp) structure=[b,dp,spec] res=seekpath.getpaths.get_path(structure, with_time_reversal=True, recipe='hpkot', threshold=1e-07, symprec=1e-05, angle_tolerance=-1.0) print("Output data:") print("Space group: %s" %spl.get_spacegroup(cell=(b,dp,spec), symprec=1e-5)) print('Primitive lattice:') for v in res['primitive_lattice']: print("a1= % 9.7f % 9.7f % 9.7f" % (v[0],v[1],v[2])) print('Atomic positions:') for i in range(len(res['primitive_positions'])): print("%2d %s" % (res['primitive_types'][i], "".join(" % 12.9f" % val for val in res['primitive_positions'][i]))) print('Crystallographic lattice:') for v in res['conv_lattice']: print("a1= % 9.7f % 9.7f % 9.7f" % (v[0],v[1],v[2])) print('Points:') for pt in res['point_coords'].items(): print(pt) print('PATH:') print (res['path'])
[(0, 0, 0), (1.0/3, 2.0/3, 0.5), (2.0/3, 1.0/3, 0.5)], [12, 5, 5]) a = [3., 0., 0.] b = [-3.66666667, 3.68178701, 0.] c = [-0.66666667, -1.3429469, 1.32364995] niggli_lattice = np.array([a, b, c]) # For VASP case # import vasp # bulk = vasp.read_vasp(sys.argv[1]) print("[get_spacegroup]") 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)
print(f'Usage: {prog} file.cif') sys.exit(1) try: cell = ase.io.read(sys.argv[1]) except Exception as e: print('Could not read CIF structure from file: ' + sys.argv[1]) print('Error message is: ' + str(e)) sys.exit(1) if sys.argv[1][-4:] == '.cif': basename = sys.argv[1][:-4] else: basename = sys.argv[1] t = [1, 2, 3, 5, 7] precs = [1e-10, 1e-9, 1e-8, 1e-7, 1e-6] + [i * j for i in [1e-5, 1e-4, 1e-3, 1e-2, 1e-1] for j in t] old = '' print('# Tolerance\tSpace group') for prec in precs: s = spglib.get_spacegroup(cell, symprec=prec) if s != old: print(f'{prec}\t\t{s}') writeCIF(cell, prec, basename) old = s sys.exit(0)