def test_get_hall_number_from_symmetry(self): for fname in self._filenames: cell = read_vasp(fname) if 'distorted' in fname: dataset = get_symmetry_dataset(cell, symprec=1e-1) hall_number = get_hall_number_from_symmetry( dataset['rotations'], dataset['translations'], symprec=1e-1) if hall_number != dataset['hall_number']: print("%d != %d in %s" % (hall_number, dataset['hall_number'], fname)) ref_cell = (dataset['std_lattice'], dataset['std_positions'], dataset['std_types']) dataset = get_symmetry_dataset(ref_cell, symprec=1e-5) hall_number = get_hall_number_from_symmetry( dataset['rotations'], dataset['translations'], symprec=1e-5) print("Using refinced cell: %d, %d in %s" % (hall_number, dataset['hall_number'], fname)) else: dataset = get_symmetry_dataset(cell, symprec=1e-5) hall_number = get_hall_number_from_symmetry( dataset['rotations'], dataset['translations'], symprec=1e-5) self.assertEqual( hall_number, dataset['hall_number'], msg=("%d != %d in %s" % (hall_number, dataset['hall_number'], 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 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 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_standardize_cell_from_primitive(self): for fname, spgnum in zip(self._filenames, self._spgnum_ref): cell = read_vasp(fname) if 'distorted' in fname: prim_cell = standardize_cell(cell, to_primitive=True, no_idealize=True, symprec=1e-1) std_cell = standardize_cell(prim_cell, to_primitive=False, no_idealize=True, symprec=1e-1) dataset = get_symmetry_dataset(std_cell, symprec=1e-1) else: prim_cell = standardize_cell(cell, to_primitive=True, no_idealize=True, symprec=1e-5) std_cell = standardize_cell(prim_cell, to_primitive=False, no_idealize=True, symprec=1e-5) dataset = get_symmetry_dataset(std_cell, symprec=1e-5) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname))
def test_find_primitive(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) primitive = find_primitive(cell, symprec=1e-1) else: dataset = get_symmetry_dataset(cell, symprec=1e-5) primitive = find_primitive(cell, symprec=1e-5) 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 symmetrize(pmg, tol=1e-3, a_tol=5.0): """ symmetrize the structure from spglib Args: pmg: pymatgen structure tol: tolerance Returns: pymatgen structure with symmetrized lattice """ atoms = (pmg.lattice.matrix, pmg.frac_coords, pmg.atomic_numbers) dataset = get_symmetry_dataset(atoms, tol, angle_tolerance=a_tol) hn = Group(dataset['number'], 3).hall_number if hn != dataset['hall_number']: dataset = get_symmetry_dataset(atoms, tol, angle_tolerance=a_tol, hall_number=hn) cell = dataset['std_lattice'] pos = dataset['std_positions'] numbers = dataset['std_types'] return Structure(cell, numbers, pos)
def test_standardize_cell_from_primitive(self): for fname in self._filenames: spgnum = int(fname.split('-')[1]) cell = read_vasp("./data/%s" % fname) if 'distorted' in fname: prim_cell = standardize_cell(cell, to_primitive=True, no_idealize=True, symprec=1e-1) std_cell = standardize_cell(prim_cell, to_primitive=False, no_idealize=True, symprec=1e-1) dataset = get_symmetry_dataset(std_cell, symprec=1e-1) else: prim_cell = standardize_cell(cell, to_primitive=True, no_idealize=True, symprec=1e-5) std_cell = standardize_cell(prim_cell, to_primitive=False, no_idealize=True, symprec=1e-5) dataset = get_symmetry_dataset(std_cell, symprec=1e-5) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname))
def calc_check(cell, spgnum, tol=1.0e-5): print('\n[primitive cell (calc)]') print_cell(cell) dataset = spglib.get_symmetry_dataset(cell, tol) spgnum_pcell = dataset['number'] hallnum_pcell = dataset['hall_number'] print_dataset(dataset) print('\n[conventional cell (calc pcell+standardize)]') scell = spglib.standardize_cell(cell) print_cell(scell) dataset = spglib.get_symmetry_dataset(scell, tol) spgnum_ccell = dataset['number'] hallnum_ccell = dataset['hall_number'] print_dataset(dataset) print('\n# check crystal structure...') print('%-25s %10s %10s' % ('', 'spg num', 'hall num')) print('%-25s %10d %10s' % ('cell orginal cif', spgnum, '-')) print('%-25s %10d %10d' % ('pcell calc', spgnum_pcell, hallnum_pcell)) print('%-25s %10d %10d' % ('ccell calc pcell+std', spgnum_ccell, hallnum_ccell)) b = True if (spgnum != spgnum_pcell): b = False print('warning: primitive cell... NG') if (spgnum != spgnum_ccell): b = False print('warning: conventional cell... NG') if (b == True): print('calc... OK') return b, spgnum_pcell
def test_find_primitive(self): for fname in self._filenames: cell = read_vasp(fname) if 'distorted' in fname: dataset = get_symmetry_dataset(cell, symprec=1e-1) primitive = find_primitive(cell, symprec=1e-1) else: dataset = get_symmetry_dataset(cell, symprec=1e-5) primitive = find_primitive(cell, symprec=1e-5) 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 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)
def test_refine_cell(self): for fname, spgnum in zip(self._filenames, self._spgnum_ref): cell = read_vasp(fname) if 'distorted' in fname: dataset_orig = get_symmetry_dataset(cell, symprec=1e-1) else: dataset_orig = get_symmetry_dataset(cell, symprec=1e-5) ref_cell = (dataset_orig['std_lattice'], dataset_orig['std_positions'], dataset_orig['std_types']) dataset = get_symmetry_dataset(ref_cell, symprec=1e-5) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname))
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_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 test_refine_cell(self): for fname in self._filenames: spgnum = int(fname.split('-')[1]) cell = read_vasp("./data/%s" % fname) if 'distorted' in fname: dataset_orig = get_symmetry_dataset(cell, symprec=1e-1) else: dataset_orig = get_symmetry_dataset(cell, symprec=1e-5) ref_cell = (dataset_orig['std_lattice'], dataset_orig['std_positions'], dataset_orig['std_types']) dataset = get_symmetry_dataset(ref_cell, symprec=1e-5) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname))
def compute_radius(atoms, nkpt, symprec=1e-4): """Estimate the right radius to be passed to Equivalence_builder to obtain the desired number of points. """ lattvec = atoms.get_cell().T vol = abs(np.linalg.det(lattvec)) spg = spglib.get_symmetry_dataset(atoms, symprec) rotations = spg["rotations"].astype(int) nrot = len(rotations) info("{} rotations".format(nrot)) newrotations = set() # Include time-reversal symmetry in the estimate if total inversion of # the axes is not among the symmetries inv = 2 for i in range(nrot): tmp = tuple(tuple(j) for j in rotations[i].tolist()) newrotations.add(tmp) if tmp == ((-1, 0, 0), (0, -1, 0), (0, 0, -1)): inv = 1 nrot = len(newrotations) info(nrot, "unique rotations", "including the inversion" if inv == 1 else "") npoints = nkpt * nrot * inv info(npoints, "total k points in the sphere") radius = (3. / (4. * np.pi) * npoints * vol)**(1. / 3.) return radius
def symsearch(sample, precision=1e-4): """ Identifies symmetry operations of the unit cell using spglib and update the sample definition. :param sample: A sample object. :param float precision: atoms are assumed equivalent if distances are smaller than precision. In Angstrom. :returns: True if successful, False otherwise. :rtype: bool """ if sample._check_lattice() and have_spg: # This may not identify rotation and translations correctly #sample.sym = spg.get_spacegroup(sample.cell, symprec=precision) dataset = spg.get_symmetry_dataset(sample.cell, symprec=precision) # spglib 1.9.9 returns a long int in python2, this causes problems # for spg.py, simple workaround is to convert it even if not necessary sample.sym = spacegroup_from_data(no=int(dataset['number']), rotations=dataset['rotations'], translations=dataset['translations'], subtrans=dataset['origin_shift']) warnings.warn( "Warning, information regarding spacegroup setting might be wrong!", RuntimeWarning, stacklevel=0) if sample.sym: return True else: return False else: return False
def prep_symmetry(atoms, symprec=1.0e-6, verbose=False): """ Prepare `at` for symmetry-preserving minimisation at precision `symprec` Returns a tuple `(rotations, translations, symm_map)` """ # check if we have access to get_spacegroup from spglib # https://atztogo.github.io/spglib/ try: import spglib # For version 1.9 or later except ImportError: from pyspglib import spglib # For versions 1.8.x or before dataset = spglib.get_symmetry_dataset(atoms, symprec=symprec) if verbose: print_symmetry(symprec, dataset) rotations = dataset['rotations'].copy() translations = dataset['translations'].copy() symm_map = [] scaled_pos = atoms.get_scaled_positions() for (rot, trans) in zip(rotations, translations): this_op_map = [-1] * len(atoms) for i_at in range(len(atoms)): new_p = rot @ scaled_pos[i_at, :] + trans dp = scaled_pos - new_p dp -= np.round(dp) i_at_map = np.argmin(np.linalg.norm(dp, axis=1)) this_op_map[i_at] = i_at_map symm_map.append(this_op_map) return (rotations, translations, symm_map)
def symsearch(sample, precision=1e-4): """ Identifies symmetry operations of the unit cell using spglib and update the sample definition. :param sample: A sample object. :param float precision: atoms are assumed equivalent if distances are smaller than precision. In Angstrom. :returns: True if successful, False otherwise. :rtype: bool """ if sample._check_lattice() and have_spg: # This may not identify rotation and translations correctly #sample.sym = spg.get_spacegroup(sample.cell, symprec=precision) dataset = spg.get_symmetry_dataset(sample.cell, symprec=precision) # spglib 1.9.9 returns a long int in python2, this causes problems # for spg.py, simple workaround is to convert it even if not necessary sample.sym = spacegroup_from_data(no=int(dataset['number']), rotations=dataset['rotations'], translations=dataset['translations'], subtrans=dataset['origin_shift']) warnings.warn("Warning, information regarding spacegroup setting might be wrong!",RuntimeWarning, stacklevel=0) if sample.sym: return True else: return False else: return False
def find_point_group(lattice, print_out=False): cell = sglib_data_types(lattice) dataset = spglib.get_symmetry_dataset(cell, symprec=1e-5, angle_tolerance=-1.0) if print_out: spglib_io.show_spg_symmetry_info(dataset) return dataset['pointgroup']
def _test_get_symmetry(self): """ *************************************************************** This test must be executed with spglib compiled with -DSPGTEST. *************************************************************** """ for fname in self._filenames: cell = read_vasp(fname) cell_spin = cell + ([ 1, ] * len(cell[2]), ) if 'distorted' in fname: symprec = 1e-1 else: symprec = 1e-5 dataset = get_symmetry_dataset(cell, symprec=symprec) 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 prep_symmetry(atoms, symprec=1.0e-6, verbose=False): """ Prepare `at` for symmetry-preserving minimisation at precision `symprec` Returns a tuple `(rotations, translations, symm_map)` """ import spglib dataset = spglib.get_symmetry_dataset(atoms_to_spglib_cell(atoms), symprec=symprec) if verbose: print_symmetry(symprec, dataset) rotations = dataset['rotations'].copy() translations = dataset['translations'].copy() symm_map = [] scaled_pos = atoms.get_scaled_positions() for (rot, trans) in zip(rotations, translations): this_op_map = [-1] * len(atoms) for i_at in range(len(atoms)): new_p = rot @ scaled_pos[i_at, :] + trans dp = scaled_pos - new_p dp -= np.round(dp) i_at_map = np.argmin(np.linalg.norm(dp, axis=1)) this_op_map[i_at] = i_at_map symm_map.append(this_op_map) return (rotations, translations, symm_map)
def from_file(cls, fname): """ log.txt の情報を読んで object を生成 log.txt と spg との整合性を check """ with open(fname, 'r') as rfile: lines = rfile.readlines() # meta_cmat = re.compile(r"\*CMAT\*.*") # i = 0 # while not meta_cmat.match(lines[i]): # i += 1 # type_trans = lines[i+3].split()[2][-2] # if type_trans not in ['P']: # print("Warning: the type_trans is not suported !!") meta_cmat = re.compile(r"translations used:.*") i = 0 while not meta_cmat.match(lines[i]): i += 1 i -= 3 cell = np.array( [[float(x) for x in y.split()] for y in lines[i+4: i+7]]) sites = [] i += 8 while lines[i].split()[0] == "atom:": sites.append([float(x) for x in lines[i].split()[5:]]) i += 1 sites = np.array(sites) atoms = Atoms(cell=cell, scaled_positions=sites, pbc=True) symm = spglib.get_symmetry_dataset(atoms) return cls(atoms, symm)
def standardize_crystal(crystal, method="spglib", **kwargs): if method != "spglib": raise NotImplementedError("Only spglib is currently supported") lattice = crystal.unit_cell.direct uc_dict = crystal.unit_cell_atoms() positions = uc_dict["frac_pos"] elements = uc_dict["element"] asym_atoms = uc_dict["asym_atom"] asym_labels = uc_dict["label"] cell = lattice, positions, elements reduced_cell = standardize_cell(cell, **kwargs) if reduced_cell is None: LOG.warn("Could not find reduced cell for crystal %s", crystal) return None dataset = get_symmetry_dataset(reduced_cell) asym_idx = np.unique(dataset["equivalent_atoms"]) asym_idx = asym_idx[np.argsort(asym_atoms[asym_idx])] sg = SpaceGroup(dataset["number"], choice=dataset["choice"]) reduced_lattice, positions, elements = reduced_cell unit_cell = UnitCell(reduced_lattice) asym = AsymmetricUnit( [Element[x] for x in elements[asym_idx]], positions[asym_idx], labels=asym_labels[asym_idx], ) return Crystal(unit_cell, sg, asym)
def _except_main(types, coords, symprec): types = np.array(types, dtype=int) fracs = np.array(coords.pop('fracs')) lattice = np.array(coords.pop('lattice')) cell = (lattice, fracs, types) # check primitiveness # alas, SPGLIB's symmetry dataset does not give any reliable way to # check this. # # FIXME this should be checked sooner in RSP2, not after expensive relaxation prim = spglib.find_primitive(cell, symprec=symprec) if not prim: SpgError.throw() prim_lattice = prim[0] vol_ratio = abs(np.linalg.det(lattice) / np.linalg.det(prim_lattice)) if abs(abs(vol_ratio) - 1) > 1e-4: return {"Err": "rsp2 requires the input to be a primitive cell"} ds = spglib.get_symmetry_dataset(cell, symprec=symprec) if not ds: SpgError.throw() # you can't JSON-serialize numpy types def un_numpy_ify(d): if isinstance(d, dict): return {k: un_numpy_ify(v) for (k, v) in d.items()} if isinstance(d, list): return [un_numpy_ify(x) for x in d] if hasattr(d, 'tolist'): return d.tolist() if isinstance(d, (float, int, str)): return d raise TypeError return {"Ok": un_numpy_ify(ds)}
def from_logtxt(cls, fname, brav='P'): """ log.txt の情報を読んで UnitCell object を生成 """ with open(fname, 'r') as rfile: lines = rfile.readlines() meta_trans = re.compile(r"translations used:") i = 0 while not meta_trans.match(lines[i]): i += 1 type_trans = lines[i].split()[2][-2] if type_trans not in ['P']: print("Warning: the type_trans is not suported !!") cell = np.array( [[float(x) for x in y.split()] for y in lines[i+1: i+4]]) sites, elems = [], [] i += 5 while lines[i].split()[0] == "atom:": sites.append([float(x) for x in lines[i].split()[5:]]) elems.append( 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.index(lines[i].split()[3][0])) i += 1 sites = np.array(sites) trans = SymmetryOperator.trans(brav) inv_trans = np.linalg.inv(trans) norm_sites = np.dot(sites, inv_trans) # print(norm_sites) atoms = Atoms( symbols=elems, cell=cell, scaled_positions=norm_sites, pbc=True) symm = spglib.get_symmetry_dataset(atoms) return cls(atoms, symm, brav)
def optimize(struc, dir1): os.mkdir(dir1) os.chdir(dir1) time0 = 0 # Step1: ISIF = 2 struc.set_calculator(set_vasp(level=0, pstress=pstress)) # , setup=setup)) print(struc.get_potential_energy()) time, ncore = read_OUTCAR() time0 += time print("time for vasp calcs0 (seconds): ", time) # Step2: ISIF = 3 struc = read("CONTCAR", format="vasp") struc.set_calculator(set_vasp(level=1, pstress=pstress)) # , setup=setup)) print(struc.get_potential_energy()) time, ncore = read_OUTCAR() time0 += time print("time for vasp calcs1 (seconds): ", time) # Step3: ISIF = 3 with high precision struc = read("CONTCAR", format="vasp") if good_lattice(struc): struc = symmetrize_cell(struc, mode="C") struc.set_calculator(set_vasp(level=2, pstress=pstress)) # , setup=setup)) print(struc.get_potential_energy()) time, ncore = read_OUTCAR() time0 += time print("time for vasp calcs2 (seconds): ", time) struc = read("CONTCAR", format="vasp") if good_lattice(struc): struc = symmetrize_cell(struc, mode="P") struc.set_calculator(set_vasp(level=3, pstress=pstress, setup=setup)) print(struc.get_potential_energy()) time, ncore = read_OUTCAR() time0 += time print("time for vasp calcs3 (seconds): ", time) struc = read("CONTCAR", format="vasp") if good_lattice(struc): struc = symmetrize_cell(struc, mode="P") struc.set_calculator(set_vasp(level=4, pstress=pstress, setup=setup)) struc.get_potential_energy() time, ncore = read_OUTCAR() print("time for vasp calcs4 (seconds): ", time) time0 += time result = vasprun().values spg = get_symmetry_dataset(struc, symprec=5e-2)["international"] print( "#####%-10s %-10s %12.6f %6.2f %8.2f %4d %12s" % ( dir1, struc.get_chemical_formula(), result["calculation"]["energy_per_atom"], result["gap"], time0, ncore, spg, ) )
def get_symmetry_spglib(filename, symprec=0.00001): with zopen(filename, "rt") as f: contents = f.read() poscar = Poscar_new.from_string(contents, False, read_velocities=False) positions = poscar.coords lattice = poscar.lattice atomic_symbols = poscar.atomic_symbols numbers = [] a = "" j = 0 for i in atomic_symbols: if i != a: a = i j = j + 1 numbers.append(j) cell = (lattice, positions, numbers) dataset = spglib.get_symmetry_dataset(cell, symprec) print("space group: ", dataset['international'], dataset['number']) print("rotations: ", dataset['rotations']) print("translations: ", dataset['translations']) print("equivalent atoms: ", dataset['equivalent_atoms']) print("sites wyckoffs: ", dataset['wyckoffs']) sym_independ = np.unique(dataset['equivalent_atoms']) print("independent atoms: ", sym_independ) for i in sym_independ: print("coordinates of independent atoms") print(positions[i])
def __init__(self, structure, symprec=1e-3, angle_tolerance=5): self._symprec = symprec self._angle_tol = angle_tolerance self._structure = structure latt = structure.lattice.matrix positions = structure.frac_coords unique_species = [] zs = [] magmoms = [] for species, g in itertools.groupby(structure, key=lambda s: s.species_and_occu): if species in unique_species: ind = unique_species.index(species) zs.extend([ind + 1] * len(tuple(g))) else: unique_species.append(species) zs.extend([len(unique_species)] * len(tuple(g))) for site in structure: if hasattr(site, 'magmom'): magmoms.append(site.magmom) elif site.is_ordered and hasattr(site.specie, 'spin'): magmoms.append(site.specie.spin) else: magmoms.append(0) self._unique_species = unique_species self._numbers = zs # For now, we are setting magmom to zero. self._cell = latt, positions, zs, magmoms self._spacegroup_data = spglib.get_symmetry_dataset( self._cell, symprec=self._symprec, angle_tolerance=angle_tolerance)
def obtain_tmat(DG, images, iv): # -- Generate lattice with DG in input basis cp_pos = images[0].get_scaled_positions() cp_lattice = images[int(iv.numIm / 2)].get_cell() cp_labels = images[0].get_atomic_numbers() for i in [int(iv.numIm / 2), iv.numIm - 1]: cp_pos = np.append(cp_pos, images[i].get_scaled_positions(), axis=0) cp_labels = np.append(cp_labels, images[i].get_atomic_numbers()) new_pos = [cp_pos[0]] new_labels = [cp_labels[0]] for j in range(0, len(cp_pos[:, 0])): atom = cp_pos[j] for i in range(0, len(DG[0])): t_coord = np.dot(atom, np.transpose(DG[0][i])) t_coord = (t_coord + DG[1][i]) % 1.0 if not any([closewrapped(t_coord, m, iv.vectol) for m in new_pos]): new_pos = np.append(new_pos, [t_coord], axis=0) new_labels = np.append(new_labels, cp_labels[j]) dataset2 = spglib.get_symmetry_dataset((cp_lattice, new_pos, new_labels), symprec=iv.symprec) return (dataset2['transformation_matrix'], dataset2['origin_shift'])
def __init__( self, struct=None, pos_name=None, lattice_index=None, lat=None, lat_recell=None, atomname=None, atomnum=None, postype=None, pos=None, spg_number=None, ): self.struct = linecache.getlines("POSCAR") # read POSCAR to get some paramatrics: sys_name; lattice; atom_name; atom_number; atom_position # and get spacegroup_number poscar = [line.strip() for line in self.struct] num = len(poscar) self.pos_name = poscar[0].split() self.lat_index = poscar[1].split() self.lattice_index = float(self.lat_index[0]) # matrics of lattice vector lat_vector = np.zeros((3, 3)) index = 0 for latt in poscar[2:5]: latt = latt.split() lat_vector[index, :] = latt[0:3] index += 1 self.lattice = lat_vector self.atomname = poscar[5].split() self.atomnum = poscar[6].split() self.postype = poscar[7].split() atom_len=len(self.atomname) # matrics of atom position i = num - 8 position_vector = np.zeros((i, 3)) index = 0 for poss in poscar[8:num]: poss = poss.split() #position_vector[index, 0:3] = poss[0:3] position_vector[index,0] = poss[0] position_vector[index,1] = poss[1] position_vector[index,2] = poss[2] index += 1 self.lat = lat_vector * self.lattice_index self.pos = position_vector atom_numbers = [1,] * (int(self.atomnum[0]))#+int(self.atomnum[1])) cell = (self.lat, self.pos, atom_numbers) database = spglib.get_symmetry_dataset( cell, symprec=1e-3 ) self.spg_number = database["number"]
def standardize_cell(spg_cell, best_prec): """Convert cell into its standard crystallographic representation""" dataset = spglib.get_symmetry_dataset(spg_cell, best_prec) box = matrix_to_box(dataset['std_lattice'].T) positions = dataset['std_positions'] return (box, positions, dataset['std_types'])
def get_equivalent_vornet(vornet, symprec=1e-5, angle_tolerance=5): positions = [] lattice = vornet.lattice for i in vornet.nodes: positions.append(i[2]) numbers = [ 1, ] * len(vornet.nodes) cell = (lattice, positions, numbers) dataset = spglib.get_symmetry_dataset(cell, symprec, angle_tolerance) print(dataset['number']) voids = [] if dataset: symm_label = dataset['equivalent_atoms'] vornet_uni_symm = vornet.parse_symmetry(symm_label) sym_independ = np.unique(dataset['equivalent_atoms']) print("symm_label", symm_label) print("sym_independ", sym_independ) print("The number of symmetry distinct voids: ", len(sym_independ)) for i in sym_independ: voids.append(positions[i]) return vornet_uni_symm, voids else: return vornet, voids
def impose_atom_type_index(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) equ_atoms = spglib.get_symmetry_dataset(Cell, symprec=2e-3)['equivalent_atoms'] new_type_dic = {} new_index = [1 for x in range(index)] new_atom_pos = [] for i in range(len(atom_pos)): if not str(atom_type[i]) + '_' + str( equ_atoms[i]) in new_type_dic.keys(): new_type_dic[str(atom_type[i]) + '_' + str(equ_atoms[i])] = [ atom_pos[i][3], atom_pos[i][3] + str(new_index[atom_type[i]]) ] new_index[atom_type[i]] = new_index[atom_type[i]] + 1 new_atom_pos.append(atom_pos[i][0:3] + new_type_dic[str(atom_type[i]) + '_' + str(equ_atoms[i])]) return new_atom_pos
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 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_space_group_number(self, structure_id): import numpy as np import spglib s0 = load_node(structure_id) slatt = s0.cell spos = np.squeeze(np.asarray(list(np.matrix(s0.cell).T.I * np.matrix(x.position).T for x in s0.sites))) snum = np.ones(len(s0.sites)) scell = (slatt, spos, snum) SGN = int(spglib.get_symmetry_dataset(scell)["number"]) return SGN
def get_symmetry_dataset(cell, tolerance=1e-5): lattice = cell.lattice.T positions = cell.get_points().T numbers = cell.numbers dataset = spglib.get_symmetry_dataset((lattice, positions, numbers), symprec=tolerance) if dataset is None: return None dataset['std_points'] = np.array(dataset['std_positions'].T, dtype='double', order='C') dataset['std_lattice'] = np.array(dataset['std_lattice'].T, dtype='double', order='C') return dataset
def test_standardize_cell_to_primitive(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 prim_cell = standardize_cell(cell, to_primitive=True, no_idealize=True, symprec=symprec) dataset = get_symmetry_dataset(prim_cell, symprec=symprec) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname))
def setUp(self): identity = np.eye(3, dtype='intc') file_and_mesh = ( [os.path.join(data_dir, "data", "cubic", "POSCAR-217"), [4, 4, 4]], [os.path.join(data_dir, "data", "hexagonal", "POSCAR-182"), [4, 4, 2]]) self.meshes = [] self.cells = [] self.rotations = [] self.grid_addresses = [] for i, (fname, mesh) in enumerate(file_and_mesh): self.meshes.append(mesh) self.cells.append(read_vasp(fname)) self.rotations.append( get_symmetry_dataset(self.cells[i])['rotations']) _, ga = get_stabilized_reciprocal_mesh(mesh, [identity, ]) self.grid_addresses.append(ga)
def setUp(self): self._filenames = [] self._datasets = [] self._cells = [] self._symprecs = [] for d in dirnames: dirname = os.path.join(data_dir, "data", d) filenames = os.listdir(dirname) self._filenames += [os.path.join(dirname, fname) for fname in filenames] for fname in self._filenames: cell = read_vasp(fname) if 'distorted' in fname: symprec = 1e-1 else: symprec = 1e-5 self._datasets.append( get_symmetry_dataset(cell, symprec=symprec)) self._cells.append(cell) self._symprecs.append(symprec)
def test_standardize_cell_and_pointgroup(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 std_cell = standardize_cell(cell, to_primitive=False, no_idealize=True, symprec=symprec) dataset = get_symmetry_dataset(std_cell, symprec=symprec) self.assertEqual(dataset['number'], spgnum, msg=("%s" % fname)) # The test for point group has to be done after standarization. ptg_symbol, _, _ = get_pointgroup(dataset['rotations']) self.assertEqual(dataset['pointgroup'], ptg_symbol, msg=("%s" % fname))
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 reduce_cij(atoms0,cij0,eps=1.e-4): """ Reduce number of independent Cij according to the crystal system of original cell. It is not Cij=Cji. """ cij = cij0 symdata = spglib.get_symmetry_dataset(atoms0) napsys = NAPSystem(ase_atoms=atoms0) sgnum = symdata['number'] print('Spacegroup number = ',sgnum,' ==> ',end='') a,b,c = napsys.get_lattice_lengths() alpha,beta,gamma = napsys.get_lattice_angles() aeqb = abs(a-b) < eps*min(a,b) beqc = abs(b-c) < eps*min(b,c) ceqa = abs(c-a) < eps*min(c,a) aleqpi2 = abs(alpha-np.pi/2) < eps*np.pi/2 bteqpi2 = abs(beta -np.pi/2) < eps*np.pi/2 gmeqpi2 = abs(gamma-np.pi/2) < eps*np.pi/2 if 0 < sgnum <= 2: # Triclinic print('Triclinic') pass elif sgnum <= 15: # Monoclinic print('Monoclinic') pass elif sgnum <= 74: # Orthorhombic print('Orthorhombic') pass elif sgnum <= 142: # Tetragonal print('Tetragonal') pass elif sgnum <= 194: # Hexagonal print('Hexagonal') print('Number of independent C_ij elements are reduced to 6.') print('C_66 should be 1/2(C_11-C_12) but this is not enforced now.') if not aleqpi2: c22 = (cij[1,1] +cij[2,2])/2 c13 = (cij[0,1] +cij[0,2])/2 c55 = (cij[4,4] +cij[5,5])/2 cij[1,1] = cij[2,2] = c22 cij[0,1] = cij[0,2] = c13 cij[4,4] = cij[5,5] = c55 elif not bteqpi2: c11 = (cij[0,0] +cij[2,2])/2 c12 = (cij[0,1] +cij[1,2])/2 c44 = (cij[3,3] +cij[5,5])/2 cij[0,0] = cij[2,2] = c11 cij[0,1] = cij[1,2] = c12 cij[3,3] = cij[5,5] = c44 elif not gmeqpi2: c11 = (cij[0,0] +cij[1,1])/2 c12 = (cij[0,2] +cij[1,2])/2 c44 = (cij[3,3] +cij[4,4])/2 cij[0,0] = cij[1,1] = c11 cij[0,2] = cij[1,2] = c12 cij[3,3] = cij[4,4] = c44 elif sgnum <= 230: # Cubic print('Cubic') print('Number of independent C_ij elements are reduced to 3.') c11 = (cij[0,0] +cij[1,1] +cij[2,2])/3 c12 = (cij[0,1] +cij[0,2] +cij[1,2])/3 c44 = (cij[3,3] +cij[4,4] +cij[5,5])/3 cij[0,0] = cij[1,1] = cij[2,2] = c11 cij[0,1] = cij[0,2] = cij[1,2] = c12 cij[3,3] = cij[4,4] = cij[5,5] = c44 else: raise ValueError('Invalid space group number, ',sgnum) # Just symmetrize Cij for i in range(6): for j in range(i,6): cij[j,i] = cij[i,j] return cij
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']") 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("[get_symmetry_dataset] ['wyckoffs']") alphabet = "abcdefghijklmnopqrstuvwxyz" print(" Wyckoff letters of Rutile are: ", dataset['wyckoffs']) print('')
def get_symmetry_dataset(self, symprec=1e-5): ret = spg.get_symmetry_dataset(cell=self.spglib_cell, symprec=symprec) if ret is None: raise ValueError(self.spglib_cell) return ret
def get_symmetry_dataset(self, symprec=1e-5): return spg.get_symmetry_dataset(cell=self.spglib_cell, symprec=symprec)