def solve_mo1_fc(sscobj, h1): cput1 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(sscobj.stdout, sscobj.verbose) mo_energy = sscobj._scf.mo_energy mo_coeff = sscobj._scf.mo_coeff mo_occ = sscobj._scf.mo_occ nset = len(h1) eai = 1. / lib.direct_sum('a-i->ai', mo_energy[mo_occ == 0], mo_energy[mo_occ > 0]) mo1 = numpy.asarray(h1) * -eai if not sscobj.cphf: return mo1 orbo = mo_coeff[:, mo_occ > 0] orbv = mo_coeff[:, mo_occ == 0] nocc = orbo.shape[1] nvir = orbv.shape[1] nmo = nocc + nvir vresp = sscobj._scf.gen_response(singlet=False, hermi=1) mo_v_o = numpy.asarray(numpy.hstack((orbv, orbo)), order='F') def vind(mo1): dm1 = _dm1_mo2ao(mo1.reshape(nset, nvir, nocc), orbv, orbo * 2) # *2 for double occupancy dm1 = dm1 + dm1.transpose(0, 2, 1) v1 = vresp(dm1) v1 = _ao2mo.nr_e2(v1, mo_v_o, (0, nvir, nvir, nmo)).reshape(nset, nvir, nocc) v1 *= eai return v1.ravel() mo1 = lib.krylov(vind, mo1.ravel(), tol=sscobj.conv_tol, max_cycle=sscobj.max_cycle_cphf, verbose=log) log.timer('solving FC CPHF eqn', *cput1) return mo1.reshape(nset, nvir, nocc)
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 kernel(self, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None): cput0 = (logger.process_clock(), logger.perf_counter()) if mo_energy is None: mo_energy = self.base.mo_energy if mo_coeff is None: mo_coeff = self.base.mo_coeff if mo_occ is None: mo_occ = self.base.mo_occ if atmlst is None: atmlst = self.atmlst else: self.atmlst = atmlst if self.verbose >= logger.WARN: self.check_sanity() if self.verbose >= logger.INFO: self.dump_flags() de = self.grad_elec(mo_energy, mo_coeff, mo_occ, atmlst) self.de = de + self.grad_nuc(atmlst=atmlst) if self.mol.symmetry: self.de = self.symmetrize(self.de, atmlst) logger.timer(self, 'SCF gradients', *cput0) self._finalize() return self.de
def make_ee(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 if not self.made_ip_imds: # 0 or 1 virtuals self.Woooo = imd.Woooo(t1, t2, eris) self.Wooov = imd.Wooov(t1, t2, eris) self.Wovoo = imd.Wovoo(t1, t2, eris) if not self.made_ea_imds: # 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_ee_imds = True logger.timer(self, 'EOM-CCSD EE intermediates', *cput0) return self
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 h1 is None: atmlst = sorted(set([j for i, j in sscobj.nuc_pair])) h1 = numpy.asarray(make_h1_pso(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 * (1 / e_ai) mo_e1 = None logger.timer(sscobj, 'solving mo1 eqn', *cput1) return mo1, mo_e1
def get_gridss(mol, level=1, gthrd=1e-10): Ktime = (logger.process_clock(), logger.perf_counter()) grids = gen_grid.Grids(mol) grids.level = level grids.build() ngrids = grids.weights.size mask = [] for p0, p1 in lib.prange(0, ngrids, 10000): ao_v = mol.eval_gto('GTOval', grids.coords[p0:p1]) ao_v *= grids.weights[p0:p1,None] wao_v0 = ao_v mask.append(numpy.any(wao_v0>gthrd, axis=1) | numpy.any(wao_v0<-gthrd, axis=1)) mask = numpy.hstack(mask) grids.coords = grids.coords[mask] grids.weights = grids.weights[mask] logger.debug(mol, 'threshold for grids screening %g', gthrd) logger.debug(mol, 'number of grids %d', grids.weights.size) logger.timer_debug1(mol, "Xg screening", *Ktime) return grids
def ao2mo(self, mo_coeff): # the exact integral transformation eris = casscf_class.ao2mo(self, mo_coeff) log = logger.Logger(self.stdout, self.verbose) # Add the approximate diagonal term for orbital hessian t1 = t0 = (logger.process_clock(), logger.perf_counter()) mo = numpy.asarray(mo_coeff, order='F') nao, nmo = mo.shape ncore = self.ncore eris.j_pc = numpy.zeros((nmo, ncore)) k_cp = numpy.zeros((ncore, nmo)) fmmm = _ao2mo.libao2mo.AO2MOmmm_nr_s2_iltj fdrv = _ao2mo.libao2mo.AO2MOnr_e2_drv ftrans = _ao2mo.libao2mo.AO2MOtranse2_nr_s2 max_memory = self.max_memory - lib.current_memory()[0] blksize = max( 4, int(min(self.with_df.blockdim, max_memory * .3e6 / 8 / nmo**2))) bufs1 = numpy.empty((blksize, nmo, nmo)) for eri1 in self.with_df.loop(blksize): naux = eri1.shape[0] buf = bufs1[:naux] fdrv(ftrans, fmmm, buf.ctypes.data_as(ctypes.c_void_p), eri1.ctypes.data_as(ctypes.c_void_p), mo.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), ctypes.c_int(nao), (ctypes.c_int * 4)(0, nmo, 0, nmo), ctypes.c_void_p(0), ctypes.c_int(0)) bufd = numpy.einsum('kii->ki', buf) eris.j_pc += numpy.einsum('ki,kj->ij', bufd, bufd[:, :ncore]) k_cp += numpy.einsum('kij,kij->ij', buf[:, :ncore], buf[:, :ncore]) t1 = log.timer_debug1('j_pc and k_pc', *t1) eris.k_pc = k_cp.T.copy() log.timer('ao2mo density fit part', *t0) return eris
def kernel(casci, mo_coeff=None, ci0=None, verbose=logger.NOTE): '''CASCI solver ''' if mo_coeff is None: mo_coeff = casci.mo_coeff log = logger.new_logger(casci, verbose) t0 = (logger.process_clock(), logger.perf_counter()) log.debug('Start CASCI') ncas = casci.ncas nelecas = casci.nelecas # 2e eri_cas = casci.get_h2eff(mo_coeff) t1 = log.timer('integral transformation to CAS space', *t0) # 1e h1eff, energy_core = casci.get_h1eff(mo_coeff) log.debug('core energy = %.15g', energy_core) t1 = log.timer('effective h1e in CAS space', *t1) if h1eff.shape[0] != ncas: raise RuntimeError('Active space size error. nmo=%d ncore=%d ncas=%d' % (mo_coeff.shape[1], casci.ncore, ncas)) # FCI max_memory = max(400, casci.max_memory - lib.current_memory()[0]) e_tot, fcivec = casci.fcisolver.kernel(h1eff, eri_cas, ncas, nelecas, ci0=ci0, verbose=log, max_memory=max_memory, ecore=energy_core) t1 = log.timer('FCI solver', *t1) e_cas = e_tot - energy_core return e_tot, e_cas, fcivec
def solve_nos1(fvind, mo_energy, mo_occ, h1, max_cycle=20, tol=1e-9, hermi=False, verbose=logger.WARN): '''For field independent basis. First order overlap matrix is zero''' log = logger.new_logger(verbose=verbose) t0 = (logger.process_clock(), logger.perf_counter()) occidxa = mo_occ[0] > 0 occidxb = mo_occ[1] > 0 viridxa = ~occidxa viridxb = ~occidxb nocca = numpy.count_nonzero(occidxa) noccb = numpy.count_nonzero(occidxb) nvira = mo_occ[0].size - nocca nvirb = mo_occ[1].size - noccb e_ai = numpy.hstack(((mo_energy[0][viridxa,None]-mo_energy[0][occidxa]).ravel(), (mo_energy[1][viridxb,None]-mo_energy[1][occidxb]).ravel())) e_ai = 1 / e_ai mo1base = numpy.hstack((h1[0].reshape(-1,nvira*nocca), h1[1].reshape(-1,nvirb*noccb))) mo1base *= -e_ai def vind_vo(mo1): v = fvind(mo1.reshape(mo1base.shape)).reshape(mo1base.shape) v *= e_ai return v.ravel() mo1 = lib.krylov(vind_vo, mo1base.ravel(), tol=tol, max_cycle=max_cycle, hermi=hermi, verbose=log) log.timer('krylov solver in CPHF', *t0) if isinstance(h1[0], numpy.ndarray) and h1[0].ndim == 2: mo1 = (mo1[:nocca*nvira].reshape(nvira,nocca), mo1[nocca*nvira:].reshape(nvirb,noccb)) else: mo1 = mo1.reshape(mo1base.shape) mo1_a = mo1[:,:nvira*nocca].reshape(-1,nvira,nocca) mo1_b = mo1[:,nvira*nocca:].reshape(-1,nvirb,noccb) mo1 = (mo1_a, mo1_b) return mo1, None
def get_init_guess(self, eris=None, nroots=1, diag=None): # MP2 initial guess if eris is None: eris = self.ao2mo(self.mo_coeff) time0 = logger.process_clock(), logger.perf_counter() mo_e = eris.mo_energy nocc = self.nocc eia = mo_e[:nocc,None] - mo_e[None,nocc:] eijab = lib.direct_sum('ia,jb->ijab',eia,eia) ci0 = 1 ci1 = eris.fock[:nocc,nocc:] / eia eris_oovv = numpy.array(eris.oovv) ci2 = eris_oovv / eijab self.emp2 = 0.25*numpy.einsum('ijab,ijab', ci2.conj(), eris_oovv).real logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2) logger.timer(self, 'init mp2', *time0) if abs(self.emp2) < 1e-3 and abs(ci1).sum() < 1e-3: ci1 = 1. / eia ci_guess = amplitudes_to_cisdvec(ci0, ci1, ci2) if nroots > 1: civec_size = ci_guess.size dtype = ci_guess.dtype nroots = min(ci1.size+1, nroots) # Consider Koopmans' theorem only if diag is None: idx = range(1, nroots) else: idx = diag[:ci1.size+1].argsort()[1:nroots] # exclude HF determinant ci_guess = [ci_guess] for i in idx: g = numpy.zeros(civec_size, dtype) g[i] = 1.0 ci_guess.append(g) return self.emp2, ci_guess
def kernel(self, mo_coeff=None, mo_occ=None, dm0=None): cput0 = (logger.process_clock(), logger.perf_counter()) if dm0 is not None: if isinstance(dm0, str): sys.stderr.write( 'Newton solver reads density matrix from chkfile %s\n' % dm0) dm0 = self.from_chk(dm0) elif mo_coeff is not None and mo_occ is None: logger.warn( self, 'Newton solver expects mo_coeff with ' 'mo_occ as initial guess but mo_occ is not found in ' 'the arguments.\n The given ' 'argument is treated as density matrix.') dm0 = mo_coeff mo_coeff = mo_occ = None else: if mo_coeff is None: mo_coeff = self.mo_coeff if mo_occ is None: mo_occ = self.mo_occ # TODO: assert mo_coeff orth-normality. If not orth-normal, # build dm from mo_coeff and mo_occ then unset mo_coeff and mo_occ. self.build(self.mol) self.dump_flags() self.converged, self.e_tot, \ self.mo_energy, self.mo_coeff, self.mo_occ = \ kernel(self, mo_coeff, mo_occ, dm0, conv_tol=self.conv_tol, conv_tol_grad=self.conv_tol_grad, max_cycle=self.max_cycle, callback=self.callback, verbose=self.verbose) logger.timer(self, 'Second order SCF', *cput0) self._finalize() return self.e_tot
def cholesky_eri_debug(mol, auxbasis='weigend+etb', auxmol=None, int3c='int3c2e', aosym='s2ij', int2c='int2c2e', comp=1, verbose=0, fauxe2=aux_e2): ''' Returns: 2D array of (naux,nao*(nao+1)/2) in C-contiguous ''' assert(comp == 1) t0 = (logger.process_clock(), logger.perf_counter()) log = logger.new_logger(mol, verbose) if auxmol is None: auxmol = addons.make_auxmol(mol, auxbasis) j2c = auxmol.intor(int2c, hermi=1) naux = j2c.shape[0] log.debug('size of aux basis %d', naux) t1 = log.timer('2c2e', *t0) j3c = fauxe2(mol, auxmol, intor=int3c, aosym=aosym).reshape(-1,naux) t1 = log.timer('3c2e', *t1) try: low = scipy.linalg.cholesky(j2c, lower=True) j2c = None t1 = log.timer('Cholesky 2c2e', *t1) cderi = scipy.linalg.solve_triangular(low, j3c.T, lower=True, overwrite_b=True) except scipy.linalg.LinAlgError: w, v = scipy.linalg.eigh(j2c) idx = w > LINEAR_DEP_THR v = (v[:,idx] / numpy.sqrt(w[idx])) cderi = lib.dot(v.T, j3c.T) j3c = None if cderi.flags.f_contiguous: cderi = lib.transpose(cderi.T) log.timer('cholesky_eri', *t0) return cderi
def kernel(self): cput0 = (logger.process_clock(), logger.perf_counter()) self.check_sanity() self.dump_flags() mag_dia = self.dia(self.gauge_orig) mag_para = self.para(self.gauge_orig) ksi = mag_para + mag_dia logger.timer(self, 'Magnetizability', *cput0) if self.verbose >= logger.NOTE: _write = rhf_nmr._write _write(self.stdout, ksi, '\nMagnetizability (au)') _write(self.stdout, mag_dia, 'dia-magnetic contribution (au)') _write(self.stdout, mag_para, 'para-magnetic contribution (au)') #if self.verbose >= logger.INFO: # _write(self.stdout, para_occ, 'occ part of para-magnetic term') # _write(self.stdout, para_vir, 'vir part of para-magnetic term') unit = nist.HARTREE2J / nist.AU2TESLA**2 * 1e30 _write(self.stdout, ksi * unit, '\nMagnetizability (10^{-30} J/T^2)') return ksi
def kernel(self, mo1=None): cput0 = (logger.process_clock(), logger.perf_counter()) self.check_sanity() self.dump_flags() gdia = self.dia(self._scf.make_rdm1(), self.gauge_orig) gpara = self.para(mo1, self._scf.mo_coeff, self._scf.mo_occ) gshift = gpara + gdia gtensor = gshift + numpy.eye(3) * nist.G_ELECTRON logger.timer(self, 'g-tensor', *cput0) if self.verbose >= logger.NOTE: logger.note(self, 'free electron g %s', nist.G_ELECTRON) gtot, v = self.align(gtensor) gdia = reduce(numpy.dot, (v.T, gdia, v)) gpara = reduce(numpy.dot, (v.T, gpara, v)) gshift = gtot - numpy.eye(3) * nist.G_ELECTRON if self.verbose >= logger.INFO: _write(self, gdia, 'g-tensor diamagnetic terms') _write(self, gpara, 'g-tensor paramagnetic terms') _write(self, gtot, 'g-tensor total') _write(self, gshift * 1e3, 'g-shift (ppt)') return gtensor
def make_ee(self): if self._made_shared is False: self._make_shared() self._made_shared = True 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 if self.made_ip_imds is False: # 0 or 1 virtuals self.Woooo = imd.Woooo(t1, t2, eris) self.Wooov = imd.Wooov(t1, t2, eris) self.Wovoo = imd.Wovoo(t1, t2, eris) if self.made_ea_imds is False: # 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_ee_imds = True log.timer('EOM-CCSD EE intermediates', *cput0)
def init_amps(self, eris): time0 = logger.process_clock(), logger.perf_counter() nocc = self.nocc nvir = self.nmo - nocc nkpts = self.nkpts mo_e_o = [eris.mo_energy[k][:nocc] for k in range(nkpts)] mo_e_v = [eris.mo_energy[k][nocc:] for k in range(nkpts)] t1 = numpy.zeros((nkpts, nocc, nvir), dtype=numpy.complex128) t2 = numpy.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=numpy.complex128) self.emp2 = 0 eris_oovv = eris.oovv.copy() # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(self, kind="split") kconserv = kpts_helper.get_kconserv(self._scf.cell, self.kpts) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] # For LARGE_DENOM, see t1new update above eia = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = numpy.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:,None] - mo_e_v[ka])[n0_ovp_ia] ejb = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_jb = numpy.ix_(nonzero_opadding[kj], nonzero_vpadding[kb]) ejb[n0_ovp_jb] = (mo_e_o[kj][:,None] - mo_e_v[kb])[n0_ovp_jb] eijab = eia[:, None, :, None] + ejb[:, None, :] t2[ki, kj, ka] = eris_oovv[ki, kj, ka] / eijab t2 = numpy.conj(t2) self.emp2 = 0.25 * numpy.einsum('pqrijab,pqrijab', t2, eris_oovv).real self.emp2 /= nkpts logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2.real) logger.timer(self, 'init mp2', *time0) return self.emp2, t1, t2
def kernel(self, mo_energy=None, mo_coeff=None, orbs=None, kptlist=None, nw=100): """ Input: kptlist: self-energy k-points orbs: self-energy orbs nw: grid number Output: mo_energy: GW quasiparticle energy """ if mo_coeff is None: mo_coeff = np.array(self._scf.mo_coeff) if mo_energy is None: mo_energy = np.array(self._scf.mo_energy) nmo = self.nmo naux = self.with_df.get_naoaux() nkpts = self.nkpts mem_incore = (2 * nkpts * nmo**2 * naux) * 16 / 1e6 mem_now = lib.current_memory()[0] if (mem_incore + mem_now > 0.99 * self.max_memory): logger.warn(self, 'Memory may not be enough!') raise NotImplementedError cput0 = (logger.process_clock(), logger.perf_counter()) self.dump_flags() self.converged, self.mo_energy, self.mo_coeff = \ kernel(self, mo_energy, mo_coeff, orbs=orbs, kptlist=kptlist, nw=nw, verbose=self.verbose) logger.warn(self, 'GW QP energies may not be sorted from min to max') logger.timer(self, 'GW', *cput0) return self.mo_energy
def get_veff(ks_grad, dm=None, kpts=None): mf = ks_grad.base cell = ks_grad.cell if dm is None: dm = mf.make_rdm1() if kpts is None: kpts = mf.kpts t0 = (logger.process_clock(), logger.perf_counter()) ni = mf._numint if ks_grad.grids is not None: grids = ks_grad.grids else: grids = mf.grids if grids.coords is None: grids.build(with_non0tab=True) omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, spin=cell.spin) mem_now = lib.current_memory()[0] max_memory = max(2000, ks_grad.max_memory*.9-mem_now) if ks_grad.grid_response: raise NotImplementedError else: vxc = get_vxc(ni, cell, grids, mf.xc, dm, kpts, max_memory=max_memory, verbose=ks_grad.verbose) t0 = logger.timer(ks_grad, 'vxc', *t0) if abs(hyb) < 1e-10 and abs(alpha) < 1e-10: vj = ks_grad.get_j(dm, kpts) vxc += vj else: vj, vk = ks_grad.get_jk(dm, kpts) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb operator with cell.with_range_coulomb(omega): vk += ks_grad.get_k(dm, kpts) * (alpha - hyb) vxc += vj - vk * .5 return vxc
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 kconserv = self.kconserv # TODO: check whether to hold Wovov Wovvo in memory if self._fimd is None: self._fimd = lib.H5TmpFile() nkpts, nocc, nvir = t1.shape self._fimd.create_dataset( 'ovov', (nkpts, nkpts, nkpts, nocc, nvir, nocc, nvir), t1.dtype.char) self._fimd.create_dataset( 'ovvo', (nkpts, nkpts, nkpts, nocc, nvir, nvir, nocc), t1.dtype.char) # 2 virtuals self.Wovov = imd.Wovov(t1, t2, eris, kconserv, self._fimd['ovov']) self.Wovvo = imd.Wovvo(t1, t2, eris, kconserv, self._fimd['ovvo']) self.Woovv = eris.oovv log.timer('EOM-CCSD shared two-electron intermediates', *cput0)
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()) log = logger.new_logger(self) if self.direct_scf and self.opt is None: self.opt = self.init_direct_scf(mol) opt_llll, opt_ssll, opt_ssss, opt_gaunt = self.opt vj, vk = get_jk_coulomb(mol, dm, hermi, self._coulomb_level, opt_llll, opt_ssll, opt_ssss, omega, log) if self.with_breit: if ('SSSS' in self._coulomb_level.upper() or # for the case both with_breit and with_ssss are set (not self.with_ssss and 'SSLL' in self._coulomb_level.upper() )): vj1, vk1 = _call_veff_gaunt_breit(mol, dm, hermi, opt_gaunt, True) log.debug('Add Breit term') vj += vj1 vk += vk1 elif self.with_gaunt and 'SS' in self._coulomb_level.upper(): log.debug('Add Gaunt term') vj1, vk1 = _call_veff_gaunt_breit(mol, dm, hermi, opt_gaunt, False) vj += vj1 vk += vk1 log.timer('vj and vk', *t0) return vj, vk
def scf(self, dm0e=None, dm0n=[], **kwargs): cput0 = (logger.process_clock(), logger.perf_counter()) self.dump_flags() if self.max_cycle > 0 or self.mo_coeff is None: self.converged, self.e_tot, self.mf_elec.mo_energy, \ self.mf_elec.mo_coeff, self.mf_elec.mo_occ = \ kernel(self, self.conv_tol, self.conv_tol_grad, dm0e=dm0e, dm0n=dm0n, callback=self.callback, conv_check=self.conv_check, **kwargs)[0 : 5] else: self.e_tot = kernel(self, self.conv_tol, self.conv_tol_grad, dm0e=dm0e, dm0n=dm0n, callback=self.callback, conv_check=self.conv_check, **kwargs)[1] logger.timer(self, 'SCF', *cput0) self._finalize() return self.e_tot
def get_pp(mydf, kpts=None): '''Get the periodic pseudotential nuc-el AO matrix, with G=0 removed. ''' t0 = (logger.process_clock(), logger.perf_counter()) cell = mydf.cell if kpts is None: kpts_lst = numpy.zeros((1,3)) else: kpts_lst = numpy.reshape(kpts, (-1,3)) nkpts = len(kpts_lst) vloc1 = get_pp_loc_part1(mydf, kpts_lst) t1 = logger.timer_debug1(mydf, 'get_pp_loc_part1', *t0) vloc2 = pseudo.pp_int.get_pp_loc_part2(cell, kpts_lst) t1 = logger.timer_debug1(mydf, 'get_pp_loc_part2', *t1) vpp = pseudo.pp_int.get_pp_nl(cell, kpts_lst) for k in range(nkpts): vpp[k] += vloc1[k] + vloc2[k] t1 = logger.timer_debug1(mydf, 'get_pp_nl', *t1) if kpts is None or numpy.shape(kpts) == (3,): vpp = vpp[0] logger.timer(mydf, 'get_pp', *t0) return vpp
def _iterative_kernel(mp, eris, verbose=None): cput1 = cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.new_logger(mp, verbose) emp2, t2 = mp.init_amps(eris=eris) log.info('Init E(MP2) = %.15g', emp2) adiis = lib.diis.DIIS(mp) conv = False for istep in range(mp.max_cycle): t2new = mp.update_amps(t2, eris) if isinstance(t2new, numpy.ndarray): normt = numpy.linalg.norm(t2new - t2) t2 = None t2new = adiis.update(t2new) else: # UMP2 normt = numpy.linalg.norm([numpy.linalg.norm(t2new[i] - t2[i]) for i in range(3)]) t2 = None t2shape = [x.shape for x in t2new] t2new = numpy.hstack([x.ravel() for x in t2new]) t2new = adiis.update(t2new) t2new = lib.split_reshape(t2new, t2shape) t2, t2new = t2new, None emp2, e_last = mp.energy(t2, eris), emp2 log.info('cycle = %d E_corr(MP2) = %.15g dE = %.9g norm(t2) = %.6g', istep+1, emp2, emp2 - e_last, normt) cput1 = log.timer('MP2 iter', *cput1) if abs(emp2-e_last) < mp.conv_tol and normt < mp.conv_tol_normt: conv = True break log.timer('MP2', *cput0) return conv, emp2, t2
def kernel(casci, mo_coeff=None, ci0=None, verbose=logger.NOTE): '''UHF-CASCI solver ''' if mo_coeff is None: mo_coeff = casci.mo_coeff log = logger.new_logger(casci, verbose) t0 = (logger.process_clock(), logger.perf_counter()) log.debug('Start uhf-based CASCI') ncas = casci.ncas nelecas = casci.nelecas ncore = casci.ncore mo_core, mo_cas, mo_vir = extract_orbs(mo_coeff, ncas, nelecas, ncore) # 1e h1eff, energy_core = casci.h1e_for_cas(mo_coeff) log.debug('core energy = %.15g', energy_core) t1 = log.timer('effective h1e in CAS space', *t0) # 2e eri_cas = casci.get_h2eff(mo_cas) t1 = log.timer('integral transformation to CAS space', *t1) # FCI max_memory = max(400, casci.max_memory - lib.current_memory()[0]) e_tot, fcivec = casci.fcisolver.kernel(h1eff, eri_cas, ncas, nelecas, ci0=ci0, verbose=log, max_memory=max_memory, ecore=energy_core) t1 = log.timer('FCI solver', *t1) e_cas = e_tot - energy_core return e_tot, e_cas, fcivec
def make_ip(self, ip_partition=None): self._make_shared_1e() if self._made_shared_2e is False and ip_partition != 'mp': self._make_shared_2e() self._made_shared_2e = True cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(self.stdout, self.verbose) t1,t2,eris = self.t1, self.t2, self.eris kconserv = self.kconserv nkpts, nocc, nvir = t1.shape self._fimd.create_dataset('oooo', (nkpts,nkpts,nkpts,nocc,nocc,nocc,nocc), t1.dtype.char) self._fimd.create_dataset('ooov', (nkpts,nkpts,nkpts,nocc,nocc,nocc,nvir), t1.dtype.char) self._fimd.create_dataset('ovoo', (nkpts,nkpts,nkpts,nocc,nvir,nocc,nocc), t1.dtype.char) # 0 or 1 virtuals if ip_partition != 'mp': self.Woooo = imd.Woooo(t1,t2,eris,kconserv, self._fimd['oooo']) self.Wooov = imd.Wooov(t1,t2,eris,kconserv, self._fimd['ooov']) self.Wovoo = imd.Wovoo(t1,t2,eris,kconserv, self._fimd['ovoo']) self.made_ip_imds = True log.timer('EOM-CCSD IP intermediates', *cput0)
def partial_hess_elec(hessobj, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None, max_memory=4000, verbose=None): log = logger.new_logger(hessobj, verbose) time0 = t1 = (logger.process_clock(), logger.perf_counter()) mol = hessobj.mol mf = hessobj.base 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(mol.natm) nao, nmo = mo_coeff[0].shape mocca = mo_coeff[0][:, mo_occ[0] > 0] moccb = mo_coeff[1][:, mo_occ[1] > 0] dm0a = numpy.dot(mocca, mocca.T) dm0b = numpy.dot(moccb, moccb.T) if mf.nlc != '': raise NotImplementedError #enabling range-separated hybrids omega, alpha, beta = mf._numint.rsh_coeff(mf.xc) if abs(omega) > 1e-10: raise NotImplementedError else: hyb = mf._numint.hybrid_coeff(mf.xc, spin=mol.spin) de2, ej, ek = df_uhf_hess._partial_hess_ejk(hessobj, mo_energy, mo_coeff, mo_occ, atmlst, max_memory, verbose, abs(hyb) > 1e-10) de2 += ej - hyb * ek # (A,B,dR_A,dR_B) mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory * .9 - mem_now) veffa_diag, veffb_diag = uks_hess._get_vxc_diag(hessobj, mo_coeff, mo_occ, max_memory) t1 = log.timer_debug1('contracting int2e_ipip1', *t1) aoslices = mol.aoslice_by_atom() vxca, vxcb = uks_hess._get_vxc_deriv2(hessobj, mo_coeff, mo_occ, max_memory) for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] veffa = vxca[ia] veffb = vxcb[ia] de2[i0, i0] += numpy.einsum('xypq,pq->xy', veffa_diag[:, :, p0:p1], dm0a[p0:p1]) * 2 de2[i0, i0] += numpy.einsum('xypq,pq->xy', veffb_diag[:, :, p0:p1], dm0b[p0:p1]) * 2 for j0, ja in enumerate(atmlst[:i0 + 1]): q0, q1 = aoslices[ja][2:] de2[i0, j0] += numpy.einsum('xypq,pq->xy', veffa[:, :, q0:q1], dm0a[q0:q1]) * 2 de2[i0, j0] += numpy.einsum('xypq,pq->xy', veffb[:, :, q0:q1], dm0b[q0:q1]) * 2 for j0 in range(i0): de2[j0, i0] = de2[i0, j0].T log.timer('UKS partial hessian', *time0) return de2
def kernel(casscf, mo_coeff, tol=1e-7, conv_tol_grad=None, ci0=None, callback=None, verbose=None, dump_chk=True): if verbose is None: verbose = casscf.verbose if callback is None: callback = casscf.callback log = logger.Logger(casscf.stdout, verbose) cput0 = (logger.process_clock(), logger.perf_counter()) log.debug('Start 2-step CASSCF') mo = mo_coeff nmo = mo.shape[1] ncore = casscf.ncore ncas = casscf.ncas nocc = ncore + ncas eris = casscf.ao2mo(mo) e_tot, e_cas, fcivec = casscf.casci(mo, ci0, eris, log, locals()) if ncas == nmo and not casscf.internal_rotation: if casscf.canonicalization: log.debug('CASSCF canonicalization') mo, fcivec, mo_energy = casscf.canonicalize( mo, fcivec, eris, casscf.sorting_mo_energy, casscf.natorb, verbose=log) else: mo_energy = None return True, e_tot, e_cas, fcivec, mo, mo_energy if conv_tol_grad is None: conv_tol_grad = numpy.sqrt(tol) logger.info(casscf, 'Set conv_tol_grad to %g', conv_tol_grad) conv_tol_ddm = conv_tol_grad * 3 conv = False de, elast = e_tot, e_tot totmicro = totinner = 0 casdm1 = 0 r0 = None t2m = t1m = log.timer('Initializing 2-step CASSCF', *cput0) imacro = 0 while not conv and imacro < casscf.max_cycle_macro: imacro += 1 njk = 0 t3m = t2m casdm1_old = casdm1 casdm1, casdm2 = casscf.fcisolver.make_rdm12(fcivec, ncas, casscf.nelecas) norm_ddm = numpy.linalg.norm(casdm1 - casdm1_old) t3m = log.timer('update CAS DM', *t3m) max_cycle_micro = 1 # casscf.micro_cycle_scheduler(locals()) max_stepsize = casscf.max_stepsize_scheduler(locals()) for imicro in range(max_cycle_micro): rota = casscf.rotate_orb_cc(mo, lambda: fcivec, lambda: casdm1, lambda: casdm2, eris, r0, conv_tol_grad * .3, max_stepsize, log) u, g_orb, njk1, r0 = next(rota) rota.close() njk += njk1 norm_t = numpy.linalg.norm(u - numpy.eye(nmo)) norm_gorb = numpy.linalg.norm(g_orb) if imicro == 0: norm_gorb0 = norm_gorb de = numpy.dot(casscf.pack_uniq_var(u), g_orb) t3m = log.timer('orbital rotation', *t3m) eris = None u = u.copy() g_orb = g_orb.copy() mo = casscf.rotate_mo(mo, u, log) eris = casscf.ao2mo(mo) t3m = log.timer('update eri', *t3m) log.debug( 'micro %d ~dE=%5.3g |u-1|=%5.3g |g[o]|=%5.3g |dm1|=%5.3g', imicro, de, norm_t, norm_gorb, norm_ddm) if callable(callback): callback(locals()) t2m = log.timer('micro iter %d' % imicro, *t2m) if norm_t < 1e-4 or abs( de) < tol * .4 or norm_gorb < conv_tol_grad * .2: break totinner += njk totmicro += imicro + 1 e_tot, e_cas, fcivec = casscf.casci(mo, fcivec, eris, log, locals()) log.timer('CASCI solver', *t3m) t2m = t1m = log.timer('macro iter %d' % imacro, *t1m) de, elast = e_tot - elast, e_tot if (abs(de) < tol and norm_gorb < conv_tol_grad and norm_ddm < conv_tol_ddm): conv = True else: elast = e_tot if dump_chk: casscf.dump_chk(locals()) if callable(callback): callback(locals()) if conv: log.info('2-step CASSCF converged in %d macro (%d JK %d micro) steps', imacro, totinner, totmicro) else: log.info( '2-step CASSCF not converged, %d macro (%d JK %d micro) steps', imacro, totinner, totmicro) if casscf.canonicalization: log.info('CASSCF canonicalization') mo, fcivec, mo_energy = \ casscf.canonicalize(mo, fcivec, eris, casscf.sorting_mo_energy, casscf.natorb, casdm1, log) if casscf.natorb and dump_chk: # dump_chk may save casdm1 occ, ucas = casscf._eig(-casdm1, ncore, nocc) casdm1 = numpy.diag(-occ) else: if casscf.natorb: # FIXME (pyscf-2.0): Whether to transform natural orbitals in # active space when this flag is enabled? log.warn( 'The attribute natorb of mcscf object affects only the ' 'orbital canonicalization.\n' 'If you would like to get natural orbitals in active space ' 'without touching core and external orbitals, an explicit ' 'call to mc.cas_natorb_() is required') mo_energy = None if dump_chk: casscf.dump_chk(locals()) log.timer('2-step CASSCF', *cput0) return conv, e_tot, e_cas, fcivec, mo, mo_energy
def kernel(casscf, mo_coeff, tol=1e-7, conv_tol_grad=None, ci0=None, callback=None, verbose=logger.NOTE, dump_chk=True): '''Second order CASSCF driver ''' log = logger.new_logger(casscf, verbose) log.warn('SO-CASSCF (Second order CASSCF) is an experimental feature. ' 'Its performance is bad for large systems.') cput0 = (logger.process_clock(), logger.perf_counter()) log.debug('Start SO-CASSCF (newton CASSCF)') if callback is None: callback = casscf.callback mo = mo_coeff nmo = mo_coeff.shape[1] #TODO: lazy evaluate eris, to leave enough memory for FCI solver eris = casscf.ao2mo(mo) e_tot, e_cas, fcivec = casscf.casci(mo, ci0, eris, log, locals()) if casscf.ncas == nmo and not casscf.internal_rotation: if casscf.canonicalization: log.debug('CASSCF canonicalization') mo, fcivec, mo_energy = casscf.canonicalize(mo, fcivec, eris, casscf.sorting_mo_energy, casscf.natorb, verbose=log) return True, e_tot, e_cas, fcivec, mo, mo_energy casdm1 = casscf.fcisolver.make_rdm1(fcivec, casscf.ncas, casscf.nelecas) if conv_tol_grad is None: conv_tol_grad = numpy.sqrt(tol) logger.info(casscf, 'Set conv_tol_grad to %g', conv_tol_grad) conv_tol_ddm = conv_tol_grad * 3 conv = False totmicro = totinner = 0 norm_gorb = norm_gci = -1 de, elast = e_tot, e_tot dr0 = None t2m = t1m = log.timer('Initializing newton CASSCF', *cput0) imacro = 0 tot_hop = 0 tot_kf = 0 while not conv and imacro < casscf.max_cycle_macro: imacro += 1 u, fcivec, norm_gall, stat, dr0 = \ update_orb_ci(casscf, mo, fcivec, eris, dr0, conv_tol_grad*.3, verbose=log) tot_hop += stat.tot_hop tot_kf += stat.tot_kf t2m = log.timer('update_orb_ci', *t2m) eris = None mo = casscf.rotate_mo(mo, u, log) eris = casscf.ao2mo(mo) t2m = log.timer('update eri', *t2m) e_tot, e_cas, fcivec = casscf.casci(mo, fcivec, eris, log, locals()) log.timer('CASCI solver', *t2m) t2m = t1m = log.timer('macro iter %d'%imacro, *t1m) de, elast = e_tot - elast, e_tot if (abs(de) < tol and norm_gall < conv_tol_grad): conv = True if dump_chk: casscf.dump_chk(locals()) if callable(callback): callback(locals()) if conv: log.info('newton CASSCF converged in %d macro (%d KF %d Hx) steps', imacro, tot_kf, tot_hop) else: log.info('newton CASSCF not converged, %d macro (%d KF %d Hx) steps', imacro, tot_kf, tot_hop) casdm1 = casscf.fcisolver.make_rdm1(fcivec, casscf.ncas, casscf.nelecas) if casscf.canonicalization: log.info('CASSCF canonicalization') mo, fcivec, mo_energy = \ casscf.canonicalize(mo, fcivec, eris, casscf.sorting_mo_energy, casscf.natorb, casdm1, log) if casscf.natorb: # dump_chk may save casdm1 ncas = casscf.ncas ncore = casscf.ncore nocc = ncas + ncore occ, ucas = casscf._eig(-casdm1, ncore, nocc) casdm1 = -occ else: if casscf.natorb: # FIXME (pyscf-2.0): Whether to transform natural orbitals in # active space when this flag is enabled? log.warn('The attribute natorb of mcscf object affects only the ' 'orbital canonicalization.\n' 'If you would like to get natural orbitals in active space ' 'without touching core and external orbitals, an explicit ' 'call to mc.cas_natorb_() is required') mo_energy = None if dump_chk: casscf.dump_chk(locals()) log.timer('newton CASSCF', *cput0) return conv, e_tot, e_cas, fcivec, mo, mo_energy
def davidson(mult_by_A, N, neig, x0=None, Adiag=None, verbose=logger.INFO): """Diagonalize a matrix via non-symmetric Davidson algorithm. mult_by_A() is a function which takes a vector of length N and returns a vector of length N. neig is the number of eigenvalues requested """ if isinstance(verbose, logger.Logger): log = verbose else: import sys log = logger.Logger(sys.stdout, verbose) cput1 = (logger.process_clock(), logger.perf_counter()) Mmin = min(neig,N) Mmax = min(N,2000) tol = 1e-6 #Adiagcheck = np.zeros(N,np.complex) #for i in range(N): # test = np.zeros(N,np.complex) # test[i] = 1.0 # Adiagcheck[i] = mult_by_A(test)[i] #print "Analytical Adiag == numerical Adiag?", np.allclose(Adiag,Adiagcheck) if Adiag is None: Adiag = np.zeros(N,np.complex) for i in range(N): test = np.zeros(N,np.complex) test[i] = 1.0 Adiag[i] = mult_by_A(test)[i] xi = np.zeros(N,np.complex) lamda_k_old = 0 lamda_k = 0 target = 0 conv = False if x0 is not None: assert x0.shape == (N, Mmin) b = x0.copy() Ab = np.zeros((N,Mmin),np.complex) for m in range(Mmin): Ab[:,m] = mult_by_A(b[:,m]) for istep,M in enumerate(range(Mmin,Mmax+1)): if M == Mmin: # Set of M unit vectors from lowest Adiag (NxM) b = np.zeros((N,M)) idx = Adiag.argsort() for m,i in zip(range(M),idx): b[i,m] = 1.0 ## Add random noise and orthogonalize #for m in range(M): # b[:,m] += 0.01*np.random.random(N) # b[:,m] /= np.linalg.norm(b[:,m]) # b,R = np.linalg.qr(b) Ab = np.zeros((N,M),np.complex) for m in range(M): Ab[:,m] = mult_by_A(b[:,m]) else: Ab = np.column_stack( (Ab,mult_by_A(b[:,M-1])) ) Atilde = np.dot(b.conj().transpose(),Ab) lamda, alpha = diagonalize_asymm(Atilde) lamda_k_old, lamda_k = lamda_k, lamda[target] alpha_k = alpha[:,target] if M == Mmax: break q = np.dot( Ab-lamda_k*b, alpha_k ) log.info('davidson istep = %d root = %d E = %.15g dE = %.9g residual = %.6g', istep, target, lamda_k.real, (lamda_k - lamda_k_old).real, np.linalg.norm(q)) cput1 = log.timer('davidson iter', *cput1) if np.linalg.norm(q) < tol: if target == neig-1: conv = True break else: target += 1 #for i in range(N): #eps = 0. #if np.allclose(lamda_k,Adiag[i]): # eps = 1e-10 #xi[i] = q[i]/(lamda_k-Adiag[i]+eps) eps = 1e-10 xi = q/(lamda_k-Adiag+eps) # orthonormalize xi wrt b bxi,R = np.linalg.qr(np.column_stack((b,xi))) if FOUND_MPI4PY: # Ensure all processes search in same direction bxi = MPI_COMM.bcast(bxi) # append orthonormalized xi to b b = np.column_stack((b,bxi[:,-1])) #if M > Mmin and M == Mmax: # print("WARNING: Davidson algorithm reached max basis size " # "M = %d without converging."%(M)) # Express alpha in original basis evecs = np.dot(b,alpha) # b is N x M, alpha is M x M return conv, lamda[:neig], evecs[:,:neig], istep
def eeccsd(self, nroots=1, koopmans=False, guess=None, partition=None): '''Calculate N-electron neutral excitations via EE-EOM-CCSD. Kwargs: nroots : int Number of roots (eigenvalues) requested partition : bool or str Use a matrix-partitioning for the doubles-doubles block. Can be None, 'mp' (Moller-Plesset, i.e. orbital energies on the diagonal), or 'full' (full diagonal elements). koopmans : bool Calculate Koopmans'-like (1p1h) excitations only, targeting via overlap. guess : list of ndarray List of guess vectors to use for targeting via overlap. ''' cput0 = (logger.process_clock(), logger.perf_counter()) log = logger.Logger(self.stdout, self.verbose) size = self.nee() nroots = min(nroots, size) if partition: partition = partition.lower() assert partition in ['mp', 'full'] self.ee_partition = partition if partition == 'full': self._eeccsd_diag_matrix2 = self.vector_to_amplitudes_ee( self.eeccsd_diag())[1] nvir = self.nmo - self.nocc adiag = self.eeccsd_diag() user_guess = False if guess: user_guess = True assert len(guess) == nroots for g in guess: assert g.size == size else: guess = [] idx = adiag.argsort() n = 0 for i in idx: g = np.zeros(size) g[i] = 1.0 if koopmans: if np.linalg.norm(g[:self.nocc * nvir])**2 > 0.8: guess.append(g) n += 1 else: guess.append(g) n += 1 if n == nroots: break def precond(r, e0, x0): return r / (e0 - adiag + 1e-12) eig = linalg_helper.eig if user_guess or koopmans: def pickeig(w, v, nr, envs): x0 = linalg_helper._gen_x0(envs['v'], envs['xs']) idx = np.argmax(np.abs( np.dot(np.array(guess).conj(), np.array(x0).T)), axis=1) return lib.linalg_helper._eigs_cmplx2real(w, v, idx) eee, evecs = eig(self.eeccsd_matvec, guess, precond, pick=pickeig, tol=self.conv_tol, max_cycle=self.max_cycle, max_space=self.max_space, nroots=nroots, verbose=self.verbose) else: eee, evecs = eig(self.eeccsd_matvec, guess, precond, tol=self.conv_tol, max_cycle=self.max_cycle, max_space=self.max_space, nroots=nroots, verbose=self.verbose) self.eee = eee.real if nroots == 1: eee, evecs = [self.eee], [evecs] for n, en, vn in zip(range(nroots), eee, evecs): logger.info(self, 'EE root %d E = %.16g qpwt = %0.6g', n, en, np.linalg.norm(vn[:self.nocc * nvir])**2) log.timer('EE-CCSD', *cput0) if nroots == 1: return eee[0], evecs[0] else: return eee, evecs