Ejemplo n.º 1
0
    def get_dos(
        self,
        kpoint_mesh: Union[float, int, List[int]],
        energy_cutoff: Optional[float] = None,
        scissor: Optional[float] = None,
        bandgap: Optional[float] = None,
        estep: float = defaults["dos_estep"],
        symprec: float = defaults["symprec"],
        atomic_units: bool = False,
    ) -> Union[Dos, FermiDos]:
        """Calculates the density of states using the interpolated bands.

        Args:
            kpoint_mesh: The k-point mesh as a 1x3 array. E.g.,``[6, 6, 6]``.
                Alternatively, if a single value is provided this will be
                treated as a reciprocal density and the k-point mesh dimensions
                generated automatically.
            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.
            estep: The energy step, where smaller numbers give more
                accuracy but are more expensive.
            symprec: The symmetry tolerance used when determining the symmetry
                inequivalent k-points on which to interpolate.
            atomic_units: Whether to return the DOS in atomic units. If False, the
                unit of energy will be eV.

        Returns:
            The density of states.
        """
        if isinstance(kpoint_mesh, numeric_types):
            logger.info("DOS k-point length cutoff: {}".format(kpoint_mesh))
        else:
            str_mesh = "x".join(map(str, kpoint_mesh))
            logger.info("DOS k-point mesh: {}".format(str_mesh))

        structure = self._band_structure.structure
        tri = not self._soc
        (
            ir_kpts,
            _,
            full_kpts,
            ir_kpts_idx,
            ir_to_full_idx,
            tetrahedra,
            *ir_tetrahedra_info,
        ) = get_kpoints_tetrahedral(kpoint_mesh,
                                    structure,
                                    symprec=symprec,
                                    time_reversal_symmetry=tri)

        energies, efermi, vb_idx = self.get_energies(
            ir_kpts,
            scissor=scissor,
            bandgap=bandgap,
            energy_cutoff=energy_cutoff,
            atomic_units=atomic_units,
            return_efermi=True,
            return_vb_idx=True,
        )

        if not self._band_structure.is_metal():
            # if not a metal, set the Fermi level to the top of the valence band.
            efermi = np.max(
                [np.max(e[vb_idx[spin]]) for spin, e in energies.items()])

        full_energies = {s: e[:, ir_to_full_idx] for s, e in energies.items()}
        tetrahedral_band_structure = TetrahedralBandStructure(
            full_energies, full_kpts, tetrahedra, structure, ir_kpts_idx,
            ir_to_full_idx, *ir_tetrahedra_info)

        emin = np.min([np.min(spin_eners) for spin_eners in energies.values()])
        emax = np.max([np.max(spin_eners) for spin_eners in energies.values()])
        epoints = int(round((emax - emin) / estep))
        energies = np.linspace(emin, emax, epoints)

        _, dos = tetrahedral_band_structure.get_density_of_states(energies)

        return FermiDos(efermi,
                        energies,
                        dos,
                        structure,
                        atomic_units=atomic_units)
Ejemplo n.º 2
0
    def get_amset_data(
        self,
        energy_cutoff: Optional[float] = None,
        scissor: float = None,
        bandgap: float = None,
        symprec: float = defaults["symprec"],
        nworkers: int = defaults["nworkers"],
    ) -> AmsetData:
        """Gets an AmsetData object using the interpolated bands.

        Note, the interpolation mesh is determined using by
        ``interpolate_factor`` option in the ``Inteprolater`` constructor.

        This method is much faster than the ``get_energies`` function but
        doesn't provide as much flexibility.

        The degree of parallelization is controlled by the ``nworkers`` option.

        Args:
            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 when determining the symmetry
                inequivalent k-points on which to interpolate.
            nworkers: The number of processors used to perform the
                interpolation. If set to ``-1``, the number of workers will
                be set to the number of CPU cores.

        Returns:
            The electronic structure (including energies, velocities, density of
            states and k-point information) as an AmsetData object.
        """
        is_metal = self._band_structure.is_metal()

        if is_metal and (bandgap or scissor):
            raise ValueError("{} option set but system is metallic".format(
                "bandgap" if bandgap else "scissor"))

        nworkers = multiprocessing.cpu_count() if nworkers == -1 else nworkers

        logger.info("Interpolation parameters:")
        iinfo = [
            "k-point mesh: {}".format("x".join(
                map(str, self.interpolation_mesh))),
            "energy cutoff: {} eV".format(energy_cutoff),
        ]
        log_list(iinfo)

        ibands = get_ibands(energy_cutoff, self._band_structure)
        new_vb_idx = get_vb_idx(energy_cutoff, self._band_structure)

        energies = {}
        vvelocities = {}
        velocities = {}
        forgotten_electrons = 0
        for spin in self._spins:
            spin_ibands = ibands[spin]
            min_b = spin_ibands.min() + 1
            max_b = spin_ibands.max() + 1
            info = "Interpolating {} bands {}-{}".format(
                spin_name[spin], min_b, max_b)
            logger.info(info)

            # these are bands beneath the Fermi level that are dropped
            forgotten_electrons += min_b - 1

            t0 = time.perf_counter()
            energies[spin], vvelocities[spin], _, velocities[
                spin] = get_bands_fft(
                    self._equivalences,
                    self._coefficients[spin][spin_ibands],
                    self._lattice_matrix,
                    return_effective_mass=False,
                    nworkers=nworkers,
                )
            log_time_taken(t0)

        if not self._soc and len(self._spins) == 1:
            forgotten_electrons *= 2
        nelectrons = self._num_electrons - forgotten_electrons

        if is_metal:
            efermi = self._band_structure.efermi * ev_to_hartree

        else:
            energies = _shift_energies(energies,
                                       new_vb_idx,
                                       scissor=scissor,
                                       bandgap=bandgap)

            # if material is semiconducting, set Fermi level to middle of gap
            efermi = _get_efermi(energies, new_vb_idx)

        # get the actual k-points used in the BoltzTraP2 interpolation
        # unfortunately, BoltzTraP2 doesn't expose this information so we
        # have to get it ourselves
        (
            ir_kpts,
            _,
            full_kpts,
            ir_kpts_idx,
            ir_to_full_idx,
            tetrahedra,
            *ir_tetrahedra_info,
        ) = get_kpoints_tetrahedral(
            self.interpolation_mesh,
            self._band_structure.structure,
            symprec=symprec,
            time_reversal_symmetry=not self._soc,
        )

        energies, vvelocities, velocities = sort_amset_results(
            full_kpts, energies, vvelocities, velocities)
        atomic_structure = get_atomic_structure(self._band_structure.structure)

        return AmsetData(
            atomic_structure,
            energies,
            vvelocities,
            velocities,
            self.interpolation_mesh,
            full_kpts,
            ir_kpts,
            ir_kpts_idx,
            ir_to_full_idx,
            tetrahedra,
            ir_tetrahedra_info,
            efermi,
            nelectrons,
            is_metal,
            self._soc,
            vb_idx=new_vb_idx,
        )