Example #1
0
 def poisson(self, n_g, l=0):  # Old C version
     vr_g = self.zeros()
     nrdr_g = n_g * self.r_g * self.dr_g
     beta = self.a / self.b
     ng = int(round(1.0 / self.b))
     assert abs(ng - 1 / self.b) < 1e-5
     hartree(l, nrdr_g, beta, ng, vr_g)
     #vrp_g = self.purepythonpoisson(n_g,l)
     #assert abs(vr_g-vrp_g).max() < 1e-12
     return vr_g
Example #2
0
def atomic_exact_exchange(atom, type='all'):
    """Returns the exact exchange energy of the atom defined by the
       instantiated AllElectron object 'atom'
    """
    G_LLL = gaunt(lmax=max(atom.l_j))  # Make gaunt coeff. list
    Nj = len(atom.n_j)  # The total number of orbitals

    # determine relevant states for chosen type of exchange contribution
    if type == 'all':
        nstates = mstates = range(Nj)
    else:
        Njcore = core_states(atom.symbol)  # The number of core orbitals
        if type == 'val-val':
            nstates = mstates = range(Njcore, Nj)
        elif type == 'core-core':
            nstates = mstates = range(Njcore)
        elif type == 'val-core':
            nstates = range(Njcore, Nj)
            mstates = range(Njcore)
        else:
            raise RuntimeError('Unknown type of exchange: ', type)

    # Arrays for storing the potential (times radius)
    vr = np.zeros(atom.N)
    vrl = np.zeros(atom.N)

    # do actual calculation of exchange contribution
    Exx = 0.0
    for j1 in nstates:
        # angular momentum of first state
        l1 = atom.l_j[j1]

        for j2 in mstates:
            # angular momentum of second state
            l2 = atom.l_j[j2]

            # joint occupation number
            f12 = 0.5 * (atom.f_j[j1] / (2. * l1 + 1) * atom.f_j[j2] /
                         (2. * l2 + 1))

            # electron density times radius times length element
            nrdr = atom.u_j[j1] * atom.u_j[j2] * atom.dr
            nrdr[1:] /= atom.r[1:]

            # potential times radius
            vr[:] = 0.0

            # L summation
            for l in range(l1 + l2 + 1):
                # get potential for current l-value
                hartree(l, nrdr, atom.r, vrl)

                # take all m1 m2 and m values of Gaunt matrix of the form
                # G(L1,L2,L) where L = {l,m}
                G2 = G_LLL[l1**2:(l1 + 1)**2, l2**2:(l2 + 1)**2,
                           l**2:(l + 1)**2]**2

                # add to total potential
                vr += vrl * np.sum(G2)

            # add to total exchange the contribution from current two states
            Exx += -.5 * f12 * np.dot(vr, nrdr)

    # double energy if mixed contribution
    if type == 'val-core':
        Exx *= 2.

    # return exchange energy
    return Exx
Example #3
0
def constructX(gen):
    """Construct the X_p^a matrix for the given atom.

    The X_p^a matrix describes the valence-core interactions of the
    partial waves.
    """
    # initialize attributes
    uv_j = gen.vu_j    # soft valence states * r:
    lv_j = gen.vl_j    # their repective l quantum numbers
    Nvi  = 0 
    for l in lv_j:
        Nvi += 2 * l + 1   # total number of valence states (including m)

    # number of core and valence orbitals (j only, i.e. not m-number)
    Njcore = gen.njcore
    Njval  = len(lv_j)

    # core states * r:
    uc_j = gen.u_j[:Njcore]
    r, dr, N, beta = gen.r, gen.dr, gen.N, gen.beta

    # potential times radius
    vr = np.zeros(N)
        
    # initialize X_ii matrix
    X_ii = np.zeros((Nvi, Nvi))

    # make gaunt coeff. list
    lmax = max(gen.l_j[:Njcore] + gen.vl_j)
    gaunt = make_gaunt(lmax=lmax)

    # sum over core states
    for jc in range(Njcore):
        lc = gen.l_j[jc]

        # sum over first valence state index
        i1 = 0
        for jv1 in range(Njval):
            lv1 = lv_j[jv1] 

            # electron density 1 times radius times length element
            n1c = uv_j[jv1] * uc_j[jc] * dr
            n1c[1:] /= r[1:]

            # sum over second valence state index
            i2 = 0
            for jv2 in range(Njval):
                lv2 = lv_j[jv2]
                
                # electron density 2
                n2c = uv_j[jv2] * uc_j[jc] * dr
                n2c[1:] /= r[1:]
            
                # sum expansion in angular momenta
                for l in range(min(lv1, lv2) + lc + 1):
                    # Int density * potential * r^2 * dr:
                    hartree(l, n2c, beta, N, vr)
                    nv = np.dot(n1c, vr)
                    
                    # expansion coefficients
                    A_mm = X_ii[i1:i1 + 2 * lv1 + 1, i2:i2 + 2 * lv2 + 1]
                    for mc in range(2 * lc + 1):
                        for m in range(2 * l + 1):
                            G1c = gaunt[lv1**2:(lv1 + 1)**2,
                                        lc**2 + mc, l**2 + m]
                            G2c = gaunt[lv2**2:(lv2 + 1)**2,
                                        lc**2 + mc, l**2 + m]
                            A_mm += nv * np.outer(G1c, G2c)
                i2 += 2 * lv2 + 1
            i1 += 2 * lv1 + 1

    # pack X_ii matrix
    X_p = pack2(X_ii)
    return X_p
Example #4
0
def atomic_exact_exchange(atom, type = 'all'):
    """Returns the exact exchange energy of the atom defined by the
       instantiated AllElectron object 'atom'
    """
    gaunt = make_gaunt(lmax=max(atom.l_j)) # Make gaunt coeff. list
    Nj = len(atom.n_j)                     # The total number of orbitals

    # determine relevant states for chosen type of exchange contribution
    if type == 'all':
        nstates = mstates = range(Nj)
    else:
        Njcore = core_states(atom.symbol) # The number of core orbitals
        if type == 'val-val':
            nstates = mstates = range(Njcore, Nj)
        elif type == 'core-core':
            nstates = mstates = range(Njcore)
        elif type == 'val-core':
            nstates = range(Njcore,Nj)
            mstates = range(Njcore)
        else:
            raise RuntimeError('Unknown type of exchange: ', type)

    # Arrays for storing the potential (times radius)
    vr = np.zeros(atom.N)
    vrl = np.zeros(atom.N)
    
    # do actual calculation of exchange contribution
    Exx = 0.0
    for j1 in nstates:
        # angular momentum of first state
        l1 = atom.l_j[j1]

        for j2 in mstates:
            # angular momentum of second state
            l2 = atom.l_j[j2]

            # joint occupation number
            f12 = .5 * atom.f_j[j1] / (2. * l1 + 1) * \
                       atom.f_j[j2] / (2. * l2 + 1)

            # electron density times radius times length element
            nrdr = atom.u_j[j1] * atom.u_j[j2] * atom.dr
            nrdr[1:] /= atom.r[1:]

            # potential times radius
            vr[:] = 0.0

            # L summation
            for l in range(l1 + l2 + 1):
                # get potential for current l-value
                hartree(l, nrdr, atom.beta, atom.N, vrl)

                # take all m1 m2 and m values of Gaunt matrix of the form
                # G(L1,L2,L) where L = {l,m}
                G2 = gaunt[l1**2:(l1+1)**2, l2**2:(l2+1)**2, l**2:(l+1)**2]**2

                # add to total potential
                vr += vrl * np.sum(G2)

            # add to total exchange the contribution from current two states
            Exx += -.5 * f12 * np.dot(vr, nrdr)

    # double energy if mixed contribution
    if type == 'val-core': Exx *= 2.

    # return exchange energy
    return Exx
Example #5
0
 def poisson(self, n_g, l=0):
     vr_g = self.zeros()
     nrdr_g = n_g * self.r_g * self.dr_g
     hartree(l, nrdr_g, self.r_g, vr_g)
     return vr_g
