Example #1
0
    def Coulomb_integral_kss(self, kss_ij, kss_kq, phit, rhot):
        # smooth part
        I = self.gd.integrate(rhot * phit)
        
        wfs = self.paw.wfs
        Pij_ani = wfs.kpt_u[kss_ij.spin].P_ani
        Pkq_ani = wfs.kpt_u[kss_kq.spin].P_ani

        # Add atomic corrections
        Ia = 0.0
        for a, Pij_ni in Pij_ani.items():
            Pi_i = Pij_ni[kss_ij.i]
            Pj_i = Pij_ni[kss_ij.j]
            Dij_ii = np.outer(Pi_i, Pj_i)
            Dij_p = pack(Dij_ii)
            Pk_i = Pkq_ani[a][kss_kq.i]
            Pq_i = Pkq_ani[a][kss_kq.j]
            Dkq_ii = np.outer(Pk_i, Pq_i)
            Dkq_p = pack(Dkq_ii)
            C_pp = wfs.setups[a].M_pp
            #   ----
            # 2 >      P   P  C    P  P
            #   ----    ip  jr prst ks qt
            #   prst
            Ia += 2.0*np.dot(Dkq_p, np.dot(C_pp, Dij_p))
        I += self.gd.comm.sum(Ia)

        return I
Example #2
0
    def calculate_paw_fHXC_corrections(self, kss_ip, kss_jq, I_asp):
        i = kss_ip.occ_ind
        p = kss_ip.unocc_ind
        j = kss_jq.occ_ind
        q = kss_jq.unocc_ind

        Ia = 0.0
        for a, P_ni in self.calc.wfs.kpt_u[kss_jq.spin_ind].P_ani.items():
            Pip_ni = self.calc.wfs.kpt_u[kss_ip.spin_ind].P_ani[a]
            Dip_ii = np.outer(Pip_ni[i], Pip_ni[p])
            Dip_p = pack(Dip_ii)

            Pjq_ni = self.calc.wfs.kpt_u[kss_jq.spin_ind].P_ani[a]
            Djq_ii = np.outer(Pjq_ni[j], Pjq_ni[q])
            Djq_p = pack(Djq_ii)

            # Hartree part
            C_pp = self.calc.wfs.setups[a].M_pp
            # why factor of two here?
            # see appendix A of J. Chem. Phys. 128, 244101 (2008)
            #
            # 2 sum_prst      P   P   C     P   P
            #                  ip  jr  prst  ks  qt
            Ia += self.fH_pre * 2.0 * np.dot(Djq_p, np.dot(C_pp, Dip_p))

            # XC part, CHECK THIS JQ EVERWHERE!!!
            Ia += self.fxc_pre * np.dot(I_asp[a][kss_jq.spin_ind], Djq_p)

        return Ia
Example #3
0
    def symmetrize_atomic_density_matrices(self, D_asp):
        if len(self.kd.symmetry.op_scc) == 0:
            return

        if hasattr(D_asp, 'redistribute'):
            a_sa = self.kd.symmetry.a_sa
            D_asp.redistribute(self.atom_partition.as_serial())
            for s in range(self.nspins):
                D_aii = [unpack2(D_asp[a][s])
                         for a in range(len(D_asp))]
                for a, D_ii in enumerate(D_aii):
                    setup = self.setups[a]
                    D_asp[a][s] = pack(setup.symmetrize(a, D_aii, a_sa))
            D_asp.redistribute(self.atom_partition)
        else:
            all_D_asp = []
            for a, setup in enumerate(self.setups):
                D_sp = D_asp.get(a)
                if D_sp is None:
                    ni = setup.ni
                    D_sp = np.empty((self.nspins, ni * (ni + 1) // 2))
                self.gd.comm.broadcast(D_sp, self.atom_partition.rank_a[a])
                all_D_asp.append(D_sp)

            for s in range(self.nspins):
                D_aii = [unpack2(D_sp[s]) for D_sp in all_D_asp]
                for a, D_sp in D_asp.items():
                    setup = self.setups[a]
                    D_sp[s] = pack(setup.symmetrize(a, D_aii,
                                                    self.kd.symmetry.a_sa))
Example #4
0
    def write(self, writer):
        """Writes response specific data to disc.

        During the writing process, the DeltaXC is calculated
        (if not yet calculated).
        """

        if self.Dxc_vt_sG is None:
            self.calculate_delta_xc()

        wfs = self.wfs
        kpt_comm = wfs.kd.comm
        gd = wfs.gd

        nadm = 0
        for setup in wfs.setups:
            ni = setup.ni
            nadm += ni * (ni + 1) // 2

        # Not yet tested for parallerization
        # assert world.size == 1

        shape = (wfs.nspins,) + tuple(gd.get_size_of_global_array())

        # Write the pseudodensity on the coarse grid:
        writer.add_array('gllb_pseudo_response_potential', shape)
        if kpt_comm.rank == 0:
            for vt_G in self.vt_sG:
                writer.fill(gd.collect(vt_G) * Hartree)

        writer.add_array('gllb_dxc_pseudo_response_potential', shape)
        if kpt_comm.rank == 0:
            for Dxc_vt_G in self.Dxc_vt_sG:
                writer.fill(gd.collect(Dxc_vt_G) * (Hartree / Bohr))

        def pack(X0_asp):
            X_asp = self.wfs.setups.empty_atomic_matrix(
                self.wfs.nspins, self.wfs.atom_partition)
            # XXX some of the provided X0_asp contain strangely duplicated
            # elements.  Take only the minimal set:
            for a in X_asp:
                X_asp[a][:] = X0_asp[a]
            return pack_atomic_matrices(X_asp)

        writer.write(gllb_atomic_density_matrices=pack(self.D_asp))
        writer.write(gllb_atomic_response_matrices=pack(self.Dresp_asp))
        writer.write(gllb_dxc_atomic_density_matrices=pack(self.Dxc_D_asp))
        writer.write(
            gllb_dxc_atomic_response_matrices=pack(self.Dxc_Dresp_asp))
Example #5
0
    def add_compensation_charges(self, nt_G, rhot_g):
        """Add compensation charges to input pair density, which
        is interpolated to the fine grid if needed."""

        if self.finegrid:
            # interpolate the pair density to the fine grid
            self.density.interpolator.apply(nt_G, rhot_g)
        else:
            # copy values
            rhot_g[:] = nt_G
        
        # Determine the compensation charges for each nucleus
        Q_aL = {}
        for a, P_ni in self.P_ani.items():
            assert P_ni.dtype == float
            # Generate density matrix
            P1_i = P_ni[self.n1]
            P2_i = P_ni[self.n2]
            D_ii = np.outer(P1_i.conj(), P2_i)
            # allowed to pack as used in the scalar product with
            # the symmetric array Delta_pL
            D_p  = pack(D_ii, tolerance=1e30)
            
            # Determine compensation charge coefficients:
            Q_aL[a] = np.dot(D_p, self.density.setups[a].Delta_pL)

        # Add compensation charges
        if self.finegrid:
            self.density.ghat.add(rhot_g, Q_aL)
        else:
            self.density.Ghat.add(rhot_g, Q_aL)
Example #6
0
    def calculate_pair_density(self, n1, n2, kpt1, kpt2, ik1, ik2, bzq_index):
        psit1_G = self.kd.transform_wave_function(kpt1.psit_nG[n1], ik1)
        psit2_G = self.kd.transform_wave_function(kpt2.psit_nG[n2], ik2)
        nt_G = psit1_G.conj() * psit2_G

        s1 = self.kd.sym_k[ik1]
        s2 = self.kd.sym_k[ik2]
        t1 = self.kd.time_reversal_k[ik1]
        t2 = self.kd.time_reversal_k[ik2]
        k1_c = self.kd.ibzk_kc[kpt1.k]
        k2_c = self.kd.ibzk_kc[kpt2.k]

        Q_aL = {}
        for a in kpt1.P_ani.keys():
            b1 = self.kd.symmetry.a_sa[s1, a]
            b2 = self.kd.symmetry.a_sa[s2, a]
            S1_c = np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s1]) - self.spos_ac[b1]
            S2_c = np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s2]) - self.spos_ac[b2]
            assert abs(S1_c.round() - S1_c).max() < 1e-13
            assert abs(S2_c.round() - S2_c).max() < 1e-13
            x1 = np.exp(2j * pi * np.dot(k1_c, S1_c))
            x2 = np.exp(2j * pi * np.dot(k2_c, S2_c))
            P1_i = np.dot(self.setups[a].R_sii[s1], kpt1.P_ani[b1][n1]) * x1
            P2_i = np.dot(self.setups[a].R_sii[s2], kpt2.P_ani[b2][n2]) * x2
            if t1:
                P1_i = P1_i.conj()
            if t2:
                P2_i = P2_i.conj()

            D_ii = np.outer(P1_i.conj(), P2_i)
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        self.ghat.add(nt_G, Q_aL, bzq_index)
        return nt_G
Example #7
0
def raw_wignerseitz_LDOS(paw, a, spin):
    """Return a list of eigenvalues, and their weight on the specified atom"""
    wfs = paw.wfs
    assert wfs.dtype == float
    gd = wfs.gd
    atom_index = wignerseitz(gd, paw.atoms)

    w_k = wfs.weight_k
    nk = len(w_k)
    nb = wfs.bd.nbands

    energies = np.empty(nb * nk)
    weights = np.empty(nb * nk)
    x = 0
    for k, w in enumerate(w_k):
        u = spin * nk + k
        energies[x:x + nb] = wfs.collect_eigenvalues(k=k, s=spin)
        for n, psit_G in enumerate(wfs.kpt_u[u].psit_nG):
            P_i = wfs.kpt_u[u].P_ani[a][n]
            P_p = pack(np.outer(P_i, P_i))
            Delta_p = sqrt(4 * pi) * wfs.setups[a].Delta_pL[:, 0]
            weights[x + n] = w * (gd.integrate(abs(
                np.where(atom_index == a, psit_G, 0.0))**2)
                                  + np.dot(Delta_p, P_p))
        x += nb
    return energies, weights
Example #8
0
def raw_wignerseitz_LDOS(paw, a, spin):
    """Return a list of eigenvalues, and their weight on the specified atom"""
    wfs = paw.wfs
    assert wfs.dtype == float
    gd = wfs.gd
    atom_index = wignerseitz(gd, paw.atoms)

    w_k = wfs.kd.weight_k
    nk = len(w_k)
    nb = wfs.bd.nbands

    energies = np.empty(nb * nk)
    weights = np.empty(nb * nk)
    x = 0
    for k, w in enumerate(w_k):
        u = spin * nk + k
        energies[x:x + nb] = wfs.collect_eigenvalues(k=k, s=spin)
        for n, psit_G in enumerate(wfs.kpt_u[u].psit_nG):
            P_i = wfs.kpt_u[u].P_ani[a][n]
            P_p = pack(np.outer(P_i, P_i))
            Delta_p = sqrt(4 * pi) * wfs.setups[a].Delta_pL[:, 0]
            weights[x + n] = w * (
                gd.integrate(abs(np.where(atom_index == a, psit_G, 0.0))**2) +
                np.dot(Delta_p, P_p))
        x += nb
    return energies, weights
Example #9
0
    def with_compensation_charges(self, finegrid=False):
        """Get pair densisty including the compensation charges"""
        rhot = self.get(finegrid)

        # Determine the compensation charges for each nucleus
        Q_aL = {}
        for a, P_ni in self.P_ani.items():
            # Generate density matrix
            Pi_i = P_ni[self.i]
            Pj_i = P_ni[self.j]
            D_ii = np.outer(Pi_i, Pj_i)
            # allowed to pack as used in the scalar product with
            # the symmetric array Delta_pL
            D_p  = pack(D_ii)
            
            # Determine compensation charge coefficients:
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        # Add compensation charges
        if finegrid:
            self.density.ghat.add(rhot, Q_aL)
        else:
            if not hasattr(self.density, 'Ghat'):
                self.density.Ghat = LFC(self.density.gd,
                                        [setup.ghat_l
                                         for setup in self.setups],
                                        integral=sqrt(4 * pi))
                self.density.Ghat.set_positions(self.spos_ac)
            self.density.Ghat.add(rhot, Q_aL)
                
        return rhot
