Esempio n. 1
0
    def calculate_exx_paw_correction(self):
        exx = 0
        deg = 2 // self.nspins  # spin degeneracy
        for a, D_sp in self.density.D_asp.items():
            setup = self.setups[a]
            for D_p in D_sp:
                D_ii = unpack2(D_p)
                ni = len(D_ii)

                for i1 in range(ni):
                    for i2 in range(ni):
                        A = 0.0
                        for i3 in range(ni):
                            p13 = packed_index(i1, i3, ni)
                            for i4 in range(ni):
                                p24 = packed_index(i2, i4, ni)
                                A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                        exx -= self.hybrid / deg * D_ii[i1, i2] * A

                if self.core_valence:
                    if setup.X_p is not None:
                        exx -= self.hybrid * np.dot(D_p, setup.X_p)
            if self.coredensity:
                exx += self.hybrid * setup.ExxC
        return exx
Esempio n. 2
0
    def calculate_exx_paw_correction(self):
        self.timer.start('PAW correction')
        self.devv = 0.0
        self.evc = 0.0
        self.ecc = 0.0

        deg = 2 // self.wfs.nspins  # spin degeneracy
        for a, D_sp in self.dens.D_asp.items():
            setup = self.wfs.setups[a]
            for D_p in D_sp:
                D_ii = unpack2(D_p)
                ni = len(D_ii)

                for i1 in range(ni):
                    for i2 in range(ni):
                        A = 0.0
                        for i3 in range(ni):
                            p13 = packed_index(i1, i3, ni)
                            for i4 in range(ni):
                                p24 = packed_index(i2, i4, ni)
                                A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                        self.devv -= D_ii[i1, i2] * A / deg

                self.evc -= np.dot(D_p, setup.X_p)
            self.ecc += setup.ExxC

        if not self.bandstructure:
            self.timer.stop('PAW correction')
            return

        Q = self.world.size // self.wfs.kd.comm.size
        self.exx_skn *= Q
        for kpt in self.wfs.kpt_u:
            for a, D_sp in self.dens.D_asp.items():
                setup = self.wfs.setups[a]
                for D_p in D_sp:
                    D_ii = unpack2(D_p)
                    ni = len(D_ii)
                    P_ni = kpt.P_ani[a]
                    for i1 in range(ni):
                        for i2 in range(ni):
                            A = 0.0
                            for i3 in range(ni):
                                p13 = packed_index(i1, i3, ni)
                                for i4 in range(ni):
                                    p24 = packed_index(i2, i4, ni)
                                    A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                            self.exx_skn[kpt.s, kpt.k] -= \
                                (A * P_ni[:, i1].conj() * P_ni[:, i2]).real
                            p12 = packed_index(i1, i2, ni)
                            self.exx_skn[kpt.s, kpt.k] -= \
                                (P_ni[:, i1].conj() * setup.X_p[p12] *
                                 P_ni[:, i2]).real / self.wfs.nspins

        self.world.sum(self.exx_skn)
        self.exx_skn *= self.hybrid / Q
        self.timer.stop('PAW correction')
    def calculate_exx_paw_correction(self):
        self.timer.start('PAW correction')
        self.devv = 0.0
        self.evc = 0.0
        self.ecc = 0.0
                         
        deg = 2 // self.wfs.nspins  # spin degeneracy
        for a, D_sp in self.dens.D_asp.items():
            setup = self.wfs.setups[a]
            for D_p in D_sp:
                D_ii = unpack2(D_p)
                ni = len(D_ii)

                for i1 in range(ni):
                    for i2 in range(ni):
                        A = 0.0
                        for i3 in range(ni):
                            p13 = packed_index(i1, i3, ni)
                            for i4 in range(ni):
                                p24 = packed_index(i2, i4, ni)
                                A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                        self.devv -= D_ii[i1, i2] * A / deg

                self.evc -= np.dot(D_p, setup.X_p)
            self.ecc += setup.ExxC

        if not self.bandstructure:
            self.timer.stop('PAW correction')
            return

        Q = self.world.size // self.wfs.kd.comm.size
        self.exx_skn *= Q
        for kpt in self.wfs.kpt_u:
            for a, D_sp in self.dens.D_asp.items():
                setup = self.wfs.setups[a]
                for D_p in D_sp:
                    D_ii = unpack2(D_p)
                    ni = len(D_ii)
                    P_ni = kpt.P_ani[a]
                    for i1 in range(ni):
                        for i2 in range(ni):
                            A = 0.0
                            for i3 in range(ni):
                                p13 = packed_index(i1, i3, ni)
                                for i4 in range(ni):
                                    p24 = packed_index(i2, i4, ni)
                                    A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                            self.exx_skn[kpt.s, kpt.k] -= \
                                (A * P_ni[:, i1].conj() * P_ni[:, i2]).real
                            p12 = packed_index(i1, i2, ni)
                            self.exx_skn[kpt.s, kpt.k] -= \
                                (P_ni[:, i1].conj() * setup.X_p[p12] *
                                 P_ni[:, i2]).real / self.wfs.nspins

        self.world.sum(self.exx_skn)
        self.exx_skn *= self.hybrid / Q
        self.timer.stop('PAW correction')
Esempio n. 4
0
def pawexxvv(atomdata, D_ii):
    """PAW correction for valence-valence EXX energy."""
    ni = len(D_ii)
    V_ii = np.empty((ni, ni))
    for i1 in range(ni):
        for i2 in range(ni):
            V = 0.0
            for i3 in range(ni):
                p13 = packed_index(i1, i3, ni)
                for i4 in range(ni):
                    p24 = packed_index(i2, i4, ni)
                    V += atomdata.M_pp[p13, p24] * D_ii[i3, i4]
            V_ii[i1, i2] = V
    return V_ii
