def _get_conductivity(self, n_idx, t_idx): velocities = self._get_group_velocity() lifetimes = 1 / self._get_scattering_rates(n_idx, t_idx) energies = self._get_energies() _, weights = np.unique(self.ir_to_full_kpoint_mapping, return_counts=True) ef = self.fermi_levels[n_idx, t_idx] temp = self.temperatures[t_idx] dfde = -dFDde(energies, ef, temp * units.BOLTZMANN) nkpoints = len(self.kpoints) integrand = velocities**2 * lifetimes * dfde * weights[ None, :] / nkpoints conductivity = np.sum(integrand) return integrand / conductivity
def calculate_fd_cutoffs( self, fd_tolerance: Optional[float] = 0.01, cutoff_pad: float = 0.0 ): energies = self.dos.energies # three fermi integrals govern transport properties: # 1. df/de controls conductivity and mobility # 2. (e-u) * df/de controls Seebeck # 3. (e-u)^2 df/de controls electronic thermal conductivity # take the absolute sum of the integrals across all doping and # temperatures. this gives us the energies that are important for # transport weights = np.zeros(energies.shape) for n, t in np.ndindex(self.fermi_levels.shape): ef = self.fermi_levels[n, t] temp = self.temperatures[t] dfde = -dFDde(energies, ef, temp * units.BOLTZMANN) sigma_int = np.abs(dfde) seeb_int = np.abs((energies - ef) * dfde) ke_int = np.abs((energies - ef) ** 2 * dfde) # normalize the transport integrals and sum nt_weights = sigma_int / sigma_int.max() nt_weights += seeb_int / seeb_int.max() nt_weights += ke_int / ke_int.max() weights = np.maximum(weights, nt_weights) if not self.is_metal: # weights should be zero in the band gap as there will be no density vb_bands = [ np.max(self.energies[s][: self.vb_idx[s] + 1]) for s in self.spins ] cb_bands = [ np.min(self.energies[s][self.vb_idx[s] + 1 :]) for s in self.spins ] vbm_e = np.max(vb_bands) cbm_e = np.min(cb_bands) weights[(energies > vbm_e) & (energies < cbm_e)] = 0 weights /= np.max(weights) cumsum = np.cumsum(weights) cumsum /= np.max(cumsum) if fd_tolerance: min_cutoff = energies[cumsum < fd_tolerance / 2].max() max_cutoff = energies[cumsum > 1 - fd_tolerance / 2].min() else: min_cutoff = energies.min() max_cutoff = energies.max() min_cutoff -= cutoff_pad max_cutoff += cutoff_pad logger.info("Calculated Fermi–Dirac cut-offs:") log_list( [ "min: {:.3f} eV".format(min_cutoff / units.eV), "max: {:.3f} eV".format(max_cutoff / units.eV), ] ) self.fd_cutoffs = (min_cutoff, max_cutoff)