Esempio n. 1
0
    def calculate_rate(self, spin, b_idx, k_idx, energy_diff=None):
        rlat = self.amset_data.structure.lattice.reciprocal_lattice.matrix
        ir_kpoints_idx = self.amset_data.ir_kpoints_idx
        energy = self.amset_data.energies[spin][b_idx, ir_kpoints_idx][k_idx]

        if energy_diff:
            energy += energy_diff

        tbs = self.amset_data.tetrahedral_band_structure

        (
            tet_dos,
            tet_mask,
            cs_weights,
            tet_contributions,
        ) = tbs.get_tetrahedra_density_of_states(
            spin,
            energy,
            return_contributions=True,
            symmetry_reduce=False,
            # band_idx=b_idx,  # turn this on to disable interband scattering
        )

        if len(tet_dos) == 0:
            return 0

        # next, get k-point indices and band_indices
        # property_mask, band_kpoint_mask, band_mask, kpoint_mask = tbs.get_masks(
        #     spin, tet_mask
        # )

        k = self.amset_data.ir_kpoints[k_idx]
        # k_primes = self.amset_data.kpoints[kpoint_mask]

        # overlap = self.amset_data.overlap_calculator.get_overlap(
        #     spin, b_idx, k, band_mask, k_primes
        # )
        #
        # # put overlap back in array with shape (nbands, nkpoints)
        # all_overlap = np.zeros(self.amset_data.energies[spin].shape)
        # all_overlap[band_kpoint_mask] = overlap
        #
        # # now select the properties at the tetrahedron vertices
        # vert_overlap = all_overlap[property_mask]
        #
        # # get interpolated overlap at centre of tetrahedra cross sections
        # tet_overlap = get_cross_section_values(vert_overlap, *tet_contributions)
        tetrahedra = tbs.tetrahedra[spin][tet_mask]

        # have to deal with the case where the tetrahedron cross section crosses the
        # zone boundary. This is a slight inaccuracy but we just treat the
        # cross section as if it is on one side of the boundary
        tet_kpoints = self.amset_data.kpoints[tetrahedra]
        base_kpoints = tet_kpoints[:, 0][:, None, :]
        k_diff = pbc_diff(tet_kpoints, base_kpoints) + pbc_diff(
            base_kpoints, k)

        k_diff = np.dot(k_diff, rlat)
        intersections = get_cross_section_values(k_diff,
                                                 *tet_contributions,
                                                 average=False)
        projected_intersections, basis = get_projected_intersections(
            intersections)

        k_spacing = np.linalg.norm(
            np.dot(rlat, 1 / self.amset_data.kpoint_mesh))
        qpoints, weights, mapping = get_fine_mesh_qpoints(
            projected_intersections,
            basis,
            *tet_contributions[0:3],
            high_tol=k_spacing * 0.5,
            med_tol=k_spacing * 2,
            cross_section_weights=cs_weights)
        qpoint_norm_sq = np.sum(qpoints**2, axis=-1)

        k_primes = np.dot(qpoints, np.linalg.inv(rlat)) + k
        k_primes = kpoints_to_first_bz(k_primes)
        if energy_diff:
            fd = _get_fd(energy, self.amset_data)
            emission = energy_diff <= 0
            rates = [
                s.factor(qpoint_norm_sq, emission, fd)
                for s in self.inelastic_scatterers
            ]
            mrta_factor = 1
        else:
            mrta_factor = self.amset_data.mrta_calculator.get_mrta_factor(
                spin, b_idx, k, tet_mask[0][mapping], k_primes)
            rates = [s.factor(qpoint_norm_sq) for s in self.elastic_scatterers]

        rates = np.array(rates)

        # sometimes the projected intersections can be nan when the density of states
        # contribution is infinitesimally small; this catches those errors
        rates[np.isnan(rates)] = 0

        overlap = self.amset_data.overlap_calculator.get_overlap(
            spin, b_idx, k, tet_mask[0][mapping], k_primes)

        rates /= self.amset_data.structure.lattice.reciprocal_lattice.volume
        rates *= overlap * weights * mrta_factor

        return np.sum(rates, axis=-1)