Esempio n. 5
0
def pawexxvv(atomdata, D_ii):
    """PAW correction for valence-valence EXX energy."""
    ni = len(D_ii)
    V_ii = np.empty((ni, ni))
    for i1 in range(ni):
        for i2 in range(ni):
            V = 0.0
            for i3 in range(ni):
                p13 = packed_index(i1, i3, ni)
                for i4 in range(ni):
                    p24 = packed_index(i2, i4, ni)
                    V += atomdata.M_pp[p13, p24] * D_ii[i3, i4]
            V_ii[i1, i2] = V
    return V_ii
Esempio n. 6
0
def dipole_op(c, state1, state2, k=0, s=0):
    # Taken from KSSingle, maybe make this accessible in
    # KSSingle?
    wfs = c.wfs
    gd = wfs.gd

    kpt = None
    for i in wfs.kpt_u:
        if i.k == k and i.s == s:
            kpt = i

    pd = PairDensity(c)
    pd.initialize(kpt, state1, state2)

    # coarse grid contribution
    # <i|r|j> is the negative of the dipole moment (because of negative
    # e- charge)
    me = -gd.calculate_dipole_moment(pd.get())

    # augmentation contributions
    ma = np.zeros(me.shape)
    pos_av = c.get_atoms().get_positions() / Bohr
    for a, P_ni in kpt.P_ani.items():
        Ra = pos_av[a]
        Pi_i = P_ni[state1]
        Pj_i = P_ni[state2]
        Delta_pL = wfs.setups[a].Delta_pL
        ni = len(Pi_i)

        ma0 = 0
        ma1 = np.zeros(me.shape)
        for i in range(ni):
            for j in range(ni):
                pij = Pi_i[i] * Pj_i[j]
                ij = packed_index(i, j, ni)
                # L=0 term
                ma0 += Delta_pL[ij, 0] * pij
                # L=1 terms
                if wfs.setups[a].lmax >= 1:
                    # see spherical_harmonics.py for
                    # L=1:y L=2:z; L=3:x
                    ma1 += np.array([
                        Delta_pL[ij, 3], Delta_pL[ij, 1], Delta_pL[ij, 2]
                    ]) * pij
        ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0
    gd.comm.sum(ma)

    me += ma

    return me * Bohr
Esempio n. 7
0
 def calculate_vv(ni, D_ii, M_pp, weight, addme=False):
     """Calculate the local corrections depending on Mpp."""
     dexx = 0
     dekin = 0
     if not addme:
         addsign = -2.0
     else:
         addsign = 2.0
     for i1 in range(ni):
         for i2 in range(ni):
             A = 0.0
             for i3 in range(ni):
                 p13 = packed_index(i1, i3, ni)
                 for i4 in range(ni):
                     p24 = packed_index(i2, i4, ni)
                     A += M_pp[p13, p24] * D_ii[i3, i4]
             p12 = packed_index(i1, i2, ni)
             if Htpsit_nG is not None:
                 dH_p[p12] += addsign * weight / \
                     deg * A / ((i1 != i2) + 1)
             dekin += 2 * weight / deg * D_ii[i1, i2] * A
             dexx -= weight / deg * D_ii[i1, i2] * A
     return (dexx, dekin)
Esempio n. 8
0
def dipole_op(c, state1, state2, k=0, s=0):
    # Taken from KSSingle, maybe make this accessible in
    # KSSingle?
    wfs = c.wfs
    gd = wfs.gd

    kpt = None
    for i in wfs.kpt_u:
        if i.k == k and i.s == s:
            kpt = i
    
    pd = PairDensity(c)
    pd.initialize(kpt, state1, state2)

    # coarse grid contribution
    # <i|r|j> is the negative of the dipole moment (because of negative
    # e- charge)
    me = -gd.calculate_dipole_moment(pd.get())

    # augmentation contributions
    ma = np.zeros(me.shape)
    pos_av = c.get_atoms().get_positions() / Bohr
    for a, P_ni in kpt.P_ani.items():
        Ra = pos_av[a]
        Pi_i = P_ni[state1]
        Pj_i = P_ni[state2]
        Delta_pL = wfs.setups[a].Delta_pL
        ni = len(Pi_i)

        ma0 = 0
        ma1 = np.zeros(me.shape)
        for i in range(ni):
            for j in range(ni):
                pij = Pi_i[i]*Pj_i[j]
                ij = packed_index(i, j, ni)
                # L=0 term
                ma0 += Delta_pL[ij,0]*pij
                # L=1 terms
                if wfs.setups[a].lmax >= 1:
                    # see spherical_harmonics.py for
                    # L=1:y L=2:z; L=3:x
                    ma1 += np.array([Delta_pL[ij,3], Delta_pL[ij,1],
                                     Delta_pL[ij,2]]) * pij
        ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0
    gd.comm.sum(ma)

    me += ma

    return me * Bohr
