Пример #1
0
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
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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))
Пример #6
0
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
Пример #7
0
 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)
Пример #8
0
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
Пример #9
0
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
Пример #10
0
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))
Пример #11
0
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)
Пример #12
0
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
Пример #13
0
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())
Пример #14
0
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)
Пример #15
0
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)
Пример #16
0
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
Пример #17
0
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
Пример #18
0
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
Пример #19
0
 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)
Пример #20
0
    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
Пример #21
0
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
Пример #22
0
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
Пример #23
0
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
Пример #24
0
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())
Пример #25
0
 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)
Пример #26
0
 def absorb_h1e(self, h1e, eri, norb, nelec, fac=1):
     return direct_spin1.absorb_h1e(h1e, eri, norb, nelec, fac)
Пример #27
0
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)
Пример #28
0
def absorb_h1e(*args, **kwargs):
    return direct_spin1.absorb_h1e(*args, **kwargs)
Пример #29
0
 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)
Пример #30
0
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())
Пример #31
0
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)
Пример #32
0
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)
Пример #33
0
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)
Пример #34
0
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))
Пример #35
0
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())
Пример #36
0
 def absorb_h1e(self, h1e, eri, norb, nelec, fac=1):
     return direct_spin1.absorb_h1e(h1e, eri, norb, nelec, fac)
Пример #37
0
    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)
Пример #38
0
    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)
Пример #39
0
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