Пример #1
0
def get_init_guess(norb,
                   nelec,
                   nroots,
                   hdiag_csf,
                   smult,
                   csd_mask,
                   wfnsym_str=None,
                   idx_sym=None):
    ''' The existing _get_init_guess function will work in the csf basis if I pass it with na, nb = ncsf, 1. This might change in future PySCF versions though. 

    ...For point-group symmetry, I pass the direct_spin1.py version of _get_init_guess with na, nb = ncsf_sym, 1 and hdiag_csf including only csfs of the right point-group symmetry.
    This should clean up the symmetry-breaking "noise" in direct_spin1_symm.py! '''
    neleca, nelecb = _unpack_nelec(nelec)
    ncsf_tot = count_all_csfs(norb, neleca, nelecb, smult)
    if idx_sym is None:
        ncsf_sym = ncsf_tot
        ci = _get_init_guess(ncsf_sym, 1, nroots, hdiag_csf)
    else:
        ncsf_sym = np.count_nonzero(idx_sym)
        assert (
            ncsf_sym >= nroots
        ), "Can't find {} roots among only {} CSFs of symmetry {}".format(
            nroots, ncsf_sym, wfnsym_str)
        ci = _get_init_guess(ncsf_sym, 1, nroots, hdiag_csf[idx_sym])
    ci = unpack_sym_ci(ci, idx_sym)
    ci = transform_civec_csf2det(ci,
                                 norb,
                                 neleca,
                                 nelecb,
                                 smult,
                                 csd_mask=csd_mask)[0]
    return ci
Пример #2
0
def make_hdiag_csf (h1e, eri, norb, nelec, transformer, hdiag_det=None):
    smult = transformer.smult
    if hdiag_det is None:
        hdiag_det = make_hdiag_det (None, h1e, eri, norb, nelec)
    eri = ao2mo.restore(1, eri, norb)
    tlib = wlib = 0
    neleca, nelecb = _unpack_nelec (nelec)
    min_npair, npair_csd_offset, npair_dconf_size, npair_sconf_size, npair_sdet_size = get_csdaddrs_shape (norb, neleca, nelecb)
    _, npair_csf_offset, _, _, npair_csf_size = get_csfvec_shape (norb, neleca, nelecb, smult)
    npair_econf_size = npair_dconf_size * npair_sconf_size
    max_npair = min (neleca, nelecb)
    ncsf_all = count_all_csfs (norb, neleca, nelecb, smult)
    ndeta_all = cistring.num_strings(norb, neleca)
    ndetb_all = cistring.num_strings(norb, nelecb)
    ndet_all = ndeta_all * ndetb_all
    hdiag_csf = np.ascontiguousarray (np.zeros (ncsf_all, dtype=np.float64))
    hdiag_csf_check = np.ones (ncsf_all, dtype=np.bool)
    for npair in range (min_npair, max_npair+1):
        ipair = npair - min_npair
        nconf = npair_econf_size[ipair]
        ndet = npair_sdet_size[ipair]
        ncsf = npair_csf_size[ipair]
        if ncsf == 0:
            continue
        nspin = neleca + nelecb - 2*npair
        csd_offset = npair_csd_offset[ipair]
        csf_offset = npair_csf_offset[ipair]
        hdiag_conf = np.ascontiguousarray (np.zeros ((nconf, ndet, ndet), dtype=np.float64))
        det_addr = transformer.csd_mask[csd_offset:][:nconf*ndet]
        if ndet == 1:
            # Closed-shell singlets
            assert (ncsf == 1)
            hdiag_csf[csf_offset:][:nconf] = hdiag_det[det_addr.flat]
            hdiag_csf_check[csf_offset:][:nconf] = False
            continue
        det_addra, det_addrb = divmod (det_addr, ndetb_all)
        det_stra = np.ascontiguousarray (cistring.addrs2str (norb, neleca, det_addra).reshape (nconf, ndet, order='C'))
        det_strb = np.ascontiguousarray (cistring.addrs2str (norb, nelecb, det_addrb).reshape (nconf, ndet, order='C'))
        det_addr = det_addr.reshape (nconf, ndet, order='C')
        hdiag_conf = np.ascontiguousarray (np.zeros ((nconf, ndet, ndet), dtype=np.float64))
        hdiag_conf_det = np.ascontiguousarray (hdiag_det[det_addr], dtype=np.float64)
        t1 = time.process_time ()
        w1 = time.time ()
        libcsf.FCICSFhdiag (hdiag_conf.ctypes.data_as (ctypes.c_void_p),
                            hdiag_conf_det.ctypes.data_as (ctypes.c_void_p),
                            eri.ctypes.data_as (ctypes.c_void_p),
                            det_stra.ctypes.data_as (ctypes.c_void_p),
                            det_strb.ctypes.data_as (ctypes.c_void_p),
                            ctypes.c_uint (norb), ctypes.c_uint (nconf), ctypes.c_uint (ndet))
        tlib += time.process_time () - t1
        wlib += time.time () - w1
        umat = get_spin_evecs (nspin, neleca, nelecb, smult)
        hdiag_conf = np.tensordot (hdiag_conf, umat, axes=1)
        hdiag_conf *= umat[np.newaxis,:,:]
        hdiag_csf[csf_offset:][:nconf*ncsf] = hdiag_conf.sum (1).ravel (order='C')
        hdiag_csf_check[csf_offset:][:nconf*ncsf] = False
    assert (np.count_nonzero (hdiag_csf_check) == 0), np.count_nonzero (hdiag_csf_check)
    #print ("Time in hdiag_csf library: {}, {}".format (tlib, wlib))
    return hdiag_csf