Esempio n. 9
0
    def calculate_exx_paw_correction(self):
        exx = 0
        deg = 2 // self.nspins  # spin degeneracy
        for a, D_sp in self.density.D_asp.items():
            setup = self.setups[a]
            for D_p in D_sp:
                D_ii = unpack2(D_p)
                ni = len(D_ii)

                for i1 in range(ni):
                    for i2 in range(ni):
                        A = 0.0
                        for i3 in range(ni):
                            p13 = packed_index(i1, i3, ni)
                            for i4 in range(ni):
                                p24 = packed_index(i2, i4, ni)
                                A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                        p12 = packed_index(i1, i2, ni)
                        exx -= self.hybrid / deg * D_ii[i1, i2] * A

                if setup.X_p is not None:
                    exx -= self.hybrid * np.dot(D_p, setup.X_p)
            exx += self.hybrid * setup.ExxC
        return exx
Esempio n. 10
0
 def atomic_val_val(self, paw, H_nn, u=0):
     deg = 2 / self.nspins
     kpt = paw.wfs.kpt_u[u]
     for a, P_ni in kpt.P_ani.items():
         # Add atomic corrections to the valence-valence exchange energy
         # --
         # >  D   C     D
         # --  ii  iiii  ii
         setup = paw.wfs.setups[a]
         D_p = paw.density.D_asp[a][kpt.s]
         H_p = np.zeros_like(D_p)
         D_ii = unpack2(D_p)
         ni = len(D_ii)
         for i1 in range(ni):
             for i2 in range(ni):
                 A = 0.0
                 for i3 in range(ni):
                     p13 = packed_index(i1, i3, ni)
                     for i4 in range(ni):
                         p24 = packed_index(i2, i4, ni)
                         A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                 p12 = packed_index(i1, i2, ni)
                 H_p[p12] -= 2 / deg * A / ((i1 != i2) + 1)
         H_nn += np.dot(P_ni, np.inner(unpack(H_p), P_ni.conj()))
Esempio n. 11
0
File: tddft.py Progetto: qsnake/gpaw
    def _nuc_corr(self, i_m, j_d, k_m, k_d):
        ma = 0

        for a, P_ni_m in self.c_m.wfs.kpt_u[k_m].P_ani.items():
            P_ni_d = self.c_d.wfs.kpt_u[k_d].P_ani[a]
            Pi_i = P_ni_m[i_m]
            Pj_i = P_ni_d[j_d]
            Delta_pL = self.c_m.wfs.setups[a].Delta_pL

            for i in range(len(Pi_i)):
                for j in range(len(Pj_i)):
                    pij = Pi_i[i] * Pj_i[j]
                    ij = packed_index(i, j, len(Pi_i))
                    ma += Delta_pL[ij, 0] * pij

        self.gd.comm.sum(ma)
        return sqrt(4 * pi) * ma
Esempio n. 12
0
    def _nuc_corr(self, i_m, j_d, k_m, k_d):
        ma = 0.0

        for a, P_ni_m in self.c_m.wfs.kpt_u[k_m].P_ani.items():
            P_ni_d = self.c_d.wfs.kpt_u[k_d].P_ani[a]
            Pi_i = P_ni_m[i_m]
            Pj_i = P_ni_d[j_d]
            Delta_pL = self.c_m.wfs.setups[a].Delta_pL

            for i in range(len(Pi_i)):
                for j in range(len(Pj_i)):
                    pij = Pi_i[i] * Pj_i[j]
                    ij = packed_index(i, j, len(Pi_i))
                    ma += Delta_pL[ij, 0] * pij

        ma = self.gd.comm.sum(ma)
        return sqrt(4 * pi) * ma
Esempio n. 13
0
    def full(self, other, myspin=0, otherspin=0):
        """Overlap of Kohn-Sham states including local terms.

        Parameter
        ---------
        other: gpaw
            gpaw-object containing wave functions
 
        Returns
        -------
        out: array
            u_kij =  \int dx mypsi_ki^*(x) otherpsi_kj(x)
        """
        ov_knn = self.pseudo(other, normalize=False)
        for k in range(self.nk):
            # XXX what if parallelized over spin or kpoints ?
            kpt_rank, u = self.kd.get_rank_and_index(myspin, k)
            assert self.kd.comm.rank == kpt_rank
            kpt_rank, uo = other.wfs.kd.get_rank_and_index(otherspin, k)
            assert self.kd.comm.rank == kpt_rank

            mkpt = self.calc.wfs.kpt_u[u]
            okpt = other.wfs.kpt_u[uo]

            aov_nn = np.zeros_like(ov_knn[k])
            for a, mP_ni in mkpt.P_ani.items():
                oP_ni = okpt.P_ani[a]
                Delta_p = (np.sqrt(4 * np.pi) *
                           self.calc.wfs.setups[a].Delta_pL[:, 0])
                for n0, mP_i in enumerate(mP_ni):
                    for n1, oP_i in enumerate(oP_ni):
                        ni = len(mP_i)
                        assert (len(oP_i) == ni)
                        for i, mP in enumerate(mP_i):
                            for j, oP in enumerate(oP_i):
                                ij = packed_index(i, j, ni)
                                aov_nn[n0, n1] += Delta_p[ij] * mP.conj() * oP
            self.calc.wfs.gd.comm.sum(aov_nn)
            ov_knn[k] += aov_nn
        return ov_knn
