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)
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)
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)