Exemple #1
0
 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)
Exemple #2
0
    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