def setUp(self): with open(os.path.join(test_dir, "CaO_2605_bandstructure.json"), "r", encoding="utf-8") as f: d = json.loads(f.read()) self.bs = BandStructureSymmLine.from_dict(d) self.plotter = BSPlotter(self.bs) self.assertEqual(len(self.plotter._bs), 1, "wrong number of band objects") with open(os.path.join(test_dir, "N2_12103_bandstructure.json"), "r", encoding="utf-8") as f: d = json.loads(f.read()) self.sbs_sc = BandStructureSymmLine.from_dict(d) with open(os.path.join(test_dir, "C_48_bandstructure.json"), "r", encoding="utf-8") as f: d = json.loads(f.read()) self.sbs_met = BandStructureSymmLine.from_dict(d) self.plotter_multi = BSPlotter([self.sbs_sc, self.sbs_met]) self.assertEqual(len(self.plotter_multi._bs), 2, "wrong number of band objects") self.assertEqual(self.plotter_multi._nb_bands, [96, 96], "wrong number of bands") warnings.simplefilter("ignore")
def setUp(self): with open(os.path.join(test_dir, "Cu2O_361_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs = BandStructureSymmLine.from_dict(d) self.assertListEqual( self.bs._projections[Spin.up][10][12][Orbital.s], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "wrong projections") self.assertListEqual( self.bs._projections[Spin.up][25][0][Orbital.dyz], [0.0, 0.0, 0.0011, 0.0219, 0.0219, 0.069], "wrong projections") self.assertAlmostEqual( self.bs.get_projection_on_elements()[Spin.up][25][10]['O'], 0.0328) self.assertAlmostEqual( self.bs.get_projection_on_elements()[Spin.up][22][25]['Cu'], 0.8327) self.assertAlmostEqual( self.bs.get_projections_on_elts_and_orbitals( {'Cu': ['s', 'd']})[Spin.up][25][0]['Cu']['s'], 0.0027) self.assertAlmostEqual( self.bs.get_projections_on_elts_and_orbitals( {'Cu': ['s', 'd']})[Spin.up][25][0]['Cu']['d'], 0.8495999999999999) with open(os.path.join(test_dir, "CaO_2605_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) #print d.keys() self.bs = BandStructureSymmLine.from_dict(d) #print self.bs.as_dict().keys() #this doesn't really test as_dict() -> from_dict very well #self.assertEqual(self.bs.as_dict().keys(), d.keys()) self.one_kpoint = self.bs.kpoints[31] self.assertEqual(self.bs._nb_bands, 16) self.assertAlmostEqual(self.bs._bands[Spin.up][5][10], 0.5608) self.assertAlmostEqual(self.bs._bands[Spin.up][5][10], 0.5608) self.assertEqual(self.bs._branches[5]['name'], "L-U") self.assertEqual(self.bs._branches[5]['start_index'], 80) self.assertEqual(self.bs._branches[5]['end_index'], 95) self.assertAlmostEqual(self.bs._distance[70], 4.2335127528765737) with open(os.path.join(test_dir, "NiO_19009_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs_spin = BandStructureSymmLine.from_dict(d) #this doesn't really test as_dict() -> from_dict very well #self.assertEqual(self.bs_spin.as_dict().keys(), d.keys()) self.assertEqual(self.bs_spin._nb_bands, 27) self.assertAlmostEqual(self.bs_spin._bands[Spin.up][5][10], 0.262) self.assertAlmostEqual(self.bs_spin._bands[Spin.down][5][10], 1.6156)
def setUp(self): with open(os.path.join(test_dir, "Cu2O_361_bandstructure.json"), "r", encoding="utf-8") as f: d = json.load(f) self.bs = BandStructureSymmLine.from_dict(d) with open(os.path.join(test_dir, "CaO_2605_bandstructure.json"), "r", encoding="utf-8") as f: d = json.load(f) self.bs2 = BandStructureSymmLine.from_dict(d) with open(os.path.join(test_dir, "NiO_19009_bandstructure.json"), "r", encoding="utf-8") as f: d = json.load(f) self.bs_spin = BandStructureSymmLine.from_dict(d)
def setUp(self): with open(os.path.join(test_dir, "CaO_2605_bandstructure.json"), "r", encoding='utf-8') as f: d = json.loads(f.read()) self.bs = BandStructureSymmLine.from_dict(d) self.plotter = BSPlotter(self.bs) warnings.simplefilter("ignore")
def get_band_structure(self): """Return a BandStructureSymmLine object interpolating bands along a High symmetry path calculated from the structure using HighSymmKpath function""" kpath = HighSymmKpath(self.data.structure) kpt_line = [ Kpoint(k, self.data.structure.lattice) for k in kpath.get_kpoints(coords_are_cartesian=False)[0] ] kpoints = np.array([kp.frac_coords for kp in kpt_line]) labels_dict = { l: k for k, l in zip(*kpath.get_kpoints(coords_are_cartesian=False)) if l } lattvec = self.data.get_lattvec() egrid, vgrid = fite.getBands(kpoints, self.equivalences, lattvec, self.coeffs) bands_dict = {Spin.up: (egrid / units.eV)} sbs = BandStructureSymmLine( kpoints, bands_dict, self.data.structure.lattice.reciprocal_lattice, self.efermi / units.eV, labels_dict=labels_dict) return sbs
def get_bands_symkpath(efermi=0., mode="tb"): comm = MPI.COMM_WORLD rank = comm.Get_rank() if rank == 0: gmodel = get_gmodel() kpath = get_symkpath() nk = (len(kpath.kpath["kpoints"])-1)*12 k_vec, k_dist, k_node = gmodel.k_path(kpath.kpath["kpoints"]. \ values(), nk) else: gmodel = kpath = k_vec = k_dist = k_node = None gmodel = comm.bcast(gmodel, root=0) kpath = comm.bcast(kpath, root=0) k_vec = comm.bcast(k_vec, root=0) k_dist = comm.bcast(k_dist, root=0) k_node = comm.bcast(k_node, root=0) bnd_es, bnd_vs = mpiget_bndev(k_vec, gmodel=gmodel, mode=mode) # prepare the args for pymatgen bs class. if rank == 0: eigenvals = {} eigenvals[Spin.up] = bnd_es[0].T if len(bnd_es) == 2: eigenvals[Spin.down] = bnd_es[1].T bs = BandStructureSymmLine(k_vec, eigenvals, \ kpath._structure.lattice.reciprocal_lattice, \ efermi, kpath.kpath["kpoints"]) else: bs = None return bs
def band_structure(bands_file, cell_file=None): """Convert band structure data from CASTEP to Pymatgen/Sumo format Args: bands_file (:obj:`str`): Path to CASTEP prefix.bands output file. The lattice parameters, k-point positions and eigenvalues are read from this file. cell_file (:obj:`str`, optional): Path to CASTEP prefix.cell input file. If found, the positions of high-symmetry points are read from the ``[bs|spectral]_kpoint(s)_[path|list]`` block in this file. Returns: :obj:`pymatgen.electronic_structure.bandstructure.BandStructureSymmLine` """ header = _read_bands_header_verbose(bands_file) lattice = Lattice(header['lattice_vectors']) lattice = Lattice(lattice.matrix * _bohr_to_angstrom) logging.info("Reading band structure eigenvalues...") kpoints, _, eigenvalues = read_bands_eigenvalues(bands_file, header) if cell_file is None: labels = {} else: labels = labels_from_cell(cell_file) return BandStructureSymmLine(kpoints, eigenvalues, lattice.reciprocal_lattice_crystallographic, header['e_fermi'][0] * _ry_to_ev * 2, labels, coords_are_cartesian=False)
def setUp(self): with open(os.path.join(test_dir, "CaO_2605_bandstructure.json"), "r", encoding='utf-8') as f: d = json.loads(f.read()) self.bs = BandStructureSymmLine.from_dict(d) self.plotter = BSPlotter(self.bs)
def extract_bs(mat): bs = None # Process the bandstructure for information if "bs" in mat["bandstructure"]: bs_dict = mat["bandstructure"]["bs"] # Add in structure if not already there if "structure" not in bs_dict: bs_dict["structure"] = mat["structure"] # Add in High Symm K Path if not already there if len(bs_dict.get("labels_dict", {})) == 0: labels = get(mat, "inputs.nscf_line.kpoints.labels", None) kpts = get(mat, "inputs.nscf_line.kpoints.kpoints", None) if labels and kpts: labels_dict = dict(zip(labels, kpts)) labels_dict.pop(None, None) else: struc = Structure.from_dict(mat["structure"]) labels_dict = HighSymmKpath(struc)._kpath["kpoints"] bs_dict["labels_dict"] = labels_dict bs = BandStructureSymmLine.from_dict( BandStructure.from_dict(bs_dict).as_dict()) return bs
def test_old_format_load(self): with open(os.path.join(test_dir, "bs_ZnS_old.json"), "r", encoding='utf-8') as f: d = json.load(f) bs_old = BandStructureSymmLine.from_dict(d) self.assertEqual(bs_old.get_projection_on_elements()[ Spin.up][0][0]['Zn'], 0.0971)
def setUp(self): with open(os.path.join(test_dir, 'si_structure.json'), 'r') as sth: si_str = Structure.from_dict(json.load(sth)) with open(os.path.join(test_dir, 'si_bandstructure_line.json'), 'r') as bsh: si_bs_line = BandStructureSymmLine.from_dict(json.load(bsh)) si_bs_line.structure = si_str with open(os.path.join(test_dir, 'si_bandstructure_uniform.json'), 'r') as bsh: si_bs_uniform = BandStructure.from_dict(json.load(bsh)) si_bs_uniform.structure = si_str self.si_kpts = list(HighSymmKpath(si_str).kpath['kpoints'].values()) self.df = pd.DataFrame({ 'bs_line': [si_bs_line], 'bs_uniform': [si_bs_uniform] }) with open(os.path.join(test_dir, 'VBr2_971787_bandstructure.json'), 'r') as bsh: vbr2_uniform = BandStructure.from_dict(json.load(bsh)) self.vbr2kpts = [ k.frac_coords for k in vbr2_uniform.labels_dict.values() ] self.vbr2kpts = [ [0.0, 0.0, 0.0], # \\Gamma [0.2, 0.0, 0.0], # between \\Gamma and M [0.5, 0.0, 0.0], # M [0.5, 0.0, 0.5] ] # L self.df2 = pd.DataFrame({'bs_line': [vbr2_uniform]})
def setUp(self): with open(os.path.join(test_dir, "Cu2O_361_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs = BandStructureSymmLine.from_dict(d) self.plotter = BSPlotterProjected(self.bs) warnings.simplefilter("ignore")
def read_band_structure(self): raise NotImplementedError("") structure = self.read_structure() from pprint import pprint kpoints = self.read_value("reduced_coordinates_of_kpoints") efermi = Ha2eV(self.read_value("fermie")) np_eigvals = Ha2eV(self.read_value("eigenvalues")) # TODO #assert np_eigvals.units == "atomic units" nsppol = np_eigvals.shape[0] # FIXME: Here I need the labels labels_dict = {} for (i, kpoint) in enumerate(kpoints): labels_dict[str(i)] = kpoint eigenvals = {} for isp in range(nsppol): spin = Spin.up if isp == 1: spin = Spin.down eigenvals[spin] = np_eigvals[isp,:,:].transpose() print(eigenvals[spin].shape) #tmp = np_eigvals[isp,:,:].transpose() #bands = BandStructure(kpoints, eigenvals, structure.lattice, efermi, # labels_dict=None, structure=structure) bands = BandStructureSymmLine(kpoints, eigenvals, structure.lattice, efermi, labels_dict, structure=structure) return bands
def test_old_format_load(self): with open(os.path.join(PymatgenTest.TEST_FILES_DIR, "bs_ZnS_old.json"), encoding="utf-8") as f: d = json.load(f) bs_old = BandStructureSymmLine.from_dict(d) self.assertEqual( bs_old.get_projection_on_elements()[Spin.up][0][0]["Zn"], 0.0971)
def setUp(self): with open(os.path.join(PymatgenTest.TEST_FILES_DIR, "Cu2O_361_bandstructure.json"), encoding="utf-8") as f: d = json.load(f) self.bs = BandStructureSymmLine.from_dict(d) self.plotter = BSPlotterProjected(self.bs) warnings.simplefilter("ignore")
def setUp(self): with open(os.path.join(test_dir, "Cu2O_361_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs = BandStructureSymmLine.from_dict(d) with open(os.path.join(test_dir, "CaO_2605_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs2 = BandStructureSymmLine.from_dict(d) with open(os.path.join(test_dir, "NiO_19009_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs_spin = BandStructureSymmLine.from_dict(d)
def get_bs(db_file): """ return bandstructure object from the database """ d1, d2, d3, d4 = get_collections(db_file) db = get_db(db_file) fs = gridfs.GridFS(db, 'bandstructure_fs') bs_fs_id = d3["calcs_reversed"][0]["bandstructure_fs_id"] bs_json = zlib.decompress(fs.get(bs_fs_id).read()) bs_dict = json.loads(bs_json.decode()) return BandStructureSymmLine.from_dict(bs_dict)
def get_line_mode_band_structure( self, line_density: int = 50, energy_cutoff: Optional[float] = None, scissor: Optional[float] = None, bandgap: Optional[float] = None, symprec: float = 0.01, ) -> BandStructureSymmLine: """Gets the interpolated band structure along high symmetry directions. Args: line_density: The maximum number of k-points between each two consecutive high-symmetry k-points energy_cutoff: The energy cut-off to determine which bands are included in the interpolation. If the energy of a band falls within the cut-off at any k-point it will be included. For metals the range is defined as the Fermi level ± energy_cutoff. For gapped materials, the energy range is from the VBM - energy_cutoff to the CBM + energy_cutoff. scissor: The amount by which the band gap is scissored. Cannot be used in conjunction with the ``bandgap`` option. Has no effect for metallic systems. bandgap: Automatically adjust the band gap to this value. Cannot be used in conjunction with the ``scissor`` option. Has no effect for metallic systems. symprec: The symmetry tolerance used to determine the space group and high-symmetry path. Returns: The line mode band structure. """ hsk = HighSymmKpath(self._band_structure.structure, symprec=symprec) kpoints, labels = hsk.get_kpoints(line_density=line_density, coords_are_cartesian=True) labels_dict = { label: kpoint for kpoint, label in zip(kpoints, labels) if label != "" } energies = self.get_energies( kpoints, scissor=scissor, bandgap=bandgap, atomic_units=False, energy_cutoff=energy_cutoff, coords_are_cartesian=True, ) return BandStructureSymmLine( kpoints, energies, self._band_structure.structure.lattice, self._band_structure.efermi, labels_dict, coords_are_cartesian=True, )
def get_band_structure(self, kpaths=None, kpoints_lbls_dict=None, density=20): """ Return a BandStructureSymmLine object interpolating bands along a High symmetry path calculated from the structure using HighSymmKpath function. If kpaths and kpoints_lbls_dict are provided, a custom path is interpolated. kpaths: List of lists of following kpoints labels defining the segments of the path. E.g. [['L','M'],['L','X']] kpoints_lbls_dict: Dict where keys are the kpoint labels used in kpaths and values are their fractional coordinates. E.g. {'L':np.array(0.5,0.5,0.5)}, 'M':np.array(0.5,0.,0.5), 'X':np.array(0.5,0.5,0.)} density: Number of points in each segment. """ if isinstance(kpaths, list) and isinstance(kpoints_lbls_dict, dict): kpoints = [] for kpath in kpaths: for i, k in enumerate(kpath[:-1]): sta = kpoints_lbls_dict[kpath[i]] end = kpoints_lbls_dict[kpath[i + 1]] kpoints.append(np.linspace(sta, end, density)) kpoints = np.concatenate(kpoints) else: kpath = HighSymmKpath(self.data.structure) kpoints = np.vstack( kpath.get_kpoints(density, coords_are_cartesian=False)[0]) kpoints_lbls_dict = kpath.kpath["kpoints"] lattvec = self.data.get_lattvec() egrid, vgrid = fite.getBands(kpoints, self.equivalences, lattvec, self.coeffs) # print(egrid.shape) if self.data.is_spin_polarized: h = sum(np.array_split(self.accepted, 2)[0]) egrid = np.array_split(egrid, [h], axis=0) bands_dict = { Spin.up: (egrid[0] / units.eV), Spin.down: (egrid[1] / units.eV), } else: bands_dict = {Spin.up: (egrid / units.eV)} sbs = BandStructureSymmLine( kpoints, bands_dict, self.data.structure.lattice.reciprocal_lattice, self.efermi / units.eV, labels_dict=kpoints_lbls_dict, ) return sbs
def get_band_structure(self, task_id, line_mode=False): m_task = self.collection.find_one({"task_id": task_id}, {"calcs_reversed": 1}) fs_id = m_task['calcs_reversed'][0]['bandstructure_fs_id'] fs = gridfs.GridFS(self.db, 'bandstructure_fs') bs_json = zlib.decompress(fs.get(fs_id).read()) bs_dict = json.loads(bs_json) if line_mode: return BandStructureSymmLine.from_dict(bs_dict) else: return BandStructure.from_dict(bs_dict)
def get_BandStructureSymmLine(self): eigenvalues = self.eigenvalues eigendict = {Spin.up: eigenvalues} highsymmkpath = HighSymmKpath( self.get_Structure().get_primitive_structure()).kpath return BandStructureSymmLine(efermi=self.fermi_energy, eigenvals=eigendict, kpoints=self.k_points, structure=self.get_Structure(), labels_dict=highsymmkpath['kpoints'], lattice=self.get_reciprocal_Lattice())
def update_dosbandsfig(n_clicks, dos, bs, projlist): ## figure updates when the inputs change or the button is clicked ## figure does NOT update when elements or orbitals are selected ## de-serialize dos and bs from json format to pymatgen objects if dos: dos = CompleteDos.from_dict(json.loads(dos)) if bs: bs = BandStructureSymmLine.from_dict(json.loads(bs)) ## update the band structure and dos figure dosbandfig = BandsFig().generate_fig(dos, bs, projlist) return dosbandfig
def get_band_structure(self, task_id): m_task = self.collection.find_one({"task_id": task_id}, {"calcs_reversed": 1}) fs_id = m_task['calcs_reversed'][0]['bandstructure_fs_id'] fs = gridfs.GridFS(self.db, 'bandstructure_fs') bs_json = zlib.decompress(fs.get(fs_id).read()) bs_dict = json.loads(bs_json.decode()) if bs_dict["@class"] == "BandStructure": return BandStructure.from_dict(bs_dict) elif bs_dict["@class"] == "BandStructureSymmLine": return BandStructureSymmLine.from_dict(bs_dict) else: raise ValueError("Unknown class for band structure! {}".format(bs_dict["@class"]))
def setUp(self): with open(os.path.join(test_dir, "Cu2O_361_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs = BandStructureSymmLine.from_dict(d) self.assertListEqual(self.bs._projections[Spin.up][10][12][Orbital.s], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "wrong projections") self.assertListEqual(self.bs._projections[Spin.up][25][0][Orbital.dyz], [0.0, 0.0, 0.0011, 0.0219, 0.0219, 0.069], "wrong projections") self.assertAlmostEqual(self.bs.get_projection_on_elements()[Spin.up][25][10]['O'], 0.0328) self.assertAlmostEqual(self.bs.get_projection_on_elements()[Spin.up][22][25]['Cu'], 0.8327) self.assertAlmostEqual(self.bs.get_projections_on_elts_and_orbitals({'Cu':['s','d']})[Spin.up][25][0]['Cu']['s'], 0.0027) self.assertAlmostEqual(self.bs.get_projections_on_elts_and_orbitals({'Cu':['s','d']})[Spin.up][25][0]['Cu']['d'], 0.8495999999999999) with open(os.path.join(test_dir, "CaO_2605_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) #print d.keys() self.bs = BandStructureSymmLine.from_dict(d) #print self.bs.as_dict().keys() #this doesn't really test as_dict() -> from_dict very well #self.assertEqual(self.bs.as_dict().keys(), d.keys()) self.one_kpoint = self.bs.kpoints[31] self.assertEqual(self.bs._nb_bands, 16) self.assertAlmostEqual(self.bs._bands[Spin.up][5][10], 0.5608) self.assertAlmostEqual(self.bs._bands[Spin.up][5][10], 0.5608) self.assertEqual(self.bs._branches[5]['name'], "L-U") self.assertEqual(self.bs._branches[5]['start_index'], 80) self.assertEqual(self.bs._branches[5]['end_index'], 95) self.assertAlmostEqual(self.bs._distance[70], 4.2335127528765737) with open(os.path.join(test_dir, "NiO_19009_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs_spin = BandStructureSymmLine.from_dict(d) #this doesn't really test as_dict() -> from_dict very well #self.assertEqual(self.bs_spin.as_dict().keys(), d.keys()) self.assertEqual(self.bs_spin._nb_bands, 27) self.assertAlmostEqual(self.bs_spin._bands[Spin.up][5][10], 0.262) self.assertAlmostEqual(self.bs_spin._bands[Spin.down][5][10], 1.6156)
def get_band_structure(self, task_id): """ Read the BS data into a PMG BandStructure or BandStructureSymmLine object Args: task_id(int or str): the task_id containing the data Returns: BandStructure or BandStructureSymmLine """ obj_dict = self.get_data_from_maggma_or_gridfs(task_id, key="bandstructure") if obj_dict["@class"] == "BandStructure": return BandStructure.from_dict(obj_dict) elif obj_dict["@class"] == "BandStructureSymmLine": return BandStructureSymmLine.from_dict(obj_dict) else: raise ValueError("Unknown class for band structure! {}".format( obj_dict["@class"]))
def setUp(self): with open(os.path.join(test_dir, 'si_structure.json'), 'r') as sth: si_str = Structure.from_dict(json.load(sth)) with open(os.path.join(test_dir, 'si_bandstructure_line.json'), 'r') as bsh: si_bs_line = BandStructureSymmLine.from_dict(json.load(bsh)) si_bs_line.structure = si_str with open(os.path.join(test_dir, 'si_bandstructure_uniform.json'), 'r') as bsh: si_bs_uniform = BandStructure.from_dict(json.load(bsh)) si_bs_uniform.structure = si_str self.si_kpts = list(HighSymmKpath(si_str).kpath['kpoints'].values()) self.df = pd.DataFrame({ 'bs_line': [si_bs_line], 'bs_uniform': [si_bs_uniform] })
def _get_bs_dos(data): data = data or {} # this component can be loaded either from mpid or # directly from BandStructureSymmLine or CompleteDos objects # if mpid is supplied, this is preferred mpid = data.get("mpid") bandstructure_symm_line = data.get("bandstructure_symm_line") density_of_states = data.get("density_of_states") if not mpid and (bandstructure_symm_line is None or density_of_states is None): return None, None if mpid: with MPRester() as mpr: try: bandstructure_symm_line = mpr.get_bandstructure_by_material_id( mpid) except Exception as exc: print(exc) bandstructure_symm_line = None try: density_of_states = mpr.get_dos_by_material_id(mpid) except Exception as exc: print(exc) density_of_states = None else: if bandstructure_symm_line and isinstance(bandstructure_symm_line, dict): bandstructure_symm_line = BandStructureSymmLine.from_dict( bandstructure_symm_line) if density_of_states and isinstance(density_of_states, dict): density_of_states = CompleteDos.from_dict(density_of_states) return bandstructure_symm_line, density_of_states
def build_bs(bs_dict, mat): bs_dict["structure"] = mat["structure"] # Add in High Symm K Path if not already there if len(bs_dict.get("labels_dict", {})) == 0: labels = get(mat, "inputs.nscf_line.kpoints.labels", None) kpts = get(mat, "inputs.nscf_line.kpoints.kpoints", None) if labels and kpts: labels_dict = dict(zip(labels, kpts)) labels_dict.pop(None, None) else: struc = Structure.from_dict(bs_dict["structure"]) labels_dict = HighSymmKpath(struc)._kpath["kpoints"] bs_dict["labels_dict"] = labels_dict # This is somethign to do with BandStructureSymmLine's from dict being problematic bs = BandStructureSymmLine.from_dict(bs_dict) return bs
def setUp(self): with open(os.path.join(test_dir, 'si_structure.json'),'r') as sth: si_str = Structure.from_dict(json.load(sth)) with open(os.path.join(test_dir, 'si_bandstructure_line.json'),'r') as bsh: si_bs_line = BandStructureSymmLine.from_dict(json.load(bsh)) si_bs_line.structure = si_str with open(os.path.join(test_dir, 'si_bandstructure_uniform.json'),'r') as bsh: si_bs_uniform = BandStructure.from_dict(json.load(bsh)) si_bs_uniform.structure = si_str self.si_kpts = list(HighSymmKpath(si_str).kpath['kpoints'].values()) self.df = pd.DataFrame({'bs_line': [si_bs_line], 'bs_uniform': [si_bs_uniform]}) with open(os.path.join(test_dir, 'VBr2_971787_bandstructure.json'), 'r') as bsh: vbr2_uniform = BandStructure.from_dict(json.load(bsh)) self.vbr2kpts = [k.frac_coords for k in vbr2_uniform.labels_dict.values()] self.vbr2kpts = [[0.0, 0.0, 0.0], # \\Gamma [0.2, 0.0, 0.0], # between \\Gamma and M [0.5, 0.0, 0.0], # M [0.5, 0.0, 0.5]] # L self.df2 = pd.DataFrame({'bs_line': [vbr2_uniform]})
def get_line_mode_band_structure( self, line_density: int = 50, kpath: Optional[Kpath] = None, symprec: Optional[float] = defaults["symprec"], return_other_properties: bool = False, ) -> Union[ BandStructureSymmLine, Tuple[BandStructureSymmLine, Dict[Spin, Dict[str, np.ndarray]]], ]: """Gets the interpolated band structure along high symmetry directions. Args: line_density: The maximum number of k-points between each two consecutive high-symmetry k-points symprec: The symmetry tolerance used to determine the space group and high-symmetry path. return_other_properties: Whether to include the interpolated other_properties data for each k-point along the band structure path. Returns: The line mode band structure. """ if not kpath: kpath = PymatgenKpath(self.structure, symprec=symprec) kpoints, labels = kpath.get_kpoints(line_density=line_density, cart_coords=True) labels_dict = { label: kpoint for kpoint, label in zip(kpoints, labels) if label != "" } rlat = self.structure.lattice.reciprocal_lattice frac_kpoints = rlat.get_fractional_coords(kpoints) energies = {} other_properties = defaultdict(dict) for spin in self.spins: energies[spin] = self._interpolate_spin( spin, frac_kpoints, self.bs_interpolator ) if return_other_properties: for prop, property_interpolator in self.property_interpolators.items(): other_properties[spin][prop] = self._interpolate_spin( spin, frac_kpoints, property_interpolator ) bs = BandStructureSymmLine( kpoints, energies, rlat, self.efermi, labels_dict, coords_are_cartesian=True, structure=self.structure, ) if return_other_properties: return bs, other_properties else: return bs
def get_continuous_path(bandstructure): """ Obtain a continous version of an inputted path using graph theory. This routine will attempt to add connections between nodes of odd-degree to ensure a Eulerian path can be formed. Initial k-path must be able to be converted to a connected graph. See npj Comput Mater 6, 112 (2020). 10.1038/s41524-020-00383-7 for more details. Args: bandstructure (BandstructureSymmLine): BandstructureSymmLine object. Returns: bandstructure (BandstructureSymmLine): New BandstructureSymmLine object with continous path. """ G = nx.Graph() labels = [] for point in bandstructure.kpoints: if point.label is not None: labels.append(point.label) plot_axis = [] for i in range(int(len(labels) / 2)): G.add_edges_from([(labels[2 * i], labels[(2 * i) + 1])]) plot_axis.append((labels[2 * i], labels[(2 * i) + 1])) G_euler = nx.algorithms.euler.eulerize(G) G_euler_circuit = nx.algorithms.euler.eulerian_circuit(G_euler) distances_map = [] kpath_euler = [] for edge_euler in G_euler_circuit: kpath_euler.append(edge_euler) for edge_reg in plot_axis: if edge_euler == edge_reg: distances_map.append((plot_axis.index(edge_reg), False)) elif edge_euler[::-1] == edge_reg: distances_map.append((plot_axis.index(edge_reg), True)) if bandstructure.is_spin_polarized: spins = [Spin.up, Spin.down] else: spins = [Spin.up] new_kpoints = [] new_bands = { spin: [np.array([]) for _ in range(bandstructure.nb_bands)] for spin in spins } new_projections = { spin: [[] for _ in range(bandstructure.nb_bands)] for spin in spins } for entry in distances_map: if not entry[1]: branch = bandstructure.branches[entry[0]] start = branch["start_index"] stop = branch["end_index"] + 1 step = 1 else: branch = bandstructure.branches[entry[0]] start = branch["end_index"] stop = branch["start_index"] - 1 step = -1 # kpoints new_kpoints += [ point.frac_coords for point in bandstructure.kpoints[start:stop:step] ] # eigenvals for spin in spins: for n, band in enumerate(bandstructure.bands[spin]): new_bands[spin][n] = np.concatenate( (new_bands[spin][n], band[start:stop:step])) # projections for spin in spins: for n, band in enumerate(bandstructure.projections[spin]): new_projections[spin][n] += band[start:stop:step].tolist() for spin in spins: new_projections[spin] = np.array(new_projections[spin]) new_labels_dict = { label: point.frac_coords for label, point in bandstructure.labels_dict.items() } new_bandstructure = BandStructureSymmLine( kpoints=new_kpoints, eigenvals=new_bands, lattice=bandstructure.lattice_rec, efermi=bandstructure.efermi, labels_dict=new_labels_dict, structure=bandstructure.structure, projections=new_projections, ) return new_bandstructure
def get_line_mode_band_structure( self, line_density: int = 50, kpath: Optional[Kpath] = None, energy_cutoff: Optional[float] = None, scissor: Optional[float] = None, bandgap: Optional[float] = None, symprec: float = defaults["symprec"], return_other_properties: bool = False, ) -> Union[BandStructureSymmLine, Tuple[BandStructureSymmLine, Dict[ Spin, Dict[str, np.ndarray]]], ]: """Gets the interpolated band structure along high symmetry directions. Args: line_density: The maximum number of k-points between each two consecutive high-symmetry k-points energy_cutoff: The energy cut-off to determine which bands are included in the interpolation. If the energy of a band falls within the cut-off at any k-point it will be included. For metals the range is defined as the Fermi level ± energy_cutoff. For gapped materials, the energy range is from the VBM - energy_cutoff to the CBM + energy_cutoff. scissor: The amount by which the band gap is scissored. Cannot be used in conjunction with the ``bandgap`` option. Has no effect for metallic systems. bandgap: Automatically adjust the band gap to this value. Cannot be used in conjunction with the ``scissor`` option. Has no effect for metallic systems. symprec: The symmetry tolerance used to determine the space group and high-symmetry path. return_other_properties: Whether to include the interpolated other_properties data for each k-point along the band structure path. Returns: The line mode band structure. """ if not kpath: kpath = PymatgenKpath(self._band_structure.structure, symprec=symprec) kpoints, labels = kpath.get_kpoints(line_density=line_density, cart_coords=True) labels_dict = { label: kpoint for kpoint, label in zip(kpoints, labels) if label != "" } energies = self.get_energies( kpoints, scissor=scissor, bandgap=bandgap, atomic_units=False, energy_cutoff=energy_cutoff, coords_are_cartesian=True, return_other_properties=return_other_properties, symprec=symprec, ) if return_other_properties: energies, other_properties = energies bs = BandStructureSymmLine( kpoints, energies, self._band_structure.structure.lattice, self._band_structure.efermi, labels_dict, coords_are_cartesian=True, ) if return_other_properties: return bs, other_properties else: return bs
def process_item(self, mat): """ Process the tasks and materials into just a list of materials Args: mat (dict): material document Returns: (dict): electronic_structure document """ self.logger.info("Processing: {}".format(mat[self.materials.key])) d = {self.electronic_structure.key: mat[ self.materials.key], "bandstructure": {}} bs = None dos = None interpolated_dos = None # Process the bandstructure for information if "bs" in mat["bandstructure"]: if "structure" not in mat["bandstructure"]["bs"]: mat["bandstructure"]["bs"]["structure"] = mat["structure"] if len(mat["bandstructure"]["bs"].get("labels_dict", {})) == 0: struc = Structure.from_dict(mat["structure"]) kpath = HighSymmKpath(struc)._kpath["kpoints"] mat["bandstructure"]["bs"]["labels_dict"] = kpath # Somethign is wrong with the as_dict / from_dict encoding in the two band structure objects so have to use this hodge podge serialization # TODO: Fix bandstructure objects in pymatgen bs = BandStructureSymmLine.from_dict( BandStructure.from_dict(mat["bandstructure"]["bs"]).as_dict()) d["bandstructure"]["band_gap"] = {"band_gap": bs.get_band_gap()["energy"], "direct_gap": bs.get_direct_band_gap(), "is_direct": bs.get_band_gap()["direct"], "transition": bs.get_band_gap()["transition"]} if self.small_plot: d["bandstructure"]["plot_small"] = get_small_plot(bs) if "dos" in mat["bandstructure"]: dos = CompleteDos.from_dict(mat["bandstructure"]["dos"]) if self.interpolate_dos and "uniform_bs" in mat["bandstructure"]: try: interpolated_dos = self.get_interpolated_dos(mat) except Exception: self.logger.warning("Boltztrap interpolation failed for {}. Continuing with regular DOS".format(mat[self.materials.key])) # Generate static images if self.static_images: try: ylim = None if bs: plotter = WebBSPlotter(bs) fig = plotter.get_plot() ylim = fig.ylim() # Used by DOS plot fig.close() d["bandstructure"]["bs_plot"] = image_from_plotter(plotter) if dos: plotter = WebDosVertPlotter() plotter.add_dos_dict(dos.get_element_dos()) if interpolated_dos: plotter.add_dos("Total DOS", interpolated_dos) d["bandstructure"]["dos_plot"] = image_from_plotter(plotter, ylim=ylim) d["bandstructure"]["dos_plot"] = image_from_plotter(plotter, ylim=ylim) except Exception: self.logger.warning( "Caught error in electronic structure plotting for {}: {}".format(mat[self.materials.key], traceback.format_exc())) return None return d
def bs_dos_traces(bandStructureSymmLine, densityOfStates): if bandStructureSymmLine == "error" or densityOfStates == "error": return "error" if bandStructureSymmLine == None or densityOfStates == None: raise PreventUpdate # - BS Data bstraces = [] bs_reg_plot = BSPlotter(BSML.from_dict(bandStructureSymmLine)) bs_data = bs_reg_plot.bs_plot_data() # -- Strip latex math wrapping str_replace = { "$": "", "\\mid": "|", "\\Gamma": "Γ", "\\Sigma": "Σ", "_1": "₁", "_2": "₂", "_3": "₃", "_4": "₄", } for entry_num in range(len(bs_data["ticks"]["label"])): for key in str_replace.keys(): if key in bs_data["ticks"]["label"][entry_num]: bs_data["ticks"]["label"][entry_num] = bs_data[ "ticks"]["label"][entry_num].replace( key, str_replace[key]) for d in range(len(bs_data["distances"])): for i in range(bs_reg_plot._nb_bands): bstraces.append( go.Scatter( x=bs_data["distances"][d], y=[ bs_data["energy"][d][str(Spin.up)][i][j] for j in range(len(bs_data["distances"][d])) ], mode="lines", line=dict(color=("#666666"), width=2), hoverinfo="skip", showlegend=False, )) if bs_reg_plot._bs.is_spin_polarized: bstraces.append( go.Scatter( x=bs_data["distances"][d], y=[ bs_data["energy"][d][str(Spin.down)][i][j] for j in range(len(bs_data["distances"] [d])) ], mode="lines", line=dict(color=("#666666"), width=2, dash="dash"), hoverinfo="skip", showlegend=False, )) # -- DOS Data dostraces = [] dos = CompleteDos.from_dict(densityOfStates) if Spin.down in dos.densities: # Add second spin data if available trace_tdos = go.Scatter( x=dos.densities[Spin.down], y=dos.energies - dos.efermi, mode="lines", name="Total DOS (spin ↓)", line=go.scatter.Line(color="#444444", dash="dash"), fill="tozeroy", ) dostraces.append(trace_tdos) tdos_label = "Total DOS (spin ↑)" else: tdos_label = "Total DOS" # Total DOS trace_tdos = go.Scatter( x=dos.densities[Spin.up], y=dos.energies - dos.efermi, mode="lines", name=tdos_label, line=go.scatter.Line(color="#444444"), fill="tozeroy", legendgroup="spinup", ) dostraces.append(trace_tdos) p_ele_dos = dos.get_element_dos() # Projected DOS count = 0 colors = [ "#1f77b4", # muted blue "#ff7f0e", # safety orange "#2ca02c", # cooked asparagus green "#d62728", # brick red "#9467bd", # muted purple "#8c564b", # chestnut brown "#e377c2", # raspberry yogurt pink "#bcbd22", # curry yellow-green "#17becf", # blue-teal ] for ele in p_ele_dos.keys(): if bs_reg_plot._bs.is_spin_polarized: trace = go.Scatter( x=p_ele_dos[ele].densities[Spin.down], y=dos.energies - dos.efermi, mode="lines", name=ele.symbol + " (spin ↓)", line=dict(width=3, color=colors[count], dash="dash"), ) dostraces.append(trace) spin_up_label = ele.symbol + " (spin ↑)" else: spin_up_label = ele.symbol trace = go.Scatter( x=p_ele_dos[ele].densities[Spin.up], y=dos.energies - dos.efermi, mode="lines", name=spin_up_label, line=dict(width=3, color=colors[count]), ) dostraces.append(trace) count += 1 traces = [bstraces, dostraces, bs_data] return traces
def setUp(self): with open(os.path.join(test_dir, "Cu2O_361_bandstructure.json"), "r", encoding='utf-8') as f: d = json.load(f) self.bs = BandStructureSymmLine.from_dict(d) self.plotter = BSPlotterProjected(self.bs)
def get_reconstructed_band_structure(list_bs, efermi=None): """Combine a list of band structures into a single band structure. This is typically very useful when you split non self consistent band structure runs in several independent jobs and want to merge back the results. This method will also ensure that any BandStructure objects will contain branches. Args: list_bs (:obj:`list` of \ :obj:`~pymatgen.electronic_structure.bandstructure.BandStructure` \ or :obj:`~pymatgen.electronic_structure.bandstructure.BandStructureSymmLine`): The band structures. efermi (:obj:`float`, optional): The Fermi energy of the reconstructed band structure. If `None`, an average of all the Fermi energies across all band structures is used. Returns: :obj:`pymatgen.electronic_structure.bandstructure.BandStructure` or \ :obj:`pymatgen.electronic_structure.bandstructureBandStructureSymmLine`: A band structure object. The type depends on the type of the band structures in ``list_bs``. """ if efermi is None: efermi = sum([b.efermi for b in list_bs]) / len(list_bs) kpoints = [] labels_dict = {} rec_lattice = list_bs[0].lattice_rec nb_bands = min([list_bs[i].nb_bands for i in range(len(list_bs))]) kpoints = np.concatenate([[k.frac_coords for k in bs.kpoints] for bs in list_bs]) dicts = [bs.labels_dict for bs in list_bs] labels_dict = {k: v.frac_coords for d in dicts for k, v in d.items()} # pymatgen band structure objects support branches. These are formed when # two kpoints with the same label are next to each other. This bit of code # will ensure that the band structure will contain branches, if it doesn't # already. dup_ids = [] for i, k in enumerate(kpoints): dup_ids.append(i) if (tuple(k) in tuple(map(tuple, labels_dict.values())) and i != 0 and i != len(kpoints) - 1 and (not np.array_equal(kpoints[i + 1], k) or not np.array_equal(kpoints[i - 1], k))): dup_ids.append(i) kpoints = kpoints[dup_ids] eigenvals = {} eigenvals[Spin.up] = np.concatenate( [bs.bands[Spin.up][:nb_bands] for bs in list_bs], axis=1) eigenvals[Spin.up] = eigenvals[Spin.up][:, dup_ids] if list_bs[0].is_spin_polarized: eigenvals[Spin.down] = np.concatenate( [bs.bands[Spin.down][:nb_bands] for bs in list_bs], axis=1) eigenvals[Spin.down] = eigenvals[Spin.up][:, dup_ids] projections = {} if len(list_bs[0].projections) != 0: projs = [bs.projections[Spin.up][:nb_bands][dup_ids] for bs in list_bs] projections[Spin.up] = np.concatenate(projs, axis=1)[:, dup_ids] if list_bs[0].is_spin_polarized: projs = [ bs.projections[Spin.down][:nb_bands][dup_ids] for bs in list_bs ] projections[Spin.down] = np.concatenate(projs, axis=1)[:, dup_ids] if isinstance(list_bs[0], BandStructureSymmLine): return BandStructureSymmLine(kpoints, eigenvals, rec_lattice, efermi, labels_dict, structure=list_bs[0].structure, projections=projections) else: return BandStructure(kpoints, eigenvals, rec_lattice, efermi, labels_dict, structure=list_bs[0].structure, projections=projections)
def setUp(self): with open(os.path.join(test_dir, "CaO_2605_bandstructure.json"), "rb") as f: d = json.loads(f.read()) self.bs = BandStructureSymmLine.from_dict(d) self.plotter = BSPlotter(self.bs)