Esempio n. 14
0
    def __init__(self,
                 iidx=None,
                 jidx=None,
                 pspin=None,
                 kpt=None,
                 paw=None,
                 string=None,
                 fijscale=1):

        if string is not None:
            self.fromstring(string)
            return None

        # normal entry

        PairDensity.__init__(self, paw)
        wfs = paw.wfs
        PairDensity.initialize(self, kpt, iidx, jidx)

        self.pspin = pspin

        f = kpt.f_n
        self.fij = (f[iidx] - f[jidx]) * fijscale
        e = kpt.eps_n
        self.energy = e[jidx] - e[iidx]

        # calculate matrix elements -----------

        gd = wfs.gd
        self.gd = gd

        # length form ..........................

        # course grid contribution
        # <i|r|j> is the negative of the dipole moment (because of negative
        # e- charge)
        me = -gd.calculate_dipole_moment(self.get())

        # augmentation contributions
        ma = np.zeros(me.shape)
        pos_av = paw.atoms.get_positions() / Bohr
        for a, P_ni in kpt.P_ani.items():
            Ra = pos_av[a]
            Pi_i = P_ni[self.i]
            Pj_i = P_ni[self.j]
            Delta_pL = wfs.setups[a].Delta_pL
            ni = len(Pi_i)
            ma0 = 0
            ma1 = np.zeros(me.shape)
            for i in range(ni):
                for j in range(ni):
                    pij = Pi_i[i] * Pj_i[j]
                    ij = packed_index(i, j, ni)
                    # L=0 term
                    ma0 += Delta_pL[ij, 0] * pij
                    # L=1 terms
                    if wfs.setups[a].lmax >= 1:
                        # see spherical_harmonics.py for
                        # L=1:y L=2:z; L=3:x
                        ma1 += np.array([
                            Delta_pL[ij, 3], Delta_pL[ij, 1], Delta_pL[ij, 2]
                        ]) * pij
            ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0
        gd.comm.sum(ma)

        ##        print '<KSSingle> i,j,me,ma,fac=',self.i,self.j,\
        ##            me, ma,sqrt(self.energy*self.fij)
        #        print 'l: me, ma', me, ma
        self.me = sqrt(self.energy * self.fij) * (me + ma)

        self.mur = -(me + ma)
        ##        print '<KSSingle> mur=',self.mur,-self.fij *me

        # velocity form .............................
        self.muv = np.zeros(me.shape)  # does not work XXX
Esempio n. 15
0
    def __init__(self, iidx=None, jidx=None, pspin=None, kpt=None,
                 paw=None, string=None, fijscale=1):
        
        if string is not None: 
            self.fromstring(string)
            return None

        # normal entry
        
        PairDensity.__init__(self, paw)
        wfs = paw.wfs
        PairDensity.initialize(self, kpt, iidx, jidx)

        self.pspin=pspin
        
        f = kpt.f_n
        self.fij = (f[iidx] - f[jidx]) * fijscale
        e = kpt.eps_n
        self.energy = e[jidx] - e[iidx]

        # calculate matrix elements -----------

        gd = wfs.gd
        self.gd = gd

        # length form ..........................

        # course grid contribution
        # <i|r|j> is the negative of the dipole moment (because of negative
        # e- charge)
        me = - gd.calculate_dipole_moment(self.get())

        # augmentation contributions
        ma = np.zeros(me.shape)
        pos_av = paw.atoms.get_positions() / Bohr
        for a, P_ni in kpt.P_ani.items():
            Ra = pos_av[a]
            Pi_i = P_ni[self.i]
            Pj_i = P_ni[self.j]
            Delta_pL = wfs.setups[a].Delta_pL
            ni=len(Pi_i)
            ma0 = 0
            ma1 = np.zeros(me.shape)
            for i in range(ni):
                for j in range(ni):
                    pij = Pi_i[i]*Pj_i[j]
                    ij = packed_index(i, j, ni)
                    # L=0 term
                    ma0 += Delta_pL[ij,0]*pij
                    # L=1 terms
                    if wfs.setups[a].lmax >= 1:
                        # see spherical_harmonics.py for
                        # L=1:y L=2:z; L=3:x
                        ma1 += np.array([Delta_pL[ij,3], Delta_pL[ij,1],
                                         Delta_pL[ij,2]]) * pij
            ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0
        gd.comm.sum(ma)

        self.me = sqrt(self.energy * self.fij) * ( me + ma )

        self.mur = - ( me + ma )

        # velocity form .............................

        me = np.zeros(self.mur.shape)

        # get derivatives
        dtype = self.wfj.dtype
        dwfj_cg = gd.empty((3), dtype=dtype)
        if not hasattr(gd, 'ddr'):
            gd.ddr = [Gradient(gd, c, dtype=dtype).apply for c in range(3)]
        for c in range(3):
            gd.ddr[c](self.wfj, dwfj_cg[c], kpt.phase_cd)
            me[c] = gd.integrate(self.wfi * dwfj_cg[c])

        if 0:
            me2 = np.zeros(self.mur.shape)
            for c in range(3):
                gd.ddr[c](self.wfi, dwfj_cg[c], kpt.phase_cd)
                me2[c] = gd.integrate(self.wfj * dwfj_cg[c])
            print me, -me2, me2+me

        # augmentation contributions
        ma = np.zeros(me.shape)
        for a, P_ni in kpt.P_ani.items():
            Pi_i = P_ni[self.i]
            Pj_i = P_ni[self.j]
            nabla_iiv = paw.wfs.setups[a].nabla_iiv
            for c in range(3):
                for i1, Pi in enumerate(Pi_i):
                    for i2, Pj in enumerate(Pj_i):
                        ma[c] += Pi * Pj * nabla_iiv[i1, i2, c]
        gd.comm.sum(ma)
        
        self.muv = - (me + ma) / self.energy
