def __call__(self, unit=None): """ Return the value for the constant in the given unit, otherwise will return the units in SI units """ if unit is None: return self return PhysicalConstant(self * units(self.unit, unit), unit)
def effective_mass(self, band, k, k_direction, band_spin=0, n_points=10): """Calculates the effective mass from the curvature of a band in a given k point. It works by fitting the band to a second order polynomial. Notes ----- Only valid if there are no band-crossings in the fitted range. The effective mass may be highly dependent on the `k_direction` parameter, as well as the number of points fitted. Parameters ----------- band: int The index of the band that we want to fit k: float or str The k value where we want to find the curvature of the band to calculate the effective mass. band_spin: int, optional The spin value for which we want the effective mass. n_points: int The number of points that we want to use for the polynomial fit. k_direction: {"symmetric", "right", "left"}, optional Indicates in which direction -starting from `k`- should the band be fitted. "left" and "right" mean that the fit will only be done in one direction, while "symmetric" indicates that points from both sides will be used. Return ----------- float The efective mass, in atomic units. """ from sisl.unit.base import units # Get the band that we want to fit band_vals = self.bands.sel(band=band, spin=band_spin) # Sanitize k to a float k = self._sanitize_k(k) # Find the index of the requested k k_index = abs(self.bands.k - k).values.argmin() # Determine which slice of the band will we take depending on k_direction and n_points if k_direction == "symmetric": sel_slice = slice(k_index - n_points // 2, k_index + n_points // 2 + 1) elif k_direction == "left": sel_slice = slice(k_index - n_points + 1, k_index + 1) elif k_direction == "right": sel_slice = slice(k_index, k_index + n_points) else: raise ValueError( f"k_direction must be one of ['symmetric', 'left', 'right'], {k_direction} was passed" ) # Grab the slice of the band that we are going to fit sel_band = band_vals[sel_slice] * units("eV", "Hartree") sel_k = self.bands.k[sel_slice] - k # Fit the band to a second order polynomial polyfit = np.polynomial.Polynomial.fit(sel_k, sel_band, 2) # Get the coefficient for the second order term coeff_2 = polyfit.convert().coef[2] # Calculate the effective mass from the dispersion relation. # Note that hbar = m_e = 1, since we are using atomic units. eff_m = 1 / (2 * coeff_2) return eff_m