示例#1
0
def _calculate_transport_properties(amset_data):
    kmask = amset_data.transport_mask
    energies = np.vstack([amset_data.energies[spin]
                          for spin in amset_data.spins])
    vv = np.vstack([amset_data.velocities_product[spin]
                    for spin in amset_data.spins])

    # mask data to remove extra k-points that are not part of the regular
    # k-point mesh (necessary as BoltzTraP2 doesn't support custom k-point
    # weights.
    energies = energies[:, kmask]
    vv = vv[..., kmask]

    n_t_size = (len(amset_data.doping), len(amset_data.temperatures))

    sigma = np.zeros(n_t_size + (3, 3))
    seebeck = np.zeros(n_t_size + (3, 3))
    kappa = np.zeros(n_t_size + (3, 3))

    # solve sigma, seebeck, kappa and hall using information from all bands
    for n, t in np.ndindex(n_t_size):
        sum_rates = [np.sum(amset_data.scattering_rates[s][:, n, t], axis=0)
                     for s in amset_data.spins]
        lifetimes = 1 / np.vstack(sum_rates)
        lifetimes = lifetimes[:, kmask]
        # print(lifetimes.min())

        # Nones are required as BoltzTraP2 expects the Fermi and temp as arrays
        fermi = amset_data.fermi_levels[n, t][None] * units.eV
        temp = amset_data.temperatures[t][None]

        # obtain the Fermi integrals
        epsilon, dos, vvdos, cdos = BTPDOS(
            energies, vv, scattering_model=lifetimes,
            npts=len(amset_data.dos.energies))
        # epsilon, dos, vvdos, cdos = AMSETDOS(
        #     energies, vv, scattering_model=lifetimes,
        #     npts=len(amset_data.dos.energies),
        #     kpoint_weights=amset_data.kpoint_weights)

        _, l0, l1, l2, lm11 = fermiintegrals(
            epsilon, dos, vvdos, mur=fermi, Tr=temp,
            dosweight=amset_data.dos_weight)

        volume = (amset_data.structure.lattice.volume * units.Angstrom ** 3)

        # Compute the Onsager coefficients from Fermi integrals
        # Don't store the Hall coefficient as we don't have the curvature
        # information.
        # TODO: Fix Hall coefficient
        sigma[n, t], seebeck[n, t], kappa[n, t], _ = \
            calc_Onsager_coefficients(l0, l1, l2, fermi, temp, volume)

    # convert seebeck to µV/K
    seebeck *= 1e6

    return sigma, seebeck, kappa
示例#2
0
    def __init__(self, BztInterpolator, temp_r=np.arange(100, 1400, 100),
                 doping=10. ** np.arange(16, 23), npts_mu=4000, CRTA=1e-14, margin=None):

        self.CRTA = CRTA
        self.temp_r = temp_r
        self.doping = doping
        self.dosweight = BztInterpolator.data.dosweight
        lattvec = BztInterpolator.data.get_lattvec()

        self.epsilon, self.dos, self.vvdos, self.cdos = BL.BTPDOS(BztInterpolator.eband, BztInterpolator.vvband,
                                                                  npts=npts_mu, cband=BztInterpolator.cband)

        if margin is None:
            margin = 9. * units.BOLTZMANN * temp_r.max()

        mur_indices = np.logical_and(self.epsilon > self.epsilon.min() + margin,
                                     self.epsilon < self.epsilon.max() - margin)

        self.mu_r = self.epsilon[mur_indices]

        N, L0, L1, L2, Lm11 = BL.fermiintegrals(
            self.epsilon, self.dos, self.vvdos, mur=self.mu_r, Tr=temp_r, dosweight=self.dosweight, cdos=self.cdos)

        self.efermi = BztInterpolator.data.fermi / units.eV
        self.mu_r_eV = self.mu_r / units.eV - self.efermi
        self.nelect = BztInterpolator.data.nelect
        self.volume = BztInterpolator.data.get_volume()

        # Compute the Onsager coefficients from those Fermi integrals
        self.Conductivity_mu, self.Seebeck_mu, self.Kappa_mu, Hall_mu = BL.calc_Onsager_coefficients(L0, L1, L2,
                                                                                                     self.mu_r, temp_r,
                                                                                                     self.volume,
                                                                                                     Lm11=Lm11)

        # Common properties rescaling
        self.Conductivity_mu *= CRTA  # S / m
        self.Seebeck_mu *= 1e6  # microvolt / K
        self.Kappa_mu *= CRTA  # W / (m K)
        self.Hall_carrier_conc_trace_mu = units.Coulomb * 1e-6 / (np.abs(Hall_mu[:, :, 0, 1, 2] +
                                                                         Hall_mu[:, :, 2, 0, 1] +
                                                                         Hall_mu[:, :, 1, 2, 0]) / 3)
        self.Carrier_conc_mu = (N + self.nelect) / (self.volume / (units.Meter / 100.) ** 3)

        # Derived properties
        cond_eff_mass = np.zeros((len(self.temp_r), len(self.mu_r), 3, 3))
        for t in range(len(self.temp_r)):
            for i in range(len(self.mu_r)):
                try:
                    cond_eff_mass[t, i] = np.linalg.inv(self.Conductivity_mu[t, i]) * self.Carrier_conc_mu[
                        t, i] * units.qe_SI ** 2 / units.me_SI * 1e6
                except np.linalg.LinAlgError:
                    pass

        self.Effective_mass_mu = cond_eff_mass * CRTA

        self.Power_Factor_mu = (self.Seebeck_mu @ self.Seebeck_mu) @ self.Conductivity_mu
        self.Power_Factor_mu *= 1e-9  # milliWatt / m / K**2
