Returns the band structure as a BandStructure object

        Args:
            kpoints_filename (str): Full path of the KPOINTS file from which
                the band structure is generated.
                If none is provided, the code will try to intelligently
                determine the appropriate KPOINTS file by substituting the
                filename of the vasprun.xml with KPOINTS.
                The latter is the default behavior.
            efermi (float): If you want to specify manually the fermi energy
                this is where you should do it. By default, the None value
                means the code will get it from the vasprun.
            line_mode (bool): Force the band structure to be considered as
                a run along symmetry lines.
            force_hybrid_mode (bool): Makes it possible to read in self-consistent band structure calculations for every type of functional

        Returns:
            a BandStructure object (or more specifically a
            BandStructureSymmLine object if the run is detected to be a run
            along symmetry lines)

            Two types of runs along symmetry lines are accepted: non-sc with
            Line-Mode in the KPOINT file or hybrid, self-consistent with a
            uniform grid+a few kpoints along symmetry lines (explicit KPOINTS
            file) (it's not possible to run a non-sc band structure with hybrid
            functionals). The explicit KPOINTS file needs to have data on the
            kpoint label as commentary.

def get_band_structure(self, kpoints_filename=None, efermi=None,
                           line_mode=False, force_hybrid_mode=False):
        """
        Returns the band structure as a BandStructure object

        Args:
            kpoints_filename (str): Full path of the KPOINTS file from which
                the band structure is generated.
                If none is provided, the code will try to intelligently
                determine the appropriate KPOINTS file by substituting the
                filename of the vasprun.xml with KPOINTS.
                The latter is the default behavior.
            efermi (float): If you want to specify manually the fermi energy
                this is where you should do it. By default, the None value
                means the code will get it from the vasprun.
            line_mode (bool): Force the band structure to be considered as
                a run along symmetry lines.
            force_hybrid_mode (bool): Makes it possible to read in self-consistent band structure calculations for every type of functional

        Returns:
            a BandStructure object (or more specifically a
            BandStructureSymmLine object if the run is detected to be a run
            along symmetry lines)

            Two types of runs along symmetry lines are accepted: non-sc with
            Line-Mode in the KPOINT file or hybrid, self-consistent with a
            uniform grid+a few kpoints along symmetry lines (explicit KPOINTS
            file) (it's not possible to run a non-sc band structure with hybrid
            functionals). The explicit KPOINTS file needs to have data on the
            kpoint label as commentary.
        """

        if not kpoints_filename:
            kpoints_filename = zpath(
                os.path.join(os.path.dirname(self.filename), 'KPOINTS'))
        if not os.path.exists(kpoints_filename) and line_mode is True:
            raise VaspParserError('KPOINTS needed to obtain band structure '
                                  'along symmetry lines.')

        if efermi is None:
            efermi = self.efermi

        kpoint_file = None
        if os.path.exists(kpoints_filename):
            kpoint_file = Kpoints.from_file(kpoints_filename)
        lattice_new = Lattice(self.lattice_rec.matrix)

        kpoints = [np.array(self.actual_kpoints[i])
                   for i in range(len(self.actual_kpoints))]

        p_eigenvals = defaultdict(list)
        eigenvals = defaultdict(list)

        nkpts = len(kpoints)

        neigenvalues = [len(v) for v in self.eigenvalues[Spin.up]]
        min_eigenvalues = min(neigenvalues)

        for spin, v in self.eigenvalues.items():
            v = np.swapaxes(v, 0, 1)
            eigenvals[spin] = v[:, :, 0]

            if self.projected_eigenvalues:
                peigen = self.projected_eigenvalues[spin]
                # Original axes for self.projected_eigenvalues are kpoints,
                # band, ion, orb.
                # For BS input, we need band, kpoints, orb, ion.
                peigen = np.swapaxes(peigen, 0, 1)  # Swap kpoint and band axes
                peigen = np.swapaxes(peigen, 2, 3)  # Swap ion and orb axes

                p_eigenvals[spin] = peigen
                # for b in range(min_eigenvalues):
                #     p_eigenvals[spin].append(
                #         [{Orbital(orb): v for orb, v in enumerate(peigen[b, k])}
                #          for k in range(nkpts)])

        # check if we have an hybrid band structure computation
        # for this we look at the presence of the LHFCALC tag
        hybrid_band = False
        if self.parameters.get('LHFCALC', False) or \
                0. in self.actual_kpoints_weights:
            hybrid_band = True

        if kpoint_file is not None:
            if kpoint_file.style == Kpoints.supported_modes.Line_mode:
                line_mode = True

        if line_mode:
            labels_dict = {}
            if hybrid_band or force_hybrid_mode:
                start_bs_index = 0
                for i in range(len(self.actual_kpoints)):
                    if self.actual_kpoints_weights[i] == 0.0:
                        start_bs_index = i
                        break
                for i in range(start_bs_index, len(kpoint_file.kpts)):
                    if kpoint_file.labels[i] is not None:
                        labels_dict[kpoint_file.labels[i]] = \
                            kpoint_file.kpts[i]
                # remake the data only considering line band structure k-points
                # (weight = 0.0 kpoints)
                nbands = len(eigenvals[Spin.up])
                kpoints = kpoints[start_bs_index:nkpts]
                up_eigen = [eigenvals[Spin.up][i][start_bs_index:nkpts]
                            for i in range(nbands)]
                if self.projected_eigenvalues:
                    p_eigenvals[Spin.up] = [p_eigenvals[Spin.up][i][
                                            start_bs_index:nkpts]
                                            for i in range(nbands)]
                if self.is_spin:
                    down_eigen = [eigenvals[Spin.down][i][start_bs_index:nkpts]
                                  for i in range(nbands)]
                    eigenvals = {Spin.up: up_eigen, Spin.down: down_eigen}
                    if self.projected_eigenvalues:
                        p_eigenvals[Spin.down] = [p_eigenvals[Spin.down][i][
                                                  start_bs_index:nkpts]
                                                  for i in range(nbands)]
                else:
                    eigenvals = {Spin.up: up_eigen}
            else:
                if '' in kpoint_file.labels:
                    raise Exception("A band structure along symmetry lines "
                                    "requires a label for each kpoint. "
                                    "Check your KPOINTS file")
                labels_dict = dict(zip(kpoint_file.labels, kpoint_file.kpts))
                labels_dict.pop(None, None)
            return BandStructureSymmLine(kpoints, eigenvals, lattice_new,
                                         efermi, labels_dict,
                                         structure=self.final_structure,
                                         projections=p_eigenvals)
        else:
            return BandStructure(kpoints, eigenvals, lattice_new, efermi,
                                 structure=self.final_structure,
                                 projections=p_eigenvals)