Example #10
0
    def add_compensation_charges(self, nt_G, rhot_g):
        """Add compensation charges to input pair density, which
        is interpolated to the fine grid if needed."""

        if self.finegrid:
            # interpolate the pair density to the fine grid
            self.density.interpolator.apply(nt_G, rhot_g)
        else:
            # copy values
            rhot_g[:] = nt_G

        # Determine the compensation charges for each nucleus
        Q_aL = {}
        for a, P_ni in self.P_ani.items():
            assert P_ni.dtype == float
            # Generate density matrix
            P1_i = P_ni[self.n1]
            P2_i = P_ni[self.n2]
            D_ii = np.outer(P1_i.conj(), P2_i)
            # allowed to pack as used in the scalar product with
            # the symmetric array Delta_pL
            D_p = pack(D_ii, tolerance=1e30)

            # Determine compensation charge coefficients:
            Q_aL[a] = np.dot(D_p, self.density.setups[a].Delta_pL)

        # Add compensation charges
        if self.finegrid:
            self.density.ghat.add(rhot_g, Q_aL)
        else:
            self.density.Ghat.add(rhot_g, Q_aL)
Example #11
0
    def with_compensation_charges(self, finegrid=False):
        """Get pair densisty including the compensation charges"""
        rhot = self.get(finegrid)

        # Determine the compensation charges for each nucleus
        Q_aL = {}
        for a, P_ni in self.P_ani.items():
            # Generate density matrix
            Pi_i = P_ni[self.i]
            Pj_i = P_ni[self.j]
            D_ii = np.outer(Pi_i, Pj_i)
            # allowed to pack as used in the scalar product with
            # the symmetric array Delta_pL
            D_p = pack(D_ii)

            # Determine compensation charge coefficients:
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        # Add compensation charges
        if finegrid:
            self.density.ghat.add(rhot, Q_aL)
        else:
            if not hasattr(self.density, 'Ghat'):
                self.density.Ghat = LFC(
                    self.density.gd, [setup.ghat_l for setup in self.setups],
                    integral=sqrt(4 * pi))
                self.density.Ghat.set_positions(self.spos_ac)
            self.density.Ghat.add(rhot, Q_aL)

        return rhot
Example #12
0
    def initialize_density_matrix(self, f_si):
        nspins, nao = f_si.shape
        ni = self.ni

        D_sii = np.zeros((nspins, ni, ni))
        D_sp = np.zeros((nspins, ni * (ni + 1) // 2))
        nj = len(self.n_j)
        j = 0
        i = 0
        ib = 0
        for phit in self.phit_j:
            l = phit.get_angular_momentum_number()
            # Skip projector functions not in basis set:
            while j < nj and self.l_j[j] != l:
                i += 2 * self.l_j[j] + 1
                j += 1
            if j == nj:
                break

            for m in range(2 * l + 1):
                D_sii[:, i + m, i + m] = f_si[:, ib + m]
            j += 1
            i += 2 * l + 1
            ib += 2 * l + 1
        for s in range(nspins):
            D_sp[s] = pack(D_sii[s])
        return D_sp
Example #13
0
    def initialize_density_matrix(self, f_si):
        nspins, nao = f_si.shape
        ni = self.ni

        D_sii = np.zeros((nspins, ni, ni))
        D_sp = np.zeros((nspins, ni * (ni + 1) // 2))
        nj = len(self.l_j)
        j = 0
        i = 0
        ib = 0
        for phit in self.phit_j:
            l = phit.get_angular_momentum_number()
            # Skip functions not in basis set:
            while j < nj and self.l_j[j] != l:
                i += 2 * self.l_j[j] + 1
                j += 1
            if j == nj:
                break

            for m in range(2 * l + 1):
                D_sii[:, i + m, i + m] = f_si[:, ib + m]
            j += 1
            i += 2 * l + 1
            ib += 2 * l + 1
        for s in range(nspins):
            D_sp[s] = pack(D_sii[s])
        return D_sp
Example #14
0
 def get_orbital_density_matrix(self, a, kpt, n):
     """Add the nth band density from kpt to density matrix D_sp"""
     ni = self.setups[a].ni
     D_sii = np.zeros((self.nspins, ni, ni))
     P_i = kpt.P_ani[a][n]
     D_sii[kpt.s] += np.outer(P_i.conj(), P_i).real
     D_sp = [pack(D_ii) for D_ii in D_sii]
     return D_sp
Example #15
0
 def get_orbital_density_matrix(self, a, kpt, n):
     """Add the nth band density from kpt to density matrix D_sp"""
     ni = self.setups[a].ni
     D_sii = np.zeros((self.nspins, ni, ni))
     P_i = kpt.P_ani[a][n]
     D_sii[kpt.s] += np.outer(P_i.conj(), P_i).real
     D_sp = [pack(D_ii) for D_ii in D_sii]
     return D_sp
Example #16
0
    def calculate_delta_xc_perturbation(self):
        h**o, lumo = self.occupations.get_homo_lumo(self.wfs)
        Ksgap = lumo - h**o

        # Calculate average of lumo reference response potential
        method1_dxc = np.average(self.Dxc_vt_sG[0])
        #print self.Dxc_vt_sG[0][0][0]

        nt_G = self.gd.empty()

        ne = self.nvalence  # Number of electrons
        assert self.nspins == 1
        lumo_n = ne // 2
        eps_u = []
        eps_un = np.zeros((len(self.kpt_u), len(self.kpt_u[0].psit_nG)))
        for u, kpt in enumerate(self.kpt_u):
            #print "K-Point index: ",u
            for n in range(len(kpt.psit_nG)):
                nt_G[:] = 0.0
                self.wfs.add_orbital_density(nt_G, kpt, n)
                E = 0.0
                for a in self.density.D_asp:
                    D_sp = self.Dxc_D_asp[a]
                    Dresp_sp = self.Dxc_Dresp_asp[a]
                    P_ni = kpt.P_ani[a]
                    Dwf_p = pack(np.outer(P_ni[n].T.conj(), P_ni[n]).real)
                    E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p)
                #print "Atom corrections", E*27.21
                E = self.grid_comm.sum(E)
                E += self.gd.integrate(nt_G * self.Dxc_vt_sG[0])
                E += kpt.eps_n[lumo_n]
                #print "Old eigenvalue",  kpt.eps_n[lumo_n]*27.21, " New eigenvalue ", E*27.21, " DXC", E*27.21-kpt.eps_n[lumo_n]*27.21
                eps_un[u][n] = E

        method2_lumo = min([eps_n[lumo_n] for eps_n in eps_un])
        method2_lumo = -self.kpt_comm.max(-method2_lumo)
        method2_dxc = method2_lumo - lumo
        Ha = 27.2116
        Ksgap *= Ha
        method1_dxc *= Ha
        method2_dxc *= Ha
        if world.rank is not 0:
            return (Ksgap, method2_dxc)

        print
        print "\Delta XC calulation"
        print "-----------------------------------------------"
        print "| Method      |  KS-Gap | \Delta XC |  QP-Gap |"
        print "-----------------------------------------------"
        print "| Averaging   | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc,
                                                           Ksgap + method1_dxc)
        print "| Lumo pert.  | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc,
                                                           Ksgap + method2_dxc)
        print "-----------------------------------------------"
        print
        return (Ksgap, method2_dxc)
Example #17
0
    def calculate_delta_xc_perturbation_spin(self, s=0):
        h**o, lumo = self.occupations.get_homo_lumo_by_spin(self.wfs, s)
        Ksgap = lumo - h**o

        # Calculate average of lumo reference response potential
        method1_dxc = np.average(self.Dxc_vt_sG[s])
        nt_G = self.gd.empty()

        # Find the lumo-orbital of this spin
        sign = 1 - s * 2
        lumo_n = (self.occupations.nvalence +
                  sign * self.occupations.magmom) // 2
        gaps = [1000.0]
        for u, kpt in enumerate(self.kpt_u):
            if kpt.s == s:
                nt_G[:] = 0.0
                self.wfs.add_orbital_density(nt_G, kpt, lumo_n)
                E = 0.0
                for a in self.density.D_asp:
                    D_sp = self.Dxc_D_asp[a]
                    Dresp_sp = self.Dxc_Dresp_asp[a]
                    P_ni = kpt.P_ani[a]
                    Dwf_p = pack(
                        np.outer(P_ni[lumo_n].T.conj(), P_ni[lumo_n]).real)
                    print(
                        "self.integrate_sphere DOES NOT SUPPORT SPIN POLARIZED? atc_response.py"
                    )
                    E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p)
                E = self.grid_comm.sum(E)
                E += self.gd.integrate(nt_G * self.Dxc_vt_sG[s])
                E += kpt.eps_n[lumo_n]
                gaps.append(E - lumo)
                #print "Old eigenvalue",  kpt.eps_n[lumo_n]*27.21, " New eigenvalue ", E*27.21, " DXC", E*27.21-kpt.eps_n[lumo_n]*27.21
                #eps_un[u][n] = E

        method2_dxc = -self.kpt_comm.max(-min(gaps))
        Ha = 27.2116
        Ksgap *= Ha
        method1_dxc *= Ha
        method2_dxc *= Ha
        if world.rank is not 0:
            return (Ksgap, method2_dxc)

        print()
        print("\Delta XC calulation")
        print("-----------------------------------------------")
        print("| Method      |  KS-Gap | \Delta XC |  QP-Gap |")
        print("-----------------------------------------------")
        print("| Averaging   | %7.2f | %9.2f | %7.2f |" %
              (Ksgap, method1_dxc, Ksgap + method1_dxc))
        print("| Lumo pert.  | %7.2f | %9.2f | %7.2f |" %
              (Ksgap, method2_dxc, Ksgap + method2_dxc))
        print("-----------------------------------------------")
        print()
        return (Ksgap, method2_dxc)
Example #18
0
    def calculate_delta_xc_perturbation(self):
        h**o, lumo = self.occupations.get_homo_lumo(self.wfs)
        Ksgap = lumo - h**o
        
        # Calculate average of lumo reference response potential
        method1_dxc = np.average(self.Dxc_vt_sG[0])
        #print self.Dxc_vt_sG[0][0][0]

        nt_G = self.gd.empty()

        ne = self.nvalence # Number of electrons
        assert self.nspins == 1
        lumo_n = ne // 2
        eps_u =[]
        eps_un = np.zeros((len(self.kpt_u),len(self.kpt_u[0].psit_nG)))
        for u, kpt in enumerate(self.kpt_u):
            #print "K-Point index: ",u
            for n in range(len(kpt.psit_nG)):
                nt_G[:] = 0.0
                self.wfs.add_orbital_density(nt_G, kpt, n)
                E = 0.0
                for a in self.density.D_asp:
                    D_sp = self.Dxc_D_asp[a]
                    Dresp_sp = self.Dxc_Dresp_asp[a]
                    P_ni = kpt.P_ani[a]
                    Dwf_p = pack(np.outer(P_ni[n].T.conj(), P_ni[n]).real)
                    E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p)
                #print "Atom corrections", E*27.21
                E = self.grid_comm.sum(E)
                E += self.gd.integrate(nt_G*self.Dxc_vt_sG[0])
                E += kpt.eps_n[lumo_n]
                #print "Old eigenvalue",  kpt.eps_n[lumo_n]*27.21, " New eigenvalue ", E*27.21, " DXC", E*27.21-kpt.eps_n[lumo_n]*27.21
                eps_un[u][n] = E

        method2_lumo = min([ eps_n[lumo_n] for eps_n in eps_un])
        method2_lumo = -self.kpt_comm.max(-method2_lumo)
        method2_dxc = method2_lumo-lumo
        Ha = 27.2116 
        Ksgap *= Ha
        method1_dxc *= Ha
        method2_dxc *= Ha
        if world.rank is not 0:
            return (Ksgap, method2_dxc)
        
        print
        print "\Delta XC calulation"
        print "-----------------------------------------------"
        print "| Method      |  KS-Gap | \Delta XC |  QP-Gap |"
        print "-----------------------------------------------"
        print "| Averaging   | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc, Ksgap+method1_dxc)
        print "| Lumo pert.  | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc, Ksgap+method2_dxc)
        print "-----------------------------------------------"
        print
        return (Ksgap, method2_dxc)