示例#3
0
    def __init__(self, BztInterpolator, temp_r=np.arange(100, 1400, 100),
                 doping=10. ** np.arange(16, 23), npts_mu=4000, CRTA=1e-14, margin=None):

        self.CRTA = CRTA
        self.temp_r = temp_r
        self.doping = doping
        self.dosweight = BztInterpolator.data.dosweight
        lattvec = BztInterpolator.data.get_lattvec()

        self.epsilon, self.dos, self.vvdos, self.cdos = BL.BTPDOS(BztInterpolator.eband, BztInterpolator.vvband,
                                                                  npts=npts_mu, cband=BztInterpolator.cband)

        if margin is None:
            margin = 9. * units.BOLTZMANN * temp_r.max()

        mur_indices = np.logical_and(self.epsilon > self.epsilon.min() + margin,
                                     self.epsilon < self.epsilon.max() - margin)

        self.mu_r = self.epsilon[mur_indices]

        N, L0, L1, L2, Lm11 = BL.fermiintegrals(
            self.epsilon, self.dos, self.vvdos, mur=self.mu_r, Tr=temp_r, dosweight=self.dosweight, cdos=self.cdos)

        self.efermi = BztInterpolator.data.fermi / units.eV
        self.mu_r_eV = self.mu_r / units.eV - self.efermi
        self.nelect = BztInterpolator.data.nelect
        self.volume = BztInterpolator.data.get_volume()

        # Compute the Onsager coefficients from those Fermi integrals
        self.Conductivity_mu, self.Seebeck_mu, self.Kappa_mu, Hall_mu = BL.calc_Onsager_coefficients(L0, L1, L2,
                                                                                                     self.mu_r, temp_r,
                                                                                                     self.volume,
                                                                                                     Lm11=Lm11)

        # Common properties rescaling
        self.Conductivity_mu *= CRTA  # S / m
        self.Seebeck_mu *= 1e6  # microvolt / K
        self.Kappa_mu *= CRTA  # W / (m K)
        self.Hall_carrier_conc_trace_mu = units.Coulomb * 1e-6 / (np.abs(Hall_mu[:, :, 0, 1, 2] +
                                                                         Hall_mu[:, :, 2, 0, 1] +
                                                                         Hall_mu[:, :, 1, 2, 0]) / 3)
        self.Carrier_conc_mu = (N + self.nelect) / (self.volume / (units.Meter / 100.) ** 3)

        # Derived properties
        cond_eff_mass = np.zeros((len(self.temp_r), len(self.mu_r), 3, 3))
        for t in range(len(self.temp_r)):
            for i in range(len(self.mu_r)):
                try:
                    cond_eff_mass[t, i] = np.linalg.inv(self.Conductivity_mu[t, i]) * self.Carrier_conc_mu[
                        t, i] * units.qe_SI ** 2 / units.me_SI * 1e6
                except np.linalg.LinAlgError:
                    pass

        self.Effective_mass_mu = cond_eff_mass * CRTA

        self.Power_Factor_mu = (self.Seebeck_mu @ self.Seebeck_mu) @ self.Conductivity_mu
        self.Power_Factor_mu *= 1e-9  # milliWatt / m / K**2
示例#4
0
def _calculate_transport_properties(amset_data,
                                    progress_bar: bool = defaults["print_log"]
                                    ):
    n_t_size = (len(amset_data.doping), len(amset_data.temperatures))

    sigma = np.zeros(n_t_size + (3, 3))
    seebeck = np.zeros(n_t_size + (3, 3))
    kappa = np.zeros(n_t_size + (3, 3))
    volume = amset_data.structure.volume

    epsilon, dos = amset_data.tetrahedral_band_structure.get_density_of_states(
        amset_data.dos.energies, sum_spins=True, use_cached_weights=True)

    iterable = list(np.ndindex(n_t_size))
    if progress_bar:
        pbar = get_progress_bar(iterable=iterable, desc="transport")
    else:
        pbar = iterable

    # solve sigma, seebeck, kappa and hall using information from all bands
    for n, t in pbar:
        lifetimes = {
            s: 1 / np.sum(amset_data.scattering_rates[s][:, n, t], axis=0)
            for s in amset_data.spins
        }

        # Nones are required as BoltzTraP2 expects the Fermi and temp as arrays
        fermi = amset_data.fermi_levels[n, t][None]
        temp = amset_data.temperatures[t][None]

        # obtain the Fermi integrals
        vvdos = get_transport_dos(
            amset_data.tetrahedral_band_structure,
            amset_data.velocities_product,
            lifetimes,
            amset_data.dos.energies,
        )

        _, l0, l1, l2, lm11 = fermiintegrals(
            epsilon,
            dos,
            vvdos,
            mur=fermi,
            Tr=temp,
            dosweight=amset_data.dos.dos_weight)

        # Compute the Onsager coefficients from Fermi integrals
        # Don't store the Hall coefficient as we don't have the curvature
        # information.
        sigma[n, t], seebeck[n, t], kappa[n, t], _ = calc_Onsager_coefficients(
            l0, l1, l2, fermi, temp, volume)

    # convert seebeck to µV/K
    seebeck *= 1e6

    return sigma, seebeck, kappa