Example #6
0
    def run(self, core='', rcut=1.0, extra=None,
            logderiv=False, vbar=None, exx=False, name=None,
            normconserving='', filter=(0.4, 1.75), rcutcomp=None,
            write_xml=True, use_restart_file=True,
            empty_states=''):

        self.name = name

        self.core = core
        if type(rcut) is float:
            rcut_l = [rcut]
        else:
            rcut_l = rcut
        rcutmax = max(rcut_l)
        rcutmin = min(rcut_l)
        self.rcut_l = rcut_l

        if rcutcomp is None:
            rcutcomp = rcutmin
        self.rcutcomp = rcutcomp

        hfilter, xfilter = filter

        Z = self.Z

        n_j = self.n_j
        l_j = self.l_j
        f_j = self.f_j
        e_j = self.e_j

        if vbar is None:
            vbar = ('poly', rcutmin * 0.9)
        vbar_type, rcutvbar = vbar

        normconserving_l = [x in normconserving for x in 'spdf']

        # Parse core string:
        j = 0
        if core.startswith('['):
            a, core = core.split(']')
            core_symbol = a[1:]
            j = len(configurations[core_symbol][1])

        while core != '':
            assert n_j[j] == int(core[0])
            assert l_j[j] == 'spdf'.find(core[1])
            if j != self.jcorehole:
                assert f_j[j] == 2 * (2 * l_j[j] + 1)
            j += 1
            core = core[2:]

        njcore = j
        self.njcore = njcore

        lmaxocc = max(l_j[njcore:])

        while empty_states != '':
            n = int(empty_states[0])
            l = 'spdf'.find(empty_states[1])
            assert n == 1 + l + l_j.count(l)
            n_j.append(n)
            l_j.append(l)
            f_j.append(0.0)
            e_j.append(-0.01)
            empty_states = empty_states[2:]
            
        if 2 in l_j[njcore:]:
            # We have a bound valence d-state.  Add bound s- and
            # p-states if not already there:
            for l in [0, 1]:
                if l not in l_j[njcore:]:
                    n_j.append(1 + l + l_j.count(l))
                    l_j.append(l)
                    f_j.append(0.0)
                    e_j.append(-0.01)

        if l_j[njcore:] == [0] and Z > 2:
            # We have only a bound valence s-state and we are not
            # hydrogen and not helium.  Add bound p-state:
            n_j.append(n_j[njcore])
            l_j.append(1)
            f_j.append(0.0)
            e_j.append(-0.01)

        nj = len(n_j)

        self.Nv = sum(f_j[njcore:])
        self.Nc = sum(f_j[:njcore])

        # Do all-electron calculation:
        AllElectron.run(self, use_restart_file)

        # Highest occupied atomic orbital:
        self.emax = max(e_j)

        N = self.N
        r = self.r
        dr = self.dr
        d2gdr2 = self.d2gdr2
        beta = self.beta

        dv = r**2 * dr

        t = self.text
        t()
        t('Generating PAW setup')
        if core != '':
            t('Frozen core:', core)

        # So far - no ghost-states:
        self.ghost = False

        # Calculate the kinetic energy of the core states:
        Ekincore = 0.0
        j = 0
        for f, e, u in zip(f_j[:njcore], e_j[:njcore], self.u_j[:njcore]):
            u = np.where(abs(u) < 1e-160, 0, u)  # XXX Numeric!
            k = e - np.sum((u**2 * self.vr * dr)[1:] / r[1:])
            Ekincore += f * k
            if j == self.jcorehole:
                self.Ekincorehole = k
            j += 1

        # Calculate core density:
        if njcore == 0:
            nc = np.zeros(N)
        else:
            uc_j = self.u_j[:njcore]
            uc_j = np.where(abs(uc_j) < 1e-160, 0, uc_j)  # XXX Numeric!
            nc = np.dot(f_j[:njcore], uc_j**2) / (4 * pi)
            nc[1:] /= r[1:]**2
            nc[0] = nc[1]

        self.nc = nc

        # Calculate core kinetic energy density
        if njcore == 0:
            tauc = np.zeros(N)
        else:
            tauc = self.radial_kinetic_energy_density(f_j[:njcore],
                                                      l_j[:njcore],
                                                      self.u_j[:njcore])
            t('Kinetic energy of the core from tauc =',
              np.dot(tauc * r * r, dr) * 4 * pi)

        lmax = max(l_j[njcore:])

        # Order valence states with respect to angular momentum
        # quantum number:
        self.n_ln = n_ln = []
        self.f_ln = f_ln = []
        self.e_ln = e_ln = []
        for l in range(lmax + 1):
            n_n = []
            f_n = []
            e_n = []
            for j in range(njcore, nj):
                if l_j[j] == l:
                    n_n.append(n_j[j])
                    f_n.append(f_j[j])
                    e_n.append(e_j[j])
            n_ln.append(n_n)
            f_ln.append(f_n)
            e_ln.append(e_n)

        # Add extra projectors:
        if extra is not None:
            if len(extra) == 0:
                lmaxextra = 0
            else:
                lmaxextra = max(extra.keys())
            if lmaxextra > lmax:
                for l in range(lmax, lmaxextra):
                    n_ln.append([])
                    f_ln.append([])
                    e_ln.append([])
                lmax = lmaxextra
            for l in extra:
                nn = -1
                for e in extra[l]:
                    n_ln[l].append(nn)
                    f_ln[l].append(0.0)
                    e_ln[l].append(e)
                    nn -= 1
        else:
            # Automatic:

            # Make sure we have two projectors for each occupied channel:
            for l in range(lmaxocc + 1):
                if len(n_ln[l]) < 2 and not normconserving_l[l]:
                    # Only one - add one more:
                    assert len(n_ln[l]) == 1
                    n_ln[l].append(-1)
                    f_ln[l].append(0.0)
                    e_ln[l].append(1.0 + e_ln[l][0])

            if lmaxocc < 2 and lmaxocc == lmax:
                # Add extra projector for l = lmax + 1:
                n_ln.append([-1])
                f_ln.append([0.0])
                e_ln.append([0.0])
                lmax += 1

        self.lmax = lmax

        rcut_l.extend([rcutmin] * (lmax + 1 - len(rcut_l)))

        t('Cutoffs:')
        for rc, s in zip(rcut_l, 'spdf'):
            t('rc(%s)=%.3f' % (s, rc))
        t('rc(vbar)=%.3f' % rcutvbar)
        t('rc(comp)=%.3f' % rcutcomp)
        t('rc(nct)=%.3f' % rcutmax)
        t()
        t('Kinetic energy of the core states: %.6f' % Ekincore)

        # Allocate arrays:
        self.u_ln = u_ln = []  # phi * r
        self.s_ln = s_ln = []  # phi-tilde * r
        self.q_ln = q_ln = []  # p-tilde * r
        for l in range(lmax + 1):
            nn = len(n_ln[l])
            u_ln.append(np.zeros((nn, N)))
            s_ln.append(np.zeros((nn, N)))
            q_ln.append(np.zeros((nn, N)))

        # Fill in all-electron wave functions:
        for l in range(lmax + 1):
            # Collect all-electron wave functions:
            u_n = [self.u_j[j] for j in range(njcore, nj) if l_j[j] == l]
            for n, u in enumerate(u_n):
                u_ln[l][n] = u

        # Grid-index corresponding to rcut:
        gcut_l = [1 + int(rc * N / (rc + beta)) for rc in rcut_l]

        rcutfilter = xfilter * rcutmax
        self.rcutfilter = rcutfilter
        gcutfilter = 1 + int(rcutfilter * N / (rcutfilter + beta))
        gcutmax = 1 + int(rcutmax * N / (rcutmax + beta))

        # Outward integration of unbound states stops at 3 * rcut:
        gmax = int(3 * rcutmax * N / (3 * rcutmax + beta))
        assert gmax > gcutfilter

        # Calculate unbound extra states:
        c2 = -(r / dr)**2
        c10 = -d2gdr2 * r**2
        for l, (n_n, e_n, u_n) in enumerate(zip(n_ln, e_ln, u_ln)):
            for n, e, u in zip(n_n, e_n, u_n):
                if n < 0:
                    u[:] = 0.0
                    shoot(u, l, self.vr, e, self.r2dvdr, r, dr, c10, c2,
                          self.scalarrel, gmax=gmax)
                    u *= 1.0 / u[gcut_l[l]]

        charge = Z - self.Nv - self.Nc
        t('Charge: %.1f' % charge)
        t('Core electrons: %.1f' % self.Nc)
        t('Valence electrons: %.1f' % self.Nv)

        # Construct smooth wave functions:
        coefs = []
        for l, (u_n, s_n) in enumerate(zip(u_ln, s_ln)):
            nodeless = True
            gc = gcut_l[l]
            for u, s in zip(u_n, s_n):
                s[:] = u
                if normconserving_l[l]:
                    A = np.zeros((5, 5))
                    A[:4, 0] = 1.0
                    A[:4, 1] = r[gc - 2:gc + 2]**2
                    A[:4, 2] = A[:4, 1]**2
                    A[:4, 3] = A[:4, 1] * A[:4, 2]
                    A[:4, 4] = A[:4, 2]**2
                    A[4, 4] = 1.0
                    a = u[gc - 2:gc + 3] / r[gc - 2:gc + 3]**(l + 1)
                    a = np.log(a)
                    def f(x):
                        a[4] = x
                        b = solve(A, a)
                        r1 = r[:gc]
                        r2 = r1**2
                        rl1 = r1**(l + 1)
                        y = b[0] + r2 * (b[1] + r2 * (b[2] + r2 * (b[3] + r2
                                                                   * b[4])))
                        y = np.exp(y)
                        s[:gc] = rl1 * y
                        return np.dot(s**2, dr) - 1
                    x1 = 0.0
                    x2 = 0.001
                    f1 = f(x1)
                    f2 = f(x2)
                    while abs(f1) > 1e-6:
                        x0 = (x1 / f1 - x2 / f2) / (1 / f1 - 1 / f2)
                        f0 = f(x0)
                        if abs(f1) < abs(f2):
                            x2, f2 = x1, f1
                        x1, f1 = x0, f0

                else:
                    A = np.ones((4, 4))
                    A[:, 0] = 1.0
                    A[:, 1] = r[gc - 2:gc + 2]**2
                    A[:, 2] = A[:, 1]**2
                    A[:, 3] = A[:, 1] * A[:, 2]
                    a = u[gc - 2:gc + 2] / r[gc - 2:gc + 2]**(l + 1)
                    if 0:#l < 2 and nodeless:
                        a = np.log(a)
                    a = solve(A, a)
                    r1 = r[:gc]
                    r2 = r1**2
                    rl1 = r1**(l + 1)
                    y = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * (a[3])))
                    if 0:#l < 2 and nodeless:
                        y = np.exp(y)
                    s[:gc] = rl1 * y

                coefs.append(a)
                if nodeless:
                    if not np.alltrue(s[1:gc] > 0.0):
                        raise RuntimeError(
                            'Error: The %d%s pseudo wave has a node!' %
                            (n_ln[l][0], 'spdf'[l]))
                    # Only the first state for each l must be nodeless:
                    nodeless = False

        # Calculate pseudo core density:
        gcutnc = 1 + int(rcutmax * N / (rcutmax + beta))
        self.nct = nct = nc.copy()
        A = np.ones((4, 4))
        A[0] = 1.0
        A[1] = r[gcutnc - 2:gcutnc + 2]**2
        A[2] = A[1]**2
        A[3] = A[1] * A[2]
        a = nc[gcutnc - 2:gcutnc + 2]
        a = solve(np.transpose(A), a)
        r2 = r[:gcutnc]**2
        nct[:gcutnc] = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * a[3]))
        t('Pseudo-core charge: %.6f' % (4 * pi * np.dot(nct, dv)))

        # ... and the pseudo core kinetic energy density:
        tauct = tauc.copy()
        a = tauc[gcutnc - 2:gcutnc + 2]
        a = solve(np.transpose(A), a)
        tauct[:gcutnc] = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * a[3]))

        # ... and the soft valence density:
        nt = np.zeros(N)
        for f_n, s_n in zip(f_ln, s_ln):
            nt += np.dot(f_n, s_n**2) / (4 * pi)
        nt[1:] /= r[1:]**2
        nt[0] = nt[1]
        nt += nct
        self.nt = nt

        # Calculate the shape function:
        x = r / rcutcomp
        gaussian = np.zeros(N)
        self.gamma = gamma = 10.0
        gaussian[:gmax] = np.exp(-gamma * x[:gmax]**2)
        gt = 4 * (gamma / rcutcomp**2)**1.5 / sqrt(pi) * gaussian
        t('Shape function alpha=%.3f' % (gamma / rcutcomp**2))
        norm = np.dot(gt, dv)
        #print norm, norm-1
        assert abs(norm - 1) < 1e-2
        gt /= norm


        # Calculate smooth charge density:
        Nt = np.dot(nt, dv)
        rhot = nt - (Nt + charge / (4 * pi)) * gt
        t('Pseudo-electron charge', 4 * pi * Nt)

        vHt = np.zeros(N)
        hartree(0, rhot * r * dr, self.beta, self.N, vHt)
        vHt[1:] /= r[1:]
        vHt[0] = vHt[1]

        vXCt = np.zeros(N)

        extra_xc_data = {}

        if self.xc.type != 'GLLB':
            Exct = self.xc.calculate_spherical(self.rgd,
                                               nt.reshape((1, -1)),
                                               vXCt.reshape((1, -1)))
        else:
            Exct = self.xc.get_smooth_xc_potential_and_energy_1d(vXCt)

            # Calculate extra-stuff for non-local functionals
            self.xc.get_extra_setup_data(extra_xc_data)

        vt = vHt + vXCt

        # Construct zero potential:
        gc = 1 + int(rcutvbar * N / (rcutvbar + beta))
        if vbar_type == 'f':
            assert lmax == 2
            uf = np.zeros(N)
            l = 3

            # Solve for all-electron f-state:
            eps = 0.0
            shoot(uf, l, self.vr, eps, self.r2dvdr, r, dr, c10, c2,
                  self.scalarrel, gmax=gmax)
            uf *= 1.0 / uf[gc]

            # Fit smooth pseudo f-state polynomium:
            A = np.ones((4, 4))
            A[:, 0] = 1.0
            A[:, 1] = r[gc - 2:gc + 2]**2
            A[:, 2] = A[:, 1]**2
            A[:, 3] = A[:, 1] * A[:, 2]
            a = uf[gc - 2:gc + 2] / r[gc - 2:gc + 2]**(l + 1)
            a0, a1, a2, a3 = solve(A, a)
            r1 = r[:gc]
            r2 = r1**2
            rl1 = r1**(l + 1)
            y = a0 + r2 * (a1 + r2 * (a2 + r2 * a3))
            sf = uf.copy()
            sf[:gc] = rl1 * y

            # From 0 to gc, use analytic formula for kinetic energy operator:
            r4 = r2**2
            r6 = r4 * r2
            enumerator = (a0 * l * (l + 1) +
                          a1 * (l + 2) * (l + 3) * r2 +
                          a2 * (l + 4) * (l + 5) * r4 +
                          a3 * (l + 6) * (l + 7) * r6)
            denominator = a0 + a1 * r2 + a2 * r4 + a3 * r6            
            ekin_over_phit = - 0.5 * (enumerator / denominator - l * (l + 1))
            ekin_over_phit[1:] /= r2[1:]

            vbar = eps - vt
            vbar[:gc] -= ekin_over_phit
            vbar[0] = vbar[1] # Actually we can collect the terms into
            # a single fraction without poles, so as to avoid doing this,
            # but this is good enough

            # From gc to gmax, use finite-difference formula for kinetic
            # energy operator:
            vbar[gc:gmax] -= self.kin(l, sf)[gc:gmax] / sf[gc:gmax]
            vbar[gmax:] = 0.0
        else:
            assert vbar_type == 'poly'
            A = np.ones((2, 2))
            A[0] = 1.0
            A[1] = r[gc - 1:gc + 1]**2
            a = vt[gc - 1:gc + 1]
            a = solve(np.transpose(A), a)
            r2 = r**2
            vbar = a[0] + r2 * a[1] - vt
            vbar[gc:] = 0.0

        vt += vbar

        # Construct projector functions:
        for l, (e_n, s_n, q_n) in enumerate(zip(e_ln, s_ln, q_ln)):
            for e, s, q in zip(e_n, s_n, q_n):
                q[:] = self.kin(l, s) + (vt - e) * s
                q[gcutmax:] = 0.0

        filter = Filter(r, dr, gcutfilter, hfilter).filter

        vbar = filter(vbar * r)

        # Calculate matrix elements:
        self.dK_lnn = dK_lnn = []
        self.dH_lnn = dH_lnn = []
        self.dO_lnn = dO_lnn = []
        for l, (e_n, u_n, s_n, q_n) in enumerate(zip(e_ln, u_ln,
                                                     s_ln, q_ln)):

            A_nn = np.inner(s_n, q_n * dr)
            # Do a LU decomposition of A:
            nn = len(e_n)
            L_nn = np.identity(nn, float)
            U_nn = A_nn.copy()
            
            # Keep all bound states normalized
            if sum([n > 0 for n in n_ln[l]]) <= 1:
                for i in range(nn):
                    for j in range(i + 1, nn):
                        L_nn[j, i] = 1.0 * U_nn[j, i] / U_nn[i, i]
                        U_nn[j, :] -= U_nn[i, :] * L_nn[j, i]

            dO_nn = (np.inner(u_n, u_n * dr) -
                     np.inner(s_n, s_n * dr))

            e_nn = np.zeros((nn, nn))
            e_nn.ravel()[::nn + 1] = e_n
            dH_nn = np.dot(dO_nn, e_nn) - A_nn

            q_n[:] = np.dot(inv(np.transpose(U_nn)), q_n)
            s_n[:] = np.dot(inv(L_nn), s_n)
            u_n[:] = np.dot(inv(L_nn), u_n)

            dO_nn = np.dot(np.dot(inv(L_nn), dO_nn),
                            inv(np.transpose(L_nn)))
            dH_nn = np.dot(np.dot(inv(L_nn), dH_nn),
                            inv(np.transpose(L_nn)))

            ku_n = [self.kin(l, u, e) for u, e in zip(u_n, e_n)]
            ks_n = [self.kin(l, s) for s in s_n]
            dK_nn = 0.5 * (np.inner(u_n, ku_n * dr) -
                           np.inner(s_n, ks_n * dr))
            dK_nn += np.transpose(dK_nn).copy()

            dK_lnn.append(dK_nn)
            dO_lnn.append(dO_nn)
            dH_lnn.append(dH_nn)

            for n, q in enumerate(q_n):
                q[:] = filter(q, l) * r**(l + 1)

            A_nn = np.inner(s_n, q_n * dr)
            q_n[:] = np.dot(inv(np.transpose(A_nn)), q_n)

        self.vt = vt
        self.vbar = vbar


        t('state    eigenvalue         norm')
        t('--------------------------------')
        for l, (n_n, f_n, e_n) in enumerate(zip(n_ln, f_ln, e_ln)):
            for n in range(len(e_n)):
                if n_n[n] > 0:
                    f = '(%d)' % f_n[n]
                    t('%d%s%-4s: %12.6f %12.6f' % (
                        n_n[n], 'spdf'[l], f, e_n[n],
                        np.dot(s_ln[l][n]**2, dr)))
                else:
                    t('*%s    : %12.6f' % ('spdf'[l], e_n[n]))
        t('--------------------------------')

        self.logd = {}
        if logderiv:
            ni = 300
            self.elog = np.linspace(-5.0, 1.0, ni)
            # Calculate logarithmic derivatives:
            gld = gcutmax + 10
            self.rlog = r[gld]
            assert gld < gmax
            t('Calculating logarithmic derivatives at r=%.3f' % r[gld])
            t('(skip with [Ctrl-C])')

            try:
                u = np.zeros(N)
                for l in range(4):
                    self.logd[l] = (np.empty(ni), np.empty(ni))
                    if l <= lmax:
                        dO_nn = dO_lnn[l]
                        dH_nn = dH_lnn[l]
                        q_n = q_ln[l]

                    fae = open(self.symbol + '.ae.ld.' + 'spdf'[l], 'w')
                    fps = open(self.symbol + '.ps.ld.' + 'spdf'[l], 'w')

                    for i, e in enumerate(self.elog):
                        # All-electron logarithmic derivative:
                        u[:] = 0.0
                        shoot(u, l, self.vr, e, self.r2dvdr, r, dr, c10, c2,
                              self.scalarrel, gmax=gld)
                        dudr = 0.5 * (u[gld + 1] - u[gld - 1]) / dr[gld]
                        ld = dudr / u[gld] - 1.0 / r[gld]
                        print >> fae, e, ld
                        self.logd[l][0][i] = ld

                        # PAW logarithmic derivative:
                        s = self.integrate(l, vt, e, gld)
                        if l <= lmax:
                            A_nn = dH_nn - e * dO_nn
                            s_n = [self.integrate(l, vt, e, gld, q)
                                   for q in q_n]
                            B_nn = np.inner(q_n, s_n * dr)
                            a_n = np.dot(q_n, s * dr)

                            B_nn = np.dot(A_nn, B_nn)
                            B_nn.ravel()[::len(a_n) + 1] += 1.0
                            c_n = solve(B_nn, np.dot(A_nn, a_n))
                            s -= np.dot(c_n, s_n)

                        dsdr = 0.5 * (s[gld + 1] - s[gld - 1]) / dr[gld]
                        ld = dsdr / s[gld] - 1.0 / r[gld]
                        print >> fps, e, ld
                        self.logd[l][1][i] = ld

            except KeyboardInterrupt:
                pass

        self.write(nc,'nc')
        self.write(nt, 'nt')
        self.write(nct, 'nct')
        self.write(vbar, 'vbar')
        self.write(vt, 'vt')
        self.write(tauc, 'tauc')
        self.write(tauct, 'tauct')

        for l, (n_n, f_n, u_n, s_n, q_n) in enumerate(zip(n_ln, f_ln,
                                                          u_ln, s_ln, q_ln)):
            for n, f, u, s, q in zip(n_n, f_n, u_n, s_n, q_n):
                if n < 0:
                    self.write(u, 'ae', n=n, l=l)
                self.write(s, 'ps', n=n, l=l)
                self.write(q, 'proj', n=n, l=l)

        # Test for ghost states:
        for h in [0.05]:
            self.diagonalize(h)

        self.vn_j = vn_j = []
        self.vl_j = vl_j = []
        self.vf_j = vf_j = []
        self.ve_j = ve_j = []
        self.vu_j = vu_j = []
        self.vs_j = vs_j = []
        self.vq_j = vq_j = []
        j_ln = [[0 for f in f_n] for f_n in f_ln]
        j = 0
        for l, n_n in enumerate(n_ln):
            for n, nn in enumerate(n_n):
                if nn > 0:
                    vf_j.append(f_ln[l][n])
                    vn_j.append(nn)
                    vl_j.append(l)
                    ve_j.append(e_ln[l][n])
                    vu_j.append(u_ln[l][n])
                    vs_j.append(s_ln[l][n])
                    vq_j.append(q_ln[l][n])
                    j_ln[l][n] = j
                    j += 1
        for l, n_n in enumerate(n_ln):
            for n, nn in enumerate(n_n):
                if nn < 0:
                    vf_j.append(0)
                    vn_j.append(nn)
                    vl_j.append(l)
                    ve_j.append(e_ln[l][n])
                    vu_j.append(u_ln[l][n])
                    vs_j.append(s_ln[l][n])
                    vq_j.append(q_ln[l][n])
                    j_ln[l][n] = j
                    j += 1
        nj = j

        self.dK_jj = np.zeros((nj, nj))
        for l, j_n in enumerate(j_ln):
            for n1, j1 in enumerate(j_n):
                for n2, j2 in enumerate(j_n):
                    self.dK_jj[j1, j2] = self.dK_lnn[l][n1, n2]

        if exx:
            X_p = constructX(self)
            ExxC = atomic_exact_exchange(self, 'core-core')
        else:
            X_p = None
            ExxC = None

        sqrt4pi = sqrt(4 * pi)
        setup = SetupData(self.symbol, self.xc.name, self.name,
                          readxml=False)

        def divide_by_r(x_g, l):
            r = self.r
            #for x_g, l in zip(x_jg, l_j):
            p = x_g.copy()
            p[1:] /= self.r[1:]
            # XXXXX go to higher order!!!!!
            if l == 0:#l_j[self.jcorehole] == 0:
                p[0] = (p[2] +
                        (p[1] - p[2]) * (r[0] - r[2]) / (r[1] - r[2]))
            return p

        def divide_all_by_r(x_jg):
            return [divide_by_r(x_g, l) for x_g, l in zip(x_jg, vl_j)]

        setup.l_j = vl_j
        setup.n_j = vn_j
        setup.f_j = vf_j
        setup.eps_j = ve_j
        setup.rcut_j = [rcut_l[l] for l in vl_j]

        setup.nc_g = nc * sqrt4pi
        setup.nct_g = nct * sqrt4pi
        setup.nvt_g = (nt - nct) * sqrt4pi
        setup.e_kinetic_core = Ekincore
        setup.vbar_g = vbar * sqrt4pi
        setup.tauc_g = tauc * sqrt4pi
        setup.tauct_g = tauct * sqrt4pi
        setup.extra_xc_data = extra_xc_data
        setup.Z = Z
        setup.Nc = self.Nc
        setup.Nv = self.Nv
        setup.e_kinetic = self.Ekin
        setup.e_xc = self.Exc
        setup.e_electrostatic = self.Epot
        setup.e_total = self.Epot + self.Exc + self.Ekin

        setup.rgd = self.rgd
        
        setup.rcgauss = self.rcutcomp / sqrt(self.gamma)
        setup.e_kin_jj = self.dK_jj
        setup.ExxC = ExxC
        setup.phi_jg = divide_all_by_r(vu_j)
        setup.phit_jg = divide_all_by_r(vs_j)
        setup.pt_jg = divide_all_by_r(vq_j)
        setup.X_p = X_p

        if self.jcorehole is not None:
            setup.has_corehole = True
            setup.lcorehole = l_j[self.jcorehole] # l_j or vl_j ????? XXX
            setup.ncorehole = n_j[self.jcorehole]
            setup.phicorehole_g = divide_by_r(self.u_j[self.jcorehole],
                                                  setup.lcorehole)
            setup.core_hole_e = self.e_j[self.jcorehole]
            setup.core_hole_e_kin = self.Ekincorehole
            setup.fcorehole = self.fcorehole

        if self.ghost:
            raise RuntimeError('Ghost!')

        if self.scalarrel:
            reltype = 'scalar-relativistic'
        else:
            reltype = 'non-relativistic'

        attrs = [('type', reltype), ('name', 'gpaw-%s' % version)]
        data = 'Frozen core: '+ (self.core or 'none')

        setup.generatorattrs = attrs
        setup.generatordata  = data

        self.id_j = []
        for l, n in zip(vl_j, vn_j):
            if n > 0:
                id = '%s-%d%s' % (self.symbol, n, 'spdf'[l])
            else:
                id = '%s-%s%d' % (self.symbol, 'spdf'[l], -n)
            self.id_j.append(id)
        setup.id_j = self.id_j

        if write_xml:
            setup.write_xml()
        return setup