Example #19
0
    def calculate_delta_xc_perturbation_spin(self, s=0):
        h**o, lumo = self.wfs.get_homo_lumo(s)
        Ksgap = lumo - h**o

        # Calculate average of lumo reference response potential
        method1_dxc = np.average(self.Dxc_vt_sG[s])
        nt_G = self.gd.empty()

        # Find the lumo-orbital of this spin
        sign = 1 - s * 2
        lumo_n = int((self.wfs.nvalence + sign * self.occupations.magmom) // 2)
        gaps = [1000.0]
        for u, kpt in enumerate(self.kpt_u):
            if kpt.s == s:
                nt_G[:] = 0.0
                self.wfs.add_orbital_density(nt_G, kpt, lumo_n)
                E = 0.0
                for a in self.density.D_asp:
                    D_sp = self.Dxc_D_asp[a]
                    Dresp_sp = self.Dxc_Dresp_asp[a]
                    P_ni = kpt.P_ani[a]
                    Dwf_p = pack(
                        np.outer(P_ni[lumo_n].T.conj(), P_ni[lumo_n]).real)
                    E += self.integrate_sphere(a,
                                               Dresp_sp,
                                               D_sp,
                                               Dwf_p,
                                               spin=s)
                E = self.grid_comm.sum(E)
                E += self.gd.integrate(nt_G * self.Dxc_vt_sG[s])
                E += kpt.eps_n[lumo_n]
                gaps.append(E - lumo)

        method2_dxc = -self.kpt_comm.max(-min(gaps))
        Ha = 27.2116
        Ksgap *= Ha
        method1_dxc *= Ha
        method2_dxc *= Ha
        if world.rank is not 0:
            return (Ksgap, method2_dxc)

        if 0:  # TODO print properly, not to stdout!
            print()
            print('\Delta XC calulation')
            print('-----------------------------------------------')
            print('| Method      |  KS-Gap | \Delta XC |  QP-Gap |')
            print('-----------------------------------------------')
            print('| Averaging   | %7.2f | %9.2f | %7.2f |' %
                  (Ksgap, method1_dxc, Ksgap + method1_dxc))
            print('| Lumo pert.  | %7.2f | %9.2f | %7.2f |' %
                  (Ksgap, method2_dxc, Ksgap + method2_dxc))
            print('-----------------------------------------------')
            print()
        return (Ksgap, method2_dxc)
Example #20
0
    def symmetrize_atomic_density_matrices(self, D_asp):
        if len(self.kd.symmetry.op_scc) == 0:
            return

        a_sa = self.kd.symmetry.a_sa
        D_asp.redistribute(self.atom_partition.as_serial())
        for s in range(self.nspins):
            D_aii = [unpack2(D_asp[a][s]) for a in range(len(D_asp))]
            for a, D_ii in enumerate(D_aii):
                setup = self.setups[a]
                D_asp[a][s] = pack(setup.symmetrize(a, D_aii, a_sa))
        D_asp.redistribute(self.atom_partition)
    def calculate_delta_xc_perturbation_spin(self, s=0):
        h**o, lumo = self.occupations.get_homo_lumo_by_spin(self.wfs, s)
        Ksgap = lumo - h**o
        
        # Calculate average of lumo reference response potential
        method1_dxc = np.average(self.Dxc_vt_sG[s])
        nt_G = self.gd.empty()

        # Find the lumo-orbital of this spin
        sign = 1 - s * 2
        lumo_n = (self.occupations.nvalence + sign * self.occupations.magmom) // 2
        gaps = [ 1000.0 ]
        for u, kpt in enumerate(self.kpt_u):
            if kpt.s == s:
                nt_G[:] = 0.0
                self.wfs.add_orbital_density(nt_G, kpt, lumo_n)
                E = 0.0
                for a in self.density.D_asp:
                    D_sp = self.Dxc_D_asp[a]
                    Dresp_sp = self.Dxc_Dresp_asp[a]
                    P_ni = kpt.P_ani[a]
                    Dwf_p = pack(np.outer(P_ni[lumo_n].T.conj(), P_ni[lumo_n]).real)
                    print("self.integrate_sphere DOES NOT SUPPORT SPIN POLARIZED? atc_response.py")
                    E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p)
                E = self.grid_comm.sum(E)
                E += self.gd.integrate(nt_G*self.Dxc_vt_sG[s])
                E += kpt.eps_n[lumo_n]
                gaps.append(E-lumo)
                #print "Old eigenvalue",  kpt.eps_n[lumo_n]*27.21, " New eigenvalue ", E*27.21, " DXC", E*27.21-kpt.eps_n[lumo_n]*27.21
                #eps_un[u][n] = E

        method2_dxc = -self.kpt_comm.max(-min(gaps))
        Ha = 27.2116 
        Ksgap *= Ha
        method1_dxc *= Ha
        method2_dxc *= Ha
        if world.rank is not 0:
            return (Ksgap, method2_dxc)
        
        print()
        print("\Delta XC calulation")
        print("-----------------------------------------------")
        print("| Method      |  KS-Gap | \Delta XC |  QP-Gap |")
        print("-----------------------------------------------")
        print("| Averaging   | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc, Ksgap+method1_dxc))
        print("| Lumo pert.  | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc, Ksgap+method2_dxc))
        print("-----------------------------------------------")
        print()
        return (Ksgap, method2_dxc)
Example #22
0
    def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un):
        """Calculate atomic density matrices from projections with
        custom occupation f_un."""
        # Varying f_n used in calculation of response part of GLLB-potential
        for a, D_sp in D_asp.items():
            ni = self.setups[a].ni
            D_sii = np.zeros((self.nspins, ni, ni))
            for f_n, kpt in zip(f_un, self.kpt_u):
                self.calculate_atomic_density_matrices_k_point(D_sii, kpt, a,
                                                               f_n)
            D_sp[:] = [pack(D_ii) for D_ii in D_sii]
            self.band_comm.sum(D_sp)
            self.kpt_comm.sum(D_sp)

        self.symmetrize_atomic_density_matrices(D_asp)
Example #23
0
    def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un):
        """Calculate atomic density matrices from projections with
        custom occupation f_un."""
        # Varying f_n used in calculation of response part of GLLB-potential
        for a, D_sp in D_asp.items():
            ni = self.setups[a].ni
            D_sii = np.zeros((len(D_sp), ni, ni))
            for f_n, kpt in zip(f_un, self.kpt_u):
                self.calculate_atomic_density_matrices_k_point(D_sii, kpt, a,
                                                               f_n)
            D_sp[:] = [pack(D_ii) for D_ii in D_sii]
            self.band_comm.sum(D_sp)
            self.kpt_comm.sum(D_sp)

        self.symmetrize_atomic_density_matrices(D_asp)
Example #24
0
 def make_optimized(qstart, qend):
     g_qG = np.zeros((qend - qstart,) + w_wG.shape[1:], float)
     P_aqp = {}
     for a, P_wi in P_awi.items():
         ni = P_wi.shape[1]
         nii = ni * (ni + 1) // 2
         P_aqp[a] = np.zeros((qend - qstart, nii), float)
     for w1, w1_G in enumerate(w_wG):
         U = Uisq_iqj[w1, qstart: qend].copy()
         gemm(1., w1_G * w_wG, U, 1.0, g_qG)
         for a, P_wi in P_awi.items():
             P_wp = np.array([pack(np.outer(P_wi[w1], P_wi[w2])) 
                             for w2 in range(Ni)])
             gemm(1., P_wp, U, 1.0, P_aqp[a])
     return g_qG, P_aqp
Example #25
0
 def make_optimized(qstart, qend):
     g_qG = np.zeros((qend - qstart,) + w_wG.shape[1:], float)
     P_aqp = {}
     for a, P_wi in P_awi.items():
         ni = P_wi.shape[1]
         nii = ni * (ni + 1) // 2
         P_aqp[a] = np.zeros((qend - qstart, nii), float)
     for w1, w1_G in enumerate(w_wG):
         U = Uisq_iqj[w1, qstart: qend].copy()
         gemm(1., w1_G * w_wG, U, 1.0, g_qG)
         for a, P_wi in P_awi.items():
             P_wp = np.array([pack(np.outer(P_wi[w1], P_wi[w2])) 
                             for w2 in range(Ni)])
             gemm(1., P_wp, U, 1.0, P_aqp[a])
     return g_qG, P_aqp