示例#5
0
文件: transport.py 项目: gmp007/amset
def _calculate_transport_properties(amset_data):
    energies = np.vstack(
        [amset_data.energies[spin] for spin in amset_data.spins])
    vv = np.vstack(
        [amset_data.velocities_product[spin] for spin in amset_data.spins])
    # curvature = np.vstack([amset_data.curvature[spin] for spin in amset_data.spins])

    n_t_size = (len(amset_data.doping), len(amset_data.temperatures))

    sigma = np.zeros(n_t_size + (3, 3))
    seebeck = np.zeros(n_t_size + (3, 3))
    kappa = np.zeros(n_t_size + (3, 3))
    hall = np.zeros(n_t_size + (3, 3))

    # solve sigma, seebeck, kappa and hall using information from all bands
    for n, t in np.ndindex(n_t_size):
        sum_rates = [
            np.sum(amset_data.scattering_rates[s][:, n, t], axis=0)
            for s in amset_data.spins
        ]
        lifetimes = 1 / np.vstack(sum_rates)

        # Nones are required as BoltzTraP2 expects the Fermi and temp as arrays
        fermi = amset_data.fermi_levels[n, t][None]
        temp = amset_data.temperatures[t][None]

        # obtain the Fermi integrals
        epsilon, dos, vvdos, cdos = get_transport_dos(
            energies,
            vv,
            scattering_model=lifetimes,
            npts=len(amset_data.dos.energies),
            kpoint_weights=amset_data.kpoint_weights)

        _, l0, l1, l2, lm11 = fermiintegrals(
            epsilon,
            dos,
            vvdos,
            cdos=cdos,
            mur=fermi,
            Tr=temp,
            dosweight=amset_data.dos.dos_weight)

        volume = (amset_data.structure.lattice.volume * units.Angstrom**3)

        # Compute the Onsager coefficients from Fermi integrals
        # Don't store the Hall coefficient as we don't have the curvature
        # information.
        sigma[n, t], seebeck[n, t], kappa[n, t], _ = \
            calc_Onsager_coefficients(l0, l1, l2, fermi, temp, volume)

    # convert seebeck to µV/K
    seebeck *= 1e6

    return sigma, seebeck, kappa
示例#6
0
def _calculate_mobility(
    amset_data: AmsetData,
    rate_idx: Union[int, List[int], np.ndarray],
    pbar_label: str = "mobility",
):
    if isinstance(rate_idx, int):
        rate_idx = [rate_idx]

    volume = amset_data.structure.volume
    mobility = np.zeros(amset_data.fermi_levels.shape + (3, 3))

    epsilon, dos = amset_data.tetrahedral_band_structure.get_density_of_states(
        amset_data.dos.energies, sum_spins=True, use_cached_weights=True)

    pbar = get_progress_bar(iterable=list(
        np.ndindex(amset_data.fermi_levels.shape)),
                            desc=pbar_label)
    for n, t in pbar:
        br = {
            s: np.arange(len(amset_data.energies[s]))
            for s in amset_data.spins
        }
        cb_idx = {s: amset_data.vb_idx[s] + 1 for s in amset_data.spins}

        if amset_data.doping[n] < 0:
            band_idx = {s: br[s][cb_idx[s]:] for s in amset_data.spins}
        else:
            band_idx = {s: br[s][:cb_idx[s]] for s in amset_data.spins}

        lifetimes = {
            s:
            1 / np.sum(amset_data.scattering_rates[s][rate_idx, n, t], axis=0)
            for s in amset_data.spins
        }

        # Nones are required as BoltzTraP2 expects the Fermi and temp as arrays
        fermi = amset_data.fermi_levels[n, t][None]
        temp = amset_data.temperatures[t][None]

        # obtain the Fermi integrals for the temperature and doping
        vvdos = get_transport_dos(
            amset_data.tetrahedral_band_structure,
            amset_data.velocities_product,
            lifetimes,
            amset_data.dos.energies,
            band_idx=band_idx,
        )

        c, l0, l1, l2, lm11 = fermiintegrals(
            epsilon,
            dos,
            vvdos,
            mur=fermi,
            Tr=temp,
            dosweight=amset_data.dos.dos_weight)

        # Compute the Onsager coefficients from Fermi integrals
        sigma, _, _, _ = calc_Onsager_coefficients(l0, l1, l2, fermi, temp,
                                                   volume)

        if amset_data.doping[n] < 0:
            carrier_conc = amset_data.electron_conc[n, t]
        else:
            carrier_conc = amset_data.hole_conc[n, t]

        # don't use c as we don't use the correct DOS each time
        # c = -c[0, ...] / (volume / (Meter / 100.)**3)

        # convert mobility to cm^2/V.s
        uc = 0.01 / (e * carrier_conc * (1 / bohr_to_cm)**3)
        mobility[n, t] = sigma[0, ...] * uc

    return mobility
