def calculate(self, e_g, n_sg, dedn_sg,
               sigma_xg=None, dedsigma_xg=None,
               tau_sg=None, dedtau_sg=None):
     n_g = n_sg[0]
     m_vg = n_sg[1:4]
     m_g = (m_vg**2).sum(0)**0.5
     nnew_sg = np.empty((2,) + n_g.shape)
     nnew_sg[:] = n_g
     nnew_sg[0] += m_g
     nnew_sg[1] -= m_g
     nnew_sg *= 0.5
     vnew_sg = np.zeros_like(nnew_sg)
     LibXC.calculate(self, e_g, nnew_sg, vnew_sg)
     dedn_sg[0] += 0.5 * vnew_sg.sum(0)
     vnew_sg /= np.where(m_g < 1e-15, 1, m_g)
     dedn_sg[1:4] += 0.5 * vnew_sg[0] * m_vg
     dedn_sg[1:4] -= 0.5 * vnew_sg[1] * m_vg
Exemplo n.º 2
0
 def calculate(self,
               e_g,
               n_sg,
               dedn_sg,
               sigma_xg=None,
               dedsigma_xg=None,
               tau_sg=None,
               dedtau_sg=None):
     n_g = n_sg[0]
     m_vg = n_sg[1:4]
     m_g = (m_vg**2).sum(0)**0.5
     nnew_sg = np.empty((2, ) + n_g.shape)
     nnew_sg[:] = n_g
     nnew_sg[0] += m_g
     nnew_sg[1] -= m_g
     nnew_sg *= 0.5
     vnew_sg = np.zeros_like(nnew_sg)
     LibXC.calculate(self, e_g, nnew_sg, vnew_sg)
     dedn_sg[0] += 0.5 * vnew_sg.sum(0)
     vnew_sg /= np.where(m_g < 1e-15, 1, m_g)
     dedn_sg[1:4] += 0.5 * vnew_sg[0] * m_vg
     dedn_sg[1:4] -= 0.5 * vnew_sg[1] * m_vg
