Пример #1
0
    def nelec(self, mu):

        logger.debug1(self.__log__, "| requested mu={:.3e}".format(
            mu,
        ))

        result = []
        total = 0
        for ind, (i, c) in enumerate(zip(self.solvers, self.factors)):
            n = i.__hcore__.shape[0] // 2
            i.__hcore__[:n, :n] -= numpy.eye(n) * mu
            i.kernel()
            i.__hcore__[:n, :n] += numpy.eye(n) * mu
            dm = i.make_rdm1()
            result.append(numpy.diag(dm)[:n].sum())
            total += c*result[-1]
            logger.debug2(self.__log__, "| solver {:d} E={:.8f}".format(
                ind,
                i.e_tot,
            ))

        logger.debug1(self.__log__, "| occupations {} = {:.3e}".format(
            "+".join("{:.1f}*{:.3f}".format(i, j) for i, j in zip(self.factors, result)),
            total,
        ))

        return total-self.target
Пример #2
0
 def dump_flags(self, verbose=None):
     logger.info(self, '******** %s ********', self.__class__)
     logger.info(self, 'lebedev_order = %s (%d grids per sphere)',
                 self.lebedev_order, gen_grid.LEBEDEV_ORDER[self.lebedev_order])
     logger.info(self, 'lmax = %s'         , self.lmax)
     logger.info(self, 'eta = %s'          , self.eta)
     logger.info(self, 'eps = %s'          , self.eps)
     logger.debug2(self, 'radii_table %s', self.radii_table)
     if self.atom_radii:
         logger.info(self, 'User specified atomic radii %s', str(self.atom_radii))
     self.grids.dump_flags(verbose)
     return self
Пример #3
0
 def dump_flags(self, verbose=None):
     logger.info(self, 'radial grids: %s', self.radi_method.__doc__)
     logger.info(self, 'becke partition: %s', self.becke_scheme.__doc__)
     logger.info(self, 'pruning grids: %s', self.prune)
     logger.info(self, 'grids dens level: %d', self.level)
     logger.info(self, 'symmetrized grids: %s', self.symmetry)
     if self.radii_adjust is not None:
         logger.info(self, 'atomic radii adjust function: %s',
                     self.radii_adjust)
         logger.debug2(self, 'atomic_radii : %s', self.atomic_radii)
     if self.atom_grid:
         logger.info(self, 'User specified grid scheme %s', str(self.atom_grid))
     return self
