def add_snl(self, snl, force_new=False, snlgroup_guess=None): try: self.lock_db() snl_id = self._get_next_snl_id() spstruc = snl.structure.copy() spstruc.remove_oxidation_states() sf = SpacegroupAnalyzer(spstruc, SPACEGROUP_TOLERANCE, ANGLE_TOLERANCE) sf.get_spacegroup() sgnum = sf.get_spacegroup_number() if sf.get_spacegroup_number() \ else -1 sgsym = sf.get_spacegroup_symbol() if sf.get_spacegroup_symbol() \ else 'unknown' sghall = sf.get_hall() if sf.get_hall() else 'unknown' sgxtal = sf.get_crystal_system() if sf.get_crystal_system() \ else 'unknown' sglatt = sf.get_lattice_type() if sf.get_lattice_type() else 'unknown' sgpoint = sf.get_point_group() mpsnl = MPStructureNL.from_snl(snl, snl_id, sgnum, sgsym, sghall, sgxtal, sglatt, sgpoint) snlgroup, add_new, spec_group = self.add_mpsnl(mpsnl, force_new, snlgroup_guess) self.release_lock() return mpsnl, snlgroup.snlgroup_id, spec_group except: self.release_lock() traceback.print_exc() raise ValueError("Error while adding SNL!")
def add_snl(self, snl, force_new=False, snlgroup_guess=None): try: self.lock_db() snl_id = self._get_next_snl_id() spstruc = snl.structure.copy() spstruc.remove_oxidation_states() sf = SpacegroupAnalyzer(spstruc, SPACEGROUP_TOLERANCE) sf.get_spacegroup() sgnum = sf.get_spacegroup_number() if sf.get_spacegroup_number() \ else -1 sgsym = sf.get_spacegroup_symbol() if sf.get_spacegroup_symbol() \ else 'unknown' sghall = sf.get_hall() if sf.get_hall() else 'unknown' sgxtal = sf.get_crystal_system() if sf.get_crystal_system() \ else 'unknown' sglatt = sf.get_lattice_type() if sf.get_lattice_type( ) else 'unknown' sgpoint = sf.get_point_group() mpsnl = MPStructureNL.from_snl(snl, snl_id, sgnum, sgsym, sghall, sgxtal, sglatt, sgpoint) snlgroup, add_new, spec_group = self.add_mpsnl( mpsnl, force_new, snlgroup_guess) self.release_lock() return mpsnl, snlgroup.snlgroup_id, spec_group except: self.release_lock() traceback.print_exc() raise ValueError("Error while adding SNL!")
def test_tricky_structure(self): # for some reason this structure kills spglib1.9 # 1.7 can't find symmetry either, but at least doesn't kill python s = Structure.from_file(os.path.join(test_dir, 'POSCAR.tricky_symmetry')) sa = SpacegroupAnalyzer(s, 0.1) sa.get_spacegroup_symbol() sa.get_spacegroup_number() sa.get_point_group() sa.get_crystal_system() sa.get_hall()
def test_tricky_structure(self): # for some reason this structure kills spglib1.9 # 1.7 can't find symmetry either, but at least doesn't kill python s = Structure.from_file(os.path.join(test_dir, 'POSCAR.tricky_symmetry')) sa = SpacegroupAnalyzer(s, 0.1) sa.get_spacegroup_symbol() sa.get_spacegroup_number() sa.get_point_group() sa.get_crystal_system() sa.get_hall()
def test_magnetic(self): lfp = PymatgenTest.get_structure("LiFePO4") sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_spacegroup_symbol(), "Pnma") magmoms = [0] * len(lfp) magmoms[4] = 1 magmoms[5] = -1 magmoms[6] = 1 magmoms[7] = -1 lfp.add_site_property("magmom", magmoms) sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_spacegroup_symbol(), "Pnma")
def test_magnetic(self): lfp = PymatgenTest.get_structure("LiFePO4") sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_spacegroup_symbol(), "Pnma") magmoms = [0] * len(lfp) magmoms[4] = 1 magmoms[5] = -1 magmoms[6] = 1 magmoms[7] = -1 lfp.add_site_property("magmom", magmoms) sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_spacegroup_symbol(), "Pnma")
def unique_symmetry_operations_as_vectors_from_structure( structure, subset = None ): """ Uses pymatgen symmetry analysis to find the minimum complete set of symmetry operations for the space group of a structure. Args: structure (pymatgen Structure): structure to be analysed. subset (Optional [list]): list of atom indices to be used for generating the symmetry operations Returns: a list of lists, containing the symmetry operations as vector mappings. """ symmetry_analyzer = SpacegroupAnalyzer( structure ) print( "The spacegroup for structure is {}".format(symmetry_analyzer.get_spacegroup_symbol()) ) symmetry_operations = symmetry_analyzer.get_symmetry_operations() mappings = [] if subset: species_subset = [ spec for i,spec in enumerate(structure.species) if i in subset] frac_coords_subset = [ coord for i, coord in enumerate( structure.frac_coords ) if i in subset ] mapping_structure = Structure( structure.lattice, species_subset, frac_coords_subset ) else: mapping_structure = structure for symmop in symmetry_operations: new_structure = Structure( mapping_structure.lattice, mapping_structure.species, symmop.operate_multi( mapping_structure.frac_coords ) ) new_mapping = [ x+1 for x in list( coord_list_mapping_pbc( new_structure.frac_coords, mapping_structure.frac_coords ) ) ] if new_mapping not in mappings: mappings.append( new_mapping ) return mappings
def create_structure_db_info(structure, spacegroup=None): # Figure out the symmetry group if not spacegroup: spacegroup = SpacegroupAnalyzer(structure, normalised_symmetry_precision(structure), -1) d = dict() # Set the composition and formulas for the system comp = structure.composition el_amt = structure.composition.get_el_amt_dict() d.update({"unit_cell_formula": comp.to_dict, "reduced_cell_formula": comp.to_reduced_dict, "elements": list(el_amt.keys()), "nelements": len(el_amt), "pretty_formula": comp.reduced_formula, "anonymous_formula": comp.anonymized_formula, "nsites": comp.num_atoms, "chemsys": "-".join(sorted(el_amt.keys()))}) d["spacegroup"] = {"symbol": unicode(spacegroup.get_spacegroup_symbol(), errors="ignore"), "number": spacegroup.get_spacegroup_number(), "point_group": unicode(spacegroup.get_point_group(), errors="ignore"), "source": "spglib", "crystal_system": spacegroup.get_crystal_system(), "hall": spacegroup.get_hall()} return d
def complete_ordering(self, structure, num_remove_dict): self.logger.debug("Performing complete ordering...") all_structures = [] symprec = 0.2 s = SpacegroupAnalyzer(structure, symprec=symprec) self.logger.debug( "Symmetry of structure is determined to be {}.".format( s.get_spacegroup_symbol())) sg = s.get_spacegroup() tested_sites = [] starttime = time.time() self.logger.debug("Performing initial ewald sum...") ewaldsum = EwaldSummation(structure) self.logger.debug("Ewald sum took {} seconds.".format(time.time() - starttime)) starttime = time.time() allcombis = [] for ind, num in num_remove_dict.items(): allcombis.append(itertools.combinations(ind, num)) count = 0 for allindices in itertools.product(*allcombis): sites_to_remove = [] indices_list = [] for indices in allindices: sites_to_remove.extend([structure[i] for i in indices]) indices_list.extend(indices) s_new = Structure.from_sites(structure.sites) s_new.remove_sites(indices_list) energy = ewaldsum.compute_partial_energy(indices_list) already_tested = False for i, tsites in enumerate(tested_sites): tenergy = all_structures[i]["energy"] if abs((energy - tenergy) / len(s_new)) < 1e-5 and \ sg.are_symmetrically_equivalent(sites_to_remove, tsites, symm_prec=symprec): already_tested = True if not already_tested: tested_sites.append(sites_to_remove) all_structures.append({"structure": s_new, "energy": energy}) count += 1 if count % 10 == 0: timenow = time.time() self.logger.debug("{} structures, {:.2f} seconds.".format( count, timenow - starttime)) self.logger.debug("Average time per combi = {} seconds".format( (timenow - starttime) / count)) self.logger.debug( "{} symmetrically distinct structures found.".format( len(all_structures))) self.logger.debug( "Total symmetrically distinct structures found = {}".format( len(all_structures))) all_structures = sorted(all_structures, key=lambda s: s["energy"]) return all_structures
def print_spg(src="POSCAR"): srcpos = Poscar.from_file(src) finder = SpacegroupAnalyzer(srcpos.structure, symprec=5e-2, angle_tolerance=8) spg = finder.get_spacegroup_symbol() spg_num = finder.get_spacegroup_number() print(spg) print(spg_num)
def complete_ordering(self, structure, num_remove_dict): self.logger.debug("Performing complete ordering...") all_structures = [] symprec = 0.2 s = SpacegroupAnalyzer(structure, symprec=symprec) self.logger.debug("Symmetry of structure is determined to be {}." .format(s.get_spacegroup_symbol())) sg = s.get_spacegroup() tested_sites = [] starttime = time.time() self.logger.debug("Performing initial ewald sum...") ewaldsum = EwaldSummation(structure) self.logger.debug("Ewald sum took {} seconds." .format(time.time() - starttime)) starttime = time.time() allcombis = [] for ind, num in num_remove_dict.items(): allcombis.append(itertools.combinations(ind, num)) count = 0 for allindices in itertools.product(*allcombis): sites_to_remove = [] indices_list = [] for indices in allindices: sites_to_remove.extend([structure[i] for i in indices]) indices_list.extend(indices) s_new = structure.copy() s_new.remove_sites(indices_list) energy = ewaldsum.compute_partial_energy(indices_list) already_tested = False for i, tsites in enumerate(tested_sites): tenergy = all_structures[i]["energy"] if abs((energy - tenergy) / len(s_new)) < 1e-5 and \ sg.are_symmetrically_equivalent(sites_to_remove, tsites, symm_prec=symprec): already_tested = True if not already_tested: tested_sites.append(sites_to_remove) all_structures.append({"structure": s_new, "energy": energy}) count += 1 if count % 10 == 0: timenow = time.time() self.logger.debug("{} structures, {:.2f} seconds." .format(count, timenow - starttime)) self.logger.debug("Average time per combi = {} seconds" .format((timenow - starttime) / count)) self.logger.debug("{} symmetrically distinct structures found." .format(len(all_structures))) self.logger.debug("Total symmetrically distinct structures found = {}" .format(len(all_structures))) all_structures = sorted(all_structures, key=lambda s: s["energy"]) return all_structures
def print_spg(src='POSCAR'): """ space group を return """ srcpos = Poscar.from_file(src) finder = SpacegroupAnalyzer(srcpos.structure, symprec=5e-2, angle_tolerance=8) spg = finder.get_spacegroup_symbol() spg_num = finder.get_spacegroup_number() return spg, spg_num
def run_task(self, fw_spec): btrap_dir = os.path.join(os.getcwd(), "boltztrap") bta = BoltztrapAnalyzer.from_files(btrap_dir) d = bta.as_dict() d["boltztrap_dir"] = btrap_dir # trim the output for x in ['cond', 'seebeck', 'kappa', 'hall', 'mu_steps', 'mu_doping', 'carrier_conc']: del d[x] if not self.get("hall_doping"): del d["hall_doping"] # add the structure bandstructure_dir = os.getcwd() v, o = get_vasprun_outcar(bandstructure_dir, parse_eigen=False, parse_dos=False) structure = v.final_structure d["structure"] = structure.as_dict() d.update(get_meta_from_structure(structure)) d["bandstructure_dir"] = bandstructure_dir # add the spacegroup sg = SpacegroupAnalyzer(Structure.from_dict(d["structure"]), 0.1) d["spacegroup"] = {"symbol": sg.get_spacegroup_symbol(), "number": sg.get_spacegroup_number(), "point_group": sg.get_point_group(), "source": "spglib", "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall()} d["created_at"] = datetime.utcnow() db_file = env_chk(self.get('db_file'), fw_spec) if not db_file: with open(os.path.join(btrap_dir, "boltztrap.json"), "w") as f: f.write(json.dumps(d, default=DATETIME_HANDLER)) else: mmdb = MMDb.from_db_file(db_file, admin=True) # dos gets inserted into GridFS dos = json.dumps(d["dos"], cls=MontyEncoder) fsid, compression = mmdb.insert_gridfs( dos, collection="dos_boltztrap_fs", compress=True) d["dos_boltztrap_fs_id"] = fsid del d["dos"] mmdb.db.boltztrap.insert(d)
def _get_data_from_single_dirc(dirc, src_str="str_relax.out", src_ene='energy'): """ 指定したdircから構造とエネルギーを読み取る """ src = os.path.join(dirc, src_str) strout = StrOut.from_file(src) src = os.path.join(dirc, src_ene) with open(src, 'r') as rfile: lines = rfile.readlines() num_atoms = sum(strout.structure.composition. to_data_dict['unit_cell_composition'].values()) energy = float(lines[0]) / num_atoms analyzer = SpacegroupAnalyzer(strout.structure) #std_prim = analyzer.get_primitive_standard_structure() std_str = analyzer.get_conventional_standard_structure() analyzer = SpacegroupAnalyzer(std_str) wyckoffs = analyzer.get_symmetry_dataset()['wyckoffs'] formula = std_str.composition.to_data_dict['unit_cell_composition'] symbol_spg = analyzer.get_spacegroup_symbol() num_spg = analyzer.get_spacegroup_number() spg = [symbol_spg, num_spg] lattice = std_str.as_dict()['lattice'] equiv_sites = analyzer.get_symmetrized_structure().equivalent_sites equiv_indices = analyzer.get_symmetrized_structure().equivalent_indices # Wycoffs labelと組み合わせたsites_groupのlistを作る sites_and_wyckoffs = [] for eq_s, eq_i in zip(equiv_sites, equiv_indices): sites_and_wyckoffs.append({'wyckoffs': wyckoffs[eq_i[0]], 'site_grp': eq_s}) # check for i in range(len(eq_i)-1): if wyckoffs[eq_i[i]] != wyckoffs[eq_i[i+1]] or \ len(eq_s) != len(eq_i): print("wyckoffs label is wrong !!!!") print(wyckoffs) print(eq_i) print(len(eq_s)) print(dirc) exit() return {'formula': formula, 'lattice': lattice, 'spg': spg, 'sites_and_wyckoffs': sites_and_wyckoffs, 'energy': energy, 'str_id': os.path.basename(dirc)}
def _make_struc_file(self, file_name): sym = SpacegroupAnalyzer(self._bs._structure, symprec=0.01) with open(file_name, 'w') as f: f.write(self._bs._structure.composition.formula+" " + str(sym.get_spacegroup_symbol())+"\n") for i in range(3): line = '' for j in range(3): line += "%12.5f" % ( Length(self._bs._structure.lattice.matrix[i][j], "ang").to("bohr")) f.write(line+'\n') ops = sym.get_symmetry_dataset()['rotations'] f.write(str(len(ops))+"\n") for c in ops: f.write('\n'.join([' '.join([str(int(i)) for i in row]) for row in c])) f.write('\n')
def set_output_data(self, d_calc, d): """ set the 'output' key """ d["output"] = { "structure": d_calc["output"]["structure"], "density": d_calc.pop("density"), "energy": d_calc["output"]["energy"], "energy_per_atom": d_calc["output"]["energy_per_atom"]} d["output"].update(self.get_basic_processed_data(d)) sg = SpacegroupAnalyzer(Structure.from_dict(d_calc["output"]["structure"]), 0.1) if not sg.get_symmetry_dataset(): sg = SpacegroupAnalyzer(Structure.from_dict(d_calc["output"]["structure"]), 1e-3, 1) d["output"]["spacegroup"] = { "source": "spglib", "symbol": sg.get_spacegroup_symbol(), "number": sg.get_spacegroup_number(), "point_group": sg.get_point_group(), "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall()} if d["input"]["parameters"].get("LEPSILON"): for k in ['epsilon_static', 'epsilon_static_wolfe', 'epsilon_ionic']: d["output"][k] = d_calc["output"][k]
class SpacegroupAnalyzerTest(PymatgenTest): def setUp(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) self.structure = p.structure self.sg = SpacegroupAnalyzer(self.structure, 0.001) self.disordered_structure = self.get_structure('Li10GeP2S12') self.disordered_sg = SpacegroupAnalyzer(self.disordered_structure, 0.001) s = p.structure.copy() site = s[0] del s[0] s.append(site.species_and_occu, site.frac_coords) self.sg3 = SpacegroupAnalyzer(s, 0.001) graphite = self.get_structure('Graphite') graphite.add_site_property("magmom", [0.1] * len(graphite)) self.sg4 = SpacegroupAnalyzer(graphite, 0.001) def test_get_space_symbol(self): self.assertEqual(self.sg.get_spacegroup_symbol(), "Pnma") self.assertEqual(self.disordered_sg.get_spacegroup_symbol(), "P4_2/nmc") self.assertEqual(self.sg3.get_spacegroup_symbol(), "Pnma") self.assertEqual(self.sg4.get_spacegroup_symbol(), "R-3m") def test_get_space_number(self): self.assertEqual(self.sg.get_spacegroup_number(), 62) self.assertEqual(self.disordered_sg.get_spacegroup_number(), 137) self.assertEqual(self.sg4.get_spacegroup_number(), 166) def test_get_hall(self): self.assertEqual(self.sg.get_hall(), '-P 2ac 2n') self.assertEqual(self.disordered_sg.get_hall(), 'P 4n 2n -1n') def test_get_pointgroup(self): self.assertEqual(self.sg.get_point_group(), 'mmm') self.assertEqual(self.disordered_sg.get_point_group(), '4/mmm') def test_get_symmetry_dataset(self): ds = self.sg.get_symmetry_dataset() self.assertEqual(ds['international'], 'Pnma') def test_get_crystal_system(self): crystal_system = self.sg.get_crystal_system() self.assertEqual('orthorhombic', crystal_system) self.assertEqual('tetragonal', self.disordered_sg.get_crystal_system()) def test_get_symmetry_operations(self): fracsymmops = self.sg.get_symmetry_operations() symmops = self.sg.get_symmetry_operations(True) self.assertEqual(len(symmops), 8) latt = self.structure.lattice for fop, op in zip(fracsymmops, symmops): for site in self.structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac)) found = False newsite = PeriodicSite(site.species_and_occu, newcart, latt, coords_are_cartesian=True) for testsite in self.structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) def test_get_refined_structure(self): for a in self.sg.get_refined_structure().lattice.angles: self.assertEqual(a, 90) refined = self.disordered_sg.get_refined_structure() for a in refined.lattice.angles: self.assertEqual(a, 90) self.assertEqual(refined.lattice.a, refined.lattice.b) s = self.get_structure('Li2O') sg = SpacegroupAnalyzer(s, 0.001) self.assertEqual(sg.get_refined_structure().num_sites, 4 * s.num_sites) def test_get_symmetrized_structure(self): symm_struct = self.sg.get_symmetrized_structure() for a in symm_struct.lattice.angles: self.assertEqual(a, 90) self.assertEqual(len(symm_struct.equivalent_sites), 5) symm_struct = self.disordered_sg.get_symmetrized_structure() self.assertEqual(len(symm_struct.equivalent_sites), 8) self.assertEqual([len(i) for i in symm_struct.equivalent_sites], [16,4,8,4,2,8,8,8]) s1 = symm_struct.equivalent_sites[1][1] s2 = symm_struct[symm_struct.equivalent_indices[1][1]] self.assertEqual(s1, s2) self.assertEqual(self.sg4.get_symmetrized_structure()[0].magmom, 0.1) def test_find_primitive(self): """ F m -3 m Li2O testing of converting to primitive cell """ parser = CifParser(os.path.join(test_dir, 'Li2O.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive() self.assertEqual(primitive_structure.formula, "Li2 O1") # This isn't what is expected. All the angles should be 60 self.assertAlmostEqual(primitive_structure.lattice.alpha, 60) self.assertAlmostEqual(primitive_structure.lattice.beta, 60) self.assertAlmostEqual(primitive_structure.lattice.gamma, 60) self.assertAlmostEqual(primitive_structure.lattice.volume, structure.lattice.volume / 4.0) def test_get_ir_reciprocal_mesh(self): grid=self.sg.get_ir_reciprocal_mesh() self.assertEqual(len(grid), 216) self.assertAlmostEquals(grid[1][0][0], 0.1) self.assertAlmostEquals(grid[1][0][1], 0.0) self.assertAlmostEquals(grid[1][0][2], 0.0) self.assertEqual(grid[1][1], 2) def test_get_conventional_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.b, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.c, 9.1980270633769461) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.b, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.c, 4.2327080177761687) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 2.9542233922299999) self.assertAlmostEqual(conv.lattice.b, 4.6330325651443296) self.assertAlmostEqual(conv.lattice.c, 5.373703587040775) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 4.1430033493799998) self.assertAlmostEqual(conv.lattice.b, 31.437979757624728) self.assertAlmostEqual(conv.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 117.53832420192903) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 14.033435583000625) self.assertAlmostEqual(conv.lattice.b, 3.96052850731) self.assertAlmostEqual(conv.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'rhomb_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 120) self.assertAlmostEqual(conv.lattice.a, 3.699919902005897) self.assertAlmostEqual(conv.lattice.b, 3.699919902005897) self.assertAlmostEqual(conv.lattice.c, 6.9779585500000003) def test_get_primitive_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 109.47122063400001) self.assertAlmostEqual(prim.lattice.beta, 109.47122063400001) self.assertAlmostEqual(prim.lattice.gamma, 109.47122063400001) self.assertAlmostEqual(prim.lattice.a, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.b, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.c, 7.9657251015812145) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 105.015053349) self.assertAlmostEqual(prim.lattice.beta, 105.015053349) self.assertAlmostEqual(prim.lattice.gamma, 118.80658411899999) self.assertAlmostEqual(prim.lattice.a, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.b, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.c, 4.1579321075608791) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 134.78923546600001) self.assertAlmostEqual(prim.lattice.beta, 105.856239333) self.assertAlmostEqual(prim.lattice.gamma, 91.276341676000001) self.assertAlmostEqual(prim.lattice.a, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.b, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.c, 3.8428217771014852) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 164.985257335) self.assertAlmostEqual(prim.lattice.a, 15.854897098324196) self.assertAlmostEqual(prim.lattice.b, 15.854897098324196) self.assertAlmostEqual(prim.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 63.579155761999999) self.assertAlmostEqual(prim.lattice.beta, 116.42084423747779) self.assertAlmostEqual(prim.lattice.gamma, 148.47965136208569) self.assertAlmostEqual(prim.lattice.a, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.b, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'rhomb_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 120) self.assertAlmostEqual(prim.lattice.a, 3.699919902005897) self.assertAlmostEqual(prim.lattice.b, 3.699919902005897) self.assertAlmostEqual(prim.lattice.c, 6.9779585500000003)
def calc_shiftk(self, symprec=0.01, angle_tolerance=5): """ Find the values of `shiftk` and `nshiftk` appropriated for the sampling of the Brillouin zone. When the primitive vectors of the lattice do NOT form a FCC or a BCC lattice, the usual (shifted) Monkhorst-Pack grids are formed by using nshiftk=1 and shiftk 0.5 0.5 0.5 . This is often the preferred k point sampling. For a non-shifted Monkhorst-Pack grid, use `nshiftk=1` and `shiftk 0.0 0.0 0.0`, but there is little reason to do that. When the primitive vectors of the lattice form a FCC lattice, with rprim:: 0.0 0.5 0.5 0.5 0.0 0.5 0.5 0.5 0.0 the (very efficient) usual Monkhorst-Pack sampling will be generated by using nshiftk= 4 and shiftk:: 0.5 0.5 0.5 0.5 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.5 When the primitive vectors of the lattice form a BCC lattice, with rprim:: -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 the usual Monkhorst-Pack sampling will be generated by using nshiftk= 2 and shiftk:: 0.25 0.25 0.25 -0.25 -0.25 -0.25 However, the simple sampling nshiftk=1 and shiftk 0.5 0.5 0.5 is excellent. For hexagonal lattices with hexagonal axes, e.g. rprim:: 1.0 0.0 0.0 -0.5 sqrt(3)/2 0.0 0.0 0.0 1.0 one can use nshiftk= 1 and shiftk 0.0 0.0 0.5 In rhombohedral axes, e.g. using angdeg 3*60., this corresponds to shiftk 0.5 0.5 0.5, to keep the shift along the symmetry axis. Returns: Suggested value of shiftk. """ # Find lattice type. sym = SpacegroupAnalyzer(self, symprec=symprec, angle_tolerance=angle_tolerance) lattice_type, spg_symbol = sym.get_lattice_type( ), sym.get_spacegroup_symbol() # Generate the appropriate set of shifts. shiftk = None if lattice_type == "cubic": if "F" in spg_symbol: # FCC shiftk = [ 0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5 ] elif "I" in spg_symbol: # BCC shiftk = [0.25, 0.25, 0.25, -0.25, -0.25, -0.25] #shiftk = [0.5, 0.5, 05]) elif lattice_type == "hexagonal": # Find the hexagonal axis and set the shift along it. for i, angle in enumerate(self.lattice.angles): if abs(angle - 120) < 1.0: j = (i + 1) % 3 k = (i + 2) % 3 hex_ax = [ax for ax in range(3) if ax not in [j, k]][0] break else: raise ValueError("Cannot find hexagonal axis") shiftk = [0.0, 0.0, 0.0] shiftk[hex_ax] = 0.5 if shiftk is None: # Use default value. shiftk = [0.5, 0.5, 0.5] return np.reshape(shiftk, (-1, 3))
def __init__(self, struct, find_spacegroup=False, symprec=None): """ Args: struct (Structure): structure to write find_spacegroup (bool): whether to try to determine the spacegroup symprec (float): If not none, finds the symmetry of the structure and writes the cif with symmetry information. Passes symprec to the SpacegroupAnalyzer """ format_str = "{:.8f}" block = OrderedDict() loops = [] latt = struct.lattice comp = struct.composition no_oxi_comp = comp.element_composition spacegroup = ("P 1", 1) if find_spacegroup: sf = SpacegroupAnalyzer(struct, 0.001) spacegroup = (sf.get_spacegroup_symbol(), sf.get_spacegroup_number()) block["_symmetry_space_group_name_H-M"] = spacegroup[0] for cell_attr in ['a', 'b', 'c']: block["_cell_length_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) for cell_attr in ['alpha', 'beta', 'gamma']: block["_cell_angle_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) block["_symmetry_Int_Tables_number"] = spacegroup[1] block["_chemical_formula_structural"] = no_oxi_comp.reduced_formula block["_chemical_formula_sum"] = no_oxi_comp.formula block["_cell_volume"] = latt.volume.__str__() reduced_comp = no_oxi_comp.reduced_composition el = no_oxi_comp.elements[0] amt = comp[el] fu = int(amt / reduced_comp[Element(el.symbol)]) block["_cell_formula_units_Z"] = str(fu) if symprec is None: block["_symmetry_equiv_pos_site_id"] = ["1"] block["_symmetry_equiv_pos_as_xyz"] = ["x, y, z"] else: sf = SpacegroupAnalyzer(struct, symprec) ops = [op.as_xyz_string() for op in sf.get_symmetry_operations()] block["_symmetry_equiv_pos_site_id"] = \ ["%d" % i for i in range(1, len(ops) + 1)] block["_symmetry_equiv_pos_as_xyz"] = ops loops.append(["_symmetry_equiv_pos_site_id", "_symmetry_equiv_pos_as_xyz"]) contains_oxidation = True try: symbol_to_oxinum = OrderedDict([ (el.__str__(), float(el.oxi_state)) for el in sorted(comp.elements)]) except AttributeError: symbol_to_oxinum = OrderedDict([(el.symbol, 0) for el in sorted(comp.elements)]) contains_oxidation = False if contains_oxidation: block["_atom_type_symbol"] = symbol_to_oxinum.keys() block["_atom_type_oxidation_number"] = symbol_to_oxinum.values() loops.append(["_atom_type_symbol", "_atom_type_oxidation_number"]) atom_site_type_symbol = [] atom_site_symmetry_multiplicity = [] atom_site_fract_x = [] atom_site_fract_y = [] atom_site_fract_z = [] atom_site_label = [] atom_site_occupancy = [] count = 1 if symprec is None: for site in struct: for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("1") atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 else: for group in sf.get_symmetrized_structure().equivalent_sites: site = group[0] for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("%d" % len(group)) atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 block["_atom_site_type_symbol"] = atom_site_type_symbol block["_atom_site_label"] = atom_site_label block["_atom_site_symmetry_multiplicity"] = \ atom_site_symmetry_multiplicity block["_atom_site_fract_x"] = atom_site_fract_x block["_atom_site_fract_y"] = atom_site_fract_y block["_atom_site_fract_z"] = atom_site_fract_z block["_atom_site_occupancy"] = atom_site_occupancy loops.append(["_atom_site_type_symbol", "_atom_site_label", "_atom_site_symmetry_multiplicity", "_atom_site_fract_x", "_atom_site_fract_y", "_atom_site_fract_z", "_atom_site_occupancy"]) d = OrderedDict() d[comp.reduced_formula] = CifBlock(block, loops, comp.reduced_formula) self._cf = CifFile(d)
def __init__(self, struct, symprec=None): format_str = "{:.8f}" block = OrderedDict() loops = [] latt = struct.lattice comp = struct.composition no_oxi_comp = comp.element_composition spacegroup = ("P 1", 1) if symprec is not None: sf = SpacegroupAnalyzer(struct, symprec) spacegroup = (sf.get_spacegroup_symbol(), sf.get_spacegroup_number()) block["_symmetry_space_group_name_H-M"] = spacegroup[0] for cell_attr in ['a', 'b', 'c']: block["_cell_length_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) for cell_attr in ['alpha', 'beta', 'gamma']: block["_cell_angle_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) block["_symmetry_Int_Tables_number"] = spacegroup[1] block["_chemical_formula_structural"] = no_oxi_comp.reduced_formula block["_chemical_formula_sum"] = no_oxi_comp.formula block["_cell_volume"] = latt.volume.__str__() reduced_comp, fu = no_oxi_comp.get_reduced_composition_and_factor() block["_cell_formula_units_Z"] = str(int(fu)) if symprec is None: block["_symmetry_equiv_pos_site_id"] = ["1"] block["_symmetry_equiv_pos_as_xyz"] = ["x, y, z"] else: sf = SpacegroupAnalyzer(struct, symprec) def round_symm_trans(i): for t in TRANSLATIONS.values(): if abs(i - t) < symprec: return t if abs(i - round(i)) < symprec: return 0 raise ValueError("Invalid translation!") symmops = [] for op in sf.get_symmetry_operations(): v = op.translation_vector v = [round_symm_trans(i) for i in v] symmops.append(SymmOp.from_rotation_and_translation( op.rotation_matrix, v)) ops = [op.as_xyz_string() for op in symmops] block["_symmetry_equiv_pos_site_id"] = \ ["%d" % i for i in range(1, len(ops) + 1)] block["_symmetry_equiv_pos_as_xyz"] = ops loops.append(["_symmetry_equiv_pos_site_id", "_symmetry_equiv_pos_as_xyz"]) contains_oxidation = True try: symbol_to_oxinum = OrderedDict([ (el.__str__(), float(el.oxi_state)) for el in sorted(comp.elements)]) except AttributeError: symbol_to_oxinum = OrderedDict([(el.symbol, 0) for el in sorted(comp.elements)]) contains_oxidation = False if contains_oxidation: block["_atom_type_symbol"] = symbol_to_oxinum.keys() block["_atom_type_oxidation_number"] = symbol_to_oxinum.values() loops.append(["_atom_type_symbol", "_atom_type_oxidation_number"]) atom_site_type_symbol = [] atom_site_symmetry_multiplicity = [] atom_site_fract_x = [] atom_site_fract_y = [] atom_site_fract_z = [] atom_site_label = [] atom_site_occupancy = [] count = 1 if symprec is None: for site in struct: for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("1") atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 else: # The following just presents a deterministic ordering. unique_sites = [ (sorted(sites, key=lambda s: tuple([abs(x) for x in s.frac_coords]))[0], len(sites)) for sites in sf.get_symmetrized_structure().equivalent_sites ] for site, mult in sorted( unique_sites, key=lambda t: (t[0].species_and_occu.average_electroneg, -t[1], t[0].a, t[0].b, t[0].c)): for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("%d" % mult) atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 block["_atom_site_type_symbol"] = atom_site_type_symbol block["_atom_site_label"] = atom_site_label block["_atom_site_symmetry_multiplicity"] = \ atom_site_symmetry_multiplicity block["_atom_site_fract_x"] = atom_site_fract_x block["_atom_site_fract_y"] = atom_site_fract_y block["_atom_site_fract_z"] = atom_site_fract_z block["_atom_site_occupancy"] = atom_site_occupancy loops.append(["_atom_site_type_symbol", "_atom_site_label", "_atom_site_symmetry_multiplicity", "_atom_site_fract_x", "_atom_site_fract_y", "_atom_site_fract_z", "_atom_site_occupancy"]) d = OrderedDict() d[comp.reduced_formula] = CifBlock(block, loops, comp.reduced_formula) self._cf = CifFile(d)
def _gen_input_file(self): """ Generate the necessary struct_enum.in file for enumlib. See enumlib documentation for details. """ coord_format = "{:.6f} {:.6f} {:.6f}" # Using symmetry finder, get the symmetrically distinct sites. fitter = SpacegroupAnalyzer(self.structure, self.symm_prec) symmetrized_structure = fitter.get_symmetrized_structure() logger.debug("Spacegroup {} ({}) with {} distinct sites".format( fitter.get_spacegroup_symbol(), fitter.get_spacegroup_number(), len(symmetrized_structure.equivalent_sites)) ) """ Enumlib doesn"t work when the number of species get too large. To simplify matters, we generate the input file only with disordered sites and exclude the ordered sites from the enumeration. The fact that different disordered sites with the exact same species may belong to different equivalent sites is dealt with by having determined the spacegroup earlier and labelling the species differently. """ # index_species and index_amounts store mappings between the indices # used in the enum input file, and the actual species and amounts. index_species = [] index_amounts = [] #Stores the ordered sites, which are not enumerated. ordered_sites = [] disordered_sites = [] coord_str = [] for sites in symmetrized_structure.equivalent_sites: if sites[0].is_ordered: ordered_sites.append(sites) else: sp_label = [] species = {k: v for k, v in sites[0].species_and_occu.items()} if sum(species.values()) < 1 - EnumlibAdaptor.amount_tol: #Let us first make add a dummy element for every single #site whose total occupancies don't sum to 1. species[DummySpecie("X")] = 1 - sum(species.values()) for sp in species.keys(): if sp not in index_species: index_species.append(sp) sp_label.append(len(index_species) - 1) index_amounts.append(species[sp] * len(sites)) else: ind = index_species.index(sp) sp_label.append(ind) index_amounts[ind] += species[sp] * len(sites) sp_label = "/".join(["{}".format(i) for i in sorted(sp_label)]) for site in sites: coord_str.append("{} {}".format( coord_format.format(*site.coords), sp_label)) disordered_sites.append(sites) def get_sg_info(ss): finder = SpacegroupAnalyzer(Structure.from_sites(ss), self.symm_prec) sgnum = finder.get_spacegroup_number() return sgnum curr_sites = list(itertools.chain.from_iterable(disordered_sites)) min_sgnum = get_sg_info(curr_sites) logger.debug("Disorderd sites has sgnum %d" % ( min_sgnum)) #It could be that some of the ordered sites has a lower symmetry than #the disordered sites. So we consider the lowest symmetry sites as #disordered in our enumeration. self.ordered_sites = [] to_add = [] if self.check_ordered_symmetry: for sites in ordered_sites: temp_sites = list(curr_sites) + sites sgnum = get_sg_info(temp_sites) if sgnum < min_sgnum: logger.debug("Adding {} to sites to be ordered. " "New sgnum {}" .format(sites, sgnum)) to_add = sites min_sgnum = sgnum for sites in ordered_sites: if sites == to_add: index_species.append(sites[0].specie) index_amounts.append(len(sites)) sp_label = len(index_species) - 1 logger.debug("Lowest symmetry {} sites are included in enum." .format(sites[0].specie)) for site in sites: coord_str.append("{} {}".format( coord_format.format(*site.coords), sp_label)) disordered_sites.append(sites) else: self.ordered_sites.extend(sites) self.index_species = index_species lattice = self.structure.lattice output = [self.structure.formula, "bulk"] for vec in lattice.matrix: output.append(coord_format.format(*vec)) output.append("{}".format(len(index_species))) output.append("{}".format(len(coord_str))) output.extend(coord_str) output.append("{} {}".format(self.min_cell_size, self.max_cell_size)) output.append(str(self.enum_precision_parameter)) output.append("partial") ndisordered = sum([len(s) for s in disordered_sites]) base = int(ndisordered*reduce(lcm, [f.limit_denominator( ndisordered * self.max_cell_size).denominator for f in map(fractions.Fraction, index_amounts)])) #base = ndisordered #10 ** int(math.ceil(math.log10(ndisordered))) #To get a reasonable number of structures, we fix concentrations to the #range expected in the original structure. total_amounts = sum(index_amounts) for amt in index_amounts: conc = amt / total_amounts if abs(conc * base - round(conc * base)) < 1e-5: output.append("{} {} {}".format(int(round(conc * base)), int(round(conc * base)), base)) else: min_conc = int(math.floor(conc * base)) output.append("{} {} {}".format(min_conc - 1, min_conc + 1, base)) output.append("") logger.debug("Generated input file:\n{}".format("\n".join(output))) with open("struct_enum.in", "w") as f: f.write("\n".join(output))
class HighSymmKpath(object): """ This class looks for path along high symmetry lines in the Brillouin Zone. It is based on Setyawan, W., & Curtarolo, S. (2010). High-throughput electronic band structure calculations: Challenges and tools. Computational Materials Science, 49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010 The symmetry is determined by spglib through the SpacegroupAnalyzer class Args: structure (Structure): Structure object symprec (float): Tolerance for symmetry finding angle_tolerance (float): Angle tolerance for symmetry finding. """ def __init__(self, structure, symprec=0.01, angle_tolerance=5): self._structure = structure self._sym = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance) self._prim = self._sym\ .get_primitive_standard_structure(international_monoclinic=False) self._conv = self._sym.get_conventional_standard_structure( international_monoclinic=False) self._prim_rec = self._prim.lattice.reciprocal_lattice self._kpath = None lattice_type = self._sym.get_lattice_type() spg_symbol = self._sym.get_spacegroup_symbol() if lattice_type == "cubic": if "P" in spg_symbol: self._kpath = self.cubic() elif "F" in spg_symbol: self._kpath = self.fcc() elif "I" in spg_symbol: self._kpath = self.bcc() else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "tetragonal": if "P" in spg_symbol: self._kpath = self.tet() elif "I" in spg_symbol: a = self._conv.lattice.abc[0] c = self._conv.lattice.abc[2] if c < a: self._kpath = self.bctet1(c, a) else: self._kpath = self.bctet2(c, a) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "orthorhombic": a = self._conv.lattice.abc[0] b = self._conv.lattice.abc[1] c = self._conv.lattice.abc[2] if "P" in spg_symbol: self._kpath = self.orc() elif "F" in spg_symbol: if 1 / a**2 > 1 / b**2 + 1 / c**2: self._kpath = self.orcf1(a, b, c) elif 1 / a**2 < 1 / b**2 + 1 / c**2: self._kpath = self.orcf2(a, b, c) else: self._kpath = self.orcf3(a, b, c) elif "I" in spg_symbol: self._kpath = self.orci(a, b, c) elif "C" in spg_symbol: self._kpath = self.orcc(a, b, c) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "hexagonal": self._kpath = self.hex() elif lattice_type == "rhombohedral": alpha = self._prim.lattice.lengths_and_angles[1][0] if alpha < 90: self._kpath = self.rhl1(alpha * pi / 180) else: self._kpath = self.rhl2(alpha * pi / 180) elif lattice_type == "monoclinic": a, b, c = self._conv.lattice.abc alpha = self._conv.lattice.lengths_and_angles[1][0] #beta = self._conv.lattice.lengths_and_angles[1][1] if "P" in spg_symbol: self._kpath = self.mcl(b, c, alpha * pi / 180) elif "C" in spg_symbol: kgamma = self._prim_rec.lengths_and_angles[1][2] if kgamma > 90: self._kpath = self.mclc1(a, b, c, alpha * pi / 180) if kgamma == 90: self._kpath = self.mclc2(a, b, c, alpha * pi / 180) if kgamma < 90: if b * cos(alpha * pi / 180) / c\ + b ** 2 * sin(alpha) ** 2 / a ** 2 < 1: self._kpath = self.mclc3(a, b, c, alpha * pi / 180) if b * cos(alpha * pi / 180) / c \ + b ** 2 * sin(alpha) ** 2 / a ** 2 == 1: self._kpath = self.mclc4(a, b, c, alpha * pi / 180) if b * cos(alpha * pi / 180) / c \ + b ** 2 * sin(alpha) ** 2 / a ** 2 > 1: self._kpath = self.mclc5(a, b, c, alpha * pi / 180) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "triclinic": kalpha = self._prim_rec.lengths_and_angles[1][0] kbeta = self._prim_rec.lengths_and_angles[1][1] kgamma = self._prim_rec.lengths_and_angles[1][2] if kalpha > 90 and kbeta > 90 and kgamma > 90: self._kpath = self.tria() if kalpha < 90 and kbeta < 90 and kgamma < 90: self._kpath = self.trib() if kalpha > 90 and kbeta > 90 and kgamma == 90: self._kpath = self.tria() if kalpha < 90 and kbeta < 90 and kgamma == 90: self._kpath = self.trib() else: warn("Unknown lattice type %s" % lattice_type) @property def structure(self): """ Returns: The standardized primitive structure """ return self._prim @property def conventional(self): """ Returns: The conventional cell structure """ return self._conv @property def prim(self): """ Returns: The primitive cell structure """ return self._prim @property def prim_rec(self): """ Returns: The primitive reciprocal cell structure """ return self._prim_rec @property def kpath(self): """ Returns: The symmetry line path in reciprocal space """ return self._kpath def get_kpoints(self, line_density=20, coords_are_cartesian=True): """ Returns: the kpoints along the paths in cartesian coordinates together with the labels for symmetry points -Wei """ list_k_points = [] sym_point_labels = [] for b in self.kpath['path']: for i in range(1, len(b)): start = np.array(self.kpath['kpoints'][b[i - 1]]) end = np.array(self.kpath['kpoints'][b[i]]) distance = np.linalg.norm( self._prim_rec.get_cartesian_coords(start) - self._prim_rec.get_cartesian_coords(end)) nb = int(ceil(distance * line_density)) sym_point_labels.extend([b[i - 1]] + [''] * (nb - 1) + [b[i]]) list_k_points.extend([ self._prim_rec.get_cartesian_coords(start) + float(i) / float(nb) * (self._prim_rec.get_cartesian_coords(end) - self._prim_rec.get_cartesian_coords(start)) for i in range(0, nb + 1) ]) if coords_are_cartesian: return list_k_points, sym_point_labels else: frac_k_points = [ self._prim_rec.get_fractional_coords(k) for k in list_k_points ] return frac_k_points, sym_point_labels def cubic(self): self.name = "CUB" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'X': np.array([0.0, 0.5, 0.0]), 'R': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.5, 0.0]) } path = [["\Gamma", "X", "M", "\Gamma", "R", "X"], ["M", "R"]] return {'kpoints': kpoints, 'path': path} def fcc(self): self.name = "FCC" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'K': np.array([3.0 / 8.0, 3.0 / 8.0, 3.0 / 4.0]), 'L': np.array([0.5, 0.5, 0.5]), 'U': np.array([5.0 / 8.0, 1.0 / 4.0, 5.0 / 8.0]), 'W': np.array([0.5, 1.0 / 4.0, 3.0 / 4.0]), 'X': np.array([0.5, 0.0, 0.5]) } path = [["\Gamma", "X", "W", "K", "\Gamma", "L", "U", "W", "L", "K"], ["U", "X"]] return {'kpoints': kpoints, 'path': path} def bcc(self): self.name = "BCC" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'H': np.array([0.5, -0.5, 0.5]), 'P': np.array([0.25, 0.25, 0.25]), 'N': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "H", "N", "\Gamma", "P", "H"], ["P", "N"]] return {'kpoints': kpoints, 'path': path} def tet(self): self.name = "TET" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.5, 0.0]), 'R': np.array([0.0, 0.5, 0.5]), 'X': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "X", "M", "\Gamma", "Z", "R", "A", "Z"], ["X", "R"], ["M", "A"]] return {'kpoints': kpoints, 'path': path} def bctet1(self, c, a): self.name = "BCT1" eta = (1 + c**2 / a**2) / 4.0 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'M': np.array([-0.5, 0.5, 0.5]), 'N': np.array([0.0, 0.5, 0.0]), 'P': np.array([0.25, 0.25, 0.25]), 'X': np.array([0.0, 0.0, 0.5]), 'Z': np.array([eta, eta, -eta]), 'Z_1': np.array([-eta, 1 - eta, eta]) } path = [["\Gamma", "X", "M", "\Gamma", "Z", "P", "N", "Z_1", "M"], ["X", "P"]] return {'kpoints': kpoints, 'path': path} def bctet2(self, c, a): self.name = "BCT2" eta = (1 + a**2 / c**2) / 4.0 zeta = a**2 / (2 * c**2) kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.0, 0.5, 0.0]), 'P': np.array([0.25, 0.25, 0.25]), '\Sigma': np.array([-eta, eta, eta]), '\Sigma_1': np.array([eta, 1 - eta, -eta]), 'X': np.array([0.0, 0.0, 0.5]), 'Y': np.array([-zeta, zeta, 0.5]), 'Y_1': np.array([0.5, 0.5, -zeta]), 'Z': np.array([0.5, 0.5, -0.5]) } path = [[ "\Gamma", "X", "Y", "\Sigma", "\Gamma", "Z", "\Sigma_1", "N", "P", "Y_1", "Z" ], ["X", "P"]] return {'kpoints': kpoints, 'path': path} def orc(self): self.name = "ORC" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'R': np.array([0.5, 0.5, 0.5]), 'S': np.array([0.5, 0.5, 0.0]), 'T': np.array([0.0, 0.5, 0.5]), 'U': np.array([0.5, 0.0, 0.5]), 'X': np.array([0.5, 0.0, 0.0]), 'Y': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "X", "S", "Y", "\Gamma", "Z", "U", "R", "T", "Z"], ["Y", "T"], ["U", "X"], ["S", "R"]] return {'kpoints': kpoints, 'path': path} def orcf1(self, a, b, c): self.name = "ORCF1" zeta = (1 + a**2 / b**2 - a**2 / c**2) / 4 eta = (1 + a**2 / b**2 + a**2 / c**2) / 4 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5 + zeta, zeta]), 'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]), 'L': np.array([0.5, 0.5, 0.5]), 'T': np.array([1, 0.5, 0.5]), 'X': np.array([0.0, eta, eta]), 'X_1': np.array([1, 1 - eta, 1 - eta]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0]) } path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"], ["T", "X_1"], ["X", "A", "Z"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orcf2(self, a, b, c): self.name = "ORCF2" phi = (1 + c**2 / b**2 - c**2 / a**2) / 4 eta = (1 + a**2 / b**2 - a**2 / c**2) / 4 delta = (1 + b**2 / a**2 - b**2 / c**2) / 4 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'C': np.array([0.5, 0.5 - eta, 1 - eta]), 'C_1': np.array([0.5, 0.5 + eta, eta]), 'D': np.array([0.5 - delta, 0.5, 1 - delta]), 'D_1': np.array([0.5 + delta, 0.5, delta]), 'L': np.array([0.5, 0.5, 0.5]), 'H': np.array([1 - phi, 0.5 - phi, 0.5]), 'H_1': np.array([phi, 0.5 + phi, 0.5]), 'X': np.array([0.0, 0.5, 0.5]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0]) } path = [["\Gamma", "Y", "C", "D", "X", "\Gamma", "Z", "D_1", "H", "C"], ["C_1", "Z"], ["X", "H_1"], ["H", "Y"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orcf3(self, a, b, c): self.name = "ORCF3" zeta = (1 + a**2 / b**2 - a**2 / c**2) / 4 eta = (1 + a**2 / b**2 + a**2 / c**2) / 4 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5 + zeta, zeta]), 'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]), 'L': np.array([0.5, 0.5, 0.5]), 'T': np.array([1, 0.5, 0.5]), 'X': np.array([0.0, eta, eta]), 'X_1': np.array([1, 1 - eta, 1 - eta]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0]) } path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"], ["X", "A", "Z"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orci(self, a, b, c): self.name = "ORCI" zeta = (1 + a**2 / c**2) / 4 eta = (1 + b**2 / c**2) / 4 delta = (b**2 - a**2) / (4 * c**2) mu = (a**2 + b**2) / (4 * c**2) kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([-mu, mu, 0.5 - delta]), 'L_1': np.array([mu, -mu, 0.5 + delta]), 'L_2': np.array([0.5 - delta, 0.5 + delta, -mu]), 'R': np.array([0.0, 0.5, 0.0]), 'S': np.array([0.5, 0.0, 0.0]), 'T': np.array([0.0, 0.0, 0.5]), 'W': np.array([0.25, 0.25, 0.25]), 'X': np.array([-zeta, zeta, zeta]), 'X_1': np.array([zeta, 1 - zeta, -zeta]), 'Y': np.array([eta, -eta, eta]), 'Y_1': np.array([1 - eta, eta, -eta]), 'Z': np.array([0.5, 0.5, -0.5]) } path = [[ "\Gamma", "X", "L", "T", "W", "R", "X_1", "Z", "\Gamma", "Y", "S", "W" ], ["L_1", "Y"], ["Y_1", "Z"]] return {'kpoints': kpoints, 'path': path} def orcc(self, a, b, c): self.name = "ORCC" zeta = (1 + a**2 / b**2) / 4 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([zeta, zeta, 0.5]), 'A_1': np.array([-zeta, 1 - zeta, 0.5]), 'R': np.array([0.0, 0.5, 0.5]), 'S': np.array([0.0, 0.5, 0.0]), 'T': np.array([-0.5, 0.5, 0.5]), 'X': np.array([zeta, zeta, 0.0]), 'X_1': np.array([-zeta, 1 - zeta, 0.0]), 'Y': np.array([-0.5, 0.5, 0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [[ "\Gamma", "X", "S", "R", "A", "Z", "\Gamma", "Y", "X_1", "A_1", "T", "Y" ], ["Z", "T"]] return {'kpoints': kpoints, 'path': path} def hex(self): self.name = "HEX" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.0, 0.0, 0.5]), 'H': np.array([1.0 / 3.0, 1.0 / 3.0, 0.5]), 'K': np.array([1.0 / 3.0, 1.0 / 3.0, 0.0]), 'L': np.array([0.5, 0.0, 0.5]), 'M': np.array([0.5, 0.0, 0.0]) } path = [["\Gamma", "M", "K", "\Gamma", "A", "L", "H", "A"], ["L", "M"], ["K", "H"]] return {'kpoints': kpoints, 'path': path} def rhl1(self, alpha): self.name = "RHL1" eta = (1 + 4 * cos(alpha)) / (2 + 4 * cos(alpha)) nu = 3.0 / 4.0 - eta / 2.0 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'B': np.array([eta, 0.5, 1.0 - eta]), 'B_1': np.array([1.0 / 2.0, 1.0 - eta, eta - 1.0]), 'F': np.array([0.5, 0.5, 0.0]), 'L': np.array([0.5, 0.0, 0.0]), 'L_1': np.array([0.0, 0.0, -0.5]), 'P': np.array([eta, nu, nu]), 'P_1': np.array([1.0 - nu, 1.0 - nu, 1.0 - eta]), 'P_2': np.array([nu, nu, eta - 1.0]), 'Q': np.array([1.0 - nu, nu, 0.0]), 'X': np.array([nu, 0.0, -nu]), 'Z': np.array([0.5, 0.5, 0.5]) } path = [["\Gamma", "L", "B_1"], ["B", "Z", "\Gamma", "X"], ["Q", "F", "P_1", "Z"], ["L", "P"]] return {'kpoints': kpoints, 'path': path} def rhl2(self, alpha): self.name = "RHL2" eta = 1 / (2 * tan(alpha / 2.0)**2) nu = 3.0 / 4.0 - eta / 2.0 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([0.5, -0.5, 0.0]), 'L': np.array([0.5, 0.0, 0.0]), 'P': np.array([1 - nu, -nu, 1 - nu]), 'P_1': np.array([nu, nu - 1.0, nu - 1.0]), 'Q': np.array([eta, eta, eta]), 'Q_1': np.array([1.0 - eta, -eta, -eta]), 'Z': np.array([0.5, -0.5, 0.5]) } path = [[ "\Gamma", "P", "Z", "Q", "\Gamma", "F", "P_1", "Q_1", "L", "Z" ]] return {'kpoints': kpoints, 'path': path} def mcl(self, b, c, beta): self.name = "MCL" eta = (1 - b * cos(beta) / c) / (2 * sin(beta)**2) nu = 0.5 - eta * c * cos(beta) / b kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5, 0.0]), 'C': np.array([0.0, 0.5, 0.5]), 'D': np.array([0.5, 0.0, 0.5]), 'D_1': np.array([0.5, 0.5, -0.5]), 'E': np.array([0.5, 0.5, 0.5]), 'H': np.array([0.0, eta, 1.0 - nu]), 'H_1': np.array([0.0, 1.0 - eta, nu]), 'H_2': np.array([0.0, eta, -nu]), 'M': np.array([0.5, eta, 1.0 - nu]), 'M_1': np.array([0.5, 1 - eta, nu]), 'M_2': np.array([0.5, 1 - eta, nu]), 'X': np.array([0.0, 0.5, 0.0]), 'Y': np.array([0.0, 0.0, 0.5]), 'Y_1': np.array([0.0, 0.0, -0.5]), 'Z': np.array([0.5, 0.0, 0.0]) } path = [["\Gamma", "Y", "H", "C", "E", "M_1", "A", "X", "H_1"], ["M", "D", "Z"], ["Y", "D"]] return {'kpoints': kpoints, 'path': path} def mclc1(self, a, b, c, alpha): self.name = "MCLC1" zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha)**2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b psi = 0.75 - a**2 / (4 * b**2 * sin(alpha)**2) phi = psi + (0.75 - psi) * b * cos(alpha) / c kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'F': np.array([1 - zeta, 1 - zeta, 1 - eta]), 'F_1': np.array([zeta, zeta, eta]), 'F_2': np.array([-zeta, -zeta, 1 - eta]), #'F_3': np.array([1 - zeta, -zeta, 1 - eta]), 'I': np.array([phi, 1 - phi, 0.5]), 'I_1': np.array([1 - phi, phi - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'X': np.array([1 - psi, psi - 1, 0.0]), 'X_1': np.array([psi, 1 - psi, 0.0]), 'X_2': np.array([psi - 1, -psi, 0.0]), 'Y': np.array([0.5, 0.5, 0.0]), 'Y_1': np.array([-0.5, -0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"], ["Y", "X_1"], ["X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc2(self, a, b, c, alpha): self.name = "MCLC2" zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha)**2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b psi = 0.75 - a**2 / (4 * b**2 * sin(alpha)**2) phi = psi + (0.75 - psi) * b * cos(alpha) / c kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'F': np.array([1 - zeta, 1 - zeta, 1 - eta]), 'F_1': np.array([zeta, zeta, eta]), 'F_2': np.array([-zeta, -zeta, 1 - eta]), 'F_3': np.array([1 - zeta, -zeta, 1 - eta]), 'I': np.array([phi, 1 - phi, 0.5]), 'I_1': np.array([1 - phi, phi - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'X': np.array([1 - psi, psi - 1, 0.0]), 'X_1': np.array([psi, 1 - psi, 0.0]), 'X_2': np.array([psi - 1, -psi, 0.0]), 'Y': np.array([0.5, 0.5, 0.0]), 'Y_1': np.array([-0.5, -0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"], ["N", "\Gamma", "M"]] return {'kpoints': kpoints, 'path': path} def mclc3(self, a, b, c, alpha): self.name = "MCLC3" mu = (1 + b**2 / a**2) / 4.0 delta = b * c * cos(alpha) / (2 * a**2) zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\ / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b phi = 1 + zeta - 2 * mu psi = eta - 2 * delta kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([1 - phi, 1 - phi, 1 - psi]), 'F_1': np.array([phi, phi - 1, psi]), 'F_2': np.array([1 - phi, -phi, 1 - psi]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([0.5, -0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "H", "Z", "I", "F_1"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc4(self, a, b, c, alpha): self.name = "MCLC4" mu = (1 + b**2 / a**2) / 4.0 delta = b * c * cos(alpha) / (2 * a**2) zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\ / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b phi = 1 + zeta - 2 * mu psi = eta - 2 * delta kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([1 - phi, 1 - phi, 1 - psi]), 'F_1': np.array([phi, phi - 1, psi]), 'F_2': np.array([1 - phi, -phi, 1 - psi]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([0.5, -0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "H", "Z", "I"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc5(self, a, b, c, alpha): self.name = "MCLC5" zeta = (b**2 / a**2 + (1 - b * cos(alpha) / c) / sin(alpha)**2) / 4 eta = 0.5 + 2 * zeta * c * cos(alpha) / b mu = eta / 2 + b ** 2 / (4 * a ** 2) \ - b * c * cos(alpha) / (2 * a ** 2) nu = 2 * mu - zeta rho = 1 - zeta * a**2 / b**2 omega = (4 * nu - 1 - b ** 2 * sin(alpha) ** 2 / a ** 2)\ * c / (2 * b * cos(alpha)) delta = zeta * c * cos(alpha) / b + omega / 2 - 0.25 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([nu, nu, omega]), 'F_1': np.array([1 - nu, 1 - nu, 1 - omega]), 'F_2': np.array([nu, nu - 1, omega]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([rho, 1 - rho, 0.5]), 'I_1': np.array([1 - rho, rho - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "H", "F_1"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def tria(self): self.name = "TRI1a" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([0.5, 0.5, 0.0]), 'M': np.array([0.0, 0.5, 0.5]), 'N': np.array([0.5, 0.0, 0.5]), 'R': np.array([0.5, 0.5, 0.5]), 'X': np.array([0.5, 0.0, 0.0]), 'Y': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"], ["N", "\Gamma", "M"], ["R", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def trib(self): self.name = "TRI1b" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([0.5, -0.5, 0.0]), 'M': np.array([0.0, 0.0, 0.5]), 'N': np.array([-0.5, -0.5, 0.5]), 'R': np.array([0.0, -0.5, 0.5]), 'X': np.array([0.0, -0.5, 0.0]), 'Y': np.array([0.5, 0.0, 0.0]), 'Z': np.array([-0.5, 0.0, 0.5]) } path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"], ["N", "\Gamma", "M"], ["R", "\Gamma"]] return {'kpoints': kpoints, 'path': path}
print("-d must be followed by an integer") exit(1) # read structure if os.path.exists(fstruct): struct = mg.Structure.from_file(fstruct) else: print("File %s does not exist" % fstruct) exit(1) # symmetry information struct_sym = SpacegroupAnalyzer(struct) print("\nLattice details:") print("----------------") print("lattice type : {0}".format(struct_sym.get_lattice_type())) print("space group : {0} ({1})".format(struct_sym.get_spacegroup_symbol(), struct_sym.get_spacegroup_number())) # Compute first brillouin zone ibz = HighSymmKpath(struct) print("ibz type : {0}".format(ibz.name)) ibz.get_kpath_plot(savefig="path.png") # print specific kpoints in the first brillouin zone print("\nList of high symmetry k-points:") print("-------------------------------") for key, val in ibz.kpath["kpoints"].items(): print("%8s %s" % (key, str(val))) # suggested path for the band structure print("\nSuggested paths in first brillouin zone:")
class SpacegroupAnalyzerTest(PymatgenTest): def setUp(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) self.structure = p.structure self.sg = SpacegroupAnalyzer(self.structure, 0.001) self.disordered_structure = self.get_structure('Li10GeP2S12') self.disordered_sg = SpacegroupAnalyzer(self.disordered_structure, 0.001) s = p.structure.copy() site = s[0] del s[0] s.append(site.species_and_occu, site.frac_coords) self.sg3 = SpacegroupAnalyzer(s, 0.001) graphite = self.get_structure('Graphite') graphite.add_site_property("magmom", [0.1] * len(graphite)) self.sg4 = SpacegroupAnalyzer(graphite, 0.001) def test_get_space_symbol(self): self.assertEqual(self.sg.get_spacegroup_symbol(), "Pnma") self.assertEqual(self.disordered_sg.get_spacegroup_symbol(), "P4_2/nmc") self.assertEqual(self.sg3.get_spacegroup_symbol(), "Pnma") self.assertEqual(self.sg4.get_spacegroup_symbol(), "P6_3/mmc") def test_get_space_number(self): self.assertEqual(self.sg.get_spacegroup_number(), 62) self.assertEqual(self.disordered_sg.get_spacegroup_number(), 137) self.assertEqual(self.sg4.get_spacegroup_number(), 194) def test_get_hall(self): self.assertEqual(self.sg.get_hall(), '-P 2ac 2n') self.assertEqual(self.disordered_sg.get_hall(), 'P 4n 2n -1n') def test_get_pointgroup(self): self.assertEqual(self.sg.get_point_group(), 'mmm') self.assertEqual(self.disordered_sg.get_point_group(), '4/mmm') def test_get_symmetry_dataset(self): ds = self.sg.get_symmetry_dataset() self.assertEqual(ds['international'], 'Pnma') def test_get_crystal_system(self): crystal_system = self.sg.get_crystal_system() self.assertEqual('orthorhombic', crystal_system) self.assertEqual('tetragonal', self.disordered_sg.get_crystal_system()) def test_get_symmetry_operations(self): fracsymmops = self.sg.get_symmetry_operations() symmops = self.sg.get_symmetry_operations(True) self.assertEqual(len(symmops), 8) latt = self.structure.lattice for fop, op in zip(fracsymmops, symmops): for site in self.structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac)) found = False newsite = PeriodicSite(site.species_and_occu, newcart, latt, coords_are_cartesian=True) for testsite in self.structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) def test_get_refined_structure(self): for a in self.sg.get_refined_structure().lattice.angles: self.assertEqual(a, 90) refined = self.disordered_sg.get_refined_structure() for a in refined.lattice.angles: self.assertEqual(a, 90) self.assertEqual(refined.lattice.a, refined.lattice.b) s = self.get_structure('Li2O') sg = SpacegroupAnalyzer(s, 0.001) self.assertEqual(sg.get_refined_structure().num_sites, 4 * s.num_sites) def test_get_symmetrized_structure(self): symm_struct = self.sg.get_symmetrized_structure() for a in symm_struct.lattice.angles: self.assertEqual(a, 90) self.assertEqual(len(symm_struct.equivalent_sites), 5) symm_struct = self.disordered_sg.get_symmetrized_structure() self.assertEqual(len(symm_struct.equivalent_sites), 8) self.assertEqual([len(i) for i in symm_struct.equivalent_sites], [16,4,8,4,2,8,8,8]) s1 = symm_struct.equivalent_sites[1][1] s2 = symm_struct[symm_struct.equivalent_indices[1][1]] self.assertEqual(s1, s2) self.assertEqual(self.sg4.get_symmetrized_structure()[0].magmom, 0.1) def test_find_primitive(self): """ F m -3 m Li2O testing of converting to primitive cell """ parser = CifParser(os.path.join(test_dir, 'Li2O.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive() self.assertEqual(primitive_structure.formula, "Li2 O1") # This isn't what is expected. All the angles should be 60 self.assertAlmostEqual(primitive_structure.lattice.alpha, 60) self.assertAlmostEqual(primitive_structure.lattice.beta, 60) self.assertAlmostEqual(primitive_structure.lattice.gamma, 60) self.assertAlmostEqual(primitive_structure.lattice.volume, structure.lattice.volume / 4.0) def test_get_ir_reciprocal_mesh(self): grid=self.sg.get_ir_reciprocal_mesh() self.assertEqual(len(grid), 216) self.assertAlmostEquals(grid[1][0][0], 0.1) self.assertAlmostEquals(grid[1][0][1], 0.0) self.assertAlmostEquals(grid[1][0][2], 0.0) self.assertEqual(grid[1][1], 2) def test_get_conventional_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.b, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.c, 9.1980270633769461) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.b, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.c, 4.2327080177761687) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 2.9542233922299999) self.assertAlmostEqual(conv.lattice.b, 4.6330325651443296) self.assertAlmostEqual(conv.lattice.c, 5.373703587040775) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 4.1430033493799998) self.assertAlmostEqual(conv.lattice.b, 31.437979757624728) self.assertAlmostEqual(conv.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 117.53832420192903) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 14.033435583000625) self.assertAlmostEqual(conv.lattice.b, 3.96052850731) self.assertAlmostEqual(conv.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'hex_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 120) self.assertAlmostEqual(conv.lattice.a, 3.699919902005897) self.assertAlmostEqual(conv.lattice.b, 3.699919902005897) self.assertAlmostEqual(conv.lattice.c, 6.9779585500000003) def test_get_primitive_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 109.47122063400001) self.assertAlmostEqual(prim.lattice.beta, 109.47122063400001) self.assertAlmostEqual(prim.lattice.gamma, 109.47122063400001) self.assertAlmostEqual(prim.lattice.a, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.b, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.c, 7.9657251015812145) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 105.015053349) self.assertAlmostEqual(prim.lattice.beta, 105.015053349) self.assertAlmostEqual(prim.lattice.gamma, 118.80658411899999) self.assertAlmostEqual(prim.lattice.a, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.b, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.c, 4.1579321075608791) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 134.78923546600001) self.assertAlmostEqual(prim.lattice.beta, 105.856239333) self.assertAlmostEqual(prim.lattice.gamma, 91.276341676000001) self.assertAlmostEqual(prim.lattice.a, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.b, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.c, 3.8428217771014852) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 164.985257335) self.assertAlmostEqual(prim.lattice.a, 15.854897098324196) self.assertAlmostEqual(prim.lattice.b, 15.854897098324196) self.assertAlmostEqual(prim.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 63.579155761999999) self.assertAlmostEqual(prim.lattice.beta, 116.42084423747779) self.assertAlmostEqual(prim.lattice.gamma, 148.47965136208569) self.assertAlmostEqual(prim.lattice.a, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.b, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'hex_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 120) self.assertAlmostEqual(prim.lattice.a, 3.699919902005897) self.assertAlmostEqual(prim.lattice.b, 3.699919902005897) self.assertAlmostEqual(prim.lattice.c, 6.9779585500000003) parser = CifParser(os.path.join(test_dir, 'rhomb_3478_conv.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 28.049186140546812) self.assertAlmostEqual(prim.lattice.beta, 28.049186140546812) self.assertAlmostEqual(prim.lattice.gamma, 28.049186140546812) self.assertAlmostEqual(prim.lattice.a, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.b, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.c, 5.9352627428399982)
print("-d must be followed by an integer") exit(1) # read structure if os.path.exists(fstruct): struct = mg.Structure.from_file(fstruct) else: print("File %s does not exist" % fstruct) exit(1) # symmetry information struct_sym = SpacegroupAnalyzer(struct) print("\nLattice details:") print("----------------") print("lattice type : {0}".format(struct_sym.get_lattice_type())) print("space group : {0} ({1})".format(struct_sym.get_spacegroup_symbol(), struct_sym.get_spacegroup_number())) # Compute first brillouin zone ibz = HighSymmKpath(struct) print("ibz type : {0}".format(ibz.name)) ibz.get_kpath_plot(savefig="path.png") # print specific kpoints in the first brillouin zone print("\nList of high symmetry k-points:") print("-------------------------------") for key, val in ibz.kpath["kpoints"].items(): print("%8s %s" % (key, str(val))) # suggested path for the band structure print("\nSuggested paths in first brillouin zone:")
def _gen_input_file(self): """ Generate the necessary struct_enum.in file for enumlib. See enumlib documentation for details. """ coord_format = "{:.6f} {:.6f} {:.6f}" # Using symmetry finder, get the symmetrically distinct sites. fitter = SpacegroupAnalyzer(self.structure, self.symm_prec) symmetrized_structure = fitter.get_symmetrized_structure() logger.debug("Spacegroup {} ({}) with {} distinct sites".format( fitter.get_spacegroup_symbol(), fitter.get_spacegroup_number(), len(symmetrized_structure.equivalent_sites))) """ Enumlib doesn"t work when the number of species get too large. To simplify matters, we generate the input file only with disordered sites and exclude the ordered sites from the enumeration. The fact that different disordered sites with the exact same species may belong to different equivalent sites is dealt with by having determined the spacegroup earlier and labelling the species differently. """ # index_species and index_amounts store mappings between the indices # used in the enum input file, and the actual species and amounts. index_species = [] index_amounts = [] #Stores the ordered sites, which are not enumerated. ordered_sites = [] disordered_sites = [] coord_str = [] for sites in symmetrized_structure.equivalent_sites: if sites[0].is_ordered: ordered_sites.append(sites) else: sp_label = [] species = {k: v for k, v in sites[0].species_and_occu.items()} if sum(species.values()) < 1 - EnumlibAdaptor.amount_tol: #Let us first make add a dummy element for every single #site whose total occupancies don't sum to 1. species[DummySpecie("X")] = 1 - sum(species.values()) for sp in species.keys(): if sp not in index_species: index_species.append(sp) sp_label.append(len(index_species) - 1) index_amounts.append(species[sp] * len(sites)) else: ind = index_species.index(sp) sp_label.append(ind) index_amounts[ind] += species[sp] * len(sites) sp_label = "/".join(["{}".format(i) for i in sorted(sp_label)]) for site in sites: coord_str.append("{} {}".format( coord_format.format(*site.coords), sp_label)) disordered_sites.append(sites) def get_sg_info(ss): finder = SpacegroupAnalyzer(Structure.from_sites(ss), self.symm_prec) sgnum = finder.get_spacegroup_number() return sgnum curr_sites = list(itertools.chain.from_iterable(disordered_sites)) min_sgnum = get_sg_info(curr_sites) logger.debug("Disorderd sites has sgnum %d" % (min_sgnum)) #It could be that some of the ordered sites has a lower symmetry than #the disordered sites. So we consider the lowest symmetry sites as #disordered in our enumeration. self.ordered_sites = [] to_add = [] if self.check_ordered_symmetry: for sites in ordered_sites: temp_sites = list(curr_sites) + sites sgnum = get_sg_info(temp_sites) if sgnum < min_sgnum: logger.debug("Adding {} to sites to be ordered. " "New sgnum {}".format(sites, sgnum)) to_add = sites min_sgnum = sgnum for sites in ordered_sites: if sites == to_add: index_species.append(sites[0].specie) index_amounts.append(len(sites)) sp_label = len(index_species) - 1 logger.debug( "Lowest symmetry {} sites are included in enum.".format( sites[0].specie)) for site in sites: coord_str.append("{} {}".format( coord_format.format(*site.coords), sp_label)) disordered_sites.append(sites) else: self.ordered_sites.extend(sites) self.index_species = index_species lattice = self.structure.lattice output = [self.structure.formula, "bulk"] for vec in lattice.matrix: output.append(coord_format.format(*vec)) output.append("{}".format(len(index_species))) output.append("{}".format(len(coord_str))) output.extend(coord_str) output.append("{} {}".format(self.min_cell_size, self.max_cell_size)) output.append(str(self.enum_precision_parameter)) output.append("partial") ndisordered = sum([len(s) for s in disordered_sites]) base = ndisordered #10 ** int(math.ceil(math.log10(ndisordered))) #To get a reasonable number of structures, we fix concentrations to the #range expected in the original structure. total_amounts = sum(index_amounts) for amt in index_amounts: conc = amt / total_amounts if abs(conc * base - round(conc * base)) < 1e-5: output.append("{} {} {}".format(int(round(conc * base)), int(round(conc * base)), base)) else: min_conc = int(math.floor(conc * base)) output.append("{} {} {}".format(min_conc - 1, min_conc + 1, base)) output.append("") logger.debug("Generated input file:\n{}".format("\n".join(output))) with open("struct_enum.in", "w") as f: f.write("\n".join(output))
def generate_doc(self, dir_name, vasprun_files): """ Process aflow style runs, where each run is actually a combination of two vasp runs. """ try: fullpath = os.path.abspath(dir_name) #Defensively copy the additional fields first. This is a MUST. #Otherwise, parallel updates will see the same object and inserts #will be overridden!! d = {k: v for k, v in self.additional_fields.items()} d["dir_name"] = fullpath d["schema_version"] = VaspToDbTaskDrone.__version__ d["calculations"] = [ self.process_vasprun(dir_name, taskname, filename) for taskname, filename in vasprun_files.items()] d1 = d["calculations"][0] d2 = d["calculations"][-1] #Now map some useful info to the root level. for root_key in ["completed_at", "nsites", "unit_cell_formula", "reduced_cell_formula", "pretty_formula", "elements", "nelements", "cif", "density", "is_hubbard", "hubbards", "run_type"]: d[root_key] = d2[root_key] d["chemsys"] = "-".join(sorted(d2["elements"])) #store any overrides to the exchange correlation functional xc = d2["input"]["incar"].get("GGA") if xc: xc = xc.upper() d["input"] = {"crystal": d1["input"]["crystal"], "is_lasph": d2["input"]["incar"].get("LASPH", False), "potcar_spec": d1["input"].get("potcar_spec"), "xc_override": xc} vals = sorted(d2["reduced_cell_formula"].values()) d["anonymous_formula"] = {string.ascii_uppercase[i]: float(vals[i]) for i in range(len(vals))} d["output"] = { "crystal": d2["output"]["crystal"], "final_energy": d2["output"]["final_energy"], "final_energy_per_atom": d2["output"]["final_energy_per_atom"]} d["name"] = "aflow" p = d2["input"]["potcar_type"][0].split("_") pot_type = p[0] functional = "lda" if len(pot_type) == 1 else "_".join(p[1:]) d["pseudo_potential"] = {"functional": functional.lower(), "pot_type": pot_type.lower(), "labels": d2["input"]["potcar"]} if len(d["calculations"]) == len(self.runs) or \ list(vasprun_files.keys())[0] != "relax1": d["state"] = "successful" if d2["has_vasp_completed"] \ else "unsuccessful" else: d["state"] = "stopped" d["analysis"] = get_basic_analysis_and_error_checks(d) sg = SpacegroupAnalyzer(Structure.from_dict(d["output"]["crystal"]), 0.1) d["spacegroup"] = {"symbol": sg.get_spacegroup_symbol(), "number": sg.get_spacegroup_number(), "point_group": sg.get_point_group(), "source": "spglib", "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall()} d["last_updated"] = datetime.datetime.today() return d except Exception as ex: import traceback print(traceback.format_exc()) logger.error("Error in " + os.path.abspath(dir_name) + ".\n" + traceback.format_exc()) return None
def __init__(self, struct, find_spacegroup=False, symprec=None): """ Args: struct (Structure): structure to write find_spacegroup (bool): whether to try to determine the spacegroup symprec (float): If not none, finds the symmetry of the structure and writes the cif with symmetry information. Passes symprec to the SpacegroupAnalyzer """ format_str = "{:.8f}" block = OrderedDict() loops = [] latt = struct.lattice comp = struct.composition no_oxi_comp = comp.element_composition spacegroup = ("P 1", 1) if find_spacegroup: sf = SpacegroupAnalyzer(struct, 0.001) spacegroup = (sf.get_spacegroup_symbol(), sf.get_spacegroup_number()) block["_symmetry_space_group_name_H-M"] = spacegroup[0] for cell_attr in ['a', 'b', 'c']: block["_cell_length_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) for cell_attr in ['alpha', 'beta', 'gamma']: block["_cell_angle_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) block["_symmetry_Int_Tables_number"] = spacegroup[1] block["_chemical_formula_structural"] = no_oxi_comp.reduced_formula block["_chemical_formula_sum"] = no_oxi_comp.formula block["_cell_volume"] = latt.volume.__str__() reduced_comp = no_oxi_comp.reduced_composition el = no_oxi_comp.elements[0] amt = comp[el] fu = int(amt / reduced_comp[Element(el.symbol)]) block["_cell_formula_units_Z"] = str(fu) if symprec is None: block["_symmetry_equiv_pos_site_id"] = ["1"] block["_symmetry_equiv_pos_as_xyz"] = ["x, y, z"] else: sf = SpacegroupAnalyzer(struct, symprec) ops = [op.as_xyz_string() for op in sf.get_symmetry_operations()] block["_symmetry_equiv_pos_site_id"] = \ ["%d" % i for i in range(1, len(ops) + 1)] block["_symmetry_equiv_pos_as_xyz"] = ops loops.append( ["_symmetry_equiv_pos_site_id", "_symmetry_equiv_pos_as_xyz"]) contains_oxidation = True try: symbol_to_oxinum = OrderedDict([(el.__str__(), float(el.oxi_state)) for el in sorted(comp.elements)]) except AttributeError: symbol_to_oxinum = OrderedDict([(el.symbol, 0) for el in sorted(comp.elements)]) contains_oxidation = False if contains_oxidation: block["_atom_type_symbol"] = symbol_to_oxinum.keys() block["_atom_type_oxidation_number"] = symbol_to_oxinum.values() loops.append(["_atom_type_symbol", "_atom_type_oxidation_number"]) atom_site_type_symbol = [] atom_site_symmetry_multiplicity = [] atom_site_fract_x = [] atom_site_fract_y = [] atom_site_fract_z = [] atom_site_label = [] atom_site_occupancy = [] count = 1 if symprec is None: for site in struct: for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("1") atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 else: for group in sf.get_symmetrized_structure().equivalent_sites: site = group[0] for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("%d" % len(group)) atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 block["_atom_site_type_symbol"] = atom_site_type_symbol block["_atom_site_label"] = atom_site_label block["_atom_site_symmetry_multiplicity"] = \ atom_site_symmetry_multiplicity block["_atom_site_fract_x"] = atom_site_fract_x block["_atom_site_fract_y"] = atom_site_fract_y block["_atom_site_fract_z"] = atom_site_fract_z block["_atom_site_occupancy"] = atom_site_occupancy loops.append([ "_atom_site_type_symbol", "_atom_site_label", "_atom_site_symmetry_multiplicity", "_atom_site_fract_x", "_atom_site_fract_y", "_atom_site_fract_z", "_atom_site_occupancy" ]) d = OrderedDict() d[comp.reduced_formula] = CifBlock(block, loops, comp.reduced_formula) self._cf = CifFile(d)
parser.add_argument('POSCAR', action='store' ,type=str, help="POSCAR is the name of the input file in VASP5 format") parser.add_argument('tol', type=float, help='the tolerance for analysing space group. A number less than 0.05 is recommended.') parser.add_argument('npoints', type=int, help='the number of sampling points. Usually 50 is proper') parser.add_argument('type', type=int, help='this number determine the type of output: 0 for phonon and 1 for electronic band structure calculations should be used.') args=parser.parse_args() #************************************************************ tol = args.tol np = args.npoints tp = args.type keyword = ['phonon band','output band'] #structure = read_structure(file) structure = mg.Structure.from_file("POSCAR") #str(open("rlx_str040.cif").read(),fmt="cif") #str(open("POSCAR").read(),fmt="poscar") #from pymatgen.symmetry.finder import SymmetryFinder #symmetries = SymmetryFinder(structure, 0.001, 5) finder = SpacegroupAnalyzer(structure,symprec=tol,angle_tolerance=5) spg_s = finder.get_spacegroup_symbol() spg_n = finder.get_spacegroup_number() pg = finder.get_point_group() pm =finder.find_primitive() #print "Spacegroup : ", spg_s print "SPG (Int number) : ", spg_n #print "pointgroup : ", pg pather = HighSymmKpath(structure,symprec=tol, angle_tolerance=5) kpoints_path=pather.kpath kk=kpoints_path["kpoints"] pp=kpoints_path["path"] count=1 #pp[1]=['K','X'] #print pp
class HighSymmKpath(object): """ This class looks for path along high symmetry lines in the Brillouin Zone. It is based on Setyawan, W., & Curtarolo, S. (2010). High-throughput electronic band structure calculations: Challenges and tools. Computational Materials Science, 49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010 The symmetry is determined by spglib through the SpacegroupAnalyzer class Args: structure (Structure): Structure object symprec (float): Tolerance for symmetry finding angle_tolerance (float): Angle tolerance for symmetry finding. """ def __init__(self, structure, symprec=0.01, angle_tolerance=5): self._structure = structure self._sym = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance) self._prim = self._sym\ .get_primitive_standard_structure(international_monoclinic=False) self._conv = self._sym.get_conventional_standard_structure( international_monoclinic=False) self._prim_rec = self._prim.lattice.reciprocal_lattice self._kpath = None lattice_type = self._sym.get_lattice_type() spg_symbol = self._sym.get_spacegroup_symbol() if lattice_type == "cubic": if "P" in spg_symbol: self._kpath = self.cubic() elif "F" in spg_symbol: self._kpath = self.fcc() elif "I" in spg_symbol: self._kpath = self.bcc() else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "tetragonal": if "P" in spg_symbol: self._kpath = self.tet() elif "I" in spg_symbol: a = self._conv.lattice.abc[0] c = self._conv.lattice.abc[2] if c < a: self._kpath = self.bctet1(c, a) else: self._kpath = self.bctet2(c, a) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "orthorhombic": a = self._conv.lattice.abc[0] b = self._conv.lattice.abc[1] c = self._conv.lattice.abc[2] if "P" in spg_symbol: self._kpath = self.orc() elif "F" in spg_symbol: if 1 / a**2 > 1 / b**2 + 1 / c**2: self._kpath = self.orcf1(a, b, c) elif 1 / a**2 < 1 / b**2 + 1 / c**2: self._kpath = self.orcf2(a, b, c) else: self._kpath = self.orcf3(a, b, c) elif "I" in spg_symbol: self._kpath = self.orci(a, b, c) elif "C" in spg_symbol: self._kpath = self.orcc(a, b, c) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "hexagonal": self._kpath = self.hex() elif lattice_type == "rhombohedral": alpha = self._prim.lattice.lengths_and_angles[1][0] if alpha < 90: self._kpath = self.rhl1(alpha * pi / 180) else: self._kpath = self.rhl2(alpha * pi / 180) elif lattice_type == "monoclinic": a, b, c = self._conv.lattice.abc alpha = self._conv.lattice.lengths_and_angles[1][0] #beta = self._conv.lattice.lengths_and_angles[1][1] if "P" in spg_symbol: self._kpath = self.mcl(b, c, alpha * pi / 180) elif "C" in spg_symbol: kgamma = self._prim_rec.lengths_and_angles[1][2] if kgamma > 90: self._kpath = self.mclc1(a, b, c, alpha * pi / 180) if kgamma == 90: self._kpath = self.mclc2(a, b, c, alpha * pi / 180) if kgamma < 90: if b * cos(alpha * pi / 180) / c\ + b ** 2 * sin(alpha) ** 2 / a ** 2 < 1: self._kpath = self.mclc3(a, b, c, alpha * pi / 180) if b * cos(alpha * pi / 180) / c \ + b ** 2 * sin(alpha) ** 2 / a ** 2 == 1: self._kpath = self.mclc4(a, b, c, alpha * pi / 180) if b * cos(alpha * pi / 180) / c \ + b ** 2 * sin(alpha) ** 2 / a ** 2 > 1: self._kpath = self.mclc5(a, b, c, alpha * pi / 180) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "triclinic": kalpha = self._prim_rec.lengths_and_angles[1][0] kbeta = self._prim_rec.lengths_and_angles[1][1] kgamma = self._prim_rec.lengths_and_angles[1][2] if kalpha > 90 and kbeta > 90 and kgamma > 90: self._kpath = self.tria() if kalpha < 90 and kbeta < 90 and kgamma < 90: self._kpath = self.trib() if kalpha > 90 and kbeta > 90 and kgamma == 90: self._kpath = self.tria() if kalpha < 90 and kbeta < 90 and kgamma == 90: self._kpath = self.trib() else: warn("Unknown lattice type %s" % lattice_type) @property def structure(self): """ Returns: The standardized primitive structure """ return self._prim @property def kpath(self): """ Returns: The symmetry line path in reciprocal space """ return self._kpath def get_kpoints(self, line_density=20, coords_are_cartesian=True): """ Returns: the kpoints along the paths in cartesian coordinates together with the labels for symmetry points -Wei """ list_k_points = [] sym_point_labels = [] for b in self.kpath['path']: for i in range(1, len(b)): start = np.array(self.kpath['kpoints'][b[i - 1]]) end = np.array(self.kpath['kpoints'][b[i]]) distance = np.linalg.norm( self._prim_rec.get_cartesian_coords(start) - self._prim_rec.get_cartesian_coords(end)) nb = int(ceil(distance * line_density)) sym_point_labels.extend([b[i - 1]] + [''] * (nb - 1) + [b[i]]) list_k_points.extend([ self._prim_rec.get_cartesian_coords(start) + float(i) / float(nb) * (self._prim_rec.get_cartesian_coords(end) - self._prim_rec.get_cartesian_coords(start)) for i in range(0, nb + 1) ]) if coords_are_cartesian: return list_k_points, sym_point_labels else: frac_k_points = [ self._prim_rec.get_fractional_coords(k) for k in list_k_points ] return frac_k_points, sym_point_labels def get_kpath_plot(self, **kwargs): """ Gives the plot (as a matplotlib object) of the symmetry line path in the Brillouin Zone. Returns: `matplotlib` figure. ================ ============================================================== kwargs Meaning ================ ============================================================== show True to show the figure (Default). savefig 'abc.png' or 'abc.eps'* to save the figure to a file. ================ ============================================================== """ import itertools import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import axes3d def _plot_shape_skeleton(bz, style): for iface in range(len(bz)): for line in itertools.combinations(bz[iface], 2): for jface in range(len(bz)): if iface < jface and line[0] in bz[jface]\ and line[1] in bz[jface]: ax.plot([line[0][0], line[1][0]], [line[0][1], line[1][1]], [line[0][2], line[1][2]], style) def _plot_lattice(lattice): vertex1 = lattice.get_cartesian_coords([0.0, 0.0, 0.0]) vertex2 = lattice.get_cartesian_coords([1.0, 0.0, 0.0]) ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]], [vertex1[2], vertex2[2]], color='g', linewidth=3) vertex2 = lattice.get_cartesian_coords([0.0, 1.0, 0.0]) ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]], [vertex1[2], vertex2[2]], color='g', linewidth=3) vertex2 = lattice.get_cartesian_coords([0.0, 0.0, 1.0]) ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]], [vertex1[2], vertex2[2]], color='g', linewidth=3) def _plot_kpath(kpath, lattice): for line in kpath['path']: for k in range(len(line) - 1): vertex1 = lattice.get_cartesian_coords( kpath['kpoints'][line[k]]) vertex2 = lattice.get_cartesian_coords( kpath['kpoints'][line[k + 1]]) ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]], [vertex1[2], vertex2[2]], color='r', linewidth=3) def _plot_labels(kpath, lattice): for k in kpath['kpoints']: label = k if k.startswith("\\") or k.find("_") != -1: label = "$" + k + "$" off = 0.01 ax.text( lattice.get_cartesian_coords(kpath['kpoints'][k])[0] + off, lattice.get_cartesian_coords(kpath['kpoints'][k])[1] + off, lattice.get_cartesian_coords(kpath['kpoints'][k])[2] + off, label, color='b', size='25') ax.scatter( [lattice.get_cartesian_coords(kpath['kpoints'][k])[0]], [lattice.get_cartesian_coords(kpath['kpoints'][k])[1]], [lattice.get_cartesian_coords(kpath['kpoints'][k])[2]], color='b') fig = plt.figure() ax = axes3d.Axes3D(fig) _plot_lattice(self._prim_rec) _plot_shape_skeleton(self._prim_rec.get_wigner_seitz_cell(), '-k') _plot_kpath(self.kpath, self._prim_rec) _plot_labels(self.kpath, self._prim_rec) ax.axis("off") show = kwargs.pop("show", True) if show: plt.show() savefig = kwargs.pop("savefig", None) if savefig: fig.savefig(savefig) return fig def cubic(self): self.name = "CUB" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'X': np.array([0.0, 0.5, 0.0]), 'R': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.5, 0.0]) } path = [["\Gamma", "X", "M", "\Gamma", "R", "X"], ["M", "R"]] return {'kpoints': kpoints, 'path': path} def fcc(self): self.name = "FCC" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'K': np.array([3.0 / 8.0, 3.0 / 8.0, 3.0 / 4.0]), 'L': np.array([0.5, 0.5, 0.5]), 'U': np.array([5.0 / 8.0, 1.0 / 4.0, 5.0 / 8.0]), 'W': np.array([0.5, 1.0 / 4.0, 3.0 / 4.0]), 'X': np.array([0.5, 0.0, 0.5]) } path = [["\Gamma", "X", "W", "K", "\Gamma", "L", "U", "W", "L", "K"], ["U", "X"]] return {'kpoints': kpoints, 'path': path} def bcc(self): self.name = "BCC" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'H': np.array([0.5, -0.5, 0.5]), 'P': np.array([0.25, 0.25, 0.25]), 'N': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "H", "N", "\Gamma", "P", "H"], ["P", "N"]] return {'kpoints': kpoints, 'path': path} def tet(self): self.name = "TET" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.5, 0.0]), 'R': np.array([0.0, 0.5, 0.5]), 'X': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "X", "M", "\Gamma", "Z", "R", "A", "Z"], ["X", "R"], ["M", "A"]] return {'kpoints': kpoints, 'path': path} def bctet1(self, c, a): self.name = "BCT1" eta = (1 + c**2 / a**2) / 4.0 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'M': np.array([-0.5, 0.5, 0.5]), 'N': np.array([0.0, 0.5, 0.0]), 'P': np.array([0.25, 0.25, 0.25]), 'X': np.array([0.0, 0.0, 0.5]), 'Z': np.array([eta, eta, -eta]), 'Z_1': np.array([-eta, 1 - eta, eta]) } path = [["\Gamma", "X", "M", "\Gamma", "Z", "P", "N", "Z_1", "M"], ["X", "P"]] return {'kpoints': kpoints, 'path': path} def bctet2(self, c, a): self.name = "BCT2" eta = (1 + a**2 / c**2) / 4.0 zeta = a**2 / (2 * c**2) kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.0, 0.5, 0.0]), 'P': np.array([0.25, 0.25, 0.25]), '\Sigma': np.array([-eta, eta, eta]), '\Sigma_1': np.array([eta, 1 - eta, -eta]), 'X': np.array([0.0, 0.0, 0.5]), 'Y': np.array([-zeta, zeta, 0.5]), 'Y_1': np.array([0.5, 0.5, -zeta]), 'Z': np.array([0.5, 0.5, -0.5]) } path = [[ "\Gamma", "X", "Y", "\Sigma", "\Gamma", "Z", "\Sigma_1", "N", "P", "Y_1", "Z" ], ["X", "P"]] return {'kpoints': kpoints, 'path': path} def orc(self): self.name = "ORC" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'R': np.array([0.5, 0.5, 0.5]), 'S': np.array([0.5, 0.5, 0.0]), 'T': np.array([0.0, 0.5, 0.5]), 'U': np.array([0.5, 0.0, 0.5]), 'X': np.array([0.5, 0.0, 0.0]), 'Y': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "X", "S", "Y", "\Gamma", "Z", "U", "R", "T", "Z"], ["Y", "T"], ["U", "X"], ["S", "R"]] return {'kpoints': kpoints, 'path': path} def orcf1(self, a, b, c): self.name = "ORCF1" zeta = (1 + a**2 / b**2 - a**2 / c**2) / 4 eta = (1 + a**2 / b**2 + a**2 / c**2) / 4 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5 + zeta, zeta]), 'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]), 'L': np.array([0.5, 0.5, 0.5]), 'T': np.array([1, 0.5, 0.5]), 'X': np.array([0.0, eta, eta]), 'X_1': np.array([1, 1 - eta, 1 - eta]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0]) } path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"], ["T", "X_1"], ["X", "A", "Z"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orcf2(self, a, b, c): self.name = "ORCF2" phi = (1 + c**2 / b**2 - c**2 / a**2) / 4 eta = (1 + a**2 / b**2 - a**2 / c**2) / 4 delta = (1 + b**2 / a**2 - b**2 / c**2) / 4 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'C': np.array([0.5, 0.5 - eta, 1 - eta]), 'C_1': np.array([0.5, 0.5 + eta, eta]), 'D': np.array([0.5 - delta, 0.5, 1 - delta]), 'D_1': np.array([0.5 + delta, 0.5, delta]), 'L': np.array([0.5, 0.5, 0.5]), 'H': np.array([1 - phi, 0.5 - phi, 0.5]), 'H_1': np.array([phi, 0.5 + phi, 0.5]), 'X': np.array([0.0, 0.5, 0.5]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0]) } path = [["\Gamma", "Y", "C", "D", "X", "\Gamma", "Z", "D_1", "H", "C"], ["C_1", "Z"], ["X", "H_1"], ["H", "Y"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orcf3(self, a, b, c): self.name = "ORCF3" zeta = (1 + a**2 / b**2 - a**2 / c**2) / 4 eta = (1 + a**2 / b**2 + a**2 / c**2) / 4 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5 + zeta, zeta]), 'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]), 'L': np.array([0.5, 0.5, 0.5]), 'T': np.array([1, 0.5, 0.5]), 'X': np.array([0.0, eta, eta]), 'X_1': np.array([1, 1 - eta, 1 - eta]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0]) } path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"], ["X", "A", "Z"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orci(self, a, b, c): self.name = "ORCI" zeta = (1 + a**2 / c**2) / 4 eta = (1 + b**2 / c**2) / 4 delta = (b**2 - a**2) / (4 * c**2) mu = (a**2 + b**2) / (4 * c**2) kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([-mu, mu, 0.5 - delta]), 'L_1': np.array([mu, -mu, 0.5 + delta]), 'L_2': np.array([0.5 - delta, 0.5 + delta, -mu]), 'R': np.array([0.0, 0.5, 0.0]), 'S': np.array([0.5, 0.0, 0.0]), 'T': np.array([0.0, 0.0, 0.5]), 'W': np.array([0.25, 0.25, 0.25]), 'X': np.array([-zeta, zeta, zeta]), 'X_1': np.array([zeta, 1 - zeta, -zeta]), 'Y': np.array([eta, -eta, eta]), 'Y_1': np.array([1 - eta, eta, -eta]), 'Z': np.array([0.5, 0.5, -0.5]) } path = [[ "\Gamma", "X", "L", "T", "W", "R", "X_1", "Z", "\Gamma", "Y", "S", "W" ], ["L_1", "Y"], ["Y_1", "Z"]] return {'kpoints': kpoints, 'path': path} def orcc(self, a, b, c): self.name = "ORCC" zeta = (1 + a**2 / b**2) / 4 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([zeta, zeta, 0.5]), 'A_1': np.array([-zeta, 1 - zeta, 0.5]), 'R': np.array([0.0, 0.5, 0.5]), 'S': np.array([0.0, 0.5, 0.0]), 'T': np.array([-0.5, 0.5, 0.5]), 'X': np.array([zeta, zeta, 0.0]), 'X_1': np.array([-zeta, 1 - zeta, 0.0]), 'Y': np.array([-0.5, 0.5, 0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [[ "\Gamma", "X", "S", "R", "A", "Z", "\Gamma", "Y", "X_1", "A_1", "T", "Y" ], ["Z", "T"]] return {'kpoints': kpoints, 'path': path} def hex(self): self.name = "HEX" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.0, 0.0, 0.5]), 'H': np.array([1.0 / 3.0, 1.0 / 3.0, 0.5]), 'K': np.array([1.0 / 3.0, 1.0 / 3.0, 0.0]), 'L': np.array([0.5, 0.0, 0.5]), 'M': np.array([0.5, 0.0, 0.0]) } path = [["\Gamma", "M", "K", "\Gamma", "A", "L", "H", "A"], ["L", "M"], ["K", "H"]] return {'kpoints': kpoints, 'path': path} def rhl1(self, alpha): self.name = "RHL1" eta = (1 + 4 * cos(alpha)) / (2 + 4 * cos(alpha)) nu = 3.0 / 4.0 - eta / 2.0 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'B': np.array([eta, 0.5, 1.0 - eta]), 'B_1': np.array([1.0 / 2.0, 1.0 - eta, eta - 1.0]), 'F': np.array([0.5, 0.5, 0.0]), 'L': np.array([0.5, 0.0, 0.0]), 'L_1': np.array([0.0, 0.0, -0.5]), 'P': np.array([eta, nu, nu]), 'P_1': np.array([1.0 - nu, 1.0 - nu, 1.0 - eta]), 'P_2': np.array([nu, nu, eta - 1.0]), 'Q': np.array([1.0 - nu, nu, 0.0]), 'X': np.array([nu, 0.0, -nu]), 'Z': np.array([0.5, 0.5, 0.5]) } path = [["\Gamma", "L", "B_1"], ["B", "Z", "\Gamma", "X"], ["Q", "F", "P_1", "Z"], ["L", "P"]] return {'kpoints': kpoints, 'path': path} def rhl2(self, alpha): self.name = "RHL2" eta = 1 / (2 * tan(alpha / 2.0)**2) nu = 3.0 / 4.0 - eta / 2.0 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([0.5, -0.5, 0.0]), 'L': np.array([0.5, 0.0, 0.0]), 'P': np.array([1 - nu, -nu, 1 - nu]), 'P_1': np.array([nu, nu - 1.0, nu - 1.0]), 'Q': np.array([eta, eta, eta]), 'Q_1': np.array([1.0 - eta, -eta, -eta]), 'Z': np.array([0.5, -0.5, 0.5]) } path = [[ "\Gamma", "P", "Z", "Q", "\Gamma", "F", "P_1", "Q_1", "L", "Z" ]] return {'kpoints': kpoints, 'path': path} def mcl(self, b, c, beta): self.name = "MCL" eta = (1 - b * cos(beta) / c) / (2 * sin(beta)**2) nu = 0.5 - eta * c * cos(beta) / b kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5, 0.0]), 'C': np.array([0.0, 0.5, 0.5]), 'D': np.array([0.5, 0.0, 0.5]), 'D_1': np.array([0.5, 0.5, -0.5]), 'E': np.array([0.5, 0.5, 0.5]), 'H': np.array([0.0, eta, 1.0 - nu]), 'H_1': np.array([0.0, 1.0 - eta, nu]), 'H_2': np.array([0.0, eta, -nu]), 'M': np.array([0.5, eta, 1.0 - nu]), 'M_1': np.array([0.5, 1 - eta, nu]), 'M_2': np.array([0.5, 1 - eta, nu]), 'X': np.array([0.0, 0.5, 0.0]), 'Y': np.array([0.0, 0.0, 0.5]), 'Y_1': np.array([0.0, 0.0, -0.5]), 'Z': np.array([0.5, 0.0, 0.0]) } path = [["\Gamma", "Y", "H", "C", "E", "M_1", "A", "X", "H_1"], ["M", "D", "Z"], ["Y", "D"]] return {'kpoints': kpoints, 'path': path} def mclc1(self, a, b, c, alpha): self.name = "MCLC1" zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha)**2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b psi = 0.75 - a**2 / (4 * b**2 * sin(alpha)**2) phi = psi + (0.75 - psi) * b * cos(alpha) / c kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'F': np.array([1 - zeta, 1 - zeta, 1 - eta]), 'F_1': np.array([zeta, zeta, eta]), 'F_2': np.array([-zeta, -zeta, 1 - eta]), #'F_3': np.array([1 - zeta, -zeta, 1 - eta]), 'I': np.array([phi, 1 - phi, 0.5]), 'I_1': np.array([1 - phi, phi - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'X': np.array([1 - psi, psi - 1, 0.0]), 'X_1': np.array([psi, 1 - psi, 0.0]), 'X_2': np.array([psi - 1, -psi, 0.0]), 'Y': np.array([0.5, 0.5, 0.0]), 'Y_1': np.array([-0.5, -0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"], ["Y", "X_1"], ["X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc2(self, a, b, c, alpha): self.name = "MCLC2" zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha)**2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b psi = 0.75 - a**2 / (4 * b**2 * sin(alpha)**2) phi = psi + (0.75 - psi) * b * cos(alpha) / c kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'F': np.array([1 - zeta, 1 - zeta, 1 - eta]), 'F_1': np.array([zeta, zeta, eta]), 'F_2': np.array([-zeta, -zeta, 1 - eta]), 'F_3': np.array([1 - zeta, -zeta, 1 - eta]), 'I': np.array([phi, 1 - phi, 0.5]), 'I_1': np.array([1 - phi, phi - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'X': np.array([1 - psi, psi - 1, 0.0]), 'X_1': np.array([psi, 1 - psi, 0.0]), 'X_2': np.array([psi - 1, -psi, 0.0]), 'Y': np.array([0.5, 0.5, 0.0]), 'Y_1': np.array([-0.5, -0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"], ["N", "\Gamma", "M"]] return {'kpoints': kpoints, 'path': path} def mclc3(self, a, b, c, alpha): self.name = "MCLC3" mu = (1 + b**2 / a**2) / 4.0 delta = b * c * cos(alpha) / (2 * a**2) zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\ / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b phi = 1 + zeta - 2 * mu psi = eta - 2 * delta kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([1 - phi, 1 - phi, 1 - psi]), 'F_1': np.array([phi, phi - 1, psi]), 'F_2': np.array([1 - phi, -phi, 1 - psi]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([0.5, -0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "H", "Z", "I", "F_1"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc4(self, a, b, c, alpha): self.name = "MCLC4" mu = (1 + b**2 / a**2) / 4.0 delta = b * c * cos(alpha) / (2 * a**2) zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\ / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b phi = 1 + zeta - 2 * mu psi = eta - 2 * delta kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([1 - phi, 1 - phi, 1 - psi]), 'F_1': np.array([phi, phi - 1, psi]), 'F_2': np.array([1 - phi, -phi, 1 - psi]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([0.5, -0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "H", "Z", "I"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc5(self, a, b, c, alpha): self.name = "MCLC5" zeta = (b**2 / a**2 + (1 - b * cos(alpha) / c) / sin(alpha)**2) / 4 eta = 0.5 + 2 * zeta * c * cos(alpha) / b mu = eta / 2 + b ** 2 / (4 * a ** 2) \ - b * c * cos(alpha) / (2 * a ** 2) nu = 2 * mu - zeta rho = 1 - zeta * a**2 / b**2 omega = (4 * nu - 1 - b ** 2 * sin(alpha) ** 2 / a ** 2)\ * c / (2 * b * cos(alpha)) delta = zeta * c * cos(alpha) / b + omega / 2 - 0.25 kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([nu, nu, omega]), 'F_1': np.array([1 - nu, 1 - nu, 1 - omega]), 'F_2': np.array([nu, nu - 1, omega]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([rho, 1 - rho, 0.5]), 'I_1': np.array([1 - rho, rho - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "H", "F_1"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def tria(self): self.name = "TRI1a" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([0.5, 0.5, 0.0]), 'M': np.array([0.0, 0.5, 0.5]), 'N': np.array([0.5, 0.0, 0.5]), 'R': np.array([0.5, 0.5, 0.5]), 'X': np.array([0.5, 0.0, 0.0]), 'Y': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5]) } path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"], ["N", "\Gamma", "M"], ["R", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def trib(self): self.name = "TRI1b" kpoints = { '\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([0.5, -0.5, 0.0]), 'M': np.array([0.0, 0.0, 0.5]), 'N': np.array([-0.5, -0.5, 0.5]), 'R': np.array([0.0, -0.5, 0.5]), 'X': np.array([0.0, -0.5, 0.0]), 'Y': np.array([0.5, 0.0, 0.0]), 'Z': np.array([-0.5, 0.0, 0.5]) } path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"], ["N", "\Gamma", "M"], ["R", "\Gamma"]] return {'kpoints': kpoints, 'path': path}
def calc_shiftk(self, symprec=0.01, angle_tolerance=5): """ Find the values of shiftk and nshiftk appropriate for the sampling of the Brillouin zone. Returns Suggested value of shiftk .. note: When the primitive vectors of the lattice do NOT form a FCC or a BCC lattice, the usual (shifted) Monkhorst-Pack grids are formed by using nshiftk=1 and shiftk 0.5 0.5 0.5 . This is often the preferred k point sampling. For a non-shifted Monkhorst-Pack grid, use nshiftk=1 and shiftk 0.0 0.0 0.0 , but there is little reason to do that. 2) When the primitive vectors of the lattice form a FCC lattice, with rprim 0.0 0.5 0.5 0.5 0.0 0.5 0.5 0.5 0.0 the (very efficient) usual Monkhorst-Pack sampling will be generated by using nshiftk= 4 and shiftk 0.5 0.5 0.5 0.5 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.5 3) When the primitive vectors of the lattice form a BCC lattice, with rprim -0.5 0.5 0.5 0.5 -0.5 0.5 0.5 0.5 -0.5 the usual Monkhorst-Pack sampling will be generated by using nshiftk= 2 and shiftk 0.25 0.25 0.25 -0.25 -0.25 -0.25 However, the simple sampling nshiftk=1 and shiftk 0.5 0.5 0.5 is excellent. 4) For hexagonal lattices with hexagonal axes, e.g. rprim 1.0 0.0 0.0 -0.5 sqrt(3)/2 0.0 0.0 0.0 1.0 one can use nshiftk= 1 and shiftk 0.0 0.0 0.5 In rhombohedral axes, e.g. using angdeg 3*60., this corresponds to shiftk 0.5 0.5 0.5, to keep the shift along the symmetry axis. """ # Find lattice type. sym = SpacegroupAnalyzer(self, symprec=symprec, angle_tolerance=angle_tolerance) lattice_type = sym.get_lattice_type() spg_symbol = sym.get_spacegroup_symbol() # Generate the appropriate set of shifts. shiftk = None if lattice_type == "cubic": if "F" in spg_symbol: # FCC shiftk = [0.5, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5] elif "I" in spg_symbol: # BCC shiftk = [0.25, 0.25, 0.25, -0.25, -0.25, -0.25] #shiftk = [0.5, 0.5, 05]) elif lattice_type == "hexagonal": # Find the hexagonal axis and set the shift along it. for i, angle in enumerate(self.lattice.angles): if abs(angle - 120) < 1.0: j = (i + 1) % 3 k = (i + 2) % 3 hex_ax = [ax for ax in range(3) if ax not in [j,k]][0] break else: raise ValueError("Cannot find hexagonal axis") shiftk = [0.0, 0.0, 0.0] shiftk[hex_ax] = 0.5 if shiftk is None: # Use default value. shiftk = [0.5, 0.5, 0.5] return np.reshape(shiftk, (-1,3))
def generate_doc(self, dir_name, vasprun_files): """ Overridden """ try: fullpath = os.path.abspath(dir_name) d = {k: v for k, v in self.additional_fields.items()} d["dir_name"] = fullpath d["schema_version"] = VaspToDbTaskDrone.__version__ d["calculations"] = [ self.process_vasprun(dir_name, taskname, filename) for taskname, filename in vasprun_files.items() ] d1 = d["calculations"][0] d2 = d["calculations"][-1] # Now map some useful info to the root level. for root_key in [ "completed_at", "nsites", "unit_cell_formula", "reduced_cell_formula", "pretty_formula", "elements", "nelements", "cif", "density", "is_hubbard", "hubbards", "run_type" ]: d[root_key] = d2[root_key] d["chemsys"] = "-".join(sorted(d2["elements"])) # store any overrides to the exchange correlation functional xc = d2["input"]["incar"].get("GGA") if xc: xc = xc.upper() d["input"] = { "crystal": d1["input"]["crystal"], "is_lasph": d2["input"]["incar"].get("LASPH", False), "potcar_spec": d1["input"].get("potcar_spec"), "xc_override": xc } vals = sorted(d2["reduced_cell_formula"].values()) d["anonymous_formula"] = { string.ascii_uppercase[i]: float(vals[i]) for i in range(len(vals)) } d["output"] = { "crystal": d2["output"]["crystal"], "final_energy": d2["output"]["final_energy"], "final_energy_per_atom": d2["output"]["final_energy_per_atom"] } d["name"] = "vasp" p = d2["input"]["potcar_type"][0].split("_") pot_type = p[0] functional = "lda" if len(pot_type) == 1 else "_".join(p[1:]) d["pseudo_potential"] = { "functional": functional.lower(), "pot_type": pot_type.lower(), "labels": d2["input"]["potcar"] } if len(d["calculations"]) == len(self.runs) or \ list(vasprun_files.keys())[0] != "relax1": d["state"] = "successful" if d2["has_vasp_completed"] \ else "unsuccessful" else: d["state"] = "stopped" d["analysis"] = analysis_and_error_checks(d) sg = SpacegroupAnalyzer( Structure.from_dict(d["output"]["crystal"]), 0.1) d["spacegroup"] = { "symbol": sg.get_spacegroup_symbol(), "number": sg.get_spacegroup_number(), "point_group": sg.get_point_group(), "source": "spglib", "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall() } d["last_updated"] = datetime.datetime.today() return d except Exception as ex: import traceback print(traceback.format_exc()) logger.error("Error in " + os.path.abspath(dir_name) + ".\n" + traceback.format_exc()) return None
class HighSymmKpath(object): """ This class looks for path along high symmetry lines in the Brillouin Zone. It is based on Setyawan, W., & Curtarolo, S. (2010). High-throughput electronic band structure calculations: Challenges and tools. Computational Materials Science, 49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010 The symmetry is determined by spglib through the SpacegroupAnalyzer class Args: structure (Structure): Structure object symprec (float): Tolerance for symmetry finding angle_tolerance (float): Angle tolerance for symmetry finding. """ def __init__(self, structure, symprec=0.01, angle_tolerance=5): self._structure = structure self._sym = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance) self._prim = self._sym\ .get_primitive_standard_structure(international_monoclinic=False) self._conv = self._sym.get_conventional_standard_structure(international_monoclinic=False) self._prim_rec = self._prim.lattice.reciprocal_lattice self._kpath = None lattice_type = self._sym.get_lattice_type() spg_symbol = self._sym.get_spacegroup_symbol() if lattice_type == "cubic": if "P" in spg_symbol: self._kpath = self.cubic() elif "F" in spg_symbol: self._kpath = self.fcc() elif "I" in spg_symbol: self._kpath = self.bcc() else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "tetragonal": if "P" in spg_symbol: self._kpath = self.tet() elif "I" in spg_symbol: a = self._conv.lattice.abc[0] c = self._conv.lattice.abc[2] if c < a: self._kpath = self.bctet1(c, a) else: self._kpath = self.bctet2(c, a) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "orthorhombic": a = self._conv.lattice.abc[0] b = self._conv.lattice.abc[1] c = self._conv.lattice.abc[2] if "P" in spg_symbol: self._kpath = self.orc() elif "F" in spg_symbol: if 1 / a ** 2 > 1 / b ** 2 + 1 / c ** 2: self._kpath = self.orcf1(a, b, c) elif 1 / a ** 2 < 1 / b ** 2 + 1 / c ** 2: self._kpath = self.orcf2(a, b, c) else: self._kpath = self.orcf3(a, b, c) elif "I" in spg_symbol: self._kpath = self.orci(a, b, c) elif "C" in spg_symbol: self._kpath = self.orcc(a, b, c) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "hexagonal": self._kpath = self.hex() elif lattice_type == "rhombohedral": alpha = self._prim.lattice.lengths_and_angles[1][0] if alpha < 90: self._kpath = self.rhl1(alpha * pi / 180) else: self._kpath = self.rhl2(alpha * pi / 180) elif lattice_type == "monoclinic": a, b, c = self._conv.lattice.abc alpha = self._conv.lattice.lengths_and_angles[1][0] #beta = self._conv.lattice.lengths_and_angles[1][1] if "P" in spg_symbol: self._kpath = self.mcl(b, c, alpha * pi / 180) elif "C" in spg_symbol: kgamma = self._prim_rec.lengths_and_angles[1][2] if kgamma > 90: self._kpath = self.mclc1(a, b, c, alpha * pi / 180) if kgamma == 90: self._kpath = self.mclc2(a, b, c, alpha * pi / 180) if kgamma < 90: if b * cos(alpha * pi / 180) / c\ + b ** 2 * sin(alpha) ** 2 / a ** 2 < 1: self._kpath = self.mclc3(a, b, c, alpha * pi / 180) if b * cos(alpha * pi / 180) / c \ + b ** 2 * sin(alpha) ** 2 / a ** 2 == 1: self._kpath = self.mclc4(a, b, c, alpha * pi / 180) if b * cos(alpha * pi / 180) / c \ + b ** 2 * sin(alpha) ** 2 / a ** 2 > 1: self._kpath = self.mclc5(a, b, c, alpha * pi / 180) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "triclinic": kalpha = self._prim_rec.lengths_and_angles[1][0] kbeta = self._prim_rec.lengths_and_angles[1][1] kgamma = self._prim_rec.lengths_and_angles[1][2] if kalpha > 90 and kbeta > 90 and kgamma > 90: self._kpath = self.tria() if kalpha < 90 and kbeta < 90 and kgamma < 90: self._kpath = self.trib() if kalpha > 90 and kbeta > 90 and kgamma == 90: self._kpath = self.tria() if kalpha < 90 and kbeta < 90 and kgamma == 90: self._kpath = self.trib() else: warn("Unknown lattice type %s" % lattice_type) @property def structure(self): """ Returns: The standardized primitive structure """ return self._prim @property def kpath(self): """ Returns: The symmetry line path in reciprocal space """ return self._kpath def get_kpoints(self, line_density=20, coords_are_cartesian=True): """ Returns: the kpoints along the paths in cartesian coordinates together with the labels for symmetry points -Wei """ list_k_points = [] sym_point_labels = [] for b in self.kpath['path']: for i in range(1, len(b)): start = np.array(self.kpath['kpoints'][b[i - 1]]) end = np.array(self.kpath['kpoints'][b[i]]) distance = np.linalg.norm( self._prim_rec.get_cartesian_coords(start) - self._prim_rec.get_cartesian_coords(end)) nb = int(ceil(distance * line_density)) sym_point_labels.extend([b[i - 1]] + [''] * (nb - 1) + [b[i]]) list_k_points.extend( [self._prim_rec.get_cartesian_coords(start) + float(i) / float(nb) * (self._prim_rec.get_cartesian_coords(end) - self._prim_rec.get_cartesian_coords(start)) for i in range(0, nb + 1)]) if coords_are_cartesian: return list_k_points, sym_point_labels else: frac_k_points = [self._prim_rec.get_fractional_coords(k) for k in list_k_points] return frac_k_points, sym_point_labels def get_kpath_plot(self, **kwargs): """ Gives the plot (as a matplotlib object) of the symmetry line path in the Brillouin Zone. Returns: `matplotlib` figure. ================ ==================================================== kwargs Meaning ================ ==================================================== title Title of the plot (Default: None). show True to show the figure (default: True). savefig 'abc.png' or 'abc.eps' to save the figure to a file. size_kwargs Dictionary with options passed to fig.set_size_inches example: size_kwargs=dict(w=3, h=4) tight_layout True if to call fig.tight_layout (default: False) ================ ==================================================== """ lines = [[self.kpath['kpoints'][k] for k in p] for p in self.kpath['path']] return plot_brillouin_zone(bz_lattice=self._prim_rec, lines=lines, labels=self.kpath['kpoints'], **kwargs) def cubic(self): self.name = "CUB" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'X': np.array([0.0, 0.5, 0.0]), 'R': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.5, 0.0])} path = [["\Gamma", "X", "M", "\Gamma", "R", "X"], ["M", "R"]] return {'kpoints': kpoints, 'path': path} def fcc(self): self.name = "FCC" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'K': np.array([3.0 / 8.0, 3.0 / 8.0, 3.0 / 4.0]), 'L': np.array([0.5, 0.5, 0.5]), 'U': np.array([5.0 / 8.0, 1.0 / 4.0, 5.0 / 8.0]), 'W': np.array([0.5, 1.0 / 4.0, 3.0 / 4.0]), 'X': np.array([0.5, 0.0, 0.5])} path = [["\Gamma", "X", "W", "K", "\Gamma", "L", "U", "W", "L", "K"], ["U", "X"]] return {'kpoints': kpoints, 'path': path} def bcc(self): self.name = "BCC" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'H': np.array([0.5, -0.5, 0.5]), 'P': np.array([0.25, 0.25, 0.25]), 'N': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "H", "N", "\Gamma", "P", "H"], ["P", "N"]] return {'kpoints': kpoints, 'path': path} def tet(self): self.name = "TET" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.5, 0.0]), 'R': np.array([0.0, 0.5, 0.5]), 'X': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "X", "M", "\Gamma", "Z", "R", "A", "Z"], ["X", "R"], ["M", "A"]] return {'kpoints': kpoints, 'path': path} def bctet1(self, c, a): self.name = "BCT1" eta = (1 + c ** 2 / a ** 2) / 4.0 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'M': np.array([-0.5, 0.5, 0.5]), 'N': np.array([0.0, 0.5, 0.0]), 'P': np.array([0.25, 0.25, 0.25]), 'X': np.array([0.0, 0.0, 0.5]), 'Z': np.array([eta, eta, -eta]), 'Z_1': np.array([-eta, 1 - eta, eta])} path = [["\Gamma", "X", "M", "\Gamma", "Z", "P", "N", "Z_1", "M"], ["X", "P"]] return {'kpoints': kpoints, 'path': path} def bctet2(self, c, a): self.name = "BCT2" eta = (1 + a ** 2 / c ** 2) / 4.0 zeta = a ** 2 / (2 * c ** 2) kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.0, 0.5, 0.0]), 'P': np.array([0.25, 0.25, 0.25]), '\Sigma': np.array([-eta, eta, eta]), '\Sigma_1': np.array([eta, 1 - eta, -eta]), 'X': np.array([0.0, 0.0, 0.5]), 'Y': np.array([-zeta, zeta, 0.5]), 'Y_1': np.array([0.5, 0.5, -zeta]), 'Z': np.array([0.5, 0.5, -0.5])} path = [["\Gamma", "X", "Y", "\Sigma", "\Gamma", "Z", "\Sigma_1", "N", "P", "Y_1", "Z"], ["X", "P"]] return {'kpoints': kpoints, 'path': path} def orc(self): self.name = "ORC" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'R': np.array([0.5, 0.5, 0.5]), 'S': np.array([0.5, 0.5, 0.0]), 'T': np.array([0.0, 0.5, 0.5]), 'U': np.array([0.5, 0.0, 0.5]), 'X': np.array([0.5, 0.0, 0.0]), 'Y': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "X", "S", "Y", "\Gamma", "Z", "U", "R", "T", "Z"], ["Y", "T"], ["U", "X"], ["S", "R"]] return {'kpoints': kpoints, 'path': path} def orcf1(self, a, b, c): self.name = "ORCF1" zeta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4 eta = (1 + a ** 2 / b ** 2 + a ** 2 / c ** 2) / 4 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5 + zeta, zeta]), 'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]), 'L': np.array([0.5, 0.5, 0.5]), 'T': np.array([1, 0.5, 0.5]), 'X': np.array([0.0, eta, eta]), 'X_1': np.array([1, 1 - eta, 1 - eta]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0])} path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"], ["T", "X_1"], ["X", "A", "Z"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orcf2(self, a, b, c): self.name = "ORCF2" phi = (1 + c ** 2 / b ** 2 - c ** 2 / a ** 2) / 4 eta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4 delta = (1 + b ** 2 / a ** 2 - b ** 2 / c ** 2) / 4 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'C': np.array([0.5, 0.5 - eta, 1 - eta]), 'C_1': np.array([0.5, 0.5 + eta, eta]), 'D': np.array([0.5 - delta, 0.5, 1 - delta]), 'D_1': np.array([0.5 + delta, 0.5, delta]), 'L': np.array([0.5, 0.5, 0.5]), 'H': np.array([1 - phi, 0.5 - phi, 0.5]), 'H_1': np.array([phi, 0.5 + phi, 0.5]), 'X': np.array([0.0, 0.5, 0.5]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0])} path = [["\Gamma", "Y", "C", "D", "X", "\Gamma", "Z", "D_1", "H", "C"], ["C_1", "Z"], ["X", "H_1"], ["H", "Y"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orcf3(self, a, b, c): self.name = "ORCF3" zeta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4 eta = (1 + a ** 2 / b ** 2 + a ** 2 / c ** 2) / 4 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5 + zeta, zeta]), 'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]), 'L': np.array([0.5, 0.5, 0.5]), 'T': np.array([1, 0.5, 0.5]), 'X': np.array([0.0, eta, eta]), 'X_1': np.array([1, 1 - eta, 1 - eta]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0])} path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"], ["X", "A", "Z"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orci(self, a, b, c): self.name = "ORCI" zeta = (1 + a ** 2 / c ** 2) / 4 eta = (1 + b ** 2 / c ** 2) / 4 delta = (b ** 2 - a ** 2) / (4 * c ** 2) mu = (a ** 2 + b ** 2) / (4 * c ** 2) kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([-mu, mu, 0.5 - delta]), 'L_1': np.array([mu, -mu, 0.5 + delta]), 'L_2': np.array([0.5 - delta, 0.5 + delta, -mu]), 'R': np.array([0.0, 0.5, 0.0]), 'S': np.array([0.5, 0.0, 0.0]), 'T': np.array([0.0, 0.0, 0.5]), 'W': np.array([0.25, 0.25, 0.25]), 'X': np.array([-zeta, zeta, zeta]), 'X_1': np.array([zeta, 1 - zeta, -zeta]), 'Y': np.array([eta, -eta, eta]), 'Y_1': np.array([1 - eta, eta, -eta]), 'Z': np.array([0.5, 0.5, -0.5])} path = [["\Gamma", "X", "L", "T", "W", "R", "X_1", "Z", "\Gamma", "Y", "S", "W"], ["L_1", "Y"], ["Y_1", "Z"]] return {'kpoints': kpoints, 'path': path} def orcc(self, a, b, c): self.name = "ORCC" zeta = (1 + a ** 2 / b ** 2) / 4 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([zeta, zeta, 0.5]), 'A_1': np.array([-zeta, 1 - zeta, 0.5]), 'R': np.array([0.0, 0.5, 0.5]), 'S': np.array([0.0, 0.5, 0.0]), 'T': np.array([-0.5, 0.5, 0.5]), 'X': np.array([zeta, zeta, 0.0]), 'X_1': np.array([-zeta, 1 - zeta, 0.0]), 'Y': np.array([-0.5, 0.5, 0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "X", "S", "R", "A", "Z", "\Gamma", "Y", "X_1", "A_1", "T", "Y"], ["Z", "T"]] return {'kpoints': kpoints, 'path': path} def hex(self): self.name = "HEX" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.0, 0.0, 0.5]), 'H': np.array([1.0 / 3.0, 1.0 / 3.0, 0.5]), 'K': np.array([1.0 / 3.0, 1.0 / 3.0, 0.0]), 'L': np.array([0.5, 0.0, 0.5]), 'M': np.array([0.5, 0.0, 0.0])} path = [["\Gamma", "M", "K", "\Gamma", "A", "L", "H", "A"], ["L", "M"], ["K", "H"]] return {'kpoints': kpoints, 'path': path} def rhl1(self, alpha): self.name = "RHL1" eta = (1 + 4 * cos(alpha)) / (2 + 4 * cos(alpha)) nu = 3.0 / 4.0 - eta / 2.0 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'B': np.array([eta, 0.5, 1.0 - eta]), 'B_1': np.array([1.0 / 2.0, 1.0 - eta, eta - 1.0]), 'F': np.array([0.5, 0.5, 0.0]), 'L': np.array([0.5, 0.0, 0.0]), 'L_1': np.array([0.0, 0.0, -0.5]), 'P': np.array([eta, nu, nu]), 'P_1': np.array([1.0 - nu, 1.0 - nu, 1.0 - eta]), 'P_2': np.array([nu, nu, eta - 1.0]), 'Q': np.array([1.0 - nu, nu, 0.0]), 'X': np.array([nu, 0.0, -nu]), 'Z': np.array([0.5, 0.5, 0.5])} path = [["\Gamma", "L", "B_1"], ["B", "Z", "\Gamma", "X"], ["Q", "F", "P_1", "Z"], ["L", "P"]] return {'kpoints': kpoints, 'path': path} def rhl2(self, alpha): self.name = "RHL2" eta = 1 / (2 * tan(alpha / 2.0) ** 2) nu = 3.0 / 4.0 - eta / 2.0 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([0.5, -0.5, 0.0]), 'L': np.array([0.5, 0.0, 0.0]), 'P': np.array([1 - nu, -nu, 1 - nu]), 'P_1': np.array([nu, nu - 1.0, nu - 1.0]), 'Q': np.array([eta, eta, eta]), 'Q_1': np.array([1.0 - eta, -eta, -eta]), 'Z': np.array([0.5, -0.5, 0.5])} path = [["\Gamma", "P", "Z", "Q", "\Gamma", "F", "P_1", "Q_1", "L", "Z"]] return {'kpoints': kpoints, 'path': path} def mcl(self, b, c, beta): self.name = "MCL" eta = (1 - b * cos(beta) / c) / (2 * sin(beta) ** 2) nu = 0.5 - eta * c * cos(beta) / b kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5, 0.0]), 'C': np.array([0.0, 0.5, 0.5]), 'D': np.array([0.5, 0.0, 0.5]), 'D_1': np.array([0.5, 0.5, -0.5]), 'E': np.array([0.5, 0.5, 0.5]), 'H': np.array([0.0, eta, 1.0 - nu]), 'H_1': np.array([0.0, 1.0 - eta, nu]), 'H_2': np.array([0.0, eta, -nu]), 'M': np.array([0.5, eta, 1.0 - nu]), 'M_1': np.array([0.5, 1 - eta, nu]), 'M_2': np.array([0.5, 1 - eta, nu]), 'X': np.array([0.0, 0.5, 0.0]), 'Y': np.array([0.0, 0.0, 0.5]), 'Y_1': np.array([0.0, 0.0, -0.5]), 'Z': np.array([0.5, 0.0, 0.0])} path = [["\Gamma", "Y", "H", "C", "E", "M_1", "A", "X", "H_1"], ["M", "D", "Z"], ["Y", "D"]] return {'kpoints': kpoints, 'path': path} def mclc1(self, a, b, c, alpha): self.name = "MCLC1" zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b psi = 0.75 - a ** 2 / (4 * b ** 2 * sin(alpha) ** 2) phi = psi + (0.75 - psi) * b * cos(alpha) / c kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'F': np.array([1 - zeta, 1 - zeta, 1 - eta]), 'F_1': np.array([zeta, zeta, eta]), 'F_2': np.array([-zeta, -zeta, 1 - eta]), #'F_3': np.array([1 - zeta, -zeta, 1 - eta]), 'I': np.array([phi, 1 - phi, 0.5]), 'I_1': np.array([1 - phi, phi - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'X': np.array([1 - psi, psi - 1, 0.0]), 'X_1': np.array([psi, 1 - psi, 0.0]), 'X_2': np.array([psi - 1, -psi, 0.0]), 'Y': np.array([0.5, 0.5, 0.0]), 'Y_1': np.array([-0.5, -0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"], ["Y", "X_1"], ["X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc2(self, a, b, c, alpha): self.name = "MCLC2" zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b psi = 0.75 - a ** 2 / (4 * b ** 2 * sin(alpha) ** 2) phi = psi + (0.75 - psi) * b * cos(alpha) / c kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'F': np.array([1 - zeta, 1 - zeta, 1 - eta]), 'F_1': np.array([zeta, zeta, eta]), 'F_2': np.array([-zeta, -zeta, 1 - eta]), 'F_3': np.array([1 - zeta, -zeta, 1 - eta]), 'I': np.array([phi, 1 - phi, 0.5]), 'I_1': np.array([1 - phi, phi - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'X': np.array([1 - psi, psi - 1, 0.0]), 'X_1': np.array([psi, 1 - psi, 0.0]), 'X_2': np.array([psi - 1, -psi, 0.0]), 'Y': np.array([0.5, 0.5, 0.0]), 'Y_1': np.array([-0.5, -0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"], ["N", "\Gamma", "M"]] return {'kpoints': kpoints, 'path': path} def mclc3(self, a, b, c, alpha): self.name = "MCLC3" mu = (1 + b ** 2 / a ** 2) / 4.0 delta = b * c * cos(alpha) / (2 * a ** 2) zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\ / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b phi = 1 + zeta - 2 * mu psi = eta - 2 * delta kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([1 - phi, 1 - phi, 1 - psi]), 'F_1': np.array([phi, phi - 1, psi]), 'F_2': np.array([1 - phi, -phi, 1 - psi]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([0.5, -0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "H", "Z", "I", "F_1"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc4(self, a, b, c, alpha): self.name = "MCLC4" mu = (1 + b ** 2 / a ** 2) / 4.0 delta = b * c * cos(alpha) / (2 * a ** 2) zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\ / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b phi = 1 + zeta - 2 * mu psi = eta - 2 * delta kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([1 - phi, 1 - phi, 1 - psi]), 'F_1': np.array([phi, phi - 1, psi]), 'F_2': np.array([1 - phi, -phi, 1 - psi]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([0.5, -0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "H", "Z", "I"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc5(self, a, b, c, alpha): self.name = "MCLC5" zeta = (b ** 2 / a ** 2 + (1 - b * cos(alpha) / c) / sin(alpha) ** 2) / 4 eta = 0.5 + 2 * zeta * c * cos(alpha) / b mu = eta / 2 + b ** 2 / (4 * a ** 2) \ - b * c * cos(alpha) / (2 * a ** 2) nu = 2 * mu - zeta rho = 1 - zeta * a ** 2 / b ** 2 omega = (4 * nu - 1 - b ** 2 * sin(alpha) ** 2 / a ** 2)\ * c / (2 * b * cos(alpha)) delta = zeta * c * cos(alpha) / b + omega / 2 - 0.25 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([nu, nu, omega]), 'F_1': np.array([1 - nu, 1 - nu, 1 - omega]), 'F_2': np.array([nu, nu - 1, omega]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([rho, 1 - rho, 0.5]), 'I_1': np.array([1 - rho, rho - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "H", "F_1"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def tria(self): self.name = "TRI1a" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([0.5, 0.5, 0.0]), 'M': np.array([0.0, 0.5, 0.5]), 'N': np.array([0.5, 0.0, 0.5]), 'R': np.array([0.5, 0.5, 0.5]), 'X': np.array([0.5, 0.0, 0.0]), 'Y': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"], ["N", "\Gamma", "M"], ["R", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def trib(self): self.name = "TRI1b" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([0.5, -0.5, 0.0]), 'M': np.array([0.0, 0.0, 0.5]), 'N': np.array([-0.5, -0.5, 0.5]), 'R': np.array([0.0, -0.5, 0.5]), 'X': np.array([0.0, -0.5, 0.0]), 'Y': np.array([0.5, 0.0, 0.0]), 'Z': np.array([-0.5, 0.0, 0.5])} path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"], ["N", "\Gamma", "M"], ["R", "\Gamma"]] return {'kpoints': kpoints, 'path': path}
def read_data(data=None,ff=None): pot_file=open(ff,"r") lines = pot_file.read().splitlines() symb=[] count=0 from pymatgen.core.periodic_table import Element for i, line in enumerate(lines): if "pair_coeff" in line.split(): sp=line.split() print "spsplit",sp,os.getcwd() for el in sp: try: if Element(el): #if el=='M': # el='Mo' #count=count+1 #if count >4: symb.append(el) except: pass print "symb=",symb f=open(data,"r") lines = f.read().splitlines() for i, line in enumerate(lines): if "atoms" in line.split(): natoms=int(line.split()[0]) if "types" in line.split(): print line ntypes=int(line.split()[0]) if "xlo" in line.split(): xlo=float(line.split()[0]) xhi=float(line.split()[1]) if "ylo" in line.split(): ylo=float(line.split()[0]) yhi=float(line.split()[1]) if "zlo" in line.split(): zlo=float(line.split()[0]) zhi=float(line.split()[1]) if "xy" in line.split(): xy=float(line.split()[0]) xz=float(line.split()[1]) yz=float(line.split()[2]) if len(symb) != ntypes: print ("Something wrong in atom type assignment",len(symb),ntypes) sys.exit() lat=Lattice([[ xhi-xlo,0.0,0.0],[xy,yhi-ylo,0.0],[xz,yz,zhi-zlo]]) typ= np.empty((natoms),dtype="S20") x=np.zeros((natoms)) y=np.zeros((natoms)) z=np.zeros((natoms)) q=np.zeros((natoms)) coords = list() for i, line in enumerate(lines): if "Atoms" in line.split(): for j in range(0,natoms): #print int(((lines[j+2]).split()[1]))-1 typ[j]=symb[int(((lines[i+j+2]).split()[1]))-1] q[j]=(lines[i+j+2]).split()[2] x[j]=(lines[i+j+2]).split()[3] y[j]=(lines[i+j+2]).split()[4] z[j]=(lines[i+j+2]).split()[5] coords.append([x[j],y[j],z[j]]) f.close() print "info",len(typ),len(coords) pot_file.close() struct=Structure(lat,typ,coords,coords_are_cartesian=True) #print struct finder = SpacegroupAnalyzer(struct) num=finder.get_spacegroup_symbol() #print(num) return struct
def __init__(self, struct, symprec=None): format_str = "{:.8f}" block = OrderedDict() loops = [] spacegroup = ("P 1", 1) if symprec is not None: sf = SpacegroupAnalyzer(struct, symprec) spacegroup = (sf.get_spacegroup_symbol(), sf.get_spacegroup_number()) # Needs the refined struture when using symprec. This converts # primitive to conventional structures, the standard for CIF. struct = sf.get_refined_structure() latt = struct.lattice comp = struct.composition no_oxi_comp = comp.element_composition block["_symmetry_space_group_name_H-M"] = spacegroup[0] for cell_attr in ['a', 'b', 'c']: block["_cell_length_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) for cell_attr in ['alpha', 'beta', 'gamma']: block["_cell_angle_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) block["_symmetry_Int_Tables_number"] = spacegroup[1] block["_chemical_formula_structural"] = no_oxi_comp.reduced_formula block["_chemical_formula_sum"] = no_oxi_comp.formula block["_cell_volume"] = latt.volume.__str__() reduced_comp, fu = no_oxi_comp.get_reduced_composition_and_factor() block["_cell_formula_units_Z"] = str(int(fu)) if symprec is None: block["_symmetry_equiv_pos_site_id"] = ["1"] block["_symmetry_equiv_pos_as_xyz"] = ["x, y, z"] else: sf = SpacegroupAnalyzer(struct, symprec) def round_symm_trans(i): for t in TRANSLATIONS.values(): if abs(i - t) < symprec: return t if abs(i - round(i)) < symprec: return 0 raise ValueError("Invalid translation!") symmops = [] for op in sf.get_symmetry_operations(): v = op.translation_vector v = [round_symm_trans(i) for i in v] symmops.append( SymmOp.from_rotation_and_translation( op.rotation_matrix, v)) ops = [op.as_xyz_string() for op in symmops] block["_symmetry_equiv_pos_site_id"] = \ ["%d" % i for i in range(1, len(ops) + 1)] block["_symmetry_equiv_pos_as_xyz"] = ops loops.append( ["_symmetry_equiv_pos_site_id", "_symmetry_equiv_pos_as_xyz"]) contains_oxidation = True try: symbol_to_oxinum = OrderedDict([(el.__str__(), float(el.oxi_state)) for el in sorted(comp.elements)]) except AttributeError: symbol_to_oxinum = OrderedDict([(el.symbol, 0) for el in sorted(comp.elements)]) contains_oxidation = False if contains_oxidation: block["_atom_type_symbol"] = symbol_to_oxinum.keys() block["_atom_type_oxidation_number"] = symbol_to_oxinum.values() loops.append(["_atom_type_symbol", "_atom_type_oxidation_number"]) atom_site_type_symbol = [] atom_site_symmetry_multiplicity = [] atom_site_fract_x = [] atom_site_fract_y = [] atom_site_fract_z = [] atom_site_label = [] atom_site_occupancy = [] count = 1 if symprec is None: for site in struct: for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("1") atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 else: # The following just presents a deterministic ordering. unique_sites = [ (sorted(sites, key=lambda s: tuple([abs(x) for x in s.frac_coords]))[0], len(sites)) for sites in sf.get_symmetrized_structure().equivalent_sites ] for site, mult in sorted(unique_sites, key=lambda t: (t[0].species_and_occu.average_electroneg, -t[1], t[0].a, t[0].b, t[0].c)): for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("%d" % mult) atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 block["_atom_site_type_symbol"] = atom_site_type_symbol block["_atom_site_label"] = atom_site_label block["_atom_site_symmetry_multiplicity"] = \ atom_site_symmetry_multiplicity block["_atom_site_fract_x"] = atom_site_fract_x block["_atom_site_fract_y"] = atom_site_fract_y block["_atom_site_fract_z"] = atom_site_fract_z block["_atom_site_occupancy"] = atom_site_occupancy loops.append([ "_atom_site_type_symbol", "_atom_site_label", "_atom_site_symmetry_multiplicity", "_atom_site_fract_x", "_atom_site_fract_y", "_atom_site_fract_z", "_atom_site_occupancy" ]) d = OrderedDict() d[comp.reduced_formula] = CifBlock(block, loops, comp.reduced_formula) self._cf = CifFile(d)
class HighSymmKpath(object): """ This class looks for path along high symmetry lines in the Brillouin Zone. It is based on Setyawan, W., & Curtarolo, S. (2010). High-throughput electronic band structure calculations: Challenges and tools. Computational Materials Science, 49(2), 299-312. doi:10.1016/j.commatsci.2010.05.010 The symmetry is determined by spglib through the SpacegroupAnalyzer class Args: structure (Structure): Structure object symprec (float): Tolerance for symmetry finding angle_tolerance (float): Angle tolerance for symmetry finding. """ def __init__(self, structure, symprec=0.01, angle_tolerance=5): self._structure = structure self._sym = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance) self._prim = self._sym\ .get_primitive_standard_structure(international_monoclinic=False) self._conv = self._sym.get_conventional_standard_structure(international_monoclinic=False) self._prim_rec = self._prim.lattice.reciprocal_lattice self._kpath = None lattice_type = self._sym.get_lattice_type() spg_symbol = self._sym.get_spacegroup_symbol() if lattice_type == "cubic": if "P" in spg_symbol: self._kpath = self.cubic() elif "F" in spg_symbol: self._kpath = self.fcc() elif "I" in spg_symbol: self._kpath = self.bcc() else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "tetragonal": if "P" in spg_symbol: self._kpath = self.tet() elif "I" in spg_symbol: a = self._conv.lattice.abc[0] c = self._conv.lattice.abc[2] if c < a: self._kpath = self.bctet1(c, a) else: self._kpath = self.bctet2(c, a) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "orthorhombic": a = self._conv.lattice.abc[0] b = self._conv.lattice.abc[1] c = self._conv.lattice.abc[2] if "P" in spg_symbol: self._kpath = self.orc() elif "F" in spg_symbol: if 1 / a ** 2 > 1 / b ** 2 + 1 / c ** 2: self._kpath = self.orcf1(a, b, c) elif 1 / a ** 2 < 1 / b ** 2 + 1 / c ** 2: self._kpath = self.orcf2(a, b, c) else: self._kpath = self.orcf3(a, b, c) elif "I" in spg_symbol: self._kpath = self.orci(a, b, c) elif "C" in spg_symbol: self._kpath = self.orcc(a, b, c) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "hexagonal": self._kpath = self.hex() elif lattice_type == "rhombohedral": alpha = self._prim.lattice.lengths_and_angles[1][0] if alpha < 90: self._kpath = self.rhl1(alpha * pi / 180) else: self._kpath = self.rhl2(alpha * pi / 180) elif lattice_type == "monoclinic": a, b, c = self._conv.lattice.abc alpha = self._conv.lattice.lengths_and_angles[1][0] #beta = self._conv.lattice.lengths_and_angles[1][1] if "P" in spg_symbol: self._kpath = self.mcl(b, c, alpha * pi / 180) elif "C" in spg_symbol: kgamma = self._prim_rec.lengths_and_angles[1][2] if kgamma > 90: self._kpath = self.mclc1(a, b, c, alpha * pi / 180) if kgamma == 90: self._kpath = self.mclc2(a, b, c, alpha * pi / 180) if kgamma < 90: if b * cos(alpha * pi / 180) / c\ + b ** 2 * sin(alpha) ** 2 / a ** 2 < 1: self._kpath = self.mclc3(a, b, c, alpha * pi / 180) if b * cos(alpha * pi / 180) / c \ + b ** 2 * sin(alpha) ** 2 / a ** 2 == 1: self._kpath = self.mclc4(a, b, c, alpha * pi / 180) if b * cos(alpha * pi / 180) / c \ + b ** 2 * sin(alpha) ** 2 / a ** 2 > 1: self._kpath = self.mclc5(a, b, c, alpha * pi / 180) else: warn("Unexpected value for spg_symbol: %s" % spg_symbol) elif lattice_type == "triclinic": kalpha = self._prim_rec.lengths_and_angles[1][0] kbeta = self._prim_rec.lengths_and_angles[1][1] kgamma = self._prim_rec.lengths_and_angles[1][2] if kalpha > 90 and kbeta > 90 and kgamma > 90: self._kpath = self.tria() if kalpha < 90 and kbeta < 90 and kgamma < 90: self._kpath = self.trib() if kalpha > 90 and kbeta > 90 and kgamma == 90: self._kpath = self.tria() if kalpha < 90 and kbeta < 90 and kgamma == 90: self._kpath = self.trib() else: warn("Unknown lattice type %s" % lattice_type) @property def structure(self): """ Returns: The standardized primitive structure """ return self._prim @property def kpath(self): """ Returns: The symmetry line path in reciprocal space """ return self._kpath def get_kpoints(self, line_density=20): """ Returns: the kpoints along the paths in cartesian coordinates together with the labels for symmetry points -Wei """ list_k_points = [] sym_point_labels = [] for b in self.kpath['path']: for i in range(1, len(b)): start = np.array(self.kpath['kpoints'][b[i - 1]]) end = np.array(self.kpath['kpoints'][b[i]]) distance = np.linalg.norm( self._prim_rec.get_cartesian_coords(start) - self._prim_rec.get_cartesian_coords(end)) nb = int(ceil(distance * line_density)) sym_point_labels.extend([b[i - 1]] + [''] * (nb - 1) + [b[i]]) list_k_points.extend( [self._prim_rec.get_cartesian_coords(start) + float(i) / float(nb) * (self._prim_rec.get_cartesian_coords(end) - self._prim_rec.get_cartesian_coords(start)) for i in range(0, nb + 1)]) return list_k_points, sym_point_labels def get_kpath_plot(self, **kwargs): """ Gives the plot (as a matplotlib object) of the symmetry line path in the Brillouin Zone. Returns: `matplotlib` figure. ================ ============================================================== kwargs Meaning ================ ============================================================== show True to show the figure (Default). savefig 'abc.png' or 'abc.eps'* to save the figure to a file. ================ ============================================================== """ import itertools import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import axes3d def _plot_shape_skeleton(bz, style): for iface in range(len(bz)): for line in itertools.combinations(bz[iface], 2): for jface in range(len(bz)): if iface < jface and line[0] in bz[jface]\ and line[1] in bz[jface]: ax.plot([line[0][0], line[1][0]], [line[0][1], line[1][1]], [line[0][2], line[1][2]], style) def _plot_lattice(lattice): vertex1 = lattice.get_cartesian_coords([0.0, 0.0, 0.0]) vertex2 = lattice.get_cartesian_coords([1.0, 0.0, 0.0]) ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]], [vertex1[2], vertex2[2]], color='g', linewidth=3) vertex2 = lattice.get_cartesian_coords([0.0, 1.0, 0.0]) ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]], [vertex1[2], vertex2[2]], color='g', linewidth=3) vertex2 = lattice.get_cartesian_coords([0.0, 0.0, 1.0]) ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]], [vertex1[2], vertex2[2]], color='g', linewidth=3) def _plot_kpath(kpath, lattice): for line in kpath['path']: for k in range(len(line) - 1): vertex1 = lattice.get_cartesian_coords(kpath['kpoints'] [line[k]]) vertex2 = lattice.get_cartesian_coords(kpath['kpoints'] [line[k + 1]]) ax.plot([vertex1[0], vertex2[0]], [vertex1[1], vertex2[1]], [vertex1[2], vertex2[2]], color='r', linewidth=3) def _plot_labels(kpath, lattice): for k in kpath['kpoints']: label = k if k.startswith("\\") or k.find("_") != -1: label = "$" + k + "$" off = 0.01 ax.text(lattice.get_cartesian_coords(kpath['kpoints'][k])[0] + off, lattice.get_cartesian_coords(kpath['kpoints'][k])[1] + off, lattice.get_cartesian_coords(kpath['kpoints'][k])[2] + off, label, color='b', size='25') ax.scatter([lattice.get_cartesian_coords( kpath['kpoints'][k])[0]], [lattice.get_cartesian_coords( kpath['kpoints'][k])[1]], [lattice.get_cartesian_coords( kpath['kpoints'][k])[2]], color='b') fig = plt.figure() ax = axes3d.Axes3D(fig) _plot_lattice(self._prim_rec) _plot_shape_skeleton(self._prim_rec.get_wigner_seitz_cell(), '-k') _plot_kpath(self.kpath, self._prim_rec) _plot_labels(self.kpath, self._prim_rec) ax.axis("off") show = kwargs.pop("show", True) if show: plt.show() savefig = kwargs.pop("savefig", None) if savefig: fig.savefig(savefig) return fig def cubic(self): self.name = "CUB" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'X': np.array([0.0, 0.5, 0.0]), 'R': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.5, 0.0])} path = [["\Gamma", "X", "M", "\Gamma", "R", "X"], ["M", "R"]] return {'kpoints': kpoints, 'path': path} def fcc(self): self.name = "FCC" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'K': np.array([3.0 / 8.0, 3.0 / 8.0, 3.0 / 4.0]), 'L': np.array([0.5, 0.5, 0.5]), 'U': np.array([5.0 / 8.0, 1.0 / 4.0, 5.0 / 8.0]), 'W': np.array([0.5, 1.0 / 4.0, 3.0 / 4.0]), 'X': np.array([0.5, 0.0, 0.5])} path = [["\Gamma", "X", "W", "K", "\Gamma", "L", "U", "W", "L", "K"], ["U", "X"]] return {'kpoints': kpoints, 'path': path} def bcc(self): self.name = "BCC" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'H': np.array([0.5, -0.5, 0.5]), 'P': np.array([0.25, 0.25, 0.25]), 'N': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "H", "N", "\Gamma", "P", "H"], ["P", "N"]] return {'kpoints': kpoints, 'path': path} def tet(self): self.name = "TET" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.5, 0.0]), 'R': np.array([0.0, 0.5, 0.5]), 'X': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "X", "M", "\Gamma", "Z", "R", "A", "Z"], ["X", "R"], ["M", "A"]] return {'kpoints': kpoints, 'path': path} def bctet1(self, c, a): self.name = "BCT1" eta = (1 + c ** 2 / a ** 2) / 4.0 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'M': np.array([-0.5, 0.5, 0.5]), 'N': np.array([0.0, 0.5, 0.0]), 'P': np.array([0.25, 0.25, 0.25]), 'X': np.array([0.0, 0.0, 0.5]), 'Z': np.array([eta, eta, -eta]), 'Z_1': np.array([-eta, 1 - eta, eta])} path = [["\Gamma", "X", "M", "\Gamma", "Z", "P", "N", "Z_1", "M"], ["X", "P"]] return {'kpoints': kpoints, 'path': path} def bctet2(self, c, a): self.name = "BCT2" eta = (1 + a ** 2 / c ** 2) / 4.0 zeta = a ** 2 / (2 * c ** 2) kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.0, 0.5, 0.0]), 'P': np.array([0.25, 0.25, 0.25]), '\Sigma': np.array([-eta, eta, eta]), '\Sigma_1': np.array([eta, 1 - eta, -eta]), 'X': np.array([0.0, 0.0, 0.5]), 'Y': np.array([-zeta, zeta, 0.5]), 'Y_1': np.array([0.5, 0.5, -zeta]), 'Z': np.array([0.5, 0.5, -0.5])} path = [["\Gamma", "X", "Y", "\Sigma", "\Gamma", "Z", "\Sigma_1", "N", "P", "Y_1", "Z"], ["X", "P"]] return {'kpoints': kpoints, 'path': path} def orc(self): self.name = "ORC" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'R': np.array([0.5, 0.5, 0.5]), 'S': np.array([0.5, 0.5, 0.0]), 'T': np.array([0.0, 0.5, 0.5]), 'U': np.array([0.5, 0.0, 0.5]), 'X': np.array([0.5, 0.0, 0.0]), 'Y': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "X", "S", "Y", "\Gamma", "Z", "U", "R", "T", "Z"], ["Y", "T"], ["U", "X"], ["S", "R"]] return {'kpoints': kpoints, 'path': path} def orcf1(self, a, b, c): self.name = "ORCF1" zeta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4 eta = (1 + a ** 2 / b ** 2 + a ** 2 / c ** 2) / 4 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5 + zeta, zeta]), 'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]), 'L': np.array([0.5, 0.5, 0.5]), 'T': np.array([1, 0.5, 0.5]), 'X': np.array([0.0, eta, eta]), 'X_1': np.array([1, 1 - eta, 1 - eta]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0])} path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"], ["T", "X_1"], ["X", "A", "Z"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orcf2(self, a, b, c): self.name = "ORCF2" phi = (1 + c ** 2 / b ** 2 - c ** 2 / a ** 2) / 4 eta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4 delta = (1 + b ** 2 / a ** 2 - b ** 2 / c ** 2) / 4 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'C': np.array([0.5, 0.5 - eta, 1 - eta]), 'C_1': np.array([0.5, 0.5 + eta, eta]), 'D': np.array([0.5 - delta, 0.5, 1 - delta]), 'D_1': np.array([0.5 + delta, 0.5, delta]), 'L': np.array([0.5, 0.5, 0.5]), 'H': np.array([1 - phi, 0.5 - phi, 0.5]), 'H_1': np.array([phi, 0.5 + phi, 0.5]), 'X': np.array([0.0, 0.5, 0.5]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0])} path = [["\Gamma", "Y", "C", "D", "X", "\Gamma", "Z", "D_1", "H", "C"], ["C_1", "Z"], ["X", "H_1"], ["H", "Y"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orcf3(self, a, b, c): self.name = "ORCF3" zeta = (1 + a ** 2 / b ** 2 - a ** 2 / c ** 2) / 4 eta = (1 + a ** 2 / b ** 2 + a ** 2 / c ** 2) / 4 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5 + zeta, zeta]), 'A_1': np.array([0.5, 0.5 - zeta, 1 - zeta]), 'L': np.array([0.5, 0.5, 0.5]), 'T': np.array([1, 0.5, 0.5]), 'X': np.array([0.0, eta, eta]), 'X_1': np.array([1, 1 - eta, 1 - eta]), 'Y': np.array([0.5, 0.0, 0.5]), 'Z': np.array([0.5, 0.5, 0.0])} path = [["\Gamma", "Y", "T", "Z", "\Gamma", "X", "A_1", "Y"], ["X", "A", "Z"], ["L", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def orci(self, a, b, c): self.name = "ORCI" zeta = (1 + a ** 2 / c ** 2) / 4 eta = (1 + b ** 2 / c ** 2) / 4 delta = (b ** 2 - a ** 2) / (4 * c ** 2) mu = (a ** 2 + b ** 2) / (4 * c ** 2) kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([-mu, mu, 0.5 - delta]), 'L_1': np.array([mu, -mu, 0.5 + delta]), 'L_2': np.array([0.5 - delta, 0.5 + delta, -mu]), 'R': np.array([0.0, 0.5, 0.0]), 'S': np.array([0.5, 0.0, 0.0]), 'T': np.array([0.0, 0.0, 0.5]), 'W': np.array([0.25, 0.25, 0.25]), 'X': np.array([-zeta, zeta, zeta]), 'X_1': np.array([zeta, 1 - zeta, -zeta]), 'Y': np.array([eta, -eta, eta]), 'Y_1': np.array([1 - eta, eta, -eta]), 'Z': np.array([0.5, 0.5, -0.5])} path = [["\Gamma", "X", "L", "T", "W", "R", "X_1", "Z", "\Gamma", "Y", "S", "W"], ["L_1", "Y"], ["Y_1", "Z"]] return {'kpoints': kpoints, 'path': path} def orcc(self, a, b, c): self.name = "ORCC" zeta = (1 + a ** 2 / b ** 2) / 4 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([zeta, zeta, 0.5]), 'A_1': np.array([-zeta, 1 - zeta, 0.5]), 'R': np.array([0.0, 0.5, 0.5]), 'S': np.array([0.0, 0.5, 0.0]), 'T': np.array([-0.5, 0.5, 0.5]), 'X': np.array([zeta, zeta, 0.0]), 'X_1': np.array([-zeta, 1 - zeta, 0.0]), 'Y': np.array([-0.5, 0.5, 0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "X", "S", "R", "A", "Z", "\Gamma", "Y", "X_1", "A_1", "T", "Y"], ["Z", "T"]] return {'kpoints': kpoints, 'path': path} def hex(self): self.name = "HEX" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.0, 0.0, 0.5]), 'H': np.array([1.0 / 3.0, 1.0 / 3.0, 0.5]), 'K': np.array([1.0 / 3.0, 1.0 / 3.0, 0.0]), 'L': np.array([0.5, 0.0, 0.5]), 'M': np.array([0.5, 0.0, 0.0])} path = [["\Gamma", "M", "K", "\Gamma", "A", "L", "H", "A"], ["L", "M"], ["K", "H"]] return {'kpoints': kpoints, 'path': path} def rhl1(self, alpha): self.name = "RHL1" eta = (1 + 4 * cos(alpha)) / (2 + 4 * cos(alpha)) nu = 3.0 / 4.0 - eta / 2.0 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'B': np.array([eta, 0.5, 1.0 - eta]), 'B_1': np.array([1.0 / 2.0, 1.0 - eta, eta - 1.0]), 'F': np.array([0.5, 0.5, 0.0]), 'L': np.array([0.5, 0.0, 0.0]), 'L_1': np.array([0.0, 0.0, -0.5]), 'P': np.array([eta, nu, nu]), 'P_1': np.array([1.0 - nu, 1.0 - nu, 1.0 - eta]), 'P_2': np.array([nu, nu, eta - 1.0]), 'Q': np.array([1.0 - nu, nu, 0.0]), 'X': np.array([nu, 0.0, -nu]), 'Z': np.array([0.5, 0.5, 0.5])} path = [["\Gamma", "L", "B_1"], ["B", "Z", "\Gamma", "X"], ["Q", "F", "P_1", "Z"], ["L", "P"]] return {'kpoints': kpoints, 'path': path} def rhl2(self, alpha): self.name = "RHL2" eta = 1 / (2 * tan(alpha / 2.0) ** 2) nu = 3.0 / 4.0 - eta / 2.0 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([0.5, -0.5, 0.0]), 'L': np.array([0.5, 0.0, 0.0]), 'P': np.array([1 - nu, -nu, 1 - nu]), 'P_1': np.array([nu, nu - 1.0, nu - 1.0]), 'Q': np.array([eta, eta, eta]), 'Q_1': np.array([1.0 - eta, -eta, -eta]), 'Z': np.array([0.5, -0.5, 0.5])} path = [["\Gamma", "P", "Z", "Q", "\Gamma", "F", "P_1", "Q_1", "L", "Z"]] return {'kpoints': kpoints, 'path': path} def mcl(self, b, c, beta): self.name = "MCL" eta = (1 - b * cos(beta) / c) / (2 * sin(beta) ** 2) nu = 0.5 - eta * c * cos(beta) / b kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'A': np.array([0.5, 0.5, 0.0]), 'C': np.array([0.0, 0.5, 0.5]), 'D': np.array([0.5, 0.0, 0.5]), 'D_1': np.array([0.5, 0.5, -0.5]), 'E': np.array([0.5, 0.5, 0.5]), 'H': np.array([0.0, eta, 1.0 - nu]), 'H_1': np.array([0.0, 1.0 - eta, nu]), 'H_2': np.array([0.0, eta, -nu]), 'M': np.array([0.5, eta, 1.0 - nu]), 'M_1': np.array([0.5, 1 - eta, nu]), 'M_2': np.array([0.5, 1 - eta, nu]), 'X': np.array([0.0, 0.5, 0.0]), 'Y': np.array([0.0, 0.0, 0.5]), 'Y_1': np.array([0.0, 0.0, -0.5]), 'Z': np.array([0.5, 0.0, 0.0])} path = [["\Gamma", "Y", "H", "C", "E", "M_1", "A", "X", "H_1"], ["M", "D", "Z"], ["Y", "D"]] return {'kpoints': kpoints, 'path': path} def mclc1(self, a, b, c, alpha): self.name = "MCLC1" zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b psi = 0.75 - a ** 2 / (4 * b ** 2 * sin(alpha) ** 2) phi = psi + (0.75 - psi) * b * cos(alpha) / c kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'F': np.array([1 - zeta, 1 - zeta, 1 - eta]), 'F_1': np.array([zeta, zeta, eta]), 'F_2': np.array([-zeta, -zeta, 1 - eta]), #'F_3': np.array([1 - zeta, -zeta, 1 - eta]), 'I': np.array([phi, 1 - phi, 0.5]), 'I_1': np.array([1 - phi, phi - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'X': np.array([1 - psi, psi - 1, 0.0]), 'X_1': np.array([psi, 1 - psi, 0.0]), 'X_2': np.array([psi - 1, -psi, 0.0]), 'Y': np.array([0.5, 0.5, 0.0]), 'Y_1': np.array([-0.5, -0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"], ["Y", "X_1"], ["X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc2(self, a, b, c, alpha): self.name = "MCLC2" zeta = (2 - b * cos(alpha) / c) / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b psi = 0.75 - a ** 2 / (4 * b ** 2 * sin(alpha) ** 2) phi = psi + (0.75 - psi) * b * cos(alpha) / c kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'F': np.array([1 - zeta, 1 - zeta, 1 - eta]), 'F_1': np.array([zeta, zeta, eta]), 'F_2': np.array([-zeta, -zeta, 1 - eta]), 'F_3': np.array([1 - zeta, -zeta, 1 - eta]), 'I': np.array([phi, 1 - phi, 0.5]), 'I_1': np.array([1 - phi, phi - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'X': np.array([1 - psi, psi - 1, 0.0]), 'X_1': np.array([psi, 1 - psi, 0.0]), 'X_2': np.array([psi - 1, -psi, 0.0]), 'Y': np.array([0.5, 0.5, 0.0]), 'Y_1': np.array([-0.5, -0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "F_1"], ["N", "\Gamma", "M"]] return {'kpoints': kpoints, 'path': path} def mclc3(self, a, b, c, alpha): self.name = "MCLC3" mu = (1 + b ** 2 / a ** 2) / 4.0 delta = b * c * cos(alpha) / (2 * a ** 2) zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\ / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b phi = 1 + zeta - 2 * mu psi = eta - 2 * delta kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([1 - phi, 1 - phi, 1 - psi]), 'F_1': np.array([phi, phi - 1, psi]), 'F_2': np.array([1 - phi, -phi, 1 - psi]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([0.5, -0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "H", "Z", "I", "F_1"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc4(self, a, b, c, alpha): self.name = "MCLC4" mu = (1 + b ** 2 / a ** 2) / 4.0 delta = b * c * cos(alpha) / (2 * a ** 2) zeta = mu - 0.25 + (1 - b * cos(alpha) / c)\ / (4 * sin(alpha) ** 2) eta = 0.5 + 2 * zeta * c * cos(alpha) / b phi = 1 + zeta - 2 * mu psi = eta - 2 * delta kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([1 - phi, 1 - phi, 1 - psi]), 'F_1': np.array([phi, phi - 1, psi]), 'F_2': np.array([1 - phi, -phi, 1 - psi]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([0.5, -0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "H", "Z", "I"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def mclc5(self, a, b, c, alpha): self.name = "MCLC5" zeta = (b ** 2 / a ** 2 + (1 - b * cos(alpha) / c) / sin(alpha) ** 2) / 4 eta = 0.5 + 2 * zeta * c * cos(alpha) / b mu = eta / 2 + b ** 2 / (4 * a ** 2) \ - b * c * cos(alpha) / (2 * a ** 2) nu = 2 * mu - zeta rho = 1 - zeta * a ** 2 / b ** 2 omega = (4 * nu - 1 - b ** 2 * sin(alpha) ** 2 / a ** 2)\ * c / (2 * b * cos(alpha)) delta = zeta * c * cos(alpha) / b + omega / 2 - 0.25 kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'F': np.array([nu, nu, omega]), 'F_1': np.array([1 - nu, 1 - nu, 1 - omega]), 'F_2': np.array([nu, nu - 1, omega]), 'H': np.array([zeta, zeta, eta]), 'H_1': np.array([1 - zeta, -zeta, 1 - eta]), 'H_2': np.array([-zeta, -zeta, 1 - eta]), 'I': np.array([rho, 1 - rho, 0.5]), 'I_1': np.array([1 - rho, rho - 1, 0.5]), 'L': np.array([0.5, 0.5, 0.5]), 'M': np.array([0.5, 0.0, 0.5]), 'N': np.array([0.5, 0.0, 0.0]), 'N_1': np.array([0.0, -0.5, 0.0]), 'X': np.array([0.5, -0.5, 0.0]), 'Y': np.array([mu, mu, delta]), 'Y_1': np.array([1 - mu, -mu, -delta]), 'Y_2': np.array([-mu, -mu, -delta]), 'Y_3': np.array([mu, mu - 1, delta]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["\Gamma", "Y", "F", "L", "I"], ["I_1", "Z", "H", "F_1"], ["H_1", "Y_1", "X", "\Gamma", "N"], ["M", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def tria(self): self.name = "TRI1a" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([0.5, 0.5, 0.0]), 'M': np.array([0.0, 0.5, 0.5]), 'N': np.array([0.5, 0.0, 0.5]), 'R': np.array([0.5, 0.5, 0.5]), 'X': np.array([0.5, 0.0, 0.0]), 'Y': np.array([0.0, 0.5, 0.0]), 'Z': np.array([0.0, 0.0, 0.5])} path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"], ["N", "\Gamma", "M"], ["R", "\Gamma"]] return {'kpoints': kpoints, 'path': path} def trib(self): self.name = "TRI1b" kpoints = {'\Gamma': np.array([0.0, 0.0, 0.0]), 'L': np.array([0.5, -0.5, 0.0]), 'M': np.array([0.0, 0.0, 0.5]), 'N': np.array([-0.5, -0.5, 0.5]), 'R': np.array([0.0, -0.5, 0.5]), 'X': np.array([0.0, -0.5, 0.0]), 'Y': np.array([0.5, 0.0, 0.0]), 'Z': np.array([-0.5, 0.0, 0.5])} path = [["X", "\Gamma", "Y"], ["L", "\Gamma", "Z"], ["N", "\Gamma", "M"], ["R", "\Gamma"]] return {'kpoints': kpoints, 'path': path}