Example #7
0
    def run(self,
            core='',
            rcut=1.0,
            extra=None,
            logderiv=False,
            vbar=None,
            exx=False,
            name=None,
            normconserving='',
            filter=(0.4, 1.75),
            rcutcomp=None,
            write_xml=True,
            use_restart_file=True,
            empty_states=''):

        self.name = name

        self.core = core
        if type(rcut) is float:
            rcut_l = [rcut]
        else:
            rcut_l = rcut
        rcutmax = max(rcut_l)
        rcutmin = min(rcut_l)
        self.rcut_l = rcut_l

        if rcutcomp is None:
            rcutcomp = rcutmin
        self.rcutcomp = rcutcomp

        hfilter, xfilter = filter

        Z = self.Z

        n_j = self.n_j
        l_j = self.l_j
        f_j = self.f_j
        e_j = self.e_j

        if vbar is None:
            vbar = ('poly', rcutmin * 0.9)
        vbar_type, rcutvbar = vbar

        normconserving_l = [x in normconserving for x in 'spdf']

        # Parse core string:
        j = 0
        if core.startswith('['):
            a, core = core.split(']')
            core_symbol = a[1:]
            j = len(configurations[core_symbol][1])

        while core != '':
            assert n_j[j] == int(core[0])
            assert l_j[j] == 'spdf'.find(core[1])
            if j != self.jcorehole:
                assert f_j[j] == 2 * (2 * l_j[j] + 1)
            j += 1
            core = core[2:]

        njcore = j
        self.njcore = njcore

        lmaxocc = max(l_j[njcore:])

        while empty_states != '':
            n = int(empty_states[0])
            l = 'spdf'.find(empty_states[1])
            print l_j
            assert n == 1 + l + l_j.count(l)
            n_j.append(n)
            l_j.append(l)
            f_j.append(0.0)
            e_j.append(-0.01)
            empty_states = empty_states[2:]

        if 2 in l_j[njcore:]:
            # We have a bound valence d-state.  Add bound s- and
            # p-states if not already there:
            for l in [0, 1]:
                if l not in l_j[njcore:]:
                    n_j.append(1 + l + l_j.count(l))
                    l_j.append(l)
                    f_j.append(0.0)
                    e_j.append(-0.01)

        if l_j[njcore:] == [0] and Z > 2:
            # We have only a bound valence s-state and we are not
            # hydrogen and not helium.  Add bound p-state:
            n_j.append(n_j[njcore])
            l_j.append(1)
            f_j.append(0.0)
            e_j.append(-0.01)

        nj = len(n_j)

        self.Nv = sum(f_j[njcore:])
        self.Nc = sum(f_j[:njcore])

        # Do all-electron calculation:
        AllElectron.run(self, use_restart_file)

        # Highest occupied atomic orbital:
        self.emax = max(e_j)

        N = self.N
        r = self.r
        dr = self.dr
        d2gdr2 = self.d2gdr2
        beta = self.beta

        dv = r**2 * dr

        t = self.text
        t()
        t('Generating PAW setup')
        if core != '':
            t('Frozen core:', core)

        # So far - no ghost-states:
        self.ghost = False

        # Calculate the kinetic energy of the core states:
        Ekincore = 0.0
        j = 0
        for f, e, u in zip(f_j[:njcore], e_j[:njcore], self.u_j[:njcore]):
            u = np.where(abs(u) < 1e-160, 0, u)  # XXX Numeric!
            k = e - np.sum((u**2 * self.vr * dr)[1:] / r[1:])
            Ekincore += f * k
            if j == self.jcorehole:
                self.Ekincorehole = k
            j += 1

        # Calculate core density:
        if njcore == 0:
            nc = np.zeros(N)
        else:
            uc_j = self.u_j[:njcore]
            uc_j = np.where(abs(uc_j) < 1e-160, 0, uc_j)  # XXX Numeric!
            nc = np.dot(f_j[:njcore], uc_j**2) / (4 * pi)
            nc[1:] /= r[1:]**2
            nc[0] = nc[1]

        self.nc = nc

        # Calculate core kinetic energy density
        if njcore == 0:
            tauc = np.zeros(N)
        else:
            tauc = self.radial_kinetic_energy_density(f_j[:njcore],
                                                      l_j[:njcore],
                                                      self.u_j[:njcore])
            t('Kinetic energy of the core from tauc =',
              np.dot(tauc * r * r, dr) * 4 * pi)

        lmax = max(l_j[njcore:])

        # Order valence states with respect to angular momentum
        # quantum number:
        self.n_ln = n_ln = []
        self.f_ln = f_ln = []
        self.e_ln = e_ln = []
        for l in range(lmax + 1):
            n_n = []
            f_n = []
            e_n = []
            for j in range(njcore, nj):
                if l_j[j] == l:
                    n_n.append(n_j[j])
                    f_n.append(f_j[j])
                    e_n.append(e_j[j])
            n_ln.append(n_n)
            f_ln.append(f_n)
            e_ln.append(e_n)

        # Add extra projectors:
        if extra is not None:
            if len(extra) == 0:
                lmaxextra = 0
            else:
                lmaxextra = max(extra.keys())
            if lmaxextra > lmax:
                for l in range(lmax, lmaxextra):
                    n_ln.append([])
                    f_ln.append([])
                    e_ln.append([])
                lmax = lmaxextra
            for l in extra:
                nn = -1
                for e in extra[l]:
                    n_ln[l].append(nn)
                    f_ln[l].append(0.0)
                    e_ln[l].append(e)
                    nn -= 1
        else:
            # Automatic:

            # Make sure we have two projectors for each occupied channel:
            for l in range(lmaxocc + 1):
                if len(n_ln[l]) < 2 and not normconserving_l[l]:
                    # Only one - add one more:
                    assert len(n_ln[l]) == 1
                    n_ln[l].append(-1)
                    f_ln[l].append(0.0)
                    e_ln[l].append(1.0 + e_ln[l][0])

            if lmaxocc < 2 and lmaxocc == lmax:
                # Add extra projector for l = lmax + 1:
                n_ln.append([-1])
                f_ln.append([0.0])
                e_ln.append([0.0])
                lmax += 1

        self.lmax = lmax

        rcut_l.extend([rcutmin] * (lmax + 1 - len(rcut_l)))

        t('Cutoffs:')
        for rc, s in zip(rcut_l, 'spdf'):
            t('rc(%s)=%.3f' % (s, rc))
        t('rc(vbar)=%.3f' % rcutvbar)
        t('rc(comp)=%.3f' % rcutcomp)
        t()
        t('Kinetic energy of the core states: %.6f' % Ekincore)

        # Allocate arrays:
        self.u_ln = u_ln = []  # phi * r
        self.s_ln = s_ln = []  # phi-tilde * r
        self.q_ln = q_ln = []  # p-tilde * r
        for l in range(lmax + 1):
            nn = len(n_ln[l])
            u_ln.append(np.zeros((nn, N)))
            s_ln.append(np.zeros((nn, N)))
            q_ln.append(np.zeros((nn, N)))

        # Fill in all-electron wave functions:
        for l in range(lmax + 1):
            # Collect all-electron wave functions:
            u_n = [self.u_j[j] for j in range(njcore, nj) if l_j[j] == l]
            for n, u in enumerate(u_n):
                u_ln[l][n] = u

        # Grid-index corresponding to rcut:
        gcut_l = [1 + int(rc * N / (rc + beta)) for rc in rcut_l]

        rcutfilter = xfilter * rcutmax
        self.rcutfilter = rcutfilter
        gcutfilter = 1 + int(rcutfilter * N / (rcutfilter + beta))
        gcutmax = 1 + int(rcutmax * N / (rcutmax + beta))

        # Outward integration of unbound states stops at 3 * rcut:
        gmax = int(3 * rcutmax * N / (3 * rcutmax + beta))
        assert gmax > gcutfilter

        # Calculate unbound extra states:
        c2 = -(r / dr)**2
        c10 = -d2gdr2 * r**2
        for l, (n_n, e_n, u_n) in enumerate(zip(n_ln, e_ln, u_ln)):
            for n, e, u in zip(n_n, e_n, u_n):
                if n < 0:
                    u[:] = 0.0
                    shoot(u,
                          l,
                          self.vr,
                          e,
                          self.r2dvdr,
                          r,
                          dr,
                          c10,
                          c2,
                          self.scalarrel,
                          gmax=gmax)
                    u *= 1.0 / u[gcut_l[l]]

        charge = Z - self.Nv - self.Nc
        t('Charge: %.1f' % charge)
        t('Core electrons: %.1f' % self.Nc)
        t('Valence electrons: %.1f' % self.Nv)

        # Construct smooth wave functions:
        coefs = []
        for l, (u_n, s_n) in enumerate(zip(u_ln, s_ln)):
            nodeless = True
            gc = gcut_l[l]
            for u, s in zip(u_n, s_n):
                s[:] = u
                if normconserving_l[l]:
                    A = np.zeros((5, 5))
                    A[:4, 0] = 1.0
                    A[:4, 1] = r[gc - 2:gc + 2]**2
                    A[:4, 2] = A[:4, 1]**2
                    A[:4, 3] = A[:4, 1] * A[:4, 2]
                    A[:4, 4] = A[:4, 2]**2
                    A[4, 4] = 1.0
                    a = u[gc - 2:gc + 3] / r[gc - 2:gc + 3]**(l + 1)
                    a = np.log(a)

                    def f(x):
                        a[4] = x
                        b = solve(A, a)
                        r1 = r[:gc]
                        r2 = r1**2
                        rl1 = r1**(l + 1)
                        y = b[0] + r2 * (b[1] + r2 * (b[2] + r2 *
                                                      (b[3] + r2 * b[4])))
                        y = np.exp(y)
                        s[:gc] = rl1 * y
                        return np.dot(s**2, dr) - 1

                    x1 = 0.0
                    x2 = 0.001
                    f1 = f(x1)
                    f2 = f(x2)
                    while abs(f1) > 1e-6:
                        x0 = (x1 / f1 - x2 / f2) / (1 / f1 - 1 / f2)
                        f0 = f(x0)
                        if abs(f1) < abs(f2):
                            x2, f2 = x1, f1
                        x1, f1 = x0, f0

                else:
                    A = np.ones((4, 4))
                    A[:, 0] = 1.0
                    A[:, 1] = r[gc - 2:gc + 2]**2
                    A[:, 2] = A[:, 1]**2
                    A[:, 3] = A[:, 1] * A[:, 2]
                    a = u[gc - 2:gc + 2] / r[gc - 2:gc + 2]**(l + 1)
                    if 0:  #l < 2 and nodeless:
                        a = np.log(a)
                    a = solve(A, a)
                    r1 = r[:gc]
                    r2 = r1**2
                    rl1 = r1**(l + 1)
                    y = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * (a[3])))
                    if 0:  #l < 2 and nodeless:
                        y = np.exp(y)
                    s[:gc] = rl1 * y

                coefs.append(a)
                if nodeless:
                    if not np.alltrue(s[1:gc] > 0.0):
                        raise RuntimeError(
                            'Error: The %d%s pseudo wave has a node!' %
                            (n_ln[l][0], 'spdf'[l]))
                    # Only the first state for each l must be nodeless:
                    nodeless = False

        # Calculate pseudo core density:
        gcutnc = 1 + int(rcutmax * N / (rcutmax + beta))
        self.nct = nct = nc.copy()
        A = np.ones((4, 4))
        A[0] = 1.0
        A[1] = r[gcutnc - 2:gcutnc + 2]**2
        A[2] = A[1]**2
        A[3] = A[1] * A[2]
        a = nc[gcutnc - 2:gcutnc + 2]
        a = solve(np.transpose(A), a)
        r2 = r[:gcutnc]**2
        nct[:gcutnc] = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * a[3]))
        t('Pseudo-core charge: %.6f' % (4 * pi * np.dot(nct, dv)))

        # ... and the pseudo core kinetic energy density:
        tauct = tauc.copy()
        a = tauc[gcutnc - 2:gcutnc + 2]
        a = solve(np.transpose(A), a)
        tauct[:gcutnc] = a[0] + r2 * (a[1] + r2 * (a[2] + r2 * a[3]))

        # ... and the soft valence density:
        nt = np.zeros(N)
        for f_n, s_n in zip(f_ln, s_ln):
            nt += np.dot(f_n, s_n**2) / (4 * pi)
        nt[1:] /= r[1:]**2
        nt[0] = nt[1]
        nt += nct
        self.nt = nt

        # Calculate the shape function:
        x = r / rcutcomp
        gaussian = np.zeros(N)
        self.gamma = gamma = 10.0
        gaussian[:gmax] = np.exp(-gamma * x[:gmax]**2)
        gt = 4 * (gamma / rcutcomp**2)**1.5 / sqrt(pi) * gaussian
        norm = np.dot(gt, dv)
        #print norm, norm-1
        assert abs(norm - 1) < 1e-2
        gt /= norm

        # Calculate smooth charge density:
        Nt = np.dot(nt, dv)
        rhot = nt - (Nt + charge / (4 * pi)) * gt
        t('Pseudo-electron charge', 4 * pi * Nt)

        vHt = np.zeros(N)
        hartree(0, rhot * r * dr, self.beta, self.N, vHt)
        vHt[1:] /= r[1:]
        vHt[0] = vHt[1]

        vXCt = np.zeros(N)

        extra_xc_data = {}

        if self.xc.type != 'GLLB':
            Exct = self.xc.calculate_spherical(self.rgd, nt.reshape((1, -1)),
                                               vXCt.reshape((1, -1)))
        else:
            Exct = self.xc.get_smooth_xc_potential_and_energy_1d(vXCt)

            # Calculate extra-stuff for non-local functionals
            self.xc.get_extra_setup_data(extra_xc_data)

        vt = vHt + vXCt

        # Construct zero potential:
        gc = 1 + int(rcutvbar * N / (rcutvbar + beta))
        if vbar_type == 'f':
            assert lmax == 2
            uf = np.zeros(N)
            l = 3

            # Solve for all-electron f-state:
            eps = 0.0
            shoot(uf,
                  l,
                  self.vr,
                  eps,
                  self.r2dvdr,
                  r,
                  dr,
                  c10,
                  c2,
                  self.scalarrel,
                  gmax=gmax)
            uf *= 1.0 / uf[gc]

            # Fit smooth pseudo f-state polynomium:
            A = np.ones((4, 4))
            A[:, 0] = 1.0
            A[:, 1] = r[gc - 2:gc + 2]**2
            A[:, 2] = A[:, 1]**2
            A[:, 3] = A[:, 1] * A[:, 2]
            a = uf[gc - 2:gc + 2] / r[gc - 2:gc + 2]**(l + 1)
            a0, a1, a2, a3 = solve(A, a)
            r1 = r[:gc]
            r2 = r1**2
            rl1 = r1**(l + 1)
            y = a0 + r2 * (a1 + r2 * (a2 + r2 * a3))
            sf = uf.copy()
            sf[:gc] = rl1 * y

            # From 0 to gc, use analytic formula for kinetic energy operator:
            r4 = r2**2
            r6 = r4 * r2
            enumerator = (a0 * l * (l + 1) + a1 * (l + 2) * (l + 3) * r2 + a2 *
                          (l + 4) * (l + 5) * r4 + a3 * (l + 6) * (l + 7) * r6)
            denominator = a0 + a1 * r2 + a2 * r4 + a3 * r6
            ekin_over_phit = -0.5 * (enumerator / denominator - l * (l + 1))
            ekin_over_phit[1:] /= r2[1:]

            vbar = eps - vt
            vbar[:gc] -= ekin_over_phit
            vbar[0] = vbar[1]  # Actually we can collect the terms into
            # a single fraction without poles, so as to avoid doing this,
            # but this is good enough

            # From gc to gmax, use finite-difference formula for kinetic
            # energy operator:
            vbar[gc:gmax] -= self.kin(l, sf)[gc:gmax] / sf[gc:gmax]
            vbar[gmax:] = 0.0
        else:
            assert vbar_type == 'poly'
            A = np.ones((2, 2))
            A[0] = 1.0
            A[1] = r[gc - 1:gc + 1]**2
            a = vt[gc - 1:gc + 1]
            a = solve(np.transpose(A), a)
            r2 = r**2
            vbar = a[0] + r2 * a[1] - vt
            vbar[gc:] = 0.0

        vt += vbar

        # Construct projector functions:
        for l, (e_n, s_n, q_n) in enumerate(zip(e_ln, s_ln, q_ln)):
            for e, s, q in zip(e_n, s_n, q_n):
                q[:] = self.kin(l, s) + (vt - e) * s
                q[gcutmax:] = 0.0

        filter = Filter(r, dr, gcutfilter, hfilter).filter

        vbar = filter(vbar * r)

        # Calculate matrix elements:
        self.dK_lnn = dK_lnn = []
        self.dH_lnn = dH_lnn = []
        self.dO_lnn = dO_lnn = []
        for l, (e_n, u_n, s_n, q_n) in enumerate(zip(e_ln, u_ln, s_ln, q_ln)):

            A_nn = np.inner(s_n, q_n * dr)
            # Do a LU decomposition of A:
            nn = len(e_n)
            L_nn = np.identity(nn, float)
            U_nn = A_nn.copy()

            # Keep all bound states normalized
            if sum([n > 0 for n in n_ln[l]]) <= 1:
                for i in range(nn):
                    for j in range(i + 1, nn):
                        L_nn[j, i] = 1.0 * U_nn[j, i] / U_nn[i, i]
                        U_nn[j, :] -= U_nn[i, :] * L_nn[j, i]

            dO_nn = (np.inner(u_n, u_n * dr) - np.inner(s_n, s_n * dr))

            e_nn = np.zeros((nn, nn))
            e_nn.ravel()[::nn + 1] = e_n
            dH_nn = np.dot(dO_nn, e_nn) - A_nn

            q_n[:] = np.dot(inv(np.transpose(U_nn)), q_n)
            s_n[:] = np.dot(inv(L_nn), s_n)
            u_n[:] = np.dot(inv(L_nn), u_n)

            dO_nn = np.dot(np.dot(inv(L_nn), dO_nn), inv(np.transpose(L_nn)))
            dH_nn = np.dot(np.dot(inv(L_nn), dH_nn), inv(np.transpose(L_nn)))

            ku_n = [self.kin(l, u, e) for u, e in zip(u_n, e_n)]
            ks_n = [self.kin(l, s) for s in s_n]
            dK_nn = 0.5 * (np.inner(u_n, ku_n * dr) - np.inner(s_n, ks_n * dr))
            dK_nn += np.transpose(dK_nn).copy()

            dK_lnn.append(dK_nn)
            dO_lnn.append(dO_nn)
            dH_lnn.append(dH_nn)

            for n, q in enumerate(q_n):
                q[:] = filter(q, l) * r**(l + 1)

            A_nn = np.inner(s_n, q_n * dr)
            q_n[:] = np.dot(inv(np.transpose(A_nn)), q_n)

        self.vt = vt
        self.vbar = vbar

        t('state    eigenvalue         norm')
        t('--------------------------------')
        for l, (n_n, f_n, e_n) in enumerate(zip(n_ln, f_ln, e_ln)):
            for n in range(len(e_n)):
                if n_n[n] > 0:
                    f = '(%d)' % f_n[n]
                    t('%d%s%-4s: %12.6f %12.6f' %
                      (n_n[n], 'spdf'[l], f, e_n[n], np.dot(s_ln[l][n]**2,
                                                            dr)))
                else:
                    t('*%s    : %12.6f' % ('spdf'[l], e_n[n]))
        t('--------------------------------')

        self.logd = {}
        if logderiv:
            ni = 300
            self.elog = np.linspace(-5.0, 1.0, ni)
            # Calculate logarithmic derivatives:
            gld = gcutmax + 10
            self.rlog = r[gld]
            assert gld < gmax
            t('Calculating logarithmic derivatives at r=%.3f' % r[gld])
            t('(skip with [Ctrl-C])')

            try:
                u = np.zeros(N)
                for l in range(4):
                    self.logd[l] = (np.empty(ni), np.empty(ni))
                    if l <= lmax:
                        dO_nn = dO_lnn[l]
                        dH_nn = dH_lnn[l]
                        q_n = q_ln[l]

                    fae = open(self.symbol + '.ae.ld.' + 'spdf'[l], 'w')
                    fps = open(self.symbol + '.ps.ld.' + 'spdf'[l], 'w')

                    for i, e in enumerate(self.elog):
                        # All-electron logarithmic derivative:
                        u[:] = 0.0
                        shoot(u,
                              l,
                              self.vr,
                              e,
                              self.r2dvdr,
                              r,
                              dr,
                              c10,
                              c2,
                              self.scalarrel,
                              gmax=gld)
                        dudr = 0.5 * (u[gld + 1] - u[gld - 1]) / dr[gld]
                        ld = dudr / u[gld] - 1.0 / r[gld]
                        print >> fae, e, ld
                        self.logd[l][0][i] = ld

                        # PAW logarithmic derivative:
                        s = self.integrate(l, vt, e, gld)
                        if l <= lmax:
                            A_nn = dH_nn - e * dO_nn
                            s_n = [
                                self.integrate(l, vt, e, gld, q) for q in q_n
                            ]
                            B_nn = np.inner(q_n, s_n * dr)
                            a_n = np.dot(q_n, s * dr)

                            B_nn = np.dot(A_nn, B_nn)
                            B_nn.ravel()[::len(a_n) + 1] += 1.0
                            c_n = solve(B_nn, np.dot(A_nn, a_n))
                            s -= np.dot(c_n, s_n)

                        dsdr = 0.5 * (s[gld + 1] - s[gld - 1]) / dr[gld]
                        ld = dsdr / s[gld] - 1.0 / r[gld]
                        print >> fps, e, ld
                        self.logd[l][1][i] = ld

            except KeyboardInterrupt:
                pass

        self.write(nc, 'nc')
        self.write(nt, 'nt')
        self.write(nct, 'nct')
        self.write(vbar, 'vbar')
        self.write(vt, 'vt')
        self.write(tauc, 'tauc')
        self.write(tauct, 'tauct')

        for l, (n_n, f_n, u_n, s_n,
                q_n) in enumerate(zip(n_ln, f_ln, u_ln, s_ln, q_ln)):
            for n, f, u, s, q in zip(n_n, f_n, u_n, s_n, q_n):
                if n < 0:
                    self.write(u, 'ae', n=n, l=l)
                self.write(s, 'ps', n=n, l=l)
                self.write(q, 'proj', n=n, l=l)

        # Test for ghost states:
        for h in [0.05]:
            self.diagonalize(h)

        self.vn_j = vn_j = []
        self.vl_j = vl_j = []
        self.vf_j = vf_j = []
        self.ve_j = ve_j = []
        self.vu_j = vu_j = []
        self.vs_j = vs_j = []
        self.vq_j = vq_j = []
        j_ln = [[0 for f in f_n] for f_n in f_ln]
        j = 0
        for l, n_n in enumerate(n_ln):
            for n, nn in enumerate(n_n):
                if nn > 0:
                    vf_j.append(f_ln[l][n])
                    vn_j.append(nn)
                    vl_j.append(l)
                    ve_j.append(e_ln[l][n])
                    vu_j.append(u_ln[l][n])
                    vs_j.append(s_ln[l][n])
                    vq_j.append(q_ln[l][n])
                    j_ln[l][n] = j
                    j += 1
        for l, n_n in enumerate(n_ln):
            for n, nn in enumerate(n_n):
                if nn < 0:
                    vf_j.append(0)
                    vn_j.append(nn)
                    vl_j.append(l)
                    ve_j.append(e_ln[l][n])
                    vu_j.append(u_ln[l][n])
                    vs_j.append(s_ln[l][n])
                    vq_j.append(q_ln[l][n])
                    j_ln[l][n] = j
                    j += 1
        nj = j

        self.dK_jj = np.zeros((nj, nj))
        for l, j_n in enumerate(j_ln):
            for n1, j1 in enumerate(j_n):
                for n2, j2 in enumerate(j_n):
                    self.dK_jj[j1, j2] = self.dK_lnn[l][n1, n2]

        if exx:
            X_p = constructX(self)
            ExxC = atomic_exact_exchange(self, 'core-core')
        else:
            X_p = None
            ExxC = None

        sqrt4pi = sqrt(4 * pi)
        setup = SetupData(self.symbol, self.xc.name, self.name, readxml=False)

        def divide_by_r(x_g, l):
            r = self.r
            #for x_g, l in zip(x_jg, l_j):
            p = x_g.copy()
            p[1:] /= self.r[1:]
            # XXXXX go to higher order!!!!!
            if l == 0:  #l_j[self.jcorehole] == 0:
                p[0] = (p[2] + (p[1] - p[2]) * (r[0] - r[2]) / (r[1] - r[2]))
            return p

        def divide_all_by_r(x_jg):
            return [divide_by_r(x_g, l) for x_g, l in zip(x_jg, vl_j)]

        setup.l_j = vl_j
        setup.n_j = vn_j
        setup.f_j = vf_j
        setup.eps_j = ve_j
        setup.rcut_j = [rcut_l[l] for l in vl_j]

        setup.nc_g = nc * sqrt4pi
        setup.nct_g = nct * sqrt4pi
        setup.nvt_g = (nt - nct) * sqrt4pi
        setup.e_kinetic_core = Ekincore
        setup.vbar_g = vbar * sqrt4pi
        setup.tauc_g = tauc * sqrt4pi
        setup.tauct_g = tauct * sqrt4pi
        setup.extra_xc_data = extra_xc_data
        setup.Z = Z
        setup.Nc = self.Nc
        setup.Nv = self.Nv
        setup.e_kinetic = self.Ekin
        setup.e_xc = self.Exc
        setup.e_electrostatic = self.Epot
        setup.e_total = self.Epot + self.Exc + self.Ekin
        setup.beta = self.beta
        setup.ng = self.N
        setup.rcgauss = self.rcutcomp / sqrt(self.gamma)
        setup.e_kin_jj = self.dK_jj
        setup.ExxC = ExxC
        setup.phi_jg = divide_all_by_r(vu_j)
        setup.phit_jg = divide_all_by_r(vs_j)
        setup.pt_jg = divide_all_by_r(vq_j)
        setup.X_p = X_p

        if self.jcorehole is not None:
            setup.has_corehole = True
            setup.lcorehole = l_j[self.jcorehole]  # l_j or vl_j ????? XXX
            setup.ncorehole = n_j[self.jcorehole]
            setup.phicorehole_g = divide_by_r(self.u_j[self.jcorehole],
                                              setup.lcorehole)
            setup.core_hole_e = self.e_j[self.jcorehole]
            setup.core_hole_e_kin = self.Ekincorehole
            setup.fcorehole = self.fcorehole

        if self.ghost:
            raise RuntimeError('Ghost!')

        if self.scalarrel:
            reltype = 'scalar-relativistic'
        else:
            reltype = 'non-relativistic'

        attrs = [('type', reltype), ('name', 'gpaw-%s' % version)]
        data = 'Frozen core: ' + (self.core or 'none')

        setup.generatorattrs = attrs
        setup.generatordata = data

        self.id_j = []
        for l, n in zip(vl_j, vn_j):
            if n > 0:
                id = '%s-%d%s' % (self.symbol, n, 'spdf'[l])
            else:
                id = '%s-%s%d' % (self.symbol, 'spdf'[l], -n)
            self.id_j.append(id)
        setup.id_j = self.id_j

        if write_xml:
            setup.write_xml()
        return setup
