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)
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, )