##        print self.mur, self.muv, self.mur - self.muv

        # magnetic transition dipole ................

        magn = np.zeros(me.shape)
        r_cg, r2_g = coordinates(gd)

        wfi_g = self.wfi
        for ci in range(3):
            cj = (ci + 1) % 3
            ck = (ci + 2) % 3
            magn[ci] = gd.integrate(wfi_g * r_cg[cj] * dwfj_cg[ck] -
                                    wfi_g * r_cg[ck] * dwfj_cg[cj]  )
        # augmentation contributions
        ma = np.zeros(magn.shape)
        for a, P_ni in kpt.P_ani.items():
            Pi_i = P_ni[self.i]
            Pj_i = P_ni[self.j]
            rnabla_iiv = paw.wfs.setups[a].rnabla_iiv
            for c in range(3):
                for i1, Pi in enumerate(Pi_i):
                    for i2, Pj in enumerate(Pj_i):
                        ma[c] += Pi * Pj * rnabla_iiv[i1, i2, c]
        gd.comm.sum(ma)
        
        self.magn = -alpha / 2. * (magn + ma)
Esempio n. 16
0
    def apply_orbital_dependent_hamiltonian(self, kpt, psit_nG,
                                            Htpsit_nG=None, dH_asp=None):
        if kpt.f_n is None:
            return
        
        deg = 2 // self.nspins   # Spin degeneracy
        hybrid = self.hybrid
        
        P_ani = kpt.P_ani
        setups = self.setups

        vt_g = self.finegd.empty()
        if self.gd is not self.finegd:
            vt_G = self.gd.empty()

        nocc = int(kpt.f_n.sum()) // (3 - self.nspins)
        if self.unocc:
            nbands = len(kpt.f_n)
        else:
            nbands = nocc
        self.nocc_s[kpt.s] = nocc

        if Htpsit_nG is not None:
            kpt.vt_nG = self.gd.empty(nbands)
            kpt.vxx_ani = {}
            kpt.vxx_anii = {}
            for a, P_ni in P_ani.items():
                I = P_ni.shape[1]
                kpt.vxx_ani[a] = np.zeros((nbands, I))
                kpt.vxx_anii[a] = np.zeros((nbands, I, I))

        exx = 0.0
        ekin = 0.0

        # Determine pseudo-exchange
        for n1 in range(nbands):
            psit1_G = psit_nG[n1]
            f1 = kpt.f_n[n1] / deg
            for n2 in range(n1, nbands):
                psit2_G = psit_nG[n2]
                f2 = kpt.f_n[n2] / deg

                # Double count factor:
                dc = (1 + (n1 != n2)) * deg
                
                nt_G, rhot_g = self.calculate_pair_density(n1, n2, psit_nG,
                                                           P_ani)
                vt_g[:] = 0.0
                iter = self.poissonsolver.solve(vt_g, -rhot_g,
                                                charge=-float(n1 == n2),
                                                eps=1e-12,
                                                zero_initial_phi=True)
                vt_g *= hybrid

                if self.gd is self.finegd:
                    vt_G = vt_g
                else:
                    self.restrictor.apply(vt_g, vt_G)

                # Integrate the potential on fine and coarse grids
                int_fine = self.finegd.integrate(vt_g * rhot_g)
                int_coarse = self.gd.integrate(vt_G * nt_G)
                if self.gd.comm.rank == 0:  # only add to energy on master CPU
                    exx += 0.5 * dc * f1 * f2 * int_fine
                    ekin -= dc * f1 * f2 * int_coarse
                if Htpsit_nG is not None:
                    Htpsit_nG[n1] += f2 * vt_G * psit2_G
                    if n1 == n2:
                        kpt.vt_nG[n1] = f1 * vt_G
                    else:
                        Htpsit_nG[n2] += f1 * vt_G * psit1_G

                    # Update the vxx_uni and vxx_unii vectors of the nuclei,
                    # used to determine the atomic hamiltonian, and the 
                    # residuals
                    v_aL = self.ghat.dict()
                    self.ghat.integrate(vt_g, v_aL)
                    for a, v_L in v_aL.items():
                        v_ii = unpack(np.dot(setups[a].Delta_pL, v_L))
                        v_ni = kpt.vxx_ani[a]
                        v_nii = kpt.vxx_anii[a]
                        P_ni = P_ani[a]
                        v_ni[n1] += f2 * np.dot(v_ii, P_ni[n2])
                        if n1 != n2:
                            v_ni[n2] += f1 * np.dot(v_ii, P_ni[n1])
                        else:
                            # XXX Check this:
                            v_nii[n1] = f1 * v_ii

        # Apply the atomic corrections to the energy and the Hamiltonian matrix
        for a, P_ni in P_ani.items():
            setup = setups[a]

            if Htpsit_nG is not None:
                # Add non-trivial corrections the Hamiltonian matrix
                h_nn = symmetrize(np.inner(P_ni[:nbands], 
                                           kpt.vxx_ani[a][:nbands]))
                ekin -= np.dot(kpt.f_n[:nbands], h_nn.diagonal())

                dH_p = dH_asp[a][kpt.s]
            
            # Get atomic density and Hamiltonian matrices
            D_p  = self.density.D_asp[a][kpt.s]
            D_ii = unpack2(D_p)
            ni = len(D_ii)
            
            # Add atomic corrections to the valence-valence exchange energy
            # --
            # >  D   C     D
            # --  ii  iiii  ii
            for i1 in range(ni):
                for i2 in range(ni):
                    A = 0.0
                    for i3 in range(ni):
                        p13 = packed_index(i1, i3, ni)
                        for i4 in range(ni):
                            p24 = packed_index(i2, i4, ni)
                            A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                    p12 = packed_index(i1, i2, ni)
                    if Htpsit_nG is not None:
                        dH_p[p12] -= 2 * hybrid / deg * A / ((i1 != i2) + 1)
                    ekin += 2 * hybrid / deg * D_ii[i1, i2] * A
                    exx -= hybrid / deg * D_ii[i1, i2] * A
            
            # Add valence-core exchange energy
            # --
            # >  X   D
            # --  ii  ii
            if setup.X_p is not None:
                exx -= hybrid * np.dot(D_p, setup.X_p)
                if Htpsit_nG is not None:
                    dH_p -= hybrid * setup.X_p
                    ekin += hybrid * np.dot(D_p, setup.X_p)

                # Add core-core exchange energy
                if kpt.s == 0:
                    exx += hybrid * setup.ExxC

        self.exx_s[kpt.s] = self.gd.comm.sum(exx)
        self.ekin_s[kpt.s] = self.gd.comm.sum(ekin)