Exemplo n.º 3
0
class VDWFunctional(GGA):
    """Base class for vdW-DF."""

    def __init__(
        self,
        name,
        world=None,
        q0cut=5.0,
        phi0=0.5,
        ds=1.0,
        Dmax=20.0,
        nD=201,
        ndelta=21,
        soft_correction=False,
        kernel=None,
        Zab=None,
        vdwcoef=1.0,
        verbose=False,
        energy_only=False,
    ):
        """vdW-DF.

        parameters:

        name: str
            Name of functional.
        world: MPI communicator
            Communicator to parallelize over.  Defaults to gpaw.mpi.world.
        q0cut: float
            Maximum value for q0.
        phi0: float
            Smooth value for phi(0,0).
        ds: float
            Cutoff for smooth kernel.
        Dmax: float
            Maximum value for D.
        nD: int
            Number of values for D in kernel-table.
        ndelta: int
            Number of values for delta in kernel-table.
        soft_correction: bool
            Correct for soft kernel.
        kernel:
            Which kernel to use.
        Zab:
            parameter in nonlocal kernel.
        vdwcoef: float
            Scaling of vdW energy.
        verbose: bool
            Print useful information.
        """

        if world is None:
            self.world = mpi.world
        else:
            self.world = world

        self.q0cut = q0cut
        self.phi0 = phi0
        self.ds = ds

        self.delta_i = np.linspace(0, 1.0, ndelta)
        self.D_j = np.linspace(0, Dmax, nD)

        self.verbose = verbose

        self.read_table()

        self.soft_correction = soft_correction
        if soft_correction:
            dD = self.D_j[1]
            self.C_soft = np.dot(self.D_j ** 2, self.phi_ij[0]) * 4 * pi * dD

        self.gd = None
        self.energy_only = energy_only
        self.timer = nulltimer

        if name == "vdW-DF":
            assert kernel is None and Zab is None
            kernel = LibXC("GGA_X_PBE_R+LDA_C_PW")
            Zab = -0.8491
        elif name == "vdW-DF2":
            assert kernel is None and Zab is None
            kernel = LibXC("GGA_X_RPW86+LDA_C_PW")
            Zab = -1.887
        elif name == "optPBE-vdW":
            assert kernel is None and Zab is None
            kernel = LibXC("GGA_X_OPTPBE_VDW+LDA_C_PW")
            Zab = -0.8491
        elif name == "optB88-vdW":
            assert kernel is None and Zab is None
            kernel = LibXC("GGA_X_OPTB88_VDW+LDA_C_PW")
            Zab = -0.8491
        elif name == "C09-vdW":
            assert kernel is None and Zab is None
            kernel = LibXC("GGA_X_C09X+LDA_C_PW")
            Zab = -0.8491
        else:
            assert kernel is not None and Zab is not None

        self.Zab = Zab
        GGA.__init__(self, kernel)
        self.vdwcoef = vdwcoef
        self.name = name
        self.LDAc = LibXC("LDA_C_PW")

    def get_setup_name(self):
        return "revPBE"

    def initialize(self, density, hamiltonian, wfs, occupations):
        self.timer = wfs.timer

    def get_Ecnl(self):
        return self.Ecnl

    def calculate_gga(self, e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg):
        GGA.calculate_gga(self, e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg)

        eLDAc_g = self.gd.empty()
        vLDAc_sg = self.gd.zeros(1)

        if self.vdwcoef == 0.0:
            return

        if len(n_sg) == 1:
            self.LDAc.calculate(eLDAc_g, n_sg, vLDAc_sg)
            e = self.get_non_local_energy(n_sg[0], sigma_xg[0], eLDAc_g, vLDAc_sg[0], dedn_sg[0], dedsigma_xg[0])
        else:
            n_sg = n_sg.sum(0)
            n_sg.shape = (1,) + n_sg.shape
            self.LDAc.calculate(eLDAc_g, n_sg, vLDAc_sg)
            v_g = np.zeros_like(e_g)
            deda2nl_g = np.zeros_like(e_g)
            a2_g = sigma_xg[0] + 2 * sigma_xg[1] + sigma_xg[2]
            e = self.get_non_local_energy(n_sg[0], a2_g, eLDAc_g, vLDAc_sg[0], v_g, deda2nl_g)
            dedsigma_xg[0] += self.vdwcoef * deda2nl_g
            dedsigma_xg[1] += self.vdwcoef * 2 * deda2nl_g
            dedsigma_xg[2] += self.vdwcoef * deda2nl_g
            dedn_sg += self.vdwcoef * v_g

        if self.gd.comm.rank == 0:
            e_g[0, 0, 0] += self.vdwcoef * e / self.gd.dv

    def get_non_local_energy(self, n_g=None, a2_g=None, e_LDAc_g=None, v_LDAc_g=None, v_g=None, deda2_g=None):
        """Calculate non-local correlation energy.

        parameters:

        n_g: ndarray
            Density.
        a2_g: ndarray
            Absolute value of the gradient of the density - squared.
        e_LDAc_g: ndarray
            LDA correlation energy density.
        """

        gd = self.gd

        n_g = n_g.clip(1e-7, np.inf)

        # Calculate q0 and cut it off smoothly at q0cut:
        kF_g = (3 * pi ** 2 * n_g) ** (1.0 / 3.0)
        q0_g, dhdx_g = hRPS(kF_g - 4 * pi / 3 * e_LDAc_g / n_g - self.Zab / 36 / kF_g * a2_g / n_g ** 2, self.q0cut)

        if self.verbose:
            print ("VDW: q0 (min, mean, max): (%f, %f, %f)" % (q0_g.min(), q0_g.mean(), q0_g.max()))

        if self.soft_correction:
            dEcnl = gd.integrate(n_g ** 2 / q0_g ** 3) * 0.5 * self.C_soft
        else:
            dEcnl = 0.0

        # Distribute density and q0 to all processors:
        n_g = gd.collect(n_g, broadcast=True)
        q0_g = gd.collect(q0_g, broadcast=True)

        if not self.energy_only:
            self.dhdx_g = gd.collect(dhdx_g, broadcast=True)

        Ecnl = self.calculate_6d_integral(n_g, q0_g, a2_g, e_LDAc_g, v_LDAc_g, v_g, deda2_g)
        Ecnl += dEcnl
        self.Ecnl = Ecnl
        return Ecnl

    def read_table(self):
        name = "phi-%.3f-%.3f-%.3f-%d-%d.pckl" % (self.phi0, self.ds, self.D_j[-1], len(self.delta_i), len(self.D_j))

        if "GPAW_VDW" in os.environ:
            print "Use of GPAW_VDW is deprecated."
            print "Put", name, "in your GPAW_SETUP_PATH directory."
            dirs = [os.environ["GPAW_VDW"]]
        else:
            dirs = setup_paths + ["."]

        for dir in dirs:
            filename = os.path.join(dir, name)
            if os.path.isfile(filename):
                self.phi_ij = pickle.load(open(filename))
                if self.verbose:
                    print "VDW: using", filename
                return

        print "VDW: Could not find table file:", name
        self.make_table(name)

    def make_table(self, name):
        print "VDW: Generating vdW-DF kernel ..."
        print "VDW:",
        ndelta = len(self.delta_i)
        nD = len(self.D_j)
        self.phi_ij = np.zeros((ndelta, nD))
        for i in range(self.world.rank, ndelta, self.world.size):
            print ndelta - i,
            sys.stdout.flush()
            delta = self.delta_i[i]
            for j in range(nD - 1, -1, -1):
                D = self.D_j[j]
                d = D * (1.0 + delta)
                dp = D * (1.0 - delta)
                if d ** 2 + dp ** 2 > self.ds ** 2:
                    self.phi_ij[i, j] = phi(d, dp)
                else:
                    P = np.polyfit(
                        [0, self.D_j[j + 1] ** 2, self.D_j[j + 2] ** 2],
                        [self.phi0, self.phi_ij[i, j + 1], self.phi_ij[i, j + 2]],
                        2,
                    )
                    self.phi_ij[i, : j + 3] = np.polyval(P, self.D_j[: j + 3] ** 2)
                    break

        self.world.sum(self.phi_ij)

        print
        print "VDW: Done!"
        if self.world.rank == 0:
            pickle.dump(self.phi_ij, open(name, "w"), pickle.HIGHEST_PROTOCOL)

    def make_prl_plot(self, multiply_by_4_pi_D_squared=True):
        import pylab as plt

        x = np.linspace(0, 8.0, 100)
        for delta in [0, 0.5, 0.9]:
            y = [self.phi(D * (1.0 + delta), D * (1.0 - delta)) for D in x]
            if multiply_by_4_pi_D_squared:
                y *= 4 * pi * x ** 2
            plt.plot(x, y, label=r"$\delta=%.1f$" % delta)
        plt.legend(loc="best")
        plt.plot(x, np.zeros(len(x)), "k-")
        plt.xlabel("D")
        plt.ylabel(r"$4\pi D^2 \phi(\rm{Hartree})$")
        plt.show()

    def phi(self, d, dp):
        """Kernel function.

        Uses bi-linear interpolation and returns zero for D > Dmax.
        """

        P = self.phi_ij
        D = (d + dp) / 2.0
        if D < 1e-14:
            return P[0, 0]
        if D >= self.D_j[-1]:
            return 0.0

        delta = abs((d - dp) / (2 * D))
        ddelta = self.delta_i[1]
        x = delta / ddelta
        i = int(x)
        if i == len(self.delta_i) - 1:
            i -= 1
            x = 1.0
        else:
            x -= i

        dD = self.D_j[1]
        y = D / dD
        j = int(y)
        y -= j
        return x * (y * P[i + 1, j + 1] + (1 - y) * P[i + 1, j]) + (1 - x) * (y * P[i, j + 1] + (1 - y) * P[i, j])
