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
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
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
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
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)
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
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)
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, ))