Esempio n. 17
0
    def calculate_exx(self):
        """Non-selfconsistent calculation."""

        kd = self.kd
        K = kd.nibzkpts
        W = self.world.size // self.nspins
        parallel = (W > 1)

        self.log("%d CPU's used for %d IBZ k-points" % (W, K))
        self.log('Spins:', self.nspins)

        if self.etotflag and not self.gygi:
            self.nbandstmp = 0
            for s in range(self.nspins):
                kpt1_k = [KPoint(kd, kpt) for kpt in self.kpt_u if kpt.s == s]
                for kpt1 in kpt1_k:
                    for n1 in range(self.bd.nbands):
                        f_n = kpt1.f_n[n1]
                        if np.abs(f_n) < 1e-10:
                            self.nbandstmp = max(self.nbandstmp, n1)
                            break
                    else:
                        self.nbandstmp = self.bd.nbands

            tmp = np.zeros(kd.comm.size, dtype=int)
            kd.comm.all_gather(np.array([self.nbandstmp]), tmp)
            self.nbands = tmp.max()
        else:
            self.nbands = self.bd.nbands

        B = self.nbands
        self.log('Number of bands calculated:', B)
        self.log('Number of valence electrons:', self.setups.nvalence)

        E = B - self.setups.nvalence / 2.0  # empty bands
        self.npairs = (K * kd.nbzkpts - 0.5 * K**2) * (B**2 - E**2)
        self.log('Approximate number of pairs:', self.npairs)

        if not self.etotflag:
            self.exx_skn = np.zeros((self.nspins, K, B))
            self.debug_skn = np.zeros((self.nspins, K, B))

        for s in range(self.nspins):
            kpt1_q = [KPoint(kd, kpt) for kpt in self.kpt_u if kpt.s == s]
            kpt2_q = kpt1_q[:]

            if len(kpt1_q) == 0:
                # No s-spins on this CPU:
                continue

            # Send rank:
            srank = kd.get_rank_and_index(s, (kpt1_q[0].k - 1) % K)[0]
            # Receive rank:
            rrank = kd.get_rank_and_index(s, (kpt1_q[-1].k + 1) % K)[0]

            # Shift k-points K - 1 times:
            for i in range(K):
                if i < K - 1:
                    if parallel:
                        kpt = kpt2_q[-1].next()
                        kpt.start_receiving(rrank)
                        kpt2_q[0].start_sending(srank)
                    else:
                        kpt = kpt2_q[0]

                for kpt1, kpt2 in zip(kpt1_q, kpt2_q):
                    for k, ik in enumerate(kd.bz2ibz_k):
                        if ik == kpt2.k:
                            self.apply(kpt1, kpt2, k)

                if i < K - 1:
                    if parallel:
                        kpt.wait()
                        kpt2_q[0].wait()
                    kpt2_q.pop(0)
                    kpt2_q.append(kpt)

        if self.etotflag:
            if self.acdf:
                self.exxacdf = self.world.sum(self.exxacdf[0])
                self.exx = self.exxacdf
            else:
                self.exx = self.world.sum(self.exx)
            self.exx += self.calculate_exx_paw_correction()

        else:
            for kpt in self.kpt_u:
                for a, D_sp in self.density.D_asp.items():
                    setup = self.setups[a]
                    for D_p in D_sp:
                        D_ii = unpack2(D_p)
                        ni = len(D_ii)
                        P_ni = kpt.P_ani[a]
                        for i1 in range(ni):
                            for i2 in range(ni):
                                A = 0.0
                                for i3 in range(ni):
                                    p13 = packed_index(i1, i3, ni)
                                    for i4 in range(ni):
                                        p24 = packed_index(i2, i4, ni)
                                        A += setup.M_pp[p13, p24] * D_ii[i3,
                                                                         i4]
                                self.exx_skn[kpt.s, kpt.k] -= \
                                    (self.hybrid * A *
                                     P_ni[:, i1].conj() * P_ni[:, i2]).real

                                p12 = packed_index(i1, i2, ni)
                                if self.core_valence:
                                    if setup.X_p is not None:
                                        self.exx_skn[kpt.s, kpt.k] -= self.hybrid * \
                                                                      (P_ni[:, i1].conj() * setup.X_p[p12] *
                                                                       P_ni[:, i2]).real / self.nspins

            self.world.sum(self.exx_skn)
            self.exx = 0.0
            for kpt in self.kpt_u:
                self.exx += 0.5 * np.dot(kpt.f_n, self.exx_skn[kpt.s, kpt.k])
            self.exx = self.world.sum(self.exx)

            for a, D_sp in self.density.D_asp.items():
                setup = self.setups[a]
                if self.coredensity:
                    self.exx += self.hybrid * setup.ExxC
                if self.core_valence:
                    self.exx -= self.hybrid * 0.5 * np.dot(
                        D_sp.sum(0), setup.X_p)

            self.world.sum(self.debug_skn)
            assert (self.debug_skn == self.kd.nbzkpts * B).all()