Exemplo n.º 4
0
class BEEVDWKernel(XCKernel):
    """Kernel for BEEVDW functionals."""
    def __init__(self, bee, xcoefs, ldac, ggac):
        """BEEVDW kernel.

        parameters:

        bee : str
            choose BEE1 or BEE2 exchange basis expansion.
        xcoefs : array
            coefficients for exchange.
        ldac : float
            coefficient for LDA correlation.
        pbec : float
            coefficient for PBE correlation.

        """

        if bee == 'BEE2':
            self.BEE = BEE2(xcoefs)
            self.GGAc = LibXC('GGA_C_PBE')
            self.xtype = 'GGA'
            self.type = 'GGA'
        elif bee == 'BEE3':
            self.BEE = LibXC('MGGA_X_MBEEFVDW')
            self.GGAc = LibXC('GGA_C_PBE_SOL')
            self.xtype = 'MGGA'
            self.type = 'MGGA'
        else:
            raise ValueError('Unknown BEE exchange: %s', bee)

        self.LDAc = LibXC('LDA_C_PW')
        self.ldac = ldac
        self.ggac = ggac
        if bee in ['BEE1', 'BEE2']:
            self.ggac -= 1.0
        self.name = 'BEEVDW'

    def calculate(self,
                  e_g,
                  n_sg,
                  dedn_sg,
                  sigma_xg=None,
                  dedsigma_xg=None,
                  tau_sg=None,
                  dedtau_sg=None):
        if debug:
            self.check_arguments(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg,
                                 tau_sg, dedtau_sg)

        if self.xtype == 'GGA':
            self.BEE.calculate(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg)
        elif self.xtype == 'MGGA':
            self.BEE.calculate(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg,
                               tau_sg, dedtau_sg)
        else:
            raise ValueError('Unexpected value of xtype:', self.xtype)

        e0_g = np.empty_like(e_g)
        dedn0_sg = np.empty_like(dedn_sg)
        dedsigma0_xg = np.empty_like(dedsigma_xg)
        for coef, kernel in [(self.ldac, self.LDAc), (self.ggac, self.GGAc)]:
            dedn0_sg[:] = 0.0
            kernel.calculate(e0_g, n_sg, dedn0_sg, sigma_xg, dedsigma0_xg)
            e_g += coef * e0_g
            dedn_sg += coef * dedn0_sg
            if kernel.type == 'GGA':
                dedsigma_xg += coef * dedsigma0_xg
Exemplo n.º 5
0
class CXGGAKernel:
    def __init__(self, just_kidding=False):
        self.just_kidding = just_kidding
        self.type = 'GGA'
        self.lda_c = LibXC('LDA_C_PW')
        if self.just_kidding:
            self.name = 'purepython rPW86_with_%s' % self.lda_c.name
        else:
            self.name = 'purepython cx'

    def calculate(self, e_g, n_sg, v_sg, sigma_xg, dedsigma_xg):
        e_g[:] = 0.0
        dedsigma_xg[:] = 0.0

        self.lda_c.calculate(e_g, n_sg, v_sg, sigma_xg, dedsigma_xg)

        for arr in [n_sg, v_sg, sigma_xg, dedsigma_xg]:
            assert len(arr) == 1
        self._exchange(n_sg[0], sigma_xg[0], e_g, v_sg[0], dedsigma_xg[0])

    def _exchange(self, rho, grho, sx, v1x, v2x):
        """Calculate cx local exchange.

        Note that this *adds* to the energy density sx so that it can
        be called after LDA correlation part without ruining anything.
        Also it adds to v1x and v2x as is normal in GPAW."""
        tol = 1e-20
        rho[rho < tol] = tol
        grho[grho < tol] = tol
        alp = 0.021789
        beta = 1.15
        a = 1.851
        b = 17.33
        c = 0.163
        mu_LM = 0.09434
        s_prefactor = 6.18733545256027
        Ax = -0.738558766382022  # = -3./4. * (3./pi)**(1./3)
        four_thirds = 4. / 3.

        grad_rho = np.sqrt(grho)

        # eventually we need s to power 12.  Clip to avoid overflow
        # (We have individual tolerances on both rho and grho, but
        # they are not sufficient to guarantee this)
        s_1 = (grad_rho / (s_prefactor * rho**four_thirds)).clip(0.0, 1e20)
        s_2 = s_1 * s_1
        s_3 = s_2 * s_1
        s_4 = s_3 * s_1
        s_5 = s_4 * s_1
        s_6 = s_5 * s_1

        fs_rPW86 = (1.0 + a * s_2 + b * s_4 + c * s_6)**(1. / 15.)

        if self.just_kidding:
            fs = fs_rPW86
        else:
            fs = (1.0 + mu_LM * s_2) / (1.0 + alp * s_6) \
                + alp * s_6 / (beta + alp * s_6) * fs_rPW86

        # the energy density for the exchange.
        sx[:] += Ax * rho**four_thirds * fs

        df_rPW86_ds = (1. / (15. * fs_rPW86**14.0)) * \
            (2 * a * s_1 + 4 * b * s_3 + 6 * c * s_5)

        if self.just_kidding:
            df_ds = df_rPW86_ds  # XXXXXXXXXXXXXXXXXXXX
        else:
            df_ds = 1. / (1. + alp * s_6)**2 \
                * (2.0 * mu_LM * s_1 * (1. + alp * s_6) -
                   6.0 * alp * s_5 * (1. + mu_LM * s_2)) \
                + alp * s_6 / (beta + alp * s_6) * df_rPW86_ds \
                + 6.0 * alp * s_5 * fs_rPW86 / (beta + alp * s_6) \
                * (1. - alp * s_6 / (beta + alp * s_6))

        # de/dn.  This is the partial derivative of sx wrt. n, for s constant
        v1x[:] += Ax * four_thirds * (rho**(1. / 3.) * fs - grad_rho /
                                      (s_prefactor * rho) * df_ds)
        # de/d(nabla n).  The other partial derivative
        v2x[:] += 0.5 * Ax * df_ds / (s_prefactor * grad_rho)