示例#7
0
    def compute_properties_doping(self, doping, temp_r=None):
        """
        Calculate all the properties w.r.t. the doping levels in input.

        Args:
            doping: numpy array specifying the doping levels

        When executed, it add the following variable at the BztTransportProperties
        object:
            Conductivity_doping, Seebeck_doping, Kappa_doping, Power_Factor_doping,
            cond_Effective_mass_doping are dictionaries with 'n' and 'p' keys and
            arrays of dim (len(temp_r),len(doping),3,3) as values.
            Carriers_conc_doping: carriers concentration for each doping level and T.
            mu_doping_eV: the chemical potential corrispondent to each doping level.
        """

        if temp_r is None:
            temp_r = self.temp_r

        (
            self.Conductivity_doping,
            self.Seebeck_doping,
            self.Kappa_doping,
            self.Carriers_conc_doping,
        ) = ({}, {}, {}, {})

        self.Power_Factor_doping, self.Effective_mass_doping = {}, {}

        mu_doping = {}
        doping_carriers = [
            dop * (self.volume / (units.Meter / 100.0)**3) for dop in doping
        ]

        for dop_type in ["n", "p"]:
            sbk = np.zeros((len(temp_r), len(doping), 3, 3))
            cond = np.zeros((len(temp_r), len(doping), 3, 3))
            kappa = np.zeros((len(temp_r), len(doping), 3, 3))
            hall = np.zeros((len(temp_r), len(doping), 3, 3, 3))
            dc = np.zeros((len(temp_r), len(doping)))

            if dop_type == "p":
                doping_carriers = [-dop for dop in doping_carriers]

            mu_doping[dop_type] = np.zeros((len(temp_r), len(doping)))
            for t, temp in enumerate(temp_r):
                for i, dop_car in enumerate(doping_carriers):
                    mu_doping[dop_type][t, i] = BL.solve_for_mu(
                        self.epsilon,
                        self.dos,
                        self.nelect + dop_car,
                        temp,
                        self.dosweight,
                        True,
                        False,
                    )
                    # mu_doping[dop_type][t, i] = self.find_mu_doping(
                    #     self.epsilon, self.dos, self.nelect + dop_car, temp,
                    #     self.dosweight)

                N, L0, L1, L2, Lm11 = BL.fermiintegrals(
                    self.epsilon,
                    self.dos,
                    self.vvdos,
                    mur=mu_doping[dop_type][t],
                    Tr=np.array([temp]),
                    dosweight=self.dosweight,
                )

                cond[t], sbk[t], kappa[t], hall[
                    t] = BL.calc_Onsager_coefficients(
                        L0,
                        L1,
                        L2,
                        mu_doping[dop_type][t],
                        np.array([temp]),
                        self.volume,
                        Lm11,
                    )

                dc[t] = self.nelect + N

            self.Conductivity_doping[dop_type] = cond * self.CRTA  # S / m
            self.Seebeck_doping[dop_type] = sbk * 1e6  # microVolt / K
            self.Kappa_doping[dop_type] = kappa * self.CRTA  # W / (m K)
            # self.Hall_doping[dop_type] = hall
            self.Carriers_conc_doping[dop_type] = dc / (
                self.volume / (units.Meter / 100.0)**3)

            self.Power_Factor_doping[dop_type] = (
                sbk @ sbk) @ cond * self.CRTA * 1e3

            cond_eff_mass = np.zeros((len(temp_r), len(doping), 3, 3))
            for t in range(len(temp_r)):
                for i, dop in enumerate(doping):
                    try:
                        cond_eff_mass[t, i] = np.linalg.inv(
                            cond[t,
                                 i]) * dop * units.qe_SI**2 / units.me_SI * 1e6
                    except np.linalg.LinAlgError:
                        pass

            self.Effective_mass_doping[dop_type] = cond_eff_mass

        self.doping = doping
        self.mu_doping = mu_doping
        self.mu_doping_eV = {
            k: v / units.eV - self.efermi
            for k, v in mu_doping.items()
        }
        self.contain_props_doping = True