Пример #3
0
def kernel(fci, h1e, eri, norb, nelec, smult=None, idx_sym=None, ci0=None,
           tol=None, lindep=None, max_cycle=None, max_space=None,
           nroots=None, davidson_only=None, pspace_size=None, max_memory=None,
           orbsym=None, wfnsym=None, ecore=0, transformer=None, **kwargs):
    t0 = (time.process_time (), time.time ())
    if 'verbose' in kwargs:
        verbose = kwargs['verbose']
        kwargs.pop ('verbose')
    else: verbose = lib.logger.Logger (stdout=fci.stdout, verbose=fci.verbose)
    if (isinstance (verbose, lib.logger.Logger) and verbose.verbose >= lib.logger.WARN) or (isinstance (verbose, int) and verbose >= lib.logger.WARN):
        fci.check_sanity()
    if nroots is None: nroots = fci.nroots
    if pspace_size is None: pspace_size = fci.pspace_size
    if davidson_only is None: davidson_only = fci.davidson_only
    if transformer is None: transformer = fci.transformer
    nelec = _unpack_nelec(nelec, fci.spin)
    neleca, nelecb = nelec
    t0 = lib.logger.timer (fci, "csf.kernel: throat-clearing", *t0)
    hdiag_det = fci.make_hdiag (h1e, eri, norb, nelec)
    t0 = lib.logger.timer (fci, "csf.kernel: hdiag_det", *t0)
    hdiag_csf = fci.make_hdiag_csf (h1e, eri, norb, nelec, hdiag_det=hdiag_det)
    t0 = lib.logger.timer (fci, "csf.kernel: hdiag_csf", *t0)
    ncsf_all = count_all_csfs (norb, neleca, nelecb, smult)
    if idx_sym is None:
        ncsf_sym = ncsf_all
    else:
        ncsf_sym = np.count_nonzero (idx_sym)
    nroots = min(ncsf_sym, nroots)
    if nroots is not None:
        assert (ncsf_sym >= nroots), "Can't find {} roots among only {} CSFs".format (nroots, ncsf_sym)
    link_indexa, link_indexb = _unpack(norb, nelec, None)
    na = link_indexa.shape[0]
    nb = link_indexb.shape[0]

    t0 = lib.logger.timer (fci, "csf.kernel: throat-clearing", *t0)
    addr, h0 = fci.pspace(h1e, eri, norb, nelec, idx_sym=idx_sym, hdiag_det=hdiag_det, hdiag_csf=hdiag_csf, npsp=max(pspace_size,nroots))
    lib.logger.debug (fci, 'csf.kernel: error of hdiag_csf: %s', np.amax (np.abs (hdiag_csf[addr]-np.diag (h0))))
    t0 = lib.logger.timer (fci, "csf.kernel: make pspace", *t0)
    if pspace_size > 0:
        pw, pv = fci.eig (h0)
    else:
        pw = pv = None

    if pspace_size >= ncsf_sym and not davidson_only:
        if ncsf_sym == 1:
            civec = transformer.vec_csf2det (pv[:,0].reshape (1,1))
            return pw[0]+ecore, civec
        elif nroots > 1:
            civec = np.empty((nroots,ncsf_all))
            civec[:,addr] = pv[:,:nroots].T
            civec = transformer.vec_csf2det (civec)
            return pw[:nroots]+ecore, [c.reshape(na,nb) for c in civec]
        elif abs(pw[0]-pw[1]) > 1e-12:
            civec = np.empty((ncsf_all))
            civec[addr] = pv[:,0]
            civec = transformer.vec_csf2det (civec)
            return pw[0]+ecore, civec.reshape(na,nb)

    t0 = lib.logger.timer (fci, "csf.kernel: throat-clearing", *t0)
    if idx_sym is None:
        precond = fci.make_precond(hdiag_csf, pw, pv, addr)
    else:
        addr_bool = np.zeros (ncsf_all, dtype=np.bool)
        addr_bool[addr] = True
        precond = fci.make_precond(hdiag_csf[idx_sym], pw, pv, addr_bool[idx_sym])
    t0 = lib.logger.timer (fci, "csf.kernel: make preconditioner", *t0)
    '''
    fci.eci, fci.ci = \
            kernel_ms1(fci, h1e, eri, norb, nelec, ci0, None,
                       tol, lindep, max_cycle, max_space, nroots,
                       davidson_only, pspace_size, ecore=ecore, **kwargs)
    '''
    h2e = fci.absorb_h1e(h1e, eri, norb, nelec, .5)
    t0 = lib.logger.timer (fci, "csf.kernel: h2e", *t0)
    def hop(x):
        x_det = transformer.vec_csf2det (x)
        hx = fci.contract_2e(h2e, x_det, norb, nelec, (link_indexa,link_indexb))
        return transformer.vec_det2csf (hx, normalize=False).ravel ()

    t0 = lib.logger.timer (fci, "csf.kernel: make hop", *t0)
    if ci0 is None:
        if hasattr(fci, 'get_init_guess'):
            def ci0 ():
                return transformer.vec_det2csf (fci.get_init_guess(norb, nelec, nroots, hdiag_csf))
                
                    
        else:
            def ci0():  # lazy initialization to reduce memory footprint
                x0 = []
                for i in range(nroots):
                    x = np.zeros(ncsf_sym)
                    x[addr[i]] = 1
                    x0.append(x)
                return x0
    else:
        if isinstance(ci0, np.ndarray) and ci0.size == na*nb:
            ci0 = [transformer.vec_det2csf (ci0.ravel ())]
        else:
            nrow = len (ci0)
            ci0 = np.asarray (ci0).reshape (nrow, -1, order='C')
            ci0 = np.ascontiguousarray (ci0)
            ci0 = transformer.vec_det2csf (ci0.ravel ())
            ci0 = [c for c in ci0.reshape (nrow, -1)]
    t0 = lib.logger.timer (fci, "csf.kernel: ci0 handling", *t0)

    if tol is None: tol = fci.conv_tol
    if lindep is None: lindep = fci.lindep
    if max_cycle is None: max_cycle = fci.max_cycle
    if max_space is None: max_space = fci.max_space
    if max_memory is None: max_memory = fci.max_memory
    tol_residual = getattr(fci, 'conv_tol_residual', None)

    #with lib.with_omp_threads(fci.threads):
        #e, c = lib.davidson(hop, ci0, precond, tol=fci.conv_tol, lindep=fci.lindep)
    e, c = fci.eig(hop, ci0, precond, tol=tol, lindep=lindep,
                       max_cycle=max_cycle, max_space=max_space, nroots=nroots,
                       max_memory=max_memory, verbose=verbose, follow_state=True,
                       tol_residual=tol_residual, **kwargs)
    t0 = lib.logger.timer (fci, "csf.kernel: running fci.eig", *t0)
    c = transformer.vec_csf2det (c, order='C')
    t0 = lib.logger.timer (fci, "csf.kernel: transforming final ci vector", *t0)
    if nroots > 1:
        return e+ecore, [ci.reshape(na,nb) for ci in c]
    else:
        return e+ecore, c.reshape(na,nb)