Example #26
0
    def symmetrize_atomic_density_matrices(self, D_asp):
        if len(self.kd.symmetry.op_scc) > 1:
            all_D_asp = []
            for a, setup in enumerate(self.setups):
                D_sp = D_asp.get(a)
                if D_sp is None:
                    ni = setup.ni
                    D_sp = np.empty((self.ns, ni * (ni + 1) // 2))
                self.gd.comm.broadcast(D_sp, self.rank_a[a])
                all_D_asp.append(D_sp)

            for s in range(self.nspins):
                D_aii = [unpack2(D_sp[s]) for D_sp in all_D_asp]
                for a, D_sp in D_asp.items():
                    setup = self.setups[a]
                    D_sp[s] = pack(setup.symmetrize(a, D_aii, self.kd.symmetry.a_sa))
Example #27
0
    def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un):
        """Calculate atomic density matrices from projections with
        custom occupation f_un."""

        # Parameter check (if user accidentally passes f_n instead of f_un)
        if f_un[0] is not None:  # special case for transport calculations...
            assert isinstance(f_un[0], np.ndarray)
        # Varying f_n used in calculation of response part of GLLB-potential
        for a, D_sp in D_asp.items():
            ni = self.setups[a].ni
            D_sii = np.zeros((len(D_sp), ni, ni))
            for f_n, kpt in zip(f_un, self.kpt_u):
                self.calculate_atomic_density_matrices_k_point(D_sii, kpt, a, f_n)
            D_sp[:] = [pack(D_ii) for D_ii in D_sii]
            self.kptband_comm.sum(D_sp)

        self.symmetrize_atomic_density_matrices(D_asp)
Example #28
0
    def expand_wave_function(self, psit_G, u, n):
        """Get the weights of wave function in Wigner-Seitz cells
        around the atoms. The spin-k-point index u and band number n
        are needed for the augmentation sphere corrections."""

        assert psit_G.dtype == float
        # smooth part
        weigths = self.expand(psit_G**2)

        # add augmentation sphere corrections
        for a, nucleus in enumerate(self.atoms):
            P_i = nucleus.P_uni[u, n]
            P_p = pack(np.outer(P_i, P_i))
            Delta_p = sqrt(4 * pi) * nucleus.setup.Delta_pL[:, 0]
            weigths[a] += np.dot(Delta_p, P_p) 

        return weigths
Example #29
0
    def symmetrize_atomic_density_matrices(self, D_asp):
        if len(self.kd.symmetry.op_scc) > 1:
            all_D_asp = []
            for a, setup in enumerate(self.setups):
                D_sp = D_asp.get(a)
                if D_sp is None:
                    ni = setup.ni
                    D_sp = np.empty((self.ns, ni * (ni + 1) // 2))
                self.gd.comm.broadcast(D_sp, self.rank_a[a])
                all_D_asp.append(D_sp)

            for s in range(self.nspins):
                D_aii = [unpack2(D_sp[s]) for D_sp in all_D_asp]
                for a, D_sp in D_asp.items():
                    setup = self.setups[a]
                    D_sp[s] = pack(
                        setup.symmetrize(a, D_aii, self.kd.symmetry.a_sa))
Example #30
0
    def expand_wave_function(self, psit_G, u, n):
        """Get the weights of wave function in Wigner-Seitz cells
        around the atoms. The spin-k-point index u and band number n
        are needed for the augmentation sphere corrections."""

        assert psit_G.dtype == float
        # smooth part
        weigths = self.expand(psit_G**2)

        # add augmentation sphere corrections
        for a, nucleus in enumerate(self.atoms):
            P_i = nucleus.P_uni[u, n]
            P_p = pack(np.outer(P_i, P_i))
            Delta_p = sqrt(4 * pi) * nucleus.setup.Delta_pL[:, 0]
            weigths[a] += np.dot(Delta_p, P_p) 

        return weigths
Example #31
0
    def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un):
        """Calculate atomic density matrices from projections with
        custom occupation f_un."""

        # Parameter check (if user accidentally passes f_n instead of f_un)
        if f_un[0] is not None:  # special case for transport calculations...
            assert isinstance(f_un[0], np.ndarray)
        # Varying f_n used in calculation of response part of GLLB-potential
        for a, D_sp in D_asp.items():
            ni = self.setups[a].ni
            D_sii = np.zeros((len(D_sp), ni, ni))
            for f_n, kpt in zip(f_un, self.kpt_u):
                self.calculate_atomic_density_matrices_k_point(
                    D_sii, kpt, a, f_n)
            D_sp[:] = [pack(D_ii) for D_ii in D_sii]
            self.kptband_comm.sum(D_sp)

        self.symmetrize_atomic_density_matrices(D_asp)
Example #32
0
    def calculate_delta_xc_perturbation_spin(self, s=0):
        h**o, lumo = self.occupations.get_homo_lumo_by_spin(self.wfs, s)
        Ksgap = lumo - h**o
        
        # Calculate average of lumo reference response potential
        method1_dxc = np.average(self.Dxc_vt_sG[s])
        nt_G = self.gd.empty()

        epsilon = 1e-2
        gaps = [ 1000.0 ]
        for u, kpt in enumerate(self.kpt_u):
            if kpt.s == s:
                lumo_n = np.flatnonzero(kpt.f_n/kpt.weight <= epsilon)[0]
                nt_G[:] = 0.0
                self.wfs.add_orbital_density(nt_G, kpt, lumo_n)
                E = 0.0
                for a in self.density.D_asp:
                    D_sp = self.Dxc_D_asp[a]
                    Dresp_sp = self.Dxc_Dresp_asp[a]
                    P_ni = kpt.P_ani[a]
                    Dwf_p = pack(np.outer(P_ni[lumo_n].T.conj(), P_ni[lumo_n]).real)
                    E += self.integrate_sphere(a, Dresp_sp, D_sp, Dwf_p)
                E = self.grid_comm.sum(E)
                E += self.gd.integrate(nt_G*self.Dxc_vt_sG[s])
                E += kpt.eps_n[lumo_n]
                gaps.append(E-lumo)

        method2_dxc = self.kpt_comm.min(min(gaps))
        Ksgap *= Hartree
        method1_dxc *= Hartree
        method2_dxc *= Hartree
        if world.rank is not 0:
            return (Ksgap, method2_dxc)
        
        print
        print "\Delta XC calulation"
        print "-----------------------------------------------"
        print "| Method      |  KS-Gap | \Delta XC |  QP-Gap |"
        print "-----------------------------------------------"
        print "| Averaging   | %7.2f | %9.2f | %7.2f |" % (Ksgap, method1_dxc, Ksgap+method1_dxc)
        print "| Lumo pert.  | %7.2f | %9.2f | %7.2f |" % (Ksgap, method2_dxc, Ksgap+method2_dxc)
        print "-----------------------------------------------"
        print
        return (Ksgap, method2_dxc)
Example #33
0
    def calculate_pair_density(self, n1, n2, kpt1, kpt2, q, invert):
        if invert:
            nt_G = kpt1.psit_nG[n1].conj() * kpt2.psit_nG[n2].conj()
        else:
            nt_G = kpt1.psit_nG[n1].conj() * kpt2.psit_nG[n2]

        Q_aL = {}
        for a, P1_ni in kpt1.P_ani.items():
            P1_i = P1_ni[n1]
            P2_i = kpt2.P_ani[a][n2]
            if invert:
                D_ii = np.outer(P1_i.conj(), P2_i.conj())
            else:
                D_ii = np.outer(P1_i.conj(), P2_i)
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        self.ghat.add(nt_G, Q_aL, q)
        return nt_G
Example #34
0
    def calculate_pair_density(self, n1, n2, kpt1, kpt2, q, invert):
        if invert:
            nt_G = kpt1.psit_nG[n1].conj() * kpt2.psit_nG[n2].conj()
        else:
            nt_G = kpt1.psit_nG[n1].conj() * kpt2.psit_nG[n2]

        Q_aL = {}
        for a, P1_ni in kpt1.P_ani.items():
            P1_i = P1_ni[n1]
            P2_i = kpt2.P_ani[a][n2]
            if invert:
                D_ii = np.outer(P1_i.conj(), P2_i.conj())
            else:
                D_ii = np.outer(P1_i.conj(), P2_i)
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        self.ghat.add(nt_G, Q_aL, q)
        return nt_G
Example #35
0
    def calculate_pair_density(self, n1, n2, kpt1, kpt2, q, k, eik1r_R,
                               eik2r_R, eiqr_R, ibz2):
        if isinstance(self.wfs, PWWaveFunctions):
            psit1_R = self.wfs.pd.ifft(kpt1.psit_nG[n1]) * eik1r_R
            psit2_R = self.wfs.pd.ifft(kpt2.psit_nG[n2]) * eik2r_R
        else:
            psit1_R = kpt1.psit_nG[n1]
            psit2_R = kpt2.psit_nG[n2]

        if ibz2:
            psit2_R = psit2_R
        else:
            psit2_R = np.asarray(self.kd.transform_wave_function(psit2_R, k),
                                 complex)
        nt_R = psit1_R.conj() * psit2_R

        s = self.kd.sym_k[k]
        time_reversal = self.kd.time_reversal_k[k]
        k2_c = self.kd.ibzk_kc[kpt2.k]

        Q_aL = {}
        for a, P1_ni in kpt1.P_ani.items():
            P1_i = P1_ni[n1]

            b = self.kd.symmetry.a_sa[s, a]
            S_c = (np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s]) -
                   self.spos_ac[b])
            assert abs(S_c.round() - S_c).max() < 1e-13
            x = np.exp(2j * pi * np.dot(k2_c, S_c))
            P2_i = np.dot(self.setups[a].R_sii[s], kpt2.P_ani[b][n2]) * x
            if time_reversal:
                P2_i = P2_i.conj()

            if ibz2:
                P2_i = kpt2.P_ani[a][n2]

            D_ii = np.outer(P1_i.conj(), P2_i)
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        self.ghat.add(nt_R, Q_aL, q)
        return nt_R / eiqr_R
Example #36
0
    def calculate_pair_density(self, n1, n2, psit_nG, P_ani):
        Q_aL = {}
        for a, P_ni in P_ani.items():
            P1_i = P_ni[n1]
            P2_i = P_ni[n2]
            D_ii = np.outer(P1_i, P2_i.conj()).real
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)
            
        nt_G = psit_nG[n1] * psit_nG[n2]

        if self.finegd is self.gd:
            nt_g = nt_G
        else:
            nt_g = self.finegd.empty()
            self.interpolator.apply(nt_G, nt_g)

        rhot_g = nt_g.copy()
        self.ghat.add(rhot_g, Q_aL)

        return nt_G, rhot_g
Example #37
0
    def calculate_pair_density(self, n1, n2, psit_nG, P_ani):
        Q_aL = {}
        for a, P_ni in P_ani.items():
            P1_i = P_ni[n1]
            P2_i = P_ni[n2]
            D_ii = np.outer(P1_i, P2_i.conj()).real
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        nt_G = psit_nG[n1] * psit_nG[n2]

        if self.finegd is self.gd:
            nt_g = nt_G
        else:
            nt_g = self.finegd.empty()
            self.interpolator.apply(nt_G, nt_g)

        rhot_g = nt_g.copy()
        self.ghat.add(rhot_g, Q_aL)

        return nt_G, rhot_g
Example #38
0
    def apply_oper(self, obj, sym, cart_rot, atom_deperm):
        from gpaw.utilities import pack, unpack2

        a_a = self.symmetry.a_sa[sym]
        assert (
            a_a == atom_deperm).all(), "mismatched oper order or something?"

        # permute the 'a' axis (atoms in the dict)
        obj = super().apply_oper(obj, sym, cart_rot, atom_deperm)

        # and now the 'p' axis
        dH_asp = obj
        for a in range(len(dH_asp)):
            R_ii = self.symmetry.R_asii[a][sym]
            for s in range(self.nspins):
                dH_p = dH_asp[a][s]
                dH_ii = unpack2(dH_p)
                tmp_ii = R_ii @ dH_ii @ R_ii.T
                tmp_p = pack(tmp_ii)
                dH_asp[a][s][...] = tmp_p

        return dH_asp
Example #39
0
    def calculate_density(self, m):
        # pseudo density
        nt_G = self.phit_mG[m]**2

        if self.finegd is self.gd:
            nt_g = nt_G
        else:
            nt_g = self.finegd.empty()
            self.interpolator.apply(nt_G, nt_g)
            # normalize single-particle density
            nt_g *= self.gd.integrate(nt_G) / self.finegd.integrate(nt_g)

        # PAW corrections
        Q_aL = {}
        D_ap = {}
        for a, P_mi in self.P_ami.items():
            P_i = P_mi[m]
            D_ii = np.outer(P_i, P_i.conj()).real
            D_ap[a] = D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        return nt_g, Q_aL, D_ap
Example #40
0
    def calculate_density(self, m):
        #
        # pseudo density
        nt_G = self.phit_mG[m]**2

        if self.finegd is self.gd:
            nt_g = nt_G
        else:
            nt_g = self.finegd.empty()
            self.interpolator.apply(nt_G, nt_g)
            # normalize single-particle density
            nt_g *= self.gd.integrate(nt_G) / self.finegd.integrate(nt_g)

        # PAW corrections
        Q_aL = {}
        D_ap = {}
        for a, P_mi in self.P_ami.items():
            P_i = P_mi[m]
            D_ii = np.outer(P_i, P_i.conj()).real
            D_ap[a] = D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        return nt_g, Q_aL, D_ap
Example #41
0
def get_density(rho_MM, wfs, density, density_type='comp', u=0):
    rho_G = density.gd.zeros()
    kpt = wfs.kpt_u[u]
    assert kpt.q == 0
    rho_MM = rho_MM.astype(wfs.dtype)
    wfs.basis_functions.construct_density(rho_MM, rho_G, kpt.q)

    # Uncomment this if you want to add the static part
    # rho_G += density.nct_G

    if density_type == 'pseudocoarse':
        return rho_G

    rho_g = density.finegd.zeros()
    density.distribute_and_interpolate(rho_G, rho_g)
    rho_G = None

    if density_type == 'pseudo':
        return rho_g

    if density_type == 'comp':
        D_asp = density.atom_partition.arraydict(density.D_asp.shapes_a)
        Q_aL = {}
        for a, D_sp in D_asp.items():
            P_Mi = wfs.P_aqMi[a][kpt.q]
            assert np.max(np.absolute(P_Mi.imag)) == 0
            P_Mi = P_Mi.real
            assert P_Mi.dtype == float
            D_ii = np.dot(np.dot(P_Mi.T.conj(), rho_MM), P_Mi)
            D_sp[:] = pack(D_ii)[np.newaxis, :]
            Q_aL[a] = np.dot(D_sp.sum(axis=0), wfs.setups[a].Delta_pL)
        tmp_g = density.finegd.zeros()
        density.ghat.add(tmp_g, Q_aL)
        rho_g += tmp_g
        return rho_g

    raise RuntimeError('Unknown density type: %s' % density_type)
