def build(self, j_only=None, with_j3c=True, kpts_band=None): if self.kpts_band is not None: self.kpts_band = numpy.reshape(self.kpts_band, (-1,3)) if kpts_band is not None: kpts_band = numpy.reshape(kpts_band, (-1,3)) if self.kpts_band is None: self.kpts_band = kpts_band else: self.kpts_band = unique(numpy.vstack((self.kpts_band,kpts_band)))[0] self.check_sanity() self.dump_flags() self.auxcell = make_modrho_basis(self.cell, self.auxbasis, self.exp_to_discard) # Remove duplicated k-points. Duplicated kpts may lead to a buffer # located in incore.wrap_int3c larger than necessary. Integral code # only fills necessary part of the buffer, leaving some space in the # buffer unfilled. uniq_idx = unique(self.kpts)[1] kpts = numpy.asarray(self.kpts)[uniq_idx] if self.kpts_band is None: kband_uniq = numpy.zeros((0,3)) else: kband_uniq = [k for k in self.kpts_band if len(member(k, kpts))==0] if j_only is None: j_only = self._j_only if j_only: kall = numpy.vstack([kpts,kband_uniq]) kptij_lst = numpy.hstack((kall,kall)).reshape(-1,2,3) else: kptij_lst = [(ki, kpts[j]) for i, ki in enumerate(kpts) for j in range(i+1)] kptij_lst.extend([(ki, kj) for ki in kband_uniq for kj in kpts]) kptij_lst.extend([(ki, ki) for ki in kband_uniq]) kptij_lst = numpy.asarray(kptij_lst) if with_j3c: if isinstance(self._cderi_to_save, str): cderi = self._cderi_to_save else: cderi = self._cderi_to_save.name if isinstance(self._cderi, str): if self._cderi == cderi and os.path.isfile(cderi): logger.warn(self, 'DF integrals in %s (specified by ' '._cderi) is overwritten by GDF ' 'initialization. ', cderi) else: logger.warn(self, 'Value of ._cderi is ignored. ' 'DF integrals will be saved in file %s .', cderi) self._cderi = cderi t1 = (logger.process_clock(), logger.perf_counter()) self._make_j3c(self.cell, self.auxcell, kptij_lst, cderi) t1 = logger.timer_debug1(self, 'j3c', *t1) return self
def solve_mo1(nmrobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): '''Solve the first order equation Kwargs: with_cphf : boolean or function(dm_mo) => v1_mo If a boolean value is given, the value determines whether CPHF equation will be solved or not. The induced potential will be generated by the function gen_vind. If a function is given, CPHF equation will be solved, and the given function is used to compute induced potential ''' cput1 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(nmrobj.stdout, nmrobj.verbose) if mo_energy is None: mo_energy = nmrobj._scf.mo_energy if mo_coeff is None: mo_coeff = nmrobj._scf.mo_coeff if mo_occ is None: mo_occ = nmrobj._scf.mo_occ if with_cphf is None: with_cphf = nmrobj.cphf mol = nmrobj.mol orboa = mo_coeff[0][:, mo_occ[0] > 0] orbob = mo_coeff[1][:, mo_occ[1] > 0] if h1 is None: dm0 = nmrobj._scf.make_rdm1(mo_coeff, mo_occ) h1 = nmrobj.get_fock(dm0) h1 = (lib.einsum('xpq,pi,qj->xij', h1[0], mo_coeff[0].conj(), orboa), lib.einsum('xpq,pi,qj->xij', h1[1], mo_coeff[1].conj(), orbob)) cput1 = log.timer('first order Fock matrix', *cput1) if s1 is None: s1 = nmrobj.get_ovlp(mol) s1 = (lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[0].conj(), orboa), lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[1].conj(), orbob)) if with_cphf: if callable(with_cphf): vind = with_cphf else: vind = gen_vind(nmrobj._scf, mo_coeff, mo_occ) mo10, mo_e10 = ucphf.solve(vind, mo_energy, mo_occ, h1, s1, nmrobj.max_cycle_cphf, nmrobj.conv_tol, verbose=log) else: mo10, mo_e10 = _solve_mo1_uncoupled(mo_energy, mo_occ, h1, s1) logger.timer(nmrobj, 'solving mo1 eqn', *cput1) return mo10, mo_e10
def kernel(mycc, eris=None, t1=None, t2=None, max_cycle=50, tol=1e-8, tolnormt=1e-6, verbose=None): log = logger.new_logger(mycc, verbose) if eris is None: eris = mycc.ao2mo(mycc.mo_coeff) if t1 is None and t2 is None: t1, t2 = mycc.get_init_guess(eris) elif t2 is None: t2 = mycc.get_init_guess(eris)[1] cput1 = cput0 = (logger.process_clock(), logger.perf_counter()) eold = 0 eccsd = mycc.energy(t1, t2, eris) log.info('Init E_corr(QCISD) = %.15g', eccsd) if isinstance(mycc.diis, lib.diis.DIIS): adiis = mycc.diis elif mycc.diis: adiis = lib.diis.DIIS(mycc, mycc.diis_file, incore=mycc.incore_complete) adiis.space = mycc.diis_space else: adiis = None conv = False for istep in range(max_cycle): t1new, t2new = mycc.update_amps(t1, t2, eris) tmpvec = mycc.amplitudes_to_vector(t1new, t2new) tmpvec -= mycc.amplitudes_to_vector(t1, t2) normt = numpy.linalg.norm(tmpvec) tmpvec = None if mycc.iterative_damping < 1.0: alpha = mycc.iterative_damping t1new = (1 - alpha) * t1 + alpha * t1new t2new *= alpha t2new += (1 - alpha) * t2 t1, t2 = t1new, t2new t1new = t2new = None t1, t2 = mycc.run_diis(t1, t2, istep, normt, eccsd - eold, adiis) eold, eccsd = eccsd, mycc.energy(t1, t2, eris) log.info( 'cycle = %d E_corr(QCISD) = %.15g dE = %.9g norm(t1,t2) = %.6g', istep + 1, eccsd, eccsd - eold, normt) cput1 = log.timer('QCISD iter', *cput1) if abs(eccsd - eold) < tol and normt < tolnormt: conv = True break log.timer('QCISD', *cput0) return conv, eccsd, t1, t2
def get_jk(self, mol=None, dm=None, hermi=1, with_j=True, with_k=True, omega=None): if mol is None: mol = self.mol if dm is None: dm = self.make_rdm1() t0 = (logger.process_clock(), logger.perf_counter()) if self.direct_scf and self.opt is None: self.opt = self.init_direct_scf(mol) vj, vk = get_jk(mol, dm, hermi, self.opt, with_j, with_k) logger.timer(self, 'vj and vk', *t0) return vj, vk
def _make_shared_1e(self): cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(self.stdout, self.verbose) t1, t2, eris = self.t1, self.t2, self.eris self.Loo = imd.Loo(t1, t2, eris) self.Lvv = imd.Lvv(t1, t2, eris) self.Fov = imd.cc_Fov(t1, t2, eris) log.timer('EOM-CCSD shared one-electron intermediates', *cput0)
def kernel(self, x0=None, nstates=None): '''TDHF diagonalization with non-Hermitian eigenvalue solver ''' cpu0 = (logger.process_clock(), logger.perf_counter()) self.check_sanity() self.dump_flags() if nstates is None: nstates = self.nstates else: self.nstates = nstates log = logger.Logger(self.stdout, self.verbose) vind, hdiag = self.gen_vind(self._scf) precond = self.get_precond(hdiag) if x0 is None: x0 = self.init_guess(self._scf, self.nstates) ensure_real = self._scf.mo_coeff.dtype == numpy.double def pickeig(w, v, nroots, envs): realidx = numpy.where((abs(w.imag) < REAL_EIG_THRESHOLD) & (w.real > self.positive_eig_threshold))[0] # FIXME: Should the amplitudes be real? It also affects x2c-tdscf return lib.linalg_helper._eigs_cmplx2real(w, v, realidx, ensure_real) self.converged, w, x1 = \ lib.davidson_nosym1(vind, x0, precond, tol=self.conv_tol, nroots=nstates, lindep=self.lindep, max_cycle=self.max_cycle, max_space=self.max_space, pick=pickeig, verbose=log) nocc = (self._scf.mo_occ > 0).sum() nmo = self._scf.mo_occ.size nvir = nmo - nocc self.e = w def norm_xy(z): x, y = z.reshape(2, nocc, nvir) norm = lib.norm(x)**2 - lib.norm(y)**2 norm = numpy.sqrt(1. / norm) return x * norm, y * norm self.xy = [norm_xy(z) for z in x1] if self.chkfile: lib.chkfile.save(self.chkfile, 'tddft/e', self.e) lib.chkfile.save(self.chkfile, 'tddft/xy', self.xy) log.timer('TDDFT', *cpu0) self._finalize() return self.e, self.xy
def _make_shared_2e(self): cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(self.stdout, self.verbose) t1, t2, eris = self.t1, self.t2, self.eris # 2 virtuals self.Wovov = imd.Wovov(t1, t2, eris) self.Wovvo = imd.Wovvo(t1, t2, eris) self.Woovv = np.asarray(eris.ovov).transpose(0, 2, 1, 3) log.timer('EOM-CCSD shared two-electron intermediates', *cput0)
def kernel(self, x0=None, nstates=None): '''TDHF diagonalization with non-Hermitian eigenvalue solver ''' cpu0 = (logger.process_clock(), logger.perf_counter()) self.check_sanity() self.dump_flags() if nstates is None: nstates = self.nstates else: self.nstates = nstates log = logger.Logger(self.stdout, self.verbose) vind, hdiag = self.gen_vind(self._scf) precond = self.get_precond(hdiag) if x0 is None: x0 = self.init_guess(self._scf, self.nstates) # We only need positive eigenvalues def pickeig(w, v, nroots, envs): realidx = numpy.where((abs(w.imag) < REAL_EIG_THRESHOLD) & (w.real > self.positive_eig_threshold))[0] # If the complex eigenvalue has small imaginary part, both the # real part and the imaginary part of the eigenvector can # approximately be used as the "real" eigen solutions. return lib.linalg_helper._eigs_cmplx2real(w, v, realidx, real_eigenvectors=True) self.converged, w, x1 = \ lib.davidson_nosym1(vind, x0, precond, tol=self.conv_tol, nroots=nstates, lindep=self.lindep, max_cycle=self.max_cycle, max_space=self.max_space, pick=pickeig, verbose=log) nocc = (self._scf.mo_occ>0).sum() nmo = self._scf.mo_occ.size nvir = nmo - nocc self.e = w def norm_xy(z): x, y = z.reshape(2,nocc,nvir) norm = lib.norm(x)**2 - lib.norm(y)**2 norm = numpy.sqrt(.5/norm) # normalize to 0.5 for alpha spin return x*norm, y*norm self.xy = [norm_xy(z) for z in x1] if self.chkfile: lib.chkfile.save(self.chkfile, 'tddft/e', self.e) lib.chkfile.save(self.chkfile, 'tddft/xy', self.xy) log.timer('TDDFT', *cpu0) self._finalize() return self.e, self.xy
def _make_qmo_eris_outcore(agf2, eri, coeffs): ''' Returns H5 dataset ''' cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(agf2.stdout, agf2.verbose) nmo = eri.nmo ci, cj, ca = coeffs ni = ci.shape[1] nj = cj.shape[1] na = ca.shape[1] npair = nmo * (nmo + 1) // 2 mask = get_frozen_mask(agf2) frozen = np.sum(~mask) # possible to have incore MO, outcore QMO if getattr(eri, 'feri', None) is None: eri.feri = lib.H5TmpFile() elif 'qmo' in eri.feri: del eri.feri['qmo'] eri.feri.create_dataset('qmo', (nmo - frozen, ni, nj, na), 'f8') blksize = _agf2.get_blksize(agf2.max_memory, (nmo * npair, nj * na, npair), (nmo * ni, nj * na)) blksize = min(nmo, max(BLKMIN, blksize)) log.debug1('blksize (ragf2._make_qmo_eris_outcore) = %d', blksize) tril2sq = lib.square_mat_in_trilu_indices(nmo) q1 = 0 for p0, p1 in lib.prange(0, nmo, blksize): if not np.any(mask[p0:p1]): # block is fully frozen continue inds = np.arange(p0, p1)[mask[p0:p1]] q0, q1 = q1, q1 + len(inds) idx = list(np.concatenate(tril2sq[inds])) buf = eri.eri[idx] # (blk, nmo, npair) buf = buf.reshape((q1 - q0) * nmo, -1) # (blk*nmo, npair) jasym, nja, cja, sja = ao2mo.incore._conc_mos(cj, ca, compact=True) buf = ao2mo._ao2mo.nr_e2(buf, cja, sja, 's2kl', 's1') buf = buf.reshape(q1 - q0, nmo, nj, na) buf = lib.einsum('xpja,pi->xija', buf, ci) eri.feri['qmo'][q0:q1] = np.asarray(buf, order='C') log.timer('QMO integral transformation', *cput0) return eri.feri['qmo']
def _make_eris_outcore(mycc, mo_coeff=None): cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(mycc.stdout, mycc.verbose) eris = _ChemistsERIs() eris._common_init_(mycc, mo_coeff) mol = mycc.mol mo_coeff = eris.mo_coeff nocc = eris.nocc nao, nmo = mo_coeff.shape nvir = nmo - nocc eris.feri1 = lib.H5TmpFile() eris.oooo = eris.feri1.create_dataset('oooo', (nocc,nocc,nocc,nocc), 'f8') eris.ovoo = eris.feri1.create_dataset('ovoo', (nocc,nvir,nocc,nocc), 'f8', chunks=(nocc,1,nocc,nocc)) eris.ovov = eris.feri1.create_dataset('ovov', (nocc,nvir,nocc,nvir), 'f8', chunks=(nocc,1,nocc,nvir)) eris.ovvo = eris.feri1.create_dataset('ovvo', (nocc,nvir,nvir,nocc), 'f8', chunks=(nocc,1,nvir,nocc)) eris.ovvv = eris.feri1.create_dataset('ovvv', (nocc,nvir,nvir,nvir), 'f8') eris.oovv = eris.feri1.create_dataset('oovv', (nocc,nocc,nvir,nvir), 'f8', chunks=(nocc,nocc,1,nvir)) eris.vvvv = eris.feri1.create_dataset('vvvv', (nvir,nvir,nvir,nvir), 'f8') max_memory = max(MEMORYMIN, mycc.max_memory-lib.current_memory()[0]) ftmp = lib.H5TmpFile() ao2mo.full(mol, mo_coeff, ftmp, max_memory=max_memory, verbose=log) eri = ftmp['eri_mo'] nocc_pair = nocc*(nocc+1)//2 tril2sq = lib.square_mat_in_trilu_indices(nmo) oo = eri[:nocc_pair] eris.oooo[:] = ao2mo.restore(1, oo[:,:nocc_pair], nocc) oovv = lib.take_2d(oo, tril2sq[:nocc,:nocc].ravel(), tril2sq[nocc:,nocc:].ravel()) eris.oovv[:] = oovv.reshape(nocc,nocc,nvir,nvir) oo = oovv = None tril2sq = lib.square_mat_in_trilu_indices(nmo) blksize = min(nvir, max(BLKMIN, int(max_memory*1e6/8/nmo**3/2))) for p0, p1 in lib.prange(0, nvir, blksize): q0, q1 = p0+nocc, p1+nocc off0 = q0*(q0+1)//2 off1 = q1*(q1+1)//2 buf = lib.unpack_tril(eri[off0:off1]) tmp = buf[ tril2sq[q0:q1,:nocc] - off0 ] eris.ovoo[:,p0:p1] = tmp[:,:,:nocc,:nocc].transpose(1,0,2,3) eris.ovvo[:,p0:p1] = tmp[:,:,nocc:,:nocc].transpose(1,0,2,3) eris.ovov[:,p0:p1] = tmp[:,:,:nocc,nocc:].transpose(1,0,2,3) eris.ovvv[:,p0:p1] = tmp[:,:,nocc:,nocc:].transpose(1,0,2,3) tmp = buf[ tril2sq[q0:q1,nocc:q1] - off0 ] eris.vvvv[p0:p1,:p1] = tmp[:,:,nocc:,nocc:] if p0 > 0: eris.vvvv[:p0,p0:p1] = tmp[:,:p0,nocc:,nocc:].transpose(1,0,2,3) buf = tmp = None log.timer('CCSD integral transformation', *cput0) return eris
def get_vsap(ks, mol=None): '''Superposition of atomic potentials S. Lehtola, Assessment of initial guesses for self-consistent field calculations. Superposition of Atomic Potentials: simple yet efficient, J. Chem. Theory Comput. 15, 1593 (2019). DOI: 10.1021/acs.jctc.8b01089. arXiv:1810.11659. This function evaluates the effective charge of a neutral atom, given by exchange-only LDA on top of spherically symmetric unrestricted Hartree-Fock calculations as described in S. Lehtola, L. Visscher, E. Engel, Efficient implementation of the superposition of atomic potentials initial guess for electronic structure calculations in Gaussian basis sets, J. Chem. Phys., in press (2020). The potentials have been calculated for the ground-states of spherically symmetric atoms at the non-relativistic level of theory as described in S. Lehtola, "Fully numerical calculations on atoms with fractional occupations and range-separated exchange functionals", Phys. Rev. A 101, 012516 (2020). DOI: 10.1103/PhysRevA.101.012516 using accurate finite-element calculations as described in S. Lehtola, "Fully numerical Hartree-Fock and density functional calculations. I. Atoms", Int. J. Quantum Chem. e25945 (2019). DOI: 10.1002/qua.25945 .. note:: This function will modify the input ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. Returns: matrix Vsap = Vnuc + J + Vxc. ''' if mol is None: mol = ks.mol t0 = (logger.process_clock(), logger.perf_counter()) if ks.grids.coords is None: ks.grids.build(with_non0tab=True) t0 = logger.timer(ks, 'setting up grids', *t0) ni = ks._numint max_memory = ks.max_memory - lib.current_memory()[0] vsap = ni.nr_sap(mol, ks.grids, max_memory=max_memory) return vsap
def para(magobj, gauge_orig=None, h1=None, s1=None, with_cphf=None): '''Paramagnetic susceptibility tensor Kwargs: h1: (3,nmo,nocc) array First order Fock matrix in MO basis. s1: (3,nmo,nocc) array First order overlap matrix in MO basis. with_cphf : boolean or function(dm_mo) => v1_mo If a boolean value is given, the value determines whether CPHF equation will be solved or not. The induced potential will be generated by the function gen_vind. If a function is given, CPHF equation will be solved, and the given function is used to compute induced potential ''' log = logger.Logger(magobj.stdout, magobj.verbose) cput1 = (logger.process_clock(), logger.perf_counter()) mol = magobj.mol mf = magobj._scf mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] if h1 is None: # Imaginary part of F10 dm0 = mf.make_rdm1(mo_coeff, mo_occ) h1 = lib.einsum('xpq,pi,qj->xij', magobj.get_fock(dm0, gauge_orig), mo_coeff.conj(), orbo) if s1 is None: # Imaginary part of S10 s1 = lib.einsum('xpq,pi,qj->xij', magobj.get_ovlp(mol, gauge_orig), mo_coeff.conj(), orbo) cput1 = log.timer('first order Fock matrix', *cput1) with_cphf = magobj.cphf mo1, mo_e1 = rhf_nmr.solve_mo1(magobj, mo_energy, mo_coeff, mo_occ, h1, s1, with_cphf) cput1 = logger.timer(magobj, 'solving mo1 eqn', *cput1) mag_para = numpy.einsum('yji,xji->xy', mo1, h1) mag_para -= numpy.einsum('yji,xji,i->xy', mo1, s1, mo_energy[occidx]) # + c.c. mag_para = mag_para + mag_para.conj() mag_para -= numpy.einsum('xij,yij->xy', s1[:, occidx], mo_e1) # *2 for double occupancy. mag_para *= 2 return -mag_para
def kernel(mycc, eris=None, t1=None, t2=None, l1=None, l2=None, max_cycle=50, tol=1e-8, verbose=logger.INFO, fintermediates=None, fupdate=None): if eris is None: eris = mycc.ao2mo() cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.new_logger(mycc, verbose) if t1 is None: t1 = mycc.t1 if t2 is None: t2 = mycc.t2 if l1 is None: l1 = t1 if l2 is None: l2 = t2 if fintermediates is None: fintermediates = make_intermediates if fupdate is None: fupdate = update_lambda imds = fintermediates(mycc, t1, t2, eris) if isinstance(mycc.diis, lib.diis.DIIS): adiis = mycc.diis elif mycc.diis: adiis = lib.diis.DIIS(mycc, mycc.diis_file, incore=mycc.incore_complete) adiis.space = mycc.diis_space else: adiis = None cput0 = log.timer('CCSD lambda initialization', *cput0) conv = False for istep in range(max_cycle): l1new, l2new = fupdate(mycc, t1, t2, l1, l2, eris, imds) normt = numpy.linalg.norm( mycc.amplitudes_to_vector(l1new, l2new) - mycc.amplitudes_to_vector(l1, l2)) l1, l2 = l1new, l2new l1new = l2new = None l1, l2 = mycc.run_diis(l1, l2, istep, normt, 0, adiis) log.info('cycle = %d norm(lambda1,lambda2) = %.6g', istep + 1, normt) cput0 = log.timer('CCSD iter', *cput0) if normt < tol: conv = True break return conv, l1, l2
def solve_mo1(sscobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): cput1 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(sscobj.stdout, sscobj.verbose) if mo_energy is None: mo_energy = sscobj._scf.mo_energy if mo_coeff is None: mo_coeff = sscobj._scf.mo_coeff if mo_occ is None: mo_occ = sscobj._scf.mo_occ if with_cphf is None: with_cphf = sscobj.cphf mol = sscobj.mol if sscobj.mb.upper().startswith('ST'): # Sternheim approximation nmo = mo_occ.size mo_energy = mo_energy[nmo//2:] mo_coeff = mo_coeff[:,nmo//2:] mo_occ = mo_occ[nmo//2:] if h1 is None: atmlst = sorted(set([j for i,j in sscobj.nuc_pair])) h1 = numpy.asarray(make_h1(mol, mo_coeff, mo_occ, atmlst)) if with_cphf: if callable(with_cphf): vind = with_cphf else: vind = gen_vind(sscobj._scf, mo_coeff, mo_occ) mo1, mo_e1 = cphf.solve(vind, mo_energy, mo_occ, h1, None, sscobj.max_cycle_cphf, sscobj.conv_tol, verbose=log) else: e_ai = lib.direct_sum('i-a->ai', mo_energy[mo_occ>0], mo_energy[mo_occ==0]) mo1 = h1 / e_ai mo_e1 = None # Calculate RMB with approximation # |MO1> = Z_RMB |i> + |p> bar{C}_{pi}^1 ~= |p> C_{pi}^1 # bar{C}_{pi}^1 ~= C_{pi}^1 - <p|Z_RMB|i> if sscobj.mb.upper() == 'RMB': orbo = mo_coeff[:,mo_occ> 0] orbv = mo_coeff[:,mo_occ==0] n4c = mo_coeff.shape[0] n2c = n4c // 2 c = lib.param.LIGHT_SPEED orbvS_T = orbv[n2c:].conj().T for ia in atmlst: mol.set_rinv_origin(mol.atom_coord(ia)) a01int = mol.intor('int1e_sa01sp_spinor', 3) for k in range(3): s1 = orbvS_T.dot(a01int[k].conj().T).dot(orbo[n2c:]) mo1[ia*3+k] -= s1 * (.25/c**2) logger.timer(sscobj, 'solving mo1 eqn', *cput1) return mo1, mo_e1
def init_amps(self, eris): time0 = logger.process_clock(), logger.perf_counter() mo_e = eris.fock.diagonal() nocc = self.nocc eia = mo_e[:nocc, None] - mo_e[None, nocc:] eijab = lib.direct_sum('ia,jb->ijab', eia, eia) t1 = eris.fock[:nocc, nocc:] / eia eris_oovv = np.array(eris.oovv) t2 = eris_oovv / eijab self.emp2 = 0.25 * einsum('ijab,ijab', t2, eris_oovv.conj()).real logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2) logger.timer(self, 'init mp2', *time0) return self.emp2, t1, t2
def _make_mo_eris_incore(agf2, mo_coeff=None): ''' Returns _ChemistsERIs ''' cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(agf2.stdout, agf2.verbose) eris = _ChemistsERIs() eris._common_init_(agf2, mo_coeff) with_df = agf2.with_df moa, mob = eris.mo_coeff nmoa, nmob = moa.shape[1], mob.shape[1] npaira, npairb = nmoa * (nmoa + 1) // 2, nmob * (nmob + 1) // 2 naux = with_df.get_naoaux() qxy_a = np.zeros((naux, npaira)) qxy_b = np.zeros((naux, npairb)) moa = np.asarray(moa, order='F') mob = np.asarray(mob, order='F') sija = (0, nmoa, 0, nmoa) sijb = (0, nmob, 0, nmob) sym = dict(aosym='s2', mosym='s2') for p0, p1 in with_df.prange(): eri0 = with_df._cderi[p0:p1] qxy_a[p0:p1] = ao2mo._ao2mo.nr_e2(eri0, moa, sija, out=qxy_a[p0:p1], **sym) qxy_b[p0:p1] = ao2mo._ao2mo.nr_e2(eri0, mob, sijb, out=qxy_b[p0:p1], **sym) mpi_helper.barrier() mpi_helper.allreduce_safe_inplace(qxy_a) mpi_helper.allreduce_safe_inplace(qxy_b) eris.eri_a = qxy_a eris.eri_b = qxy_b eris.eri_aa = (eris.eri_a, eris.eri_a) eris.eri_ab = (eris.eri_a, eris.eri_b) eris.eri_ba = (eris.eri_b, eris.eri_a) eris.eri_bb = (eris.eri_b, eris.eri_b) eris.eri = (eris.eri_a, eris.eri_b) log.timer('MO integral transformation', *cput0) return eris
def grad_elec(mf_grad, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None): mf = mf_grad.base mol = mf_grad.mol if mo_energy is None: mo_energy = mf.mo_energy if mo_occ is None: mo_occ = mf.mo_occ if mo_coeff is None: mo_coeff = mf.mo_coeff log = logger.Logger(mf_grad.stdout, mf_grad.verbose) hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) dm0 = mf.make_rdm1(mf.mo_coeff, mf.mo_occ) n2c = dm0.shape[0] // 2 t0 = (logger.process_clock(), logger.perf_counter()) log.debug('Compute Gradients of NR Hartree-Fock Coulomb repulsion') vhf = mf_grad.get_veff(mol, dm0) log.timer('gradients of 2e part', *t0) dme0 = mf_grad.make_rdm1e(mf.mo_energy, mf.mo_coeff, mf.mo_occ) if atmlst is None: atmlst = range(mol.natm) aoslices = mol.aoslice_2c_by_atom() de = numpy.zeros((len(atmlst), 3)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) de[k] += numpy.einsum('xij,ji->x', h1ao, dm0).real # large components de[k] += ( numpy.einsum('xij,ji->x', vhf[:, p0:p1], dm0[:, p0:p1]) + numpy.einsum('xji,ji->x', vhf[:, p0:p1].conj(), dm0[p0:p1])).real de[k] -= ( numpy.einsum('xij,ji->x', s1[:, p0:p1], dme0[:, p0:p1]) + numpy.einsum('xji,ji->x', s1[:, p0:p1].conj(), dme0[p0:p1])).real # small components p0 += n2c p1 += n2c de[k] += ( numpy.einsum('xij,ji->x', vhf[:, p0:p1], dm0[:, p0:p1]) + numpy.einsum('xji,ji->x', vhf[:, p0:p1].conj(), dm0[p0:p1])).real de[k] -= ( numpy.einsum('xij,ji->x', s1[:, p0:p1], dme0[:, p0:p1]) + numpy.einsum('xji,ji->x', s1[:, p0:p1].conj(), dme0[p0:p1])).real log.debug('gradients of electronic part') log.debug(str(de)) return de
def get_jk(self, cell=None, dm=None, hermi=1, kpt=None, kpts_band=None, with_j=True, with_k=True, omega=None, **kwargs): r'''Get Coulomb (J) and exchange (K) following :func:`scf.hf.RHF.get_jk_`. for particular k-point (kpt). When kpts_band is given, the J, K matrices on kpts_band are evaluated. J_{pq} = \sum_{rs} (pq|rs) dm[s,r] K_{pq} = \sum_{rs} (pr|sq) dm[r,s] where r,s are orbitals on kpt. p and q are orbitals on kpts_band if kpts_band is given otherwise p and q are orbitals on kpt. ''' if cell is None: cell = self.cell if dm is None: dm = self.make_rdm1() if kpt is None: kpt = self.kpt cpu0 = (logger.process_clock(), logger.perf_counter()) dm = np.asarray(dm) nao = dm.shape[-1] if (not omega and kpts_band is None and # TODO: generate AO integrals with rsjk algorithm not self.rsjk and (self.exxdiv == 'ewald' or not self.exxdiv) and (self._eri is not None or cell.incore_anyway or (not self.direct_scf and self._is_mem_enough()))): if self._eri is None: logger.debug(self, 'Building PBC AO integrals incore') self._eri = self.with_df.get_ao_eri(kpt, compact=True) vj, vk = mol_hf.dot_eri_dm(self._eri, dm, hermi, with_j, with_k) if with_k and self.exxdiv == 'ewald': from pyscf.pbc.df.df_jk import _ewald_exxdiv_for_G0 # G=0 is not inculded in the ._eri integrals _ewald_exxdiv_for_G0(self.cell, kpt, dm.reshape(-1,nao,nao), vk.reshape(-1,nao,nao)) elif self.rsjk: vj, vk = self.rsjk.get_jk(dm.reshape(-1,nao,nao), hermi, kpt, kpts_band, with_j, with_k, omega, exxdiv=self.exxdiv) else: vj, vk = self.with_df.get_jk(dm.reshape(-1,nao,nao), hermi, kpt, kpts_band, with_j, with_k, omega, exxdiv=self.exxdiv) if with_j: vj = _format_jks(vj, dm, kpts_band) if with_k: vk = _format_jks(vk, dm, kpts_band) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
def scf(self, dm0=None): cput0 = (logger.process_clock(), logger.perf_counter()) self.build() self.dump_flags() self.converged, self.e_tot, \ self.mo_energy, self.mo_coeff, self.mo_occ \ = kernel(self, self.conv_tol, self.conv_tol_grad, dm0=dm0, callback=self.callback, conv_check=self.conv_check) logger.timer(self, 'SCF', *cput0) self._finalize() return self.e_tot
def transform_integrals_df(myadc): cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(myadc.stdout, myadc.verbose) mo_coeff = np.asarray(myadc.mo_coeff, order='F') nocc = myadc._nocc nao, nmo = mo_coeff.shape nvir = myadc._nmo - myadc._nocc with_df = myadc.with_df naux = with_df.get_naoaux() eris = lambda: None eris.vvvv = None eris.ovvv = None Loo = np.empty((naux,nocc,nocc)) Lvo = np.empty((naux,nvir,nocc)) eris.Lvv = np.empty((naux,nvir,nvir)) eris.Lov = np.empty((naux,nocc,nvir)) ijslice = (0, nmo, 0, nmo) Lpq = None p1 = 0 for eri1 in with_df.loop(): Lpq = ao2mo._ao2mo.nr_e2(eri1, mo_coeff, ijslice, aosym='s2', out=Lpq).reshape(-1,nmo,nmo) p0, p1 = p1, p1 + Lpq.shape[0] Loo[p0:p1] = Lpq[:,:nocc,:nocc] #Lov[p0:p1] = Lpq[:,:nocc,nocc:] eris.Lov[p0:p1] = Lpq[:,:nocc,nocc:] Lvo[p0:p1] = Lpq[:,nocc:,:nocc] eris.Lvv[p0:p1] = Lpq[:,nocc:,nocc:] Loo = Loo.reshape(naux,nocc*nocc) eris.Lov = eris.Lov.reshape(naux,nocc*nvir) Lvo = Lvo.reshape(naux,nocc*nvir) eris.Lvv = eris.Lvv.reshape(naux,nvir*nvir) eris.feri1 = lib.H5TmpFile() eris.oooo = eris.feri1.create_dataset('oooo', (nocc,nocc,nocc,nocc), 'f8') eris.oovv = eris.feri1.create_dataset('oovv', (nocc,nocc,nvir,nvir), 'f8', chunks=(nocc,nocc,1,nvir)) eris.ovoo = eris.feri1.create_dataset('ovoo', (nocc,nvir,nocc,nocc), 'f8', chunks=(nocc,1,nocc,nocc)) eris.ovvo = eris.feri1.create_dataset('ovvo', (nocc,nvir,nvir,nocc), 'f8', chunks=(nocc,1,nvir,nocc)) eris.oooo[:] = lib.ddot(Loo.T, Loo).reshape(nocc,nocc,nocc,nocc) eris.ovoo[:] = lib.ddot(eris.Lov.T, Loo).reshape(nocc,nvir,nocc,nocc) eris.oovv[:] = lib.ddot(Loo.T, eris.Lvv).reshape(nocc,nocc,nvir,nvir) eris.ovvo[:] = lib.ddot(eris.Lov.T, Lvo).reshape(nocc,nvir,nvir,nocc) log.timer('DF-ADC integral transformation', *cput0) return eris
def kernel(self, x0=None, nstates=None): '''TDA diagonalization solver ''' cpu0 = (logger.process_clock(), logger.perf_counter()) self.check_sanity() self.dump_flags() if nstates is None: nstates = self.nstates else: self.nstates = nstates log = logger.Logger(self.stdout, self.verbose) vind, hdiag = self.gen_vind(self._scf) precond = self.get_precond(hdiag) if x0 is None: x0 = self.init_guess(self._scf, self.nstates) def pickeig(w, v, nroots, envs): idx = numpy.where(w > POSTIVE_EIG_THRESHOLD)[0] return w[idx], v[:, idx], idx self.converged, self.e, x1 = \ lib.davidson1(vind, x0, precond, tol=self.conv_tol, nroots=nstates, lindep=self.lindep, max_cycle=self.max_cycle, max_space=self.max_space, pick=pickeig, verbose=log) nmo = self._scf.mo_occ[0].size nocca = (self._scf.mo_occ[0] > 0).sum() noccb = (self._scf.mo_occ[1] > 0).sum() nvira = nmo - nocca nvirb = nmo - noccb self.xy = [ ( ( xi[:nocca * nvira].reshape(nocca, nvira), # X_alpha xi[nocca * nvira:].reshape(noccb, nvirb)), # X_beta (0, 0)) # (Y_alpha, Y_beta) for xi in x1 ] if self.chkfile: lib.chkfile.save(self.chkfile, 'tddft/e', self.e) lib.chkfile.save(self.chkfile, 'tddft/xy', self.xy) log.timer('TDA', *cpu0) self._finalize() return self.e, self.xy
def _gen_contract_aaa(t1T, t2T, vooo, fock, mo_energy, orbsym, log): nvir, nocc = t1T.shape mo_energy = numpy.asarray(mo_energy, order='C') fvo = fock[nocc:, :nocc].copy() cpu2 = [logger.process_clock(), logger.perf_counter()] orbsym = numpy.hstack( (numpy.sort(orbsym[:nocc]), numpy.sort(orbsym[nocc:]))) o_ir_loc = numpy.append( 0, numpy.cumsum(numpy.bincount(orbsym[:nocc], minlength=8))) v_ir_loc = numpy.append( 0, numpy.cumsum(numpy.bincount(orbsym[nocc:], minlength=8))) o_sym = orbsym[:nocc] oo_sym = (o_sym[:, None] ^ o_sym).ravel() oo_ir_loc = numpy.append(0, numpy.cumsum(numpy.bincount(oo_sym, minlength=8))) nirrep = max(oo_sym) + 1 orbsym = orbsym.astype(numpy.int32) o_ir_loc = o_ir_loc.astype(numpy.int32) v_ir_loc = v_ir_loc.astype(numpy.int32) oo_ir_loc = oo_ir_loc.astype(numpy.int32) dtype = numpy.result_type(t2T.dtype, vooo.dtype, fock.dtype) if dtype == numpy.complex: drv = _ccsd.libcc.CCuccsd_t_zaaa else: drv = _ccsd.libcc.CCuccsd_t_aaa def contract(et_sum, a0, a1, b0, b1, cache): cache_row_a, cache_col_a, cache_row_b, cache_col_b = cache drv(et_sum.ctypes.data_as(ctypes.c_void_p), mo_energy.ctypes.data_as(ctypes.c_void_p), t1T.ctypes.data_as(ctypes.c_void_p), t2T.ctypes.data_as(ctypes.c_void_p), vooo.ctypes.data_as(ctypes.c_void_p), fvo.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(nocc), ctypes.c_int(nvir), ctypes.c_int(a0), ctypes.c_int(a1), ctypes.c_int(b0), ctypes.c_int(b1), ctypes.c_int(nirrep), o_ir_loc.ctypes.data_as(ctypes.c_void_p), v_ir_loc.ctypes.data_as(ctypes.c_void_p), oo_ir_loc.ctypes.data_as(ctypes.c_void_p), orbsym.ctypes.data_as(ctypes.c_void_p), cache_row_a.ctypes.data_as(ctypes.c_void_p), cache_col_a.ctypes.data_as(ctypes.c_void_p), cache_row_b.ctypes.data_as(ctypes.c_void_p), cache_col_b.ctypes.data_as(ctypes.c_void_p)) cpu2[:] = log.timer_debug1('contract %d:%d,%d:%d' % (a0, a1, b0, b1), *cpu2) return contract
def get_jk(self, cell=None, dm_kpts=None, hermi=1, kpts=None, kpts_band=None, with_j=True, with_k=True, omega=None, **kwargs): if cell is None: cell = self.cell if kpts is None: kpts = self.kpts if dm_kpts is None: dm_kpts = self.make_rdm1() cpu0 = (logger.process_clock(), logger.perf_counter()) if self.rsjk: vj, vk = self.rsjk.get_jk(dm_kpts, hermi, kpts, kpts_band, with_j, with_k, omega, self.exxdiv) else: vj, vk = self.with_df.get_jk(dm_kpts, hermi, kpts, kpts_band, with_j, with_k, omega, self.exxdiv) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
def _make_shared(self): cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(self.cc.stdout, self.cc.verbose) t1, t2, eris = self.cc.t1, self.cc.t2, self.cc.eris self.Foo = imd.Foo(t1, t2, eris) self.Fvv = imd.Fvv(t1, t2, eris) self.Fov = imd.Fov(t1, t2, eris) # 2 virtuals self.Wovvo = imd.Wovvo(t1, t2, eris) self.Woovv = eris.oovv log.timer('EOM-CCSD shared intermediates', *cput0)
def grad_elec(mf_grad, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None): ''' Electronic part of UHF/UKS gradients Args: mf_grad : grad.uhf.Gradients or grad.uks.Gradients object ''' mf = mf_grad.base mol = mf_grad.mol if mo_energy is None: mo_energy = mf.mo_energy if mo_occ is None: mo_occ = mf.mo_occ if mo_coeff is None: mo_coeff = mf.mo_coeff log = logger.Logger(mf_grad.stdout, mf_grad.verbose) hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) dm0 = mf.make_rdm1(mo_coeff, mo_occ) t0 = (logger.process_clock(), logger.perf_counter()) log.debug('Computing Gradients of NR-UHF Coulomb repulsion') vhf = mf_grad.get_veff(mol, dm0) log.timer('gradients of 2e part', *t0) dme0 = mf_grad.make_rdm1e(mo_energy, mo_coeff, mo_occ) dm0_sf = dm0[0] + dm0[1] dme0_sf = dme0[0] + dme0[1] if atmlst is None: atmlst = range(mol.natm) aoslices = mol.aoslice_by_atom() de = numpy.zeros((len(atmlst), 3)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) de[k] += numpy.einsum('xij,ij->x', h1ao, dm0_sf) # s1, vhf are \nabla <i|h|j>, the nuclear gradients = -\nabla de[k] += numpy.einsum('sxij,sij->x', vhf[:, :, p0:p1], dm0[:, p0:p1]) * 2 de[k] -= numpy.einsum('xij,ij->x', s1[:, p0:p1], dme0_sf[p0:p1]) * 2 de[k] += mf_grad.extra_force(ia, locals()) if log.verbose >= logger.DEBUG: log.debug('gradients of electronic part') rhf_grad._write(log, mol, de, atmlst) return de
def _make_eris(mp, mo_coeff=None, ao2mofn=None, verbose=None): log = logger.new_logger(mp, verbose) time0 = (logger.process_clock(), logger.perf_counter()) eris = _ChemistsERIs() eris._common_init_(mp, mo_coeff) mo_coeff = eris.mo_coeff nocc = mp.nocc nmo = mp.nmo nvir = nmo - nocc mem_incore, mem_outcore, mem_basic = _mem_usage(nocc, nvir) mem_now = lib.current_memory()[0] max_memory = max(0, mp.max_memory - mem_now) if max_memory < mem_basic: log.warn( 'Not enough memory for integral transformation. ' 'Available mem %s MB, required mem %s MB', max_memory, mem_basic) co = numpy.asarray(mo_coeff[:, :nocc], order='F') cv = numpy.asarray(mo_coeff[:, nocc:], order='F') if (mp.mol.incore_anyway or (mp._scf._eri is not None and mem_incore < max_memory)): log.debug('transform (ia|jb) incore') if callable(ao2mofn): eris.ovov = ao2mofn( (co, cv, co, cv)).reshape(nocc * nvir, nocc * nvir) else: eris.ovov = ao2mo.general(mp._scf._eri, (co, cv, co, cv)) elif getattr(mp._scf, 'with_df', None): # To handle the PBC or custom 2-electron with 3-index tensor. # Call dfmp2.MP2 for efficient DF-MP2 implementation. log.warn('DF-HF is found. (ia|jb) is computed based on the DF ' '3-tensor integrals.\n' 'You can switch to dfmp2.MP2 for better performance') log.debug('transform (ia|jb) with_df') eris.ovov = mp._scf.with_df.ao2mo((co, cv, co, cv)) else: log.debug('transform (ia|jb) outcore') eris.feri = lib.H5TmpFile() #ao2mo.outcore.general(mp.mol, (co,cv,co,cv), eris.feri, # max_memory=max_memory, verbose=log) #eris.ovov = eris.feri['eri_mo'] eris.ovov = _ao2mo_ovov(mp, co, cv, eris.feri, max(2000, max_memory), log) log.timer('Integral transformation', *time0) return eris
def _make_shared(self): cput0 = (logger.process_clock(), logger.perf_counter()) t1, t2, eris = self.t1, self.t2, self.eris self.Foo = imd.Foo(t1, t2, eris) self.Fvv = imd.Fvv(t1, t2, eris) self.Fov = imd.Fov(t1, t2, eris) # 2 virtuals self.Wovvo = imd.Wovvo(t1, t2, eris) self.Woovv = eris.oovv self._made_shared = True logger.timer_debug1(self, 'EOM-CCSD shared intermediates', *cput0) return self
def grad_elec(mf_grad, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None): mf = mf_grad.base cell = mf_grad.cell kpts = mf.kpts nkpts = len(kpts) if mo_energy is None: mo_energy = mf.mo_energy if mo_occ is None: mo_occ = mf.mo_occ if mo_coeff is None: mo_coeff = mf.mo_coeff if atmlst is None: atmlst = range(cell.natm) log = logger.Logger(mf_grad.stdout, mf_grad.verbose) hcore_deriv = mf_grad.hcore_generator(cell, kpts) s1 = mf_grad.get_ovlp(cell, kpts) dm0 = mf.make_rdm1(mo_coeff, mo_occ) t0 = (logger.process_clock(), logger.perf_counter()) log.debug('Computing Gradients of NR-UHF Coulomb repulsion') vhf = mf_grad.get_veff(dm0, kpts) log.timer('gradients of 2e part', *t0) dme0 = mf_grad.make_rdm1e(mo_energy, mo_coeff, mo_occ) dm0_sf = dm0[0] + dm0[1] dme0_sf = dme0[0] + dme0[1] if atmlst is None: atmlst = range(cell.natm) aoslices = cell.aoslice_by_atom() de = np.zeros((len(atmlst), 3)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) de[k] += np.einsum('xkij,kji->x', h1ao, dm0_sf).real de[k] += np.einsum('xskij,skji->x', vhf[:, :, :, p0:p1], dm0[:, :, :, p0:p1]).real * 2 de[k] -= np.einsum('kxij,kji->x', s1[:, :, p0:p1], dme0_sf[:, :, p0:p1]).real * 2 de[k] /= nkpts de[k] += mf_grad.extra_force(ia, locals()) if log.verbose > logger.DEBUG: log.debug('gradients of electronic part') mf_grad._write(log, cell, de, atmlst) return de
def make_t3p2_ea(self, cc): cput0 = (logger.process_clock(), logger.perf_counter()) t1, t2, eris = cc.t1, cc.t2, self.eris delta_E_corr, pt1, pt2, Wovoo, Wvvvo = \ imd.get_t3p2_imds_slow(cc, t1, t2, eris) self.t1 = pt1 self.t2 = pt2 self._made_shared = False # Force update self.make_ea() # Make after t1/t2 updated self.Wvvvo = self.Wvvvo + Wvvvo self.made_ea_imds = True logger.timer_debug1(self, 'EOM-CCSD(T)a EA intermediates', *cput0) return self
def make_ea(self): if not self._made_shared: self._make_shared() cput0 = (logger.process_clock(), logger.perf_counter()) t1, t2, eris = self.t1, self.t2, self.eris # 3 or 4 virtuals self.Wvovv = imd.Wvovv(t1, t2, eris) self.Wvvvv = imd.Wvvvv(t1, t2, eris) self.Wvvvo = imd.Wvvvo(t1, t2, eris, self.Wvvvv) self.made_ea_imds = True logger.timer_debug1(self, 'EOM-CCSD EA intermediates', *cput0) return self