def kernel_ft_smpl(h1e, g2e, norb, nelec, T, m=50,\ nsmpl=20000, Tmin=1e-3, symm='SOC', **kwargs): if symm is 'RHF': from pyscf.fci import direct_spin1 as fcisolver elif symm is 'SOC': from pyscf.fci import fci_slow_spinless as fcisolver elif symm is 'UHF': from pyscf.fci import direct_uhf as fcisolver else: from pyscf.fci import direct_spin1 as fcisolver if T < Tmin: return fcisolver.kernel(h1e, g2e, norb, nelec)[0] h2e = fcisolver.absorb_h1e(h1e, g2e, norb, nelec, .5) if symm is 'SOC': na = cistring.num_strings(norb, nelec) ci0 = numpy.random.randn(na) else: na = cistring.num_strings(norb, nelec // 2) ci0 = numpy.random.randn(na * na) ci0 = ci0 / numpy.linalg.norm(ci0) hdiag = fcisolver.make_hdiag(h1e, g2e, norb, nelec) hdiag = hdiag - hdiag[0] def hop(c): hc = fcisolver.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) E = ftsmpl.ft_smpl_E(hop, ci0, T, nsamp=nsmpl) return E
def ft_rdm1s(h1e, g2e, norb, nelec, T, m=50, nsamp=40, Tmin=10e-4): '''rdm of spin a and b at temperature T ''' if T < Tmin: e, c = kernel(h1e, g2e, norb, nelec) rdma, rdmb = direct_spin1.make_rdm1s(c, norb, nelec) return rdma, rdmb h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) def vecgen(n1=na, n2=nb): ci0 = numpy.random.randn(n1, n2) # ci0[0, 0] = 1. return ci0.reshape(-1) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) def qud(v1, v2): dma, dmb = direct_spin1.trans_rdm1s(v1, v2, norb, nelec) return dma, dmb # rdma, rdmb = flan.ht_rdm1s(qud, hop, vecgen, T, norb, m, nsamp) rdma, rdmb = flan.ftlan_rdm1s(qud, hop, vecgen, T, norb, m, nsamp) return rdma, rdmb
def kernel_ft(h1e, g2e, norb, nelec, T, m=50, nsamp=100, Tmin=10e-4): '''E at temperature T ''' if T < Tmin: e, c = kernel(h1e, g2e, norb, nelec) return e h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) def vecgen(n1=na, n2=nb): ci0 = numpy.random.randn(n1, n2) return ci0.reshape(-1) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) E = flan.ftlan_E(hop, vecgen, T, m, nsamp) return E
def diagH(h1e, g2e, norb, nelec, fcisolver): ''' exactly diagonalize the hamiltonian. ''' h2e = fcisolver.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, np.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) ndim = na * nb eyebas = np.eye(ndim) def hop(c): hc = fcisolver.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) Hmat = [] for i in range(ndim): hc = hop(eyebas[i]) Hmat.append(hc) Hmat = np.asarray(Hmat).T ew, ev = nl.eigh(Hmat) return ew, ev
def energy(h1e, eri, fcivec, norb, nelec, link_index=None): '''Compute the FCI electronic energy for given Hamiltonian and FCI vector. ''' from pyscf.fci import direct_spin1 h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) ci1 = direct_spin1.contract_2e(h2e, fcivec, norb, nelec, link_index) return numpy.dot(fcivec.reshape(-1), ci1.reshape(-1))
def diagH(h1e, g2e, norb, nelec, fcisolver): ''' exactly diagonalize the hamiltonian. ''' #print datetime.datetime.now(), ' Starting diagH' #print 'electron number: ', nelec h2e = fcisolver.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, np.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) ndim = na * nb #print 'ndim: ', ndim eyemat = np.eye(ndim) def hop(c): hc = fcisolver.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) Hmat = [] for i in range(ndim): hc = hop(eyemat[i]) Hmat.append(hc) #print datetime.datetime.now(), ' End generating H' Hmat = np.asarray(Hmat).T ew, ev = nl.eigh(Hmat) #print datetime.datetime.now(), ' End diagonalizing H' return ew, ev
def test_lasuccsd_total_energy (self): mc = mcscf.CASCI (mf, 4, 4) mc.mo_coeff = las.mo_coeff mc.fcisolver = lasuccsd.FCISolver (mol) mc.fcisolver.norb_f = [2,2] mc.kernel () with self.subTest (from_='reported'): self.assertAlmostEqual (mc.e_tot, ref.e_tot, 6) psi = mc.fcisolver.psi x = psi.x h1, h0 = mc.get_h1eff () h2 = mc.get_h2eff () h = [h0, h1, h2] energy, gradient = psi.e_de (x, h) with self.subTest (from_='obj fn'): self.assertAlmostEqual (energy, mc.e_tot, 9) c = np.squeeze (fockspace.fock2hilbert (psi.get_fcivec (x), 4, (2,2))) h2eff = direct_spin1.absorb_h1e (h1, h2, 4, (2,2), 0.5) hc = direct_spin1.contract_2e (h2eff, c, 4, (2,2)) chc = c.conj ().ravel ().dot (hc.ravel ()) + h0 with self.subTest (from_='h2 contraction'): self.assertAlmostEqual (chc, mc.e_tot, 9) c_f = psi.ci_f for ifrag, c in enumerate (c_f): heff = psi.get_dense_heff (x, h, ifrag) hc = np.dot (heff.full, c.ravel ()) chc = np.dot (c.conj ().ravel (), hc) with self.subTest (from_='frag {} Fock-space dense effective Hamiltonian'.format (ifrag)): self.assertAlmostEqual (chc, mc.e_tot, 9) heff, _ = heff.get_number_block ((1,1),(1,1)) c = np.squeeze (fockspace.fock2hilbert (c, 2, (1,1))).ravel () hc = np.dot (heff, c) chc = np.dot (c.conj (), hc) with self.subTest (from_='frag {} Hilbert-space dense effective Hamiltonian'.format (ifrag)): self.assertAlmostEqual (chc, mc.e_tot, 9)
def exdiagH(h1e, g2e, norb, nelec, writefile=True): ''' exactly diagonalize the hamiltonian. ''' h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, np.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec naa = cistring.num_strings(norb, neleca) nbb = cistring.num_strings(norb, nelecb) ndim = naa*nbb eyebas = np.eye(ndim, ndim) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) Hmat = [] for i in range(ndim): hc = hop(eyebas[i].copy()) Hmat.append(hc) Hmat = np.asarray(Hmat) # Hmat = Hmat.T.copy() ew, ev = nl.eigh(Hmat.T) if writefile: np.savetxt("cards/eignE.dat", ew, fmt="%10.10f") np.savetxt("cards/eignV.dat", ev, fmt="%10.10f") return ew, ev
def ft_rdm1s(h1e, g2e, norb, nelec, T, m=50, nsamp=40, Tmin=10e-4): '''rdm of spin a and b at temperature T ''' if T < Tmin: e, c = kernel(h1e, g2e, norb, nelec) rdma, rdmb = direct_spin1.make_rdm1s(c, norb, nelec) return rdma, rdmb h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) def vecgen(n1=na, n2=nb): ci0 = numpy.random.randn(n1, n2) # ci0[0, 0] = 1. return ci0.reshape(-1) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) def qud(v1, v2): dma, dmb = direct_spin1.trans_rdm1s(v1, v2, norb, nelec) return dma, dmb # rdma, rdmb = flan.ht_rdm1s(qud, hop, vecgen, T, norb, m, nsamp) rdma, rdmb = flan.ftlan_rdm1s(qud, hop, vecgen, T, norb, m, nsamp) return rdma, rdmb
def kernel(h1e, eri, norb, nelec, ecore=0, verbose=logger.NOTE): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) namax = cistring.num_strings(norb, neleca) nbmax = cistring.num_strings(norb, nelecb) myci = SelectedCI() strsa = [int('1'*neleca, 2)] strsb = [int('1'*nelecb, 2)] ci_strs = (strsa, strsb) ci0 = numpy.ones((1,1)) ci0, ci_strs = enlarge_space(myci, (ci0, ci_strs), h2e, norb, nelec) def all_linkstr_index(ci_strs): cd_indexa = cre_des_linkstr(ci_strs[0], norb, neleca) dd_indexa = des_des_linkstr(ci_strs[0], norb, neleca) cd_indexb = cre_des_linkstr(ci_strs[1], norb, nelecb) dd_indexb = des_des_linkstr(ci_strs[1], norb, nelecb) return cd_indexa, dd_indexa, cd_indexb, dd_indexb def hop(c): hc = contract_2e(h2e, (c, ci_strs), norb, nelec, link_index) return hc.reshape(-1) precond = lambda x, e, *args: x/(hdiag-e+1e-4) e_last = 0 tol = 1e-2 conv = False for icycle in range(norb): tol = max(tol*1e-2, myci.float_tol) link_index = all_linkstr_index(ci_strs) hdiag = make_hdiag(h1e, eri, ci_strs, norb, nelec) e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=tol, verbose=verbose) print('icycle %d ci.shape %s E = %.15g' % (icycle, (len(ci_strs[0]), len(ci_strs[1])), e)) if ci0.shape == (namax,nbmax) or abs(e-e_last) < myci.float_tol*10: conv = True break ci1, ci_strs = enlarge_space(myci, (ci0, ci_strs), h2e, norb, nelec) if ci1.size < ci0.size*1.02: conv = True break e_last = e ci0 = ci1 link_index = all_linkstr_index(ci_strs) hdiag = make_hdiag(h1e, eri, ci_strs, norb, nelec) e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=myci.conv_tol, verbose=verbose) na = len(ci_strs[0]) nb = len(ci_strs[1]) return e+ecore, (ci0.reshape(na,nb), ci_strs)
def rdm12s_ft_smpl(h1e, g2e, norb, nelec, T, \ m=50, nsmpl=20000, Tmin=1e-3, symm='RHF', **kwargs): if symm is 'RHF': from pyscf.fci import direct_spin1 as fcisolver elif symm is 'SOC': from pyscf.fci import fci_slow_spinless as fcisolver elif symm is 'UHF': from pyscf.fci import direct_uhf as fcisolver else: from pyscf.fci import direct_spin1 as fcisolver if T < Tmin: e, c = fcisolver.kernel(h1e, g2e, norb, nelec) dm1, dm2 = fcisolver.make_rdm12s(c, norb, nelec) dm1 = numpy.asarray(dm1) dm2 = numpy.asarray(dm2) else: h2e = fcisolver.absorb_h1e(h1e, g2e, norb, nelec, .5) if symm is 'SOC': na = cistring.num_strings(norb, nelec) ci0 = numpy.random.randn(na) else: na = cistring.num_strings(norb, nelec // 2) ci0 = numpy.random.randn(na * na) hdiag = fcisolver.make_hdiag(h1e, g2e, norb, nelec) hdiag = hdiag - hdiag[0] disp = numpy.exp(T) * 0.5 ci0 = ci0 / numpy.linalg.norm(ci0) def hop(c): hc = fcisolver.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) def qud(v1): dm1, dm2 = fcisolver.make_rdm12s(v1, norb, nelec) return dm1, dm2 dm1, dm2, e = ftsmpl.ft_smpl_rdm12s(qud, hop, ci0, T, norb, nsamp=nsmpl, M=m) if symm is 'UHF': return dm1, dm2, e elif len(dm1.shape) == 3: return numpy.sum(dm1, axis=0), numpy.sum(dm2, axis=0), e else: return dm1, dm2, e
def energy(h1e, eri, fcivec, norb, nelec, link_index=None, orbsym=None, wfnsym=0): h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec) * .5 ci1 = contract_2e(h2e, fcivec, norb, nelec, link_index, orbsym, wfnsym) return numpy.dot(fcivec.ravel(), ci1.ravel())
def kernel_fixed_space(myci, h1e, eri, norb, nelec, ci_strs, ci0=None, tol=None, lindep=None, max_cycle=None, max_space=None, nroots=None, davidson_only=None, max_memory=None, verbose=None, ecore=0, **kwargs): if verbose is None: log = logger.Logger(myci.stdout, myci.verbose) elif isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(myci.stdout, verbose) if tol is None: tol = myci.conv_tol if lindep is None: lindep = myci.lindep if max_cycle is None: max_cycle = myci.max_cycle if max_space is None: max_space = myci.max_space if max_memory is None: max_memory = myci.max_memory if nroots is None: nroots = myci.nroots if myci.verbose >= logger.WARN: myci.check_sanity() nelec = direct_spin1._unpack_nelec(nelec, myci.spin) ci0, nelec, ci_strs = _unpack(ci0, nelec, ci_strs) na = len(ci_strs[0]) nb = len(ci_strs[1]) h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) h2e = ao2mo.restore(1, h2e, norb) link_index = _all_linkstr_index(ci_strs, norb, nelec) hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) if isinstance(ci0, _SCIvector): if ci0.size == na*nb: ci0 = [ci0.ravel()] else: ci0 = [x.ravel() for x in ci0] else: ci0 = myci.get_init_guess(ci_strs, norb, nelec, nroots, hdiag) def hop(c): hc = myci.contract_2e(h2e, _as_SCIvector(c, ci_strs), norb, nelec, link_index) return hc.reshape(-1) precond = lambda x, e, *args: x/(hdiag-e+1e-4) #e, c = lib.davidson(hop, ci0, precond, tol=myci.conv_tol) e, c = myci.eig(hop, ci0, precond, tol=tol, lindep=lindep, max_cycle=max_cycle, max_space=max_space, nroots=nroots, max_memory=max_memory, verbose=log, **kwargs) if nroots > 1: return e+ecore, [_as_SCIvector(ci.reshape(na,nb),ci_strs) for ci in c] else: return e+ecore, _as_SCIvector(c.reshape(na,nb), ci_strs)
def kernel_fixed_space(myci, h1e, eri, norb, nelec, ci_strs, ci0=None, tol=None, lindep=None, max_cycle=None, max_space=None, nroots=None, davidson_only=None, max_memory=None, verbose=None, ecore=0, **kwargs): log = logger.new_logger(myci, verbose) if tol is None: tol = myci.conv_tol if lindep is None: lindep = myci.lindep if max_cycle is None: max_cycle = myci.max_cycle if max_space is None: max_space = myci.max_space if max_memory is None: max_memory = myci.max_memory if nroots is None: nroots = myci.nroots if myci.verbose >= logger.WARN: myci.check_sanity() nelec = direct_spin1._unpack_nelec(nelec, myci.spin) ci0, nelec, ci_strs = _unpack(ci0, nelec, ci_strs) na = len(ci_strs[0]) nb = len(ci_strs[1]) h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) h2e = ao2mo.restore(1, h2e, norb) link_index = _all_linkstr_index(ci_strs, norb, nelec) hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) if isinstance(ci0, _SCIvector): if ci0.size == na*nb: ci0 = [ci0.ravel()] else: ci0 = [x.ravel() for x in ci0] else: ci0 = myci.get_init_guess(ci_strs, norb, nelec, nroots, hdiag) def hop(c): hc = myci.contract_2e(h2e, _as_SCIvector(c, ci_strs), norb, nelec, link_index) return hc.reshape(-1) precond = lambda x, e, *args: x/(hdiag-e+1e-4) #e, c = lib.davidson(hop, ci0, precond, tol=myci.conv_tol) e, c = myci.eig(hop, ci0, precond, tol=tol, lindep=lindep, max_cycle=max_cycle, max_space=max_space, nroots=nroots, max_memory=max_memory, verbose=log, **kwargs) if nroots > 1: return e+ecore, [_as_SCIvector(ci.reshape(na,nb),ci_strs) for ci in c] else: return e+ecore, _as_SCIvector(c.reshape(na,nb), ci_strs)
def kernel(h1e, g2e, norb, nelec): h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): neleca = nelec//2 else: neleca = nelec[0] na = cistring.num_strings(norb, neleca) ci0 = numpy.zeros((na,na)) ci0[0,0] = 1 def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) hdiag = direct_spin1.make_hdiag(h1e, g2e, norb, nelec) precond = lambda x, e, *args: x/(hdiag-e+1e-4) e, c = pyscf.lib.davidson(hop, ci0.reshape(-1), precond) return e, c
def kernel(h1e, g2e, norb, nelec): h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): neleca = nelec // 2 else: neleca = nelec[0] na = cistring.num_strings(norb, neleca) ci0 = numpy.zeros((na, na)) ci0[0, 0] = 1 def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) hdiag = direct_spin1.make_hdiag(h1e, g2e, norb, nelec) precond = lambda x, e, *args: x / (hdiag - e + 1e-4) e, c = pyscf.lib.davidson(hop, ci0.reshape(-1), precond) return e, c
def kernel_ft_smpl(h1e, g2e, norb, nelec, T, vecgen=0, m=50, nsmpl=250, nblk=10, Tmin=10e-4, nrotation=200): if T < Tmin: e, c = kernel(h1e, g2e, norb, nelec) return e disp = numpy.exp(T) * 0.1 # displacement h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) ci0 = numpy.random.randn(na, nb) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) E, dev, ar = ftsmpl(hop, ci0, T, flan.ftlan_E1c, nsamp=nsmpl, dr=disp, genci=vecgen, nblock=nblk, nrot=nrotation) # ar is the acceptance ratio return E, dev, ar
def test_ham(self): for norb in range(2, 5): npair = norb * (norb + 1) // 2 c = np.random.rand(2**(2 * norb)) c /= linalg.norm(c) h0 = np.random.rand(1)[0] h1 = np.random.rand(norb, norb) h2 = np.random.rand(npair, npair) h1 += h1.T h2 += h2.T hc_ref = np.zeros_like(c) for nelec in product(range(norb + 1), repeat=2): c_h = np.squeeze(fockspace.fock2hilbert(c, norb, nelec)) h2eff = direct_spin1.absorb_h1e(h1, h2, norb, nelec, 0.5) hc_h = h0 * c_h + direct_spin1.contract_2e( h2eff, c_h, norb, nelec) hc_ref += fockspace.hilbert2fock(hc_h, norb, nelec).ravel() h1 = h1[np.tril_indices(norb)] hc_test = _op1h_spinsym(norb, [h0, h1, h2], c) with self.subTest(norb=norb): self.assertAlmostEqual(lib.fp(hc_test), lib.fp(hc_ref), 6)
def kernel_ref(h1e, eri, norb, nelec, ecore=0, **kwargs): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) h2e = ao2mo.restore(1, h2e, norb) na = cistring.num_strings(norb, neleca) ci0 = numpy.zeros(na) ci0[0] = 1 link_index = cistring.gen_linkstr_index(range(norb), neleca) def hop(c): return contract_2e_ref(h2e, c, norb, nelec, link_index) hdiag = make_hdiag(h1e, eri, norb, nelec) precond = lambda x, e, *args: x / (hdiag - e + 1e-4) e, c = lib.davidson(hop, ci0.reshape(-1), precond, **kwargs) return e + ecore
def kernel_ft_smpl(h1e, g2e, norb, nelec, T, vecgen = 0, m=50, nsmpl = 250, nblk = 10, Tmin=10e-4, nrotation = 200): if T < Tmin: e, c = kernel(h1e, g2e, norb, nelec) return e disp = numpy.exp(T) * 0.1 # displacement h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) ci0 = numpy.random.randn(na, nb) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) E, dev, ar = ftsmpl(hop, ci0, T, flan.ftlan_E1c, nsamp = nsmpl, dr = disp, genci=vecgen, nblock = nblk, nrot = nrotation) # ar is the acceptance ratio return E, dev, ar
def rdm1s_ft_smpl(h1e, g2e, norb, nelec, T, \ m=50, nsmpl=20000, Tmin=1e-3, symm='RHF', **kwargs): if symm is 'RHF': from pyscf.fci import direct_spin1 as fcisolver elif symm is 'SOC': from pyscf.fci import fci_slow_spinless as fcisolver elif symm is 'UHF': from pyscf.fci import direct_uhf as fcisolver else: from pyscf.fci import direct_spin1 as fcisolver if T < Tmin: e, c = fcisolver.kernel(h1e, g2e, norb, nelec) rdm1 = fcisolver.make_rdm1s(c, norb, nelec) return numpy.asarray(rdm1), e h2e = fcisolver.absorb_h1e(h1e, g2e, norb, nelec, .5) if symm is 'SOC': na = cistring.num_strings(norb, nelec) ci0 = numpy.random.randn(na) else: na = cistring.num_strings(norb, nelec // 2) ci0 = numpy.random.randn(na * na) ci0 = ci0 / numpy.linalg.norm(ci0) def hop(c): hc = fcisolver.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) def qud(v1): dm1 = fcisolver.make_rdm1s(v1, norb, nelec) return dm1 dm1, e = ftsmpl.ft_smpl_rdm1s(qud,\ hop, ci0, T, norb, nsamp=nsmpl,M=m) return dm1, e
def kernel_ft(h1e, g2e, norb, nelec, T, m=50, nsamp=100, Tmin=10e-4): '''E at temperature T ''' if T < Tmin: e, c = kernel(h1e, g2e, norb, nelec) return e h2e = direct_spin1.absorb_h1e(h1e, g2e, norb, nelec, .5) if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) def vecgen(n1=na, n2=nb): ci0 = numpy.random.randn(n1, n2) return ci0.reshape(-1) def hop(c): hc = direct_spin1.contract_2e(h2e, c, norb, nelec) return hc.reshape(-1) E = flan.ftlan_E(hop, vecgen, T, m, nsamp) return E
def energy(h1e, eri, fcivec, norb, nelec, link_index=None): h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) ci1 = contract_2e(h2e, fcivec, norb, nelec, link_index) return numpy.dot(fcivec.ravel(), ci1.ravel())
def absorb_h1e(self, h1e, eri, norb, nelec, fac=1): nelec = _unpack_nelec(nelec, self.spin) return direct_spin1.absorb_h1e(h1e, eri, norb, nelec, fac)
def absorb_h1e(self, h1e, eri, norb, nelec, fac=1): return direct_spin1.absorb_h1e(h1e, eri, norb, nelec, fac)
def kernel_float_space(myci, h1e, eri, norb, nelec, ci0=None, tol=None, lindep=None, max_cycle=None, max_space=None, nroots=None, davidson_only=None, max_memory=None, verbose=None, ecore=0, **kwargs): if verbose is None: log = logger.Logger(myci.stdout, myci.verbose) elif isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(myci.stdout, verbose) if tol is None: tol = myci.conv_tol if lindep is None: lindep = myci.lindep if max_cycle is None: max_cycle = myci.max_cycle if max_space is None: max_space = myci.max_space if max_memory is None: max_memory = myci.max_memory if nroots is None: nroots = myci.nroots if myci.verbose >= logger.WARN: myci.check_sanity() nelec = direct_spin1._unpack_nelec(nelec, myci.spin) h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) h2e = ao2mo.restore(1, h2e, norb) # TODO: initial guess from CISD if isinstance(ci0, _SCIvector): if ci0.size == len(ci0._strs[0]) * len(ci0._strs[1]): ci0 = [ci0.ravel()] else: ci0 = [x.ravel() for x in ci0] else: ci_strs = (numpy.asarray([int('1' * nelec[0], 2)]), numpy.asarray([int('1' * nelec[1], 2)])) ci0 = _as_SCIvector(numpy.ones((1, 1)), ci_strs) ci0 = myci.enlarge_space(ci0, h2e, norb, nelec) if ci0.size < nroots: log.warn(''' Selected-CI space generated from HF ground state (by double exciting) is not enough for excited states. H**O->LUMO excitations are included in the initial guess. NOTE: This may introduce excited states of different symmetry.\n''') corea = '1' * (nelec[0] - 1) coreb = '1' * (nelec[1] - 1) ci_strs = (numpy.asarray([ int('1' + corea, 2), int('10' + corea, 2) ]), numpy.asarray([int('1' + coreb, 2), int('10' + coreb, 2)])) ci0 = _as_SCIvector(numpy.ones((2, 2)), ci_strs) ci0 = myci.enlarge_space(ci0, h2e, norb, nelec) if ci0.size < nroots: raise RuntimeError('Not enough selected-CI space for %d states' % nroots) ci_strs = ci0._strs hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) ci0 = myci.get_init_guess(ci_strs, norb, nelec, nroots, hdiag) def hop(c): hc = myci.contract_2e(h2e, _as_SCIvector(c, ci_strs), norb, nelec, link_index) return hc.ravel() precond = lambda x, e, *args: x / (hdiag - e + myci.level_shift) namax = cistring.num_strings(norb, nelec[0]) nbmax = cistring.num_strings(norb, nelec[1]) e_last = 0 float_tol = myci.start_tol tol_decay_rate = myci.tol_decay_rate conv = False for icycle in range(norb): ci_strs = ci0[0]._strs float_tol = max(float_tol * tol_decay_rate, tol * 1e2) log.debug('cycle %d ci.shape %s float_tol %g', icycle, (len(ci_strs[0]), len(ci_strs[1])), float_tol) ci0 = [c.ravel() for c in ci0] link_index = _all_linkstr_index(ci_strs, norb, nelec) hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) #e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=float_tol) e, ci0 = myci.eig(hop, ci0, precond, tol=float_tol, lindep=lindep, max_cycle=max_cycle, max_space=max_space, nroots=nroots, max_memory=max_memory, verbose=log, **kwargs) if nroots > 1: ci0 = [_as_SCIvector(c, ci_strs) for c in ci0] de, e_last = min(e) - e_last, min(e) log.info('cycle %d E = %s dE = %.8g', icycle, e + ecore, de) else: ci0 = [_as_SCIvector(ci0, ci_strs)] de, e_last = e - e_last, e log.info('cycle %d E = %.15g dE = %.8g', icycle, e + ecore, de) if ci0[0].shape == (namax, nbmax) or abs(de) < tol * 1e3: conv = True break last_ci0_size = float(len(ci_strs[0])), float(len(ci_strs[1])) ci0 = myci.enlarge_space(ci0, h2e, norb, nelec) na = len(ci0[0]._strs[0]) nb = len(ci0[0]._strs[1]) if ((.99 < na / last_ci0_size[0] < 1.01) and (.99 < nb / last_ci0_size[1] < 1.01)): conv = True break ci_strs = ci0[0]._strs log.debug('Extra CI in selected space %s', (len(ci_strs[0]), len(ci_strs[1]))) ci0 = [c.ravel() for c in ci0] link_index = _all_linkstr_index(ci_strs, norb, nelec) hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) e, c = myci.eig(hop, ci0, precond, tol=tol, lindep=lindep, max_cycle=max_cycle, max_space=max_space, nroots=nroots, max_memory=max_memory, verbose=log, **kwargs) na = len(ci_strs[0]) nb = len(ci_strs[1]) if nroots > 1: for i, ei in enumerate(e + ecore): log.info('Selected CI state %d E = %.15g', i, ei) return e + ecore, [ _as_SCIvector(ci.reshape(na, nb), ci_strs) for ci in c ] else: log.info('Selected CI E = %.15g', e + ecore) return e + ecore, _as_SCIvector(c.reshape(na, nb), ci_strs)
def absorb_h1e(*args, **kwargs): return direct_spin1.absorb_h1e(*args, **kwargs)
def kernel_float_space( myci, h1e, eri, norb, nelec, ci0=None, tol=None, lindep=None, max_cycle=None, max_space=None, nroots=None, davidson_only=None, max_memory=None, verbose=None, ecore=0, **kwargs ): if verbose is None: log = logger.Logger(myci.stdout, myci.verbose) elif isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(myci.stdout, verbose) if tol is None: tol = myci.conv_tol if lindep is None: lindep = myci.lindep if max_cycle is None: max_cycle = myci.max_cycle if max_space is None: max_space = myci.max_space if max_memory is None: max_memory = myci.max_memory if nroots is None: nroots = myci.nroots if myci.verbose >= logger.WARN: myci.check_sanity() nelec = direct_spin1._unpack_nelec(nelec, myci.spin) h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, 0.5) h2e = ao2mo.restore(1, h2e, norb) # TODO: initial guess from CISD if isinstance(ci0, _SCIvector): if ci0.size == len(ci0._strs[0]) * len(ci0._strs[1]): ci0 = [ci0.ravel()] else: ci0 = [x.ravel() for x in ci0] else: if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb nelec = neleca, nelecb ci_strs = (numpy.asarray([int("1" * nelec[0], 2)]), numpy.asarray([int("1" * nelec[1], 2)])) ci0 = _as_SCIvector(numpy.ones((1, 1)), ci_strs) ci0 = myci.enlarge_space(ci0, h2e, norb, nelec) ci_strs = ci0._strs hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) ci0 = myci.get_init_guess(ci_strs, norb, nelec, nroots, hdiag) def hop(c): hc = myci.contract_2e(h2e, _as_SCIvector(c, ci_strs), norb, nelec, link_index) return hc.ravel() precond = lambda x, e, *args: x / (hdiag - e + myci.level_shift) namax = cistring.num_strings(norb, nelec[0]) nbmax = cistring.num_strings(norb, nelec[1]) e_last = 0 float_tol = 3e-4 conv = False for icycle in range(norb): ci_strs = ci0[0]._strs float_tol = max(float_tol * 0.3, tol * 1e2) log.debug("cycle %d ci.shape %s float_tol %g", icycle, (len(ci_strs[0]), len(ci_strs[1])), float_tol) ci0 = [c.ravel() for c in ci0] link_index = _all_linkstr_index(ci_strs, norb, nelec) hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) # e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=float_tol) e, ci0 = myci.eig( hop, ci0, precond, tol=float_tol, lindep=lindep, max_cycle=max_cycle, max_space=max_space, nroots=nroots, max_memory=max_memory, verbose=log, **kwargs ) if nroots > 1: ci0 = [_as_SCIvector(c, ci_strs) for c in ci0] de, e_last = min(e) - e_last, min(e) log.info("cycle %d E = %s dE = %.8g", icycle, e + ecore, de) else: ci0 = [_as_SCIvector(ci0, ci_strs)] de, e_last = e - e_last, e log.info("cycle %d E = %.15g dE = %.8g", icycle, e + ecore, de) if ci0[0].shape == (namax, nbmax) or abs(de) < tol * 1e3: conv = True break last_ci0_size = float(len(ci_strs[0])), float(len(ci_strs[1])) ci0 = myci.enlarge_space(ci0, h2e, norb, nelec) na = len(ci0[0]._strs[0]) nb = len(ci0[0]._strs[1]) if (0.99 < na / last_ci0_size[0] < 1.01) and (0.99 < nb / last_ci0_size[1] < 1.01): conv = True break ci_strs = ci0[0]._strs log.debug("Extra CI in selected space %s", (len(ci_strs[0]), len(ci_strs[1]))) ci0 = [c.ravel() for c in ci0] link_index = _all_linkstr_index(ci_strs, norb, nelec) hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) e, c = myci.eig( hop, ci0, precond, tol=tol, lindep=lindep, max_cycle=max_cycle, max_space=max_space, nroots=nroots, max_memory=max_memory, verbose=log, **kwargs ) log.info("Select CI E = %.15g", e + ecore) na = len(ci_strs[0]) nb = len(ci_strs[1]) if nroots > 1: return e + ecore, [_as_SCIvector(ci.reshape(na, nb), ci_strs) for ci in c] else: return e + ecore, _as_SCIvector(c.reshape(na, nb), ci_strs)
def kernel(h1e, eri, norb, nelec, ecore=0, verbose=logger.NOTE): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec // 2 neleca = nelec - nelecb else: neleca, nelecb = nelec h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) namax = cistring.num_strings(norb, neleca) nbmax = cistring.num_strings(norb, nelecb) myci = SelectedCI() strsa = [int('1' * neleca, 2)] strsb = [int('1' * nelecb, 2)] ci_strs = (strsa, strsb) ci0 = numpy.ones((1, 1)) ci0, ci_strs = enlarge_space(myci, (ci0, ci_strs), h2e, norb, nelec) def all_linkstr_index(ci_strs): cd_indexa = cre_des_linkstr(ci_strs[0], norb, neleca) dd_indexa = des_des_linkstr(ci_strs[0], norb, neleca) cd_indexb = cre_des_linkstr(ci_strs[1], norb, nelecb) dd_indexb = des_des_linkstr(ci_strs[1], norb, nelecb) return cd_indexa, dd_indexa, cd_indexb, dd_indexb def hop(c): hc = contract_2e(h2e, (c, ci_strs), norb, nelec, link_index) return hc.reshape(-1) precond = lambda x, e, *args: x / (hdiag - e + 1e-4) e_last = 0 tol = 1e-2 conv = False for icycle in range(norb): tol = max(tol * 1e-2, myci.float_tol) link_index = all_linkstr_index(ci_strs) hdiag = make_hdiag(h1e, eri, ci_strs, norb, nelec) e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=tol, verbose=verbose) print('icycle %d ci.shape %s E = %.15g' % (icycle, (len(ci_strs[0]), len(ci_strs[1])), e)) if ci0.shape == (namax, nbmax) or abs(e - e_last) < myci.float_tol * 10: conv = True break ci1, ci_strs = enlarge_space(myci, (ci0, ci_strs), h2e, norb, nelec) if ci1.size < ci0.size * 1.02: conv = True break e_last = e ci0 = ci1 link_index = all_linkstr_index(ci_strs) hdiag = make_hdiag(h1e, eri, ci_strs, norb, nelec) e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=myci.conv_tol, verbose=verbose) na = len(ci_strs[0]) nb = len(ci_strs[1]) return e + ecore, (ci0.reshape(na, nb), ci_strs)
def kernel_float_space(myci, h1e, eri, norb, nelec, ci0=None, tol=None, lindep=None, max_cycle=None, max_space=None, nroots=None, davidson_only=None, max_memory=None, verbose=None, ecore=0, **kwargs): if verbose is None: log = logger.Logger(myci.stdout, myci.verbose) elif isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(myci.stdout, verbose) if tol is None: tol = myci.conv_tol if lindep is None: lindep = myci.lindep if max_cycle is None: max_cycle = myci.max_cycle if max_space is None: max_space = myci.max_space if max_memory is None: max_memory = myci.max_memory if nroots is None: nroots = myci.nroots if myci.verbose >= logger.WARN: myci.check_sanity() nelec = direct_spin1._unpack_nelec(nelec, myci.spin) h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) h2e = ao2mo.restore(1, h2e, norb) # TODO: initial guess from CISD if isinstance(ci0, _SCIvector): if ci0.size == len(ci0._strs[0])*len(ci0._strs[1]): ci0 = [ci0.ravel()] else: ci0 = [x.ravel() for x in ci0] else: if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb nelec = neleca, nelecb ci_strs = (numpy.asarray([int('1'*nelec[0], 2)]), numpy.asarray([int('1'*nelec[1], 2)])) ci0 = _as_SCIvector(numpy.ones((1,1)), ci_strs) ci0 = myci.enlarge_space(ci0, h2e, norb, nelec) if ci0.size < nroots: log.warn(''' Selected-CI space generated from HF ground state (by double exciting) is not enough for excited states. H**O->LUMO excitations are included in the initial guess. NOTE: This may introduce excited states of different symmetry.\n''') corea = '1' * (nelec[0]-1) coreb = '1' * (nelec[1]-1) ci_strs = (numpy.asarray([int('1'+corea, 2), int('10'+corea, 2)]), numpy.asarray([int('1'+coreb, 2), int('10'+coreb, 2)])) ci0 = _as_SCIvector(numpy.ones((2,2)), ci_strs) ci0 = myci.enlarge_space(ci0, h2e, norb, nelec) if ci0.size < nroots: raise RuntimeError('Not enough selected-CI space for %d states' % nroots) ci_strs = ci0._strs hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) ci0 = myci.get_init_guess(ci_strs, norb, nelec, nroots, hdiag) def hop(c): hc = myci.contract_2e(h2e, _as_SCIvector(c, ci_strs), norb, nelec, link_index) return hc.ravel() precond = lambda x, e, *args: x/(hdiag-e+myci.level_shift) namax = cistring.num_strings(norb, nelec[0]) nbmax = cistring.num_strings(norb, nelec[1]) e_last = 0 float_tol = 3e-4 conv = False for icycle in range(norb): ci_strs = ci0[0]._strs float_tol = max(float_tol*.3, tol*1e2) log.debug('cycle %d ci.shape %s float_tol %g', icycle, (len(ci_strs[0]), len(ci_strs[1])), float_tol) ci0 = [c.ravel() for c in ci0] link_index = _all_linkstr_index(ci_strs, norb, nelec) hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) #e, ci0 = lib.davidson(hop, ci0.reshape(-1), precond, tol=float_tol) e, ci0 = myci.eig(hop, ci0, precond, tol=float_tol, lindep=lindep, max_cycle=max_cycle, max_space=max_space, nroots=nroots, max_memory=max_memory, verbose=log, **kwargs) if nroots > 1: ci0 = [_as_SCIvector(c, ci_strs) for c in ci0] de, e_last = min(e)-e_last, min(e) log.info('cycle %d E = %s dE = %.8g', icycle, e+ecore, de) else: ci0 = [_as_SCIvector(ci0, ci_strs)] de, e_last = e-e_last, e log.info('cycle %d E = %.15g dE = %.8g', icycle, e+ecore, de) if ci0[0].shape == (namax,nbmax) or abs(de) < tol*1e3: conv = True break last_ci0_size = float(len(ci_strs[0])), float(len(ci_strs[1])) ci0 = myci.enlarge_space(ci0, h2e, norb, nelec) na = len(ci0[0]._strs[0]) nb = len(ci0[0]._strs[1]) if ((.99 < na/last_ci0_size[0] < 1.01) and (.99 < nb/last_ci0_size[1] < 1.01)): conv = True break ci_strs = ci0[0]._strs log.debug('Extra CI in selected space %s', (len(ci_strs[0]), len(ci_strs[1]))) ci0 = [c.ravel() for c in ci0] link_index = _all_linkstr_index(ci_strs, norb, nelec) hdiag = myci.make_hdiag(h1e, eri, ci_strs, norb, nelec) e, c = myci.eig(hop, ci0, precond, tol=tol, lindep=lindep, max_cycle=max_cycle, max_space=max_space, nroots=nroots, max_memory=max_memory, verbose=log, **kwargs) na = len(ci_strs[0]) nb = len(ci_strs[1]) if nroots > 1: for i, ei in enumerate(e+ecore): log.info('Selected CI state %d E = %.15g', i, ei) return e+ecore, [_as_SCIvector(ci.reshape(na,nb),ci_strs) for ci in c] else: log.info('Selected CI E = %.15g', e+ecore) return e+ecore, _as_SCIvector(c.reshape(na,nb), ci_strs)
def energy(h1e, eri, fcivec, norb, nelec, link_index=None): from pyscf.fci import direct_spin1 h2e = direct_spin1.absorb_h1e(h1e, eri, norb, nelec, .5) ci1 = direct_spin1.contract_2e(h2e, fcivec, norb, nelec, link_index) return numpy.dot(fcivec.reshape(-1), ci1.reshape(-1))
jk = jk.ravel() jk_sorted = abs(jk).argsort()[::-1] ci1 = [as_SCIvector(numpy.ones(1), hf_str)] myci = SelectedCI() myci.select_cutoff = .001 myci.ci_coeff_cutoff = .001 ci2 = enlarge_space(myci, ci1, h1, eri, jk, eri_sorted, jk_sorted, norb, nelec) print(len(ci2[0])) ci2 = enlarge_space(myci, ci1, h1, eri, jk, eri_sorted, jk_sorted, norb, nelec) numpy.random.seed(1) ci3 = numpy.random.random(ci2[0].size) ci3 *= 1./numpy.linalg.norm(ci3) ci3 = [ci3] ci3 = enlarge_space(myci, ci2, h1, eri, jk, eri_sorted, jk_sorted, norb, nelec) efci = direct_spin1.kernel(h1, eri, norb, nelec, verbose=5)[0] ci4 = contract_2e_ctypes((h1, eri), ci3[0], norb, nelec) fci3 = to_fci(ci3, norb, nelec) h2e = direct_spin1.absorb_h1e(h1, eri, norb, nelec, .5) fci4 = direct_spin1.contract_2e(h2e, fci3, norb, nelec) fci4 = from_fci(fci4, ci3[0]._strs, norb, nelec) print(abs(ci4-fci4).sum()) e = myci.kernel(h1, eri, norb, nelec, verbose=5)[0] print(e, efci)
def kernel(mc, nroots): mc_1root = mc 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 nao, nmo = mc.mo_coeff.shape ncas, ncore = mc.ncas, mc.ncore nocc = ncas + ncore mo_cas = mc.mo_coeff[:, ncore:nocc] casdm1 = mc.fcisolver.states_make_rdm1(mc.ci, mc_1root.ncas, mc_1root.nelecas) dm1 = np.dot(casdm1, mo_cas.T) dm1 = np.dot(mo_cas, dm1).transpose(1, 0, 2) aeri = ao2mo.restore(1, mc.get_h2eff(mc.mo_coeff), mc.ncas) rows, col = np.tril_indices(nroots, k=-1) pairs = len(rows) ci_array = np.array(mc.ci) u = np.identity(nroots) t = np.zeros((nroots, nroots)) t_old = np.zeros((nroots, nroots)) trans12_tdm1, trans12_tdm2 = mc.fcisolver.states_trans_rdm12( ci_array[col], ci_array[rows], mc_1root.ncas, mc_1root.nelecas) trans12_tdm1_array = np.array(trans12_tdm1) tdm1 = np.dot(trans12_tdm1_array, mo_cas.T) tdm1 = np.dot(mo_cas, tdm1).transpose(1, 0, 2) log = lib.logger.new_logger(mc, mc.verbose) log.info("Entering cmspdft3.kernel") # MRH: PySCF convention is never to use the "print" function in method code. # All I/O in published PySCF code goes through the pyscf.lib.logger module. # This prints data to an output file specified by the user like # mol = gto.M (atom = ..., verbose = lib.logger.INFO, output = 'fname.log') # If no output file is specified, it goes to the STDOUT as if it were a print # command. The different pyscf.lib.logger functions, "note", "info", "debug", # and some others, correspond to different levels of verbosity. In the above # example, log.note and log.info commands would print information to # 'fname.log', but "debug" commands, which are a higher level, are skipped. # I changed all the print commands in this function to log.debug or log.info # commands. #Print the First Coulomb Energy j = mc_1root._scf.get_j(dm=dm1) e_coul = (j * dm1).sum((1, 2)) / 2 log.debug("Reference state e_coul {}".format(e_coul)) log.info("Reference state e_coul sum = %f", e_coul.sum()) # MRH: There are a couple of things going on here. First of all, the two # statements share different levels of detail, so I use different verbosities: # "debug" (only printed if the user has verbose=DEBUG or higher) for the list # of all Coulomb energies and "info" (verbose=INFO is the default if an output # file is specified) for the sum. Secondly, I am showing two separate ways of # formatting strings in Python. log.xxx () knows how to parse the "old" Python # string-formatting rules, which is what I've used in the log.info command, but # it doesn't know how to interpret a list of arguments the way "print" does, so # you have to pass it only one single string. The other way to do this is with # "new" python formatting, which I think is simpler: # print ("{} and {} and {}".format (a, b, c)) # is basically identical to # print (a, "and", b, "and", c) # but you can only use the former in log.xxx: # log.xxx ("{} and {} and {}".format (a, b, c)) #Hessian Functions # MRH: Here's a way do not do those nested loops and conditionals and therefore # have less to worry about re indentation. Print out "rowscol2ind" and it should # be clear how this works. rowscol2ind = np.zeros((nroots, nroots), dtype=np.integer) rowscol2ind[(rows, col)] = list(range(pairs)) # 0,1,2,3,... rowscol2ind += rowscol2ind.T # Now it can handle both k>l and l>k rowscol2ind[np.diag_indices( nroots)] = -1 # Makes sure it crashes if you look # for k==l, since that's the density # matrix and we compute that with a # different function. def w_klmn(k, l, m, n, dm, tdm): # casdm1 = mc.fcisolver.states_make_rdm1 (ci,mc_1root.ncas,mc_1root.nelecas) # MRH: don't you also need to put casdm1 into the AO basis/recompute dm1? # dm1 = np.dot(casdm1,mo_cas.T) # dm1 = np.dot(mo_cas,dm1).transpose(1,0,2) # MRH: IMO it's more elegant to rewrite these functions to take the density # matrices dm1_cirot and tdm1 as you compute them for the gradient downstairs, # since it's the same density matrices for both derivatives. Then this whole # function could be like 5 lines long: d = dm[k] if k == l else tdm[rowscol2ind[k, l]] dm1_g = mc_1root._scf.get_j(dm=d) d = dm[m] if m == n else tdm[rowscol2ind[m, n]] w = (dm1_g * d).sum((0, 1)) return w # But I'll leave it like this so you can see what's going on more clearly in # the github "files changed" tab. # trans12_tdm1, trans12_tdm2 = mc.fcisolver.states_trans_rdm12(ci[col],ci[rows],mc_1root.ncas,mc_1root.nelecas) # if k==l: # dm1_g = mc_1root._scf.get_j (dm=dm1[k]) # else: # ind = rowscol2ind[k,l] # tdm1_2 = np.dot(trans12_tdm1[ind],mo_cas.T) # tdm1_2 = np.dot(mo_cas,tdm1_2).transpose(1,0) # dm1_g = mc_1root._scf.get_j(dm=tdm1_2) # if m==n: # w = (dm1_g*dm1[n]).sum((0,1)) # else: # ind2 = rowscol2ind[m,n] # tdm1_2 = np.dot(trans12_tdm1_array[ind2],mo_cas.T) # tdm1_2 = np.dot(mo_cas,tdm1_2).transpose(1,0) # w = (dm1_g*tdm1_2).sum((0,1)) def v_klmn(k, l, m, n, dm, tdm): if l == m: v = w_klmn(k, n, k, k, dm, tdm) - w_klmn( k, n, l, l, dm, tdm) + w_klmn(n, k, n, n, dm, tdm) - w_klmn( k, n, m, m, dm, tdm) - 4 * w_klmn(k, l, m, n, dm, tdm) #Compute Classical Couloumb Energy casdm1 = mc.fcisolver.states_make_rdm1(mc.ci, mc_1root.ncas, mc_1root.nelecas) dm1 = np.dot(casdm1, mo_cas.T) dm1 = np.dot(mo_cas, dm1).transpose(1, 0, 2) print("dm1", np.shape(dm1)) # print("dm1",dm1) j = mc_1root._scf.get_j(dm=dm1) # print("j",j) e_coul = (j * dm1).sum((1, 2)) / 2 print("e_coul_1", e_coul) #Transition Density for i in range(0, nroots): ci_coeff = mc.ci[i] print("ci", i, ci_coeff) print("mc.ci", type(mc.ci)) rows, col = np.tril_indices(nroots, k=-1) pairs = len(rows) print("rows", rows, "col", col, "pairs", pairs) print("mc.ci shape", np.shape(mc.ci)) mc.ci_array = np.array(mc.ci) row_ci = mc.ci_array[rows] # print ("mc.ci[rows]",row_ci) col_ci = mc.ci_array[col] trans12_tdm1, trans12_tdm2 = mc.fcisolver.states_trans_rdm12( col_ci, row_ci, mc_1root.ncas, mc_1root.nelecas) print("trans12_tdm1", np.shape(trans12_tdm1)) #Load in the two-electron integrals aeri = ao2mo.restore(1, mc.get_h2eff(mc.mo_coeff), mc.ncas) # print("aeri", aeri) # print("eri shape", np.shape(aeri)) #Initialize rotation matrix u = np.identity(mc.fcisolver.nroots) print("U :", u) t = np.zeros((nroots, nroots)) u_lt = linalg.expm(t) print("u_lt", u_lt) ###################################################### #Begin Loop ###################################################### #Gradients trans12_tdm1_array = np.array(trans12_tdm1) grad = np.zeros(pairs) for i in range(pairs): ind = rows[i] grad[i] = (casdm1[ind] * trans12_tdm1_array[i] * aeri).sum( (0, 1, 2, 3)) print('ind,i', ind, ',', i) grad = 4 * grad print('grad', grad) # gradnorm = np.linalg.norm(grad) # print ("grad norm", gradnorm) print("grad shape", np.shape(grad)) #Try 2 # j1 = mc_1root._scf.get_jk(mc._scf.mol, dm1, 'ijkl,lk->ij', intor='int2e_ip1_sph', aosym='s2kl', comp=3) # print("j1",j1) #Gradient try 3 # grad3 = trans12_tdm1_array*casdm1 * aeri # print ("grad3",grad3) # print("dm1",np.shape(dm1)) grad3 = np.zeros(pairs) # for i in range (pairs): # dg = mc_1root._scf.get_j (dm=dm1[col]) # print("dg shape",np.shape(dg)) tdm1 = np.dot(trans12_tdm1_array, mo_cas.T) tdm1 = np.dot(mo_cas, tdm1).transpose(1, 0, 2) dg = mc_1root._scf.get_j(dm=tdm1) print("tdm1_array", trans12_tdm1) # tdm1_1 = tdm1[i] # grad3 = (dg*tdm1).sum((1,2)) grad3 = 4 * (dg * dm1[rows]).sum((1, 2)) print("grad 3 shape", np.shape(grad3)) # grad3=grad3.sum((1,2)) print("grad3 rows", grad3) # print("grad3*4", grad3*4) gradnorm3 = np.linalg.norm(grad3) print("grad norm", gradnorm3) grad4 = 4 * (dg * dm1[col]).sum((1, 2)) print("grad3 col", grad4) gradnorm4 = np.linalg.norm(grad4) print("grad norm", gradnorm4) print("grad norm 3+4", gradnorm4 + gradnorm3) gradsum = grad4 + grad3 print("grad sum", gradsum) print("grad sum norm", np.linalg.norm(gradsum)) #GRADIENT TRY 5 # grad5 = np.zeros((nroots,pairs)) # for i in range(nroots): # dg = mc_1root._scf.get_j(dm=dm1[i]) # for j in range(pairs): # if rows[j]==i or col[j]==i: # grad5[i,j]=(dg*tdm1[j]).sum((0,1)) # print("grad5",grad5) #Hessian def w_klmn(k, l, m, n): if k == l: dm1_g = mc_1root._scf.get_j(dm=dm1[k]) else: for i in range(pairs): if rows[i] == k: if col[i] == l: ind = i # print("ind",ind) if col[i] == k: if rows[i] == l: ind = i # print("ind",ind) tdm1_2 = np.dot(trans12_tdm1[ind], mo_cas.T) # print("tdm1",np.shape(tdm1_2)) tdm1_2 = np.dot(mo_cas, tdm1_2).transpose(1, 0) # print("tdm1", np.shape(tdm1_2)) dm1_g = mc_1root._scf.get_j(dm=tdm1_2) if m == n: w = (dm1_g * dm1[n]).sum((0, 1)) else: for i in range(pairs): if rows[i] == m: if col[i] == n: ind2 = i # print("ind2",ind2) if col[i] == m: if rows[i] == n: ind2 = i # print("ind2",ind2) tdm1_2 = np.dot(trans12_tdm1_array[ind2], mo_cas.T) tdm1_2 = np.dot(mo_cas, tdm1_2).transpose(1, 0) w = (dm1_g * tdm1_2).sum((0, 1)) return w # for k in range (nroots): # for l in range(nroots): # for m in range(nroots): # for n in range nroots: def v_klmn(k, l, m, n): if l == m: v = w_klmn(k, n, k, k) - w_klmn(k, n, l, l) + w_klmn( n, k, n, n) - w_klmn(k, n, m, m) - 4 * w_klmn(k, l, m, n) else: v = 0 return v #Rotate to XMS States h1, h0 = mc.get_h1eff() # print("fvecs_nstates",fvecs_nstates) # ci_array = np.tensordot(fvecs_nstates, ci_array, 1) casdm1 = mc.fcisolver.states_make_rdm1(ci_array, mc_1root.ncas, mc_1root.nelecas) dm1 = np.dot(casdm1, mo_cas.T) dm1 = np.dot(mo_cas, dm1).transpose(1, 0, 2) #Loop Initializations dm1_old = dm1 maxiter = 150 ci_old = ci_array thrs = 1.0e-06 e_coul_old = e_coul conv = False ################# #Begin Loop ################# for it in range(maxiter): log.info("****iter {} ***********".format(it)) # Form U U = linalg.expm(t) # Rotate T ci_rot = np.tensordot(U, ci_old, 1) # Form New DM1s casdm1_rot = mc.fcisolver.states_make_rdm1(ci_rot, mc_1root.ncas, mc_1root.nelecas) dm1_cirot = np.dot(casdm1_rot, mo_cas.T) dm1_cirot = np.dot(mo_cas, dm1_cirot).transpose(1, 0, 2) dm1_cirot = np.array(dm1_cirot) # Form New TDM trans12_tdm1_rot, trans12_tdm2 = mc.fcisolver.states_trans_rdm12( ci_rot[col], ci_rot[rows], mc_1root.ncas, mc_1root.nelecas) trans12_tdm1_array = np.array(trans12_tdm1_rot) tdm1 = np.dot(trans12_tdm1_array, mo_cas.T) tdm1 = np.dot(mo_cas, tdm1).transpose(1, 0, 2) # Print New E coul and difference j = mc_1root._scf.get_j(dm=dm1_cirot) e_coul_new = (j * dm1_cirot).sum((1, 2)) / 2 log.info("Sum e_coul = {} ; difference = {}".format( e_coul_new.sum(), e_coul_new.sum() - e_coul_old.sum())) # Compute Gradient dg = mc_1root._scf.get_j(dm=tdm1) grad1 = (dg * dm1_cirot[rows]).sum((1, 2)) grad2 = (dg * dm1_cirot[col]).sum((1, 2)) grad = 2 * (grad1 - grad2) grad_norm = np.linalg.norm(grad) log.debug("grad: {}".format(grad)) log.info("grad norm = %f", grad_norm) # if grad_norm < thrs: # conv = True # ci_final = ci_rot # best just to use ci_rot # break # print("hello") # Hessian hess = np.zeros((pairs, pairs)) # MRH: you can do this whole nested loop, defining all six indices, in one (1) line: for (i, (k, l)), (j, (m, n)) in product(enumerate(zip(rows, col)), repeat=2): # To explain: # for k,l in zip (rows, col) # ^ Puts elements of "rows" in "k" and elements of "col" in "l" # Advances through "rows" and "col" simultaneously, so it's always # the nth element of "rows" and the nth element of "col" # So obviously, "rows" and "col" have to be the same size. # You don't need parentheses on the right-hand side at this point # for i, (k, l) in enumerate (zip (rows,col)): # ^ Iterates over the zip and puts its elements in (k, l), and also # counts upwards from zero and puts the count in "i". Here, you do # need parentheses so that the interpreter understands that "k" # and "l" are grouped together, separate from "i". # the uncommented line # ^ "Product" is like "zip", except instead of advancing through the # arguments simultaneously, it gives you all combinations of all # elements. Also, I've only entered one argument and asked it to # repeat it twice. I would have gotten the same result with, i.e., # product (enumerate, enumerate). Note that I had to import the # function "product" from the built-in Python module "itertools", # which happens on line 3. Again, you need parentheses to show # which indices are grouped together. # Using stuff like this really helps keep the indentations under # control. Nested loops and conditionals are really slow in Python, # so it's a good idea to combine them using tools like this whenever # possible. hess[i, j] = v_klmn(k, l, m, n, dm1_cirot, tdm1) + v_klmn( l, k, n, m, dm1_cirot, tdm1) - v_klmn( k, l, n, m, dm1_cirot, tdm1) - v_klmn( l, k, m, n, dm1_cirot, tdm1) # MRH: print some diagnostic stuff, but only do the potentially-expensive # diagonalization if the user-specified verbosity is high enough # if log.verbose >= lib.logger.DEBUG: evals, evecs = linalg.eigh(hess) evecs = np.array(evecs) log.info("Hessian eigenvalues: {}".format(evals)) hess1 = hess # print("hess1",hess) # print("evals",evals) for i in range(pairs): if 1E-09 > evals[i] and evals[i] > -1E-09: log.info("Hess is singular!") if evals[i] > 0: neg = False break neg = True log.info("Hess diag is neg? {}".format(neg)) # If the diagonals are positive make them negative: if neg == False: for i in range(pairs): if evals[i] > 0: evals[i] = -evals[i] # Remake the Hessian diag = np.identity(pairs) * evals hess = np.dot(np.dot(evecs, diag), evecs.T) hess2 = hess # print("hess2", hess) # print("difference between hessian", hess2-hess1) # Make T t_add = linalg.solve(hess, -grad) t[:] = 0 t[np.tril_indices(t.shape[0], k=-1)] = t_add t = t - t.T # t = t + t_old # MRH: I don't think you add them. They're expressed in different # bases, and anyway ci_rot already has the effect of t_old in it. On # iteration zero, say ci_rot is called ci0. Then on iteration 1, it's # ci1 = expm (t1) ci0 # Then on iteration 2, it's # ci2 = expm (t2) ci1 = expm (t2) expm (t1) ci0 # and so forth. So you don't need to keep the running sum. t_old = t.copy() # Reset Old Values ci_old = ci_rot e_coul_old = e_coul_new if grad_norm < thrs and neg == True: conv = True break ######################### # End Loop if conv: log.note("CMS-PDFT intermediate state determination CONVERGED") else: log.note(("CMS-PDFT intermediate state determination did not converge" " after {} cycles").format(it)) # Intermediate Energies # Run MC-PDFT #mc.ci = ci_final #E_int = np.zeros((nroots)) #with lib.temporary_env (mc, ci=ci_rot): # # This ^ ~temporarily sets mc.ci to ci_rot # # As soon as you leave this indent block, it returns to # # whatever it was before. Convenient! Of course, it would # # be WAY BETTER for me to just implement ci as a kwarg # # in mcpdft.kernel. # for i in range(nroots): # E_int [i]= mcpdft.mcpdft.kernel(mc,mc.otfnal,root=i)[0] E_int = np.asarray( [mcpdft.mcpdft.kernel(mc, ot=mc.otfnal, ci=c)[0] for c in ci_rot]) log.info("CMS-PDFT intermediate state energies: {}".format(E_int)) #Compute the full Hamiltonian h1, h0 = mc.get_h1eff() h2 = mc.get_h2eff() h2eff = direct_spin1.absorb_h1e(h1, h2, mc.ncas, mc.nelecas, 0.5) hc_all = [ direct_spin1.contract_2e(h2eff, c, mc.ncas, mc.nelecas) for c in ci_rot ] Ham = np.tensordot(ci_rot, hc_all, axes=((1, 2), (1, 2))) # print ("ham", Ham) for i in range(nroots): Ham[i, i] = E_int[i] # print("ham",Ham) log.info("Effective hamiltonian: {}".format(Ham)) e_cms, e_vecs = linalg.eigh(Ham) # print("e_cms", e_cms) log.info("CMS-PDFT final state energies: {}".format(e_cms)) return conv, E_int, ci_rot