Example #42
0
    def calculate_pair_density(self, n1, n2, kpt1, kpt2, ik1, ik2, bzq_index):
        psit1_G = self.kd.transform_wave_function(kpt1.psit_nG[n1], ik1)
        psit2_G = self.kd.transform_wave_function(kpt2.psit_nG[n2], ik2)
        nt_G = psit1_G.conj() * psit2_G

        s1 = self.kd.sym_k[ik1]
        s2 = self.kd.sym_k[ik2]
        t1 = self.kd.time_reversal_k[ik1]
        t2 = self.kd.time_reversal_k[ik2]
        k1_c = self.kd.ibzk_kc[kpt1.k]
        k2_c = self.kd.ibzk_kc[kpt2.k]

        Q_aL = {}
        for a in kpt1.P_ani.keys():
            b1 = self.kd.symmetry.a_sa[s1, a]
            b2 = self.kd.symmetry.a_sa[s2, a]
            S1_c = (np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s1]) -
                    self.spos_ac[b1])
            S2_c = (np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s2]) -
                    self.spos_ac[b2])
            assert abs(S1_c.round() - S1_c).max() < 1e-13
            assert abs(S2_c.round() - S2_c).max() < 1e-13
            x1 = np.exp(2j * pi * np.dot(k1_c, S1_c))
            x2 = np.exp(2j * pi * np.dot(k2_c, S2_c))
            P1_i = np.dot(self.setups[a].R_sii[s1], kpt1.P_ani[b1][n1]) * x1
            P2_i = np.dot(self.setups[a].R_sii[s2], kpt2.P_ani[b2][n2]) * x2
            if t1:
                P1_i = P1_i.conj()
            if t2:
                P2_i = P2_i.conj()

            D_ii = np.outer(P1_i.conj(), P2_i)
            D_p = pack(D_ii)
            Q_aL[a] = np.dot(D_p, self.setups[a].Delta_pL)

        self.ghat.add(nt_G, Q_aL, bzq_index)
        return nt_G
Example #43
0
    def get(self, nt_G, nt_g, rhot_g):
        """Get pair densities.

        nt_G
          Pair density without compensation charges on the coarse grid

        nt_g
          Pair density without compensation charges on the fine grid

        rhot_g
          Pair density with compensation charges on the fine grid
        """
        # Coarse grid product
        np.multiply(self.psit1_G.conj(), self.psit2_G, nt_G)
        # Interpolate to fine grid
        self.density.interpolator.apply(nt_G, nt_g)

        # Determine the compensation charges for each nucleus
        Q_aL = {}
        for a, P_ni in self.P_ani.items():
            assert P_ni.dtype == float
            # Generate density matrix
            P1_i = P_ni[self.n1]
            P2_i = P_ni[self.n2]
            D_ii = np.outer(P1_i.conj(), P2_i)
            # allowed to pack as used in the scalar product with
            # the symmetric array Delta_pL
            D_p = pack(D_ii)
            #FIXME: CHECK THIS D_p  = pack(D_ii, tolerance=1e30)

            # Determine compensation charge coefficients:
            Q_aL[a] = np.dot(D_p, self.density.setups[a].Delta_pL)

        # Add compensation charges
        rhot_g[:] = nt_g[:]
        self.density.ghat.add(rhot_g, Q_aL)
Example #44
0
    def calculate_paw_xc_pair_potentials(self, kss_ip):
        # XC corrections
        I_asp = {}
        i = kss_ip.occ_ind
        p = kss_ip.unocc_ind

        # s = kss_ip.spin_ind

        # FIXME, only spin unpolarized works
        #self.timer.start('Atomic XC')
        for a, P_ni in self.calc.wfs.kpt_u[kss_ip.kpt_ind].P_ani.items():
            I_sp = np.zeros_like(self.calc.density.D_asp[a])
            I_sp_2 = np.zeros_like(self.calc.density.D_asp[a])

            Pip_ni = self.calc.wfs.kpt_u[kss_ip.spin_ind].P_ani[a]
            Dip_ii = np.outer(Pip_ni[i], Pip_ni[p])
            Dip_p = pack(Dip_ii)

            # finite difference plus
            D_sp = self.calc.density.D_asp[a].copy()
            D_sp[kss_ip.spin_ind] += self.deriv_scale * Dip_p
            self.xc.calculate_paw_correction(self.calc.wfs.setups[a], D_sp,
                                             I_sp)

            # finite difference minus
            D_sp_2 = self.calc.density.D_asp[a].copy()
            D_sp_2[kss_ip.spin_ind] -= self.deriv_scale * Dip_p
            self.xc.calculate_paw_correction(self.calc.wfs.setups[a], D_sp_2,
                                             I_sp_2)

            # finite difference
            I_asp[a] = (I_sp - I_sp_2) / (2. * self.deriv_scale)

        #self.timer.stop('Atomic XC')

        return I_asp
    def calculate_interaction(self, n1_n, n2, kpt1, kpt2, q, k,
                              eik20r_R, eik2r_R, is_ibz2):
        """Calculate Coulomb interactions.

        For all n1 in the n1_n list, calculate interaction with n2."""

        # number of plane waves:
        ng1 = self.wfs.ng_k[kpt1.k]
        ng2 = self.wfs.ng_k[kpt2.k]

        # Transform to real space and apply symmetry operation:
        self.timer.start('IFFT1')
        if is_ibz2:
            u2_R = self.pd.ifft(kpt2.psit_nG[n2, :ng2], kpt2.k)
        else:
            psit2_R = self.pd.ifft(kpt2.psit_nG[n2, :ng2], kpt2.k) * eik20r_R
            self.timer.start('Symmetry transform')
            u2_R = self.kd.transform_wave_function(psit2_R, k) / eik2r_R
            self.timer.stop()
        self.timer.stop()

        # Calculate pair densities:
        nt_nG = self.pd2.zeros(len(n1_n), q=q)
        for n1, nt_G in zip(n1_n, nt_nG):
            self.timer.start('IFFT2')
            u1_R = self.pd.ifft(kpt1.psit_nG[n1, :ng1], kpt1.k)
            self.timer.stop()
            nt_R = u1_R.conj() * u2_R
            self.timer.start('FFT')
            nt_G[:] = self.pd2.fft(nt_R, q)
            self.timer.stop()
        
        s = self.kd.sym_k[k]
        time_reversal = self.kd.time_reversal_k[k]
        k2_c = self.kd.ibzk_kc[kpt2.k]

        self.timer.start('Compensation charges')
        Q_anL = {}  # coefficients for shape functions
        for a, P1_ni in kpt1.P_ani.items():
            P1_ni = P1_ni[n1_n]

            if is_ibz2:
                P2_i = kpt2.P_ani[a][n2]
            else:
                b = self.kd.symmetry.a_sa[s, a]
                S_c = (np.dot(self.spos_ac[a], self.kd.symmetry.op_scc[s]) -
                       self.spos_ac[b])
                assert abs(S_c.round() - S_c).max() < 1e-5
                if self.ghat.dtype == complex:
                    x = np.exp(2j * pi * np.dot(k2_c, S_c))
                else:
                    x = 1.0
                P2_i = np.dot(self.wfs.setups[a].R_sii[s],
                              kpt2.P_ani[b][n2]) * x
                if time_reversal:
                    P2_i = P2_i.conj()

            D_np = []
            for P1_i in P1_ni:
                D_ii = np.outer(P1_i.conj(), P2_i)
                D_np.append(pack(D_ii))
            Q_anL[a] = np.dot(D_np, self.wfs.setups[a].Delta_pL)
            
        self.timer.start('Expand')
        if q != self.qlatest:
            self.f_IG = self.ghat.expand(q)
            self.qlatest = q
        self.timer.stop('Expand')

        # Add compensation charges:
        self.ghat.add(nt_nG, Q_anL, q, self.f_IG)
        self.timer.stop('Compensation charges')

        if self.molecule and n2 in n1_n:
            nn = (n1_n == n2).nonzero()[0][0]
            nt_nG[nn] -= self.ngauss_G
        else:
            nn = None
            
        iG2_G = self.iG2_qG[q]
        
        # Calculate energies:
        e_n = np.empty(len(n1_n))
        for n, nt_G in enumerate(nt_nG):
            e_n[n] = -4 * pi * np.real(self.pd2.integrate(nt_G, nt_G * iG2_G))
            self.npairs += 1
        
        if nn is not None:
            e_n[nn] -= 2 * (self.pd2.integrate(nt_nG[nn], self.vgauss_G) +
                            (self.beta / 2 / pi)**0.5)

        if self.write_timing_information:
            t = (time() - self.t0) / len(n1_n)
            self.log('Time for first pair-density: %10.3f seconds' % t)
            self.log('Estimated total time:        %10.3f seconds' %
                     (t * self.npairs0 / self.world.size))
            self.write_timing_information = False

        return e_n
    def with_ae_corrections(self, finegrid=False):
        """Get pair density including the AE corrections"""
        nij_g = self.get(finegrid)
        
        # Generate the density matrix
        D_ap = {}
#        D_aii = {}
        for a, P_ni in self.P_ani.items():
            Pi_i = P_ni[self.i]
            Pj_i = P_ni[self.j]
            D_ii = np.outer(Pi_i.conj(), Pj_i)
            # Note: D_ii is not symmetric but the products of partial waves are
            # so that we can pack
            D_ap[a] = pack(D_ii)