示例#8
0
    def __init__(
        self,
        BztInterpolator,
        temp_r=np.arange(100, 1400, 100),
        doping=None,
        npts_mu=4000,
        CRTA=1e-14,
        margin=None,
        save_bztTranspProps=False,
        load_bztTranspProps=False,
        fname="bztTranspProps.json.gz",
    ):
        """
        Args:
            BztInterpolator: a BztInterpolator previously generated
            temp_r: numpy array of temperatures at which to calculate transport properties
            doping: doping levels at which to calculate transport properties. If provided,
                transport properties w.r.t. these doping levels are also computed. See
                compute_properties_doping() method for details.
            npts_mu: number of energy points at which to calculate transport properties
            CRTA: constant value of the relaxation time
            save_bztTranspProps: Default False. If True all computed transport properties
                will be stored in fname file.
            load_bztTranspProps: Default False. If True all computed transport properties
                will be loaded from fname file.
            fname: File path where to save/load transport properties.

        Upon creation, it contains properties tensors w.r.t. the chemical potential
        of size (len(temp_r),npts_mu,3,3):
            Conductivity_mu (S/m), Seebeck_mu (microV/K), Kappa_mu (W/(m*K)),
            Power_Factor_mu (milliW/K m);
            cond_Effective_mass_mu (m_e) calculated as Ref.
        Also:
            Carrier_conc_mu: carrier concentration of size (len(temp_r),npts_mu)
            Hall_carrier_conc_trace_mu: trace of Hall carrier concentration of size
                (len(temp_r),npts_mu)
            mu_r_eV: array of energies in eV and with E_fermi at 0.0
                where all the properties are calculated.

        Example:
            bztTransp = BztTransportProperties(bztInterp,temp_r = np.arange(100,1400,100))
        """

        self.dosweight = BztInterpolator.data.dosweight
        self.volume = BztInterpolator.data.get_volume()
        self.nelect = BztInterpolator.data.nelect
        self.efermi = BztInterpolator.data.fermi / units.eV

        if margin is None:
            margin = 9.0 * units.BOLTZMANN * temp_r.max()

        if load_bztTranspProps:
            self.load(fname)
        else:
            self.CRTA = CRTA
            self.temp_r = temp_r
            self.doping = doping

            self.epsilon, self.dos, self.vvdos, self.cdos = BL.BTPDOS(
                BztInterpolator.eband,
                BztInterpolator.vvband,
                npts=npts_mu,
                cband=BztInterpolator.cband,
            )

            mur_indices = np.logical_and(
                self.epsilon > self.epsilon.min() + margin,
                self.epsilon < self.epsilon.max() - margin,
            )

            self.mu_r = self.epsilon[mur_indices]
            self.mu_r_eV = self.mu_r / units.eV - self.efermi

            N, L0, L1, L2, Lm11 = BL.fermiintegrals(
                self.epsilon,
                self.dos,
                self.vvdos,
                mur=self.mu_r,
                Tr=temp_r,
                dosweight=self.dosweight,
                cdos=self.cdos,
            )

            # Compute the Onsager coefficients from those Fermi integrals
            (
                self.Conductivity_mu,
                self.Seebeck_mu,
                self.Kappa_mu,
                Hall_mu,
            ) = BL.calc_Onsager_coefficients(L0,
                                             L1,
                                             L2,
                                             self.mu_r,
                                             temp_r,
                                             self.volume,
                                             Lm11=Lm11)

            # Common properties rescaling
            self.Conductivity_mu *= CRTA  # S / m
            self.Seebeck_mu *= 1e6  # microvolt / K
            self.Kappa_mu *= CRTA  # W / (m K)
            self.Hall_carrier_conc_trace_mu = (
                units.Coulomb * 1e-6 /
                (np.abs(Hall_mu[:, :, 0, 1, 2] + Hall_mu[:, :, 2, 0, 1] +
                        Hall_mu[:, :, 1, 2, 0]) / 3))
            self.Carrier_conc_mu = (N +
                                    self.nelect) / (self.volume /
                                                    (units.Meter / 100.0)**3)

            # Derived properties
            cond_eff_mass = np.zeros((len(self.temp_r), len(self.mu_r), 3, 3))
            for t in range(len(self.temp_r)):
                for i in range(len(self.mu_r)):
                    try:
                        cond_eff_mass[t, i] = (
                            np.linalg.inv(self.Conductivity_mu[t, i]) *
                            self.Carrier_conc_mu[t, i] * units.qe_SI**2 /
                            units.me_SI * 1e6)
                    except np.linalg.LinAlgError:
                        pass

            self.Effective_mass_mu = cond_eff_mass * CRTA

            self.Power_Factor_mu = (
                self.Seebeck_mu @ self.Seebeck_mu) @ self.Conductivity_mu
            self.Power_Factor_mu *= 1e-9  # milliWatt / m / K**2

            # self.props_as_dict()

            self.contain_props_doping = False

            if isinstance(doping, np.ndarray):
                self.compute_properties_doping(doping, temp_r)

            if save_bztTranspProps:
                self.save(fname)
示例#9
0
def _calculate_mobility(amset_data: AmsetData,
                        rate_idx: Union[int, List[int], np.ndarray]):
    if isinstance(rate_idx, int):
        rate_idx = [rate_idx]

    n_t_size = (len(amset_data.doping), len(amset_data.temperatures))
    all_rates = amset_data.scattering_rates
    all_vv = amset_data.velocities_product
    all_energies = amset_data.energies
    kmask = amset_data.transport_mask

    mobility = np.zeros(n_t_size + (3, 3))
    for n, t in np.ndindex(n_t_size):
        energies = []
        vv = []
        rates = []
        for spin in amset_data.spins:
            cb_idx = amset_data.vb_idx[spin] + 1
            if amset_data.doping[n] > 0:
                # electrons
                energies.append(all_energies[spin][cb_idx:])
                vv.append(all_vv[spin][cb_idx:])
                rates.append(np.sum(all_rates[spin][rate_idx, n, t, cb_idx:],
                                    axis=0))
            else:
                # holes
                energies.append(all_energies[spin][:cb_idx])
                vv.append(all_vv[spin][:cb_idx])
                rates.append(np.sum(all_rates[spin][rate_idx, n, t, :cb_idx],
                                    axis=0))

        energies = np.vstack(energies)
        vv = np.vstack(vv)
        lifetimes = 1 / np.vstack(rates)

        # mask data to remove extra k-points that are not part of the regular
        # k-point mesh (necessary as BoltzTraP2 doesn't support custom k-point
        # weights.
        energies = energies[:, kmask]
        vv = vv[..., kmask]
        lifetimes = lifetimes[:, kmask]

        # Nones are required as BoltzTraP2 expects the Fermi and temp as arrays
        fermi = amset_data.fermi_levels[n, t][None] * units.eV
        temp = amset_data.temperatures[t][None]

        # obtain the Fermi integrals for the temperature and doping
        epsilon, dos, vvdos, cdos = BTPDOS(
            energies, vv, scattering_model=lifetimes,
            npts=len(amset_data.dos.energies))
        # epsilon, dos, vvdos, cdos = AMSETDOS(
        #     energies, vv, scattering_model=lifetimes,
        #     npts=len(amset_data.dos.energies),
        #     kpoint_weights=amset_data.kpoint_weights)

        _, l0, l1, l2, lm11 = fermiintegrals(
            epsilon, dos, vvdos, mur=fermi, Tr=temp,
            dosweight=amset_data.dos_weight)

        # Compute the Onsager coefficients from Fermi integrals
        volume = (amset_data.structure.lattice.volume * units.Angstrom ** 3)
        sigma, _, _, _ = calc_Onsager_coefficients(
            l0, l1, l2, fermi, temp, volume)

        if amset_data.doping[n] > 0:
            carrier_conc = amset_data.electron_conc[n, t]
        else:
            carrier_conc = amset_data.hole_conc[n, t]

        # convert mobility to cm^2/V.s
        mobility[n, t] = sigma[0, ...] * 0.01 / (e * carrier_conc)

    return mobility