Example #8
0
    def calculate(self):
        ESIC = 0
        xc = self.paw.hamiltonian.xc
        assert xc.type == 'LDA'

        # Calculate the contribution from the core orbitals
        for a in self.paw.density.D_asp:
            setup = self.paw.density.setups[a]
            # TODO: Use XC which has been used to calculate the actual
            # calculation.
            # TODO: Loop over setups, not atoms.
            print('Atom core SIC for ', setup.symbol)
            print('%10s%10s%10s' % ('E_xc[n_i]', 'E_Ha[n_i]', 'E_SIC'))
            g = Generator(setup.symbol, xcname='LDA', nofiles=True, txt=None)
            g.run(**parameters[setup.symbol])
            njcore = g.njcore
            for f, l, e, u in zip(g.f_j[:njcore], g.l_j[:njcore],
                                  g.e_j[:njcore], g.u_j[:njcore]):
                # Calculate orbital density
                # NOTE: It's spherically symmetrized!
                #n = np.dot(self.f_j,
                assert l == 0, ('Not tested for l>0 core states')
                na = np.where(abs(u) < 1e-160, 0, u)**2 / (4 * pi)
                na[1:] /= g.r[1:]**2
                na[0] = na[1]
                nb = np.zeros(g.N)
                v_sg = np.zeros((2, g.N))
                e_g = np.zeros(g.N)
                vHr = np.zeros(g.N)
                Exc = xc.calculate_spherical(g.rgd, np.array([na, nb]), v_sg)
                hartree(0, na * g.r * g.dr, g.r, vHr)
                EHa = 2 * pi * np.dot(vHr * na * g.r, g.dr)
                print(
                    ('%10.2f%10.2f%10.2f' % (Exc * Hartree, EHa * Hartree, -f *
                                             (EHa + Exc) * Hartree)))
                ESIC += -f * (EHa + Exc)

        sic = SIC(finegrid=True, coulomb_factor=1, xc_factor=1)
        sic.initialize(self.paw.density, self.paw.hamiltonian, self.paw.wfs)
        sic.set_positions(self.paw.atoms.get_scaled_positions())

        print('Valence electron sic ')
        print('%10s%10s%10s%10s%10s%10s' %
              ('spin', 'k-point', 'band', 'E_xc[n_i]', 'E_Ha[n_i]', 'E_SIC'))
        assert len(
            self.paw.wfs.kpt_u) == 1, ('Not tested for bulk calculations')

        for s, spin in sic.spin_s.items():
            spin.initialize_orbitals()
            spin.update_optimal_states()
            spin.update_potentials()

            n = 0
            for xc, c in zip(spin.exc_m, spin.ecoulomb_m):
                print(('%10i%10i%10i%10.2f%10.2f%10.2f' %
                       (s, 0, n, -xc * Hartree, -c * Hartree, 2 *
                        (xc + c) * Hartree)))
                n += 1

            ESIC += spin.esic

        print('Total correction for self-interaction energy:')
        print('%10.2f eV' % (ESIC * Hartree))
        print('New total energy:')
        total = (ESIC * Hartree + self.paw.get_potential_energy() +
                 self.paw.get_reference_energy())
        print('%10.2f eV' % total)
        return total
