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: 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 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