#            D_aii[a] = D_ii
        
        # Load partial waves if needed
        if ((finegrid and (not hasattr(self, 'phi'))) or
            ((not finegrid) and (not hasattr(self, 'Phi')))):
            
            # Splines
            splines = {}
            phi_aj = []
            phit_aj = []
            for a, id in enumerate(self.setups.id_a):
                if id in splines:
                    phi_j, phit_j = splines[id]
                else:
                    # Load splines:
                    phi_j, phit_j = self.setups[a].get_partial_waves()[:2]
                    splines[id] = (phi_j, phit_j)
                phi_aj.append(phi_j)
                phit_aj.append(phit_j)
            
            # Store partial waves as class variables
            if finegrid:
                gd = self.density.finegd
                self.__class__.phi = BasisFunctions(gd, phi_aj)
                self.__class__.phit = BasisFunctions(gd, phit_aj)
                self.__class__.phi.set_positions(self.spos_ac)
                self.__class__.phit.set_positions(self.spos_ac)
            else:
                gd = self.density.gd
                self.__class__.Phi = BasisFunctions(gd, phi_aj)
                self.__class__.Phit = BasisFunctions(gd, phit_aj)
                self.__class__.Phi.set_positions(self.spos_ac)
                self.__class__.Phit.set_positions(self.spos_ac)
        
        # Add AE corrections
        if finegrid:
            phi = self.phi
            phit = self.phit
            gd = self.density.finegd
        else:
            phi = self.Phi
            phit = self.Phit
            gd = self.density.gd
        
        rho_MM = np.zeros((phi.Mmax, phi.Mmax))
        M1 = 0
        for a, setup in enumerate(self.setups):
            ni = setup.ni
            D_p = D_ap.get(a)
            if D_p is None:
                D_p = np.empty((ni * (ni + 1) // 2))
            if gd.comm.size > 1:
                gd.comm.broadcast(D_p, self.wfs.rank_a[a])
            D_ii = unpack2(D_p)
#            D_ii = D_aii.get(a)
#            if D_ii is None:
#                D_ii = np.empty((ni, ni))
#            if gd.comm.size > 1:
#                gd.comm.broadcast(D_ii, self.wfs.rank_a[a])
            M2 = M1 + ni
            rho_MM[M1:M2, M1:M2] = D_ii
            M1 = M2
        
        # construct_density assumes symmetric rho_MM and
        # takes only the upper half of it
        phi.construct_density(rho_MM, nij_g, q=-1)
        phit.construct_density(-rho_MM, nij_g, q=-1)
        # TODO: use ae_valence_density_correction
#        phi.lfc.ae_valence_density_correction(
#            rho_MM, nij_g, np.zeros(len(phi.M_W), np.intc), np.zeros(self.na))
#        phit.lfc.ae_valence_density_correction(
#            -rho_MM, nij_g, np.zeros(len(phit.M_W), np.intc), np.zeros(self.na))
            
        return nij_g
import numpy.random as ra
from gpaw.setup import create_setup
from gpaw.xc.noncollinear import NonCollinearFunctional
from gpaw.xc import XC
from gpaw.test import equal
from gpaw.utilities import pack


x = 0.0000001
ra.seed(8)
for xc in ['LDA']:#, 'PBE']:
    print(xc)
    xc = XC(xc)
    s = create_setup('N', xc)
    ni = s.ni
    D_sp = np.array([pack(np.outer(P_i, P_i))
                     for P_i in 0.2 * ra.random((2, ni)) - 0.1])
    D_sp[1] += D_sp[0]

    nii = ni * (ni + 1) // 2

    E = xc.calculate_paw_correction(s, D_sp)

    xc = NonCollinearFunctional(xc)

    Dnc_sp = np.zeros((4, nii))
    Dnc_sp[0] = D_sp.sum(0)
    Dnc_sp[3] = D_sp[0] - D_sp[1]
    Enc = xc.calculate_paw_correction(s, Dnc_sp)
    print(E, E-Enc)
    assert abs(E - Enc) < 1e-11
Example #48
0
    psit_ig = np.zeros((niAO, n, n, n))
    pr.add(psit_ig, coefs)

    nii = ni * (ni + 1) // 2
    D_p = np.zeros(nii)
    H_p = np.zeros(nii)


    e_g = np.zeros((n, n, n))
    n_g = np.zeros((1, n, n, n))
    v_g = np.zeros((1, n, n, n))

    P_ni = 0.2 * ra.random((20, ni))
    P_ni[:, niAO:] = 0.0
    D_ii = np.dot(np.transpose(P_ni), P_ni)
    D_p = pack(D_ii)
    p = 0
    for i1 in range(niAO):
        for i2 in range(i1, niAO):
            n_g += D_p[p] * psit_ig[i1] * psit_ig[i2]
            p += 1
        p += ni - niAO

    p = create_localized_functions([s.nct], gd, (0.5, 0.5, 0.5))
    p.add(n_g[0], np.ones(1))
    e_g = gd.zeros()
    xc.calculate(gd, n_g, v_g, e_g)

    r2_g = np.sum((np.indices((n, n, n)) - n / 2)**2, axis=0)
    dv_g = gd.dv * np.less(r2_g, (rcut / a * n)**2)
Example #49
0
import numpy.random as ra
from gpaw.setup import create_setup
from gpaw.xc.noncollinear import NonCollinearFunctional
from gpaw.xc import XC
from gpaw.test import equal
from gpaw.utilities import pack


x = 0.0000001
ra.seed(8)
for xc in ["LDA"]:  # , 'PBE']:
    print xc
    xc = XC(xc)
    s = create_setup("N", xc)
    ni = s.ni
    D_sp = np.array([pack(np.outer(P_i, P_i)) for P_i in 0.2 * ra.random((2, ni)) - 0.1])
    D_sp[1] += D_sp[0]

    nii = ni * (ni + 1) // 2

    E = xc.calculate_paw_correction(s, D_sp)

    xc = NonCollinearFunctional(xc)

    Dnc_sp = np.zeros((4, nii))
    Dnc_sp[0] = D_sp.sum(0)
    Dnc_sp[3] = D_sp[0] - D_sp[1]
    Enc = xc.calculate_paw_correction(s, Dnc_sp)
    print E, E - Enc
    assert abs(E - Enc) < 1e-11
    def get_xc(self):
        """Add xc part of the coupling matrix"""

        # shorthands
        paw = self.paw
        wfs = paw.wfs
        gd = paw.density.finegd
        comm = gd.comm
        eh_comm = self.eh_comm

        fg = self.finegrid is 2
        kss = self.fullkss
        nij = len(kss)

        Om_xc = self.Om
        # initialize densities
        # nt_sg is the smooth density on the fine grid with spin index

        if kss.nvspins == 2:
            # spin polarised ground state calc.
            nt_sg = paw.density.nt_sg
        else:
            # spin unpolarised ground state calc.
            if kss.npspins == 2:
                # construct spin polarised densities
                nt_sg = np.array([.5 * paw.density.nt_sg[0],
                                  .5 * paw.density.nt_sg[0]])
            else:
                nt_sg = paw.density.nt_sg
        # check if D_sp have been changed before
        D_asp = self.paw.density.D_asp
        for a, D_sp in D_asp.items():
            if len(D_sp) != kss.npspins:
                if len(D_sp) == 1:
                    D_asp[a] = np.array([0.5 * D_sp[0], 0.5 * D_sp[0]])
                else:
                    D_asp[a] = np.array([D_sp[0] + D_sp[1]])

        # restrict the density if needed
        if fg:
            nt_s = nt_sg
        else:
            nt_s = self.gd.zeros(nt_sg.shape[0])
            for s in range(nt_sg.shape[0]):
                self.restrict(nt_sg[s], nt_s[s])
            gd = paw.density.gd

        # initialize vxc or fxc

        if self.derivativeLevel == 0:
            raise NotImplementedError
            if kss.npspins == 2:
                v_g = nt_sg[0].copy()
            else:
                v_g = nt_sg.copy()
        elif self.derivativeLevel == 1:
            pass
        elif self.derivativeLevel == 2:
            fxc_sg = np.zeros(nt_sg.shape)
            self.xc.calculate_fxc(gd, nt_sg, fxc_sg)
        else:
            raise ValueError('derivativeLevel can only be 0,1,2')

# self.paw.my_nuclei = []

        ns = self.numscale
        xc = self.xc
        print('XC', nij, 'transitions', file=self.txt)
        for ij in range(eh_comm.rank, nij, eh_comm.size):
            print('XC kss[' + '%d' % ij + ']', file=self.txt)

            timer = Timer()
            timer.start('init')
            timer2 = Timer()

            if self.derivativeLevel >= 1:
                # vxc is available
                # We use the numerical two point formula for calculating
                # the integral over fxc*n_ij. The results are
                # vvt_s        smooth integral
                # nucleus.I_sp atom based correction matrices (pack2)
                #              stored on each nucleus
                timer2.start('init v grids')
                vp_s = np.zeros(nt_s.shape, nt_s.dtype.char)
                vm_s = np.zeros(nt_s.shape, nt_s.dtype.char)
                if kss.npspins == 2:  # spin polarised
                    nv_s = nt_s.copy()
                    nv_s[kss[ij].pspin] += ns * kss[ij].get(fg)
                    xc.calculate(gd, nv_s, vp_s)
                    nv_s = nt_s.copy()
                    nv_s[kss[ij].pspin] -= ns * kss[ij].get(fg)
                    xc.calculate(gd, nv_s, vm_s)
                else:  # spin unpolarised
                    nv = nt_s + ns * kss[ij].get(fg)
                    xc.calculate(gd, nv, vp_s)
                    nv = nt_s - ns * kss[ij].get(fg)
                    xc.calculate(gd, nv, vm_s)
                vvt_s = (0.5 / ns) * (vp_s - vm_s)
                timer2.stop()

                # initialize the correction matrices
                timer2.start('init v corrections')
                I_asp = {}
                for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items():
                    # create the modified density matrix
                    Pi_i = P_ni[kss[ij].i]
                    Pj_i = P_ni[kss[ij].j]
                    P_ii = np.outer(Pi_i, Pj_i)
                    # we need the symmetric form, hence we can pack
                    P_p = pack(P_ii)
                    D_sp = self.paw.density.D_asp[a].copy()
                    D_sp[kss[ij].pspin] -= ns * P_p
                    setup = wfs.setups[a]
                    I_sp = np.zeros_like(D_sp)
                    self.xc.calculate_paw_correction(setup, D_sp, I_sp)
                    I_sp *= -1.0
                    D_sp = self.paw.density.D_asp[a].copy()
                    D_sp[kss[ij].pspin] += ns * P_p
                    self.xc.calculate_paw_correction(setup, D_sp, I_sp)
                    I_sp /= 2.0 * ns
                    I_asp[a] = I_sp
                timer2.stop()

            timer.stop()
            t0 = timer.get_time('init')
            timer.start(ij)

            for kq in range(ij, nij):
                weight = self.weight_Kijkq(ij, kq)

                if self.derivativeLevel == 0:
                    # only Exc is available

                    if kss.npspins == 2:  # spin polarised
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] += kss[ij].get(fg)
                        nv_g[kss[kq].pspin] += kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(
                            nv_g[0], v_g, nv_g[1], v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] += kss[ij].get(fg)
                        nv_g[kss[kq].pspin] -= kss[kq].get(fg)
                        Excpm = xc.get_energy_and_potential(
                            nv_g[0], v_g, nv_g[1], v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] -=\
                            kss[ij].get(fg)
                        nv_g[kss[kq].pspin] +=\
                            kss[kq].get(fg)
                        Excmp = xc.get_energy_and_potential(
                            nv_g[0], v_g, nv_g[1], v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] -= \
                            kss[ij].get(fg)
                        nv_g[kss[kq].pspin] -=\
                            kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(
                            nv_g[0], v_g, nv_g[1], v_g)
                    else:  # spin unpolarised
                        nv_g = nt_sg + ns * kss[ij].get(fg)\
                            + ns * kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(nv_g, v_g)
                        nv_g = nt_sg + ns * kss[ij].get(fg)\
                            - ns * kss[kq].get(fg)
                        Excpm = xc.get_energy_and_potential(nv_g, v_g)
                        nv_g = nt_sg - ns * kss[ij].get(fg)\
                            + ns * kss[kq].get(fg)
                        Excmp = xc.get_energy_and_potential(nv_g, v_g)
                        nv_g = nt_sg - ns * kss[ij].get(fg)\
                            - ns * kss[kq].get(fg)
                        Excmm = xc.get_energy_and_potential(nv_g, v_g)

                    Om_xc[ij, kq] += weight *\
                        0.25 * \
                        (Excpp - Excmp - Excpm + Excmm) / (ns * ns)

                elif self.derivativeLevel == 1:
                    # vxc is available

                    timer2.start('integrate')
                    Om_xc[ij, kq] += weight *\
                        self.gd.integrate(kss[kq].get(fg) *
                                          vvt_s[kss[kq].pspin])
                    timer2.stop()

                    timer2.start('integrate corrections')
                    Exc = 0.
                    for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items():
                        # create the modified density matrix
                        Pk_i = P_ni[kss[kq].i]
                        Pq_i = P_ni[kss[kq].j]
                        P_ii = np.outer(Pk_i, Pq_i)
                        # we need the symmetric form, hence we can pack
                        # use pack as I_sp used pack2
                        P_p = pack(P_ii)
                        Exc += np.dot(I_asp[a][kss[kq].pspin], P_p)
                    Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc)
                    timer2.stop()

                elif self.derivativeLevel == 2:
                    # fxc is available
                    if kss.npspins == 2:  # spin polarised
                        Om_xc[ij, kq] += weight *\
                            gd.integrate(kss[ij].get(fg) *
                                         kss[kq].get(fg) *
                                         fxc_sg[kss[ij].pspin, kss[kq].pspin])
                    else:  # spin unpolarised
                        Om_xc[ij, kq] += weight *\
                            gd.integrate(kss[ij].get(fg) *
                                         kss[kq].get(fg) *
                                         fxc_sg)

                    # XXX still numeric derivatives for local terms
                    timer2.start('integrate corrections')
                    Exc = 0.
                    for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items():
                        # create the modified density matrix
                        Pk_i = P_ni[kss[kq].i]
                        Pq_i = P_ni[kss[kq].j]
                        P_ii = np.outer(Pk_i, Pq_i)
                        # we need the symmetric form, hence we can pack
                        # use pack as I_sp used pack2
                        P_p = pack(P_ii)
                        Exc += np.dot(I_asp[a][kss[kq].pspin], P_p)
                    Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc)
                    timer2.stop()

                if ij != kq:
                    Om_xc[kq, ij] = Om_xc[ij, kq]

            timer.stop()