Esempio n. 18
0
    def apply_orbital_dependent_hamiltonian(self,
                                            kpt,
                                            psit_nG,
                                            Htpsit_nG=None,
                                            dH_asp=None):
        if kpt.f_n is None:
            return

        deg = 2 // self.nspins  # Spin degeneracy
        hybrid = self.hybrid

        P_ani = kpt.P_ani
        setups = self.setups

        vt_g = self.finegd.empty()
        if self.gd is not self.finegd:
            vt_G = self.gd.empty()

        nocc = int(kpt.f_n.sum()) // (3 - self.nspins)
        if self.unocc:
            nbands = len(kpt.f_n)
        else:
            nbands = nocc
        self.nocc_s[kpt.s] = nocc

        if Htpsit_nG is not None:
            kpt.vt_nG = self.gd.empty(nbands)
            kpt.vxx_ani = {}
            kpt.vxx_anii = {}
            for a, P_ni in P_ani.items():
                I = P_ni.shape[1]
                kpt.vxx_ani[a] = np.zeros((nbands, I))
                kpt.vxx_anii[a] = np.zeros((nbands, I, I))

        exx = 0.0
        ekin = 0.0

        # Determine pseudo-exchange
        for n1 in range(nbands):
            psit1_G = psit_nG[n1]
            f1 = kpt.f_n[n1] / deg
            for n2 in range(n1, nbands):
                psit2_G = psit_nG[n2]
                f2 = kpt.f_n[n2] / deg

                # Double count factor:
                dc = (1 + (n1 != n2)) * deg

                nt_G, rhot_g = self.calculate_pair_density(
                    n1, n2, psit_nG, P_ani)
                vt_g[:] = 0.0
                iter = self.poissonsolver.solve(vt_g,
                                                -rhot_g,
                                                charge=-float(n1 == n2),
                                                eps=1e-12,
                                                zero_initial_phi=True)
                vt_g *= hybrid

                if self.gd is self.finegd:
                    vt_G = vt_g
                else:
                    self.restrictor.apply(vt_g, vt_G)

                # Integrate the potential on fine and coarse grids
                int_fine = self.finegd.integrate(vt_g * rhot_g)
                int_coarse = self.gd.integrate(vt_G * nt_G)
                if self.gd.comm.rank == 0:  # only add to energy on master CPU
                    exx += 0.5 * dc * f1 * f2 * int_fine
                    ekin -= dc * f1 * f2 * int_coarse
                if Htpsit_nG is not None:
                    Htpsit_nG[n1] += f2 * vt_G * psit2_G
                    if n1 == n2:
                        kpt.vt_nG[n1] = f1 * vt_G
                    else:
                        Htpsit_nG[n2] += f1 * vt_G * psit1_G

                    # Update the vxx_uni and vxx_unii vectors of the nuclei,
                    # used to determine the atomic hamiltonian, and the
                    # residuals
                    v_aL = self.ghat.dict()
                    self.ghat.integrate(vt_g, v_aL)
                    for a, v_L in v_aL.items():
                        v_ii = unpack(np.dot(setups[a].Delta_pL, v_L))
                        v_ni = kpt.vxx_ani[a]
                        v_nii = kpt.vxx_anii[a]
                        P_ni = P_ani[a]
                        v_ni[n1] += f2 * np.dot(v_ii, P_ni[n2])
                        if n1 != n2:
                            v_ni[n2] += f1 * np.dot(v_ii, P_ni[n1])
                        else:
                            # XXX Check this:
                            v_nii[n1] = f1 * v_ii

        # Apply the atomic corrections to the energy and the Hamiltonian matrix
        for a, P_ni in P_ani.items():
            setup = setups[a]

            if Htpsit_nG is not None:
                # Add non-trivial corrections the Hamiltonian matrix
                h_nn = symmetrize(
                    np.inner(P_ni[:nbands], kpt.vxx_ani[a][:nbands]))
                ekin -= np.dot(kpt.f_n[:nbands], h_nn.diagonal())

                dH_p = dH_asp[a][kpt.s]

            # Get atomic density and Hamiltonian matrices
            D_p = self.density.D_asp[a][kpt.s]
            D_ii = unpack2(D_p)
            ni = len(D_ii)

            # Add atomic corrections to the valence-valence exchange energy
            # --
            # >  D   C     D
            # --  ii  iiii  ii
            for i1 in range(ni):
                for i2 in range(ni):
                    A = 0.0
                    for i3 in range(ni):
                        p13 = packed_index(i1, i3, ni)
                        for i4 in range(ni):
                            p24 = packed_index(i2, i4, ni)
                            A += setup.M_pp[p13, p24] * D_ii[i3, i4]
                    p12 = packed_index(i1, i2, ni)
                    if Htpsit_nG is not None:
                        dH_p[p12] -= 2 * hybrid / deg * A / ((i1 != i2) + 1)
                    ekin += 2 * hybrid / deg * D_ii[i1, i2] * A
                    exx -= hybrid / deg * D_ii[i1, i2] * A

            # Add valence-core exchange energy
            # --
            # >  X   D
            # --  ii  ii
            if setup.X_p is not None:
                exx -= hybrid * np.dot(D_p, setup.X_p)
                if Htpsit_nG is not None:
                    dH_p -= hybrid * setup.X_p
                    ekin += hybrid * np.dot(D_p, setup.X_p)

                # Add core-core exchange energy
                if kpt.s == 0:
                    exx += hybrid * setup.ExxC

        self.exx_s[kpt.s] = self.gd.comm.sum(exx)
        self.ekin_s[kpt.s] = self.gd.comm.sum(ekin)