Example #9
0
def constructX(gen):
    """Construct the X_p^a matrix for the given atom.

    The X_p^a matrix describes the valence-core interactions of the
    partial waves.
    """
    # initialize attributes
    uv_j = gen.vu_j  # soft valence states * r:
    lv_j = gen.vl_j  # their repective l quantum numbers
    Nvi = 0
    for l in lv_j:
        Nvi += 2 * l + 1  # total number of valence states (including m)

    # number of core and valence orbitals (j only, i.e. not m-number)
    Njcore = gen.njcore
    Njval = len(lv_j)

    # core states * r:
    uc_j = gen.u_j[:Njcore]
    r, dr, N, beta = gen.r, gen.dr, gen.N, gen.beta

    # potential times radius
    vr = np.zeros(N)

    # initialize X_ii matrix
    X_ii = np.zeros((Nvi, Nvi))

    # make gaunt coeff. list
    lmax = max(gen.l_j[:Njcore] + gen.vl_j)
    gaunt = make_gaunt(lmax=lmax)

    # sum over core states
    for jc in range(Njcore):
        lc = gen.l_j[jc]

        # sum over first valence state index
        i1 = 0
        for jv1 in range(Njval):
            lv1 = lv_j[jv1]

            # electron density 1 times radius times length element
            n1c = uv_j[jv1] * uc_j[jc] * dr
            n1c[1:] /= r[1:]

            # sum over second valence state index
            i2 = 0
            for jv2 in range(Njval):
                lv2 = lv_j[jv2]

                # electron density 2
                n2c = uv_j[jv2] * uc_j[jc] * dr
                n2c[1:] /= r[1:]

                # sum expansion in angular momenta
                for l in range(min(lv1, lv2) + lc + 1):
                    # Int density * potential * r^2 * dr:
                    hartree(l, n2c, r, vr)
                    nv = np.dot(n1c, vr)

                    # expansion coefficients
                    A_mm = X_ii[i1:i1 + 2 * lv1 + 1, i2:i2 + 2 * lv2 + 1]
                    for mc in range(2 * lc + 1):
                        for m in range(2 * l + 1):
                            G1c = gaunt[lv1**2:(lv1 + 1)**2, lc**2 + mc,
                                        l**2 + m]
                            G2c = gaunt[lv2**2:(lv2 + 1)**2, lc**2 + mc,
                                        l**2 + m]
                            A_mm += nv * np.outer(G1c, G2c)
                i2 += 2 * lv2 + 1
            i1 += 2 * lv1 + 1

    # pack X_ii matrix
    X_p = pack2(X_ii)
    return X_p