Exemplo n.º 6
0
class VDWFunctionalBase:
    """Base class for vdW-DF."""
    def __init__(self,
                 world=None,
                 Zab=-0.8491,
                 vdwcoef=1.0,
                 q0cut=5.0,
                 phi0=0.5,
                 ds=1.0,
                 Dmax=20.0,
                 nD=201,
                 ndelta=21,
                 soft_correction=False,
                 setup_name='revPBE',
                 verbose=False,
                 energy_only=False):
        """vdW-DF.

        parameters:

        name: str
            Name of functional.
        world: MPI communicator
            Communicator to parallelize over.  Defaults to gpaw.mpi.world.
        q0cut: float
            Maximum value for q0.
        phi0: float
            Smooth value for phi(0,0).
        ds: float
            Cutoff for smooth kernel.
        Dmax: float
            Maximum value for D.
        nD: int
            Number of values for D in kernel-table.
        ndelta: int
            Number of values for delta in kernel-table.
        soft_correction: bool
            Correct for soft kernel.
        kernel:
            Which kernel to use.
        Zab:
            parameter in nonlocal kernel.
        vdwcoef: float
            Scaling of vdW energy.
        verbose: bool
            Print useful information.
        """

        if world is None:
            self.world = mpi.world
        else:
            self.world = world

        self.Zab = Zab
        self.vdwcoef = vdwcoef
        self.q0cut = q0cut
        self.phi0 = phi0
        self.ds = ds

        self.delta_i = np.linspace(0, 1.0, ndelta)
        self.D_j = np.linspace(0, Dmax, nD)

        self.verbose = verbose

        self.read_table()

        self.soft_correction = soft_correction
        if soft_correction:
            dD = self.D_j[1]
            self.C_soft = np.dot(self.D_j**2, self.phi_ij[0]) * 4 * pi * dD

        self.gd = None
        self.energy_only = energy_only
        self.timer = nulltimer

        self.LDAc = LibXC('LDA_C_PW')
        self.setup_name = setup_name

    def get_setup_name(self):
        return self.setup_name

    def get_Ecnl(self):
        return self.Ecnl

    def calculate_impl(self, gd, n_sg, v_sg, e_g):
        sigma_xg, dedsigma_xg, gradn_svg = gga_vars(gd, self.grad_v, n_sg)
        self.calculate_exchange(e_g, n_sg, v_sg, sigma_xg, dedsigma_xg)
        self.calculate_correlation(e_g, n_sg, v_sg, sigma_xg, dedsigma_xg)
        add_gradient_correction(self.grad_v, gradn_svg, sigma_xg, dedsigma_xg,
                                v_sg)

    def calculate_exchange(self, e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg):
        raise NotImplementedError

    def calculate_correlation(self, e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg):
        eLDAc_g = self.gd.empty()
        vLDAc_sg = self.gd.zeros(1)

        if self.vdwcoef == 0.0:
            return

        if len(n_sg) == 1:
            self.LDAc.calculate(eLDAc_g, n_sg, vLDAc_sg)
            e = self.get_non_local_energy(n_sg[0], sigma_xg[0], eLDAc_g,
                                          vLDAc_sg[0], dedn_sg[0],
                                          dedsigma_xg[0])
        else:
            n_sg = n_sg.sum(0)
            n_sg.shape = (1, ) + n_sg.shape
            self.LDAc.calculate(eLDAc_g, n_sg, vLDAc_sg)
            v_g = np.zeros_like(e_g)
            deda2nl_g = np.zeros_like(e_g)
            a2_g = sigma_xg[0] + 2 * sigma_xg[1] + sigma_xg[2]
            e = self.get_non_local_energy(n_sg[0], a2_g, eLDAc_g, vLDAc_sg[0],
                                          v_g, deda2nl_g)
            dedsigma_xg[0] += self.vdwcoef * deda2nl_g
            dedsigma_xg[1] += self.vdwcoef * 2 * deda2nl_g
            dedsigma_xg[2] += self.vdwcoef * deda2nl_g
            dedn_sg += self.vdwcoef * v_g

        if self.gd.comm.rank == 0:
            e_g[0, 0, 0] += self.vdwcoef * e / self.gd.dv

    def get_non_local_energy(self,
                             n_g=None,
                             a2_g=None,
                             e_LDAc_g=None,
                             v_LDAc_g=None,
                             v_g=None,
                             deda2_g=None):
        """Calculate non-local correlation energy.

        parameters:

        n_g: ndarray
            Density.
        a2_g: ndarray
            Absolute value of the gradient of the density - squared.
        e_LDAc_g: ndarray
            LDA correlation energy density.
        """

        gd = self.gd

        n_g = n_g.clip(1e-7, np.inf)

        # Calculate q0 and cut it off smoothly at q0cut:
        kF_g = (3 * pi**2 * n_g)**(1.0 / 3.0)
        q0_g, dhdx_g = hRPS(
            kF_g - 4 * pi / 3 * e_LDAc_g / n_g -
            self.Zab / 36 / kF_g * a2_g / n_g**2, self.q0cut)

        if self.verbose:
            print(('VDW: q0 (min, mean, max): (%f, %f, %f)' %
                   (q0_g.min(), q0_g.mean(), q0_g.max())))

        if self.soft_correction:
            dEcnl = -gd.integrate(n_g**2 / q0_g**3) * 0.5 * self.C_soft
        else:
            dEcnl = 0.0

        # Distribute density and q0 to all processors:
        n_g = gd.collect(n_g, broadcast=True)
        q0_g = gd.collect(q0_g, broadcast=True)

        if not self.energy_only:
            self.dhdx_g = gd.collect(dhdx_g, broadcast=True)

        Ecnl = self.calculate_6d_integral(n_g, q0_g, a2_g, e_LDAc_g, v_LDAc_g,
                                          v_g, deda2_g)
        Ecnl += dEcnl
        self.Ecnl = Ecnl
        return Ecnl

    def read_table(self):
        name = ('phi-%.3f-%.3f-%.3f-%d-%d.txt' %
                (self.phi0, self.ds, self.D_j[-1], len(
                    self.delta_i), len(self.D_j)))
        dirs = setup_paths + ['.']

        for dir in dirs:
            filename = os.path.join(dir, name)
            if os.path.isfile(filename):
                self.phi_ij = np.loadtxt(filename)
                if self.verbose:
                    print('VDW: using', filename)
                return

        if sys.version_info[0] == 2:
            oldname = name[:-3] + 'pckl'
            for dir in dirs:
                filename = os.path.join(dir, oldname)
                if os.path.isfile(filename):
                    self.phi_ij = pickle.load(open(filename, 'rb'))
                    if self.verbose:
                        print('VDW: using', filename)
                    return

        print('VDW: Could not find table file:', name)
        self.make_table(name)

    def make_table(self, name):
        print('VDW: Generating vdW-DF kernel ...')
        print('VDW:', end=' ')
        ndelta = len(self.delta_i)
        nD = len(self.D_j)
        self.phi_ij = np.zeros((ndelta, nD))
        for i in range(self.world.rank, ndelta, self.world.size):
            print(ndelta - i, end=' ')
            sys.stdout.flush()
            delta = self.delta_i[i]
            for j in range(nD - 1, -1, -1):
                D = self.D_j[j]
                d = D * (1.0 + delta)
                dp = D * (1.0 - delta)
                if d**2 + dp**2 > self.ds**2:
                    with seterr(divide='ignore'):
                        self.phi_ij[i, j] = phi(d, dp)
                else:
                    P = np.polyfit([0, self.D_j[j + 1]**2, self.D_j[j + 2]**2],
                                   [
                                       self.phi0, self.phi_ij[i, j + 1],
                                       self.phi_ij[i, j + 2]
                                   ], 2)
                    self.phi_ij[i, :j + 3] = np.polyval(P, self.D_j[:j + 3]**2)
                    break

        self.world.sum(self.phi_ij)

        print()
        print('VDW: Done!')
        header = ('phi0={0:.3f}, ds={1:.3f}, Dmax={2:.3f}, nD={3}, ndelta={4}'.
                  format(self.phi0, self.ds, self.D_j[-1], len(self.delta_i),
                         len(self.D_j)))
        if self.world.rank == 0:
            np.savetxt(name, self.phi_ij, header=header)

    def make_prl_plot(self, multiply_by_4_pi_D_squared=True):
        import pylab as plt
        x = np.linspace(0, 8.0, 100)
        for delta in [0, 0.5, 0.9]:
            y = [self.phi(D * (1.0 + delta), D * (1.0 - delta)) for D in x]
            if multiply_by_4_pi_D_squared:
                y *= 4 * pi * x**2
            plt.plot(x, y, label=r'$\delta=%.1f$' % delta)
        plt.legend(loc='best')
        plt.plot(x, np.zeros(len(x)), 'k-')
        plt.xlabel('D')
        plt.ylabel(r'$4\pi D^2 \phi(\rm{Hartree})$')
        plt.show()

    def phi(self, d, dp):
        """Kernel function.

        Uses bi-linear interpolation and returns zero for D > Dmax.
        """

        P = self.phi_ij
        D = (d + dp) / 2.0
        if D < 1e-14:
            return P[0, 0]
        if D >= self.D_j[-1]:
            return 0.0

        delta = abs((d - dp) / (2 * D))
        ddelta = self.delta_i[1]
        x = delta / ddelta
        i = int(x)
        if i == len(self.delta_i) - 1:
            i -= 1
            x = 1.0
        else:
            x -= i

        dD = self.D_j[1]
        y = D / dD
        j = int(y)
        y -= j
        return (x * (y * P[i + 1, j + 1] + (1 - y) * P[i + 1, j]) + (1 - x) *
                (y * P[i, j + 1] + (1 - y) * P[i, j]))
