예제 #1
0
class ConductivityRTABase(ConductivityBase):
    """Base class of ConductivityRTA*.

    This is a base class of RTA classes.

    """

    def __init__(
        self,
        interaction: Interaction,
        grid_points=None,
        temperatures=None,
        sigmas=None,
        sigma_cutoff=None,
        is_isotope=False,
        mass_variances=None,
        boundary_mfp=None,  # in micrometre
        use_ave_pp=False,
        is_kappa_star=True,
        gv_delta_q=None,
        is_full_pp=False,
        read_pp=False,
        store_pp=False,
        pp_filename=None,
        is_N_U=False,
        is_gamma_detail=False,
        is_frequency_shift_by_bubble=False,
        log_level=0,
    ):
        """Init method."""
        self._is_N_U = is_N_U
        self._is_gamma_detail = is_gamma_detail
        self._is_frequency_shift_by_bubble = is_frequency_shift_by_bubble

        self._gamma_N = None
        self._gamma_U = None
        self._gamma_detail_at_q = None
        self._use_ave_pp = use_ave_pp
        self._use_const_ave_pp = None
        self._averaged_pp_interaction = None
        self._num_ignored_phonon_modes = None

        super().__init__(
            interaction,
            grid_points=grid_points,
            temperatures=temperatures,
            sigmas=sigmas,
            sigma_cutoff=sigma_cutoff,
            is_isotope=is_isotope,
            mass_variances=mass_variances,
            boundary_mfp=boundary_mfp,
            is_kappa_star=is_kappa_star,
            gv_delta_q=gv_delta_q,
            is_full_pp=is_full_pp,
            log_level=log_level,
        )

        self._use_const_ave_pp = self._pp.get_constant_averaged_interaction()
        self._read_pp = read_pp
        self._store_pp = store_pp
        self._pp_filename = pp_filename

        if self._temperatures is not None:
            self._allocate_values()

        self._collision = ImagSelfEnergy(
            self._pp, with_detail=(self._is_gamma_detail or self._is_N_U)
        )

    def get_gamma_N_U(self):
        """Return N and U parts of gamma."""
        return (self._gamma_N, self._gamma_U)

    def set_gamma_N_U(self, gamma_N, gamma_U):
        """Set N and U parts of gamma."""
        self._gamma_N = gamma_N
        self._gamma_U = gamma_U

    def get_gamma_detail_at_q(self):
        """Return contribution of each triplet to gamma at current q-point."""
        return self._gamma_detail_at_q

    def get_number_of_ignored_phonon_modes(self):
        """Return number of ignored phonon modes."""
        return self._num_ignored_phonon_modes

    def set_averaged_pp_interaction(self, ave_pp):
        """Set averaged ph-ph interaction."""
        self._averaged_pp_interaction = ave_pp

    @abstractmethod
    def set_kappa_at_sigmas(self):
        """Must be implementated in the inherited class."""
        raise NotImplementedError()

    def _allocate_values(self):
        num_band0 = len(self._pp.band_indices)
        num_grid_points = len(self._grid_points)
        num_temp = len(self._temperatures)
        if not self._read_gamma:
            self._gamma = np.zeros(
                (len(self._sigmas), num_temp, num_grid_points, num_band0),
                order="C",
                dtype="double",
            )
            if self._is_gamma_detail or self._is_N_U:
                self._gamma_N = np.zeros_like(self._gamma)
                self._gamma_U = np.zeros_like(self._gamma)

        self._gv = np.zeros((num_grid_points, num_band0, 3), order="C", dtype="double")
        if self._is_isotope:
            self._gamma_iso = np.zeros(
                (len(self._sigmas), num_grid_points, num_band0),
                order="C",
                dtype="double",
            )
        if self._is_full_pp or self._use_ave_pp or self._use_const_ave_pp:
            self._averaged_pp_interaction = np.zeros(
                (num_grid_points, num_band0), order="C", dtype="double"
            )
        self._num_ignored_phonon_modes = np.zeros(
            (len(self._sigmas), num_temp), order="C", dtype="intc"
        )

    def _run_at_grid_point(self):
        i_gp = self._grid_point_count
        self._show_log_header(i_gp)
        grid_point = self._grid_points[i_gp]
        self._set_cv(i_gp, i_gp)
        self._set_velocities(i_gp, i_gp)

        if self._read_gamma:
            if self._use_ave_pp:
                self._collision.set_grid_point(grid_point)
                self._set_gamma_at_sigmas(i_gp)
        else:
            self._collision.set_grid_point(grid_point)
            num_triplets = len(self._pp.get_triplets_at_q()[0])
            if self._log_level:
                print("Number of triplets: %d" % num_triplets)

            if (
                self._is_full_pp
                or self._read_pp
                or self._store_pp
                or self._use_ave_pp
                or self._use_const_ave_pp
                or self._is_gamma_detail
            ):
                self._set_gamma_at_sigmas(i_gp)
            else:  # can save memory space
                self._set_gamma_at_sigmas_lowmem(i_gp)

        if self._is_isotope and not self._read_gamma_iso:
            gamma_iso = self._get_gamma_isotope_at_sigmas(i_gp)
            self._gamma_iso[:, i_gp, :] = gamma_iso[:, self._pp.band_indices]

        if self._log_level:
            self._show_log(i_gp)

    def _set_gamma_at_sigmas(self, i):
        for j, sigma in enumerate(self._sigmas):
            self._collision.set_sigma(sigma, sigma_cutoff=self._sigma_cutoff)
            self._collision.run_integration_weights()

            if self._log_level:
                text = "Collisions will be calculated with "
                if sigma is None:
                    text += "tetrahedron method."
                else:
                    text += "sigma=%s" % sigma
                    if self._sigma_cutoff is None:
                        text += "."
                    else:
                        text += "(%4.2f SD)." % self._sigma_cutoff
                print(text)

            if self._read_pp:
                pp, _g_zero = read_pp_from_hdf5(
                    self._pp.mesh_numbers,
                    grid_point=self._grid_points[i],
                    sigma=sigma,
                    sigma_cutoff=self._sigma_cutoff,
                    filename=self._pp_filename,
                    verbose=(self._log_level > 0),
                )
                _, g_zero = self._collision.get_integration_weights()
                if self._log_level:
                    if len(self._sigmas) > 1:
                        print(
                            "Multiple sigmas or mixing smearing and "
                            "tetrahedron method is not supported."
                        )
                if _g_zero is not None and (_g_zero != g_zero).any():
                    raise ValueError("Inconsistency found in g_zero.")
                self._collision.set_interaction_strength(pp)
            elif self._use_ave_pp:
                self._collision.set_averaged_pp_interaction(
                    self._averaged_pp_interaction[i]
                )
            elif self._use_const_ave_pp:
                if self._log_level:
                    print(
                        "Constant ph-ph interaction of %6.3e is used."
                        % self._pp.get_constant_averaged_interaction()
                    )
                self._collision.run_interaction()
                self._averaged_pp_interaction[i] = self._pp.get_averaged_interaction()
            elif j != 0 and (self._is_full_pp or self._sigma_cutoff is None):
                if self._log_level:
                    print("Existing ph-ph interaction is used.")
            else:
                if self._log_level:
                    print("Calculating ph-ph interaction...")
                self._collision.run_interaction(is_full_pp=self._is_full_pp)
                if self._is_full_pp:
                    self._averaged_pp_interaction[
                        i
                    ] = self._pp.get_averaged_interaction()

            # Number of triplets depends on q-point.
            # So this is allocated each time.
            if self._is_gamma_detail:
                num_temp = len(self._temperatures)
                self._gamma_detail_at_q = np.empty(
                    ((num_temp,) + self._pp.get_interaction_strength().shape),
                    dtype="double",
                    order="C",
                )
                self._gamma_detail_at_q[:] = 0

            if self._log_level:
                print("Calculating collisions at temperatures...")
            for k, t in enumerate(self._temperatures):
                self._collision.temperature = t
                self._collision.run()
                self._gamma[j, k, i] = self._collision.imag_self_energy
                if self._is_N_U or self._is_gamma_detail:
                    g_N, g_U = self._collision.get_imag_self_energy_N_and_U()
                    self._gamma_N[j, k, i] = g_N
                    self._gamma_U[j, k, i] = g_U
                if self._is_gamma_detail:
                    self._gamma_detail_at_q[
                        k
                    ] = self._collision.get_detailed_imag_self_energy()

    def _set_gamma_at_sigmas_lowmem(self, i):
        """Calculate gamma without storing ph-ph interaction strength.

        `svecs` and `multi` below must not be simply replaced by
        `self._pp.primitive.get_smallest_vectors()` because they must be in
        dense format as always so in Interaction class instance.
        `p2s`, `s2p`, and `masses` have to be also given from Interaction
        class instance.

        """
        band_indices = self._pp.band_indices
        (
            svecs,
            multi,
            p2s,
            s2p,
            masses,
        ) = self._pp.get_primitive_and_supercell_correspondence()
        fc3 = self._pp.fc3
        triplets_at_q, weights_at_q, _, _ = self._pp.get_triplets_at_q()
        symmetrize_fc3_q = 0

        if None in self._sigmas:
            thm = TetrahedronMethod(self._pp.bz_grid.microzone_lattice)

        # It is assumed that self._sigmas = [None].
        for j, sigma in enumerate(self._sigmas):
            self._collision.set_sigma(sigma)
            if self._is_N_U:
                collisions = np.zeros(
                    (2, len(self._temperatures), len(band_indices)),
                    dtype="double",
                    order="C",
                )
            else:
                collisions = np.zeros(
                    (len(self._temperatures), len(band_indices)),
                    dtype="double",
                    order="C",
                )
            import phono3py._phono3py as phono3c

            if sigma is None:
                phono3c.pp_collision(
                    collisions,
                    np.array(
                        np.dot(thm.get_tetrahedra(), self._pp.bz_grid.P.T),
                        dtype="int_",
                        order="C",
                    ),
                    self._frequencies,
                    self._eigenvectors,
                    triplets_at_q,
                    weights_at_q,
                    self._pp.bz_grid.addresses,
                    self._pp.bz_grid.gp_map,
                    self._pp.bz_grid.store_dense_gp_map * 1 + 1,
                    self._pp.bz_grid.D_diag,
                    self._pp.bz_grid.Q,
                    fc3,
                    svecs,
                    multi,
                    masses,
                    p2s,
                    s2p,
                    band_indices,
                    self._temperatures,
                    self._is_N_U * 1,
                    symmetrize_fc3_q,
                    self._pp.cutoff_frequency,
                )
            else:
                if self._sigma_cutoff is None:
                    sigma_cutoff = -1
                else:
                    sigma_cutoff = float(self._sigma_cutoff)
                phono3c.pp_collision_with_sigma(
                    collisions,
                    sigma,
                    sigma_cutoff,
                    self._frequencies,
                    self._eigenvectors,
                    triplets_at_q,
                    weights_at_q,
                    self._pp.bz_grid.addresses,
                    self._pp.bz_grid.D_diag,
                    self._pp.bz_grid.Q,
                    fc3,
                    svecs,
                    multi,
                    masses,
                    p2s,
                    s2p,
                    band_indices,
                    self._temperatures,
                    self._is_N_U * 1,
                    symmetrize_fc3_q,
                    self._pp.cutoff_frequency,
                )
            col_unit_conv = self._collision.unit_conversion_factor
            pp_unit_conv = self._pp.get_unit_conversion_factor()
            if self._is_N_U:
                col = collisions.sum(axis=0)
                col_N = collisions[0]
                col_U = collisions[1]
            else:
                col = collisions
            for k in range(len(self._temperatures)):
                self._gamma[j, k, i, :] = average_by_degeneracy(
                    col[k] * col_unit_conv * pp_unit_conv,
                    band_indices,
                    self._frequencies[self._grid_points[i]],
                )
                if self._is_N_U:
                    self._gamma_N[j, k, i, :] = average_by_degeneracy(
                        col_N[k] * col_unit_conv * pp_unit_conv,
                        band_indices,
                        self._frequencies[self._grid_points[i]],
                    )
                    self._gamma_U[j, k, i, :] = average_by_degeneracy(
                        col_U[k] * col_unit_conv * pp_unit_conv,
                        band_indices,
                        self._frequencies[self._grid_points[i]],
                    )

    def _show_log(self, i_gp):
        q = self._get_qpoint_from_gp_index(i_gp)
        gp = self._grid_points[i_gp]
        frequencies = self._frequencies[gp][self._pp.band_indices]
        gv = self._gv[i_gp]

        if self._averaged_pp_interaction is not None:
            ave_pp = self._averaged_pp_interaction[i_gp]
        else:
            ave_pp = None
        self._show_log_value_names()

        if self._log_level > 2:
            self._show_log_values_on_kstar(frequencies, gv, ave_pp, gp, q)
        else:
            self._show_log_values(frequencies, gv, ave_pp)

        print("", end="", flush=True)

    def _show_log_values(self, frequencies, gv, ave_pp):
        if self._is_full_pp or self._use_ave_pp or self._use_const_ave_pp:
            for f, v, pp in zip(frequencies, gv, ave_pp):
                print(
                    "%8.3f   (%8.3f %8.3f %8.3f) %8.3f %11.3e"
                    % (f, v[0], v[1], v[2], np.linalg.norm(v), pp)
                )
        else:
            for f, v in zip(frequencies, gv):
                print(
                    "%8.3f   (%8.3f %8.3f %8.3f) %8.3f"
                    % (f, v[0], v[1], v[2], np.linalg.norm(v))
                )

    def _show_log_values_on_kstar(self, frequencies, gv, ave_pp, gp, q):
        rotation_map = get_grid_points_by_rotations(gp, self._pp.bz_grid)
        for i, j in enumerate(np.unique(rotation_map)):
            for k, (rot, rot_c) in enumerate(
                zip(self._point_operations, self._rotations_cartesian)
            ):
                if rotation_map[k] != j:
                    continue

                print(
                    " k*%-2d (%5.2f %5.2f %5.2f)" % ((i + 1,) + tuple(np.dot(rot, q)))
                )
                if self._is_full_pp or self._use_ave_pp or self._use_const_ave_pp:
                    for f, v, pp in zip(frequencies, np.dot(rot_c, gv.T).T, ave_pp):
                        print(
                            "%8.3f   (%8.3f %8.3f %8.3f) %8.3f %11.3e"
                            % (f, v[0], v[1], v[2], np.linalg.norm(v), pp)
                        )
                else:
                    for f, v in zip(frequencies, np.dot(rot_c, gv.T).T):
                        print(
                            "%8.3f   (%8.3f %8.3f %8.3f) %8.3f"
                            % (f, v[0], v[1], v[2], np.linalg.norm(v))
                        )
        print("")

    def _show_log_value_names(self):
        if self._is_full_pp or self._use_ave_pp or self._use_const_ave_pp:
            text = "Frequency     group velocity (x, y, z)     |gv|       Pqj"
        else:
            text = "Frequency     group velocity (x, y, z)     |gv|"
        if self._velocity_obj.q_length is None:
            pass
        else:
            text += "  (dq=%3.1e)" % self._velocity_obj.q_length
        print(text)