Example #10
0
    def run(self, use_restart_file=True):
        #     beta g
        # r = ------, g = 0, 1, ..., N - 1
        #     N - g
        #
        #        rN
        # g = --------
        #     beta + r

        t = self.text
        N = self.N
        beta = self.beta
        t(N, 'radial gridpoints.')
        self.rgd = AERadialGridDescriptor(beta / N, 1.0 / N, N)
        g = np.arange(N, dtype=float)
        self.r = self.rgd.r_g
        self.dr = self.rgd.dr_g
        self.d2gdr2 = self.rgd.d2gdr2()

        # Number of orbitals:
        nj = len(self.n_j)

        # Radial wave functions multiplied by radius:
        self.u_j = np.zeros((nj, self.N))

        # Effective potential multiplied by radius:
        self.vr = np.zeros(N)

        # Electron density:
        self.n = np.zeros(N)

        # Always spinpaired nspins=1
        self.xc = XC(self.xcname)

        # Initialize for non-local functionals
        if self.xc.type == 'GLLB':
            self.xc.pass_stuff_1d(self)
            self.xc.initialize_1d()

        n_j = self.n_j
        l_j = self.l_j
        f_j = self.f_j
        e_j = self.e_j

        Z = self.Z  # nuclear charge
        r = self.r  # radial coordinate
        dr = self.dr  # dr/dg
        n = self.n  # electron density
        vr = self.vr  # effective potential multiplied by r

        vHr = np.zeros(self.N)
        self.vXC = np.zeros(self.N)

        restartfile = '%s/%s.restart' % (tempdir, self.symbol)
        if self.xc.type == 'GLLB' or not use_restart_file:
            # Do not start from initial guess when doing
            # non local XC!
            # This is because we need wavefunctions as well
            # on the first iteration.
            fd = None
        else:
            try:
                fd = open(restartfile, 'rb')
            except IOError:
                fd = None
            else:
                try:
                    n[:] = pickle.load(fd)
                except (ValueError, IndexError):
                    fd = None
                else:
                    norm = np.dot(n * r**2, dr) * 4 * pi
                    if abs(norm - sum(f_j)) > 0.01:
                        fd = None
                    else:
                        t('Using old density for initial guess.')
                        n *= sum(f_j) / norm

        if fd is None:
            self.initialize_wave_functions()
            n[:] = self.calculate_density()

        bar = '|------------------------------------------------|'
        t(bar)

        niter = 0
        nitermax = 117
        qOK = log(1e-10)
        mix = 0.4

        # orbital_free needs more iterations and coefficient
        if self.orbital_free:
            mix = 0.01
            nitermax = 2000
            e_j[0] /= self.tw_coeff
            if Z > 10:  #help convergence for third row elements
                mix = 0.002
                nitermax = 10000

        vrold = None

        while True:
            # calculate hartree potential
            hartree(0, n * r * dr, r, vHr)

            # add potential from nuclear point charge (v = -Z / r)
            vHr -= Z

            # calculated exchange correlation potential and energy
            self.vXC[:] = 0.0

            if self.xc.type == 'GLLB':
                # Update the potential to self.vXC an the energy to self.Exc
                Exc = self.xc.get_xc_potential_and_energy_1d(self.vXC)
            else:
                Exc = self.xc.calculate_spherical(self.rgd, n.reshape((1, -1)),
                                                  self.vXC.reshape((1, -1)))

            # calculate new total Kohn-Sham effective potential and
            # admix with old version

            vr[:] = (vHr + self.vXC * r)

            if self.orbital_free:
                vr /= self.tw_coeff

            if niter > 0:
                vr[:] = mix * vr + (1 - mix) * vrold
            vrold = vr.copy()

            # solve Kohn-Sham equation and determine the density change
            self.solve()
            dn = self.calculate_density() - n
            n += dn

            # estimate error from the square of the density change integrated
            q = log(np.sum((r * dn)**2))

            # print progress bar
            if niter == 0:
                q0 = q
                b0 = 0
            else:
                b = int((q0 - q) / (q0 - qOK) * 50)
                if b > b0:
                    self.txt.write(bar[b0:min(b, 50)])
                    self.txt.flush()
                    b0 = b

            # check if converged and break loop if so
            if q < qOK:
                self.txt.write(bar[b0:])
                self.txt.flush()
                break

            niter += 1
            if niter > nitermax:
                raise RuntimeError('Did not converge!')

        tau = self.calculate_kinetic_energy_density()

        t()
        t('Converged in %d iteration%s.' % (niter, 's'[:niter != 1]))

        try:
            fd = open(restartfile, 'wb')
        except IOError:
            pass
        else:
            pickle.dump(n, fd)
            try:
                os.chmod(restartfile, 0o666)
            except OSError:
                pass

        Ekin = 0

        for f, e in zip(f_j, e_j):
            Ekin += f * e

        e_coulomb = 2 * pi * np.dot(n * r * (vHr - Z), dr)
        Ekin += -4 * pi * np.dot(n * vr * r, dr)

        if self.orbital_free:
            # e and vr are not scaled back
            # instead Ekin is scaled for total energy (printed and inside setup)
            Ekin *= self.tw_coeff
            t()
            t('Lambda:{0}'.format(self.tw_coeff))
            t('Correct eigenvalue:{0}'.format(e_j[0] * self.tw_coeff))
            t()

        t()
        t('Energy contributions:')
        t('-------------------------')
        t('Kinetic:   %+13.6f' % Ekin)
        t('XC:        %+13.6f' % Exc)
        t('Potential: %+13.6f' % e_coulomb)
        t('-------------------------')
        t('Total:     %+13.6f' % (Ekin + Exc + e_coulomb))
        self.ETotal = Ekin + Exc + e_coulomb
        t()

        t('state      eigenvalue         ekin         rmax')
        t('-----------------------------------------------')
        for m, l, f, e, u in zip(n_j, l_j, f_j, e_j, self.u_j):
            # Find kinetic energy:
            k = e - np.sum((
                np.where(abs(u) < 1e-160, 0, u)**2 *  # XXXNumeric!
                vr * dr)[1:] / r[1:])

            # Find outermost maximum:
            g = self.N - 4
            while u[g - 1] >= u[g]:
                g -= 1
            x = r[g - 1:g + 2]
            y = u[g - 1:g + 2]
            A = np.transpose(np.array([x**i for i in range(3)]))
            c, b, a = np.linalg.solve(A, y)
            assert a < 0.0
            rmax = -0.5 * b / a

            s = 'spdf'[l]
            t('%d%s^%-4.1f: %12.6f %12.6f %12.3f' % (m, s, f, e, k, rmax))
        t('-----------------------------------------------')
        t('(units: Bohr and Hartree)')

        for m, l, u in zip(n_j, l_j, self.u_j):
            self.write(u, 'ae', n=m, l=l)

        self.write(n, 'n')
        self.write(vr, 'vr')
        self.write(vHr, 'vHr')
        self.write(self.vXC, 'vXC')
        self.write(tau, 'tau')

        self.Ekin = Ekin
        self.e_coulomb = e_coulomb
        self.Exc = Exc