Esempio n. 2
0
    def calculate_rate(self, spin, b_idx, k_idx, energy_diff=None):
        rlat = self.amset_data.structure.lattice.reciprocal_lattice.matrix
        energy = self.amset_data.energies[spin][b_idx, k_idx]
        velocity = self.amset_data.velocities[spin][b_idx, k_idx]

        if energy_diff:
            energy += energy_diff

        tbs = self.amset_data.tetrahedral_band_structure

        (
            tet_dos,
            tet_mask,
            cs_weights,
            tet_contributions,
        ) = tbs.get_tetrahedra_density_of_states(
            spin,
            energy,
            return_contributions=True,
            symmetry_reduce=False,
            # band_idx=b_idx,  # turn this on to disable interband scattering
        )

        if len(tet_dos) == 0:
            return 0

        # next, get k-point indices and band_indices
        property_mask, band_kpoint_mask, band_mask, kpoint_mask = tbs.get_masks(
            spin, tet_mask)
        k = self.amset_data.kpoints[k_idx]
        k_primes = self.amset_data.kpoints[kpoint_mask]

        if self.cache_wavefunction:
            # use cached coefficients to calculate the overlap on the fine mesh
            # tetrahedron vertices
            p1 = self._coeffs[spin][self._coeffs_mapping[spin][b_idx, k_idx]]
            p2 = self._coeffs[spin][self._coeffs_mapping[spin][band_mask,
                                                               kpoint_mask]]
            overlap = get_overlap(p1, p2)
        else:
            overlap = self.amset_data.overlap_calculator.get_overlap(
                spin, b_idx, k, band_mask, k_primes)

        # put overlap back in array with shape (nbands, nkpoints)
        all_overlap = np.zeros(self.amset_data.energies[spin].shape)
        all_overlap[band_kpoint_mask] = overlap

        # now select the properties at the tetrahedron vertices
        vert_overlap = all_overlap[property_mask]

        # get interpolated overlap at centre of tetrahedra cross sections
        tet_overlap = get_cross_section_values(vert_overlap,
                                               *tet_contributions)
        tetrahedra = tbs.tetrahedra[spin][tet_mask]

        # have to deal with the case where the tetrahedron cross section crosses the
        # zone boundary. This is a slight inaccuracy but we just treat the
        # cross section as if it is on one side of the boundary
        tet_kpoints = self.amset_data.kpoints[tetrahedra]
        base_kpoints = tet_kpoints[:, 0][:, None, :]
        k_diff = pbc_diff(tet_kpoints, base_kpoints) + pbc_diff(
            base_kpoints, k)

        # project the tetrahedron cross sections onto 2D surfaces in either a triangle
        # or quadrilateral
        k_diff = np.dot(k_diff, rlat)
        intersections = get_cross_section_values(k_diff,
                                                 *tet_contributions,
                                                 average=False)
        projected_intersections, basis = get_projected_intersections(
            intersections)

        k_spacing = np.linalg.norm(
            np.dot(rlat, 1 / self.amset_data.kpoint_mesh))
        qpoints, weights, mapping = get_fine_mesh_qpoints(
            projected_intersections,
            basis,
            *tet_contributions[0:3],
            high_tol=k_spacing * 0.5,
            med_tol=k_spacing * 2,
            cross_section_weights=cs_weights,
        )
        qpoint_norm_sq = np.sum(qpoints**2, axis=-1)

        k_primes = np.dot(qpoints, np.linalg.inv(rlat)) + k
        k_primes = kpoints_to_first_bz(k_primes)

        # unit q in reciprocal cartesian coordinates
        unit_q = qpoints / np.sqrt(qpoint_norm_sq)[:, None]
        if energy_diff:
            e_fd = _get_fd(energy, self.amset_data)
            emission = energy_diff <= 0
            rates = [
                s.factor(unit_q, qpoint_norm_sq, emission, e_fd)
                for s in self.inelastic_scatterers
            ]
            mrta_factor = 1
        else:
            mrta_factor = self.amset_data.mrta_calculator.get_mrta_factor(
                spin, b_idx, k, tet_mask[0][mapping], k_primes)
            rates = [
                s.factor(unit_q, qpoint_norm_sq, spin, b_idx, k, velocity)
                for s in self.elastic_scatterers
            ]

        rates = np.array(rates)
        rates /= self.amset_data.structure.lattice.reciprocal_lattice.volume
        rates *= tet_overlap[mapping] * weights * mrta_factor

        # this is too expensive vs tetrahedron integration and doesn't add much more
        # accuracy; could offer this as an option
        # overlap = self.amset_data.overlap_calculator.get_overlap(
        #     spin, b_idx, k, tet_mask[0][mapping], k_primes
        # )
        # rates *= overlap * weights * mrta_factor

        # sometimes the projected intersections can be nan when the density of states
        # contribution is infinitesimally small; this catches those errors
        rates[np.isnan(rates)] = 0

        return np.sum(rates, axis=-1)
