Exemple #1
0
    def spectral_function_integration(self, domain=None, integrand=None,
                                      x=None, kwargs=None, out_wxx=None):
        """Integrate response function.

        Assume that the integral has the
        form of a response function. For the linear tetrahedron
        method it is possible calculate frequency dependent weights
        and do a point summation using these weights."""

        if out_wxx is None:
            raise NotImplementedError

        nG = out_wxx.shape[2]
        mynG = (nG + self.blockcomm.size - 1) // self.blockcomm.size
        self.Ga = min(self.blockcomm.rank * mynG, nG)
        self.Gb = min(self.Ga + mynG, nG)
        # assert mynG * (self.blockcomm.size - 1) < nG, \
        #     print('mynG', mynG, 'nG', nG, 'nblocks', self.blockcomm.size)

        # Input domain
        td = self.tesselate(domain[0])
        args = domain[1:]
        get_matrix_element, get_eigenvalues = integrand

        # The kwargs contain any constant
        # arguments provided by the user
        if kwargs is not None:
            get_matrix_element = partial(get_matrix_element,
                                         **kwargs[0])
            get_eigenvalues = partial(get_eigenvalues,
                                      **kwargs[1])

        # Relevant quantities
        bzk_kc = td.points
        nk = len(bzk_kc)

        with self.timer('pts'):
            # Point to simplex
            pts_k = [[] for n in range(nk)]
            for s, K_k in enumerate(td.simplices):
                A_kv = np.append(td.points[K_k],
                                 np.ones(4)[:, np.newaxis], axis=1)

                D_kv = np.append((A_kv[:, :-1]**2).sum(1)[:, np.newaxis],
                                 A_kv, axis=1)
                a = np.linalg.det(D_kv[:, np.arange(5) != 0])

                if np.abs(a) < 1e-10:
                    continue

                for K in K_k:
                    pts_k[K].append(s)

            # Change to numpy arrays:
            for k in range(nk):
                pts_k[k] = np.array(pts_k[k], int)

        with self.timer('neighbours'):
            # Nearest neighbours
            neighbours_k = [None for n in range(nk)]

            for k in range(nk):
                neighbours_k[k] = np.unique(td.simplices[pts_k[k]])

        # Distribute everything
        myterms_t = self.distribute_domain(list(args) +
                                           [list(range(nk))])

        with self.timer('eigenvalues'):
            # Store eigenvalues
            deps_tMk = None  # t for term
            shape = [len(domain_l) for domain_l in args]
            nterms = int(np.prod(shape))

            for t in range(nterms):
                if len(shape) == 0:
                    arguments = ()
                else:
                    arguments = np.unravel_index(t, shape)
                for K in range(nk):
                    k_c = bzk_kc[K]
                    deps_M = -get_eigenvalues(k_c, *arguments)
                    if deps_tMk is None:
                        deps_tMk = np.zeros([nterms] +
                                            list(deps_M.shape) +
                                            [nk], float)
                    deps_tMk[t, :, K] = deps_M

        omega_w = x.get_data()

        # Calculate integrations weight
        pb = ProgressBar(self.fd)
        for _, arguments in pb.enumerate(myterms_t):
            K = arguments[-1]
            if len(shape) == 0:
                t = 0
            else:
                t = np.ravel_multi_index(arguments[:-1], shape)
            deps_Mk = deps_tMk[t]
            teteps_Mk = deps_Mk[:, neighbours_k[K]]
            i0_M, i1_M = x.get_index_range(teteps_Mk.min(1), teteps_Mk.max(1))

            n_MG = get_matrix_element(bzk_kc[K],
                                      *arguments[:-1])
            for n_G, deps_k, i0, i1 in zip(n_MG, deps_Mk,
                                           i0_M, i1_M):
                if i0 == i1:
                    continue

                W_w = self.get_kpoint_weight(K, deps_k,
                                             pts_k, omega_w[i0:i1],
                                             td)

                for iw, weight in enumerate(W_w):
                    if self.blockcomm.size > 1:
                        myn_G = n_G[self.Ga:self.Gb].reshape((-1, 1))
                        gemm(weight, n_G.reshape((-1, 1)), myn_G,
                             1.0, out_wxx[i0 + iw], 'c')
                    else:
                        czher(weight, n_G.conj(), out_wxx[i0 + iw])

        self.kncomm.sum(out_wxx)

        if self.blockcomm.size == 1:
            # Fill in upper/lower triangle also:
            nx = out_wxx.shape[1]
            il = np.tril_indices(nx, -1)
            iu = il[::-1]
            for out_xx in out_wxx:
                out_xx[il] = out_xx[iu].conj()
Exemple #2
0
    def response_function_integration(self, domain=None, integrand=None,
                                      x=None, kwargs=None, out_wxx=None,
                                      timeordered=False, hermitian=False,
                                      intraband=False, hilbert=False,
                                      wings=False, **extraargs):
        """Integrate a response function over bands and kpoints.

        func: method
        omega_w: ndarray
        out: np.ndarray
        timeordered: Bool
        """
        if out_wxx is None:
            raise NotImplementedError

        nG = out_wxx.shape[2]
        mynG = (nG + self.blockcomm.size - 1) // self.blockcomm.size
        self.Ga = min(self.blockcomm.rank * mynG, nG)
        self.Gb = min(self.Ga + mynG, nG)
        # assert mynG * (self.blockcomm.size - 1) < nG, \
        #     print('mynG', mynG, 'nG', nG, 'nblocks', self.blockcomm.size)

        mydomain_t = self.distribute_domain(domain)
        nbz = len(domain[0])
        get_matrix_element, get_eigenvalues = integrand
        
        prefactor = (2 * np.pi)**3 / self.vol / nbz
        out_wxx /= prefactor

        # The kwargs contain any constant
        # arguments provided by the user
        if kwargs is not None:
            get_matrix_element = partial(get_matrix_element,
                                         **kwargs[0])
            get_eigenvalues = partial(get_eigenvalues,
                                      **kwargs[1])

        # Sum kpoints
        # Calculate integrations weight
        pb = ProgressBar(self.fd)
        for _, arguments in pb.enumerate(mydomain_t):
            n_MG = get_matrix_element(*arguments)
            if n_MG is None:
                continue
            deps_M = get_eigenvalues(*arguments)

            if intraband:
                self.update_intraband(n_MG, out_wxx, **extraargs)
            elif hermitian and not wings:
                self.update_hermitian(n_MG, deps_M, x, out_wxx, **extraargs)
            elif hermitian and wings:
                self.update_optical_limit(n_MG, deps_M, x, out_wxx,
                                          **extraargs)
            elif hilbert and not wings:
                self.update_hilbert(n_MG, deps_M, x, out_wxx, **extraargs)
            elif hilbert and wings:
                self.update_hilbert_optical_limit(n_MG, deps_M, x,
                                                  out_wxx, **extraargs)
            elif wings:
                self.update_optical_limit(n_MG, deps_M, x, out_wxx,
                                          **extraargs)
            else:
                self.update(n_MG, deps_M, x, out_wxx, **extraargs)

        # Sum over
        self.kncomm.sum(out_wxx)

        if (hermitian or hilbert) and self.blockcomm.size == 1 and not wings:
            # Fill in upper/lower triangle also:
            nx = out_wxx.shape[1]
            il = np.tril_indices(nx, -1)
            iu = il[::-1]
            if hilbert:
                for out_xx in out_wxx:
                    out_xx[il] = out_xx[iu].conj()
            else:
                for out_xx in out_wxx:
                    out_xx[iu] = out_xx[il].conj()
        
        out_wxx *= prefactor