示例#10
0
def boltztrap(dirname, bt2file, title, T):
    print(("\n\nWorking in %s for %s at %i K" % (dirname, title, T)))
    # If a ready-made file with the interpolation results is available, use it
    # Otherwise, create the file.
    if not os.path.exists(bt2file):
        # Load the input
        data = BTP.DFTData(dirname)
        # Select the interesting bands
        nemin, nemax = data.bandana(emin=data.fermi - .2, emax=data.fermi + .2)
        # Set up a k point grid with roughly five times the density of the input
        equivalences = sphere.get_equivalences(data.atoms,
                                               len(data.kpoints) * 5)
        # Perform the interpolation
        coeffs = fite.fitde3D(data, equivalences)
        # Save the result
        serialization.save_calculation(
            bt2file, data, equivalences, coeffs,
            serialization.gen_bt2_metadata(data, data.mommat is not None))

    # Load the interpolation results
    print("Load the interpolation results")
    data, equivalences, coeffs, metadata = serialization.load_calculation(
        bt2file)

    # Reconstruct the bands
    print("Reconstruct the bands")
    lattvec = data.get_lattvec()
    eband, vvband, cband = fite.getBTPbands(equivalences, coeffs, lattvec)

    # Obtain the Fermi integrals for different chemical potentials at
    # room temperature.
    TEMP = np.array([T])
    epsilon, dos, vvdos, cdos = BL.BTPDOS(eband, vvband, npts=4000)
    margin = 9. * units.BOLTZMANN * TEMP.max()
    mur_indices = np.logical_and(epsilon > epsilon.min() + margin,
                                 epsilon < epsilon.max() - margin)
    mur = epsilon[mur_indices]
    N, L0, L1, L2, Lm11 = BL.fermiintegrals(epsilon,
                                            dos,
                                            vvdos,
                                            mur=mur,
                                            Tr=TEMP,
                                            dosweight=data.dosweight)

    # Compute the Onsager coefficients from those Fermi integrals
    print("Compute the Onsager coefficients")
    UCvol = data.get_volume()
    sigma, seebeck, kappa, Hall = BL.calc_Onsager_coefficients(
        L0, L1, L2, mur, TEMP, UCvol)

    fermi = BL.solve_for_mu(epsilon, dos, data.nelect, T, data.dosweight)

    savedata[title + '-%s' % T] = {
        "sigma": sigma,
        "seebeck": seebeck,
        "kappa": kappa,
        "Hall": Hall,
        "mu": (mur - fermi) / BL.eV,
        "temp": T,
        "n": N[0] + data.nelect
    }
示例#11
0
文件: silicon_crt.py 项目: suan12/EPA
                                   vvdos,
                                   mur=np.array([mur[iT]]),
                                   Tr=np.array([T]),
                                   dosweight=data.dosweight,
                                   cdos=cdos)
#N += data.nelect # incorrect because of missing states due to ecut and efcut
# ??? N -= N[0, round(N.shape[1] / 2)] # zero doping at low T in the middle of the band gap
volume = data.get_volume()
# Translate those into Onsager coefficients
sigma, seebeck, kappa = (np.empty((Tr.shape[0], 3, 3)) for ii in range(3))
Hall = np.empty((Tr.shape[0], 3, 3, 3))
for iT, T in enumerate(Tr):
    (sigma[iT], seebeck[iT], kappa[iT],
     Hall[iT]) = BL.calc_Onsager_coefficients(np.array([[L0[iT]]]),
                                              np.array([[L1[iT]]]),
                                              np.array([[L2[iT]]]),
                                              np.array([mur[iT]]),
                                              np.array([T]), volume,
                                              np.array([[Lm11[iT]]]))

