def kernel(self, *args, **kwargs): with_solvent = self.with_solvent # The underlying ._scf object is decorated with solvent effects. # The resultant Fock matrix and orbital energies both include the # effects from solvent. It means that solvent effects for post-HF # methods are automatically counted if solvent is enabled at scf # level. if with_solvent.frozen: return old_method.kernel(self, *args, **kwargs) log = logger.new_logger(self) log.info( '\n** Self-consistently update the solvent effects for %s **', old_method) ##TODO: Suppress a few output messages #log1 = copy.copy(log) #log1.note, log1.info = log1.info, log1.debug e_last = 0 for cycle in range(self.with_solvent.max_cycle): log.info('\n** Solvent self-consistent cycle %d:', cycle) # Solvent effects are applied when accessing the # underlying ._scf objects. The flag frozen=True ensures that # the generated potential with_solvent.vpcm is passed to the # the post-HF object, without being updated in the implicit # call to the _scf iterations. with lib.temporary_env(with_solvent, frozen=True): e_tot = basic_scanner(self.mol) dm = basic_scanner.make_rdm1(ao_repr=True) if with_solvent.epcm is not None: edup = numpy.einsum('ij,ji->', with_solvent.vpcm, dm) e_tot = e_tot - edup + with_solvent.epcm log.debug(' E_diel = %.15g', with_solvent.epcm) # To generate the solvent potential for ._scf object. Since # frozen is set when calling basic_scanner, the solvent # effects are frozen during the scf iterations. with_solvent.epcm, with_solvent.vpcm = with_solvent.kernel(dm) de = e_tot - e_last log.info('Sovlent cycle %d E_tot = %.15g dE = %g', cycle, e_tot, de) if abs(e_tot - e_last).max() < with_solvent.conv_tol: break e_last = e_tot # An extra cycle to compute the total energy log.info('\n** Extra cycle for solvent effects') res = old_method.kernel(self) with lib.temporary_env(with_solvent, frozen=True): #Update everything except the _scf object and _keys basic_scanner(self.mol) new_keys = self._keys self.__dict__.update(basic_scanner.__dict__) self._keys = new_keys self._scf = scf_with_solvent self._finalize() return res
def test_sgx_jk(self): mol = gto.Mole() mol.build( verbose=0, atom=[["O", (0., 0., 0.)], [1, (0., -0.757, 0.587)], [1, (0., 0.757, 0.587)]], basis='ccpvdz', ) nao = mol.nao #numpy.random.seed(1) #dm = numpy.random.random((nao,nao)) #dm = dm + dm.T mf = scf.UHF(mol) dm = mf.get_init_guess() sgxobj = sgx.SGX(mol) sgxobj.grids = sgx_jk.get_gridss(mol, 0, 1e-10) with lib.temporary_env(sgxobj, debug=False): vj, vk = sgx_jk.get_jk_favork(sgxobj, dm) #self.assertAlmostEqual(lib.finger(vj), -19.25235595827077, 9) #self.assertAlmostEqual(lib.finger(vk), -16.711443399467267, 9) with lib.temporary_env(sgxobj, debug=True): vj1, vk1 = sgx_jk.get_jk_favork(sgxobj, dm) self.assertAlmostEqual(abs(vj1 - vj).max(), 0, 9) self.assertAlmostEqual(abs(vk1 - vk).max(), 0, 9) with lib.temporary_env(sgxobj, debug=False): vj, vk = sgx_jk.get_jk_favorj(sgxobj, dm) #self.assertAlmostEqual(lib.finger(vj), -19.176378579757973, 9) #self.assertAlmostEqual(lib.finger(vk), -16.750915356787406, 9) with lib.temporary_env(sgxobj, debug=True): vj1, vk1 = sgx_jk.get_jk_favorj(sgxobj, dm) self.assertAlmostEqual(abs(vj1 - vj).max(), 0, 9) self.assertAlmostEqual(abs(vk1 - vk).max(), 0, 9)
def kernel(self, *args, **kwargs): with_solvent = self.with_solvent # The underlying ._scf object is decorated with solvent effects. # The resultant Fock matrix and orbital energies both include the # effects from solvent. It means that solvent effects for post-HF # methods are automatically counted if solvent is enabled at scf # level. if with_solvent.frozen: return old_method.kernel(self, *args, **kwargs) log = logger.new_logger(self) log.info('\n** Self-consistently update the solvent effects for %s **', old_method) ##TODO: Suppress a few output messages #log1 = copy.copy(log) #log1.note, log1.info = log1.info, log1.debug e_last = 0 for cycle in range(self.with_solvent.max_cycle): log.info('\n** Solvent self-consistent cycle %d:', cycle) # Solvent effects are applied when accessing the # underlying ._scf objects. The flag frozen=True ensures that # the generated potential with_solvent.vpcm is passed to the # the post-HF object, without being updated in the implicit # call to the _scf iterations. with lib.temporary_env(with_solvent, frozen=True): e_tot = basic_scanner(self.mol) dm = basic_scanner.make_rdm1(ao_repr=True) if with_solvent.epcm is not None: edup = numpy.einsum('ij,ji->', with_solvent.vpcm, dm) e_tot = e_tot - edup + with_solvent.epcm log.debug(' E_diel = %.15g', with_solvent.epcm) # To generate the solvent potential for ._scf object. Since # frozen is set when calling basic_scanner, the solvent # effects are frozen during the scf iterations. with_solvent.epcm, with_solvent.vpcm = with_solvent.kernel(dm) de = e_tot - e_last log.info('Sovlent cycle %d E_tot = %.15g dE = %g', cycle, e_tot, de) if abs(e_tot-e_last).max() < with_solvent.conv_tol: break e_last = e_tot # An extra cycle to compute the total energy log.info('\n** Extra cycle for solvent effects') res = old_method.kernel(self) with lib.temporary_env(with_solvent, frozen=True): #Update everything except the _scf object and _keys basic_scanner(self.mol) new_keys = self._keys self.__dict__.update(basic_scanner.__dict__) self._keys = new_keys self._scf = scf_with_solvent self._finalize() return res
def test_rcut_vs_ke_cut(self): xc = 'lda,' with lib.temporary_env(multigrid, TASKS_TYPE='rcut'): mg_df = multigrid.MultiGridFFTDF(cell_orth) n1, exc1, v1 = multigrid.nr_rks(mg_df, xc, dm1, kpts=kpts) self.assertEqual(len(mg_df.tasks), 3) with lib.temporary_env(multigrid, TASKS_TYPE='ke_cut'): mg_df = multigrid.MultiGridFFTDF(cell_orth) n2, exc2, v2 = multigrid.nr_rks(mg_df, xc, dm1, kpts=kpts) self.assertEqual(len(mg_df.tasks), 6) self.assertAlmostEqual(n1, n2, 8) self.assertAlmostEqual(exc1, exc2, 8) self.assertAlmostEqual(abs(v1-v2).max(), 0, 8)
def test_rcut_vs_ke_cut(self): xc = 'lda,' with lib.temporary_env(multigrid, TASKS_TYPE='rcut'): mg_df = multigrid.MultiGridFFTDF(cell_orth) n1, exc1, v1 = multigrid.nr_rks(mg_df, xc, dm1, kpts=kpts) self.assertEqual(len(mg_df.tasks), 3) with lib.temporary_env(multigrid, TASKS_TYPE='ke_cut'): mg_df = multigrid.MultiGridFFTDF(cell_orth) n2, exc2, v2 = multigrid.nr_rks(mg_df, xc, dm1, kpts=kpts) self.assertEqual(len(mg_df.tasks), 6) self.assertAlmostEqual(n1, n2, 8) self.assertAlmostEqual(exc1, exc2, 8) self.assertAlmostEqual(abs(v1 - v2).max(), 0, 8)
def get_nuc(mydf, kpts=None): # Pseudopotential is ignored when computing just the nuclear attraction t0 = (time.clock(), time.time()) with lib.temporary_env(mydf.cell, _pseudo={}): nuc = get_pp_loc_part1(mydf, kpts) logger.timer(mydf, 'get_nuc', *t0) return nuc
def test_so3_id2symb(self): ref = symm.basis._SO3_ID2SYMB with lib.temporary_env(symm.basis, _SO3_ID2SYMB={}): for s in [200, 202, 314, 317, 421, 420]: self.assertEqual(ref[s], symm.basis.so3_irrep_id2symb(s)) self.assertRaises(KeyError, symm.basis.so3_irrep_id2symb, 746) self.assertRaises(KeyError, symm.basis.so3_irrep_id2symb, 729)
def test_tda_with_wfnsym(self): pmol = mol.copy() pmol.symmetry = True pmol.build(0, 0) mf = dft.RKS(pmol).run() td = rks.TDA(mf) td.wfnsym = 'A2' es = td.kernel(nstates=3)[0] self.assertTrue(len(es) == 2) # At most 2 states due to symmetry subspace size self.assertAlmostEqual(lib.fp(es), 2.1857694738741071, 6) note_args = [] def temp_logger_note(rec, msg, *args): note_args.append(args) with lib.temporary_env(lib.logger.Logger, note=temp_logger_note): td.analyze() ref = [(), (1, 'A2', 38.42106241429979, 32.26985141807447, 0.0), (2, 'A2', 38.972172173478356, 31.813519911465608, 0.0)] self.assertEqual(note_args[1][1], 'A2') self.assertEqual(note_args[2][1], 'A2') self.assertAlmostEqual(abs(numpy.append(ref[1][2:], ref[2][2:]) - numpy.append(note_args[1][2:], note_args[2][2:])).max(), 0, 7)
def ao2mo(self, mo_coeff=None): from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ with_df = self._scf.with_df kpt = self._scf.kpt def ao2mofn(mo_coeff): nao, nmo = mo_coeff.shape mo_a = mo_coeff[:nao//2] mo_b = mo_coeff[nao//2:] orbspin = getattr(mo_coeff, 'orbspin', None) if orbspin is None: eri = with_df.ao2mo(mo_a, kpt, compact=False) eri += with_df.ao2mo(mo_b, kpt, compact=False) eri1 = with_df.ao2mo((mo_a,mo_a,mo_b,mo_b), kpt, compact=False) eri += eri1 eri += eri1.T eri = eri.reshape([nmo]*4) else: mo = mo_a + mo_b eri = with_df.ao2mo(mo, kpt, compact=False).reshape([nmo]*4) sym_forbid = (orbspin[:,None] != orbspin) eri[sym_forbid,:,:] = 0 eri[:,:,sym_forbid] = 0 return eri with lib.temporary_env(self._scf, exxdiv=None): eris = gcisd.gccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) if mo_coeff is self._scf.mo_coeff: eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()] else: madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung) return eris
def vind(xys): nz = len(xys) z1xs = [_unpack(xy[:tot_x], mo_occ) for xy in xys] z1ys = [_unpack(xy[tot_x:], mo_occ) for xy in xys] dmov = numpy.empty((nz, nkpts, nao, nao), dtype=numpy.complex128) for i in range(nz): for k in range(nkpts): # *2 for double occupancy dmx = z1xs[i][k] * 2 dmy = z1ys[i][k] * 2 dmov[i, k] = reduce(numpy.dot, (orbo[k], dmx, orbv[k].T.conj())) dmov[i, k] += reduce(numpy.dot, (orbv[k], dmy.T, orbo[k].T.conj())) with lib.temporary_env(mf, exxdiv=None): v1ao = vresp(dmov) v1s = [] for i in range(nz): dmx = z1xs[i] dmy = z1ys[i] v1xs = [] v1ys = [] for k in range(nkpts): v1x = reduce(numpy.dot, (orbo[k].T.conj(), v1ao[i, k], orbv[k])) v1y = reduce(numpy.dot, (orbv[k].T.conj(), v1ao[i, k], orbo[k])).T v1x += e_ia[k] * dmx[k] v1y += e_ia[k] * dmy[k] v1xs.append(v1x.ravel()) v1ys.append(-v1y.ravel()) v1s += v1xs + v1ys return lib.asarray(v1s).reshape(nz, -1)
def vind(zs): nz = len(zs) zs = [_unpack(z, mo_occ) for z in zs] dmov = numpy.empty((2,nz,nkpts,nao,nao), dtype=numpy.complex128) for i in range(nz): dm1a, dm1b = zs[i] for k in range(nkpts): dmov[0,i,k] = reduce(numpy.dot, (orboa[k], dm1a[k], orbva[k].conj().T)) dmov[1,i,k] = reduce(numpy.dot, (orbob[k], dm1b[k], orbvb[k].conj().T)) with lib.temporary_env(mf, exxdiv=None): dmov = dmov.reshape(2*nz,nkpts,nao,nao) v1ao = vresp(dmov) v1ao = v1ao.reshape(2,nz,nkpts,nao,nao) v1s = [] for i in range(nz): dm1a, dm1b = zs[i] v1as = [] v1bs = [] for k in range(nkpts): v1a = reduce(numpy.dot, (orboa[k].conj().T, v1ao[0,i,k], orbva[k])) v1b = reduce(numpy.dot, (orbob[k].conj().T, v1ao[1,i,k], orbvb[k])) v1a += e_ia_a[k] * dm1a[k] v1b += e_ia_b[k] * dm1b[k] v1as.append(v1a.ravel()) v1bs.append(v1b.ravel()) v1s += v1as + v1bs return numpy.hstack(v1s).reshape(nz,-1)
def _get_k_lr(mol, dm, omega=0, hermi=0, vhfopt=None): import sys sys.stderr.write('This function is deprecated. ' 'It is replaced by mol.get_k(mol, dm, omege=omega)') dm = numpy.asarray(dm) # Note, ks object caches the ERIs for small systems. The cached eris are # computed with regular Coulomb operator. ks.get_jk or ks.get_k do not evalute # the K matrix with the range separated Coulomb operator. Here jk.get_jk # function computes the K matrix with the modified Coulomb operator. nao = dm.shape[-1] dms = dm.reshape(-1, nao, nao) with mol.with_range_coulomb(omega): # Compute the long range part of ERIs temporarily with omega. Restore # the original omega when the block ends if vhfopt is None: contents = lambda: None # just a place_holder else: contents = vhfopt._this.contents with lib.temporary_env( contents, fprescreen=_vhf._fpointer('CVHFnrs8_vk_prescreen')): intor = mol._add_suffix('int2e') vklr = jk.get_jk(mol, dms, ['ijkl,jk->il'] * len(dms), intor=intor, vhfopt=vhfopt) return numpy.asarray(vklr).reshape(dm.shape)
def test_tdhf_with_wfnsym(self): pmol = mol.copy() pmol.symmetry = True pmol.build() mf = scf.UHF(pmol).run() td = tdscf.uhf.TDHF(mf) td.wfnsym = 'B1' td.nroots = 3 es = td.kernel()[0] self.assertAlmostEqual(lib.finger(es), 0.11306948533259675, 6) note_args = [] def temp_logger_note(rec, msg, *args): note_args.append(args) with lib.temporary_env(lib.logger.Logger, note=temp_logger_note): td.analyze() ref = [(), (1, 'B1', 2.0573933276026657, 602.6275864706528, 0.1605980714821934), (2, 'B1', 14.851066559488304, 83.4850460381169, 0.001928664835262468), (3, 'B1', 16.832235179166293, 73.65878400799706, 0.17021505486468672)] self.assertEqual(note_args[1][1], 'B1') self.assertEqual(note_args[2][1], 'B1') self.assertEqual(note_args[3][1], 'B1') self.assertAlmostEqual(abs(numpy.hstack((ref[1][2:], ref[2][2:], ref[3][2:])) - numpy.hstack((note_args[1][2:], note_args[2][2:], note_args[3][2:]))).max(), 0, 7)
def test_analyze(self): f = td_hf.oscillator_strength(gauge='length') self.assertAlmostEqual(lib.fp(f), -0.13908774016795605, 7) f = td_hf.oscillator_strength(gauge='velocity', order=2) self.assertAlmostEqual(lib.fp(f), -0.096991134490587522, 7) note_args = [] def temp_logger_note(rec, msg, *args): note_args.append(args) with lib.temporary_env(lib.logger.Logger, note=temp_logger_note): td_hf.analyze() ref = [ (), (1, 11.834865910142547, 104.76181013351982, 0.01075359074556743), (2, 11.834865910142618, 104.76181013351919, 0.010753590745567499), (3, 16.66308427853695, 74.40651170629978, 0.3740302871966713) ] self.assertAlmostEqual( abs(numpy.hstack(ref) - numpy.hstack(note_args)).max(), 0, 7) self.assertEqual(td_hf.nroots, td_hf.nstates) self.assertAlmostEqual(lib.fp(td_hf.e_tot - mf.e_tot), 0.41508325757603637, 6)
def test_quasi_c2v(self): atoms = [ ['Fe', ( 0.0000000000, 0.0055197721, 0.0055197721)], ['O' , (-1.3265475500, 0.0000000000, -0.9445024777)], ['O' , ( 1.3265475500, 0.0000000000, -0.9445024777)], ['O' , ( 0.0000000000, -1.3265374484, 0.9444796669)], ['O' , ( 0.0000000000, 1.3265374484, 0.9444796669)],] l, orig, axes = geom.detect_symm(atoms) self.assertEqual(l, 'Cs') with lib.temporary_env(geom, TOLERANCE=1e-2): l, orig, axes = geom.detect_symm(atoms) self.assertEqual(l, 'C2v') with lib.temporary_env(geom, TOLERANCE=1e-1): l, orig, axes = geom.detect_symm(atoms) self.assertEqual(l, 'Td')
def contract_2e(c): if wfnsym is None: hc = mc.fcisolver.contract_2e(h2eff, c, ncas, nelecas) else: with lib.temporary_env(mc.fcisolver, wfnsym=wfnsym): hc = mc.fcisolver.contract_2e(h2eff, c, ncas, nelecas) return hc.ravel()
def ao2mo(self, mo_coeff=None): from pyscf.pbc import tools with_df = self._scf.with_df kpt = self._scf.kpt def ao2mofn(mo_coeff): nao, nmo = mo_coeff.shape mo_a = mo_coeff[:nao//2] mo_b = mo_coeff[nao//2:] orbspin = getattr(mo_coeff, 'orbspin', None) if orbspin is None: eri = with_df.ao2mo(mo_a, kpt, compact=False) eri += with_df.ao2mo(mo_b, kpt, compact=False) eri1 = with_df.ao2mo((mo_a,mo_a,mo_b,mo_b), kpt, compact=False) eri += eri1 eri += eri1.T eri = eri.reshape([nmo]*4) else: mo = mo_a + mo_b eri = with_df.ao2mo(mo, kpt, compact=False).reshape([nmo]*4) sym_forbid = (orbspin[:,None] != orbspin) eri[sym_forbid,:,:] = 0 eri[:,:,sym_forbid] = 0 return eri # _scf.exxdiv affects eris.fock. HF exchange correction should be # excluded from the Fock matrix. with lib.temporary_env(self._scf, exxdiv=None): eris = gccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) #if mo_coeff is self._scf.mo_coeff: # eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()] #else: madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung) return eris
def mc1step_gen_g_hop(mc, mo, u, casdm1, casdm2, eris): ''' Wrapper to mc1step.gen_g_hop for minimizing the PDFT energy instead of the CASSCF energy by varying orbitals ''' ncore, ncas, nelecas = mc.ncore, mc.ncas, mc.nelecas nocc = ncore + ncas nao, nmo = mo.shape casdm1s = casdm1 * 0.5 casdm1s = np.stack([casdm1s, casdm1s], axis=0) veff1, veff2 = mc.get_pdft_veff(mo=mo, casdm1s=casdm1s, casdm2=casdm2, incl_coul=True) veff2.eot_h_op = EotOrbitalHessianOperator(mc, mo_coeff=mo, casdm1=casdm1, casdm2=casdm2, do_cumulant=True) def get_hcore(mol=None): return mc._scf.get_hcore(mol) + veff1 with lib.temporary_env(mc, get_hcore=get_hcore): g_orb, _, h_op, h_diag = mc1step.gen_g_hop(mc, mo, u, casdm1, casdm2, veff2) gorb_update = get_gorb_update(mc, mo) return g_orb, gorb_update, h_op, h_diag
def kernel(self, h1e, eri, norb, nelec, ci0=None, tol=None, lindep=None, max_cycle=None, max_space=None, nroots=None, davidson_only=None, pspace_size=None, orbsym=None, wfnsym=None, ecore=0, **kwargs): if nroots is None: nroots = self.nroots if orbsym is None: orbsym = self.orbsym if wfnsym is None: wfnsym = self.wfnsym if self.verbose >= logger.WARN: self.check_sanity() with lib.temporary_env(self, orbsym=orbsym, wfnsym=wfnsym): e, c = selected_ci.kernel_float_space(self, h1e, eri, norb, nelec, ci0, tol, lindep, max_cycle, max_space, nroots, davidson_only, ecore=ecore, **kwargs) if wfnsym is not None: wfnsym0 = self.guess_wfnsym(norb, nelec, ci0, orbsym, wfnsym, **kwargs) strsa, strsb = c._strs if nroots > 1: for i, ci in enumerate(c): ci = addons._symmetrize_wfn(ci, strsa, strsb, self.orbsym, wfnsym0) c[i] = selected_ci._as_SCIvector(ci, c._strs) else: ci = addons._symmetrize_wfn(c, strsa, strsb, self.orbsym, wfnsym0) c = selected_ci._as_SCIvector(ci, c._strs) self.eci, self.ci = e, c return e, c
def test_nr_rks(self): cell = pbcgto.Cell() cell.verbose = 5 cell.output = '/dev/null' cell.a = np.eye(3) * 2.5 cell.mesh = [21] * 3 cell.atom = [ ['He', (1., .8, 1.9)], ['He', (.1, .2, .3)], ] cell.basis = 'ccpvdz' cell.build(False, False) grids = gen_grid.UniformGrids(cell) grids.build() nao = cell.nao_nr() np.random.seed(1) kpts = np.random.random((2, 3)) dms = np.random.random((2, nao, nao)) dms = (dms + dms.transpose(0, 2, 1)) * .5 ni = numint.NumInt() with lib.temporary_env(pbcgto.eval_gto, EXTRA_PREC=1e-5): ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', dms[0], 1, kpts[0]) self.assertAlmostEqual(ne, 5.0499199224525153, 8) self.assertAlmostEqual(exc, -3.8870579114663886, 8) self.assertAlmostEqual(lib.fp(vmat), 0.42538491159934377 + 0.14139753327162483j, 8) ni = numint.KNumInt() with lib.temporary_env(pbcgto.eval_gto, EXTRA_PREC=1e-5): ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', dms, 1, kpts) self.assertAlmostEqual(ne, 6.0923292346269742, 8) self.assertAlmostEqual(exc, -3.9899423803106466, 8) self.assertAlmostEqual(lib.fp(vmat[0]), -2348.9577179701278 - 60.733087913116719j, 7) self.assertAlmostEqual(lib.fp(vmat[1]), -2353.0350086740673 - 117.74811536967495j, 7) with lib.temporary_env(pbcgto.eval_gto, EXTRA_PREC=1e-5): ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', [dms, dms], 1, kpts) self.assertAlmostEqual(ne[1], 6.0923292346269742, 8) self.assertAlmostEqual(exc[1], -3.9899423803106466, 8) self.assertAlmostEqual(lib.fp(vmat[1][0]), -2348.9577179701278 - 60.733087913116719j, 7) self.assertAlmostEqual(lib.fp(vmat[1][1]), -2353.0350086740673 - 117.74811536967495j, 7)
def jk_ints(molA, molB, dm_ia, dm_jb): from pyscf.scf import jk, _vhf naoA = molA.nao naoB = molB.nao assert (dm_ia.shape == (naoA, naoA)) assert (dm_jb.shape == (naoB, naoB)) molAB = molA + molB vhfopt = _vhf.VHFOpt(molAB, 'int2e', 'CVHFnrs8_prescreen', 'CVHFsetnr_direct_scf', 'CVHFsetnr_direct_scf_dm') dmAB = scipy.linalg.block_diag(dm_ia, dm_jb) # The prescreen function CVHFnrs8_prescreen indexes q_cond and dm_cond # over the entire basis. "set_dm" in function jk.get_jk/direct_bindm only # creates a subblock of dm_cond which is not compatible with # CVHFnrs8_prescreen. vhfopt.set_dm(dmAB, molAB._atm, molAB._bas, molAB._env) # Then skip the "set_dm" initialization in function jk.get_jk/direct_bindm. vhfopt._dmcondname = None with lib.temporary_env(vhfopt._this.contents, fprescreen=_vhf._fpointer('CVHFnrs8_vj_prescreen')): shls_slice = (0, molA.nbas, 0, molA.nbas, molA.nbas, molAB.nbas, molA.nbas, molAB.nbas) # AABB vJ = jk.get_jk(molAB, dm_jb, 'ijkl,lk->s2ij', shls_slice=shls_slice, vhfopt=vhfopt, aosym='s4', hermi=1) cJ = np.einsum('ia,ia->', vJ, dm_ia) with lib.temporary_env(vhfopt._this.contents, fprescreen=_vhf._fpointer('CVHFnrs8_vk_prescreen')): shls_slice = (0, molA.nbas, molA.nbas, molAB.nbas, molA.nbas, molAB.nbas, 0, molA.nbas) # ABBA vK = jk.get_jk(molAB, dm_jb, 'ijkl,jk->il', shls_slice=shls_slice, vhfopt=vhfopt, aosym='s1', hermi=0) cK = np.einsum('ia,ia->', vK, dm_ia) return cJ, cK
def grad_elec(self, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None): with lib.temporary_env(self, mol=self.base._mindo_mol): return uhf_grad.grad_elec(self, mo_energy, mo_coeff, mo_occ, atmlst) * lib.param.BOHR
def __call__(self, x): ''' return dg, de; always packed ''' def no_j (*args, **kwargs): return 0 def no_jk (*args, **kwargs): return 0, 0 with lib.temporary_env (self.ks, get_j=no_j, get_jk=no_jk): dg = self.h_op (x) de = 2*np.dot (self.g_orb.ravel (), x.ravel ()) return dg, de
def test_2d(self): kpts = numpy.random.random((4,3)) * .25 kpts[3] = -numpy.einsum('ij->j', kpts[:3]) with_df = df.DF(cell).set(auxbasis='weigend') with_df.linear_dep_threshold = 1e-7 with_df.kpts = kpts mo =(numpy.random.random((nao,nao)) + numpy.random.random((nao,nao))*1j) with lib.temporary_env(cell, dimension = 2): eri = with_df.get_eri(kpts).reshape((nao,)*4) eri0 = numpy.einsum('pjkl,pi->ijkl', eri , mo.conj()) eri0 = numpy.einsum('ipkl,pj->ijkl', eri0, mo ) eri0 = numpy.einsum('ijpl,pk->ijkl', eri0, mo.conj()) eri0 = numpy.einsum('ijkp,pl->ijkl', eri0, mo ) with lib.temporary_env(cell, dimension = 2): eri1 = with_df.ao2mo(mo, kpts) self.assertAlmostEqual(abs(eri1.reshape(eri0.shape)-eri0).sum(), 0, 9)
def mo_comps(aolabels_or_baslst, mol, mo_coeff, cart=False, orth_method=ORTH_METHOD): '''Given AO(s), show how the AO(s) are distributed in MOs. Args: aolabels_or_baslst : filter function or AO labels or AO index If it's a function, the AO indices are the items for which the function return value is true. Kwargs: cart : bool whether the orbital coefficients are based on cartesian basis. orth_method : str The localization method to generated orthogonal AO upon which the AO contribution are computed. It can be one of 'meta_lowdin', 'lowdin' or 'nao'. Returns: A list of float to indicate the total contributions (normalized to 1) of localized AOs Examples: >>> from pyscf import gto, scf >>> from pyscf.tools import mo_mapping >>> mol = gto.M(atom='H 0 0 0; F 0 0 1', basis='6-31g') >>> mf = scf.RHF(mol).run() >>> comp = mo_mapping.mo_comps('F 2s', mol, mf.mo_coeff) >>> print('MO-id F-2s components') >>> for i,c in enumerate(comp): ... print('%-3d %.10f' % (i, c)) MO-id components 0 0.0000066344 1 0.8796915532 2 0.0590259826 3 0.0000000000 4 0.0000000000 5 0.0435028851 6 0.0155889103 7 0.0000000000 8 0.0000000000 9 0.0000822361 10 0.0021017982 ''' with lib.temporary_env(mol, cart=cart): assert (mo_coeff.shape[0] == mol.nao) s = mol.intor_symmetric('int1e_ovlp') lao = lo.orth.orth_ao(mol, orth_method, s=s) idx = gto.mole._aolabels2baslst(mol, aolabels_or_baslst) if len(idx) == 0: logger.warn(mol, 'Required orbitals are not found') mo1 = reduce(numpy.dot, (lao[:, idx].T, s, mo_coeff)) s1 = numpy.einsum('ki,ki->i', mo1, mo1) return s1
def test_dipole_moment(self): dip = mf.dip_moment() self.assertAlmostEqual(lib.finger(dip), 0.03847620192010277, 9) # For test cover only. Results for low-dimesion system are not # implemented. with lib.temporary_env(cell, dimension=1): kdm = kmf.get_init_guess(key='minao') dip = kmf.dip_moment(cell, kdm)
def test_dhf_nr_limit(self): mol = gto.M(atom=''' H .8 0. 0. H 0. .5 0.''', basis='ccpvdz') with lib.temporary_env(lib.param, LIGHT_SPEED=5000): r = scf.DHF(mol).run().EFG() nr = scf.RHF(mol).run().EFG() self.assertAlmostEqual(abs(r - nr).max(), 0, 7)
def test_dipole_moment(self): dip = mf.dip_moment() self.assertAlmostEqual(lib.finger(dip), 0.03847620192010277, 8) # For test cover only. Results for low-dimesion system are not # implemented. with lib.temporary_env(cell, dimension=1): kdm = kmf.get_init_guess(key='minao') dip = kmf.dip_moment(cell, kdm)
def test_init_guess_by_atom(self): with lib.temporary_env(cell, dimension=1): dm = mf.get_init_guess(key='minao') kdm = kmf.get_init_guess(key='minao') self.assertAlmostEqual(lib.finger(dm), -1.714952331211208, 8) self.assertEqual(kdm.ndim, 3) self.assertAlmostEqual(lib.finger(dm), -1.714952331211208, 8)
def states_gen_linkstr(self, norb, nelec, tril=True): linkstr = [] for solver in self.fcisolvers: with temporary_env(solver, orbsym=self.orbsym): linkstr.append( solver.gen_linkstr( norb, self._get_nelec(solver, nelec), tril=tril ) if getattr(solver, 'gen_linkstr', None) else None) return linkstr
def states_make_hdiag_csf(self, h1, h2, norb, nelec): hdiag = [] for solver, my_args, _ in self._loop_solver(_state_arg(h1)): h1e = my_args[0] with temporary_env(solver, orbsym=self.orbsym): hdiag.append( solver.make_hdiag_csf(h1e, h2, norb, self._get_nelec(solver, nelec))) return hdiag
def test_2d(self): kpts = numpy.random.random((4, 3)) * .25 kpts[3] = -numpy.einsum('ij->j', kpts[:3]) with_df = rsdf.RSDF(cell).set(auxbasis='weigend') with_df.linear_dep_threshold = 1e-7 with_df.kpts = kpts mo = (numpy.random.random((nao, nao)) + numpy.random.random( (nao, nao)) * 1j) with lib.temporary_env(cell, dimension=2): eri = with_df.get_eri(kpts).reshape((nao, ) * 4) eri0 = numpy.einsum('pjkl,pi->ijkl', eri, mo.conj()) eri0 = numpy.einsum('ipkl,pj->ijkl', eri0, mo) eri0 = numpy.einsum('ijpl,pk->ijkl', eri0, mo.conj()) eri0 = numpy.einsum('ijkp,pl->ijkl', eri0, mo) with lib.temporary_env(cell, dimension=2): eri1 = with_df.ao2mo(mo, kpts) self.assertAlmostEqual( abs(eri1.reshape(eri0.shape) - eri0).sum(), 0, 9)
def kernel(self, **kwargs): mf_grad = kwargs['mf_grad'] if 'mf_grad' in kwargs else None if mf_grad is None: kwargs['mf_grad'] = dfrhf_grad.Gradients(self.base._scf) # The below only works because dfcasscf_grad is NOT a child of casscf_grad # For instance, I can't monkeypatch rhf_grad this way b/c dfrhf_grad refers to rhf_grad # Maybe it should be, in which case I will have to change this # But on the other hand maybe it can be even simpler? with lib.temporary_env(casscf_grad, Gradients=dfcasscf_grad.Gradients): return sacasscf_grad.Gradients.kernel(self, **kwargs)
def kernel(self, dm0=None, **kwargs): scf_kernel(self, dm0, **kwargs) if not self.converged: with lib.temporary_env(self, level_shift=.2): scf_kernel(self, dm0, **kwargs) if not self.converged: mf1 = self.newton().run() del mf1._scf # mf1._scf leads to circular reference to self self.__dict__.update(mf1.__dict__) return self.e_tot
def stability(self, *args, **kwargs): # When computing orbital hessian, the second order derivatives of # solvent energy needs to be computed. It is enabled by # the attribute equilibrium_solvation in gen_response method. # If solvent was frozen, its contribution is treated as the # external potential. The response of solvent does not need to # be considered in stability analysis. with lib.temporary_env(self.with_solvent, equilibrium_solvation=not self.with_solvent.frozen): return oldMF.stability(self, *args, **kwargs)
def mo_comps(aolabels_or_baslst, mol, mo_coeff, cart=False, orth_method=ORTH_METHOD): '''Given AO(s), show how the AO(s) are distributed in MOs. Args: aolabels_or_baslst : filter function or AO labels or AO index If it's a function, the AO indices are the items for which the function return value is true. Kwargs: cart : bool whether the orbital coefficients are based on cartesian basis. orth_method : str The localization method to generated orthogonal AO upon which the AO contribution are computed. It can be one of 'meta_lowdin', 'lowdin' or 'nao'. Returns: A list of float to indicate the total contributions (normalized to 1) of localized AOs Examples: >>> from pyscf import gto, scf >>> from pyscf.tools import mo_mapping >>> mol = gto.M(atom='H 0 0 0; F 0 0 1', basis='6-31g') >>> mf = scf.RHF(mol).run() >>> comp = mo_mapping.mo_comps('F 2s', mol, mf.mo_coeff) >>> print('MO-id F-2s components') >>> for i,c in enumerate(comp): ... print('%-3d %.10f' % (i, c)) MO-id components 0 0.0000066344 1 0.8796915532 2 0.0590259826 3 0.0000000000 4 0.0000000000 5 0.0435028851 6 0.0155889103 7 0.0000000000 8 0.0000000000 9 0.0000822361 10 0.0021017982 ''' with lib.temporary_env(mol, cart=cart): assert(mo_coeff.shape[0] == mol.nao) s = mol.intor_symmetric('int1e_ovlp') lao = lo.orth.orth_ao(mol, orth_method, s=s) idx = gto.mole._aolabels2baslst(mol, aolabels_or_baslst) if len(idx) == 0: logger.warn(mol, 'Required orbitals are not found') mo1 = reduce(numpy.dot, (lao[:,idx].T, s, mo_coeff)) s1 = numpy.einsum('ki,ki->i', mo1, mo1) return s1
def vind(xys): nz = len(xys) x1s = [_unpack(x[:tot_x], mo_occ) for x in xys] y1s = [_unpack(x[tot_x:], mo_occ) for x in xys] dmov = numpy.empty((2, nz, nkpts, nao, nao), dtype=numpy.complex128) for i in range(nz): xa, xb = x1s[i] ya, yb = y1s[i] for k in range(nkpts): dmx = reduce(numpy.dot, (orboa[k], xa[k], orbva[k].conj().T)) dmy = reduce(numpy.dot, (orbva[k], ya[k].T, orboa[k].conj().T)) dmov[0, i, k] = dmx + dmy # AX + BY dmx = reduce(numpy.dot, (orbob[k], xb[k], orbvb[k].conj().T)) dmy = reduce(numpy.dot, (orbvb[k], yb[k].T, orbob[k].conj().T)) dmov[1, i, k] = dmx + dmy # AX + BY with lib.temporary_env(mf, exxdiv=None): dmov = dmov.reshape(2 * nz, nkpts, nao, nao) v1ao = vresp(dmov) v1ao = v1ao.reshape(2, nz, nkpts, nao, nao) v1s = [] for i in range(nz): xa, xb = x1s[i] ya, yb = y1s[i] v1xsa = [] v1xsb = [] v1ysa = [] v1ysb = [] for k in range(nkpts): v1xa = reduce(numpy.dot, (orboa[k].conj().T, v1ao[0, i, k], orbva[k])) v1xb = reduce(numpy.dot, (orbob[k].conj().T, v1ao[1, i, k], orbvb[k])) v1ya = reduce( numpy.dot, (orbva[k].conj().T, v1ao[0, i, k], orboa[k])).T v1yb = reduce( numpy.dot, (orbvb[k].conj().T, v1ao[1, i, k], orbob[k])).T v1xa += e_ia_a[k] * xa[k] v1xb += e_ia_b[k] * xb[k] v1ya += e_ia_a[k] * ya[k] v1yb += e_ia_b[k] * yb[k] v1xsa.append(v1xa.ravel()) v1xsb.append(v1xb.ravel()) v1ysa.append(-v1ya.ravel()) v1ysb.append(-v1yb.ravel()) v1s += v1xsa + v1xsb + v1ysa + v1ysb return numpy.hstack(v1s).reshape(nz, -1)
def test_nr_rks(self): cell = pbcgto.Cell() cell.verbose = 5 cell.output = '/dev/null' cell.a = np.eye(3) * 2.5 cell.mesh = [21]*3 cell.atom = [['He', (1., .8, 1.9)], ['He', (.1, .2, .3)],] cell.basis = 'ccpvdz' cell.build(False, False) grids = gen_grid.UniformGrids(cell) grids.build() nao = cell.nao_nr() np.random.seed(1) kpts = np.random.random((2,3)) dms = np.random.random((2,nao,nao)) dms = (dms + dms.transpose(0,2,1)) * .5 ni = numint.NumInt() with lib.temporary_env(pbcgto.eval_gto, EXTRA_PREC=1e-5): ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', dms[0], 0, kpts[0]) self.assertAlmostEqual(ne, 5.0499199224525153, 8) self.assertAlmostEqual(exc, -3.8870579114663886, 8) self.assertAlmostEqual(finger(vmat), 0.42538491159934377+0.14139753327162483j, 8) ni = numint.KNumInt() with lib.temporary_env(pbcgto.eval_gto, EXTRA_PREC=1e-5): ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', dms, 0, kpts) self.assertAlmostEqual(ne, 6.0923292346269742, 8) self.assertAlmostEqual(exc, -3.9899423803106466, 8) self.assertAlmostEqual(finger(vmat[0]), -2348.9577179701278-60.733087913116719j, 7) self.assertAlmostEqual(finger(vmat[1]), -2353.0350086740673-117.74811536967495j, 7) with lib.temporary_env(pbcgto.eval_gto, EXTRA_PREC=1e-5): ne, exc, vmat = ni.nr_rks(cell, grids, 'blyp', [dms,dms], 0, kpts) self.assertAlmostEqual(ne[1], 6.0923292346269742, 8) self.assertAlmostEqual(exc[1], -3.9899423803106466, 8) self.assertAlmostEqual(finger(vmat[1][0]), -2348.9577179701278-60.733087913116719j, 7) self.assertAlmostEqual(finger(vmat[1][1]), -2353.0350086740673-117.74811536967495j, 7)
def ao2mo(self, mo_coeff=None): from pyscf.cc import rccsd from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ ao2mofn = mp.mp2._gen_ao2mofn(self._scf) with lib.temporary_env(self._scf, exxdiv=None): eris = rccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) if mo_coeff is self._scf.mo_coeff: eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()] else: madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung) return eris
def test_c3v_1(self): mol = gto.M(atom=''' C 0.948065 -0.081406 -0.007893 C 0.462608 -0.144439 1.364854 N 0.077738 -0.194439 2.453356 H 0.591046 0.830035 -0.495369 H 0.591062 -0.944369 -0.576807 H 2.041481 -0.080642 -0.024174''') gpname, orig, axes = geom.detect_symm(mol._atom) self.assertEqual(gpname, 'C1') with lib.temporary_env(geom, TOLERANCE=1e-3): gpname, orig, axes = geom.detect_symm(mol._atom) self.assertEqual(gpname, 'C3v')
def ao2mo(self, mo_coeff=None): from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ ao2mofn = mp.mp2._gen_ao2mofn(self._scf) with lib.temporary_env(self._scf, exxdiv=None): eris = ucisd.uccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) if mo_coeff is self._scf.mo_coeff: idxa, idxb = self.get_frozen_mask() mo_e_a, mo_e_b = self._scf.mo_energy eris.mo_energy = (mo_e_a[idxa], mo_e_b[idxb]) else: nocca, noccb = eris.nocc madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = (_adjust_occ(eris.mo_energy[0], nocca, -madelung), _adjust_occ(eris.mo_energy[1], noccb, -madelung)) return eris
def ao2mo(self, mo_coeff=None): from pyscf.pbc import tools ao2mofn = mp.mp2._gen_ao2mofn(self._scf) # _scf.exxdiv affects eris.fock. HF exchange correction should be # excluded from the Fock matrix. with lib.temporary_env(self._scf, exxdiv=None): eris = uccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) #if mo_coeff is self._scf.mo_coeff: # idxa, idxb = self.get_frozen_mask() # mo_e_a, mo_e_b = self._scf.mo_energy # eris.mo_energy = (mo_e_a[idxa], mo_e_b[idxb]) #else: nocca, noccb = eris.nocc madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = (_adjust_occ(eris.mo_energy[0], nocca, -madelung), _adjust_occ(eris.mo_energy[1], noccb, -madelung)) return eris
def vind(xys): nz = len(xys) x1s = [_unpack(x[:tot_x], mo_occ) for x in xys] y1s = [_unpack(x[tot_x:], mo_occ) for x in xys] dmov = numpy.empty((2,nz,nkpts,nao,nao), dtype=numpy.complex128) for i in range(nz): xa, xb = x1s[i] ya, yb = y1s[i] for k in range(nkpts): dmx = reduce(numpy.dot, (orboa[k], xa[k] , orbva[k].conj().T)) dmy = reduce(numpy.dot, (orbva[k], ya[k].T, orboa[k].conj().T)) dmov[0,i,k] = dmx + dmy # AX + BY dmx = reduce(numpy.dot, (orbob[k], xb[k] , orbvb[k].conj().T)) dmy = reduce(numpy.dot, (orbvb[k], yb[k].T, orbob[k].conj().T)) dmov[1,i,k] = dmx + dmy # AX + BY with lib.temporary_env(mf, exxdiv=None): dmov = dmov.reshape(2*nz,nkpts,nao,nao) v1ao = vresp(dmov) v1ao = v1ao.reshape(2,nz,nkpts,nao,nao) v1s = [] for i in range(nz): xa, xb = x1s[i] ya, yb = y1s[i] v1xsa = [] v1xsb = [] v1ysa = [] v1ysb = [] for k in range(nkpts): v1xa = reduce(numpy.dot, (orboa[k].conj().T, v1ao[0,i,k], orbva[k])) v1xb = reduce(numpy.dot, (orbob[k].conj().T, v1ao[1,i,k], orbvb[k])) v1ya = reduce(numpy.dot, (orbva[k].conj().T, v1ao[0,i,k], orboa[k])).T v1yb = reduce(numpy.dot, (orbvb[k].conj().T, v1ao[1,i,k], orbob[k])).T v1xa+= e_ia_a[k] * xa[k] v1xb+= e_ia_b[k] * xb[k] v1ya+= e_ia_a[k] * ya[k] v1yb+= e_ia_b[k] * yb[k] v1xsa.append(v1xa.ravel()) v1xsb.append(v1xb.ravel()) v1ysa.append(-v1ya.ravel()) v1ysb.append(-v1yb.ravel()) v1s += v1xsa + v1xsb + v1ysa + v1ysb return numpy.hstack(v1s).reshape(nz,-1)
def kernel(self, h1e, eri, norb, nelec, ci0=None, tol=None, lindep=None, max_cycle=None, max_space=None, nroots=None, davidson_only=None, pspace_size=None, orbsym=None, wfnsym=None, ecore=0, **kwargs): if nroots is None: nroots = self.nroots if orbsym is None: orbsym = self.orbsym if wfnsym is None: wfnsym = self.wfnsym if self.verbose >= logger.WARN: self.check_sanity() self.norb = norb self.nelec = nelec wfnsym = self.guess_wfnsym(norb, nelec, ci0, orbsym, wfnsym, **kwargs) with lib.temporary_env(self, orbsym=orbsym, wfnsym=wfnsym): e, c = direct_spin1.kernel_ms1(self, h1e, eri, norb, nelec, ci0, None, tol, lindep, max_cycle, max_space, nroots, davidson_only, pspace_size, ecore=ecore, **kwargs) self.eci, self.ci = e, c return e, c
def ao2mo(self, mo_coeff=None): from pyscf.pbc import tools ao2mofn = mp.mp2._gen_ao2mofn(self._scf) # _scf.exxdiv affects eris.fock. HF exchange correction should be # excluded from the Fock matrix. with lib.temporary_env(self._scf, exxdiv=None): eris = rccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) # eris.mo_energy so far is just the diagonal part of the Fock matrix # without the exxdiv treatment. Here to add the exchange correction to # get better orbital energies. It is important for the low-dimension # systems since their occupied and the virtual orbital energies may # overlap which may lead to numerical issue in the CCSD iterations. #if mo_coeff is self._scf.mo_coeff: # eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()] #else: # # Add the HFX correction of Ewald probe charge method. # # FIXME: Whether to add this correction for other exxdiv treatments? # # Without the correction, MP2 energy may be largely off the # # correct value. madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung) return eris
def test_detect_symm_d3d(self): atoms = [ ['C', ( 1.25740, -0.72596, -0.25666)], ['C', ( 1.25740, 0.72596, 0.25666)], ['C', ( 0.00000, 1.45192, -0.25666)], ['C', (-1.25740, 0.72596, 0.25666)], ['C', (-1.25740, -0.72596, -0.25666)], ['C', ( 0.00000, -1.45192, 0.25666)], ['H', ( 2.04168, -1.17876, 0.05942)], ['H', ( 1.24249, -0.71735, -1.20798)], ['H', ( 2.04168, 1.17876, -0.05942)], ['H', ( 1.24249, 0.71735, 1.20798)], ['H', ( 0.00000, 1.43470, -1.20798)], ['H', ( 0.00000, 2.35753, 0.05942)], ['H', (-2.04168, 1.17876, -0.05942)], ['H', (-1.24249, 0.71735, 1.20798)], ['H', (-1.24249, -0.71735, -1.20798)], ['H', (-2.04168, -1.17876, 0.05942)], ['H', ( 0.00000, -1.43470, 1.20798)], ['H', ( 0.00000, -2.35753, -0.05942)], ] with lib.temporary_env(geom, TOLERANCE=1e-4): l, orig, axes = geom.detect_symm(atoms) self.assertEqual(l, 'D3d')
def get_nuc(mydf, kpts=None): # Pseudopotential is ignored when computing just the nuclear attraction with lib.temporary_env(mydf.cell, _pseudo={}): return get_pp_loc_part1(mydf, kpts)
def _make_eris_incore(cc, mo_coeff=None): from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ log = logger.Logger(cc.stdout, cc.verbose) cput0 = (time.clock(), time.time()) eris = gccsd._PhysicistsERIs() cell = cc._scf.cell kpts = cc.kpts nkpts = cc.nkpts nocc = cc.nocc nmo = cc.nmo nvir = nmo - nocc eris.nocc = nocc #if any(nocc != numpy.count_nonzero(cc._scf.mo_occ[k] > 0) for k in range(nkpts)): # raise NotImplementedError('Different occupancies found for different k-points') if mo_coeff is None: mo_coeff = cc.mo_coeff nao = mo_coeff[0].shape[0] dtype = mo_coeff[0].dtype moidx = get_frozen_mask(cc) nocc_per_kpt = numpy.asarray(get_nocc(cc, per_kpoint=True)) nmo_per_kpt = numpy.asarray(get_nmo(cc, per_kpoint=True)) padded_moidx = [] for k in range(nkpts): kpt_nocc = nocc_per_kpt[k] kpt_nvir = nmo_per_kpt[k] - kpt_nocc kpt_padded_moidx = numpy.concatenate((numpy.ones(kpt_nocc, dtype=numpy.bool), numpy.zeros(nmo - kpt_nocc - kpt_nvir, dtype=numpy.bool), numpy.ones(kpt_nvir, dtype=numpy.bool))) padded_moidx.append(kpt_padded_moidx) eris.mo_coeff = [] eris.orbspin = [] # Generate the molecular orbital coefficients with the frozen orbitals masked. # Each MO is tagged with orbspin, a list of 0's and 1's that give the overall # spin of each MO. # # Here we will work with two index arrays; one is for our original (small) moidx # array while the next is for our new (large) padded array. for k in range(nkpts): kpt_moidx = moidx[k] kpt_padded_moidx = padded_moidx[k] mo = numpy.zeros((nao, nmo), dtype=dtype) mo[:, kpt_padded_moidx] = mo_coeff[k][:, kpt_moidx] if getattr(mo_coeff[k], 'orbspin', None) is not None: orbspin_dtype = mo_coeff[k].orbspin[kpt_moidx].dtype orbspin = numpy.zeros(nmo, dtype=orbspin_dtype) orbspin[kpt_padded_moidx] = mo_coeff[k].orbspin[kpt_moidx] mo = lib.tag_array(mo, orbspin=orbspin) eris.orbspin.append(orbspin) # FIXME: What if the user freezes all up spin orbitals in # an RHF calculation? The number of electrons will still be # even. else: # guess orbital spin - assumes an RHF calculation assert (numpy.count_nonzero(kpt_moidx) % 2 == 0) orbspin = numpy.zeros(mo.shape[1], dtype=int) orbspin[1::2] = 1 mo = lib.tag_array(mo, orbspin=orbspin) eris.orbspin.append(orbspin) eris.mo_coeff.append(mo) # Re-make our fock MO matrix elements from density and fock AO dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ) with lib.temporary_env(cc._scf, exxdiv=None): # _scf.exxdiv affects eris.fock. HF exchange correction should be # excluded from the Fock matrix. fockao = cc._scf.get_hcore() + cc._scf.get_veff(cell, dm) eris.fock = numpy.asarray([reduce(numpy.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(eris.mo_coeff)]) eris.mo_energy = [eris.fock[k].diagonal().real for k in range(nkpts)] # Add HFX correction in the eris.mo_energy to improve convergence in # CCSD iteration. It is useful for the 2D systems since their occupied and # the virtual orbital energies may overlap which may lead to numerical # issue in the CCSD iterations. # FIXME: Whether to add this correction for other exxdiv treatments? # Without the correction, MP2 energy may be largely off the correct value. madelung = tools.madelung(cell, kpts) eris.mo_energy = [_adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(eris.mo_energy)] # Get location of padded elements in occupied and virtual space. nocc_per_kpt = get_nocc(cc, per_kpoint=True) nonzero_padding = padding_k_idx(cc, kind="joint") # Check direct and indirect gaps for possible issues with CCSD convergence. mo_e = [eris.mo_energy[kp][nonzero_padding[kp]] for kp in range(nkpts)] mo_e = numpy.sort([y for x in mo_e for y in x]) # Sort de-nested array gap = mo_e[numpy.sum(nocc_per_kpt)] - mo_e[numpy.sum(nocc_per_kpt)-1] if gap < 1e-5: logger.warn(cc, 'H**O-LUMO gap %s too small for KCCSD. ' 'May cause issues in convergence.', gap) kconserv = kpts_helper.get_kconserv(cell, kpts) if getattr(mo_coeff[0], 'orbspin', None) is None: # The bottom nao//2 coefficients are down (up) spin while the top are up (down). mo_a_coeff = [mo[:nao // 2] for mo in eris.mo_coeff] mo_b_coeff = [mo[nao // 2:] for mo in eris.mo_coeff] eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo), dtype=numpy.complex128) fao2mo = cc._scf.with_df.ao2mo for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kq, kr] eri_kpt = fao2mo( (mo_a_coeff[kp], mo_a_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo( (mo_b_coeff[kp], mo_b_coeff[kq], mo_b_coeff[kr], mo_b_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo( (mo_a_coeff[kp], mo_a_coeff[kq], mo_b_coeff[kr], mo_b_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo( (mo_b_coeff[kp], mo_b_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo) eri[kp, kq, kr] = eri_kpt else: mo_a_coeff = [mo[:nao // 2] + mo[nao // 2:] for mo in eris.mo_coeff] eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo), dtype=numpy.complex128) fao2mo = cc._scf.with_df.ao2mo for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kq, kr] eri_kpt = fao2mo( (mo_a_coeff[kp], mo_a_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt[(eris.orbspin[kp][:, None] != eris.orbspin[kq]).ravel()] = 0 eri_kpt[:, (eris.orbspin[kr][:, None] != eris.orbspin[ks]).ravel()] = 0 eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo) eri[kp, kq, kr] = eri_kpt # Check some antisymmetrized properties of the integrals if DEBUG: check_antisymm_3412(cc, cc.kpts, eri) # Antisymmetrizing (pq|rs)-(ps|rq), where the latter integral is equal to # (rq|ps); done since we aren't tracking the kpoint of orbital 's' eri = eri - eri.transpose(2, 1, 0, 5, 4, 3, 6) # Chemist -> physics notation eri = eri.transpose(0, 2, 1, 3, 5, 4, 6) # Set the various integrals eris.dtype = eri.dtype eris.oooo = eri[:, :, :, :nocc, :nocc, :nocc, :nocc].copy() / nkpts eris.ooov = eri[:, :, :, :nocc, :nocc, :nocc, nocc:].copy() / nkpts eris.ovoo = eri[:, :, :, :nocc, nocc:, :nocc, :nocc].copy() / nkpts eris.oovv = eri[:, :, :, :nocc, :nocc, nocc:, nocc:].copy() / nkpts eris.ovov = eri[:, :, :, :nocc, nocc:, :nocc, nocc:].copy() / nkpts eris.ovvv = eri[:, :, :, :nocc, nocc:, nocc:, nocc:].copy() / nkpts eris.vvvv = eri[:, :, :, nocc:, nocc:, nocc:, nocc:].copy() / nkpts log.timer('CCSD integral transformation', *cput0) return eris
def dryrun(mc, mo_coeff=None): '''Generate FCIDUMP and SHCI config file''' if mo_coeff is None: mo_coeff = mc.mo_coeff with lib.temporary_env(mc.fcisolver, dryrun=True): mc.casci(mo_coeff)
def vindp(x): with lib.temporary_env(mf, exxdiv=None): return vind(x)
def kernel(self, mo_coeff=None, ci0=None, verbose=None): with_solvent = self.with_solvent log = logger.new_logger(self) log.info('\n** Self-consistently update the solvent effects for %s **', oldCAS) log1 = copy.copy(log) log1.verbose -= 1 # Suppress a few output messages def casci_iter_(ci0, log): # self.e_tot, self.e_cas, and self.ci are updated in the call # to oldCAS.kernel e_tot, e_cas, ci0 = oldCAS.kernel(self, mo_coeff, ci0, log)[:3] if isinstance(self.e_cas, (float, numpy.number)): dm = self.make_rdm1(ci=ci0) else: log.debug('Computing solvent responses to DM of state %d', with_solvent.state_id) dm = self.make_rdm1(ci=ci0[with_solvent.state_id]) if with_solvent.epcm is not None: edup = numpy.einsum('ij,ji->', with_solvent.vpcm, dm) self.e_tot += with_solvent.epcm - edup if not with_solvent.frozen: with_solvent.epcm, with_solvent.vpcm = with_solvent.kernel(dm) log.debug(' E_diel = %.15g', with_solvent.epcm) return self.e_tot, e_cas, ci0 if with_solvent.frozen: with lib.temporary_env(self, _finalize=lambda:None): casci_iter_(ci0, log) log.note('Total energy with solvent effects') self._finalize() return self.e_tot, self.e_cas, self.ci, self.mo_coeff, self.mo_energy self.converged = False with lib.temporary_env(self, canonicalization=False): e_tot = e_last = 0 for cycle in range(self.with_solvent.max_cycle): log.info('\n** Solvent self-consistent cycle %d:', cycle) e_tot, e_cas, ci0 = casci_iter_(ci0, log1) de = e_tot - e_last if isinstance(e_cas, (float, numpy.number)): log.info('Sovlent cycle %d E(CASCI+solvent) = %.15g ' 'dE = %g', cycle, e_tot, de) else: for i, e in enumerate(e_tot): log.info('Solvent cycle %d CASCI root %d ' 'E(CASCI+solvent) = %.15g dE = %g', cycle, i, e, de[i]) if abs(e_tot-e_last).max() < with_solvent.conv_tol: self.converged = True break e_last = e_tot # An extra cycle to canonicalize CASCI orbitals with lib.temporary_env(self, _finalize=lambda:None): casci_iter_(ci0, log) if self.converged: log.info('self-consistent CASCI+solvent converged') else: log.info('self-consistent CASCI+solvent not converged') log.note('Total energy with solvent effects') self._finalize() return self.e_tot, self.e_cas, self.ci, self.mo_coeff, self.mo_energy