Exemplo n.º 7
0
class TB09Kernel:
    name = 'TB09'
    type = 'MGGA'
    alpha = -0.012
    beta = 1.023

    def __init__(self, c=None):
        self.tb09 = LibXC('MGGA_X_TB09').xc.tb09
        self.ldac = LibXC('LDA_C_PW')

        self.fixedc = c is not None  # calculate c or use fixed value
        self.c = c  # amount of "exact exchange"
        self.n = 0  # Lebedev quadrature point number (0-49)
        self.sign = 1.0  # sign of PAW correction: +1 for AE and -1 for PS
        self.I = None  # integral from Eq. (3)

    def calculate(self, e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg, tau_sg,
                  dedtau_sg):
        ns = len(n_sg)
        n_sg[n_sg < 1e-6] = 1e-6

        if n_sg.ndim == 4:
            if not self.fixedc:
                if self.c is None:
                    # We don't have the integral yet - just use 1.0:
                    self.c = 1.0
                else:
                    self.I = self.world.sum(self.I)
                    self.c = (self.alpha + self.beta *
                              (self.I / self.gd.volume)**0.5)

                # Start calculation of c for use in the next SCF step:
                if ns == 1:
                    gradn_g = sigma_xg[0]**0.5
                else:
                    gradn_g = (sigma_xg[0] + 2 * sigma_xg[1] +
                               sigma_xg[2])**0.5
                self.I = self.gd.integrate(gradn_g / n_sg.sum(0))
                # The domain is not distributed like the PAW corrections:
                self.I /= self.world.size

            lapl_sg = self.gd.empty(ns)
            for n_g, lapl_g in zip(n_sg, lapl_sg):
                self.lapl.apply(n_g, lapl_g)

        else:
            rgd = self.rgd
            lapl_sg = []
            for n_Lg in self.n_sLg:
                lapl_g = rgd.laplace(np.dot(self.Y_L, n_Lg))
                l = 0
                L1 = 0
                while L1 < len(self.Y_L):
                    L2 = L1 + 2 * l + 1
                    n_g = np.dot(self.Y_L[L1:L2], n_Lg[L1:L2])
                    with seterr(divide='ignore', invalid='ignore'):
                        lapl_g -= l * (l + 1) * n_g / rgd.r_g**2
                    lapl_g[0] = 0.0
                    L1 = L2
                    l += 1
                lapl_sg.append(lapl_g)

            if not self.fixedc:
                # PAW corrections to integral:
                w = self.sign * weight_n[self.n]
                if ns == 1:
                    gradn_g = sigma_xg[0]**0.5
                else:
                    gradn_g = (sigma_xg[0] + 2 * sigma_xg[1] +
                               sigma_xg[2])**0.5
                self.I += w * rgd.integrate(gradn_g / n_sg.sum(0))

                self.n += 1
                if self.n == len(weight_n):
                    self.n = 0
                    self.sign = -self.sign

        # dedn_sg[:] = 0.0
        sigma_xg[sigma_xg < 1e-10] = 1e-10
        tau_sg[tau_sg < 1e-10] = 1e-10

        for n_g, sigma_g, lapl_g, tau_g, v_g in zip(n_sg, sigma_xg[::2],
                                                    lapl_sg, tau_sg, dedn_sg):
            self.tb09(self.c, n_g.ravel(), sigma_g, lapl_g, tau_g, v_g,
                      dedsigma_xg)

        self.ldac.calculate(e_g, n_sg, dedn_sg)
        e_g[:] = 0.0

        dedsigma_xg[:] = 0.0
        dedtau_sg[:] = 0.0