# timer2.write()
            if ij < (nij - 1):
                print('XC estimated time left',
                      self.time_left(timer, t0, ij, nij), file=self.txt)
Example #51
0
    def get_xc(self):
        """Add xc part of the coupling matrix"""

        # shorthands
        paw = self.paw
        wfs = paw.wfs
        gd = paw.density.finegd
        comm = gd.comm
        eh_comm = self.eh_comm
        
        fg = self.finegrid is 2
        kss = self.fullkss
        nij = len(kss)

        Om_xc = self.Om
        # initialize densities
        # nt_sg is the smooth density on the fine grid with spin index

        if kss.nvspins==2:
            # spin polarised ground state calc.
            nt_sg = paw.density.nt_sg
        else:
            # spin unpolarised ground state calc.
            if kss.npspins==2:
                # construct spin polarised densities
                nt_sg = np.array([.5*paw.density.nt_sg[0],
                                  .5*paw.density.nt_sg[0]])
            else:
                nt_sg = paw.density.nt_sg
        # check if D_sp have been changed before
        D_asp = self.paw.density.D_asp
        for a, D_sp in D_asp.items():
            if len(D_sp) != kss.npspins:
                if len(D_sp) == 1:
                    D_asp[a] = np.array([0.5 * D_sp[0], 0.5 * D_sp[0]])
                else:
                    D_asp[a] = np.array([D_sp[0] + D_sp[1]])
                
        # restrict the density if needed
        if fg:
            nt_s = nt_sg
        else:
            nt_s = self.gd.zeros(nt_sg.shape[0])
            for s in range(nt_sg.shape[0]):
                self.restrict(nt_sg[s], nt_s[s])
            gd = paw.density.gd
                
        # initialize vxc or fxc

        if self.derivativeLevel==0:
            raise NotImplementedError
            if kss.npspins==2:
                v_g=nt_sg[0].copy()
            else:
                v_g=nt_sg.copy()
        elif self.derivativeLevel==1:
            pass
        elif self.derivativeLevel==2:
            fxc_sg = np.zeros(nt_sg.shape)
            self.xc.calculate_fxc(gd, nt_sg, fxc_sg)
        else:
            raise ValueError('derivativeLevel can only be 0,1,2')

##        self.paw.my_nuclei = []

        ns=self.numscale
        xc=self.xc
        print >> self.txt, 'XC',nij,'transitions'
        for ij in range(eh_comm.rank, nij, eh_comm.size):
            print >> self.txt,'XC kss['+'%d'%ij+']' 

            timer = Timer()
            timer.start('init')
            timer2 = Timer()
                      
            if self.derivativeLevel >= 1:
                # vxc is available
                # We use the numerical two point formula for calculating
                # the integral over fxc*n_ij. The results are
                # vvt_s        smooth integral
                # nucleus.I_sp atom based correction matrices (pack2)
                #              stored on each nucleus
                timer2.start('init v grids')
                vp_s=np.zeros(nt_s.shape,nt_s.dtype.char)
                vm_s=np.zeros(nt_s.shape,nt_s.dtype.char)
                if kss.npspins == 2: # spin polarised
                    nv_s = nt_s.copy()
                    nv_s[kss[ij].pspin] += ns * kss[ij].get(fg)
                    xc.calculate(gd, nv_s, vp_s)
                    nv_s = nt_s.copy()
                    nv_s[kss[ij].pspin] -= ns * kss[ij].get(fg)
                    xc.calculate(gd, nv_s, vm_s)
                else: # spin unpolarised
                    nv = nt_s + ns * kss[ij].get(fg)
                    xc.calculate(gd, nv, vp_s)
                    nv = nt_s - ns * kss[ij].get(fg)
                    xc.calculate(gd, nv, vm_s)
                vvt_s = (0.5 / ns) * (vp_s - vm_s)
                timer2.stop()

                # initialize the correction matrices
                timer2.start('init v corrections')
                I_asp = {}
                for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items():
                    # create the modified density matrix
                    Pi_i = P_ni[kss[ij].i]
                    Pj_i = P_ni[kss[ij].j]
                    P_ii = np.outer(Pi_i, Pj_i)
                    # we need the symmetric form, hence we can pack
                    P_p = pack(P_ii)
                    D_sp = self.paw.density.D_asp[a].copy()
                    D_sp[kss[ij].pspin] -= ns * P_p
                    setup = wfs.setups[a]
                    I_sp = np.zeros_like(D_sp)
                    self.xc.calculate_paw_correction(setup, D_sp, I_sp)
                    I_sp *= -1.0
                    D_sp = self.paw.density.D_asp[a].copy()
                    D_sp[kss[ij].pspin] += ns * P_p
                    self.xc.calculate_paw_correction(setup, D_sp, I_sp)
                    I_sp /= 2.0 * ns
                    I_asp[a] = I_sp
                timer2.stop()
                    
            timer.stop()
            t0 = timer.get_time('init')
            timer.start(ij)
            
            for kq in range(ij,nij):
                weight = self.weight_Kijkq(ij, kq)
                
                if self.derivativeLevel == 0:
                    # only Exc is available
                    
                    if kss.npspins==2: # spin polarised
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] += kss[ij].get(fg)
                        nv_g[kss[kq].pspin] += kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(
                            nv_g[0], v_g, nv_g[1], v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] += kss[ij].get(fg)
                        nv_g[kss[kq].pspin] -= kss[kq].get(fg)
                        Excpm = xc.get_energy_and_potential(\
                                            nv_g[0],v_g,nv_g[1],v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] -=\
                                        kss[ij].get(fg)
                        nv_g[kss[kq].pspin] +=\
                                        kss[kq].get(fg)
                        Excmp = xc.get_energy_and_potential(\
                                            nv_g[0],v_g,nv_g[1],v_g)
                        nv_g = nt_sg.copy()
                        nv_g[kss[ij].pspin] -= \
                                        kss[ij].get(fg)
                        nv_g[kss[kq].pspin] -=\
                                        kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(\
                                            nv_g[0],v_g,nv_g[1],v_g)
                    else: # spin unpolarised
                        nv_g=nt_sg + ns*kss[ij].get(fg)\
                              + ns*kss[kq].get(fg)
                        Excpp = xc.get_energy_and_potential(nv_g,v_g)
                        nv_g=nt_sg + ns*kss[ij].get(fg)\
                              - ns*kss[kq].get(fg)
                        Excpm = xc.get_energy_and_potential(nv_g,v_g)
                        nv_g=nt_sg - ns*kss[ij].get(fg)\
                              + ns*kss[kq].get(fg)
                        Excmp = xc.get_energy_and_potential(nv_g,v_g)
                        nv_g=nt_sg - ns*kss[ij].get(fg)\
                              - ns*kss[kq].get(fg)
                        Excmm = xc.get_energy_and_potential(nv_g,v_g)

                    Om_xc[ij,kq] += weight *\
                                0.25*(Excpp-Excmp-Excpm+Excmm)/(ns*ns)
                              
                elif self.derivativeLevel == 1:
                    # vxc is available

                    timer2.start('integrate')
                    Om_xc[ij,kq] += weight*\
                                 self.gd.integrate(kss[kq].get(fg)*
                                                   vvt_s[kss[kq].pspin])
                    timer2.stop()

                    timer2.start('integrate corrections')
                    Exc = 0.
                    for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items():
                        # create the modified density matrix
                        Pk_i = P_ni[kss[kq].i]
                        Pq_i = P_ni[kss[kq].j]
                        P_ii = np.outer(Pk_i, Pq_i)
                        # we need the symmetric form, hence we can pack
                        # use pack as I_sp used pack2
                        P_p = pack(P_ii)
                        Exc += np.dot(I_asp[a][kss[kq].pspin], P_p)
                    Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc)
                    timer2.stop()

                elif self.derivativeLevel == 2:
                    # fxc is available
                    if kss.npspins==2: # spin polarised
                        Om_xc[ij,kq] += weight *\
                            gd.integrate(kss[ij].get(fg) *
                                         kss[kq].get(fg) *
                                         fxc_sg[kss[ij].pspin, kss[kq].pspin])
                    else: # spin unpolarised
                        Om_xc[ij,kq] += weight *\
                            gd.integrate(kss[ij].get(fg) *
                                         kss[kq].get(fg) *
                                         fxc_sg)
                    
                    # XXX still numeric derivatives for local terms
                    timer2.start('integrate corrections')
                    Exc = 0.
                    for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items():
                        # create the modified density matrix
                        Pk_i = P_ni[kss[kq].i]
                        Pq_i = P_ni[kss[kq].j]
                        P_ii = np.outer(Pk_i, Pq_i)
                        # we need the symmetric form, hence we can pack
                        # use pack as I_sp used pack2
                        P_p = pack(P_ii)
                        Exc += np.dot(I_asp[a][kss[kq].pspin], P_p)
                    Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc)
                    timer2.stop()

                if ij != kq:
                    Om_xc[kq,ij] = Om_xc[ij,kq]
                
            timer.stop()
##            timer2.write()
            if ij < (nij-1):
                print >> self.txt,'XC estimated time left',\
                    self.time_left(timer, t0, ij, nij)
Example #52
0
def makeU(gpwfile='grid.gpw', orbitalfile='w_wG__P_awi.pckl',
          rotationfile='eps_q__U_pq.pckl', tolerance=1e-5,
          writeoptimizedpairs=False, dppname='D_pp.pckl', S_w=None):

    # S_w: None or diagonal of overlap matrix. In the latter case
    # the optimized and truncated pair orbitals are obtained from
    # normalized (to 1) orbitals.
    #     
    # Tolerance is used for truncation of optimized pairorbitals
    #calc = GPAW(gpwfile, txt=None)
    from gpaw import GPAW
    from gpaw.utilities import pack, unpack
    from gpaw.utilities.blas import rk, gemm
    from gpaw.mpi import world, MASTER
    calc = GPAW(gpwfile, txt='pairorb.txt') # XXX
    gd = calc.wfs.gd
    setups = calc.wfs.setups
    myatoms = calc.density.D_asp.keys()
    del calc

    # Load orbitals on master and distribute to slaves
    if world.rank == MASTER:
        wglobal_wG, P_awi = pickle.load(open(orbitalfile))
        Nw = len(wglobal_wG)
        print('Estimated total (serial) mem usage: %0.3f GB' % (
            np.prod(gd.N_c) * Nw**2 * 8 / 1024.**3))
    else:
        wglobal_wG = None
        Nw = 0
    Nw = gd.comm.sum(Nw) #distribute Nw to all nodes
    w_wG = gd.empty(n=Nw)
    gd.distribute(wglobal_wG, w_wG)
    del wglobal_wG
    
    # Make pairorbitals
    f_pG = gd.zeros(n=Nw**2)
    Np = len(f_pG)
    for p, (w1, w2) in enumerate(np.ndindex(Nw, Nw)):
        np.multiply(w_wG[w1], w_wG[w2], f_pG[p])
    del w_wG
    assert f_pG.flags.contiguous 
    # Make pairorbital overlap (lower triangle only)
    D_pp = np.zeros((Nw**2, Nw**2))
    rk(gd.dv, f_pG, 0., D_pp)

    # Add atomic corrections to pairorbital overlap
    for a in myatoms:
        if setups[a].type != 'ghost':
            P_pp = np.array([pack(np.outer(P_awi[a][w1], P_awi[a][w2]))
                             for w1, w2 in np.ndindex(Nw, Nw)])
            I4_pp = setups[a].four_phi_integrals()
            A = np.zeros((len(I4_pp), len(P_pp)))
            gemm(1.0, P_pp, I4_pp, 0.0, A, 't')
            gemm(1.0, A, P_pp, 1.0, D_pp)
            #D_pp += np.dot(P_pp, np.dot(I4_pp, P_pp.T))
   
    # Summ all contributions to master
    gd.comm.sum(D_pp, MASTER)

    if world.rank == MASTER:
        if S_w is not None:
            print('renormalizing pairorb overlap matrix (D_pp)')
            S2 = np.sqrt(S_w)
            for pa, (wa1, wa2) in enumerate(np.ndindex(Nw, Nw)):
                for pb, (wb1, wb2) in enumerate(np.ndindex(Nw, Nw)):
                    D_pp[pa, pb] /= S2[wa1] * S2[wa2] * S2[wb1] * S2[wb2]

        D_pp.dump(dppname) # XXX if the diagonalization below (on MASTER only)
                           # fails, then one can always restart the stuff
                           # below using only the stored D_pp matrix

        # Determine eigenvalues and vectors on master only
        eps_q, U_pq = np.linalg.eigh(D_pp, UPLO='L')
        del D_pp
        indices = np.argsort(-eps_q.real)
        eps_q = np.ascontiguousarray(eps_q.real[indices])
        U_pq = np.ascontiguousarray(U_pq[:, indices])

        # Truncate
        indices = eps_q > tolerance
        U_pq = np.ascontiguousarray(U_pq[:, indices])
        eps_q = np.ascontiguousarray(eps_q[indices])

        # Dump to file
        pickle.dump((eps_q, U_pq), open(rotationfile, 'wb'), 2)

    if writeoptimizedpairs is not False:
        assert world.size == 1 # works in parallel if U and eps are broadcast
        Uisq_qp = (U_pq / np.sqrt(eps_q)).T.copy()
        g_qG = gd.zeros(n=len(eps_q))
        gemm(1.0, f_pG, Uisq_qp, 0.0, g_qG)
        g_qG = gd.collect(g_qG)
        if world.rank == MASTER:
            P_app = dict([(a, np.array([pack(np.outer(P_wi[w1], P_wi[w2]),
                                             tolerance=1e3)
                                        for w1, w2 in np.ndindex(Nw, Nw)]))
                          for a, P_wi in P_awi.items()])
            P_aqp = dict([(a, np.dot(Uisq_qp, P_pp))
                          for a, P_pp in P_app.items()])
            pickle.dump((g_qG, P_aqp), open(writeoptimizedpairs, 'wb'), 2)