Пример #4
0
def make_hdiag_csf_slower (h1e, eri, norb, nelec, transformer, hdiag_det=None):
    ''' This is tricky because I need the diagonal blocks for each configuration in order to get
    the correct csf hdiag values, not just the diagonal elements for each determinant. '''
    smult = transformer.smult
    t0, w0 = time.process_time (), time.time ()
    tstr = tlib = tloop = wstr = wlib = wloop = 0
    if hdiag_det is None:
        hdiag_det = make_hdiag_det (None, h1e, eri, norb, nelec)
    eri = ao2mo.restore(1, eri, norb)
    neleca, nelecb = _unpack_nelec (nelec)
    min_npair, npair_csd_offset, npair_dconf_size, npair_sconf_size, npair_sdet_size = get_csdaddrs_shape (norb, neleca, nelecb)
    _, npair_csf_offset, _, _, npair_csf_size = get_csfvec_shape (norb, neleca, nelecb, smult)
    npair_econf_size = npair_dconf_size * npair_sconf_size
    max_npair = min (neleca, nelecb)
    ncsf_all = count_all_csfs (norb, neleca, nelecb, smult)
    ndeta_all = cistring.num_strings(norb, neleca)
    ndetb_all = cistring.num_strings(norb, nelecb)
    ndet_all = ndeta_all * ndetb_all
    hdiag_csf = np.ascontiguousarray (np.zeros (ncsf_all, dtype=np.float64))
    hdiag_csf_check = np.ones (ncsf_all, dtype=np.bool)
    for npair in range (min_npair, max_npair+1):
        ipair = npair - min_npair
        nconf = npair_econf_size[ipair]
        ndet = npair_sdet_size[ipair]
        ncsf = npair_csf_size[ipair]
        if ncsf == 0:
            continue
        nspin = neleca + nelecb - 2*npair
        csd_offset = npair_csd_offset[ipair]
        csf_offset = npair_csf_offset[ipair]
        hdiag_conf = np.ascontiguousarray (np.zeros ((nconf, ndet, ndet), dtype=np.float64))
        det_addr = transformer.csd_mask[csd_offset:][:nconf*ndet]
        if ndet == 1:
            # Closed-shell singlets
            assert (ncsf == 1)
            hdiag_csf[csf_offset:][:nconf] = hdiag_det[det_addr.flat]
            hdiag_csf_check[csf_offset:][:nconf] = False
            continue
        umat = get_spin_evecs (nspin, neleca, nelecb, smult)
        det_addra, det_addrb = divmod (det_addr, ndetb_all)
        t1, w1 = time.process_time (), time.time ()
        det_stra = cistring.addrs2str (norb, neleca, det_addra).reshape (nconf, ndet, order='C')
        det_strb = cistring.addrs2str (norb, nelecb, det_addrb).reshape (nconf, ndet, order='C')
        tstr += time.process_time () - t1
        wstr += time.time () - w1
        det_addr = det_addr.reshape (nconf, ndet, order='C')
        diag_idx = np.diag_indices (ndet)
        triu_idx = np.triu_indices (ndet)   
        ipair_check = 0
        # It looks like the library call below is, itself, usually responsible for about 50% of the
        # clock and wall time that this function consumes.
        t1, w1 = time.process_time (), time.time ()
        for iconf in range (nconf):
            addr = det_addr[iconf]
            assert (len (addr) == ndet)
            stra = det_stra[iconf]
            strb = det_strb[iconf]
            t2, w2 = time.process_time (), time.time ()
            libfci.FCIpspace_h0tril(hdiag_conf[iconf].ctypes.data_as(ctypes.c_void_p),
                h1e.ctypes.data_as(ctypes.c_void_p),
                eri.ctypes.data_as(ctypes.c_void_p),
                stra.ctypes.data_as(ctypes.c_void_p),
                strb.ctypes.data_as(ctypes.c_void_p),
                ctypes.c_int(norb), ctypes.c_int(ndet))
            tlib += time.process_time () - t2
            wlib += time.time () - w2
            #hdiag_conf[iconf][diag_idx] = hdiag_det[addr]
            #hdiag_conf[iconf] = lib.hermi_triu(hdiag_conf[iconf])
        for iconf in range (nconf): hdiag_conf[iconf] = lib.hermi_triu (hdiag_conf[iconf])
        for iconf in range (nconf): hdiag_conf[iconf][diag_idx] = hdiag_det[det_addr[iconf]]
        tloop += time.process_time () - t1
        wloop += time.time () - w1

        hdiag_conf = np.tensordot (hdiag_conf, umat, axes=1)
        hdiag_conf = (hdiag_conf * umat[np.newaxis,:,:]).sum (1)
        hdiag_csf[csf_offset:][:nconf*ncsf] = hdiag_conf.ravel (order='C')
        hdiag_csf_check[csf_offset:][:nconf*ncsf] = False
    assert (np.count_nonzero (hdiag_csf_check) == 0), np.count_nonzero (hdiag_csf_check)
    #print ("Total time in hdiag_csf: {}, {}".format (time.process_time () - t0, time.time () - w0))
    #print ("    Loop: {}, {}".format (tloop, wloop))
    #print ("    Library: {}, {}".format (tlib, wlib))
    #print ("    Cistring: {}, {}".format (tstr, wstr))
    return hdiag_csf