Exemplo n.º 8
0
class BEEVDWKernel(XCKernel):
    """Kernel for BEEVDW functionals."""
    def __init__(self, bee, xcoefs, ldac, ggac):
        """BEEVDW kernel.

        parameters:

        bee : str
            choose BEE1 or BEE2 exchange basis expansion.
        xcoefs : array
            coefficients for exchange.
        ldac : float
            coefficient for LDA correlation.
        pbec : float
            coefficient for PBE correlation.

        """

        if bee == 'BEE2':
            self.BEE = BEE2(xcoefs)
            self.GGAc = LibXC('GGA_C_PBE')
            self.xtype = 'GGA'
            self.type = 'GGA'
        elif bee == 'BEE3':
            self.BEE = LibXC('MGGA_X_MBEEFVDW')
            self.GGAc = LibXC('GGA_C_PBE_SOL')
            self.xtype = 'MGGA'
            self.type = 'MGGA'
        else:
            raise ValueError('Unknown BEE exchange: %s', bee)

        self.LDAc = LibXC('LDA_C_PW')
        self.ldac = ldac
        self.ggac = ggac
        if bee in ['BEE1', 'BEE2']:
            self.ggac -= 1.0
        self.name = 'BEEVDW'

    def calculate(self, e_g, n_sg, dedn_sg,
                  sigma_xg=None, dedsigma_xg=None,
                  tau_sg=None, dedtau_sg=None):
        if debug:
            self.check_arguments(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg,
                                 tau_sg, dedtau_sg)

        if self.xtype == 'GGA':
            self.BEE.calculate(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg)
        elif self.xtype == 'MGGA':
            self.BEE.calculate(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg,
                               tau_sg, dedtau_sg)
        else:
            raise ValueError('Unexpected value of xtype:', self.xtype)

        e0_g = np.empty_like(e_g)
        dedn0_sg = np.empty_like(dedn_sg)
        dedsigma0_xg = np.empty_like(dedsigma_xg)
        for coef, kernel in [(self.ldac, self.LDAc),
                             (self.ggac, self.GGAc)]:
            dedn0_sg[:] = 0.0
            kernel.calculate(e0_g, n_sg, dedn0_sg, sigma_xg, dedsigma0_xg)
            e_g += coef * e0_g
            dedn_sg += coef * dedn0_sg
            if kernel.type == 'GGA':
                dedsigma_xg += coef * dedsigma0_xg