# Rescale the carrier count into a volumetric density in cm^-3
#N = -N / (volume / (units.Meter / 100) ** 3)
# Obtain the scalar conductivity and Seebeck coefficient
sigmatr = sigma.trace(axis1=1, axis2=2) / 3
seebecktr = seebeck.trace(axis1=1, axis2=2) / 3
kappatr = kappa.trace(axis1=1, axis2=2) / 3
# Compute the scalar power factor
#P = sigmatr * seebecktr * seebecktr
# Transform these quantities to more convenient units
sigmatr *= tau * 1e-5  # kS / cm
seebecktr *= 1e6  # uV / K
kappatr *= tau * 1e-2  # W / cm / K
示例#12
0
    def compute_properties_doping(self, doping, temp_r=None):
        """
        Calculate all the properties w.r.t. the doping levels in input.

        Args:
            doping: numpy array specifing the doping levels

        When executed, it add the following variable at the BztTransportProperties
        object:
            Conductivity_doping, Seebeck_doping, Kappa_doping, Power_Factor_doping,
            cond_Effective_mass_doping are dictionaries with 'n' and 'p' keys and
            arrays of dim (len(temp_r),len(doping),3,3) as values
        doping_carriers: number of carriers for each doping level
        mu_doping_eV: the chemical potential corrispondent to each doping level
        """

        if temp_r is None:
            temp_r = self.temp_r

        self.Conductivity_doping, self.Seebeck_doping, self.Kappa_doping = {}, {}, {}
        # self.Hall_doping = {}

        self.Power_Factor_doping, self.Effective_mass_doping = {}, {}

        mu_doping = {}
        doping_carriers = [dop * (self.volume / (units.Meter / 100.) ** 3) for dop in doping]

        for dop_type in ['n', 'p']:
            sbk = np.zeros((len(temp_r), len(doping), 3, 3))
            cond = np.zeros((len(temp_r), len(doping), 3, 3))
            kappa = np.zeros((len(temp_r), len(doping), 3, 3))
            hall = np.zeros((len(temp_r), len(doping), 3, 3, 3))
            if dop_type == 'p':
                doping_carriers = [-dop for dop in doping_carriers]

            mu_doping[dop_type] = np.zeros((len(temp_r), len(doping)))
            for t, temp in enumerate(temp_r):
                for i, dop_car in enumerate(doping_carriers):
                    mu_doping[dop_type][t, i] = self.find_mu_doping(self.epsilon, self.dos, self.nelect + dop_car, temp,
                                                                    self.dosweight)

                N, L0, L1, L2, Lm11 = BL.fermiintegrals(self.epsilon, self.dos, self.vvdos, mur=mu_doping[dop_type][t],
                                                        Tr=np.array([temp]), dosweight=self.dosweight)
                cond[t], sbk[t], kappa[t], hall[t] = BL.calc_Onsager_coefficients(L0, L1, L2, mu_doping[dop_type][t],
                                                                                  np.array([temp]), self.volume, Lm11)

            self.Conductivity_doping[dop_type] = cond * self.CRTA  # S / m
            self.Seebeck_doping[dop_type] = sbk * 1e6  # microVolt / K
            self.Kappa_doping[dop_type] = kappa * self.CRTA  # W / (m K)
            # self.Hall_doping[dop_type] = hall

            self.Power_Factor_doping[dop_type] = (sbk @ sbk) @ cond * self.CRTA * 1e3

            cond_eff_mass = np.zeros((len(temp_r), len(doping), 3, 3))
            for t in range(len(temp_r)):
                for i, dop in enumerate(doping):
                    try:
                        cond_eff_mass[t, i] = np.linalg.inv(cond[t, i]) * dop * units.qe_SI ** 2 / units.me_SI * 1e6
                    except np.linalg.LinAlgError:
                        pass

            self.Effective_mass_doping[dop_type] = cond_eff_mass

        self.doping_carriers = doping_carriers
        self.doping = doping
        self.mu_doping = mu_doping
        self.mu_doping_eV = {k: v / units.eV - self.efermi for k, v in mu_doping.items()}
示例#13
0
    def __init__(self,
                 BztInterpolator,
                 temp_r=np.arange(100, 1400, 100),
                 doping=10.**np.arange(16, 23),
                 npts_mu=4000,
                 CRTA=1e-14,
                 margin=None):
        """
        Args:
            BztInterpolator: a BztInterpolator previously generated
            temp_r: numpy array of temperatures at which to calculate trasport properties
            doping: doping levels at which to calculate trasport properties
            npts_mu: number of energy points at which to calculate trasport properties
            CRTA: constant value of the relaxation time

        Upon creation, it contains properties tensors w.r.t. the chemical potential
        of size (len(temp_r),npts_mu,3,3):
            Conductivity_mu (S/m), Seebeck_mu (microV/K), Kappa_mu (W/(m*K)),
            Power_Factor_mu (milliW/K);
            cond_Effective_mass_mu (m_e) calculated as Ref.
        Also:
            Carrier_conc_mu: carrier concentration of size (len(temp_r),npts_mu)
            Hall_carrier_conc_trace_mu: trace of Hall carrier concentration of size
                (len(temp_r),npts_mu)
            mu_r_eV: array of energies in eV and with E_fermi at 0.0
                where all the properties are calculated.

        Example:
            bztTransp = BztTransportProperties(bztInterp,temp_r = np.arange(100,1400,100))
        """

        self.CRTA = CRTA
        self.temp_r = temp_r
        self.doping = doping
        self.dosweight = BztInterpolator.data.dosweight

        self.epsilon, self.dos, self.vvdos, self.cdos = BL.BTPDOS(
            BztInterpolator.eband,
            BztInterpolator.vvband,
            npts=npts_mu,
            cband=BztInterpolator.cband)

        if margin is None:
            margin = 9. * units.BOLTZMANN * temp_r.max()

        mur_indices = np.logical_and(
            self.epsilon > self.epsilon.min() + margin,
            self.epsilon < self.epsilon.max() - margin)

        self.mu_r = self.epsilon[mur_indices]

        N, L0, L1, L2, Lm11 = BL.fermiintegrals(self.epsilon,
                                                self.dos,
                                                self.vvdos,
                                                mur=self.mu_r,
                                                Tr=temp_r,
                                                dosweight=self.dosweight,
                                                cdos=self.cdos)

        self.efermi = BztInterpolator.data.fermi / units.eV
        self.mu_r_eV = self.mu_r / units.eV - self.efermi
        self.nelect = BztInterpolator.data.nelect
        self.volume = BztInterpolator.data.get_volume()

        # Compute the Onsager coefficients from those Fermi integrals
        self.Conductivity_mu, self.Seebeck_mu, self.Kappa_mu, Hall_mu = BL.calc_Onsager_coefficients(
            L0, L1, L2, self.mu_r, temp_r, self.volume, Lm11=Lm11)

        # Common properties rescaling
        self.Conductivity_mu *= CRTA  # S / m
        self.Seebeck_mu *= 1e6  # microvolt / K
        self.Kappa_mu *= CRTA  # W / (m K)
        self.Hall_carrier_conc_trace_mu = units.Coulomb * 1e-6 / (
            np.abs(Hall_mu[:, :, 0, 1, 2] + Hall_mu[:, :, 2, 0, 1] +
                   Hall_mu[:, :, 1, 2, 0]) / 3)
        self.Carrier_conc_mu = (N + self.nelect) / (self.volume /
                                                    (units.Meter / 100.)**3)

        # Derived properties
        cond_eff_mass = np.zeros((len(self.temp_r), len(self.mu_r), 3, 3))
        for t in range(len(self.temp_r)):
            for i in range(len(self.mu_r)):
                try:
                    cond_eff_mass[t, i] = np.linalg.inv(
                        self.Conductivity_mu[t, i]) * self.Carrier_conc_mu[
                            t, i] * units.qe_SI**2 / units.me_SI * 1e6
                except np.linalg.LinAlgError:
                    pass

        self.Effective_mass_mu = cond_eff_mass * CRTA

        self.Power_Factor_mu = (
            self.Seebeck_mu @ self.Seebeck_mu) @ self.Conductivity_mu
        self.Power_Factor_mu *= 1e-9  # milliWatt / m / K**2