Example #11
0
    def calculate(self):
        ESIC = 0
        xc = self.paw.hamiltonian.xc
        assert xc.type == 'LDA'

        # Calculate the contribution from the core orbitals
        for a in self.paw.density.D_asp:
            setup = self.paw.density.setups[a]
            # TODO: Use XC which has been used to calculate the actual
            # calculation.
            # TODO: Loop over setups, not atoms.
            print('Atom core SIC for ', setup.symbol)
            print('%10s%10s%10s' %  ('E_xc[n_i]', 'E_Ha[n_i]', 'E_SIC'))
            g = Generator(setup.symbol, xcname='LDA', nofiles=True, txt=None)
            g.run(**parameters[setup.symbol])
            njcore = g.njcore
            for f, l, e, u in zip(g.f_j[:njcore], g.l_j[:njcore],
                                  g.e_j[:njcore], g.u_j[:njcore]):
                # Calculate orbital density
                # NOTE: It's spherically symmetrized!
                #n = np.dot(self.f_j,
                assert l == 0, ('Not tested for l>0 core states')
                na = np.where(abs(u) < 1e-160, 0,u)**2 / (4 * pi)
                na[1:] /= g.r[1:]**2
                na[0] = na[1]
                nb = np.zeros(g.N)
                v_sg = np.zeros((2, g.N)) 
                e_g = np.zeros(g.N)
                vHr = np.zeros(g.N)
                Exc = xc.calculate_spherical(g.rgd, np.array([na, nb]), v_sg)
                hartree(0, na * g.r * g.dr, g.r, vHr)
                EHa = 2*pi*np.dot(vHr*na*g.r , g.dr)
                print(('%10.2f%10.2f%10.2f' % (Exc * Hartree, EHa * Hartree,
                                               -f*(EHa+Exc) * Hartree)))
                ESIC += -f*(EHa+Exc)
                
        sic = SIC(finegrid=True, coulomb_factor=1, xc_factor=1)
        sic.initialize(self.paw.density, self.paw.hamiltonian, self.paw.wfs)
        sic.set_positions(self.paw.atoms.get_scaled_positions())
        
        print('Valence electron sic ')
        print('%10s%10s%10s%10s%10s%10s' % ('spin', 'k-point', 'band',
                                            'E_xc[n_i]', 'E_Ha[n_i]', 'E_SIC'))
        assert len(self.paw.wfs.kpt_u)==1, ('Not tested for bulk calculations')
        
        for s, spin in sic.spin_s.items():
            spin.initialize_orbitals()
            spin.update_optimal_states()
            spin.update_potentials()

            n = 0
            for xc, c in zip(spin.exc_m, spin.ecoulomb_m):
                print(('%10i%10i%10i%10.2f%10.2f%10.2f' %
                       (s, 0, n, -xc * Hartree, -c * Hartree,
                        2 * (xc + c) * Hartree)))
                n += 1

            ESIC += spin.esic
            
        print('Total correction for self-interaction energy:')
        print('%10.2f eV' % (ESIC * Hartree))
        print('New total energy:')
        total = (ESIC * Hartree + self.paw.get_potential_energy() +
                 self.paw.get_reference_energy())
        print('%10.2f eV' % total)
        return total
    def run(self, use_restart_file=True):
        #     beta g
        # r = ------, g = 0, 1, ..., N - 1
        #     N - g
        #
        #        rN
        # g = --------
        #     beta + r

        t = self.text
        N = self.N
        beta = self.beta
        t(N, 'radial gridpoints.')
        self.rgd = AERadialGridDescriptor(beta / N, 1.0 / N, N)
        g = np.arange(N, dtype=float)
        self.r = self.rgd.r_g
        self.dr = self.rgd.dr_g
        self.d2gdr2 = self.rgd.d2gdr2()

        # Number of orbitals:
        nj = len(self.n_j)

        # Radial wave functions multiplied by radius:
        self.u_j = np.zeros((nj, self.N))

        # Effective potential multiplied by radius:
        self.vr = np.zeros(N)

        # Electron density:
        self.n = np.zeros(N)

        # Always spinpaired nspins=1
        self.xc = XC(self.xcname)

        # Initialize for non-local functionals
        if self.xc.type == 'GLLB':
            self.xc.pass_stuff_1d(self)
            self.xc.initialize_1d()
            
        n_j = self.n_j
        l_j = self.l_j
        f_j = self.f_j
        e_j = self.e_j
        
        Z = self.Z    # nuclear charge
        r = self.r    # radial coordinate
        dr = self.dr  # dr/dg
        n = self.n    # electron density
        vr = self.vr  # effective potential multiplied by r

        vHr = np.zeros(self.N)
        self.vXC = np.zeros(self.N)

        restartfile = '%s/%s.restart' % (tempdir, self.symbol)
        if self.xc.type == 'GLLB' or not use_restart_file:
            # Do not start from initial guess when doing
            # non local XC!
            # This is because we need wavefunctions as well
            # on the first iteration.
            fd = None
        else:
            try:
                fd = open(restartfile, 'r')
            except IOError:
                fd = None
            else:
                try:
                    n[:] = pickle.load(fd)
                except (ValueError, IndexError):
                    fd = None
                else:
                    norm = np.dot(n * r**2, dr) * 4 * pi
                    if abs(norm - sum(f_j)) > 0.01:
                        fd = None
                    else:
                        t('Using old density for initial guess.')
                        n *= sum(f_j) / norm

        if fd is None:
            self.initialize_wave_functions()
            n[:] = self.calculate_density()

        bar = '|------------------------------------------------|'
        t(bar)
        
        niter = 0
        nitermax = 117
        qOK = log(1e-10)
        mix = 0.4
        
        # orbital_free needs more iterations and coefficient
        if self.orbital_free:
            #qOK = log(1e-14)
            e_j[0] /= self.tf_coeff
            mix = 0.01
            nitermax = 1000
            
        vrold = None
        
        while True:
            # calculate hartree potential
            hartree(0, n * r * dr, r, vHr)

            # add potential from nuclear point charge (v = -Z / r)
            vHr -= Z

            # calculated exchange correlation potential and energy
            self.vXC[:] = 0.0

            if self.xc.type == 'GLLB':
                # Update the potential to self.vXC an the energy to self.Exc
                Exc = self.xc.get_xc_potential_and_energy_1d(self.vXC)
            else:
                Exc = self.xc.calculate_spherical(self.rgd,
                                                  n.reshape((1, -1)),
                                                  self.vXC.reshape((1, -1)))

            # calculate new total Kohn-Sham effective potential and
            # admix with old version
            vr[:] = (vHr + self.vXC * r) / self.tf_coeff

            if niter > 0:
                vr[:] = mix * vr + (1 - mix) * vrold
            vrold = vr.copy()

            # solve Kohn-Sham equation and determine the density change
            self.solve()
            dn = self.calculate_density() - n
            n += dn

            # estimate error from the square of the density change integrated
            q = log(np.sum((r * dn)**2))

            # print progress bar
            if niter == 0:
                q0 = q
                b0 = 0
            else:
                b = int((q0 - q) / (q0 - qOK) * 50)
                if b > b0:
                    self.txt.write(bar[b0:min(b, 50)])
                    self.txt.flush()
                    b0 = b

            # check if converged and break loop if so
            if q < qOK:
                self.txt.write(bar[b0:])
                self.txt.flush()
                break

            niter += 1
            if niter > nitermax:
                raise RuntimeError('Did not converge!')

        tau = self.calculate_kinetic_energy_density()

        t()
        t('Converged in %d iteration%s.' % (niter, 's'[:niter != 1]))

        try:
            fd = open(restartfile, 'w')
        except IOError:
            pass
        else:
            pickle.dump(n, fd)
            try:
                os.chmod(restartfile, 0666)
            except OSError:
                pass

        Ekin = 0
        if self.orbital_free:
            e_j[0] *= self.tf_coeff
            vr *= self.tf_coeff
        
        for f, e in zip(f_j, e_j):
            Ekin += f * e

        Epot = 2 * pi * np.dot(n * r * (vHr - Z), dr)
        Ekin += -4 * pi * np.dot(n * vr * r, dr)

        t()
        t('Energy contributions:')
        t('-------------------------')
        t('Kinetic:   %+13.6f' % Ekin)
        t('XC:        %+13.6f' % Exc)
        t('Potential: %+13.6f' % Epot)
        t('-------------------------')
        t('Total:     %+13.6f' % (Ekin + Exc + Epot))
        self.ETotal = Ekin + Exc + Epot
        t()

        t('state      eigenvalue         ekin         rmax')
        t('-----------------------------------------------')
        for m, l, f, e, u in zip(n_j, l_j, f_j, e_j, self.u_j):
            # Find kinetic energy:
            k = e - np.sum((np.where(abs(u) < 1e-160, 0, u)**2 *  # XXXNumeric!
                            vr * dr)[1:] / r[1:])

            # Find outermost maximum:
            g = self.N - 4
            while u[g - 1] >= u[g]:
                g -= 1
            x = r[g - 1:g + 2]
            y = u[g - 1:g + 2]
            A = np.transpose(np.array([x**i for i in range(3)]))
            c, b, a = np.linalg.solve(A, y)
            assert a < 0.0
            rmax = -0.5 * b / a

            s = 'spdf'[l]
            t('%d%s^%-4.1f: %12.6f %12.6f %12.3f' % (m, s, f, e, k, rmax))
        t('-----------------------------------------------')
        t('(units: Bohr and Hartree)')

        for m, l, u in zip(n_j, l_j, self.u_j):
            self.write(u, 'ae', n=m, l=l)

        self.write(n, 'n')
        self.write(vr, 'vr')
        self.write(vHr, 'vHr')
        self.write(self.vXC, 'vXC')
        self.write(tau, 'tau')

        self.Ekin = Ekin
        self.Epot = Epot
        self.Exc = Exc