Esempio n. 3
0
    def calculate_rate(self, spin, b_idx, k_idx, energy_diff=None):
        rlat = self.amset_data.structure.lattice.reciprocal_lattice.matrix
        ir_kpoints_idx = self.amset_data.ir_kpoints_idx
        energy = self.amset_data.energies[spin][b_idx, ir_kpoints_idx][k_idx]

        if energy_diff:
            energy += energy_diff

        tbs = self.amset_data.tetrahedral_band_structure

        tet_dos, tet_mask, cs_weights, tet_contributions = tbs.get_tetrahedra_density_of_states(
            spin,
            energy,
            return_contributions=True,
            symmetry_reduce=False,
            # band_idx=b_idx,
        )

        if len(tet_dos) == 0:
            return 0

        # next, get k-point indices and band_indices
        property_mask, band_kpoint_mask, band_mask, kpoint_mask = tbs.get_masks(
            spin, tet_mask)

        k = self.amset_data.ir_kpoints[k_idx]
        k_primes = self.amset_data.kpoints[kpoint_mask]

        overlap = self.amset_data.overlap_calculator.get_overlap(
            spin, b_idx, k, band_mask, k_primes)

        # put overlap back in array with shape (nbands, nkpoints)
        all_overlap = np.zeros(self.amset_data.energies[spin].shape)
        all_overlap[band_kpoint_mask] = overlap

        # now select the properties at the tetrahedron vertices
        vert_overlap = all_overlap[property_mask]

        # get interpolated overlap and k-point at centre of tetrahedra cross sections
        tet_overlap = get_cross_section_values(vert_overlap,
                                               *tet_contributions)
        tetrahedra = tbs.tetrahedra[spin][tet_mask]

        # have to deal with the case where the tetrahedron cross section crosses the
        # zone boundary. This is a slight inaccuracy but we just treat the
        # cross section as if it is on one side of the boundary
        tet_kpoints = self.amset_data.kpoints[tetrahedra]
        base_kpoints = tet_kpoints[:, 0][:, None, :]
        k_diff = pbc_diff(tet_kpoints, base_kpoints) + pbc_diff(
            base_kpoints, k)
        k_diff = np.dot(k_diff, rlat)

        intersections = get_cross_section_values(k_diff,
                                                 *tet_contributions,
                                                 average=False)
        projected_intersections = get_projected_intersections(intersections)

        if energy_diff:
            f = np.zeros(self.amset_data.fermi_levels.shape)

            for n, t in np.ndindex(self.amset_data.fermi_levels.shape):
                f[n, t] = FD(
                    energy,
                    self.amset_data.fermi_levels[n, t],
                    self.amset_data.temperatures[t] * units.BOLTZMANN,
                )

            functions = np.array([
                m.factor(energy_diff <= 0, f)
                for m in self.inelastic_scatterers
            ])
        else:
            functions = np.array([m.factor() for m in self.elastic_scatterers])

        rates = np.array([
            integrate_function_over_cross_section(
                f,
                projected_intersections,
                *tet_contributions[0:3],
                return_shape=self.amset_data.fermi_levels.shape,
                cross_section_weights=cs_weights) for f in functions
        ])

        # sometimes the projected intersections can be nan when the density of states
        # contribution is infinitesimally small; this catches those errors
        rates[np.isnan(rates)] = 0

        rates /= self.amset_data.structure.lattice.reciprocal_lattice.volume
        rates *= tet_overlap

        return np.sum(rates, axis=-1)