Esempio n. 19
0
    def __init__(self,
                 iidx=None,
                 jidx=None,
                 pspin=None,
                 kpt=None,
                 paw=None,
                 string=None,
                 fijscale=1,
                 dtype=float):

        if string is not None:
            self.fromstring(string, dtype)
            return None

        # normal entry

        PairDensity.__init__(self, paw)
        PairDensity.initialize(self, kpt, iidx, jidx)

        self.pspin = pspin

        self.energy = 0.0
        self.fij = 0.0

        self.me = np.zeros((3), dtype=dtype)
        self.mur = np.zeros((3), dtype=dtype)
        self.muv = np.zeros((3), dtype=dtype)
        self.magn = np.zeros((3), dtype=dtype)

        self.kpt_comm = paw.wfs.kd.comm

        # leave empty if not my kpt
        if kpt is None:
            return

        wfs = paw.wfs
        gd = wfs.gd

        self.energy = kpt.eps_n[jidx] - kpt.eps_n[iidx]
        self.fij = (kpt.f_n[iidx] - kpt.f_n[jidx]) * fijscale

        # calculate matrix elements -----------

        # length form ..........................

        # course grid contribution
        # <i|r|j> is the negative of the dipole moment (because of negative
        # e- charge)
        me = -gd.calculate_dipole_moment(self.get())

        # augmentation contributions
        ma = np.zeros(me.shape, dtype=dtype)
        pos_av = paw.atoms.get_positions() / Bohr
        for a, P_ni in kpt.P_ani.items():
            Ra = pos_av[a]
            Pi_i = P_ni[self.i].conj()
            Pj_i = P_ni[self.j]
            Delta_pL = wfs.setups[a].Delta_pL
            ni = len(Pi_i)
            ma0 = 0
            ma1 = np.zeros(me.shape, dtype=me.dtype)
            for i in range(ni):
                for j in range(ni):
                    pij = Pi_i[i] * Pj_i[j]
                    ij = packed_index(i, j, ni)
                    # L=0 term
                    ma0 += Delta_pL[ij, 0] * pij
                    # L=1 terms
                    if wfs.setups[a].lmax >= 1:
                        # see spherical_harmonics.py for
                        # L=1:y L=2:z; L=3:x
                        ma1 += np.array([
                            Delta_pL[ij, 3], Delta_pL[ij, 1], Delta_pL[ij, 2]
                        ]) * pij
            ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0
        gd.comm.sum(ma)

        self.me = sqrt(self.energy * self.fij) * (me + ma)
        self.mur = -(me + ma)

        # velocity form .............................

        if self.lcao:
            # XXX Velocity form not supported in LCAO
            return

        me = np.zeros(self.mur.shape, dtype=dtype)

        # get derivatives
        dtype = self.wfj.dtype
        dwfj_cg = gd.empty((3), dtype=dtype)
        if not hasattr(gd, 'ddr'):
            gd.ddr = [Gradient(gd, c, dtype=dtype).apply for c in range(3)]
        for c in range(3):
            gd.ddr[c](self.wfj, dwfj_cg[c], kpt.phase_cd)
            me[c] = gd.integrate(self.wfi.conj() * dwfj_cg[c])

        if 0:
            me2 = np.zeros(self.mur.shape)
            for c in range(3):
                gd.ddr[c](self.wfi, dwfj_cg[c], kpt.phase_cd)
                me2[c] = gd.integrate(self.wfj * dwfj_cg[c])
            print(me, -me2, me2 + me)

        # augmentation contributions
        ma = np.zeros(me.shape, dtype=me.dtype)
        for a, P_ni in kpt.P_ani.items():
            Pi_i = P_ni[self.i].conj()
            Pj_i = P_ni[self.j]
            nabla_iiv = paw.wfs.setups[a].nabla_iiv
            for c in range(3):
                for i1, Pi in enumerate(Pi_i):
                    for i2, Pj in enumerate(Pj_i):
                        ma[c] += Pi * Pj * nabla_iiv[i1, i2, c]
        gd.comm.sum(ma)

        self.muv = -(me + ma) / self.energy

        # magnetic transition dipole ................

        r_cg, r2_g = coordinates(gd)
        magn = np.zeros(me.shape, dtype=dtype)

        wfi_g = self.wfi.conj()
        for ci in range(3):
            cj = (ci + 1) % 3
            ck = (ci + 2) % 3
            magn[ci] = gd.integrate(wfi_g * r_cg[cj] * dwfj_cg[ck] -
                                    wfi_g * r_cg[ck] * dwfj_cg[cj])
        # augmentation contributions
        ma = np.zeros(magn.shape, dtype=magn.dtype)
        for a, P_ni in kpt.P_ani.items():
            Pi_i = P_ni[self.i].conj()
            Pj_i = P_ni[self.j]
            rnabla_iiv = paw.wfs.setups[a].rnabla_iiv
            for c in range(3):
                for i1, Pi in enumerate(Pi_i):
                    for i2, Pj in enumerate(Pj_i):
                        ma[c] += Pi * Pj * rnabla_iiv[i1, i2, c]
        gd.comm.sum(ma)

        self.magn = -alpha / 2. * (magn + ma)