Example #13
0
File: kspot.py Project: qsnake/gpaw
   def get_spherical_ks_potential(self,a):
      #self.paw.restore_state()

      print "XC:", self.paw.hamiltonian.xc.name
      assert self.paw.hamiltonian.xc.type == 'LDA'

      # If the calculation is just loaded, density needs to be interpolated
      if self.paw.density.nt_sg is None:
         print "Interpolating density"
         self.paw.density.interpolate()
         
      # Get xccorr for atom a
      setup = self.paw.density.setups[a]
      xccorr = setup.xc_correction
      
      # Get D_sp for atom a
      D_sp = self.paw.density.D_asp[a]

      # density a function of L and partial wave radial pair density coefficient
      D_sLq = np.inner(D_sp, xccorr.B_pqL.T)

      # The 'spherical' spherical harmonic
      Y0 = 1.0/sqrt(4*pi)

      # Generate cartesian fine grid xc-potential
      print "Generate cartesian fine grid xc-potential"
      gd = self.paw.density.finegd
      vxct_sg = gd.zeros(1)
      xc = self.paw.hamiltonian.xc
      xc.calculate(gd, self.paw.density.nt_sg, vxct_sg)

      # ---------------------------------------------
      # The Electrostatic potential                  
      # ---------------------------------------------
      # V_ES(r) = Vt_ES(r) - Vt^a(r) + V^a(r), where
      # Vt^a = P[ nt^a(r) + \sum Q_L g_L(r) ]       
      # V^a = P[ -Z\delta(r) + n^a(r) ]             
      # P = Poisson solution
      # ---------------------------------------------

      print "Evaluating ES Potential..."
      # Make sure that the calculation has ES potential
      # TODO
      if self.paw.hamiltonian.vHt_g == None:
         raise "Converge tha Hartree potential first."
      
      # Interpolate the smooth electrostatic potential from fine grid to radial grid
      radHt_g = self.grid_to_radial(a, gd, self.paw.hamiltonian.vHt_g)
      radHt_g *= xccorr.rgd.r_g
      
      print "D_sp", D_sp

      # Calculate the difference in density and pseudo density
      dn_g = (Y0 * np.dot(D_sLq[0, 0], (xccorr.n_qg - xccorr.nt_qg)) +
              xccorr.nc_g - xccorr.nct_g)
      
      # Add the compensation charge contribution
      dn_g -= Y0 * self.paw.density.Q_aL[a][0] * setup.g_lg[0]
      
      # Calculate the Hartree potential for this
      vHr = np.zeros((xccorr.ng,))
      hartree(0, dn_g * xccorr.rgd.r_g * xccorr.rgd.dr_g, setup.beta, setup.ng, vHr)

      # Add the core potential contribution
      vHr -= setup.Z

      radHt_g += vHr
      
      # --------------------------------------------
      # The XC potential                           
      # --------------------------------------------
      # V_xc = Vt_xc(r) - Vt_xc^a(r) + V_xc^a(r)   
      # --------------------------------------------

      print "Evaluating xc potential"
      # Interpolate the smooth xc potential  from fine grid to radial grid
      radvxct_g = self.grid_to_radial(a, gd, vxct_sg[0])

      # Arrays for evaluating radial xc potential slice
      e_g = np.zeros((xccorr.ng,))
      vxc_sg = np.zeros((len(D_sp), xccorr.ng))

      for n, Y_L in enumerate(xccorr.Y_nL):
         n_sLg = np.dot(D_sLq, xccorr.n_qg)
         n_sLg[:, 0] += sqrt(4 * pi) * xccorr.nc_g
         vxc_sg[:] = 0.0
         xc.calculate_radial(xccorr.rgd, n_sLg, Y_L, vxc_sg)
         radvxct_g += weight_n[n] * vxc_sg[0]
         nt_sLg = np.dot(D_sLq, xccorr.nt_qg)
         nt_sLg[:, 0] += sqrt(4 * pi) *xccorr.nct_g
         vxc_sg[:] = 0.0
         xc.calculate_radial(xccorr.rgd, nt_sLg, Y_L, vxc_sg)
         radvxct_g -= weight_n[n] * vxc_sg[0]

      radvks_g = radvxct_g*xccorr.rgd.r_g + radHt_g
      return (xccorr.rgd.r_g, radvks_g)
Example #14
0
File: setup.py Project: qsnake/gpaw
 def H(n_g, l):
     yrrdr_g = np.zeros(gcut2)
     nrdr_g = n_g * r_g * dr_g
     hartree(l, nrdr_g, beta, ng, yrrdr_g)
     yrrdr_g *= r_g * dr_g
     return yrrdr_g
 def poisson(self, n_g, l=0):
     vr_g = self.zeros()
     nrdr_g = n_g * self.r_g * self.dr_g
     hartree(l, nrdr_g, self.r_g, vr_g)
     return vr_g
Example #16
0
    def get_spherical_ks_potential(self, a):
        #self.paw.restore_state()

        print "XC:", self.paw.hamiltonian.xc.name
        assert self.paw.hamiltonian.xc.type == 'LDA'

        # If the calculation is just loaded, density needs to be interpolated
        if self.paw.density.nt_sg is None:
            print "Interpolating density"
            self.paw.density.interpolate()

        # Get xccorr for atom a
        setup = self.paw.density.setups[a]
        xccorr = setup.xc_correction

        # Get D_sp for atom a
        D_sp = self.paw.density.D_asp[a]

        # density a function of L and partial wave radial pair density coefficient
        D_sLq = np.inner(D_sp, xccorr.B_pqL.T)

        # The 'spherical' spherical harmonic
        Y0 = 1.0 / sqrt(4 * pi)

        # Generate cartesian fine grid xc-potential
        print "Generate cartesian fine grid xc-potential"
        gd = self.paw.density.finegd
        vxct_sg = gd.zeros(1)
        xc = self.paw.hamiltonian.xc
        xc.calculate(gd, self.paw.density.nt_sg, vxct_sg)

        # ---------------------------------------------
        # The Electrostatic potential
        # ---------------------------------------------
        # V_ES(r) = Vt_ES(r) - Vt^a(r) + V^a(r), where
        # Vt^a = P[ nt^a(r) + \sum Q_L g_L(r) ]
        # V^a = P[ -Z\delta(r) + n^a(r) ]
        # P = Poisson solution
        # ---------------------------------------------

        print "Evaluating ES Potential..."
        # Make sure that the calculation has ES potential
        # TODO
        if self.paw.hamiltonian.vHt_g == None:
            raise "Converge tha Hartree potential first."

        # Interpolate the smooth electrostatic potential from fine grid to radial grid
        radHt_g = self.grid_to_radial(a, gd, self.paw.hamiltonian.vHt_g)
        radHt_g *= xccorr.rgd.r_g

        print "D_sp", D_sp

        # Calculate the difference in density and pseudo density
        dn_g = (Y0 * np.dot(D_sLq[0, 0], (xccorr.n_qg - xccorr.nt_qg)) +
                xccorr.nc_g - xccorr.nct_g)

        # Add the compensation charge contribution
        dn_g -= Y0 * self.paw.density.Q_aL[a][0] * setup.g_lg[0]

        # Calculate the Hartree potential for this
        vHr = np.zeros((xccorr.ng, ))
        hartree(0, dn_g * xccorr.rgd.r_g * xccorr.rgd.dr_g, setup.beta,
                setup.ng, vHr)

        # Add the core potential contribution
        vHr -= setup.Z

        radHt_g += vHr

        # --------------------------------------------
        # The XC potential
        # --------------------------------------------
        # V_xc = Vt_xc(r) - Vt_xc^a(r) + V_xc^a(r)
        # --------------------------------------------

        print "Evaluating xc potential"
        # Interpolate the smooth xc potential  from fine grid to radial grid
        radvxct_g = self.grid_to_radial(a, gd, vxct_sg[0])

        # Arrays for evaluating radial xc potential slice
        e_g = np.zeros((xccorr.ng, ))
        vxc_sg = np.zeros((len(D_sp), xccorr.ng))

        for n, Y_L in enumerate(xccorr.Y_nL):
            n_sLg = np.dot(D_sLq, xccorr.n_qg)
            n_sLg[:, 0] += sqrt(4 * pi) * xccorr.nc_g
            vxc_sg[:] = 0.0
            xc.calculate_radial(xccorr.rgd, n_sLg, Y_L, vxc_sg)
            radvxct_g += weight_n[n] * vxc_sg[0]
            nt_sLg = np.dot(D_sLq, xccorr.nt_qg)
            nt_sLg[:, 0] += sqrt(4 * pi) * xccorr.nct_g
            vxc_sg[:] = 0.0
            xc.calculate_radial(xccorr.rgd, nt_sLg, Y_L, vxc_sg)
            radvxct_g -= weight_n[n] * vxc_sg[0]

        radvks_g = radvxct_g * xccorr.rgd.r_g + radHt_g
        return (xccorr.rgd.r_g, radvks_g)