def grad_elec(mfg, mo_energy=None, mo_coeff=None, mo_occ=None): t0 = (time.clock(), time.time()) mf = mfg._scf mol = mfg.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 h1 = mfg.get_hcore(mol) s1 = mfg.get_ovlp(mol) dm0 = mf.make_rdm1(mf.mo_coeff, mf.mo_occ) vhf = mfg.get_veff(mol, dm0) log.timer(mfg, 'gradients of 2e part', *t0) f1 = h1 + vhf dme0 = mfg.make_rdm1e(mf.mo_energy, mf.mo_coeff, mf.mo_occ) gs = numpy.empty((mol.natm,3)) for ia in range(mol.natm): # h1, s1, vhf are \nabla <i|h|j>, the nuclear gradients = -\nabla f =-(mfg.matblock_by_atom(mol, ia, f1) + mfg._grad_rinv(mol, ia)) s = -mfg.matblock_by_atom(mol, ia, s1) v = numpy.einsum('ij,kji->k', dm0, f) \ - numpy.einsum('ij,kji->k', dme0, s) gs[ia] = 2 * v.real log.debug(mfg, 'gradients of electronic part') log.debug(mfg, str(gs)) return gs
def kernel(self, mo_coeff=None, mo_occ=None): if mo_coeff is None: mo_coeff = self.mo_coeff if mo_occ is None: mo_occ = self.mo_occ cput0 = (time.clock(), time.time()) self.build(self.mol) self.dump_flags() if mo_coeff is None or mo_occ is None: logger.debug(self, 'Initial guess orbitals not given. ' 'Generating initial guess from %s density matrix', self.init_guess) dm = mf.get_init_guess(self.mol, self.init_guess) mo_coeff, mo_occ = self.from_dm(dm) # save initial guess because some methods may access them self.mo_coeff = mo_coeff self.mo_occ = mo_occ self.converged, self.e_tot, \ self.mo_energy, self.mo_coeff, self.mo_occ = \ kernel(self, mo_coeff, mo_occ, 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 solve_mo1(sscobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): cput1 = (time.clock(), time.time()) 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 init_amps(self, eris=None): time0 = time.clock(), time.time() if eris is None: eris = self.ao2mo(self.mo_coeff) nocca, noccb = self.nocc fova = eris.focka[:nocca,nocca:] fovb = eris.fockb[:noccb,noccb:] mo_ea_o = eris.mo_energy[0][:nocca] mo_ea_v = eris.mo_energy[0][nocca:] mo_eb_o = eris.mo_energy[1][:noccb] mo_eb_v = eris.mo_energy[1][noccb:] eia_a = lib.direct_sum('i-a->ia', mo_ea_o, mo_ea_v) eia_b = lib.direct_sum('i-a->ia', mo_eb_o, mo_eb_v) t1a = fova.conj() / eia_a t1b = fovb.conj() / eia_b eris_ovov = np.asarray(eris.ovov) eris_OVOV = np.asarray(eris.OVOV) eris_ovOV = np.asarray(eris.ovOV) t2aa = eris_ovov.transpose(0,2,1,3) / lib.direct_sum('ia+jb->ijab', eia_a, eia_a) t2ab = eris_ovOV.transpose(0,2,1,3) / lib.direct_sum('ia+jb->ijab', eia_a, eia_b) t2bb = eris_OVOV.transpose(0,2,1,3) / lib.direct_sum('ia+jb->ijab', eia_b, eia_b) t2aa = t2aa - t2aa.transpose(0,1,3,2) t2bb = t2bb - t2bb.transpose(0,1,3,2) e = np.einsum('iJaB,iaJB', t2ab, eris_ovOV) e += 0.25*np.einsum('ijab,iajb', t2aa, eris_ovov) e -= 0.25*np.einsum('ijab,ibja', t2aa, eris_ovov) e += 0.25*np.einsum('ijab,iajb', t2bb, eris_OVOV) e -= 0.25*np.einsum('ijab,ibja', t2bb, eris_OVOV) self.emp2 = e.real logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2) logger.timer(self, 'init mp2', *time0) return self.emp2, (t1a,t1b), (t2aa,t2ab,t2bb)
def shielding(self, mo1=None): cput0 = (time.clock(), time.time()) self.dump_flags() if self.verbose >= logger.WARN: self.check_sanity() t0 = (time.clock(), time.time()) unit_ppm = nist.ALPHA**2 * 1e6 msc_dia = self.dia() * unit_ppm t0 = logger.timer(self, 'h11', *t0) msc_para, para_pos, para_neg, para_occ = \ [x*unit_ppm for x in self.para(mo10=mo1)] e11 = msc_para + msc_dia logger.timer(self, 'NMR shielding', *cput0) if self.verbose > logger.QUIET: for i, atm_id in enumerate(self.shielding_nuc): rhf_nmr._write(self.stdout, e11[i], '\ntotal shielding of atom %d %s' % (atm_id, self.mol.atom_symbol(atm_id))) rhf_nmr._write(self.stdout, msc_dia[i], 'dia-magnetism') rhf_nmr._write(self.stdout, msc_para[i], 'para-magnetism') if self.verbose >= logger.INFO: rhf_nmr._write(self.stdout, para_occ[i], 'occ part of para-magnetism') rhf_nmr._write(self.stdout, para_pos[i], 'vir-pos part of para-magnetism') rhf_nmr._write(self.stdout, para_neg[i], 'vir-neg part of para-magnetism') return e11
def shielding(self, mo1=None): cput0 = (time.clock(), time.time()) self.dump_flags() if self.verbose >= logger.WARN: self.check_sanity() facppm = 1e6/param.LIGHTSPEED**2 t0 = (time.clock(), time.time()) msc_dia = self.dia() * facppm t0 = logger.timer(self, 'h11', *t0) msc_para, para_pos, para_neg, para_occ = \ [x*facppm for x in self.para(mo10=mo1)] e11 = msc_para + msc_dia logger.timer(self, 'NMR shielding', *cput0) if self.verbose > param.VERBOSE_QUIET: for i, atm_id in enumerate(self.shielding_nuc): rhf_nmr._write(self.stdout, e11[i], '\ntotal shielding of atom %d %s' % (atm_id, self.mol.atom_symbol(atm_id-1))) rhf_nmr._write(self.stdout, msc_dia[i], 'dia-magnetism') rhf_nmr._write(self.stdout, msc_para[i], 'para-magnetism') if self.verbose >= param.VERBOSE_INFO: rhf_nmr._write(self.stdout, para_occ[i], 'occ part of para-magnetism') rhf_nmr._write(self.stdout, para_pos[i], 'vir-pos part of para-magnetism') rhf_nmr._write(self.stdout, para_neg[i], 'vir-neg part of para-magnetism') self.stdout.flush() return e11
def init_amps(self, eris): time0 = time.clock(), time.time() nocc = self.nocc() nvir = self.nmo() - nocc nkpts = self.nkpts t1 = numpy.zeros((nkpts, nocc, nvir), dtype=numpy.complex128) t2 = numpy.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=numpy.complex128) woovv = numpy.empty((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=numpy.complex128) self.emp2 = 0 foo = eris.fock[:, :nocc, :nocc].copy() fvv = eris.fock[:, nocc:, nocc:].copy() eris_oovv = eris.oovv.copy() eia = numpy.zeros((nocc, nvir)) eijab = numpy.zeros((nocc, nocc, nvir, nvir)) kconserv = self.kconserv for ki in range(nkpts): for kj in range(nkpts): for ka in range(nkpts): kb = kconserv[ki, ka, kj] eia = np.diagonal(foo[ki]).reshape(-1, 1) - np.diagonal(fvv[ka]) ejb = np.diagonal(foo[kj]).reshape(-1, 1) - np.diagonal(fvv[kb]) eijab = lib.direct_sum("ia,jb->ijab", eia, ejb) woovv[ki, kj, ka] = 2 * eris_oovv[ki, kj, ka] - eris_oovv[ki, kj, kb].transpose(0, 1, 3, 2) t2[ki, kj, ka] = eris_oovv[ki, kj, ka] / eijab t2 = numpy.conj(t2) self.emp2 = numpy.einsum("pqrijab,pqrijab", t2, woovv).real self.emp2 /= nkpts logger.info(self, "Init t2, MP2 energy = %.15g", self.emp2) logger.timer(self, "init mp2", *time0) return self.emp2, t1, t2
def scf(self, dm0=None): cput0 = (time.clock(), time.time()) mol = self.mol self.build(mol) self.dump_flags() self.converged, self.hf_energy, \ self.mo_energy, self.mo_coeff, self.mo_occ \ = hf.kernel(self, self.conv_tol, dm0=dm0, callback=self.callback) logger.timer(self, 'SCF', *cput0) self.dump_energy(self.hf_energy, self.converged) # sort MOs wrt orbital energies, it should be done last. o_sort = numpy.argsort(self.mo_energy[self.mo_occ>0]) v_sort = numpy.argsort(self.mo_energy[self.mo_occ==0]) self.mo_energy = numpy.hstack((self.mo_energy[self.mo_occ>0][o_sort], \ self.mo_energy[self.mo_occ==0][v_sort])) self.mo_coeff = numpy.hstack((self.mo_coeff[:,self.mo_occ>0][:,o_sort], \ self.mo_coeff[:,self.mo_occ==0][:,v_sort])) nocc = len(o_sort) self.mo_occ[:nocc] = self.mo_occ[self.mo_occ>0][o_sort] self.mo_occ[nocc:] = 0 #if self.verbose >= logger.INFO: # self.analyze(self.verbose) return self.hf_energy
def shielding(self, mo1=None): cput0 = (time.clock(), time.time()) self.check_sanity() self.dump_flags() unit_ppm = nist.ALPHA**2 * 1e6 msc_dia = self.dia(self.gauge_orig) if mo1 is None: self.mo10, self.mo_e10 = self.solve_mo1() mo1 = self.mo10 msc_para, para_vir, para_occ = self.para(mo10=mo1) msc_dia *= unit_ppm msc_para *= unit_ppm para_vir *= unit_ppm para_occ *= unit_ppm e11 = msc_para + msc_dia logger.timer(self, 'NMR shielding', *cput0) if self.verbose >= logger.NOTE: for i, atm_id in enumerate(self.shielding_nuc): _write(self.stdout, e11[i], '\ntotal shielding of atom %d %s' \ % (atm_id, self.mol.atom_symbol(atm_id))) _write(self.stdout, msc_dia[i], 'dia-magnetic contribution') _write(self.stdout, msc_para[i], 'para-magnetic contribution') if self.verbose >= logger.INFO: _write(self.stdout, para_occ[i], 'occ part of para-magnetism') _write(self.stdout, para_vir[i], 'vir part of para-magnetism') return e11
def get_jk(self, mol=None, dm=None, hermi=1): if mol is None: mol = self.mol if dm is None: dm = self.make_rdm1() t0 = (time.clock(), time.time()) vj, vk = get_jk(mol, dm, hermi, self.opt) logger.timer(self, 'vj and vk', *t0) return vj, vk
def get_jk(self, mol=None, dm=None, hermi=1): if mol is None: mol = self.mol if dm is None: dm = self.make_rdm1() t0 = (time.clock(), time.time()) verbose_bak, mol.verbose = mol.verbose, self.verbose stdout_bak, mol.stdout = mol.stdout , self.stdout if self.direct_scf and self.opt[0] 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_now, opt_llll, opt_ssll, opt_ssss) if self.with_breit: if 'SSSS' in self._coulomb_now.upper() or not self.with_ssss: vj1, vk1 = _call_veff_gaunt_breit(mol, dm, hermi, opt_gaunt, True) logger.info(self, 'Add Breit term') vj += vj1 vk += vk1 elif self.with_gaunt and 'SS' in self._coulomb_now.upper(): logger.info(self, 'Add Gaunt term') vj1, vk1 = _call_veff_gaunt_breit(mol, dm, hermi, opt_gaunt, False) vj += vj1 vk += vk1 mol.verbose = verbose_bak mol.stdout = stdout_bak logger.timer(self, 'vj and vk', *t0) return vj, vk
def get_jk_(self, cell=None, dm=None, hermi=1, kpt=None, kpt_band=None): '''Get Coulomb (J) and exchange (K) following :func:`scf.hf.RHF.get_jk_`. Note the incore version, which initializes an _eri array in memory. ''' if cell is None: cell = self.cell if dm is None: dm = self.make_rdm1() if kpt is None: kpt = self.kpt cpu0 = (time.clock(), time.time()) vj, vk = get_jk(self, cell, dm, hermi, self.opt, kpt, kpt_band) # TODO: Check incore, direct_scf, _eri's, etc #if self._eri is not None or cell.incore_anyway or self._is_mem_enough(): # print "self._is_mem_enough() =", self._is_mem_enough() # if self._eri is None: # logger.debug(self, 'Building PBC AO integrals incore') # if kpt is not None and pyscf.lib.norm(kpt) > 1.e-15: # raise RuntimeError("Non-zero kpts not implemented for incore eris") # self._eri = ao2mo.get_ao_eri(cell) # if np.iscomplexobj(dm) or np.iscomplexobj(self._eri): # vj, vk = dot_eri_dm_complex(self._eri, dm, hermi) # else: # vj, vk = pyscf.scf.hf.dot_eri_dm(self._eri, dm, hermi) #else: # if self.direct_scf: # self.opt = self.init_direct_scf(cell) # vj, vk = get_jk(cell, dm, hermi, self.opt, kpt) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
def init_amps(self, eris): time0 = time.clock(), time.time() nocc = self.nocc() nvir = self.nmo() - nocc nkpts = self.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 foo = eris.fock[:,:nocc,:nocc].copy() fvv = eris.fock[:,nocc:,nocc:].copy() eris_oovv = eris.oovv.copy() eia = numpy.zeros((nocc,nvir)) eijab = numpy.zeros((nocc,nocc,nvir,nvir)) kconserv = tools.get_kconserv(self._scf.cell,self.kpts) for ki in range(nkpts): for kj in range(nkpts): for ka in range(nkpts): kb = kconserv[ki,ka,kj] for i in range(nocc): for a in range(nvir): eia[i,a] = foo[ki,i,i] - fvv[ka,a,a] for j in range(nocc): for b in range(nvir): eijab[i,j,a,b] = ( foo[ki,i,i] + foo[kj,j,j] - fvv[ka,a,a] - fvv[kb,b,b] ) t2[ki,kj,ka,i,j,a,b] = eris_oovv[ki,kj,ka,i,j,a,b]/eijab[i,j,a,b] 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) print "MP2 energy =", self.emp2 return self.emp2, t1, t2
def scf(self, dm0=None): '''main routine for SCF Kwargs: dm0 : ndarray If given, it will be used as the initial guess density matrix Examples: >>> import numpy >>> from pyscf import gto, scf >>> mol = gto.M(atom='H 0 0 0; F 0 0 1.1') >>> mf = scf.hf.SCF(mol) >>> dm_guess = numpy.eye(mol.nao_nr()) >>> mf.kernel(dm_guess) converged SCF energy = -98.5521904482821 -98.552190448282104 ''' cput0 = (time.clock(), time.time()) self.build() self.dump_flags() self.converged, self.hf_energy, \ self.mo_energy, self.mo_coeff, self.mo_occ = \ kernel(self, self.conv_tol, dm0=dm0, callback=self.callback) logger.timer(self, 'SCF', *cput0) self.dump_energy(self.hf_energy, self.converged) #if self.verbose >= logger.INFO: # self.analyze(self.verbose) return self.hf_energy
def solve_mo1(self, mo_energy=None, mo_occ=None, h1=None, s1=None): cput1 = (time.clock(), time.time()) log = logger.Logger(self.stdout, self.verbose) if mo_energy is None: mo_energy = self._scf.mo_energy if mo_occ is None: mo_occ = self._scf.mo_occ mol = self.mol if h1 is None: mo_coeff = self._scf.mo_coeff dm0 = self._scf.make_rdm1(mo_coeff, mo_occ) h1 = _mat_ao2mo(self.make_h10(mol, dm0), mo_coeff, mo_occ) if s1 is None: s1 = _mat_ao2mo(self.make_s10(mol), mo_coeff, mo_occ) cput1 = log.timer("first order Fock matrix", *cput1) if self.cphf: mo10, mo_e10 = cphf.solve( self.get_vind, mo_energy, mo_occ, h1, s1, self.max_cycle_cphf, self.conv_tol, verbose=log ) else: mo10, mo_e10 = solve_mo1(mo_energy, mo_occ, h1, s1) logger.timer(self, "solving mo1 eqn", *cput1) return mo10, mo_e10
def get_jk(self, cell=None, dm=None, hermi=1, kpt=None, kpt_band=None): '''Get Coulomb (J) and exchange (K) following :func:`scf.hf.RHF.get_jk_`. Note the incore version, which initializes an _eri array in memory. ''' if cell is None: cell = self.cell if dm is None: dm = self.make_rdm1() if kpt is None: kpt = self.kpt cpu0 = (time.clock(), time.time()) if (kpt_band is None and (self.exxdiv == 'ewald' or self.exxdiv is None) and (self._eri is not None or cell.incore_anyway or 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 = dot_eri_dm(self._eri, dm, hermi) if 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], [vk]) else: vj, vk = self.with_df.get_jk(dm, hermi, kpt, kpt_band, exxdiv=self.exxdiv) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
def get_j(self, cell=None, dm=None, hermi=1, kpt=None, kpts_band=None): r'''Compute J matrix for the given density matrix and k-point (kpt). When kpts_band is given, the J matrices on kpts_band are evaluated. J_{pq} = \sum_{rs} (pq|rs) dm[s,r] 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. ''' #return self.get_jk(cell, dm, hermi, kpt, kpts_band)[0] if cell is None: cell = self.cell if dm is None: dm = self.make_rdm1() if kpt is None: kpt = self.kpt cpu0 = (time.clock(), time.time()) dm = np.asarray(dm) nao = dm.shape[-1] if (kpts_band is None 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.reshape(-1,nao,nao), hermi) else: vj = self.with_df.get_jk(dm.reshape(-1,nao,nao), hermi, kpt, kpts_band, with_k=False)[0] logger.timer(self, 'vj', *cpu0) return _format_jks(vj, dm, kpts_band)
def init_amps(self, eris): time0 = time.clock(), time.time() mo_e = eris.fock.diagonal() nocc = self.nocc() nvir = mo_e.size - nocc t1 = np.zeros((nocc,nvir), eris.dtype) #eia = mo_e[:nocc,None] - mo_e[None,nocc:] #t1 = eris.fock[:nocc,nocc:] / eia t2 = np.zeros((nocc,nocc,nvir,nvir), eris.dtype) self.emp2 = 0 foo = eris.fock[:nocc,:nocc] fvv = eris.fock[nocc:,nocc:] eia = np.zeros((nocc,nvir)) eijab = np.zeros((nocc,nocc,nvir,nvir)) for i in range(nocc): for a in range(nvir): eia[i,a] = (foo[i,i] - fvv[a,a]).real for j in range(nocc): for b in range(nvir): eijab[i,j,a,b] = ( foo[i,i] + foo[j,j] - fvv[a,a] - fvv[b,b] ).real t2[i,j,a,b] = eris.oovv[i,j,a,b]/eijab[i,j,a,b] eris_oovv = _cp(eris.oovv) 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 get_jk(self, mol=None, dm=None, hermi=0): if mol is None: mol = self.mol if dm is None: dm = self._scf.make_rdm1() cpu0 = (time.clock(), time.time()) #TODO: direct_scf opt vj, vk = get_jk(mol, dm) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
def get_jk(self, cell=None, dm_kpts=None, hermi=1, kpts=None, kpt_band=None): 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 = (time.clock(), time.time()) vj, vk = self.with_df.get_jk(dm_kpts, hermi, kpts, kpt_band, exxdiv=self.exxdiv) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
def get_j(self, cell=None, dm_kpts=None, hermi=1, kpts=None, kpt_band=None): 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 = (time.clock(), time.time()) vj = self.with_df.get_jk(dm_kpts, hermi, kpts, kpt_band, with_k=False)[0] logger.timer(self, 'vj', *cpu0) return vj
def write_chk(mc, root, chkfile): t0 = (time.clock(), time.time()) fh5 = h5py.File(chkfile, "w") if mc.fcisolver.nroots > 1: mc.mo_coeff, _, mc.mo_energy = mc.canonicalize(mc.mo_coeff, ci=root) fh5["mol"] = format(mc.mol.pack()) fh5["mc/mo"] = mc.mo_coeff fh5["mc/ncore"] = mc.ncore fh5["mc/ncas"] = mc.ncas nvirt = mc.mo_coeff.shape[1] - mc.ncas - mc.ncore fh5["mc/nvirt"] = nvirt fh5["mc/nelecas"] = mc.nelecas fh5["mc/root"] = root fh5["mc/orbe"] = mc.mo_energy if hasattr(mc, "orbsym"): fh5.create_dataset("mc/orbsym", data=mc.orbsym) else: fh5.create_dataset("mc/orbsym", data=[]) mo_core = mc.mo_coeff[:, : mc.ncore] mo_cas = mc.mo_coeff[:, mc.ncore : mc.ncore + mc.ncas] mo_virt = mc.mo_coeff[:, mc.ncore + mc.ncas :] core_dm = numpy.dot(mo_core, mo_core.T) * 2 core_vhf = mc.get_veff(mc.mol, core_dm) h1e_Sr = reduce(numpy.dot, (mo_virt.T, mc.get_hcore() + core_vhf, mo_cas)) h1e_Si = reduce(numpy.dot, (mo_cas.T, mc.get_hcore() + core_vhf, mo_core)) fh5["h1e_Si"] = h1e_Si fh5["h1e_Sr"] = h1e_Sr h1e = mc.h1e_for_cas() fh5["h1e"] = h1e[0] if mc._scf._eri is None: from pyscf.scf import _vhf eri = _vhf.int2e_sph(mc.mol._atm, mol._bas, mol._env) else: eri = mc._scf._eri # FIXME # add outcore later h2e = ao2mo.incore.general(eri, [mo_cas, mo_cas, mo_cas, mo_cas], compact=False) h2e = h2e.reshape(mc.ncas, mc.ncas, mc.ncas, mc.ncas) fh5["h2e"] = h2e h2e_Sr = ao2mo.incore.general(eri, [mo_virt, mo_cas, mo_cas, mo_cas], compact=False) h2e_Sr = h2e_Sr.reshape(nvirt, mc.ncas, mc.ncas, mc.ncas) fh5["h2e_Sr"] = h2e_Sr h2e_Si = ao2mo.incore.general(eri, [mo_cas, mo_core, mo_cas, mo_cas], compact=False) h2e_Si = h2e_Si.reshape(mc.ncas, mc.ncore, mc.ncas, mc.ncas) fh5["h2e_Si"] = h2e_Si fh5.close() logger.timer(mc, "Write MPS NEVPT integral", *t0)
def get_jk_(self, mol=None, dm=None, hermi=1): if mol is None: mol = self.mol if dm is None: dm = self.make_rdm1() t0 = (time.clock(), time.time()) 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) logger.timer(self, 'vj and vk', *t0) return vj, vk
def get_jk(self, cell=None, dm_kpts=None, hermi=1, kpt=None, kpt_band=None): # Must use 'kpt' kwarg if cell is None: cell = self.cell if kpt is None: kpt = self.kpts kpts = kpt if dm_kpts is None: dm_kpts = self.make_rdm1() cpu0 = (time.clock(), time.time()) vj, vk = get_jk(self, cell, dm_kpts, kpts, kpt_band) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
def get_jk(self, mol=None, dm=None, hermi=1): '''Compute J, K matrices for the given density matrix. See :func:`scf.hf.get_jk` ''' if mol is None: mol = self.mol if dm is None: dm = self.make_rdm1() cpu0 = (time.clock(), time.time()) vj, vk = get_jk(mol, dm, hermi, self.opt) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1, kpts=None, kpt_band=None): '''Coulomb + XC functional for UKS. See pyscf/pbc/dft/uks.py :func:`get_veff` fore more details. ''' if cell is None: cell = ks.cell if dm is None: dm = ks.make_rdm1() if kpts is None: kpts = ks.kpts t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.build() small_rho_cutoff = ks.small_rho_cutoff t0 = logger.timer(ks, 'setting up grids', *t0) else: small_rho_cutoff = 0 dm = np.asarray(dm) nao = dm.shape[-1] # ndim = 4 : dm.shape = (alpha_beta, nkpts, nao, nao) ground_state = (dm.ndim == 4 and kpt_band is None) nkpts = len(kpts) if hermi == 2: # because rho = 0 n, ks._exc, vx = 0, 0, 0 else: n, ks._exc, vx = ks._numint.nr_uks(cell, ks.grids, ks.xc, dm, 1, kpts, kpt_band) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) hyb = ks._numint.hybrid_coeff(ks.xc, spin=(cell.spin>0)+1) if abs(hyb) < 1e-10: vj = ks.get_j(cell, dm, hermi, kpts, kpt_band) vhf = lib.asarray([vj[0]+vj[1]] * 2) else: vj, vk = ks.get_jk(cell, dm, hermi, kpts, kpt_band) vhf = pbcuhf._makevhf(vj, vk*hyb) if ground_state: ks._exc -= (np.einsum('Kij,Kji', dm[0], vk[0]) + np.einsum('Kij,Kji', dm[1], vk[1])).real * .5 * hyb * (1./nkpts) if ground_state: ks._ecoul = np.einsum('Kij,Kji', dm[0]+dm[1], vj[0]+vj[1]).real * .5 * (1./nkpts) if small_rho_cutoff > 1e-20 and ground_state: # Filter grids the first time setup grids idx = ks._numint.large_rho_indices(cell, dm, ks.grids, small_rho_cutoff, kpts) logger.debug(ks, 'Drop grids %d', ks.grids.weights.size - np.count_nonzero(idx)) ks.grids.coords = np.asarray(ks.grids.coords [idx], order='C') ks.grids.weights = np.asarray(ks.grids.weights[idx], order='C') ks._numint.non0tab = None return vhf + vx
def write_chk(mc,root,chkfile): t0 = (time.clock(), time.time()) fh5 = h5py.File(chkfile,'w') if mc.fcisolver.nroots > 1: mc.mo_coeff,_, mc.mo_energy = mc.canonicalize(mc.mo_coeff,ci=root) fh5['mol'] = format(mc.mol.pack()) fh5['mc/mo'] = mc.mo_coeff fh5['mc/ncore'] = mc.ncore fh5['mc/ncas'] = mc.ncas nvirt = mc.mo_coeff.shape[1] - mc.ncas-mc.ncore fh5['mc/nvirt'] = nvirt fh5['mc/nelecas'] = mc.nelecas fh5['mc/root'] = root fh5['mc/orbe'] = mc.mo_energy if hasattr(mc, 'orbsym'): fh5.create_dataset('mc/orbsym',data=mc.orbsym) else : fh5.create_dataset('mc/orbsym',data=[]) mo_core = mc.mo_coeff[:,:mc.ncore] mo_cas = mc.mo_coeff[:,mc.ncore:mc.ncore+mc.ncas] mo_virt = mc.mo_coeff[:,mc.ncore+mc.ncas:] core_dm = numpy.dot(mo_core,mo_core.T) *2 core_vhf = mc.get_veff(mc.mol,core_dm) h1e_Sr = reduce(numpy.dot, (mo_virt.T,mc.get_hcore()+core_vhf , mo_cas)) h1e_Si = reduce(numpy.dot, (mo_cas.T, mc.get_hcore()+core_vhf , mo_core)) fh5['h1e_Si'] = h1e_Si fh5['h1e_Sr'] = h1e_Sr h1e = mc.h1e_for_cas() fh5['h1e'] = h1e[0] if mc._scf._eri is None: h2e = ao2mo.outcore.general_iofree(mc.mol, (mo_cas,mo_cas,mo_cas,mo_cas),compact=False).reshape(mc.ncas,mc.ncas,mc.ncas,mc.ncas) fh5['h2e'] = h2e h2e_Sr = ao2mo.outcore.general_iofree(mc.mol,(mo_virt,mo_cas,mo_cas,mo_cas),compact=False).reshape(nvirt,mc.ncas,mc.ncas,mc.ncas) fh5['h2e_Sr'] = h2e_Sr h2e_Si = ao2mo.outcore.general_iofree(mc.mol,(mo_cas,mo_core,mo_cas,mo_cas),compact=False).reshape(mc.ncas,mc.ncore,mc.ncas,mc.ncas) fh5['h2e_Si'] = h2e_Si else: eri = mc._scf._eri h2e = ao2mo.incore.general(eri,[mo_cas,mo_cas,mo_cas,mo_cas],compact=False).reshape(mc.ncas,mc.ncas,mc.ncas,mc.ncas) fh5['h2e'] = h2e h2e_Sr = ao2mo.incore.general(eri,[mo_virt,mo_cas,mo_cas,mo_cas],compact=False).reshape(nvirt,mc.ncas,mc.ncas,mc.ncas) fh5['h2e_Sr'] = h2e_Sr h2e_Si = ao2mo.incore.general(eri,[mo_cas,mo_core,mo_cas,mo_cas],compact=False).reshape(mc.ncas,mc.ncore,mc.ncas,mc.ncas) fh5['h2e_Si'] = h2e_Si fh5.close() logger.timer(mc,'Write MPS NEVPT integral', *t0)
def get_jk(self, mol=None, dm=None, hermi=1): if mol is None: mol = self.mol if dm is None: dm = self.make_rdm1() cpu0 = (time.clock(), time.time()) if self.direct_scf and self.opt is None: self.opt = self.init_direct_scf(mol) dm = numpy.asarray(dm) nao = dm.shape[-1] vj, vk = get_jk(mol, dm.reshape(-1,nao,nao), hermi, self.opt) logger.timer(self, 'vj and vk', *cpu0) return vj.reshape(dm.shape), vk.reshape(dm.shape)
def get_j(self, cell=None, dm=None, hermi=1, kpt=None, kpt_band=None): '''Compute J matrix for the given density matrix. ''' #return self.get_jk(cell, dm, hermi, kpt, kpt_band)[0] if cell is None: cell = self.cell if dm is None: dm = self.make_rdm1() if kpt is None: kpt = self.kpt cpu0 = (time.clock(), time.time()) vj = get_j(cell, dm, hermi, self.opt, kpt, kpt_band) logger.timer(self, 'vj', *cpu0) return vj
def get_jk(self, mol=None, dm=None, hermi=1): if mol is None: mol = self.mol if dm is None: dm = self.make_rdm1() cpu0 = (time.clock(), time.time()) if self._eri is not None or self._is_mem_enough(): if self._eri is None: self._eri = _vhf.int2e_sph(mol._atm, mol._bas, mol._env) vj, vk = hf.dot_eri_dm(self._eri, dm, hermi) else: vj, vk = hf.get_jk(mol, dm, hermi, self.opt) logger.timer(self, 'vj and vk', *cpu0) return vj, vk
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 calc_optim_veig(dscf, target_dm, target_dec=None, gvx=None, nstep=1, force_factor=1., **optim_args): clfn = gen_coul_loss(dscf, fock=dscf.get_fock(vhf=dscf.get_veff0())) dm = dscf.make_rdm1() if dm.ndim == 3 and isinstance(dscf, scf.uhf.UHF): dm = dm.sum(0) t_dm = torch.from_numpy(dm).requires_grad_() t_eig = t_make_eig(t_dm, dscf._t_ovlp_shells).requires_grad_() t_ec = dscf.net(t_eig.to(dscf.device)) t_veig = torch.autograd.grad(t_ec, t_eig)[0].requires_grad_() t_lde = torch.from_numpy(target_dec) if target_dec is not None else None t_gvx = torch.from_numpy(gvx) if gvx is not None else None # build closure def closure(): [t_vc] = torch.autograd.grad( t_eig, t_dm, t_veig, retain_graph=True, create_graph=True) loss, dldv = clfn(t_vc.detach().numpy(), target_dm) grad = torch.autograd.grad( t_vc, t_veig, torch.from_numpy(dldv), only_inputs=True)[0] # build closure for force loss if t_lde is not None and t_gvx is not None: t_pde = torch.tensordot(t_gvx, t_veig) lossde = force_factor * torch.sum((t_pde - t_lde)**2) grad = grad + torch.autograd.grad(lossde, t_veig, only_inputs=True)[0] loss = loss + lossde t_veig.grad = grad return loss # do the optimization optim = torch.optim.LBFGS([t_veig], **optim_args) tic = (time.process_time(), time.perf_counter()) for _ in range(nstep): optim.step(closure) tic = logger.timer(dscf, 'LBFGS step', *tic) logger.note(dscf, f"optimized loss for veig = {closure()}") return t_veig.detach().numpy()
def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1): '''Coulomb + XC functional for UKS. See pyscf/dft/rks.py :func:`get_veff` fore more details. ''' if mol is None: mol = ks.mol if dm is None: dm = ks.make_rdm1() if not isinstance(dm, numpy.ndarray): dm = numpy.asarray(dm) if dm.ndim == 2: # RHF DM dm = numpy.asarray((dm * .5, dm * .5)) ks.initialize_grids(mol, dm) t0 = (logger.process_clock(), logger.perf_counter()) ground_state = (dm.ndim == 3 and dm.shape[0] == 2) ni = ks._numint if hermi == 2: # because rho = 0 n, exc, vxc = (0, 0), 0, 0 else: max_memory = ks.max_memory - lib.current_memory()[0] n, exc, vxc = ni.nr_uks(mol, ks.grids, ks.xc, dm, max_memory=max_memory) if ks.nlc: assert 'VV10' in ks.nlc.upper() _, enlc, vnlc = ni.nr_rks(mol, ks.nlcgrids, ks.xc + '__' + ks.nlc, dm[0] + dm[1], max_memory=max_memory) exc += enlc vxc += vnlc logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) #enabling range-separated hybrids omega, alpha, hyb = ni.rsh_and_hybrid_coeff(ks.xc, spin=mol.spin) if abs(hyb) < 1e-10 and abs(alpha) < 1e-10: vk = None if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vj', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj = ks.get_j(mol, ddm[0] + ddm[1], hermi) vj += vhf_last.vj else: vj = ks.get_j(mol, dm[0] + dm[1], hermi) vxc += vj else: if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vk', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj, vk = ks.get_jk(mol, ddm, hermi) vk *= hyb if abs(omega) > 1e-10: vklr = ks.get_k(mol, ddm, hermi, omega) vklr *= (alpha - hyb) vk += vklr vj = vj[0] + vj[1] + vhf_last.vj vk += vhf_last.vk else: vj, vk = ks.get_jk(mol, dm, hermi) vj = vj[0] + vj[1] vk *= hyb if abs(omega) > 1e-10: vklr = ks.get_k(mol, dm, hermi, omega) vklr *= (alpha - hyb) vk += vklr vxc += vj - vk if ground_state: exc -= (numpy.einsum('ij,ji', dm[0], vk[0]).real + numpy.einsum('ij,ji', dm[1], vk[1]).real) * .5 if ground_state: ecoul = numpy.einsum('ij,ji', dm[0] + dm[1], vj).real * .5 else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=vj, vk=vk) return vxc
def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1): '''Coulomb + XC functional for GKS. ''' if mol is None: mol = self.mol if dm is None: dm = ks.make_rdm1() t0 = (time.clock(), time.time()) ground_state = (isinstance(dm, numpy.ndarray) and dm.ndim == 2) assert (hermi == 1) dm = numpy.asarray(dm) nso = dm.shape[-1] nao = nso // 2 dm_a = dm[..., :nao, :nao].real dm_b = dm[..., nao:, nao:].real if ks.grids.coords is None: ks.grids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: ks.grids = rks.prune_small_rho_grids_(ks, mol, dm_a + dm_b, ks.grids) t0 = logger.timer(ks, 'setting up grids', *t0) if ks.nlc != '': if ks.nlcgrids.coords is None: ks.nlcgrids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: ks.nlcgrids = rks.prune_small_rho_grids_( ks, mol, dm_a + dm_b, ks.nlcgrids) t0 = logger.timer(ks, 'setting up nlc grids', *t0) max_memory = ks.max_memory - lib.current_memory()[0] ni = ks._numint n, exc, vxc = ni.nr_uks(mol, ks.grids, ks.xc, (dm_a, dm_b), max_memory=max_memory) if ks.nlc != '': assert ('VV10' in ks.nlc.upper()) _, enlc, vnlc = ni.nr_rks(mol, ks.nlcgrids, ks.xc + '__' + ks.nlc, dm_a + dm_b, max_memory=max_memory) exc += enlc vxc += vnlc logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) if vxc.ndim == 4: raise NotImplementedError vxc = numpy.asarray(scipy.linalg.block_diag(*vxc), dtype=dm.dtype) #enabling range-separated hybrids omega, alpha, hyb = ni.rsh_and_hybrid_coeff(ks.xc, spin=mol.spin) if abs(hyb) < 1e-10 and abs(alpha) < 1e-10: vk = None if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vj', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj = ks.get_j(mol, ddm, hermi) vj += vhf_last.vj else: vj = ks.get_j(mol, dm, hermi) vxc += vj else: if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vk', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj, vk = ks.get_jk(mol, ddm, hermi) vk *= hyb if abs(omega) > 1e-10: vklr = _get_k_lr(mol, ddm, omega, hermi) vklr *= (alpha - hyb) vk += vklr vj += vhf_last.vj vk += vhf_last.vk else: vj, vk = ks.get_jk(mol, dm, hermi) vk *= hyb if abs(omega) > 1e-10: vklr = _get_k_lr(mol, dm, omega, hermi) vklr *= (alpha - hyb) vk += vklr vxc += vj - vk if ground_state: exc -= numpy.einsum('ij,ji', dm, vk).real * .5 if ground_state: ecoul = numpy.einsum('ij,ji', dm, vj).real * .5 else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=vj, vk=vk) return vxc
def r_get_jk(dfobj, dms, hermi=1, with_j=True, with_k=True): '''Relativistic density fitting JK''' t0 = (time.clock(), time.time()) mol = dfobj.mol c1 = .5 / lib.param.LIGHT_SPEED tao = mol.tmap() ao_loc = mol.ao_loc_2c() n2c = ao_loc[-1] def fjk(dm): dm = numpy.asarray(dm, dtype=numpy.complex128) fmmm = libri.RIhalfmmm_r_s2_bra_noconj fdrv = _ao2mo.libao2mo.AO2MOr_e2_drv ftrans = libri.RItranse2_r_s2 vj = numpy.zeros_like(dm) vk = numpy.zeros_like(dm) fcopy = libri.RImmm_r_s2_transpose rargs = (ctypes.c_int(n2c), (ctypes.c_int * 4)(0, n2c, 0, 0), tao.ctypes.data_as(ctypes.c_void_p), ao_loc.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.nbas)) dmll = numpy.asarray(dm[:n2c, :n2c], order='C') dmls = numpy.asarray(dm[:n2c, n2c:], order='C') * c1 dmsl = numpy.asarray(dm[n2c:, :n2c], order='C') * c1 dmss = numpy.asarray(dm[n2c:, n2c:], order='C') * c1**2 for erill, eriss in dfobj.loop(): naux, nao_pair = erill.shape buf = numpy.empty((naux, n2c, n2c), dtype=numpy.complex) buf1 = numpy.empty((naux, n2c, n2c), dtype=numpy.complex) fdrv(ftrans, fmmm, buf.ctypes.data_as(ctypes.c_void_p), erill.ctypes.data_as(ctypes.c_void_p), dmll.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), *rargs) # buf == (P|LL) rho = numpy.einsum('kii->k', buf) fdrv(ftrans, fcopy, buf1.ctypes.data_as(ctypes.c_void_p), erill.ctypes.data_as(ctypes.c_void_p), dmll.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), *rargs) # buf1 == (P|LL) vk[:n2c, :n2c] += numpy.dot( buf1.reshape(-1, n2c).T, buf.reshape(-1, n2c)) fdrv(ftrans, fmmm, buf.ctypes.data_as(ctypes.c_void_p), eriss.ctypes.data_as(ctypes.c_void_p), dmls.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), *rargs) # buf == (P|LS) vk[:n2c, n2c:] += numpy.dot( buf1.reshape(-1, n2c).T, buf.reshape(-1, n2c)) * c1 fdrv(ftrans, fmmm, buf.ctypes.data_as(ctypes.c_void_p), eriss.ctypes.data_as(ctypes.c_void_p), dmss.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), *rargs) # buf == (P|SS) rho += numpy.einsum('kii->k', buf) vj[:n2c, :n2c] += lib.unpack_tril(numpy.dot(rho, erill), 1) vj[n2c:, n2c:] += lib.unpack_tril(numpy.dot(rho, eriss), 1) * c1**2 fdrv(ftrans, fcopy, buf1.ctypes.data_as(ctypes.c_void_p), eriss.ctypes.data_as(ctypes.c_void_p), dmss.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), *rargs) # buf == (P|SS) vk[n2c:, n2c:] += numpy.dot( buf1.reshape(-1, n2c).T, buf.reshape(-1, n2c)) * c1**2 if hermi != 1: fdrv(ftrans, fmmm, buf.ctypes.data_as(ctypes.c_void_p), erill.ctypes.data_as(ctypes.c_void_p), dmsl.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), *rargs) # buf == (P|SL) vk[n2c:, :n2c] += numpy.dot( buf1.reshape(-1, n2c).T, buf.reshape(-1, n2c)) * c1 if hermi == 1: vk[n2c:, :n2c] = vk[:n2c, n2c:].T.conj() return vj, vk if isinstance(dms, numpy.ndarray) and dms.ndim == 2: vj, vk = fjk(dms) else: vjk = [fjk(dm) for dm in dms] vj = numpy.array([x[0] for x in vjk]) vk = numpy.array([x[1] for x in vjk]) logger.timer(dfobj, 'vj and vk', *t0) return vj, vk
def get_veff(ks_grad, mol=None, dm=None): '''Coulomb + XC functional ''' if mol is None: mol = ks_grad.mol if dm is None: dm = ks_grad.base.make_rdm1() t0 = (time.clock(), time.time()) mf = ks_grad.base 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) if mf.nlc != '': raise NotImplementedError #enabling range-separated hybrids omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, spin=mol.spin) mem_now = lib.current_memory()[0] max_memory = max(2000, ks_grad.max_memory * .9 - mem_now) if ks_grad.grid_response: exc, vxc = rks_grad.get_vxc_full_response(ni, mol, grids, mf.xc, dm, max_memory=max_memory, verbose=ks_grad.verbose) logger.debug1(ks_grad, 'sum(grids response) %s', exc.sum(axis=0)) else: exc, vxc = rks_grad.get_vxc(ni, mol, grids, mf.xc, dm, 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(mol, dm) vxc += vj if ks_grad.auxbasis_response: e1_aux = vj.aux else: vj, vk = ks_grad.get_jk(mol, dm) if ks_grad.auxbasis_response: vk_aux = vk.aux * hyb vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb operator raise NotImplementedError vk_lr = ks_grad.get_k(mol, dm, omega=omega) vk += vk_lr * (alpha - hyb) if ks_grad.auxbasis_response: vk_aux += vk_lr.aux * (alpha - hyb) vxc += vj - vk * .5 if ks_grad.auxbasis_response: e1_aux = vj.aux - vk_aux * .5 if ks_grad.auxbasis_response: logger.debug1(ks_grad, 'sum(auxbasis response) %s', e1_aux.sum(axis=0)) vxc = lib.tag_array(vxc, exc1_grid=exc, aux=e1_aux) else: vxc = lib.tag_array(vxc, exc1_grid=exc) return vxc
def get_jk(self, dm_kpts, hermi=1, kpts=None, kpts_band=None, with_j=True, with_k=True, omega=None, exxdiv=None): if omega is not None: # J/K for RSH functionals # TODO: call AFTDF.get_jk function raise NotImplementedError # Does not support to specify arbitrary kpts if kpts is not None and abs(kpts - self.kpts).max() > 1e-7: raise RuntimeError('kpts error') kpts = self.kpts if kpts_band is not None: raise NotImplementedError cpu0 = (time.clock(), time.time()) if self.supmol is None: self.build() nkpts = kpts.shape[0] vhfopt = self.vhfopt supmol = self.supmol bvkcell = self.bvkcell phase = self.phase cell = self.cell_rs nao = cell.nao orig_nao = self.cell.nao # * dense_bvk_ao_loc are the AOs which appear in supmol (some basis # are removed) # * sparse_ao_loc has dimension (Nk,nbas), corresponding to the # bvkcell with all basis dense_bvk_ao_loc = bvkcell.ao_loc sparse_ao_loc = nao * np.arange(nkpts)[:, None] + cell.ao_loc[:-1] sparse_ao_loc = np.append(sparse_ao_loc.ravel(), nao * nkpts) nbands = nkpts if dm_kpts.ndim != 4: dm = dm_kpts.reshape(-1, nkpts, orig_nao, orig_nao) else: dm = dm_kpts n_dm = dm.shape[0] rs_c_coeff = cell._contr_coeff sc_dm = lib.einsum('nkij,pi,qj->nkpq', dm, rs_c_coeff, rs_c_coeff) # Utilized symmetry sc_dm[R,S] = sc_dm[S-R] = sc_dm[(S-R)%N] #:sc_dm = lib.einsum('Rk,nkuv,Sk->nRuSv', phase, sc_dm, phase.conj()) sc_dm = lib.einsum('k,Sk,nkuv->nSuv', phase[0], phase.conj(), sc_dm) dm_translation = k2gamma.double_translation_indices( self.bvk_kmesh).astype(np.int32) dm_imag_max = abs(sc_dm.imag).max() is_complex_dm = dm_imag_max > 1e-6 if is_complex_dm: if dm_imag_max < 1e-2: logger.warn( self, 'DM in (BvK) cell has small imaginary part. ' 'It may be a signal of symmetry broken in k-point symmetry' ) sc_dm = np.vstack([sc_dm.real, sc_dm.imag]) else: sc_dm = sc_dm.real sc_dm = np.asarray(sc_dm.reshape(-1, nkpts, nao, nao), order='C') n_sc_dm = sc_dm.shape[0] dm_cond = [ lib.condense('NP_absmax', d, sparse_ao_loc, sparse_ao_loc[:cell.nbas + 1]) for d in sc_dm ] dm_cond = np.asarray(np.max(dm_cond, axis=0), order='C') libpbc.CVHFset_dm_cond(vhfopt._this, dm_cond.ctypes.data_as(ctypes.c_void_p), dm_cond.size) dm_cond = None bvk_nbas = bvkcell.nbas shls_slice = (0, cell.nbas, 0, bvk_nbas, 0, bvk_nbas, 0, bvk_nbas) if hermi: fdot_suffix = 's2kl' else: fdot_suffix = 's1' if with_j and with_k: fdot = 'PBCVHF_contract_jk_' + fdot_suffix vs = np.zeros((2, n_sc_dm, nao, nkpts, nao)) elif with_j: fdot = 'PBCVHF_contract_j_' + fdot_suffix vs = np.zeros((1, n_sc_dm, nao, nkpts, nao)) else: # with_k fdot = 'PBCVHF_contract_k_' + fdot_suffix vs = np.zeros((1, n_sc_dm, nao, nkpts, nao)) drv = libpbc.PBCVHF_direct_drv drv(getattr(libpbc, fdot), vs.ctypes.data_as(ctypes.c_void_p), sc_dm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(n_dm), ctypes.c_int(nkpts), ctypes.c_int(nbands), ctypes.c_int(cell.nbas), self.ovlp_mask.ctypes.data_as(ctypes.c_void_p), self.bvk_cell_id.ctypes.data_as(ctypes.c_void_p), self.cell0_shl_id.ctypes.data_as(ctypes.c_void_p), supmol._images_loc.ctypes.data_as(ctypes.c_void_p), (ctypes.c_int * 8)(*shls_slice), dense_bvk_ao_loc.ctypes.data_as(ctypes.c_void_p), dm_translation.ctypes.data_as(ctypes.c_void_p), vhfopt._cintopt, vhfopt._this, supmol._atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(supmol.natm), supmol._bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(supmol.nbas), supmol._env.ctypes.data_as(ctypes.c_void_p)) if is_complex_dm: vs = vs[:, :n_dm] + vs[:, n_dm:] * 1j if with_j and with_k: vj, vk = vs elif with_j: vj, vk = vs[0], None else: vj, vk = None, vs[0] cpu1 = logger.timer(self, 'short range part vj and vk', *cpu0) lr_c_coeff = self.lr_aft.cell._contr_coeff lr_dm = lib.einsum('nkij,pi,qj->nkpq', dm, lr_c_coeff, lr_c_coeff) # For rho product other than diffused-diffused block, construct LR # parts in terms of full ERIs and SR ERIs vj1, vk1 = self.lr_aft.get_jk(lr_dm, hermi, kpts, kpts_band, with_j, with_k, exxdiv=exxdiv) cpu1 = logger.timer(self, 'AFT-vj and AFT-vk', *cpu1) # expRk is almost the same to phase, except a normalization factor expRk = np.exp(1j * np.dot(self.bvkmesh_Ls, kpts.T)) if with_j: vj = lib.einsum('npRq,pi,qj,Rk->nkij', vj, rs_c_coeff, rs_c_coeff, expRk) vj += lib.einsum('nkpq,pi,qj->nkij', vj1, lr_c_coeff, lr_c_coeff) if self.purify and kpts_band is None: vj = _purify(vj, phase) if gamma_point(kpts) and dm_kpts.dtype == np.double: vj = vj.real if hermi: vj = (vj + vj.conj().transpose(0, 1, 3, 2)) * .5 vj = vj.reshape(dm_kpts.shape) if with_k: vk = lib.einsum('npRq,pi,qj,Rk->nkij', vk, rs_c_coeff, rs_c_coeff, expRk) vk += lib.einsum('nkpq,pi,qj->nkij', vk1, lr_c_coeff, lr_c_coeff) if self.purify and kpts_band is None: vk = _purify(vk, phase) if gamma_point(kpts) and dm_kpts.dtype == np.double: vk = vk.real if hermi: vk = (vk + vk.conj().transpose(0, 1, 3, 2)) * .5 vk = vk.reshape(dm_kpts.shape) return vj, vk
def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True, ishf=True): t0 = (time.clock(), time.time()) if mol is None: mol = mf_grad.mol if dm is None: dm = mf_grad.base.make_rdm1() with_df = mf_grad.base.with_df auxmol = with_df.auxmol if auxmol is None: auxmol = df.addons.make_auxmol(with_df.mol, with_df.auxbasis) pmol = mol + auxmol ao_loc = mol.ao_loc nbas = mol.nbas nauxbas = auxmol.nbas get_int3c_s1 = _int3c_wrapper(mol, auxmol, 'int3c2e', 's1') get_int3c_s2 = _int3c_wrapper(mol, auxmol, 'int3c2e', 's2ij') get_int3c_ip1 = _int3c_wrapper(mol, auxmol, 'int3c2e_ip1', 's1') get_int3c_ip2 = _int3c_wrapper(mol, auxmol, 'int3c2e_ip2', 's2ij') nao = mol.nao naux = auxmol.nao dms = numpy.asarray(dm) out_shape = dms.shape[:-2] + (3, ) + dms.shape[-2:] dms = dms.reshape(-1, nao, nao) nset = dms.shape[0] idx = numpy.arange(nao) idx = idx * (idx + 1) // 2 + idx dm_tril = dms + dms.transpose(0, 2, 1) dm_tril = lib.pack_tril(dm_tril) dm_tril[:, idx] *= .5 auxslices = auxmol.aoslice_by_atom() aux_loc = auxmol.ao_loc max_memory = mf_grad.max_memory - lib.current_memory()[0] blksize = int(min(max(max_memory * .5e6 / 8 / (nao**2 * 3), 20), naux, 240)) ao_ranges = balance_partition(aux_loc, blksize) if not with_k: # (i,j|P) rhoj = numpy.empty((nset, naux)) for shl0, shl1, nL in ao_ranges: int3c = get_int3c_s2((0, nbas, 0, nbas, shl0, shl1)) # (i,j|P) p0, p1 = aux_loc[shl0], aux_loc[shl1] rhoj[:, p0:p1] = lib.einsum('wp,nw->np', int3c, dm_tril) int3c = None # (P|Q) int2c = auxmol.intor('int2c2e', aosym='s1') rhoj = scipy.linalg.solve(int2c, rhoj.T, sym_pos=True).T int2c = None # (d/dX i,j|P) vj = numpy.zeros((nset, 3, nao, nao)) for shl0, shl1, nL in ao_ranges: int3c = get_int3c_ip1((0, nbas, 0, nbas, shl0, shl1)) # (i,j|P) p0, p1 = aux_loc[shl0], aux_loc[shl1] vj += lib.einsum('xijp,np->nxij', int3c, rhoj[:, p0:p1]) int3c = None if mf_grad.auxbasis_response: # (i,j|d/dX P) vjaux = numpy.empty((nset, nset, 3, naux)) for shl0, shl1, nL in ao_ranges: int3c = get_int3c_ip2( (0, nbas, 0, nbas, shl0, shl1)) # (i,j|P) p0, p1 = aux_loc[shl0], aux_loc[shl1] vjaux[:, :, :, p0:p1] = lib.einsum('xwp,mw,np->mnxp', int3c, dm_tril, rhoj[:, p0:p1]) int3c = None # (d/dX P|Q) int2c_e1 = auxmol.intor('int2c2e_ip1', aosym='s1') vjaux -= lib.einsum('xpq,mp,nq->mnxp', int2c_e1, rhoj, rhoj) vjaux = numpy.array([ -vjaux[:, :, :, p0:p1].sum(axis=3) for p0, p1 in auxslices[:, 2:] ]) if ishf: vjaux = vjaux.sum((1, 2)) else: vjaux = numpy.ascontiguousarray(vjaux.transpose(1, 2, 0, 3)) vj = lib.tag_array(-vj.reshape(out_shape), aux=numpy.array(vjaux)) else: vj = -vj.reshape(out_shape) logger.timer(mf_grad, 'df vj', *t0) return vj, None if hasattr(dm, 'mo_coeff') and hasattr(dm, 'mo_occ'): mo_coeff = dm.mo_coeff mo_occ = dm.mo_occ elif ishf: mo_coeff = mf_grad.base.mo_coeff mo_occ = mf_grad.base.mo_occ if isinstance(mf_grad.base, scf.rohf.ROHF): mo_coeff = numpy.vstack((mo_coeff, mo_coeff)) mo_occa = numpy.array(mo_occ > 0, dtype=numpy.double) mo_occb = numpy.array(mo_occ == 2, dtype=numpy.double) assert (mo_occa.sum() + mo_occb.sum() == mo_occ.sum()) mo_occ = numpy.vstack((mo_occa, mo_occb)) else: s0 = mol.intor('int1e_ovlp') mo_occ = [] mo_coeff = [] for dm in dms: sdms = reduce(lib.dot, (s0, dm, s0)) n, c = scipy.linalg.eigh(sdms, b=s0) mo_occ.append(n) mo_coeff.append(c) mo_occ = numpy.stack(mo_occ, axis=0) nmo = mo_occ.shape[-1] mo_coeff = numpy.asarray(mo_coeff).reshape(-1, nao, nmo) mo_occ = numpy.asarray(mo_occ).reshape(-1, nmo) rhoj = numpy.zeros((nset, naux)) f_rhok = lib.H5TmpFile() orbor = [] orbol = [] nocc = [] orbor_stack = numpy.zeros((nao, 0), dtype=mo_coeff.dtype, order='F') orbol_stack = numpy.zeros((nao, 0), dtype=mo_coeff.dtype, order='F') offs = 0 for i in range(nset): idx = numpy.abs(mo_occ[i]) > 1e-8 nocc.append(numpy.count_nonzero(idx)) c = mo_coeff[i][:, idx] orbol_stack = numpy.append(orbol_stack, c, axis=1) orbol.append(orbol_stack[:, offs:offs + nocc[-1]]) cn = lib.einsum('pi,i->pi', c, mo_occ[i][idx]) orbor_stack = numpy.append(orbor_stack, cn, axis=1) orbor.append(orbor_stack[:, offs:offs + nocc[-1]]) offs += nocc[-1] # (P|Q) int2c = scipy.linalg.cho_factor(auxmol.intor('int2c2e', aosym='s1')) t1 = (time.clock(), time.time()) max_memory = mf_grad.max_memory - lib.current_memory()[0] blksize = max_memory * .5e6 / 8 / (naux * nao) mol_ao_ranges = balance_partition(ao_loc, blksize) nsteps = len(mol_ao_ranges) t2 = t1 for istep, (shl0, shl1, nd) in enumerate(mol_ao_ranges): int3c = get_int3c_s1((0, nbas, shl0, shl1, 0, nauxbas)) t2 = logger.timer_debug1(mf_grad, 'df grad intor (P|mn)', *t2) p0, p1 = ao_loc[shl0], ao_loc[shl1] for i in range(nset): # MRH 05/21/2020: De-vectorize this because array contiguity -> parallel scaling v = lib.dot(int3c.reshape(nao, -1, order='F').T, orbor[i]).reshape(naux, (p1 - p0) * nocc[i]) t2 = logger.timer_debug1(mf_grad, 'df grad einsum (P|mn) u_ni N_i = v_Pmi', *t2) rhoj[i] += numpy.dot(v, orbol[i][p0:p1].ravel()) t2 = logger.timer_debug1(mf_grad, 'df grad einsum v_Pmi u_mi = rho_P', *t2) v = scipy.linalg.cho_solve(int2c, v) t2 = logger.timer_debug1(mf_grad, 'df grad cho_solve (P|Q) D_Qmi = v_Pmi', *t2) f_rhok['%s/%s' % (i, istep)] = v.reshape(naux, p1 - p0, -1) t2 = logger.timer_debug1( mf_grad, 'df grad cache D_Pmi (m <-> i transpose upon retrieval)', *t2) int3c = v = None rhoj = scipy.linalg.cho_solve(int2c, rhoj.T).T int2c = None t1 = logger.timer_debug1( mf_grad, 'df grad vj and vk AO (P|Q) D_Q = (P|mn) D_mn solve', *t1) def load(set_id, p0, p1): buf = numpy.empty((p1 - p0, nocc[set_id], nao)) col1 = 0 for istep in range(nsteps): dat = f_rhok['%s/%s' % (set_id, istep)][p0:p1] col0, col1 = col1, col1 + dat.shape[1] buf[:p1 - p0, :, col0:col1] = dat.transpose(0, 2, 1) return buf vj = numpy.zeros((nset, 3, nao, nao)) vk = numpy.zeros((nset, 3, nao, nao)) # (d/dX i,j|P) fmmm = _ao2mo.libao2mo.AO2MOmmm_bra_nr_s1 # MO output index slower than AO output index; input AOs are asymmetric fdrv = _ao2mo.libao2mo.AO2MOnr_e2_drv # comp and aux indices are slower ftrans = _ao2mo.libao2mo.AO2MOtranse2_nr_s1 # input is not tril_packed null = lib.c_null_ptr() t2 = t1 for shl0, shl1, nL in ao_ranges: int3c = get_int3c_ip1((0, nbas, 0, nbas, shl0, shl1)).transpose(0, 3, 2, 1) # (P|mn'), row-major order t2 = logger.timer_debug1(mf_grad, "df grad intor (P|mn')", *t2) p0, p1 = aux_loc[shl0], aux_loc[shl1] for i in range(nset): # MRH 05/21/2020: De-vectorize this because array contiguity -> parallel scaling vj[i, 0] += numpy.dot(rhoj[i, p0:p1], int3c[0].reshape(p1 - p0, -1)).reshape(nao, nao).T vj[i, 1] += numpy.dot(rhoj[i, p0:p1], int3c[1].reshape(p1 - p0, -1)).reshape(nao, nao).T vj[i, 2] += numpy.dot(rhoj[i, p0:p1], int3c[2].reshape(p1 - p0, -1)).reshape(nao, nao).T t2 = logger.timer_debug1(mf_grad, "df grad einsum rho_P (P|mn') rho_P", *t2) tmp = numpy.empty((3, p1 - p0, nocc[i], nao), dtype=orbol_stack.dtype) fdrv( ftrans, fmmm, # xPmn u_mi -> xPin tmp.ctypes.data_as(ctypes.c_void_p), int3c.ctypes.data_as(ctypes.c_void_p), orbol[i].ctypes.data_as(ctypes.c_void_p), ctypes.c_int(3 * (p1 - p0)), ctypes.c_int(nao), (ctypes.c_int * 4)(0, nocc[i], 0, nao), null, ctypes.c_int(0)) t2 = logger.timer_debug1(mf_grad, "df grad einsum (P|mn') u_mi = dg_Pin", *t2) rhok = load(i, p0, p1) vk[i] += lib.einsum('xpoi,pok->xik', tmp, rhok) t2 = logger.timer_debug1(mf_grad, "df grad einsum D_Pim dg_Pin = v_ij", *t2) rhok = tmp = None int3c = None t1 = logger.timer_debug1(mf_grad, 'df grad vj and vk AO (P|mn) D_P eval', *t1) if mf_grad.auxbasis_response: # Cache (P|uv) D_ui c_vj. Must be include both upper and lower triangles # over nset. max_memory = mf_grad.max_memory - lib.current_memory()[0] blksize = int( min(max(max_memory * .5e6 / 8 / (nao * max(nocc)), 20), naux)) rhok_oo = [] for i, j in product(range(nset), repeat=2): tmp = numpy.empty((naux, nocc[i], nocc[j])) for p0, p1 in lib.prange(0, naux, blksize): rhok = load(i, p0, p1).reshape((p1 - p0) * nocc[i], nao) tmp[p0:p1] = lib.dot(rhok, orbol[j]).reshape(p1 - p0, nocc[i], nocc[j]) rhok_oo.append(tmp) rhok = tmp = None t1 = logger.timer_debug1( mf_grad, 'df grad vj and vk aux d_Pim u_mj = d_Pij eval', *t1) vjaux = numpy.zeros((nset, nset, 3, naux)) vkaux = numpy.zeros((nset, nset, 3, naux)) # (i,j|d/dX P) t2 = t1 fmmm = _ao2mo.libao2mo.AO2MOmmm_bra_nr_s2 # MO output index slower than AO output index; input AOs are symmetric fdrv = _ao2mo.libao2mo.AO2MOnr_e2_drv # comp and aux indices are slower ftrans = _ao2mo.libao2mo.AO2MOtranse2_nr_s2 # input is tril_packed null = lib.c_null_ptr() for shl0, shl1, nL in ao_ranges: int3c = get_int3c_ip2((0, nbas, 0, nbas, shl0, shl1)) # (i,j|P) t2 = logger.timer_debug1(mf_grad, "df grad intor (P'|mn)", *t2) p0, p1 = aux_loc[shl0], aux_loc[shl1] drhoj = lib.dot( int3c.transpose(0, 2, 1).reshape(3 * (p1 - p0), -1), dm_tril.T).reshape(3, p1 - p0, -1) # xpij,mij->xpm vjaux[:, :, :, p0:p1] = lib.einsum('xpm,np->mnxp', drhoj, rhoj[:, p0:p1]) t2 = logger.timer_debug1( mf_grad, "df grad einsum rho_P (P'|mn) D_mn = v_P", *t2) tmp = [ numpy.empty((3, p1 - p0, nocc_i, nao), dtype=orbor_stack.dtype) for nocc_i in nocc ] assert (orbor_stack.flags.f_contiguous), '{} {}'.format( orbor_stack.shape, orbor_stack.strides) for orb, buf, nocc_i in zip(orbol, tmp, nocc): fdrv( ftrans, fmmm, # gPmn u_ni -> gPim buf.ctypes.data_as(ctypes.c_void_p), int3c.ctypes.data_as(ctypes.c_void_p), orb.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(3 * (p1 - p0)), ctypes.c_int(nao), (ctypes.c_int * 4)(0, nocc_i, 0, nao), null, ctypes.c_int(0)) int3c = [[ lib.dot(buf.reshape(-1, nao), orb).reshape(3, p1 - p0, -1, norb) for orb, norb in zip(orbor, nocc) ] for buf in tmp] # pim,mj,j -> pij t2 = logger.timer_debug1( mf_grad, "df grad einsum (P'|mn) u_mi u_nj N_j = v_Pmn", *t2) for i, j in product(range(nset), repeat=2): k = (i * nset) + j tmp = rhok_oo[k][p0:p1] vkaux[i, j, :, p0:p1] += lib.einsum('xpij,pij->xp', int3c[i][j], tmp) t2 = logger.timer_debug1(mf_grad, "df grad einsum d_Pij v_Pij = v_P", *t2) int3c = tmp = None t1 = logger.timer_debug1(mf_grad, "df grad vj and vk aux (P'|mn) eval", *t1) # (d/dX P|Q) int2c_e1 = auxmol.intor('int2c2e_ip1') vjaux -= lib.einsum('xpq,mp,nq->mnxp', int2c_e1, rhoj, rhoj) for i, j in product(range(nset), repeat=2): k = (i * nset) + j l = (j * nset) + i tmp = lib.einsum('pij,qji->pq', rhok_oo[k], rhok_oo[l]) vkaux[i, j] -= lib.einsum('xpq,pq->xp', int2c_e1, tmp) t1 = logger.timer_debug1(mf_grad, "df grad vj and vk aux (P'|Q) eval", *t1) vjaux = numpy.array([ -vjaux[:, :, :, p0:p1].sum(axis=3) for p0, p1 in auxslices[:, 2:] ]) vkaux = numpy.array([ -vkaux[:, :, :, p0:p1].sum(axis=3) for p0, p1 in auxslices[:, 2:] ]) if ishf: vjaux = vjaux.sum((1, 2)) idx = numpy.array(list(range(nset))) * (nset + 1) vkaux = vkaux.reshape((nset**2, 3, mol.natm))[idx, :, :].sum(0) else: vjaux = numpy.ascontiguousarray(vjaux.transpose(1, 2, 0, 3)) vkaux = numpy.ascontiguousarray(vkaux.transpose(1, 2, 0, 3)) vj = lib.tag_array(-vj.reshape(out_shape), aux=numpy.array(vjaux)) vk = lib.tag_array(-vk.reshape(out_shape), aux=numpy.array(vkaux)) else: vj = -vj.reshape(out_shape) vk = -vk.reshape(out_shape) logger.timer(mf_grad, 'df grad vj and vk', *t0) return vj, vk
def write_chk(mc,root,chkfile): t0 = (time.clock(), time.time()) fh5 = h5py.File(chkfile,'w') if mc.fcisolver.nroots > 1: mc.mo_coeff,_, mc.mo_energy = mc.canonicalize(mc.mo_coeff,ci=root) fh5['mol'] = mc.mol.dumps() fh5['mc/mo'] = mc.mo_coeff fh5['mc/ncore'] = mc.ncore fh5['mc/ncas'] = mc.ncas nvirt = mc.mo_coeff.shape[1] - mc.ncas-mc.ncore fh5['mc/nvirt'] = nvirt fh5['mc/nelecas'] = mc.nelecas fh5['mc/root'] = root fh5['mc/orbe'] = mc.mo_energy fh5['mc/nroots'] = mc.fcisolver.nroots fh5['mc/wfnsym'] = mc.fcisolver.wfnsym if hasattr(mc.mo_coeff, 'orbsym'): fh5.create_dataset('mc/orbsym',data=mc.mo_coeff.orbsym) else : fh5.create_dataset('mc/orbsym',data=[]) if hasattr(mc.mo_coeff, 'orbsym') and mc.mol.symmetry: orbsym = numpy.asarray(mc.mo_coeff.orbsym) pair_irrep = orbsym.reshape(-1,1) ^ orbsym else: pair_irrep = None ncore = mc.ncore nocc = mc.ncore + mc.ncas mo_core = mc.mo_coeff[:,:mc.ncore] mo_cas = mc.mo_coeff[:,mc.ncore:mc.ncore+mc.ncas] mo_virt = mc.mo_coeff[:,mc.ncore+mc.ncas:] core_dm = numpy.dot(mo_core,mo_core.T) *2 core_vhf = mc.get_veff(mc.mol,core_dm) h1e_Sr = reduce(numpy.dot, (mo_virt.T,mc.get_hcore()+core_vhf , mo_cas)) h1e_Si = reduce(numpy.dot, (mo_cas.T, mc.get_hcore()+core_vhf , mo_core)) h1e, e_core = mc.h1e_for_cas() if pair_irrep is not None: h1e_Sr[pair_irrep[nocc:,ncore:nocc] != 0] = 0 h1e_Si[pair_irrep[ncore:nocc,:ncore] != 0] = 0 h1e[pair_irrep[ncore:nocc,ncore:nocc] != 0] = 0 fh5['h1e_Si'] = h1e_Si fh5['h1e_Sr'] = h1e_Sr fh5['h1e'] = h1e fh5['e_core'] = e_core if mc._scf._eri is None: h2e_t = ao2mo.general(mc.mol, (mc.mo_coeff,mo_cas,mo_cas,mo_cas), compact=False) h2e_t = h2e_t.reshape(-1,mc.ncas,mc.ncas,mc.ncas) if pair_irrep is not None: sym_forbid = (pair_irrep[:,ncore:nocc].reshape(-1,1) != pair_irrep[ncore:nocc,ncore:nocc].ravel()).reshape(h2e_t.shape) h2e_t[sym_forbid] = 0 h2e =h2e_t[mc.ncore:mc.ncore+mc.ncas,:,:,:] fh5['h2e'] = h2e h2e_Sr =h2e_t[mc.ncore+mc.ncas:,:,:,:] fh5['h2e_Sr'] = h2e_Sr h2e_Si =numpy.transpose(h2e_t[:mc.ncore,:,:,:], (1,0,2,3)) fh5['h2e_Si'] = h2e_Si else: eri = mc._scf._eri h2e_t = ao2mo.general(eri, [mc.mo_coeff,mo_cas,mo_cas,mo_cas], compact=False) h2e_t = h2e_t.reshape(-1,mc.ncas,mc.ncas,mc.ncas) if pair_irrep is not None: sym_forbid = (pair_irrep[:,ncore:nocc].reshape(-1,1) != pair_irrep[ncore:nocc,ncore:nocc].ravel()).reshape(h2e_t.shape) h2e_t[sym_forbid] = 0 h2e =h2e_t[mc.ncore:mc.ncore+mc.ncas,:,:,:] fh5['h2e'] = h2e h2e_Sr =h2e_t[mc.ncore+mc.ncas:,:,:,:] fh5['h2e_Sr'] = h2e_Sr h2e_Si =numpy.transpose(h2e_t[:mc.ncore,:,:,:], (1,0,2,3)) fh5['h2e_Si'] = h2e_Si fh5.close() logger.timer(mc,'Write MPS NEVPT integral', *t0)
def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1, kpts=None, kpts_band=None): '''Coulomb + XC functional .. note:: This is a replica of pyscf.dft.rks.get_veff with kpts added. This function will change the ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Returns: Veff : (nkpts, nao, nao) or (*, nkpts, nao, nao) ndarray Veff = J + Vxc. ''' if cell is None: cell = ks.cell if dm is None: dm = ks.make_rdm1() if kpts is None: kpts = ks.kpts t0 = (time.clock(), time.time()) # ndim = 3 : dm.shape = (nkpts, nao, nao) ground_state = (isinstance(dm, np.ndarray) and dm.ndim == 3 and kpts_band is None) if ks.grids.coords is None: ks.grids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: ks.grids = rks.prune_small_rho_grids_(ks, cell, dm, ks.grids, kpts) t0 = logger.timer(ks, 'setting up grids', *t0) if hermi == 2: # because rho = 0 n, exc, vxc = 0, 0, 0 else: n, exc, vxc = ks._numint.nr_rks(cell, ks.grids, ks.xc, dm, 0, kpts, kpts_band) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) weight = 1. / len(kpts) hyb = ks._numint.hybrid_coeff(ks.xc, spin=cell.spin) if abs(hyb) < 1e-10: vj = ks.get_j(cell, dm, hermi, kpts, kpts_band) vxc += vj else: if getattr(ks.with_df, '_j_only', False): # for GDF and MDF ks.with_df._j_only = False vj, vk = ks.get_jk(cell, dm, hermi, kpts, kpts_band) vxc += vj - vk * (hyb * .5) if ground_state: exc -= np.einsum('Kij,Kji', dm, vk).real * .5 * hyb * .5 * weight if ground_state: ecoul = np.einsum('Kij,Kji', dm, vj).real * .5 * weight else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=None, vk=None) return vxc
def kernel(mf, conv_tol=1e-10, conv_tol_grad=None, dump_chk=False, dm0e=None, dm0n=[], callback=None, conv_check=True, **kwargs): cput0 = (logger.process_clock(), logger.perf_counter()) if conv_tol_grad is None: conv_tol_grad = numpy.sqrt(conv_tol) logger.info(mf, 'Set gradient conv threshold to %g', conv_tol_grad) mol = mf.mol if dm0e is None: mf.dm_elec = mf.get_init_guess_elec(mol, mf.init_guess) else: mf.dm_elec = dm0e if len(dm0n) < mol.nuc_num: mf.dm_nuc = mf.get_init_guess_nuc(mol, mf.init_guess) # if mf.init_guess is not 'chkfile', then it only affects the electronic part else: mf.dm_nuc = dm0n h1e = mf.mf_elec.get_hcore(mol.elec) vhf_e = mf.mf_elec.get_veff(mol.elec, mf.dm_elec) h1n = [] veff_n = [] for i in range(mol.nuc_num): h1n.append(mf.mf_nuc[i].get_hcore(mol.nuc[i])) veff_n.append(mf.mf_nuc[i].get_veff(mol.nuc[i], mf.dm_nuc[i])) e_tot = mf.energy_tot(mf.dm_elec, mf.dm_nuc, h1e, vhf_e, h1n, veff_n) logger.info(mf, 'init E= %.15g', e_tot) scf_conv = False mo_energy_e = mo_coeff_e = mo_occ_e = None mo_energy_n = [None] * mol.nuc_num mo_coeff_n = [None] * mol.nuc_num mo_occ_n = [None] * mol.nuc_num fock_n = [None] * mol.nuc_num s1e = mf.mf_elec.get_ovlp(mol.elec) cond = lib.cond(s1e) logger.debug(mf, 'cond(S) = %s', cond) if numpy.max(cond) * 1e-17 > conv_tol: logger.warn( mf, 'Singularity detected in overlap matrix (condition number = %4.3g). ' 'SCF may be inaccurate and hard to converge.', numpy.max(cond)) s1n = [] for i in range(mol.nuc_num): s1n.append(mf.mf_nuc[i].get_ovlp(mol.nuc[i])) # Skip SCF iterations. Compute only the total energy of the initial density if mf.max_cycle <= 0: fock_e = mf.mf_elec.get_fock(h1e, s1e, vhf_e, mf.dm_elec) # = h1e + vhf, no DIIS mo_energy_e, mo_coeff_e = mf.mf_elec.eig(fock_e, s1e) mo_occ_e = mf.mf_elec.get_occ(mo_energy_e, mo_coeff_e) mf.mf_elec.mo_energy = mo_energy_e mf.mf_elec.mo_coeff = mo_coeff_e mf.mf_elec.mo_occ = mo_occ_e for i in range(mol.nuc_num): fock_n[i] = mf.mf_nuc[i].get_fock(h1n[i], s1n[i], veff_n[i], mf.dm_nuc[i]) mo_energy_n[i], mo_coeff_n[i] = mf.mf_nuc[i].eig(fock_n[i], s1n[i]) mo_occ_n[i] = mf.mf_nuc[i].get_occ(mo_energy_n[i], mo_coeff_e[i]) mf.mf_nuc[i].mo_energy = mo_energy_n[i] mf.mf_nuc[i].mo_coeff = mo_coeff_n[i] mf.mf_nuc[i].mo_occ = mo_occ_n[i] if mf.dm_elec.ndim > 2: mf.dm_elec = mf.dm_elec[0] + mf.dm_elec[1] return scf_conv, e_tot, mo_energy_e, mo_coeff_e, mo_occ_e, \ mo_energy_n, mo_coeff_n, mo_occ_n if isinstance(mf.mf_elec.diis, lib.diis.DIIS): mf_diis = mf.mf_elec.diis elif mf.mf_elec.diis: assert issubclass(mf.mf_elec.DIIS, lib.diis.DIIS) mf_diis = mf.mf_elec.DIIS(mf.mf_elec, mf.mf_elec.diis_file) mf_diis.space = mf.mf_elec.diis_space mf_diis.rollback = mf.mf_elec.diis_space_rollback else: mf_diis = None # Nuclei need DIIS when there is epc mf_nuc_diis = [None] * mol.nuc_num if hasattr(mf, 'epc') and mf.epc is not None: for i in range(mol.nuc_num): mf_nuc = mf.mf_nuc[i] if isinstance(mf_nuc.diis, lib.diis.DIIS): mf_nuc_diis[i] = mf_nuc.diis elif mf_nuc.diis: assert issubclass(mf_nuc.DIIS, lib.diis.DIIS) mf_nuc_diis[i] = mf_nuc.DIIS(mf_nuc, mf_nuc.diis_file) mf_nuc_diis[i].space = mf_nuc.diis_space mf_nuc_diis[i].rollback = mf_nuc.diis_space_rollback else: mf_nuc_diis[i] = None if dump_chk and mf.chkfile: # Explicit overwrite the mol object in chkfile # Note in pbc.scf, mf.mol == mf.cell, cell is saved under key "mol" chkfile.save_mol(mol, mf.chkfile) # A preprocessing hook before the SCF iteration mf.pre_kernel(locals()) if isinstance(mf, neo.CDFT): int1e_r = [] for i in range(mol.nuc_num): int1e_r.append(mf.mf_nuc[i].mol.intor_symmetric('int1e_r', comp=3)) cput1 = logger.timer(mf, 'initialize scf', *cput0) for cycle in range(mf.max_cycle): dm_elec_last = numpy.copy( mf.dm_elec) # why didn't pyscf.scf.hf use copy? dm_nuc_last = numpy.copy(mf.dm_nuc) last_e = e_tot # set up the electronic Hamiltonian and diagonalize it fock_e = mf.mf_elec.get_fock(h1e, s1e, vhf_e, mf.dm_elec, cycle, mf_diis) mo_energy_e, mo_coeff_e = mf.mf_elec.eig(fock_e, s1e) mo_occ_e = mf.mf_elec.get_occ(mo_energy_e, mo_coeff_e) mf.dm_elec = mf.mf_elec.make_rdm1(mo_coeff_e, mo_occ_e) # attach mo_coeff and mo_occ to dm to improve DFT get_veff efficiency mf.dm_elec = lib.tag_array(mf.dm_elec, mo_coeff=mo_coeff_e, mo_occ=mo_occ_e) # set up the nuclear Hamiltonian and diagonalize it for i in range(mol.nuc_num): # update nuclear core Hamiltonian after the electron density is updated h1n[i] = mf.mf_nuc[i].get_hcore(mf.mf_nuc[i].mol) # optimize f in cNEO skip = False if isinstance(mf, neo.CDFT): ia = mf.mf_nuc[i].mol.atom_index fx = numpy.einsum('xij,x->ij', int1e_r[i], mf.f[ia]) opt = scipy.optimize.root(mf.first_order_de, mf.f[ia], args=(mf.mf_nuc[i], h1n[i] - fx, veff_n[i], s1n[i], int1e_r[i]), method='hybr') logger.debug( mf, 'f of %s(%i) atom: %s' % (mf.mf_nuc[i].mol.atom_symbol(ia), ia, mf.f[ia])) logger.debug(mf, '1st de of L: %s', opt.fun) if mf_nuc_diis[i] is None: # skip the extra diagonalization if epc is not present and DIIS is disabled skip = True if not skip: fock_n[i] = mf.mf_nuc[i].get_fock(h1n[i], s1n[i], veff_n[i], mf.dm_nuc[i], cycle, mf_nuc_diis[i]) mo_energy_n[i], mo_coeff_n[i] = mf.mf_nuc[i].eig( fock_n[i], s1n[i]) mf.mf_nuc[i].mo_energy, mf.mf_nuc[i].mo_coeff = mo_energy_n[ i], mo_coeff_n[i] mo_occ_n[i] = mf.mf_nuc[i].get_occ(mo_energy_n[i], mo_coeff_n[i]) mf.mf_nuc[i].mo_occ = mo_occ_n[i] mf.dm_nuc[i] = mf.mf_nuc[i].make_rdm1(mo_coeff_n[i], mo_occ_n[i]) # update nuclear veff and possible ep correlation part after the diagonalization veff_n[i] = mf.mf_nuc[i].get_veff(mf.mf_nuc[i].mol, mf.dm_nuc[i]) norm_ddm_n = numpy.linalg.norm( numpy.concatenate(mf.dm_nuc, axis=None).ravel() - numpy.concatenate(dm_nuc_last, axis=None).ravel()) # update electronic core Hamiltonian after the nuclear density is updated h1e = mf.mf_elec.get_hcore(mol.elec) # also update the veff, along with the possible ep correlation part vhf_e = mf.mf_elec.get_veff(mol.elec, mf.dm_elec, dm_elec_last, vhf_e) # Here Fock matrix is h1e + vhf, without DIIS. Calling get_fock # instead of the statement "fock = h1e + vhf" because Fock matrix may # be modified in some methods. fock_e = mf.mf_elec.get_fock(h1e, s1e, vhf_e, mf.dm_elec) # = h1e + vhf, no DIIS norm_gorb_e = numpy.linalg.norm( mf.mf_elec.get_grad(mo_coeff_e, mo_occ_e, fock_e)) if not TIGHT_GRAD_CONV_TOL: norm_gorb_e = norm_gorb_e / numpy.sqrt(norm_gorb_e.size) norm_ddm_e = numpy.linalg.norm(mf.dm_elec - dm_elec_last) e_tot = mf.energy_tot(mf.dm_elec, mf.dm_nuc, h1e, vhf_e, h1n, veff_n) logger.info( mf, 'cycle= %d E= %.15g delta_E= %4.3g |g_e|= %4.3g |ddm_e|= %4.3g |ddm_n|= %4.3g', cycle + 1, e_tot, e_tot - last_e, norm_gorb_e, norm_ddm_e, norm_ddm_n) if abs(e_tot - last_e) < conv_tol and norm_gorb_e < conv_tol_grad: scf_conv = True if dump_chk: mf.dump_chk(locals()) if callable(callback): callback(locals()) cput1 = logger.timer(mf, 'cycle= %d' % (cycle + 1), *cput1) if scf_conv: break if scf_conv and conv_check: # An extra diagonalization, to remove level shift #fock = mf.get_fock(h1e, s1e, vhf, dm) # = h1e + vhf mo_energy_e, mo_coeff_e = mf.mf_elec.eig(fock_e, s1e) mo_occ_e = mf.mf_elec.get_occ(mo_energy_e, mo_coeff_e) mf.dm_elec, dm_elec_last = mf.mf_elec.make_rdm1(mo_coeff_e, mo_occ_e), mf.dm_elec mf.dm_elec = lib.tag_array(mf.dm_elec, mo_coeff=mo_coeff_e, mo_occ=mo_occ_e) for i in range(mol.nuc_num): h1n[i] = mf.mf_nuc[i].get_hcore(mf.mf_nuc[i].mol) veff_n[i] = mf.mf_nuc[i].get_veff(mf.mf_nuc[i].mol, mf.dm_nuc[i]) fock_n[i] = mf.mf_nuc[i].get_fock(h1n[i], s1n[i], veff_n[i], mf.dm_nuc[i]) mo_energy_n[i], mo_coeff_n[i] = mf.mf_nuc[i].eig(fock_n[i], s1n[i]) mf.mf_nuc[i].mo_energy, mf.mf_nuc[i].mo_coeff = mo_energy_n[ i], mo_coeff_n[i] mo_occ_n[i] = mf.mf_nuc[i].get_occ(mo_energy_n[i], mo_coeff_n[i]) mf.mf_nuc[i].mo_occ = mo_occ_n[i] mf.dm_nuc[i], dm_nuc_last[i] = mf.mf_nuc[i].make_rdm1( mo_coeff_n[i], mo_occ_n[i]), mf.dm_nuc[i] norm_ddm_n = numpy.linalg.norm( numpy.concatenate(mf.dm_nuc, axis=None).ravel() - numpy.concatenate(dm_nuc_last, axis=None).ravel()) h1e = mf.mf_elec.get_hcore(mol.elec) vhf_e = mf.mf_elec.get_veff(mol.elec, mf.dm_elec, dm_elec_last, vhf_e) fock_e = mf.mf_elec.get_fock(h1e, s1e, vhf_e, mf.dm_elec) norm_gorb_e = numpy.linalg.norm( mf.mf_elec.get_grad(mo_coeff_e, mo_occ_e, fock_e)) if not TIGHT_GRAD_CONV_TOL: norm_gorb_e = norm_gorb_e / numpy.sqrt(norm_gorb_e.size) norm_ddm_e = numpy.linalg.norm(mf.dm_elec - dm_elec_last) e_tot, last_e = mf.energy_tot(mf.dm_elec, mf.dm_nuc, h1e, vhf_e, h1n, veff_n), e_tot conv_tol = conv_tol * 10 conv_tol_grad = conv_tol_grad * 3 if abs(e_tot - last_e) < conv_tol or norm_gorb_e < conv_tol_grad: scf_conv = True logger.info( mf, 'Extra cycle E= %.15g delta_E= %4.3g |g_e|= %4.3g |ddm_e|= %4.3g |ddm_n|= %4.3g', e_tot, e_tot - last_e, norm_gorb_e, norm_ddm_e, norm_ddm_n) if dump_chk: mf.dump_chk(locals()) logger.timer(mf, 'scf_cycle', *cput0) # A post-processing hook before return mf.post_kernel(locals()) if mf.dm_elec.ndim > 2: mf.dm_elec = mf.dm_elec[0] + mf.dm_elec[1] return scf_conv, e_tot, mo_energy_e, mo_coeff_e, mo_occ_e, \ mo_energy_n, mo_coeff_n, mo_occ_n
def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1, kpts=None, kpts_band=None): '''Coulomb + XC functional .. note:: This is a replica of pyscf.dft.rks.get_veff with kpts added. This function will change the ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. The ._exc and ._ecoul attributes will be updated after return. Attributes ._dm_last, ._vj_last and ._vk_last might be changed if direct SCF method is applied. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Returns: Veff : (nkpts, nao, nao) or (*, nkpts, nao, nao) ndarray Veff = J + Vxc. ''' needs_ao_update = False if cell is None: cell = ks.cell elif not cell == ks.cell: ks.cell = cell needs_ao_update = True if kpts is None: kpts = ks.kpts elif not np.array_equal(kpts, ks.kpts): ks.kpts = np.array(kpts) needs_ao_update = True if dm is None: dm = ks.make_rdm1() t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.build(with_non0tab=True) small_rho_cutoff = ks.small_rho_cutoff t0 = logger.timer(ks, 'setting up grids', *t0) else: small_rho_cutoff = 0 ao_derivatives_required = { "LDA": 0, "GGA": 1, "MGGA": 2, }[ks._numint._xc_type(ks.xc)] # If needs an update if ks._ao is None or needs_ao_update: ks._update_ao(ao_derivatives_required) # If number of derivatives is not sufficiently large: update as well shape = ks._ao[0].shape # Retrieve primary dimension if len(shape) == 2: prim = 1 else: prim = shape[0] n = (ao_derivatives_required + 1) * (ao_derivatives_required + 2) * ( ao_derivatives_required + 3) // 6 if n > prim: ks._update_ao(ao_derivatives_required) if hermi == 2: # because rho = 0 n, ks._exc, vx = 0, 0, 0 else: n, ks._exc, vx = ks._numint.nr_rks(cell, ks.grids, ks.xc, dm, 1, kpts, kpts_band, precomputed_ao=ks._ao) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) # ndim = 3 : dm.shape = (nkpts, nao, nao) ground_state = (isinstance(dm, np.ndarray) and dm.ndim == 3 and kpts_band is None) nkpts = len(kpts) hyb = ks._numint.hybrid_coeff(ks.xc, spin=cell.spin) if abs(hyb) < 1e-10: vhf = vj = ks.get_j(cell, dm, hermi, kpts, kpts_band) else: vj, vk = ks.get_jk(cell, dm, hermi, kpts, kpts_band) vhf = vj - vk * (hyb * .5) if ground_state: ks._exc -= (1. / nkpts) * np.einsum('Kij,Kji', dm, vk).real * .5 * hyb * .5 if ground_state: ks._ecoul = (1. / nkpts) * np.einsum('Kij,Kji', dm, vj).real * .5 if (small_rho_cutoff > 1e-20 and ground_state and abs(n - cell.nelectron) < 0.01 * n): # Filter grids the first time setup grids _ao = ks._ao if len(ks._ao[0].shape) == 2 else list(i[0] for i in ks._ao) idx = ks._numint.large_rho_indices(cell, dm, ks.grids, small_rho_cutoff, kpts, precomputed_ao=_ao) logger.debug(ks, 'Drop grids %d', ks.grids.weights.size - np.count_nonzero(idx)) ks.grids.coords = np.asarray(ks.grids.coords[idx], order='C') ks.grids.weights = np.asarray(ks.grids.weights[idx], order='C') ks.grids.non0tab = ks.grids.make_mask(cell, ks.grids.coords) return vhf + vx
def kernel(mc, ot, root=-1): ''' Calculate MC-PDFT total energy Args: mc : an instance of CASSCF or CASCI class Note: this function does not currently run the CASSCF or CASCI calculation itself prior to calculating the MC-PDFT energy. Call mc.kernel () before passing to this function! ot : an instance of on-top density functional class - see otfnal.py Kwargs: root : int If mc describes a state-averaged calculation, select the root (0-indexed) Negative number requests state-averaged MC-PDFT results (i.e., using state-averaged density matrices) Returns: Total MC-PDFT energy including nuclear repulsion energy. ''' t0 = (time.clock(), time.time()) amo = mc.mo_coeff[:, mc.ncore:mc.ncore + mc.ncas] # make_rdm12s returns (a, b), (aa, ab, bb) mc_1root = mc if isinstance(mc.ci, list) and root >= 0: mc_1root = mcscf.CASCI(mc._scf, mc.ncas, mc.nelecas) mc_1root.fcisolver = fci.solver(mc._scf.mol, singlet=False, symm=False) mc_1root.mo_coeff = mc.mo_coeff mc_1root.ci = mc.ci[root] mc_1root.e_tot = mc.e_tot dm1s = np.asarray(mc_1root.make_rdm1s()) adm1s = np.stack(mc_1root.fcisolver.make_rdm1s(mc_1root.ci, mc.ncas, mc.nelecas), axis=0) adm2 = get_2CDM_from_2RDM( mc_1root.fcisolver.make_rdm12(mc_1root.ci, mc.ncas, mc.nelecas)[1], adm1s) if ot.verbose >= logger.DEBUG: adm2s = get_2CDMs_from_2RDMs( mc_1root.fcisolver.make_rdm12s(mc_1root.ci, mc.ncas, mc.nelecas)[1], adm1s) adm2s_ss = adm2s[0] + adm2s[2] adm2s_os = adm2s[1] spin = abs(mc.nelecas[0] - mc.nelecas[1]) t0 = logger.timer(ot, 'rdms', *t0) omega, alpha, hyb = ot._numint.rsh_and_hybrid_coeff(ot.otxc, spin=spin) Vnn = mc._scf.energy_nuc() h = mc._scf.get_hcore() dm1 = dm1s[0] + dm1s[1] if ot.verbose >= logger.DEBUG or abs(hyb) > 1e-10: vj, vk = mc._scf.get_jk(dm=dm1s) vj = vj[0] + vj[1] else: vj = mc._scf.get_j(dm=dm1) Te_Vne = np.tensordot(h, dm1) # (vj_a + vj_b) * (dm_a + dm_b) E_j = np.tensordot(vj, dm1) / 2 # (vk_a * dm_a) + (vk_b * dm_b) Mind the difference! if ot.verbose >= logger.DEBUG or abs(hyb) > 1e-10: E_x = -(np.tensordot(vk[0], dm1s[0]) + np.tensordot(vk[1], dm1s[1])) / 2 else: E_x = 0 logger.debug(ot, 'CAS energy decomposition:') logger.debug(ot, 'Vnn = %s', Vnn) logger.debug(ot, 'Te + Vne = %s', Te_Vne) logger.debug(ot, 'E_j = %s', E_j) logger.debug(ot, 'E_x = %s', E_x) if ot.verbose >= logger.DEBUG: # g_pqrs * l_pqrs / 2 #if ot.verbose >= logger.DEBUG: aeri = ao2mo.restore(1, mc.get_h2eff(mc.mo_coeff), mc.ncas) E_c = np.tensordot(aeri, adm2, axes=4) / 2 E_c_ss = np.tensordot(aeri, adm2s_ss, axes=4) / 2 E_c_os = np.tensordot(aeri, adm2s_os, axes=4) # ab + ba -> factor of 2 logger.info(ot, 'E_c = %s', E_c) logger.info(ot, 'E_c (SS) = %s', E_c_ss) logger.info(ot, 'E_c (OS) = %s', E_c_os) e_err = E_c_ss + E_c_os - E_c assert (abs(e_err) < 1e-8), e_err if isinstance(mc_1root.e_tot, float): e_err = mc_1root.e_tot - (Vnn + Te_Vne + E_j + E_x + E_c) assert (abs(e_err) < 1e-8), e_err if abs(hyb) > 1e-10: logger.debug(ot, 'Adding %s * %s CAS exchange to E_ot', hyb, E_x) t0 = logger.timer(ot, 'Vnn, Te, Vne, E_j, E_x', *t0) E_ot = get_E_ot(ot, dm1s, adm2, amo) t0 = logger.timer(ot, 'E_ot', *t0) e_tot = Vnn + Te_Vne + E_j + (hyb * E_x) + E_ot logger.info(ot, 'MC-PDFT E = %s, Eot(%s) = %s', e_tot, ot.otxc, E_ot) return e_tot, E_ot
def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1): '''Coulomb + XC functional .. 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. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Kwargs: dm_last : ndarray or a list of ndarrays or 0 The density matrix baseline. If not 0, this function computes the increment of HF potential w.r.t. the reference HF potential matrix. vhf_last : ndarray or a list of ndarrays or 0 The reference Vxc potential matrix. hermi : int Whether J, K matrix is hermitian | 0 : no hermitian or symmetric | 1 : hermitian | 2 : anti-hermitian Returns: matrix Veff = J + Vxc. Veff can be a list matrices, if the input dm is a list of density matrices. ''' if mol is None: mol = ks.mol if dm is None: dm = ks.make_rdm1() t0 = (logger.process_clock(), logger.perf_counter()) ground_state = (isinstance(dm, numpy.ndarray) and dm.ndim == 2) if ks.grids.coords is None: ks.grids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: # Filter grids the first time setup grids ks.grids = prune_small_rho_grids_(ks, mol, dm, ks.grids) t0 = logger.timer(ks, 'setting up grids', *t0) if ks.nlc != '': if ks.nlcgrids.coords is None: ks.nlcgrids.build(with_non0tab=True) if ks.small_rho_cutoff > 1e-20 and ground_state: # Filter grids the first time setup grids ks.nlcgrids = prune_small_rho_grids_(ks, mol, dm, ks.nlcgrids) t0 = logger.timer(ks, 'setting up nlc grids', *t0) ni = ks._numint if hermi == 2: # because rho = 0 n, exc, vxc = 0, 0, 0 else: max_memory = ks.max_memory - lib.current_memory()[0] n, exc, vxc = ni.nr_rks(mol, ks.grids, ks.xc, dm, max_memory=max_memory) if ks.nlc: assert 'VV10' in ks.nlc.upper() _, enlc, vnlc = ni.nr_rks(mol, ks.nlcgrids, ks.xc + '__' + ks.nlc, dm, max_memory=max_memory) exc += enlc vxc += vnlc logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) #enabling range-separated hybrids omega, alpha, hyb = ni.rsh_and_hybrid_coeff(ks.xc, spin=mol.spin) if abs(hyb) < 1e-10 and abs(alpha) < 1e-10: vk = None if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vj', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj = ks.get_j(mol, ddm, hermi) vj += vhf_last.vj else: vj = ks.get_j(mol, dm, hermi) vxc += vj else: if (ks._eri is None and ks.direct_scf and getattr(vhf_last, 'vk', None) is not None): ddm = numpy.asarray(dm) - numpy.asarray(dm_last) vj, vk = ks.get_jk(mol, ddm, hermi) vk *= hyb if abs(omega) > 1e-10: # For range separated Coulomb operator vklr = ks.get_k(mol, ddm, hermi, omega=omega) vklr *= (alpha - hyb) vk += vklr vj += vhf_last.vj vk += vhf_last.vk else: vj, vk = ks.get_jk(mol, dm, hermi) vk *= hyb if abs(omega) > 1e-10: vklr = ks.get_k(mol, dm, hermi, omega=omega) vklr *= (alpha - hyb) vk += vklr vxc += vj - vk * .5 if ground_state: exc -= numpy.einsum('ij,ji', dm, vk).real * .5 * .5 if ground_state: ecoul = numpy.einsum('ij,ji', dm, vj).real * .5 else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=vj, vk=vk) return vxc
def DMRG_COMPRESS_NEVPT(mc, maxM=500, root=0, nevptsolver=None, tol=1e-7): if (isinstance(mc, str)): mol = chkfile.load_mol(mc) fh5 = h5py.File(mc, 'r') ncas = fh5['mc/ncas'].value ncore = fh5['mc/ncore'].value nvirt = fh5['mc/nvirt'].value nelecas = fh5['mc/nelecas'].value nroots = fh5['mc/nroots'].value wfnsym = fh5['mc/wfnsym'].value fh5.close() mc_chk = mc else : mol = mc.mol ncas = mc.ncas ncore = mc.ncore nvirt = mc.mo_coeff.shape[1] - mc.ncas-mc.ncore nelecas = mc.nelecas nroots = mc.fcisolver.nroots wfnsym = mc.fcisolver.wfnsym mc_chk = 'nevpt_perturb_integral' write_chk(mc, root, mc_chk) if nevptsolver is None: nevptsolver = default_nevpt_schedule(mol,maxM, tol) nevptsolver.wfnsym = wfnsym nevptsolver.block_extra_keyword = mc.fcisolver.block_extra_keyword nevptsolver.nroots = nroots from pyscf.dmrgscf import settings nevptsolver.executable = settings.BLOCKEXE_COMPRESS_NEVPT scratch = nevptsolver.scratchDirectory nevptsolver.scratchDirectory = '' dmrgci.writeDMRGConfFile(nevptsolver, nelecas, False, with_2pdm=False, extraline=['fullrestart','nevpt_state_num %d'%root]) nevptsolver.scratchDirectory = scratch if nevptsolver.verbose >= logger.DEBUG1: inFile = os.path.join(nevptsolver.runtimeDir, nevptsolver.configFile) logger.debug1(nevptsolver, 'Block Input conf') logger.debug1(nevptsolver, open(inFile, 'r').read()) t0 = (time.clock(), time.time()) cmd = ' '.join((nevptsolver.mpiprefix, '%s/nevpt_mpi.py' % os.path.dirname(os.path.realpath(__file__)), mc_chk, nevptsolver.executable, os.path.join(nevptsolver.runtimeDir, nevptsolver.configFile), nevptsolver.outputFile, nevptsolver.scratchDirectory)) logger.debug(nevptsolver, 'DMRG_COMPRESS_NEVPT cmd %s', cmd) try: output = subprocess.check_call(cmd, shell=True) except subprocess.CalledProcessError as err: logger.error(nevptsolver, cmd) raise err if nevptsolver.verbose >= logger.DEBUG1: logger.debug1(nevptsolver, open(os.path.join(nevptsolver.scratchDirectory, '0/dmrg.out')).read()) fh5 = h5py.File('Perturbation_%d'%root,'r') Vi_e = fh5['Vi/energy'].value Vr_e = fh5['Vr/energy'].value fh5.close() logger.note(nevptsolver,'Nevpt Energy:') logger.note(nevptsolver,'Sr Subspace: E = %.14f'%( Vr_e)) logger.note(nevptsolver,'Si Subspace: E = %.14f'%( Vi_e)) logger.timer(nevptsolver,'MPS NEVPT calculation time', *t0)
def build(self, omega=None, direct_scf_tol=None): cpu0 = (time.clock(), time.time()) cell = self.cell kpts = self.kpts k_scaled = cell.get_scaled_kpts(kpts).sum(axis=0) k_mod_to_half = k_scaled * 2 - (k_scaled * 2).round(0) if abs(k_mod_to_half).sum() > 1e-5: raise NotImplementedError('k-points must be symmetryic') if omega is not None: self.omega = omega if self.omega is None: # Search a proper range-separation parameter omega that can balance the # computational cost between the real space integrals and moment space # integrals self.omega, self.mesh, self.ke_cutoff = _guess_omega( cell, kpts, self.mesh) else: self.ke_cutoff = aft.estimate_ke_cutoff_for_omega(cell, self.omega) self.mesh = pbctools.cutoff_to_mesh(cell.lattice_vectors(), self.ke_cutoff) logger.info(self, 'omega = %.15g ke_cutoff = %s mesh = %s', self.omega, self.ke_cutoff, self.mesh) if direct_scf_tol is None: direct_scf_tol = cell.precision**1.5 logger.debug(self, 'Set direct_scf_tol %g', direct_scf_tol) self.cell_rs = cell_rs = _re_contract_cell(cell, self.ke_cutoff) self.bvk_kmesh = kmesh = k2gamma.kpts_to_kmesh(cell_rs, kpts) bvkcell, phase = k2gamma.get_phase(cell_rs, kpts, kmesh) self.bvkmesh_Ls = Ks = k2gamma.translation_vectors_for_kmesh( cell_rs, kmesh) self.bvkcell = bvkcell self.phase = phase # Given ke_cutoff, eta corresponds to the most steep Gaussian basis # of which the Coulomb integrals can be accurately computed in moment # space. eta = aft.estimate_eta_for_ke_cutoff(cell, self.ke_cutoff, precision=cell.precision) # * Assuming the most steep function in smooth basis has exponent eta, # with attenuation parameter omega, rcut_sr is the distance of which # the value of attenuated Coulomb integrals of four shells |eta> is # smaller than the required precision. # * The attenuated coulomb integrals between four s-type Gaussians # (2*a/pi)^{3/4}exp(-a*r^2) is # (erfc(omega*a^0.5/(omega^2+a)^0.5*R) - erfc(a^0.5*R)) / R # if two Gaussians on one center and the other two on another center # and the distance between the two centers are R. # * The attenuated coulomb integrals between two spherical charge # distributions is # ~(pi/eta)^3/2 (erfc(tau*(eta/2)^0.5*R) - erfc((eta/2)^0.5*R)) / R # tau = omega/sqrt(omega^2 + eta/2) # if the spherical charge distribution is the product of above s-type # Gaussian with exponent eta and a very smooth function. # When R is large, the attenuated Coulomb integral is # ~= (pi/eta)^3/2 erfc(tau*(eta/2)^0.5*R) / R # ~= pi/(tau*eta^2*R^2) exp(-tau^2*eta*R^2/2) tau = self.omega / (self.omega**2 + eta / 2)**.5 rcut_sr = 10 # initial guess rcut_sr = (-np.log(direct_scf_tol * tau * (eta * rcut_sr)**2 / np.pi) / (tau**2 * eta / 2))**.5 logger.debug(self, 'eta = %g rcut_sr = %g', eta, rcut_sr) # Ls is the translation vectors to mimic periodicity of a cell Ls = bvkcell.get_lattice_Ls(rcut=cell.rcut + rcut_sr) self.supmol_Ls = Ls = Ls[np.linalg.norm(Ls, axis=1).argsort()] supmol = _make_extended_mole(cell_rs, Ls, Ks, self.omega, direct_scf_tol) self.supmol = supmol nkpts = len(self.bvkmesh_Ls) nbas = cell_rs.nbas n_steep, n_local, n_diffused = cell_rs._nbas_each_set n_compact = n_steep + n_local bas_mask = supmol._bas_mask self.bvk_bas_mask = bvk_bas_mask = bas_mask.any(axis=2) # Some basis in bvk-cell are not presented in the supmol. They can be # skipped when computing SR integrals self.bvkcell._bas = bvkcell._bas[bvk_bas_mask.ravel()] # Record the mapping between the dense bvkcell basis and the # original sparse bvkcell basis bvk_cell_idx = np.repeat(np.arange(nkpts)[:, None], nbas, axis=1) self.bvk_cell_id = bvk_cell_idx[bvk_bas_mask].astype(np.int32) cell0_shl_idx = np.repeat(np.arange(nbas)[None, :], nkpts, axis=0) self.cell0_shl_id = cell0_shl_idx[bvk_bas_mask].astype(np.int32) logger.timer_debug1(self, 'initializing supmol', *cpu0) logger.info(self, 'sup-mol nbas = %d cGTO = %d pGTO = %d', supmol.nbas, supmol.nao, supmol.npgto_nr()) supmol.omega = -self.omega # Set short range coulomb with supmol.with_integral_screen(direct_scf_tol**2): vhfopt = _vhf.VHFOpt(supmol, 'int2e_sph', qcondname=libpbc.PBCVHFsetnr_direct_scf) vhfopt.direct_scf_tol = direct_scf_tol self.vhfopt = vhfopt logger.timer(self, 'initializing vhfopt', *cpu0) q_cond = vhfopt.get_q_cond((supmol.nbas, supmol.nbas)) idx = supmol._images_loc bvk_q_cond = lib.condense('NP_absmax', q_cond, idx, idx) ovlp_mask = bvk_q_cond > direct_scf_tol # Remove diffused-diffused block if n_diffused > 0: diffused_mask = np.zeros_like(bvk_bas_mask) diffused_mask[:, n_compact:] = True diffused_mask = diffused_mask[bvk_bas_mask] ovlp_mask[diffused_mask[:, None] & diffused_mask] = False self.ovlp_mask = ovlp_mask.astype(np.int8) # mute rcut_threshold, divide basis into two sets only cell_lr_aft = _re_contract_cell(cell, self.ke_cutoff, -1, verbose=0) self.lr_aft = lr_aft = _LongRangeAFT(cell_lr_aft, kpts, self.omega, self.bvk_kmesh) lr_aft.ke_cutoff = self.ke_cutoff lr_aft.mesh = self.mesh lr_aft.eta = eta return self
def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1, kpt=None, kpts_band=None): '''Coulomb + XC functional for UKS. See pyscf/pbc/dft/uks.py :func:`get_veff` fore more details. ''' if cell is None: cell = ks.cell if dm is None: dm = ks.make_rdm1() if kpt is None: kpt = ks.kpt t0 = (time.clock(), time.time()) omega, alpha, hyb = ks._numint.rsh_and_hybrid_coeff(ks.xc, spin=cell.spin) if abs(omega) > 1e-10: raise NotImplementedError hybrid = abs(hyb) > 1e-10 if not hybrid and isinstance(ks.with_df, multigrid.MultiGridFFTDF): n, exc, vxc = multigrid.nr_uks(ks.with_df, ks.xc, dm, hermi, kpt.reshape(1, 3), kpts_band, with_j=True, return_j=False) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) return vxc # ndim = 3 : dm.shape = ([alpha,beta], nao, nao) ground_state = (dm.ndim == 3 and dm.shape[0] == 2 and kpts_band is None) if ks.grids.non0tab is None: ks.grids.build(with_non0tab=True) if (isinstance(ks.grids, gen_grid.BeckeGrids) and ks.small_rho_cutoff > 1e-20 and ground_state): ks.grids = rks.prune_small_rho_grids_(ks, cell, dm, ks.grids, kpt) t0 = logger.timer(ks, 'setting up grids', *t0) if not isinstance(dm, numpy.ndarray): dm = numpy.asarray(dm) if dm.ndim == 2: # RHF DM dm = numpy.asarray((dm * .5, dm * .5)) if hermi == 2: # because rho = 0 n, exc, vxc = (0, 0), 0, 0 else: n, exc, vxc = ks._numint.nr_uks(cell, ks.grids, ks.xc, dm, 0, kpt, kpts_band) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) if not hybrid: vj = ks.get_j(cell, dm[0] + dm[1], hermi, kpt, kpts_band) vxc += vj else: if getattr(ks.with_df, '_j_only', False): # for GDF and MDF ks.with_df._j_only = False vj, vk = ks.get_jk(cell, dm, hermi, kpt, kpts_band) vj = vj[0] + vj[1] vxc += vj - vk * hyb if ground_state: exc -= (numpy.einsum('ij,ji', dm[0], vk[0]) + numpy.einsum('ij,ji', dm[1], vk[1])).real * hyb * .5 if ground_state: ecoul = numpy.einsum('ij,ji', dm[0] + dm[1], vj).real * .5 else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=None, vk=None) return vxc
def build(self): t0 = (time.clock(), time.time()) lib.logger.TIMER_LEVEL = 3 self.mol = lib.chkfile.load_mol(self.chkfile) self.nelectron = self.mol.nelectron self.charge = self.mol.charge self.spin = self.mol.spin self.natm = self.mol.natm self.coords = numpy.asarray([(numpy.asarray(atom[1])).tolist() for atom in self.mol._atom]) self.charges = self.mol.atom_charges() if (self.cas): self.mo_coeff = lib.chkfile.load(self.chkfile, 'mcscf/mo_coeff') else: self.mo_coeff = lib.chkfile.load(self.chkfile, 'scf/mo_coeff') self.mo_occ = lib.chkfile.load(self.chkfile, 'scf/mo_occ') nprims, nmo = self.mo_coeff.shape self.nprims = nprims self.nmo = nmo if self.charges[self.inuc] == 1: self.rad = grid.BRAGG[self.charges[self.inuc]] else: self.rad = grid.BRAGG[self.charges[self.inuc]] * 0.5 if (self.corr): self.rdm1 = lib.chkfile.load(self.chkfile, 'rdm/rdm1') natocc, natorb = numpy.linalg.eigh(self.rdm1) natorb = numpy.dot(self.mo_coeff, natorb) self.mo_coeff = natorb self.mo_occ = natocc nocc = self.mo_occ[abs(self.mo_occ) > self.occdrop] nocc = len(nocc) self.nocc = nocc idx = 'atom' + str(self.inuc) with h5py.File(self.surfile) as f: self.xnuc = f[idx + '/xnuc'].value self.xyzrho = f[idx + '/xyzrho'].value self.npang = f[idx + '/npang'].value self.ntrial = f[idx + '/ntrial'].value self.rmin = f[idx + '/rmin'].value self.rmax = f[idx + '/rmax'].value self.rsurf = f[idx + '/rsurf'].value self.nlimsurf = f[idx + '/nlimsurf'].value self.agrids = f[idx + '/coords'].value self.brad = self.rmin * self.betafac if self.verbose >= logger.WARN: self.check_sanity() if self.verbose > logger.NOTE: self.dump_input() if (self.iqudr == 'legendre'): self.iqudr = 1 if (self.biqudr == 'legendre'): self.biqudr = 1 if (self.mapr == 'becke'): self.mapr = 1 elif (self.mapr == 'exp'): self.mapr = 2 elif (self.mapr == 'none'): self.mapr = 0 if (self.bmapr == 'becke'): self.bmapr = 1 elif (self.bmapr == 'exp'): self.bmapr = 2 elif (self.bmapr == 'none'): self.bmapr = 0 if (self.full): self.nocc = self.nmo nocc = self.nmo else: nocc = self.mo_occ[self.mo_occ > self.occdrop] nocc = len(nocc) self.nocc = nocc self.aom = numpy.zeros((nocc, nocc)) with lib.with_omp_threads(self.nthreads): aomb = int_beta(self) aoma = out_beta(self) idx = 0 for i in range(nocc): for j in range(i + 1): self.aom[i, j] = aoma[idx] + aomb[idx] self.aom[j, i] = self.aom[i, j] idx += 1 if (self.nmo <= 30): dump_tri(self.stdout, self.aom, ncol=NCOL, digits=DIGITS, start=0) logger.info(self, 'Write info to HDF5 file') atom_dic = {'aom': self.aom} lib.chkfile.save(self.surfile, 'ovlp' + str(self.inuc), atom_dic) logger.info(self, '') logger.info(self, 'AOM of atom %d done', self.inuc) logger.timer(self, 'AOM build', *t0) return self
def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1): '''Coulomb + XC functional for UKS. See pyscf/dft/rks.py :func:`get_veff` fore more details. ''' if mol is None: mol = self.mol if dm is None: dm = ks.make_rdm1() t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.build(with_non0tab=True) small_rho_cutoff = ks.small_rho_cutoff t0 = logger.timer(ks, 'setting up grids', *t0) else: # Filter grids only for the first time setting up grids small_rho_cutoff = 0 if not isinstance(dm, numpy.ndarray): dm = numpy.asarray(dm) if dm.ndim == 2: # RHF DM dm = numpy.asarray((dm * .5, dm * .5)) if hermi == 2: # because rho = 0 n, ks._exc, vx = (0, 0), 0, 0 else: n, ks._exc, vx = ks._numint.nr_uks(mol, ks.grids, ks.xc, dm) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) ground_state = (dm.ndim == 3 and dm.shape[0] == 2) hyb = ks._numint.hybrid_coeff(ks.xc, spin=mol.spin) if abs(hyb) < 1e-10: if (ks._eri is not None or not ks.direct_scf or not hasattr(ks, '_dm_last') or not isinstance(vhf_last, numpy.ndarray)): vj = ks.get_j(mol, dm, hermi) else: ddm = dm - numpy.asarray(ks._dm_last) vj = ks.get_j(mol, ddm, hermi) vj += ks._vj_last ks._dm_last = dm ks._vj_last = vj vhf = vj[0] + vj[1] vhf = numpy.asarray((vhf, vhf)) else: if (ks._eri is not None or not ks.direct_scf or not hasattr(ks, '_dm_last') or not isinstance(vhf_last, numpy.ndarray)): vj, vk = ks.get_jk(mol, dm, hermi) else: ddm = dm - numpy.asarray(ks._dm_last) vj, vk = ks.get_jk(mol, ddm, hermi) vj += ks._vj_last vk += ks._vk_last ks._dm_last = dm ks._vj_last, ks._vk_last = vj, vk vhf = uhf._makevhf(vj, vk * hyb) if ground_state: ks._exc -= (numpy.einsum('ij,ji', dm[0], vk[0]) + numpy.einsum('ij,ji', dm[1], vk[1])) * .5 * hyb if ground_state: ks._ecoul = numpy.einsum('ij,ji', dm[0] + dm[1], vj[0] + vj[1]) * .5 nelec = mol.nelec if (small_rho_cutoff > 1e-20 and ground_state and abs(n[0] - nelec[0]) < 0.01 * n[0] and abs(n[1] - nelec[1]) < 0.01 * n[1]): idx = ks._numint.large_rho_indices(mol, dm[0] + dm[1], ks.grids, small_rho_cutoff) logger.debug(ks, 'Drop grids %d', ks.grids.weights.size - numpy.count_nonzero(idx)) ks.grids.coords = numpy.asarray(ks.grids.coords[idx], order='C') ks.grids.weights = numpy.asarray(ks.grids.weights[idx], order='C') ks.grids.non0tab = ks.grids.make_mask(mol, ks.grids.coords) return vhf + vx
def get_jk(dfobj, dm, hermi=1, with_j=True, with_k=True, direct_scf_tol=1e-13): assert (with_j or with_k) if (not with_k and not dfobj.mol.incore_anyway and # 3-center integral tensor is not initialized dfobj._cderi is None): return get_j(dfobj, dm, hermi, direct_scf_tol), None t0 = t1 = (time.clock(), time.time()) log = logger.Logger(dfobj.stdout, dfobj.verbose) fmmm = _ao2mo.libao2mo.AO2MOmmm_bra_nr_s2 fdrv = _ao2mo.libao2mo.AO2MOnr_e2_drv ftrans = _ao2mo.libao2mo.AO2MOtranse2_nr_s2 null = lib.c_null_ptr() dms = numpy.asarray(dm) dm_shape = dms.shape nao = dm_shape[-1] dms = dms.reshape(-1, nao, nao) nset = dms.shape[0] vj = 0 vk = numpy.zeros_like(dms) if with_j: idx = numpy.arange(nao) dmtril = lib.pack_tril(dms + dms.conj().transpose(0, 2, 1)) dmtril[:, idx * (idx + 1) // 2 + idx] *= .5 if not with_k: for eri1 in dfobj.loop(): rho = numpy.einsum('ix,px->ip', dmtril, eri1) vj += numpy.einsum('ip,px->ix', rho, eri1) elif getattr(dm, 'mo_coeff', None) is not None: #TODO: test whether dm.mo_coeff matching dm mo_coeff = numpy.asarray(dm.mo_coeff, order='F') mo_occ = numpy.asarray(dm.mo_occ) nmo = mo_occ.shape[-1] mo_coeff = mo_coeff.reshape(-1, nao, nmo) mo_occ = mo_occ.reshape(-1, nmo) if mo_occ.shape[0] * 2 == nset: # handle ROHF DM mo_coeff = numpy.vstack((mo_coeff, mo_coeff)) mo_occa = numpy.array(mo_occ > 0, dtype=numpy.double) mo_occb = numpy.array(mo_occ == 2, dtype=numpy.double) assert (mo_occa.sum() + mo_occb.sum() == mo_occ.sum()) mo_occ = numpy.vstack((mo_occa, mo_occb)) orbo = [] for k in range(nset): c = numpy.einsum('pi,i->pi', mo_coeff[k][:, mo_occ[k] > 0], numpy.sqrt(mo_occ[k][mo_occ[k] > 0])) orbo.append(numpy.asarray(c, order='F')) max_memory = dfobj.max_memory - lib.current_memory()[0] blksize = max(4, int(min(dfobj.blockdim, max_memory * .3e6 / 8 / nao**2))) buf = numpy.empty((blksize * nao, nao)) for eri1 in dfobj.loop(blksize): naux, nao_pair = eri1.shape assert (nao_pair == nao * (nao + 1) // 2) if with_j: rho = numpy.einsum('ix,px->ip', dmtril, eri1) vj += numpy.einsum('ip,px->ix', rho, eri1) for k in range(nset): nocc = orbo[k].shape[1] if nocc > 0: buf1 = buf[:naux * nocc] fdrv(ftrans, fmmm, buf1.ctypes.data_as(ctypes.c_void_p), eri1.ctypes.data_as(ctypes.c_void_p), orbo[k].ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), ctypes.c_int(nao), (ctypes.c_int * 4)(0, nocc, 0, nao), null, ctypes.c_int(0)) vk[k] += lib.dot(buf1.T, buf1) t1 = log.timer_debug1('jk', *t1) else: #:vk = numpy.einsum('pij,jk->pki', cderi, dm) #:vk = numpy.einsum('pki,pkj->ij', cderi, vk) rargs = (ctypes.c_int(nao), (ctypes.c_int * 4)(0, nao, 0, nao), null, ctypes.c_int(0)) dms = [numpy.asarray(x, order='F') for x in dms] max_memory = dfobj.max_memory - lib.current_memory()[0] blksize = max( 4, int(min(dfobj.blockdim, max_memory * .22e6 / 8 / nao**2))) buf = numpy.empty((2, blksize, nao, nao)) for eri1 in dfobj.loop(blksize): naux, nao_pair = eri1.shape if with_j: rho = numpy.einsum('ix,px->ip', dmtril, eri1) vj += numpy.einsum('ip,px->ix', rho, eri1) for k in range(nset): buf1 = buf[0, :naux] fdrv(ftrans, fmmm, buf1.ctypes.data_as(ctypes.c_void_p), eri1.ctypes.data_as(ctypes.c_void_p), dms[k].ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), *rargs) buf2 = lib.unpack_tril(eri1, out=buf[1]) vk[k] += lib.dot( buf1.reshape(-1, nao).T, buf2.reshape(-1, nao)) t1 = log.timer_debug1('jk', *t1) if with_j: vj = lib.unpack_tril(vj, 1).reshape(dm_shape) if with_k: vk = vk.reshape(dm_shape) logger.timer(dfobj, 'df vj and vk', *t0) return vj, vk
def get_jk(dfobj, dm, hermi=1, vhfopt=None, with_j=True, with_k=True): t0 = t1 = (time.clock(), time.time()) log = logger.Logger(dfobj.stdout, dfobj.verbose) assert (with_j or with_k) fmmm = _ao2mo.libao2mo.AO2MOmmm_bra_nr_s2 fdrv = _ao2mo.libao2mo.AO2MOnr_e2_drv ftrans = _ao2mo.libao2mo.AO2MOtranse2_nr_s2 null = lib.c_null_ptr() dms = numpy.asarray(dm) dm_shape = dms.shape nao = dm_shape[-1] dms = dms.reshape(-1, nao, nao) nset = dms.shape[0] vj = [0] * nset vk = [0] * nset if not with_k: dmtril = [] idx = numpy.arange(nao) for k in range(nset): dm = lib.pack_tril(dms[k] + dms[k].T) dm[idx * (idx + 1) // 2 + idx] *= .5 dmtril.append(dm) for eri1 in dfobj.loop(): naux, nao_pair = eri1.shape for k in range(nset): rho = numpy.einsum('px,x->p', eri1, dmtril[k]) vj[k] += numpy.einsum('p,px->x', rho, eri1) elif hasattr(dm, 'mo_coeff'): #TODO: test whether dm.mo_coeff matching dm mo_coeff = numpy.asarray(dm.mo_coeff, order='F') mo_occ = numpy.asarray(dm.mo_occ) nmo = mo_occ.shape[-1] mo_coeff = mo_coeff.reshape(-1, nao, nmo) mo_occ = mo_occ.reshape(-1, nmo) if mo_occ.shape[0] * 2 == nset: # handle ROHF DM mo_coeff = numpy.vstack((mo_coeff, mo_coeff)) mo_occa = numpy.array(mo_occ > 0, dtype=numpy.double) mo_occb = numpy.array(mo_occ == 2, dtype=numpy.double) assert (mo_occa.sum() + mo_occb.sum() == mo_occ.sum()) mo_occ = numpy.vstack((mo_occa, mo_occb)) dmtril = [] orbo = [] for k in range(nset): if with_j: dmtril.append(lib.pack_tril(dms[k] + dms[k].T)) i = numpy.arange(nao) dmtril[k][i * (i + 1) // 2 + i] *= .5 c = numpy.einsum('pi,i->pi', mo_coeff[k][:, mo_occ[k] > 0], numpy.sqrt(mo_occ[k][mo_occ[k] > 0])) orbo.append(numpy.asarray(c, order='F')) buf = numpy.empty((dfobj.blockdim * nao, nao)) for eri1 in dfobj.loop(): naux, nao_pair = eri1.shape assert (nao_pair == nao * (nao + 1) // 2) for k in range(nset): if with_j: rho = numpy.einsum('px,x->p', eri1, dmtril[k]) vj[k] += numpy.einsum('p,px->x', rho, eri1) nocc = orbo[k].shape[1] if nocc > 0: buf1 = buf[:naux * nocc] fdrv(ftrans, fmmm, buf1.ctypes.data_as(ctypes.c_void_p), eri1.ctypes.data_as(ctypes.c_void_p), orbo[k].ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), ctypes.c_int(nao), (ctypes.c_int * 4)(0, nocc, 0, nao), null, ctypes.c_int(0)) vk[k] += lib.dot(buf1.T, buf1) t1 = log.timer_debug1('jk', *t1) else: #:vk = numpy.einsum('pij,jk->pki', cderi, dm) #:vk = numpy.einsum('pki,pkj->ij', cderi, vk) rargs = (ctypes.c_int(nao), (ctypes.c_int * 4)(0, nao, 0, nao), null, ctypes.c_int(0)) dms = [numpy.asarray(x, order='F') for x in dms] buf = numpy.empty((2, dfobj.blockdim, nao, nao)) for eri1 in dfobj.loop(): naux, nao_pair = eri1.shape for k in range(nset): buf1 = buf[0, :naux] fdrv(ftrans, fmmm, buf1.ctypes.data_as(ctypes.c_void_p), eri1.ctypes.data_as(ctypes.c_void_p), dms[k].ctypes.data_as(ctypes.c_void_p), ctypes.c_int(naux), *rargs) if with_j: rho = numpy.einsum('kii->k', buf1) vj[k] += numpy.einsum('p,px->x', rho, eri1) buf2 = lib.unpack_tril(eri1, out=buf[1]) vk[k] += lib.dot( buf1.reshape(-1, nao).T, buf2.reshape(-1, nao)) t1 = log.timer_debug1('jk', *t1) if with_j: vj = lib.unpack_tril(vj, 1).reshape(dm_shape) if with_k: vk = numpy.asarray(vk).reshape(dm_shape) logger.timer(dfobj, 'vj and vk', *t0) return vj, vk
def get_j(dfobj, dm, hermi=1, direct_scf_tol=1e-13): from pyscf.scf import _vhf from pyscf.scf import jk from pyscf.df import addons t0 = t1 = (time.clock(), time.time()) mol = dfobj.mol if dfobj._vjopt is None: dfobj.auxmol = auxmol = addons.make_auxmol(mol, dfobj.auxbasis) opt = _vhf.VHFOpt(mol, 'int3c2e', 'CVHFnr3c2e_schwarz_cond') opt.direct_scf_tol = direct_scf_tol # q_cond part 1: the regular int2e (ij|ij) for mol's basis opt.init_cvhf_direct(mol, 'int2e', 'CVHFsetnr_direct_scf') mol_q_cond = lib.frompointer(opt._this.contents.q_cond, mol.nbas**2) # Update q_cond to include the 2e-integrals (auxmol|auxmol) j2c = auxmol.intor('int2c2e', hermi=1) j2c_diag = numpy.sqrt(abs(j2c.diagonal())) aux_loc = auxmol.ao_loc aux_q_cond = [ j2c_diag[i0:i1].max() for i0, i1 in zip(aux_loc[:-1], aux_loc[1:]) ] q_cond = numpy.hstack((mol_q_cond, aux_q_cond)) fsetqcond = _vhf.libcvhf.CVHFset_q_cond fsetqcond(opt._this, q_cond.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(q_cond.size)) try: opt.j2c = j2c = scipy.linalg.cho_factor(j2c, lower=True) opt.j2c_type = 'cd' except scipy.linalg.LinAlgError: opt.j2c = j2c opt.j2c_type = 'regular' # jk.get_jk function supports 4-index integrals. Use bas_placeholder # (l=0, nctr=1, 1 function) to hold the last index. bas_placeholder = numpy.array([0, 0, 1, 1, 0, 0, 0, 0], dtype=numpy.int32) fakemol = mol + auxmol fakemol._bas = numpy.vstack((fakemol._bas, bas_placeholder)) opt.fakemol = fakemol dfobj._vjopt = opt t1 = logger.timer_debug1(dfobj, 'df-vj init_direct_scf', *t1) opt = dfobj._vjopt fakemol = opt.fakemol dm = numpy.asarray(dm, order='C') dm_shape = dm.shape nao = dm_shape[-1] dm = dm.reshape(-1, nao, nao) n_dm = dm.shape[0] # First compute the density in auxiliary basis # j3c = fauxe2(mol, auxmol) # jaux = numpy.einsum('ijk,ji->k', j3c, dm) # rho = numpy.linalg.solve(auxmol.intor('int2c2e'), jaux) nbas = mol.nbas nbas1 = mol.nbas + dfobj.auxmol.nbas shls_slice = (0, nbas, 0, nbas, nbas, nbas1, nbas1, nbas1 + 1) with lib.temporary_env(opt, prescreen='CVHFnr3c2e_vj_pass1_prescreen', _dmcondname='CVHFsetnr_direct_scf_dm'): jaux = jk.get_jk(fakemol, dm, ['ijkl,ji->kl'] * n_dm, 'int3c2e', aosym='s2ij', hermi=0, shls_slice=shls_slice, vhfopt=opt) # remove the index corresponding to bas_placeholder jaux = numpy.array(jaux)[:, :, 0] t1 = logger.timer_debug1(dfobj, 'df-vj pass 1', *t1) if opt.j2c_type == 'cd': rho = scipy.linalg.cho_solve(opt.j2c, jaux.T) else: rho = scipy.linalg.solve(opt.j2c, jaux.T) # transform rho to shape (:,1,naux), to adapt to 3c2e integrals (ij|k) rho = rho.T[:, numpy.newaxis, :] t1 = logger.timer_debug1(dfobj, 'df-vj solve ', *t1) # Next compute the Coulomb matrix # j3c = fauxe2(mol, auxmol) # vj = numpy.einsum('ijk,k->ij', j3c, rho) with lib.temporary_env(opt, prescreen='CVHFnr3c2e_vj_pass2_prescreen', _dmcondname=None): # CVHFnr3c2e_vj_pass2_prescreen requires custom dm_cond aux_loc = dfobj.auxmol.ao_loc dm_cond = [ abs(rho[:, :, i0:i1]).max() for i0, i1 in zip(aux_loc[:-1], aux_loc[1:]) ] dm_cond = numpy.array(dm_cond) fsetcond = _vhf.libcvhf.CVHFset_dm_cond fsetcond(opt._this, dm_cond.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(dm_cond.size)) vj = jk.get_jk(fakemol, rho, ['ijkl,lk->ij'] * n_dm, 'int3c2e', aosym='s2ij', hermi=1, shls_slice=shls_slice, vhfopt=opt) t1 = logger.timer_debug1(dfobj, 'df-vj pass 2', *t1) logger.timer(dfobj, 'df-vj', *t0) return numpy.asarray(vj).reshape(dm_shape)
def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1, kpt=None, kpts_band=None): '''Coulomb + XC functional .. note:: This function will change the ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Returns: matrix Veff = J + Vxc. Veff can be a list matrices, if the input dm is a list of density matrices. ''' if cell is None: cell = ks.cell if dm is None: dm = ks.make_rdm1() if kpt is None: kpt = ks.kpt t0 = (time.clock(), time.time()) omega, alpha, hyb = ks._numint.rsh_and_hybrid_coeff(ks.xc, spin=cell.spin) if abs(omega) > 1e-10: raise NotImplementedError hybrid = abs(hyb) > 1e-10 if not hybrid and isinstance(ks.with_df, multigrid.MultiGridFFTDF): n, exc, vxc = multigrid.nr_rks(ks.with_df, ks.xc, dm, hermi, kpt.reshape(1, 3), kpts_band, with_j=True, return_j=False) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) return vxc ground_state = (isinstance(dm, numpy.ndarray) and dm.ndim == 2 and kpts_band is None) # Use grids.non0tab to detect whether grids are initialized. For # UniformGrids, grids.coords as a property cannot indicate whehter grids are # initialized. if ks.grids.non0tab is None: ks.grids.build(with_non0tab=True) if (isinstance(ks.grids, gen_grid.BeckeGrids) and ks.small_rho_cutoff > 1e-20 and ground_state): ks.grids = prune_small_rho_grids_(ks, cell, dm, ks.grids, kpt) t0 = logger.timer(ks, 'setting up grids', *t0) if hermi == 2: # because rho = 0 n, exc, vxc = 0, 0, 0 else: n, exc, vxc = ks._numint.nr_rks(cell, ks.grids, ks.xc, dm, 0, kpt, kpts_band) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) if not hybrid: vj = ks.get_j(cell, dm, hermi, kpt, kpts_band) vxc += vj else: if getattr(ks.with_df, '_j_only', False): # for GDF and MDF ks.with_df._j_only = False vj, vk = ks.get_jk(cell, dm, hermi, kpt, kpts_band) vxc += vj - vk * (hyb * .5) if ground_state: exc -= numpy.einsum('ij,ji', dm, vk).real * .5 * hyb * .5 if ground_state: ecoul = numpy.einsum('ij,ji', dm, vj).real * .5 else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=None, vk=None) return vxc
def solve_mo1(sscobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): cput1 = (time.clock(), time.time()) 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 get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1, kpt=None, kpt_band=None): '''Coulomb + XC functional .. note:: This function will change the ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. The ._exc and ._ecoul attributes will be updated after return. Attributes ._dm_last, ._vj_last and ._vk_last might be changed if direct SCF method is applied. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Returns: matrix Veff = J + Vxc. Veff can be a list matrices, if the input dm is a list of density matrices. ''' if cell is None: cell = ks.cell if dm is None: dm = ks.make_rdm1() if kpt is None: kpt = ks.kpt t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.build() small_rho_cutoff = ks.small_rho_cutoff t0 = logger.timer(ks, 'setting up grids', *t0) else: small_rho_cutoff = 0 dm = numpy.asarray(dm) nao = dm.shape[-1] ground_state = (dm.ndim == 2) if hermi == 2: # because rho = 0 n, ks._exc, vx = 0, 0, 0 else: n, ks._exc, vx = ks._numint.nr_rks(cell, ks.grids, ks.xc, dm, 1, kpt, kpt_band) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) hyb = ks._numint.hybrid_coeff(ks.xc, spin=(cell.spin > 0) + 1) if abs(hyb) < 1e-10: vhf = vj = ks.get_j(cell, dm, hermi, kpt, kpt_band) else: vj, vk = ks.get_jk(cell, dm, hermi, kpt, kpt_band) vhf = vj - vk * (hyb * .5) if ground_state: ks._exc -= numpy.einsum('ij,ji', dm, vk).real * .5 * hyb * .5 if ground_state: ks._ecoul = numpy.einsum('ij,ji', dm, vj).real * .5 if (small_rho_cutoff > 1e-20 and ground_state and abs(n - cell.nelectron) < 0.01 * n): # Filter grids the first time setup grids idx = ks._numint.large_rho_indices(cell, dm, ks.grids, small_rho_cutoff, kpt) logger.debug(ks, 'Drop grids %d', ks.grids.weights.size - numpy.count_nonzero(idx)) ks.grids.coords = numpy.asarray(ks.grids.coords[idx], order='C') ks.grids.weights = numpy.asarray(ks.grids.weights[idx], order='C') ks._numint.non0tab = None return vhf + vx
def get_veff(ks, cell=None, dm=None, dm_last=0, vhf_last=0, hermi=1, kpts=None, kpts_band=None): '''Coulomb + XC functional .. note:: This is a replica of pyscf.dft.rks.get_veff with kpts added. This function will change the ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Returns: Veff : (nkpts, nao, nao) or (*, nkpts, nao, nao) ndarray Veff = J + Vxc. ''' if cell is None: cell = ks.cell if dm is None: dm = ks.make_rdm1() if kpts is None: kpts = ks.kpts t0 = (logger.process_clock(), logger.perf_counter()) omega, alpha, hyb = ks._numint.rsh_and_hybrid_coeff(ks.xc, spin=cell.spin) hybrid = abs(hyb) > 1e-10 or abs(alpha) > 1e-10 if not hybrid and isinstance(ks.with_df, multigrid.MultiGridFFTDF): n, exc, vxc = multigrid.nr_rks(ks.with_df, ks.xc, dm, hermi, kpts, kpts_band, with_j=True, return_j=False) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) return vxc # ndim = 3 : dm.shape = (nkpts, nao, nao) ground_state = (isinstance(dm, np.ndarray) and dm.ndim == 3 and kpts_band is None) # For UniformGrids, grids.coords does not indicate whehter grids are initialized if ks.grids.non0tab is None: ks.grids.build(with_non0tab=True) if (isinstance(ks.grids, gen_grid.BeckeGrids) and ks.small_rho_cutoff > 1e-20 and ground_state): ks.grids = rks.prune_small_rho_grids_(ks, cell, dm, ks.grids, kpts) t0 = logger.timer(ks, 'setting up grids', *t0) if hermi == 2: # because rho = 0 n, exc, vxc = 0, 0, 0 else: n, exc, vxc = ks._numint.nr_rks(cell, ks.grids, ks.xc, dm, hermi, kpts, kpts_band) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) weight = 1./len(kpts) if not hybrid: vj = ks.get_j(cell, dm, hermi, kpts, kpts_band) vxc += vj else: if getattr(ks.with_df, '_j_only', False): # for GDF and MDF ks.with_df._j_only = False vj, vk = ks.get_jk(cell, dm, hermi, kpts, kpts_band) vk *= hyb if abs(omega) > 1e-10: vklr = ks.get_k(cell, dm, hermi, kpts, kpts_band, omega=omega) vklr *= (alpha - hyb) vk += vklr vxc += vj - vk * .5 if ground_state: exc -= np.einsum('Kij,Kji', dm, vk).real * .5 * .5 * weight if ground_state: ecoul = np.einsum('Kij,Kji', dm, vj).real * .5 * weight else: ecoul = None vxc = lib.tag_array(vxc, ecoul=ecoul, exc=exc, vj=None, vk=None) return vxc
def build(self): t0 = (time.clock(), time.time()) lib.logger.TIMER_LEVEL = 3 cell = libpbc.chkfile.load_cell(self.chkfile) cell.ecp = None self.cell = cell self.a = self.cell.lattice_vectors() self.b = self.cell.reciprocal_vectors() self.vol = self.cell.vol self.nelectron = self.cell.nelectron self.charge = self.cell.charge self.spin = self.cell.spin self.natm = self.cell.natm self.kpts = lib.chkfile.load(self.chkfile, 'kcell/kpts') self.nkpts = len(self.kpts) self.ls = cell.get_lattice_Ls(dimension=3) self.ls = self.ls[numpy.argsort(lib.norm(self.ls, axis=1))] self.atm = numpy.asarray(cell._atm, dtype=numpy.int32, order='C') self.bas = numpy.asarray(cell._bas, dtype=numpy.int32, order='C') self.env = numpy.asarray(cell._env, dtype=numpy.double, order='C') self.nbas = self.bas.shape[0] self.ao_loc = cell.ao_loc_nr() self.shls_slice = (0, self.nbas) sh0, sh1 = self.shls_slice self.nao = self.ao_loc[sh1] - self.ao_loc[sh0] self.non0tab = numpy.empty((1,self.nbas), dtype=numpy.int8) # non0tab stores the number of images to be summed in real space. # Initializing it to 255 means all images are summed self.non0tab[:] = 0xff self.coords = numpy.asarray([(numpy.asarray(atom[1])).tolist() for atom in cell._atom]) self.charges = cell.atom_charges() self.mo_coeff = lib.chkfile.load(self.chkfile, 'scf/mo_coeff') self.mo_occ = lib.chkfile.load(self.chkfile, 'scf/mo_occ') nprims, nmo = self.mo_coeff[0].shape self.nprims = nprims self.nmo = nmo self.cart = cell.cart if (not self.leb): self.npang = self.npphi*self.nptheta self.rcut = _estimate_rcut(self) kpts = numpy.reshape(self.kpts, (-1,3)) kpts_lst = numpy.reshape(kpts, (-1,3)) self.explk = numpy.exp(1j * numpy.asarray(numpy.dot(self.ls, kpts_lst.T), order='C')) if (self.ntrial%2 == 0): self.ntrial += 1 geofac = numpy.power(((self.rmaxsurf-0.1)/self.rprimer),(1.0/(self.ntrial-1.0))) self.rpru = numpy.zeros((self.ntrial)) for i in range(self.ntrial): self.rpru[i] = self.rprimer*numpy.power(geofac,(i+1)-1) self.rsurf = numpy.zeros((self.npang,self.ntrial), order='C') self.nlimsurf = numpy.zeros((self.npang), dtype=numpy.int32) if self.verbose >= logger.WARN: self.check_sanity() if self.verbose > logger.NOTE: self.dump_input() if (self.iqudt == 'legendre'): self.iqudt = 1 if (self.leb): self.grids = grid.lebgrid(self.npang) else: self.grids = grid.anggrid(self.iqudt,self.nptheta,self.npphi) self.xyzrho = numpy.zeros((self.natm,3)) t = time.time() logger.info(self,'Time finding nucleus %.3f (sec)' % (time.time()-t)) if (self.backend == 'rkck'): backend = 1 elif (self.backend == 'rkdp'): backend = 2 else: raise NotImplementedError('Only rkck or rkdp ODE solver yet available') ct_ = numpy.asarray(self.grids[:,0], order='C') st_ = numpy.asarray(self.grids[:,1], order='C') cp_ = numpy.asarray(self.grids[:,2], order='C') sp_ = numpy.asarray(self.grids[:,3], order='C') mo_coeff = numpy.zeros((self.nkpts,self.nprims,self.nmo), dtype=numpy.complex128) mo_occ = numpy.zeros((self.nkpts,self.nmo)) for k in range(self.nkpts): mo_coeff[k,:,:] = self.mo_coeff[k][:,:] mo_occ[k,:] = self.mo_occ[k][:] t = time.time() feval = 'surf_driver' drv = getattr(libaim, feval) with lib.with_omp_threads(self.nthreads): drv(ctypes.c_int(self.inuc), self.xyzrho.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.npang), ct_.ctypes.data_as(ctypes.c_void_p), st_.ctypes.data_as(ctypes.c_void_p), cp_.ctypes.data_as(ctypes.c_void_p), sp_.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.ntrial), self.rpru.ctypes.data_as(ctypes.c_void_p), ctypes.c_double(self.epsiscp), ctypes.c_double(self.epsroot), ctypes.c_double(self.rmaxsurf), ctypes.c_int(backend), ctypes.c_double(self.epsilon), ctypes.c_double(self.step), ctypes.c_int(self.mstep), ctypes.c_int(self.natm), self.coords.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.cart), ctypes.c_int(self.nmo), ctypes.c_int(self.nprims), self.atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.nbas), self.bas.ctypes.data_as(ctypes.c_void_p), self.env.ctypes.data_as(ctypes.c_void_p), self.ao_loc.ctypes.data_as(ctypes.c_void_p), mo_coeff.ctypes.data_as(ctypes.c_void_p), mo_occ.ctypes.data_as(ctypes.c_void_p), ctypes.c_double(self.occdrop), # self.a.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(len(self.ls)), self.ls.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.nkpts), self.explk.ctypes.data_as(ctypes.c_void_p), self.rcut.ctypes.data_as(ctypes.c_void_p), self.non0tab.ctypes.data_as(ctypes.c_void_p), # self.nlimsurf.ctypes.data_as(ctypes.c_void_p), self.rsurf.ctypes.data_as(ctypes.c_void_p)) for i in range(self.nkpts): print k,self.mo_occ[k][:] logger.info(self,'Time finding surface %.3f (sec)' % (time.time()-t)) r = numpy.array([0.00000, 0.00000, 0.00000]) r = numpy.reshape(r, (-1,3)) ao = dft.numint.eval_ao_kpts(self.cell, r, kpts=self.kpts, deriv=1) print rhograd(self,[0,0,0]) logger.info(self,'Surface of atom %d saved',self.inuc) logger.timer(self,'BaderSurf build', *t0) return self
def build(self): t0 = (time.clock(), time.time()) lib.logger.TIMER_LEVEL = 3 mol = lib.chkfile.load_mol(self.chkfile) self.nelectron = mol.nelectron self.charge = mol.charge self.spin = mol.spin self.natm = mol.natm self.atm = numpy.asarray(mol._atm, dtype=numpy.int32, order='C') self.bas = numpy.asarray(mol._bas, dtype=numpy.int32, order='C') self.nbas = self.bas.shape[0] self.env = numpy.asarray(mol._env, dtype=numpy.double, order='C') self.ao_loc = mol.ao_loc_nr() self.shls_slice = (0, self.nbas) sh0, sh1 = self.shls_slice self.nao = self.ao_loc[sh1] - self.ao_loc[sh0] self.non0tab = numpy.ones((1, self.nbas), dtype=numpy.int8) self.coords = numpy.asarray([(numpy.asarray(atom[1])).tolist() for atom in mol._atom]) self.charges = mol.atom_charges() #if (self.cas): # self.mo_coeff = lib.chkfile.load(self.chkfile, 'mcscf/mo_coeff') #else: # self.mo_coeff = lib.chkfile.load(self.chkfile, 'scf/mo_coeff') self.mo_coeff = lib.chkfile.load(self.chkfile, 'scf/mo_coeff') self.mo_occ = lib.chkfile.load(self.chkfile, 'scf/mo_occ') nprims, nmo = self.mo_coeff.shape self.nprims = nprims self.nmo = nmo self.cart = mol.cart if (not self.leb): self.npang = self.npphi * self.nptheta if (self.corr): self.rdm1 = lib.chkfile.load(self.chkfile, 'rdm/rdm1') nmo = self.rdm1.shape[0] natocc, natorb = numpy.linalg.eigh(self.rdm1) if (self.cas): self.mo_coeff = lib.chkfile.load(self.chkfile, 'mcscf/mo_coeff') natorb = numpy.dot(self.mo_coeff, natorb) self.mo_coeff = natorb self.mo_occ = natocc nocc = self.mo_occ[abs(self.mo_occ) > self.occdrop] nocc = len(nocc) self.nocc = nocc if (self.ntrial % 2 == 0): self.ntrial += 1 geofac = numpy.power(((self.rmaxsurf - 0.1) / self.rprimer), (1.0 / (self.ntrial - 1.0))) self.rpru = numpy.zeros((self.ntrial)) for i in range(self.ntrial): self.rpru[i] = self.rprimer * numpy.power(geofac, (i + 1) - 1) self.rsurf = numpy.zeros((self.npang, self.ntrial), order='C') self.nlimsurf = numpy.zeros((self.npang), dtype=numpy.int32) if self.verbose >= logger.WARN: self.check_sanity() if self.verbose > logger.NOTE: self.dump_input() if (self.iqudt == 'legendre'): self.iqudt = 1 if (self.leb): self.grids = grid.lebgrid(self.npang) else: self.grids = grid.anggrid(self.iqudt, self.nptheta, self.npphi) self.xyzrho = numpy.zeros((self.natm, 3)) t = time.time() for i in range(self.natm): self.xyzrho[i], gradmod = gradrho(self, self.coords[i], self.step) if (gradmod > 1e-4): if (self.charges[i] > 2.0): logger.info(self, 'Good rho position %.6f %.6f %.6f', *self.xyzrho[i]) else: raise RuntimeError('Failed finding nucleus:', *self.xyzrho[i]) else: logger.info(self, 'Check rho position %.6f %.6f %.6f', *self.xyzrho[i]) logger.info(self, 'Setting xyzrho for atom to imput coords') self.xyzrho[i] = self.coords[i] self.xnuc = numpy.asarray(self.xyzrho[self.inuc]) logger.info(self, 'Time finding nucleus %.3f (sec)' % (time.time() - t)) if (self.backend == 'rkck'): backend = 1 elif (self.backend == 'rkdp'): backend = 2 else: raise NotImplementedError( 'Only rkck or rkdp ODE solver yet available') ct_ = numpy.asarray(self.grids[:, 0], order='C') st_ = numpy.asarray(self.grids[:, 1], order='C') cp_ = numpy.asarray(self.grids[:, 2], order='C') sp_ = numpy.asarray(self.grids[:, 3], order='C') t = time.time() feval = 'surf_driver' drv = getattr(libaim, feval) with lib.with_omp_threads(self.nthreads): drv(ctypes.c_int(self.inuc), self.xyzrho.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.npang), ct_.ctypes.data_as(ctypes.c_void_p), st_.ctypes.data_as(ctypes.c_void_p), cp_.ctypes.data_as(ctypes.c_void_p), sp_.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.ntrial), self.rpru.ctypes.data_as(ctypes.c_void_p), ctypes.c_double(self.epsiscp), ctypes.c_double(self.epsroot), ctypes.c_double(self.rmaxsurf), ctypes.c_int(backend), ctypes.c_double(self.epsilon), ctypes.c_double(self.step), ctypes.c_int(self.mstep), ctypes.c_int(self.natm), self.coords.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.cart), ctypes.c_int(self.nmo), ctypes.c_int(self.nprims), self.atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.nbas), self.bas.ctypes.data_as(ctypes.c_void_p), self.env.ctypes.data_as(ctypes.c_void_p), self.ao_loc.ctypes.data_as(ctypes.c_void_p), self.mo_coeff.ctypes.data_as(ctypes.c_void_p), self.mo_occ.ctypes.data_as(ctypes.c_void_p), ctypes.c_double(self.occdrop), self.nlimsurf.ctypes.data_as(ctypes.c_void_p), self.rsurf.ctypes.data_as(ctypes.c_void_p)) logger.info(self, 'Time finding surface %.3f (sec)' % (time.time() - t)) self.rmin = 1000.0 self.rmax = 0.0 for i in range(self.npang): nsurf = int(self.nlimsurf[i]) self.rmin = numpy.minimum(self.rmin, self.rsurf[i, 0]) self.rmax = numpy.maximum(self.rmax, self.rsurf[i, nsurf - 1]) logger.info(self, 'Rmin for surface %.6f', self.rmin) logger.info(self, 'Rmax for surface %.6f', self.rmax) logger.info(self, 'Write HDF5 surface file') atom_dic = { 'inuc': self.inuc, 'xnuc': self.xnuc, 'xyzrho': self.xyzrho, 'coords': self.grids, 'npang': self.npang, 'ntrial': self.ntrial, 'rmin': self.rmin, 'rmax': self.rmax, 'nlimsurf': self.nlimsurf, 'rsurf': self.rsurf } lib.chkfile.save(self.surfile, 'atom' + str(self.inuc), atom_dic) logger.info(self, 'Surface of atom %d saved', self.inuc) logger.timer(self, 'BaderSurf build', *t0) return self
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 = (time.clock(), time.time()) 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 get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1): '''Coulomb + XC functional .. note:: This function will change the ks object. Args: ks : an instance of :class:`RKS` XC functional are controlled by ks.xc attribute. Attribute ks.grids might be initialized. The ._exc and ._ecoul attributes will be updated after return. Attributes ._dm_last, ._vj_last and ._vk_last might be changed if direct SCF method is applied. dm : ndarray or list of ndarrays A density matrix or a list of density matrices Kwargs: dm_last : ndarray or a list of ndarrays or 0 The density matrix baseline. If not 0, this function computes the increment of HF potential w.r.t. the reference HF potential matrix. vhf_last : ndarray or a list of ndarrays or 0 The reference HF potential matrix. If vhf_last is not given, the function will not call direct_scf and attacalites ._dm_last, ._vj_last and ._vk_last will not be updated. hermi : int Whether J, K matrix is hermitian | 0 : no hermitian or symmetric | 1 : hermitian | 2 : anti-hermitian Returns: matrix Veff = J + Vxc. Veff can be a list matrices, if the input dm is a list of density matrices. ''' if mol is None: mol = ks.mol if dm is None: dm = ks.make_rdm1() t0 = (time.clock(), time.time()) if ks.grids.coords is None: ks.grids.build(with_non0tab=True) small_rho_cutoff = ks.small_rho_cutoff t0 = logger.timer(ks, 'setting up grids', *t0) else: small_rho_cutoff = 0 dm = numpy.asarray(dm) nao = dm.shape[-1] ground_state = (dm.ndim == 2) if hermi == 2: # because rho = 0 n, ks._exc, vx = 0, 0, 0 else: n, ks._exc, vx = ks._numint.nr_vxc(mol, ks.grids, ks.xc, dm, hermi=hermi) logger.debug(ks, 'nelec by numeric integration = %s', n) t0 = logger.timer(ks, 'vxc', *t0) hyb = ks._numint.hybrid_coeff(ks.xc, spin=mol.spin) if abs(hyb) < 1e-10: if (ks._eri is not None or not ks.direct_scf or not hasattr(ks, '_dm_last') or not isinstance(vhf_last, numpy.ndarray)): vhf = vj = ks.get_j(mol, dm, hermi) else: ddm = numpy.asarray(dm) - numpy.asarray(ks._dm_last) vj = ks.get_j(mol, ddm, hermi) vj += ks._vj_last ks._dm_last = dm vhf = ks._vj_last = vj else: raise NotImplementedError if (ks._eri is not None or not ks.direct_scf or not hasattr(ks, '_dm_last') or not isinstance(vhf_last, numpy.ndarray)): vj, vk = ks.get_jk(mol, dm, hermi) else: ddm = numpy.asarray(dm) - numpy.asarray(ks._dm_last) vj, vk = ks.get_jk(mol, ddm, hermi) vj += ks._vj_last vk += ks._vk_last ks._dm_last = dm ks._vj_last, ks._vk_last = vj, vk vhf = vj - vk * hyb if ground_state: ks._exc -= numpy.einsum('ij,ji', dm, vk) * .5 * hyb if ground_state: ks._ecoul = numpy.einsum('ij,ji', dm, vj) * .5 if (small_rho_cutoff > 1e-20 and ground_state and abs(n-mol.nelectron) < 0.01*n): # Filter grids the first time setup grids idx = ks._numint.large_rho_indices(mol, dm, ks.grids, small_rho_cutoff) logger.debug(ks, 'Drop grids %d', ks.grids.weights.size - numpy.count_nonzero(idx)) ks.grids.coords = numpy.asarray(ks.grids.coords [idx], order='C') ks.grids.weights = numpy.asarray(ks.grids.weights[idx], order='C') ks.grids.non0tab = ks.grids.make_mask(mol, ks.grids.coords) return vhf + vx