Exemplo n.º 9
0
class VDWFunctional(GGA):
    """Base class for vdW-DF."""
    def __init__(self,
                 name,
                 world=None,
                 q0cut=5.0,
                 phi0=0.5,
                 ds=1.0,
                 Dmax=20.0,
                 nD=201,
                 ndelta=21,
                 soft_correction=False,
                 kernel=None,
                 Zab=None,
                 vdwcoef=1.0,
                 verbose=False,
                 energy_only=False):
        """vdW-DF.

        parameters:

        name: str
            Name of functional.
        world: MPI communicator
            Communicator to parallelize over.  Defaults to gpaw.mpi.world.
        q0cut: float
            Maximum value for q0.
        phi0: float
            Smooth value for phi(0,0).
        ds: float
            Cutoff for smooth kernel.
        Dmax: float
            Maximum value for D.
        nD: int
            Number of values for D in kernel-table.
        ndelta: int
            Number of values for delta in kernel-table.
        soft_correction: bool
            Correct for soft kernel.
        kernel:
            Which kernel to use.
        Zab:
            parameter in nonlocal kernel.
        vdwcoef: float
            Scaling of vdW energy.
        verbose: bool
            Print useful information.
        """

        if world is None:
            self.world = mpi.world
        else:
            self.world = world

        self.q0cut = q0cut
        self.phi0 = phi0
        self.ds = ds

        self.delta_i = np.linspace(0, 1.0, ndelta)
        self.D_j = np.linspace(0, Dmax, nD)

        self.verbose = verbose

        self.read_table()

        self.soft_correction = soft_correction
        if soft_correction:
            dD = self.D_j[1]
            self.C_soft = np.dot(self.D_j**2, self.phi_ij[0]) * 4 * pi * dD

        self.gd = None
        self.energy_only = energy_only
        self.timer = nulltimer

        if name == 'vdW-DF':
            assert kernel is None and Zab is None
            kernel = LibXC('GGA_X_PBE_R+LDA_C_PW')
            Zab = -0.8491
        elif name == 'vdW-DF2':
            assert kernel is None and Zab is None
            kernel = LibXC('GGA_X_PW86+LDA_C_PW')
            Zab = -1.887

        self.Zab = Zab
        GGA.__init__(self, kernel)
        self.vdwcoef = vdwcoef
        self.name = name
        self.LDAc = LibXC('LDA_C_PW')

    def get_setup_name(self):
        return 'revPBE'

    def initialize(self, density, hamiltonian, wfs, occupations):
        self.timer = wfs.timer

    def calculate_gga(self, e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg):
        GGA.calculate_gga(self, e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg)

        eLDAc_g = self.gd.empty()
        vLDAc_sg = self.gd.zeros(1)

        if self.vdwcoef == 0.0:
            return

        if len(n_sg) == 1:
            self.LDAc.calculate(eLDAc_g, n_sg, vLDAc_sg)
            e = self.get_non_local_energy(n_sg[0], sigma_xg[0], eLDAc_g,
                                          vLDAc_sg[0], dedn_sg[0],
                                          dedsigma_xg[0])
        else:
            n_sg = n_sg.sum(0)
            n_sg.shape = (1, ) + n_sg.shape
            self.LDAc.calculate(eLDAc_g, n_sg, vLDAc_sg)
            v_g = np.zeros_like(e_g)
            deda2nl_g = np.zeros_like(e_g)
            a2_g = sigma_xg[0] + 2 * sigma_xg[1] + sigma_xg[2]
            e = self.get_non_local_energy(n_sg[0], a2_g, eLDAc_g, vLDAc_sg[0],
                                          v_g, deda2nl_g)
            dedsigma_xg[0] += self.vdwcoef * deda2nl_g
            dedsigma_xg[1] += self.vdwcoef * 2 * deda2nl_g
            dedsigma_xg[2] += self.vdwcoef * deda2nl_g
            dedn_sg += self.vdwcoef * v_g

        if self.gd.comm.rank == 0:
            e_g[0, 0, 0] += self.vdwcoef * e / self.gd.dv

    def get_non_local_energy(self,
                             n_g=None,
                             a2_g=None,
                             e_LDAc_g=None,
                             v_LDAc_g=None,
                             v_g=None,
                             deda2_g=None):
        """Calculate non-local correlation energy.

        parameters:

        n_g: ndarray
            Density.
        a2_g: ndarray
            Absolute value of the gradient of the density - squared.
        e_LDAc_g: ndarray
            LDA correlation energy density.
        """

        gd = self.gd

        n_g = n_g.clip(1e-7, np.inf)

        # Calculate q0 and cut it off smoothly at q0cut:
        kF_g = (3 * pi**2 * n_g)**(1.0 / 3.0)
        q0_g, dhdx_g = hRPS(
            kF_g - 4 * pi / 3 * e_LDAc_g / n_g -
            self.Zab / 36 / kF_g * a2_g / n_g**2, self.q0cut)

        if self.verbose:
            print('VDW: q0 (min, mean, max): (%f, %f, %f)' %
                  (q0_g.min(), q0_g.mean(), q0_g.max()))

        if self.soft_correction:
            dEcnl = gd.integrate(n_g**2 / q0_g**3) * 0.5 * self.C_soft
        else:
            dEcnl = 0.0

        # Distribute density and q0 to all processors:
        n_g = gd.collect(n_g, broadcast=True)
        q0_g = gd.collect(q0_g, broadcast=True)

        if not self.energy_only:
            self.dhdx_g = gd.collect(dhdx_g, broadcast=True)

        Ecnl = self.calculate_6d_integral(n_g, q0_g, a2_g, e_LDAc_g, v_LDAc_g,
                                          v_g, deda2_g)
        return Ecnl + dEcnl

    def read_table(self):
        name = ('phi-%.3f-%.3f-%.3f-%d-%d.pckl' %
                (self.phi0, self.ds, self.D_j[-1], len(
                    self.delta_i), len(self.D_j)))

        if 'GPAW_VDW' in os.environ:
            print 'Use of GPAW_VDW is deprecated.'
            print 'Put', name, 'in your GPAW_SETUP_PATH directory.'
            dirs = [os.environ['GPAW_VDW']]
        else:
            dirs = setup_paths + ['.']

        for dir in dirs:
            filename = os.path.join(dir, name)
            if os.path.isfile(filename):
                self.phi_ij = pickle.load(open(filename))
                if self.verbose:
                    print 'VDW: using', filename
                return

        print 'VDW: Could not find table file:', name
        self.make_table(name)

    def make_table(self, name):
        print 'VDW: Generating vdW-DF kernel ...'
        print 'VDW:',
        ndelta = len(self.delta_i)
        nD = len(self.D_j)
        self.phi_ij = np.zeros((ndelta, nD))
        for i in range(self.world.rank, ndelta, self.world.size):
            print ndelta - i,
            sys.stdout.flush()
            delta = self.delta_i[i]
            for j in range(nD - 1, -1, -1):
                D = self.D_j[j]
                d = D * (1.0 + delta)
                dp = D * (1.0 - delta)
                if d**2 + dp**2 > self.ds**2:
                    self.phi_ij[i, j] = phi(d, dp)
                else:
                    P = np.polyfit([0, self.D_j[j + 1]**2, self.D_j[j + 2]**2],
                                   [
                                       self.phi0, self.phi_ij[i, j + 1],
                                       self.phi_ij[i, j + 2]
                                   ], 2)
                    self.phi_ij[i, :j + 3] = np.polyval(P, self.D_j[:j + 3]**2)
                    break

        self.world.sum(self.phi_ij)

        print
        print 'VDW: Done!'
        if self.world.rank == 0:
            pickle.dump(self.phi_ij, open(name, 'w'), pickle.HIGHEST_PROTOCOL)

    def make_prl_plot(self, multiply_by_4_pi_D_squared=True):
        import pylab as plt
        x = np.linspace(0, 8.0, 100)
        for delta in [0, 0.5, 0.9]:
            y = [self.phi(D * (1.0 + delta), D * (1.0 - delta)) for D in x]
            if multiply_by_4_pi_D_squared:
                y *= 4 * pi * x**2
            plt.plot(x, y, label=r'$\delta=%.1f$' % delta)
        plt.legend(loc='best')
        plt.plot(x, np.zeros(len(x)), 'k-')
        plt.xlabel('D')
        plt.ylabel(r'$4\pi D^2 \phi(\rm{Hartree})$')
        plt.show()

    def phi(self, d, dp):
        """Kernel function.

        Uses bi-linear interpolation and returns zero for D > Dmax.
        """

        P = self.phi_ij
        D = (d + dp) / 2.0
        if D < 1e-14:
            return P[0, 0]
        if D >= self.D_j[-1]:
            return 0.0

        delta = abs((d - dp) / (2 * D))
        ddelta = self.delta_i[1]
        x = delta / ddelta
        i = int(x)
        if i == len(self.delta_i) - 1:
            i -= 1
            x = 1.0
        else:
            x -= i

        dD = self.D_j[1]
        y = D / dD
        j = int(y)
        y -= j
        return (x * (y * P[i + 1, j + 1] + (1 - y) * P[i + 1, j]) + (1 - x) *
                (y * P[i, j + 1] + (1 - y) * P[i, j]))