예제 #2
0
class Conductivity_RTA(Conductivity):
    def __init__(
            self,
            interaction,
            symmetry,
            grid_points=None,
            temperatures=None,
            sigmas=None,
            sigma_cutoff=None,
            is_isotope=False,
            mass_variances=None,
            boundary_mfp=None,  # in micrometre
            use_ave_pp=False,
            gamma_unit_conversion=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            is_kappa_star=True,
            gv_delta_q=None,
            is_full_pp=False,
            read_pp=False,
            store_pp=False,
            pp_filename=None,
            is_N_U=False,
            is_gamma_detail=False,
            log_level=0):
        self._pp = None
        self._temperatures = None
        self._sigmas = None
        self._sigma_cutoff = None
        self._is_kappa_star = None
        self._gv_delta_q = None
        self._is_full_pp = None
        self._is_N_U = is_N_U
        self._is_gamma_detail = is_gamma_detail
        self._log_level = None
        self._primitive = None
        self._dm = None
        self._frequency_factor_to_THz = None
        self._cutoff_frequency = None
        self._boundary_mfp = None

        self._symmetry = None
        self._point_operations = None
        self._rotations_cartesian = None

        self._grid_points = None
        self._grid_weights = None
        self._grid_address = None

        self._read_gamma = False
        self._read_gamma_iso = False

        self._frequencies = None
        self._cv = None
        self._gv = None
        self._gv_sum2 = None
        self._gamma = None
        self._gamma_iso = None
        self._gamma_N = None
        self._gamma_U = None
        self._gamma_detail_at_q = None
        self._gamma_unit_conversion = gamma_unit_conversion
        self._use_ave_pp = use_ave_pp
        self._use_const_ave_pp = None
        self._averaged_pp_interaction = None
        self._num_ignored_phonon_modes = None
        self._num_sampling_grid_points = None

        self._mesh = None
        self._conversion_factor = None

        self._is_isotope = None
        self._isotope = None
        self._mass_variances = None
        self._grid_point_count = None

        Conductivity.__init__(self,
                              interaction,
                              symmetry,
                              grid_points=grid_points,
                              temperatures=temperatures,
                              sigmas=sigmas,
                              sigma_cutoff=sigma_cutoff,
                              is_isotope=is_isotope,
                              mass_variances=mass_variances,
                              mesh_divisors=mesh_divisors,
                              coarse_mesh_shifts=coarse_mesh_shifts,
                              boundary_mfp=boundary_mfp,
                              is_kappa_star=is_kappa_star,
                              gv_delta_q=gv_delta_q,
                              is_full_pp=is_full_pp,
                              log_level=log_level)

        self._use_const_ave_pp = self._pp.get_constant_averaged_interaction()
        self._read_pp = read_pp
        self._store_pp = store_pp
        self._pp_filename = pp_filename

        if self._temperatures is not None:
            self._allocate_values()

    def set_kappa_at_sigmas(self):
        num_band = self._primitive.get_number_of_atoms() * 3
        for i, grid_point in enumerate(self._grid_points):
            cv = self._cv[:, i, :]
            gp = self._grid_points[i]
            frequencies = self._frequencies[gp]

            # Kappa
            for j in range(len(self._sigmas)):
                for k in range(len(self._temperatures)):
                    g_sum = self._get_main_diagonal(i, j, k)
                    for l in range(num_band):
                        if frequencies[l] < self._cutoff_frequency:
                            self._num_ignored_phonon_modes[j, k] += 1
                            continue

                        old_settings = np.seterr(all='raise')
                        try:
                            self._mode_kappa[j, k, i,
                                             l] = (self._gv_sum2[i, l] *
                                                   cv[k, l] / (g_sum[l] * 2) *
                                                   self._conversion_factor)
                        except FloatingPointError:
                            # supposed that g is almost 0 and |gv|=0
                            pass
                        except:
                            print("=" * 26 + " Warning " + "=" * 26)
                            print(" Unexpected physical condition of ph-ph "
                                  "interaction calculation was found.")
                            print(" g=%f at gp=%d, band=%d, freq=%f" %
                                  (g_sum[l], gp, l + 1, frequencies[l]))
                            print("=" * 61)
                        np.seterr(**old_settings)

        N = self._num_sampling_grid_points
        self._kappa = self._mode_kappa.sum(axis=2).sum(axis=2) / N

    def get_gamma_N_U(self):
        return (self._gamma_N, self._gamma_U)

    def set_gamma_N_U(self, gamma_N, gamma_U):
        self._gamma_N = gamma_N
        self._gamma_U = gamma_U

    def get_gamma_detail_at_q(self):
        return self._gamma_detail_at_q

    def get_number_of_ignored_phonon_modes(self):
        return self._num_ignored_phonon_modes

    def get_number_of_sampling_grid_points(self):
        return self._num_sampling_grid_points

    def set_averaged_pp_interaction(self, ave_pp):
        self._averaged_pp_interaction = ave_pp

    def _run_at_grid_point(self):
        i = self._grid_point_count
        self._show_log_header(i)
        grid_point = self._grid_points[i]
        self._set_harmonic_properties(i, i)

        if self._read_gamma:
            if self._use_ave_pp:
                self._collision.set_grid_point(grid_point)
                self._set_gamma_at_sigmas(i)
        else:
            self._collision.set_grid_point(
                grid_point,
                stores_triplets_map=(self._is_full_pp
                                     or self._is_gamma_detail))
            num_triplets = len(self._pp.get_triplets_at_q()[0])
            if self._log_level:
                print("Number of triplets: %d" % num_triplets)

            if (self._is_full_pp or self._read_pp or self._store_pp
                    or self._use_ave_pp or self._use_const_ave_pp
                    or self._is_gamma_detail):
                self._set_gamma_at_sigmas(i)
            else:  # can save memory space
                self._set_gamma_at_sigmas_lowmem(i)

        if self._isotope is not None and not self._read_gamma_iso:
            gamma_iso = self._get_gamma_isotope_at_sigmas(i)
            self._gamma_iso[:, i, :] = gamma_iso[:,
                                                 self._pp.get_band_indices()]

        if self._log_level:
            self._show_log(self._qpoints[i], i)

    def _allocate_values(self):
        num_band0 = len(self._pp.get_band_indices())
        num_grid_points = len(self._grid_points)
        num_temp = len(self._temperatures)
        self._kappa = np.zeros((len(self._sigmas), num_temp, 6),
                               order='C',
                               dtype='double')
        self._mode_kappa = np.zeros(
            (len(self._sigmas), num_temp, num_grid_points, num_band0, 6),
            order='C',
            dtype='double')
        if not self._read_gamma:
            self._gamma = np.zeros(
                (len(self._sigmas), num_temp, num_grid_points, num_band0),
                order='C',
                dtype='double')
            if self._is_gamma_detail or self._is_N_U:
                self._gamma_N = np.zeros_like(self._gamma)
                self._gamma_U = np.zeros_like(self._gamma)
        self._gv = np.zeros((num_grid_points, num_band0, 3),
                            order='C',
                            dtype='double')
        self._gv_sum2 = np.zeros((num_grid_points, num_band0, 6),
                                 order='C',
                                 dtype='double')
        self._cv = np.zeros((num_temp, num_grid_points, num_band0),
                            order='C',
                            dtype='double')
        if self._isotope is not None:
            self._gamma_iso = np.zeros(
                (len(self._sigmas), num_grid_points, num_band0),
                order='C',
                dtype='double')
        if self._is_full_pp or self._use_ave_pp or self._use_const_ave_pp:
            self._averaged_pp_interaction = np.zeros(
                (num_grid_points, num_band0), order='C', dtype='double')
        self._num_ignored_phonon_modes = np.zeros(
            (len(self._sigmas), num_temp), order='C', dtype='intc')
        self._collision = ImagSelfEnergy(
            self._pp,
            with_detail=(self._is_gamma_detail or self._is_N_U),
            unit_conversion=self._gamma_unit_conversion)

    def _set_gamma_at_sigmas(self, i):
        for j, sigma in enumerate(self._sigmas):
            self._collision.set_sigma(sigma, sigma_cutoff=self._sigma_cutoff)
            self._collision.set_integration_weights()

            if self._log_level:
                text = "Collisions will be calculated with "
                if sigma is None:
                    text += "tetrahedron method."
                else:
                    text += "sigma=%s" % sigma
                    if self._sigma_cutoff is None:
                        text += "."
                    else:
                        text += "(%4.2f SD)." % self._sigma_cutoff
                print(text)

            if self._read_pp:
                pp, _g_zero = read_pp_from_hdf5(
                    self._mesh,
                    grid_point=self._grid_points[i],
                    sigma=sigma,
                    sigma_cutoff=self._sigma_cutoff,
                    filename=self._pp_filename,
                    verbose=(self._log_level > 0))
                _, g_zero = self._collision.get_integration_weights()
                if self._log_level:
                    if len(self._sigmas) > 1:
                        print("Multiple sigmas or mixing smearing and "
                              "tetrahedron method is not supported.")
                if _g_zero is not None and (_g_zero != g_zero).any():
                    raise ValueError("Inconsistency found in g_zero.")
                self._collision.set_interaction_strength(pp)
            elif self._use_ave_pp:
                self._collision.set_averaged_pp_interaction(
                    self._averaged_pp_interaction[i])
            elif self._use_const_ave_pp:
                if self._log_level:
                    print("Constant ph-ph interaction of %6.3e is used." %
                          self._pp.get_constant_averaged_interaction())
                self._collision.run_interaction()
                self._averaged_pp_interaction[i] = (
                    self._pp.get_averaged_interaction())
            elif j != 0 and (self._is_full_pp or self._sigma_cutoff is None):
                if self._log_level:
                    print("Existing ph-ph interaction is used.")
            else:
                if self._log_level:
                    print("Calculating ph-ph interaction...")
                self._collision.run_interaction(is_full_pp=self._is_full_pp)
                if self._is_full_pp:
                    self._averaged_pp_interaction[i] = (
                        self._pp.get_averaged_interaction())

            # Number of triplets depends on q-point.
            # So this is allocated each time.
            if self._is_gamma_detail:
                num_temp = len(self._temperatures)
                self._gamma_detail_at_q = np.empty(
                    ((num_temp, ) + self._pp.get_interaction_strength().shape),
                    dtype='double',
                    order='C')
                self._gamma_detail_at_q[:] = 0

            if self._log_level:
                print("Calculating collisions at temperatures...")
            for k, t in enumerate(self._temperatures):
                self._collision.set_temperature(t)
                self._collision.run()
                self._gamma[j, k, i] = self._collision.get_imag_self_energy()
                if self._is_N_U or self._is_gamma_detail:
                    g_N, g_U = self._collision.get_imag_self_energy_N_and_U()
                    self._gamma_N[j, k, i] = g_N
                    self._gamma_U[j, k, i] = g_U
                if self._is_gamma_detail:
                    self._gamma_detail_at_q[k] = (
                        self._collision.get_detailed_imag_self_energy())

    def _set_gamma_at_sigmas_lowmem(self, i):
        band_indices = self._pp.get_band_indices()
        (svecs, multiplicity, p2s, s2p,
         masses) = self._pp.get_primitive_and_supercell_correspondence()
        fc3 = self._pp.get_fc3()
        triplets_at_q, weights_at_q, _, _ = self._pp.get_triplets_at_q()
        bz_map = self._pp.get_bz_map()
        symmetrize_fc3_q = 0

        if None in self._sigmas:
            reclat = np.linalg.inv(self._pp.get_primitive().get_cell())
            thm = TetrahedronMethod(reclat, mesh=self._mesh)

        # It is assumed that self._sigmas = [None].
        for j, sigma in enumerate(self._sigmas):
            self._collision.set_sigma(sigma)
            if self._is_N_U:
                collisions = np.zeros(
                    (2, len(self._temperatures), len(band_indices)),
                    dtype='double',
                    order='C')
            else:
                collisions = np.zeros(
                    (len(self._temperatures), len(band_indices)),
                    dtype='double',
                    order='C')
            import phono3py._phono3py as phono3c
            if sigma is None:
                phono3c.pp_collision(collisions, thm.get_tetrahedra(),
                                     self._frequencies, self._eigenvectors,
                                     triplets_at_q, weights_at_q,
                                     self._grid_address, bz_map, self._mesh,
                                     fc3, svecs, multiplicity, masses, p2s,
                                     s2p, band_indices, self._temperatures,
                                     self._is_N_U * 1, symmetrize_fc3_q,
                                     self._cutoff_frequency)
            else:
                if self._sigma_cutoff is None:
                    sigma_cutoff = -1
                else:
                    sigma_cutoff = float(self._sigma_cutoff)
                phono3c.pp_collision_with_sigma(
                    collisions, sigma, sigma_cutoff, self._frequencies,
                    self._eigenvectors, triplets_at_q, weights_at_q,
                    self._grid_address, self._mesh, fc3, svecs, multiplicity,
                    masses, p2s, s2p, band_indices, self._temperatures,
                    self._is_N_U * 1, symmetrize_fc3_q, self._cutoff_frequency)
            col_unit_conv = self._collision.get_unit_conversion_factor()
            pp_unit_conv = self._pp.get_unit_conversion_factor()
            if self._is_N_U:
                col = collisions.sum(axis=0)
                col_N = collisions[0]
                col_U = collisions[1]
            else:
                col = collisions
            for k in range(len(self._temperatures)):
                self._gamma[j, k, i, :] = average_by_degeneracy(
                    col[k] * col_unit_conv * pp_unit_conv, band_indices,
                    self._frequencies[self._grid_points[i]])
                if self._is_N_U:
                    self._gamma_N[j, k, i, :] = average_by_degeneracy(
                        col_N[k] * col_unit_conv * pp_unit_conv, band_indices,
                        self._frequencies[self._grid_points[i]])
                    self._gamma_U[j, k, i, :] = average_by_degeneracy(
                        col_U[k] * col_unit_conv * pp_unit_conv, band_indices,
                        self._frequencies[self._grid_points[i]])

    def _show_log(self, q, i):
        gp = self._grid_points[i]
        frequencies = self._frequencies[gp][self._pp.get_band_indices()]
        gv = self._gv[i]
        if self._averaged_pp_interaction is not None:
            ave_pp = self._averaged_pp_interaction[i]
        else:
            ave_pp = None
        self._show_log_value_names()

        if self._log_level > 1:
            self._show_log_values_on_kstar(frequencies, gv, ave_pp, gp, q)
        else:
            self._show_log_values(frequencies, gv, ave_pp)

        sys.stdout.flush()

    def _show_log_values(self, frequencies, gv, ave_pp):
        if self._is_full_pp or self._use_ave_pp or self._use_const_ave_pp:
            for f, v, pp in zip(frequencies, gv, ave_pp):
                print("%8.3f   (%8.3f %8.3f %8.3f) %8.3f %11.3e" %
                      (f, v[0], v[1], v[2], np.linalg.norm(v), pp))
        else:
            for f, v in zip(frequencies, gv):
                print("%8.3f   (%8.3f %8.3f %8.3f) %8.3f" %
                      (f, v[0], v[1], v[2], np.linalg.norm(v)))

    def _show_log_values_on_kstar(self, frequencies, gv, ave_pp, gp, q):
        rotation_map = get_grid_points_by_rotations(self._grid_address[gp],
                                                    self._point_operations,
                                                    self._mesh)
        for i, j in enumerate(np.unique(rotation_map)):
            for k, (rot, rot_c) in enumerate(
                    zip(self._point_operations, self._rotations_cartesian)):
                if rotation_map[k] != j:
                    continue

                print(" k*%-2d (%5.2f %5.2f %5.2f)" %
                      ((i + 1, ) + tuple(np.dot(rot, q))))
                if (self._is_full_pp or self._use_ave_pp
                        or self._use_const_ave_pp):
                    for f, v, pp in zip(frequencies,
                                        np.dot(rot_c, gv.T).T, ave_pp):
                        print("%8.3f   (%8.3f %8.3f %8.3f) %8.3f %11.3e" %
                              (f, v[0], v[1], v[2], np.linalg.norm(v), pp))
                else:
                    for f, v in zip(frequencies, np.dot(rot_c, gv.T).T):
                        print("%8.3f   (%8.3f %8.3f %8.3f) %8.3f" %
                              (f, v[0], v[1], v[2], np.linalg.norm(v)))
        print('')

    def _show_log_value_names(self):
        if self._is_full_pp or self._use_ave_pp or self._use_const_ave_pp:
            text = "Frequency     group velocity (x, y, z)     |gv|       Pqj"
        else:
            text = "Frequency     group velocity (x, y, z)     |gv|"
        if self._gv_delta_q is None:
            pass
        else:
            text += "  (dq=%3.1e)" % self._gv_delta_q
        print(text)