示例#14
0
TEMP = np.array([300.])
epsilon, dos, vvdos, cdos = BL.BTPDOS(eband, vvband, npts=4000)
margin = 9. * units.BOLTZMANN * TEMP.max()
mur_indices = np.logical_and(epsilon > epsilon.min() + margin,
                             epsilon < epsilon.max() - margin)
mur = epsilon[mur_indices]
N, L0, L1, L2, Lm11 = BL.fermiintegrals(epsilon,
                                        dos,
                                        vvdos,
                                        mur=mur,
                                        Tr=TEMP,
                                        dosweight=data.dosweight)

# Compute the Onsager coefficients from those Fermi integrals
UCvol = data.get_volume()
sigma, seebeck, kappa, Hall = BL.calc_Onsager_coefficients(
    L0, L1, L2, mur, TEMP, UCvol)

fermi = BL.solve_for_mu(epsilon, dos, data.nelect, 300, data.dosweight)

# Plot the results
fig1, ax1 = pl.subplots(1, figsize=(6, 3))
ax1.set_xlim([-1, 1])
ax1.set_ylim([-300, 300])
ax1.plot((mur - fermi) / BL.eV,
         seebeck[0, :, 0, 0] * 1e6,
         "k-",
         label="xx \n seebeck[0, 0:0, 0, 0] * 1e6")
ax1.plot((mur - fermi) / BL.eV, seebeck[0, :, 2, 2] * 1e6, "k--", label="zz")
ax1.set_xlabel("$\mu$ [eV]")
ax1.set_ylabel("$S$ [$\mu$V/K]")
ax1.legend()
示例#15
0
文件: transport.py 项目: gmp007/amset
def _calculate_mobility(amset_data: AmsetData, rate_idx: Union[int, List[int],
                                                               np.ndarray]):
    if isinstance(rate_idx, int):
        rate_idx = [rate_idx]

    n_t_size = (len(amset_data.doping), len(amset_data.temperatures))
    all_rates = amset_data.scattering_rates
    all_vv = amset_data.velocities_product
    all_energies = amset_data.energies
    # all_curvature = amset_data.curvature

    mobility = np.zeros(n_t_size + (3, 3))
    for n, t in np.ndindex(n_t_size):
        energies = []
        vv = []
        # curvature = []
        rates = []
        for spin in amset_data.spins:
            cb_idx = amset_data.vb_idx[spin] + 1
            if amset_data.doping[n] > 0:
                # electrons
                energies.append(all_energies[spin][cb_idx:])
                vv.append(all_vv[spin][cb_idx:])
                # curvature.append(all_curvature[spin][cb_idx:])
                rates.append(
                    np.sum(all_rates[spin][rate_idx, n, t, cb_idx:], axis=0))
            else:
                # holes
                energies.append(all_energies[spin][:cb_idx])
                vv.append(all_vv[spin][:cb_idx])
                # curvature.append(all_curvature[spin][:cb_idx])
                rates.append(
                    np.sum(all_rates[spin][rate_idx, n, t, :cb_idx], axis=0))

        energies = np.vstack(energies)
        vv = np.vstack(vv)
        # curvature = np.vstack(curvature)
        lifetimes = 1 / np.vstack(rates)

        # Nones are required as BoltzTraP2 expects the Fermi and temp as arrays
        fermi = amset_data.fermi_levels[n, t][None]
        temp = amset_data.temperatures[t][None]

        # obtain the Fermi integrals for the temperature and doping
        epsilon, dos, vvdos, cdos = get_transport_dos(
            energies,
            vv,
            scattering_model=lifetimes,
            npts=len(amset_data.dos.energies),
            kpoint_weights=amset_data.kpoint_weights)

        c, l0, l1, l2, lm11 = fermiintegrals(
            epsilon,
            dos,
            vvdos,
            cdos=cdos,
            mur=fermi,
            Tr=temp,
            dosweight=amset_data.dos.dos_weight)

        c = ((-c[0, ...] - amset_data.dos.nelect) /
             (amset_data.structure.volume / (units.Meter / 100.)**3))

        # Compute the Onsager coefficients from Fermi integrals
        volume = (amset_data.structure.lattice.volume * units.Angstrom**3)
        sigma, _, _, _ = calc_Onsager_coefficients(l0, l1, l2, fermi, temp,
                                                   volume)

        if amset_data.doping[n] > 0:
            carrier_conc = amset_data.electron_conc[n, t]
        else:
            carrier_conc = amset_data.hole_conc[n, t]

        print(carrier_conc)
        print(c)

        # convert mobility to cm^2/V.s
        mobility[n, t] = sigma[0, ...] * 0.01 / (e * carrier_conc)

    return mobility