Example #53
0
def makeU(gpwfile='grid.gpw', orbitalfile='w_wG__P_awi.pckl',
          rotationfile='eps_q__U_pq.pckl', tolerance=1e-5,
          writeoptimizedpairs=False, dppname='D_pp.pckl', S_w=None):

    # S_w: None or diagonal of overlap matrix. In the latter case
    # the optimized and truncated pair orbitals are obtained from
    # normalized (to 1) orbitals.
    #     
    # Tolerance is used for truncation of optimized pairorbitals
    #calc = GPAW(gpwfile, txt=None)
    from gpaw import GPAW
    from gpaw.utilities import pack, unpack
    from gpaw.utilities.blas import rk, gemm
    from gpaw.mpi import world, MASTER, serial_comm
    calc = GPAW(gpwfile, txt='pairorb.txt') # XXX
    gd = calc.wfs.gd
    setups = calc.wfs.setups
    myatoms = calc.density.D_asp.keys()
    del calc

    # Load orbitals on master and distribute to slaves
    if world.rank == MASTER:
        wglobal_wG, P_awi = pickle.load(open(orbitalfile))
        Nw = len(wglobal_wG)
        print 'Estimated total (serial) mem usage: %0.3f GB' % (
            np.prod(gd.N_c) * Nw**2 * 8 / 1024.**3)
    else:
        wglobal_wG = None
        Nw = 0
    Nw = gd.comm.sum(Nw) #distribute Nw to all nodes
    w_wG = gd.empty(n=Nw)
    gd.distribute(wglobal_wG, w_wG)
    del wglobal_wG
    
    # Make pairorbitals
    f_pG = gd.zeros(n=Nw**2)
    Np = len(f_pG)
    for p, (w1, w2) in enumerate(np.ndindex(Nw, Nw)):
        np.multiply(w_wG[w1], w_wG[w2], f_pG[p])
    del w_wG
    assert f_pG.flags.contiguous 
    # Make pairorbital overlap (lower triangle only)
    D_pp = np.zeros((Nw**2, Nw**2))
    rk(gd.dv, f_pG, 0., D_pp)

    # Add atomic corrections to pairorbital overlap
    for a in myatoms:
        if setups[a].type != 'ghost':
            P_pp = np.array([pack(np.outer(P_awi[a][w1], P_awi[a][w2]))
                             for w1, w2 in np.ndindex(Nw, Nw)])
            I4_pp = setups[a].four_phi_integrals()
            A = np.zeros((len(I4_pp), len(P_pp)))
            gemm(1.0, P_pp, I4_pp, 0.0, A, 't')
            gemm(1.0, A, P_pp, 1.0, D_pp)
            #D_pp += np.dot(P_pp, np.dot(I4_pp, P_pp.T))
   
    # Summ all contributions to master
    gd.comm.sum(D_pp, MASTER)

    if world.rank == MASTER:
        if S_w != None:
            print 'renormalizing pairorb overlap matrix (D_pp)'
            S2 = np.sqrt(S_w)
            for pa, (wa1, wa2) in enumerate(np.ndindex(Nw, Nw)):
                for pb, (wb1, wb2) in enumerate(np.ndindex(Nw, Nw)):
                    D_pp[pa, pb] /= S2[wa1] * S2[wa2] * S2[wb1] * S2[wb2]

        D_pp.dump(dppname) # XXX if the diagonalization below (on MASTER only)
                           # fails, then one can always restart the stuff
                           # below using only the stored D_pp matrix

        # Determine eigenvalues and vectors on master only
        eps_q, U_pq = np.linalg.eigh(D_pp, UPLO='L')
        del D_pp
        indices = np.argsort(-eps_q.real)
        eps_q = np.ascontiguousarray(eps_q.real[indices])
        U_pq = np.ascontiguousarray(U_pq[:, indices])

        # Truncate
        indices = eps_q > tolerance
        U_pq = np.ascontiguousarray(U_pq[:, indices])
        eps_q = np.ascontiguousarray(eps_q[indices])

        # Dump to file
        pickle.dump((eps_q, U_pq), open(rotationfile, 'wb'), 2)

    if writeoptimizedpairs is not False:
        assert world.size == 1 # works in parallel if U and eps are broadcast
        Uisq_qp = (U_pq / np.sqrt(eps_q)).T.copy()
        g_qG = gd.zeros(n=len(eps_q))
        gemm(1.0, f_pG, Uisq_qp, 0.0, g_qG)
        g_qG = gd.collect(g_qG)
        if world.rank == MASTER:
            P_app = dict([(a, np.array([pack(np.outer(P_wi[w1], P_wi[w2]),
                                             tolerance=1e3)
                                        for w1, w2 in np.ndindex(Nw, Nw)]))
                          for a, P_wi in P_awi.items()])
            P_aqp = dict([(a, np.dot(Uisq_qp, P_pp))
                          for a, P_pp in P_app.items()])
            pickle.dump((g_qG, P_aqp), open(writeoptimizedpairs, 'wb'), 2)
Example #54
0
    def get_rpa(self):
        """calculate RPA part of the omega matrix"""

        # shorthands
        kss=self.fullkss
        finegrid=self.finegrid
        wfs = self.paw.wfs
        eh_comm = self.eh_comm
        
        # calculate omega matrix
        nij = len(kss)
        print >> self.txt,'RPA',nij,'transitions'
        
        Om = self.Om
        
        for ij in range(eh_comm.rank, nij, eh_comm.size):
            print >> self.txt,'RPA kss['+'%d'%ij+']=', kss[ij]

            timer = Timer()
            timer.start('init')
            timer2 = Timer()
                      
            # smooth density including compensation charges
            timer2.start('with_compensation_charges 0')
            rhot_p = kss[ij].with_compensation_charges(
                finegrid is not 0)
            timer2.stop()
            
            # integrate with 1/|r_1-r_2|
            timer2.start('poisson')
            phit_p = np.zeros(rhot_p.shape, rhot_p.dtype.char)
            self.poisson.solve(phit_p, rhot_p, charge=None)
            timer2.stop()

            timer.stop()
            t0 = timer.get_time('init')
            timer.start(ij)

            if finegrid == 1:
                rhot = kss[ij].with_compensation_charges()
                phit = self.gd.zeros()
##                print "shapes 0=",phit.shape,rhot.shape
                self.restrict(phit_p,phit)
            else:
                phit = phit_p
                rhot = rhot_p

            for kq in range(ij,nij):
                if kq != ij:
                    # smooth density including compensation charges
                    timer2.start('kq with_compensation_charges')
                    rhot = kss[kq].with_compensation_charges(
                        finegrid is 2)
                    timer2.stop()

                timer2.start('integrate')
                pre = 2.*sqrt(kss[ij].get_energy()*kss[kq].get_energy()*
                                  kss[ij].get_weight()*kss[kq].get_weight())
                Om[ij,kq]= pre * self.gd.integrate(rhot*phit)
##                print "int=",Om[ij,kq]
                timer2.stop()

                # Add atomic corrections
                timer2.start('integrate corrections 2')
                Ia = 0.
                for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items():
                    Pi_i = P_ni[kss[ij].i]
                    Pj_i = P_ni[kss[ij].j]
                    Dij_ii = np.outer(Pi_i, Pj_i)
                    Dij_p = pack(Dij_ii)
                    Pkq_ni = wfs.kpt_u[kss[kq].spin].P_ani[a]
                    Pk_i = Pkq_ni[kss[kq].i]
                    Pq_i = Pkq_ni[kss[kq].j]
                    Dkq_ii = np.outer(Pk_i, Pq_i)
                    Dkq_p = pack(Dkq_ii)
                    C_pp = wfs.setups[a].M_pp
                    #   ----
                    # 2 >      P   P  C    P  P
                    #   ----    ip  jr prst ks qt
                    #   prst
                    Ia += 2.0*np.dot(Dkq_p,np.dot(C_pp,Dij_p))
                timer2.stop()
                
                Om[ij,kq] += pre * self.gd.comm.sum(Ia)
                    
                if ij == kq:
                    Om[ij,kq] += kss[ij].get_energy()**2
                else:
                    Om[kq,ij]=Om[ij,kq]

            timer.stop()
##            timer2.write()
            if ij < (nij-1):
                t = timer.get_time(ij) # time for nij-ij calculations
                t = .5*t*(nij-ij)  # estimated time for n*(n+1)/2, n=nij-(ij+1)
                print >> self.txt,'RPA estimated time left',\
                      self.timestring(t0*(nij-ij-1)+t)
Example #55
0
    coefs = np.identity(nao, float)
    psit_ig = np.zeros((nao, n, n, n))
    pr.add(psit_ig, coefs)

    nii = ni * (ni + 1) // 2
    D_p = np.zeros(nii)
    H_p = np.zeros(nii)

    e_g = np.zeros((n, n, n))
    n_g = np.zeros((1, n, n, n))
    v_g = np.zeros((1, n, n, n))

    P_ni = 0.2 * ra.random((20, ni))
    P_ni[:, nao:] = 0.0
    D_ii = np.dot(np.transpose(P_ni), P_ni)
    D_p = pack(D_ii)
    p = 0
    for i1 in range(nao):
        for i2 in range(i1, nao):
            n_g += D_p[p] * psit_ig[i1] * psit_ig[i2]
            p += 1
        p += ni - nao

    p = create_localized_functions([s.nct], gd, (0.5, 0.5, 0.5))
    p.add(n_g[0], np.ones(1))
    e_g = gd.zeros()
    xc.calculate(gd, n_g, v_g, e_g)

    r2_g = np.sum((np.indices((n, n, n)) - n / 2)**2, axis=0)
    dv_g = gd.dv * np.less(r2_g, (rcut / a * n)**2)