예제 #3
0
class Conductivity_RTA(Conductivity):
    def __init__(
            self,
            interaction,
            symmetry,
            grid_points=None,
            temperatures=np.arange(0, 1001, 10, dtype='double'),
            sigmas=None,
            is_isotope=False,
            mass_variances=None,
            boundary_mfp=None,  # in micrometre
            use_ave_pp=False,
            gamma_unit_conversion=None,
            mesh_divisors=None,
            coarse_mesh_shifts=None,
            is_kappa_star=True,
            gv_delta_q=None,
            run_with_g=True,
            is_full_pp=False,
            is_gamma_detail=False,
            log_level=0):
        self._pp = None
        self._temperatures = None
        self._sigmas = None
        self._is_kappa_star = None
        self._gv_delta_q = None
        self._run_with_g = run_with_g
        self._is_full_pp = is_full_pp
        self._is_gamma_detail = is_gamma_detail
        self._log_level = None
        self._primitive = None
        self._dm = None
        self._frequency_factor_to_THz = None
        self._cutoff_frequency = None
        self._boundary_mfp = None

        self._symmetry = None
        self._point_operations = None
        self._rotations_cartesian = None

        self._grid_points = None
        self._grid_weights = None
        self._grid_address = None

        self._read_gamma = False
        self._read_gamma_iso = False

        self._frequencies = None
        self._gv = None
        self._gv_sum2 = None
        self._gamma = None
        self._gamma_iso = None
        self._gamma_N = None
        self._gamma_U = None
        self._gamma_detail_at_q = None
        self._gamma_unit_conversion = gamma_unit_conversion
        self._use_ave_pp = use_ave_pp
        self._averaged_pp_interaction = None
        self._num_ignored_phonon_modes = None
        self._num_sampling_grid_points = None

        self._mesh = None
        self._mesh_divisors = None
        self._coarse_mesh = None
        self._coarse_mesh_shifts = None
        self._conversion_factor = None

        self._is_isotope = None
        self._isotope = None
        self._mass_variances = None
        self._grid_point_count = None

        Conductivity.__init__(self,
                              interaction,
                              symmetry,
                              grid_points=grid_points,
                              temperatures=temperatures,
                              sigmas=sigmas,
                              is_isotope=is_isotope,
                              mass_variances=mass_variances,
                              mesh_divisors=mesh_divisors,
                              coarse_mesh_shifts=coarse_mesh_shifts,
                              boundary_mfp=boundary_mfp,
                              is_kappa_star=is_kappa_star,
                              gv_delta_q=gv_delta_q,
                              log_level=log_level)

        self._cv = None

        if self._temperatures is not None:
            self._allocate_values()

    def set_kappa_at_sigmas(self):
        num_band = self._primitive.get_number_of_atoms() * 3
        self._num_sampling_grid_points = 0

        for i, grid_point in enumerate(self._grid_points):
            cv = self._cv[:, i, :]
            gp = self._grid_points[i]
            frequencies = self._frequencies[gp]

            # Outer product of group velocities (v x v) [num_k*, num_freqs, 3, 3]
            gv_by_gv_tensor, order_kstar = self._get_gv_by_gv(i)
            self._num_sampling_grid_points += order_kstar

            # Sum all vxv at k*
            gv_sum2 = np.zeros((6, num_band), dtype='double')
            for j, vxv in enumerate(
                ([0, 0], [1, 1], [2, 2], [1, 2], [0, 2], [0, 1])):
                gv_sum2[j] = gv_by_gv_tensor[:, vxv[0], vxv[1]]

            # Kappa
            for j in range(len(self._sigmas)):
                for k in range(len(self._temperatures)):
                    g_sum = self._get_main_diagonal(i, j, k)
                    for l in range(num_band):
                        if frequencies[l] < self._cutoff_frequency:
                            self._num_ignored_phonon_modes[j, k] += 1
                            continue

                        self._mode_kappa[j, k, i,
                                         l] = (gv_sum2[:, l] * cv[k, l] /
                                               (g_sum[l] * 2) *
                                               self._conversion_factor)

            self._gv_sum2[i] = gv_sum2.T

        self._mode_kappa /= self._num_sampling_grid_points
        self._kappa = self._mode_kappa.sum(axis=2).sum(axis=2)

    def get_mode_heat_capacities(self):
        return self._cv

    def get_gv_by_gv(self):
        return self._gv_sum2

    def get_gamma_N_U(self):
        return (self._gamma_N, self._gamma_U)

    def get_gamma_detail_at_q(self):
        return self._gamma_detail_at_q

    def get_number_of_ignored_phonon_modes(self):
        return self._num_ignored_phonon_modes

    def get_number_of_sampling_grid_points(self):
        return self._num_sampling_grid_points

    def get_averaged_pp_interaction(self):
        return self._averaged_pp_interaction

    def set_averaged_pp_interaction(self, ave_pp):
        self._averaged_pp_interaction = ave_pp

    def _run_at_grid_point(self):
        i = self._grid_point_count
        self._show_log_header(i)
        grid_point = self._grid_points[i]

        if self._read_gamma:
            if self._use_ave_pp:
                self._collision.set_grid_point(grid_point)
                self._collision.set_averaged_pp_interaction(
                    self._averaged_pp_interaction[i])
                self._set_gamma_at_sigmas(i)
        else:
            self._collision.set_grid_point(grid_point)
            if self._log_level:
                print("Number of triplets: %d" %
                      len(self._pp.get_triplets_at_q()[0]))
                print("Calculating ph-ph interaction...")

            self._set_gamma_at_sigmas(i)

        if self._isotope is not None and not self._read_gamma_iso:
            self._set_gamma_isotope_at_sigmas(i)

        freqs = self._frequencies[grid_point][self._pp.get_band_indices()]
        self._cv[:, i, :] = self._get_cv(freqs)
        self._set_gv(i)

        if self._log_level:
            self._show_log(self._qpoints[i], i)

    def _allocate_values(self):
        num_band0 = len(self._pp.get_band_indices())
        num_band = self._primitive.get_number_of_atoms() * 3
        num_grid_points = len(self._grid_points)
        num_temp = len(self._temperatures)
        self._kappa = np.zeros((len(self._sigmas), num_temp, 6),
                               dtype='double')
        self._mode_kappa = np.zeros(
            (len(self._sigmas), num_temp, num_grid_points, num_band0, 6),
            dtype='double')
        if not self._read_gamma:
            self._gamma = np.zeros(
                (len(self._sigmas), num_temp, num_grid_points, num_band0),
                dtype='double')
            if self._is_gamma_detail:
                self._gamma_N = np.zeros_like(self._gamma)
                self._gamma_U = np.zeros_like(self._gamma)
        self._gv = np.zeros((num_grid_points, num_band0, 3), dtype='double')
        self._gv_sum2 = np.zeros((num_grid_points, num_band0, 6),
                                 dtype='double')
        self._cv = np.zeros((num_temp, num_grid_points, num_band0),
                            dtype='double')
        if self._isotope is not None:
            self._gamma_iso = np.zeros(
                (len(self._sigmas), num_grid_points, num_band0),
                dtype='double')
        if self._is_full_pp or self._use_ave_pp:
            self._averaged_pp_interaction = np.zeros(
                (num_grid_points, num_band0), dtype='double')
        self._num_ignored_phonon_modes = np.zeros(
            (len(self._sigmas), num_temp), dtype='intc')
        self._collision = ImagSelfEnergy(
            self._pp,
            with_detail=self._is_gamma_detail,
            unit_conversion=self._gamma_unit_conversion)

    def _set_gamma_at_sigmas(self, i):
        for j, sigma in enumerate(self._sigmas):
            self._collision.set_sigma(sigma)
            if sigma is None or self._run_with_g:
                self._collision.set_integration_weights()

            if not self._use_ave_pp:
                if self._log_level:
                    text = "Calculating Gamma of ph-ph with "
                    if sigma is None:
                        text += "tetrahedron method"
                    else:
                        text += "sigma=%s" % sigma
                    print(text)
                if self._is_full_pp and j != 0:
                    pass
                else:
                    self._collision.run_interaction(
                        is_full_pp=self._is_full_pp)
                if self._is_full_pp and j == 0:
                    self._averaged_pp_interaction[i] = (
                        self._pp.get_averaged_interaction())

            # Number of triplets depends on q-point.
            # So this is allocated each time.
            if self._is_gamma_detail:
                num_temp = len(self._temperatures)
                self._gamma_detail_at_q = np.zeros(
                    ((num_temp, ) + self._pp.get_interaction_strength().shape),
                    dtype='double',
                    order='C')

            for k, t in enumerate(self._temperatures):
                self._collision.set_temperature(t)
                self._collision.run()
                self._gamma[j, k, i] = self._collision.get_imag_self_energy()
                if self._is_gamma_detail:
                    g_N, g_U = self._collision.get_imag_self_energy_N_and_U()
                    self._gamma_N[j, k, i] = g_N
                    self._gamma_U[j, k, i] = g_U
                    self._gamma_detail_at_q[k] = (
                        self._collision.get_detailed_imag_self_energy())

    def _get_gv_by_gv(self, i):
        rotation_map = get_grid_points_by_rotations(
            self._grid_address[self._grid_points[i]], self._point_operations,
            self._mesh)
        gv_by_gv = np.zeros((len(self._gv[i]), 3, 3), dtype='double')

        for r in self._rotations_cartesian:
            gvs_rot = np.dot(self._gv[i], r.T)
            gv_by_gv += [np.outer(r_gv, r_gv) for r_gv in gvs_rot]
        gv_by_gv /= len(rotation_map) // len(np.unique(rotation_map))
        order_kstar = len(np.unique(rotation_map))

        if order_kstar != self._grid_weights[i]:
            if self._log_level:
                print("*" * 33 + "Warning" + "*" * 33)
                print(" Number of elements in k* is unequal "
                      "to number of equivalent grid-points.")
                print("*" * 73)

        return gv_by_gv, order_kstar

    def _get_cv(self, freqs):
        cv = np.zeros((len(self._temperatures), len(freqs)), dtype='double')
        # T/freq has to be large enough to avoid divergence.
        # Otherwise just set 0.
        for i, f in enumerate(freqs):
            finite_t = (self._temperatures > f / 100)
            if f > self._cutoff_frequency:
                cv[:, i] = np.where(
                    finite_t,
                    get_mode_cv(np.where(finite_t, self._temperatures, 10000),
                                f * THzToEv), 0)
        return cv

    def _show_log(self, q, i):
        gp = self._grid_points[i]
        frequencies = self._frequencies[gp][self._pp.get_band_indices()]
        gv = self._gv[i]

        if self._is_full_pp or self._use_ave_pp:
            ave_pp = self._averaged_pp_interaction[i]

        if self._is_full_pp or self._use_ave_pp:
            text = "Frequency     group velocity (x, y, z)     |gv|       Pqj"
        else:
            text = "Frequency     group velocity (x, y, z)     |gv|"
        if self._gv_delta_q is None:
            pass
        else:
            text += "  (dq=%3.1e)" % self._gv_delta_q
        print(text)

        if self._log_level > 1:
            rotation_map = get_grid_points_by_rotations(
                self._grid_address[gp], self._point_operations, self._mesh)
            for i, j in enumerate(np.unique(rotation_map)):
                for k, (rot, rot_c) in enumerate(
                        zip(self._point_operations,
                            self._rotations_cartesian)):
                    if rotation_map[k] != j:
                        continue

                    print(" k*%-2d (%5.2f %5.2f %5.2f)" %
                          ((i + 1, ) + tuple(np.dot(rot, q))))
                    if self._is_full_pp or self._use_ave_pp:
                        for f, v, pp in zip(frequencies,
                                            np.dot(rot_c, gv.T).T, ave_pp):
                            print("%8.3f   (%8.3f %8.3f %8.3f) %8.3f %11.3e" %
                                  (f, v[0], v[1], v[2], np.linalg.norm(v), pp))
                    else:
                        for f, v in zip(frequencies, np.dot(rot_c, gv.T).T):
                            print("%8.3f   (%8.3f %8.3f %8.3f) %8.3f" %
                                  (f, v[0], v[1], v[2], np.linalg.norm(v)))
            print('')
        else:
            if self._is_full_pp or self._use_ave_pp:
                for f, v, pp in zip(frequencies, gv, ave_pp):
                    print("%8.3f   (%8.3f %8.3f %8.3f) %8.3f %11.3e" %
                          (f, v[0], v[1], v[2], np.linalg.norm(v), pp))
            else:
                for f, v in zip(frequencies, gv):
                    print("%8.3f   (%8.3f %8.3f %8.3f) %8.3f" %
                          (f, v[0], v[1], v[2], np.linalg.norm(v)))