Пример #4
0
    def sr_loop(self, kpti_kptj=numpy.zeros((2,3)), max_memory=2000,
                compact=True, blksize=None):
        '''Short range part'''
        kpti, kptj = kpti_kptj
        unpack = is_zero(kpti-kptj) and not compact
        is_real = is_zero(kpti_kptj)
        nao = self.cell.nao_nr()
        if blksize is None:
            if is_real:
                if unpack:
                    blksize = max_memory*1e6/8/(nao*(nao+1)//2+nao**2*2)
                else:
                    blksize = max_memory*1e6/8/(nao*(nao+1)*2)
            else:
                blksize = max_memory*1e6/16/(nao**2*3)
            blksize = max(16, min(int(blksize), self.blockdim))
            logger.debug2(self, 'max_memory %d MB, blksize %d', max_memory, blksize)

        if unpack:
            buf = numpy.empty((blksize,nao*(nao+1)//2))
        def load(Lpq, b0, b1, bufR, bufI):
            Lpq = numpy.asarray(Lpq[b0:b1])
            if is_real:
                if unpack:
                    LpqR = lib.unpack_tril(Lpq, out=bufR).reshape(-1,nao**2)
                else:
                    LpqR = Lpq
                LpqI = numpy.zeros_like(LpqR)
            else:
                shape = Lpq.shape
                if unpack:
                    tmp = numpy.ndarray(shape, buffer=buf)
                    tmp[:] = Lpq.real
                    LpqR = lib.unpack_tril(tmp, out=bufR).reshape(-1,nao**2)
                    tmp[:] = Lpq.imag
                    LpqI = lib.unpack_tril(tmp, lib.ANTIHERMI, out=bufI).reshape(-1,nao**2)
                else:
                    LpqR = numpy.ndarray(shape, buffer=bufR)
                    LpqR[:] = Lpq.real
                    LpqI = numpy.ndarray(shape, buffer=bufI)
                    LpqI[:] = Lpq.imag
            return LpqR, LpqI

        LpqR = LpqI = j3cR = j3cI = None
        with self.load_Lpq(kpti_kptj) as Lpq:
            naux = Lpq.shape[0]
            with self.load_j3c(kpti_kptj) as j3c:
                for b0, b1 in lib.prange(0, naux, blksize):
                    LpqR, LpqI = load(Lpq, b0, b1, LpqR, LpqI)
                    j3cR, j3cI = load(j3c, b0, b1, j3cR, j3cI)
                    yield LpqR, LpqI, j3cR, j3cI
Пример #5
0
def _ewald_exxdiv_for_G0(cell, kpts, dms, vk):
    if kpts is None or numpy.shape(kpts) == (3, ):
        ovlp = cell.pbc_intor('cint1e_ovlp_sph', hermi=1)
        madelung = tools.pbc.madelung(cell, numpy.zeros(3))
        for i, dm in enumerate(dms):
            vk[i] += madelung * reduce(numpy.dot, (ovlp, dm, ovlp))
    else:
        ovlp = cell.pbc_intor('cint1e_ovlp_sph', hermi=1, kpts=kpts)
        weight = 1. / dms.shape[1]
        madelung = weight * len(kpts) * tools.pbc.madelung(cell, kpts)
        for k, s in enumerate(ovlp):
            for i, dm in enumerate(dms):
                vk[i, k] += madelung * reduce(numpy.dot, (s, dm[k], s))
    logger.debug2(
        cell, 'Total energy shift = -1/2 * Nelec*madelung/cell.vol = %.12g',
        madelung * cell.nelectron * -.5)
Пример #6
0
 def dump_flags(self, verbose=None):
     logger.info(self, '******** %s (In testing) ********', self.__class__)
     logger.warn(self, 'ddPCM is an experimental feature. It is '
                 'still in testing.\nFeatures and APIs may be changed '
                 'in the future.')
     logger.info(self, 'lebedev_order = %s (%d grids per sphere)',
                 self.lebedev_order, gen_grid.LEBEDEV_ORDER[self.lebedev_order])
     logger.info(self, 'lmax = %s'         , self.lmax)
     logger.info(self, 'eta = %s'          , self.eta)
     logger.info(self, 'eps = %s'          , self.eps)
     logger.info(self, 'frozen = %s'       , self.frozen)
     logger.info(self, 'equilibrium_solvation = %s', self.equilibrium_solvation)
     logger.debug2(self, 'radii_table %s', self.radii_table)
     if self.atom_radii:
         logger.info(self, 'User specified atomic radii %s', str(self.atom_radii))
     self.grids.dump_flags(verbose)
     return self
Пример #7
0
def _ewald_exxdiv_for_G0(cell, kpts, dms, vk, kpts_band=None):
    s = cell.pbc_intor('cint1e_ovlp_sph', hermi=1, kpts=kpts)
    madelung = tools.pbc.madelung(cell, kpts)
    if kpts is None:
        for i,dm in enumerate(dms):
            vk[i] += madelung * reduce(numpy.dot, (s, dm, s))
    elif numpy.shape(kpts) == (3,):
        if kpts_band is None or is_zero(kpts_band-kpts):
            for i,dm in enumerate(dms):
                vk[i] += madelung * reduce(numpy.dot, (s, dm, s))
    else:  # kpts.shape == (*,3)
        if kpts_band is None:
            for k in range(len(kpts)):
                for i,dm in enumerate(dms):
                    vk[i,k] += madelung * reduce(numpy.dot, (s[k], dm[k], s[k]))
        else:
            kpts_band = kpts_band.reshape(-1,3)
            for k, kpt in enumerate(kpts):
                for kp in member(kpt, kpts_band):
                    for i,dm in enumerate(dms):
                        vk[i,kp] += madelung * reduce(numpy.dot, (s[k], dm[k], s[k]))
    logger.debug2(cell, 'Total energy shift = -1/2 * Nelec*madelung/cell.vol = %.12g',
                  madelung*cell.nelectron * -.5)
Пример #8
0
    def kernel(self, tolerance="default", maxiter=30):
        """
        Performs a self-consistent DMET calculation.
        Args:
            tolerance (float): convergence criterion;
            maxiter (int): maximal number of iterations;
        """
        if tolerance == "default":
            tolerance = self.conv_tol

        self.convergence_history = []

        # mixers = dict((k, diis.DIIS()) for k in self.__domains__.keys())

        while True:

            logger.info(self.__mol__, "DMET step {:d}".format(
                len(self.convergence_history),
            ))

            mf = self.run_mf_kernel()

            umat = {}

            logger.debug1(self.__mol__, "Mean-field solver total energy E = {:.10f}".format(
                mf.e_tot,
            ))

            self.e_tot = 0
            total_occupation = 0

            domain_ids = []
            embedded_solvers = []
            replica_numbers = []
            schmidt_bases = []

            # Build embedded solvers
            logger.info(self.__mol__, "Building embedded solvers ...")
            for domain_id, domain_basis, schmidt_basis in self.iter_schmidt_basis():

                domain_ids.append(domain_id)
                if self.__style__ == "interacting-bath":
                    embedded_solvers.append(self.get_embedded_solver(schmidt_basis))
                elif self.__style__ == "non-interacting-bath":
                    embedded_solvers.append(self.get_embedded_solver(schmidt_basis, kind=domain_id))
                else:
                    raise ValueError("Internal error: unknown style '{}'".format(self.__style__))
                replica_numbers.append(len(self.__domains__[domain_id]))
                schmidt_bases.append(schmidt_basis[2:])

            # Fit chemical potential
            logger.info(self.__mol__, "Fitting chemical potential ...")
            GlobalChemicalPotentialFit(
                embedded_solvers,
                replica_numbers,
                self.__mol__.nelectron,
                log=self.__mol__,
            ).kernel()

            # Fit the u-matrix
            logger.info(self.__mol__, "Fitting the u-matrix ...")
            for domain_id, embedded_solver, schmidt_basis, nreplica in zip(domain_ids, embedded_solvers, schmidt_bases, replica_numbers):

                logger.debug(self.__mol__, "Domain {}".format(domain_id))
                logger.debug1(self.__mol__, "Primary basis: {}".format(self.__domains__[domain_id][0]))
                if len(self.__domains__[domain_id]) > 1:
                    for i, b in enumerate(self.__domains__[domain_id][1:]):
                        logger.debug1(self.__mol__, "Secondary basis {:d}: {}".format(i, b))

                logger.debug1(self.__mol__, "Correlated solver total energy E = {:.10f}".format(
                    embedded_solver.e_tot,
                ))

                n_active_domain = schmidt_basis[0].shape[1]
                # TODO: fix this; no need to recalculate hcore
                partial_energy = embedded_solver.partial_etot(
                    slice(n_active_domain),
                    transform(
                        self.__mf_solver__.get_hcore(),
                        self.__orthogonal_basis_inv__.T.dot(numpy.concatenate(schmidt_basis, axis=1)),
                    ),
                )
                self.e_tot += nreplica * partial_energy

                logger.debug1(self.__mol__, "Correlated solver partial energy E = {:.10f}".format(
                    partial_energy,
                ))

                partial_occupation = embedded_solver.partial_nelec(slice(n_active_domain))
                total_occupation += nreplica * partial_occupation

                logger.debug1(self.__mol__, "Correlated solver partial occupation N = {:.10f}".format(
                    partial_occupation,
                ))

                logger.debug2(self.__mol__, "Correlated solver density matrix: {}".format(embedded_solver.make_rdm1()))

                if tolerance is not None:
                    # Continue with self-consistency
                    nscf_mf = NonSelfConsistentMeanField(mf)
                    nscf_mf.kernel()

                    sc = self.__self_consistency__(
                        nscf_mf,
                        self.__orthogonal_basis__.dot(numpy.concatenate(schmidt_basis, axis=1)),
                        embedded_solver,
                        log=self.__mol__,
                    )
                    sc.kernel(x0=None)

                    local_umat = sc.parametrize_umat_full(sc.final_parameters)
                    umat[domain_id] = local_umat

                    logger.debug(self.__mol__, "Parameters: {}".format(
                        sc.final_parameters,
                    ))

            self.e_tot += mf.energy_nuc()

            if tolerance is not None:
                self.convergence_history.append(self.convergence_measure(umat))
                self.umat = umat
                # self.umat = dict((k, mixers[k].update(umat[k])) for k in self.__domains__.keys())

                logger.info(self.__mol__, "E = {:.10f} delta = {:.3e} q = {:.3e} max(umat) = {:.3e}".format(
                    self.e_tot,
                    self.convergence_history[-1],
                    self.__mol__.nelectron - total_occupation,
                    max(v.max() for v in self.umat.values()),
                ))

            else:

                logger.info(self.__mol__, "E = {:.10f} q = {:.3e}".format(
                    self.e_tot,
                    self.__mol__.nelectron - total_occupation,
                ))

            if tolerance is None or self.convergence_history[-1] < tolerance:
                return self.e_tot

            if maxiter is not None and len(self.convergence_history) >= maxiter:
                raise RuntimeError("The maximal number of iterations {:d} reached. The error {:.3e} is still above the requested tolerance of {:.3e}".format(
                    maxiter,
                    self.convergence_history[-1],
                    tolerance,
                ))