Exemple #1
0
def get_subspace_symmetry_blocks(the_subspace,
                                 the_blocks,
                                 atol=params.num_zero_atol,
                                 rtol=params.num_zero_rtol):
    c2p = np.asarray(the_subspace)
    new_blocks = []
    remaining_space = None
    for idx, c2s in enumerate(the_blocks):
        s2c = c2s.conjugate().T
        s2p = s2c @ c2p
        svals, p2s = matrix_svd_control_options(s2p,
                                                rspace=remaining_space,
                                                only_nonzero_vals=True,
                                                full_matrices=True,
                                                sort_vecs=-1,
                                                num_zero_atol=rtol)[1:3]
        assert (
            np.all(np.isclose(svals, 1, atol=atol, rtol=rtol))
        ), 'Subspace may not be symmetry-adapted: svals for {}th block: {}'.format(
            idx, svals)
        new_blocks.append(p2s[:, :len(svals)])
        remaining_space = p2s[:, len(svals):]
    p2s = np.concatenate(new_blocks, axis=1)
    assert (is_basis_orthonormal_and_complete(p2s)
            ), measure_basis_nonorthonormality(p2s)
    return new_blocks
Exemple #2
0
def analyze_operator_blockbreaking(the_operator,
                                   the_blocks,
                                   block_labels=None):
    if block_labels is None:
        block_labels = np.arange(len(the_blocks), dtype=int)
    if isinstance(the_blocks[0], np.ndarray):
        c2s = np.concatenate(the_blocks, axis=1)
        assert (is_basis_orthonormal_and_complete(c2s)
                ), "Symmetry block problem? Not a complete, orthonormal basis."
        blocked_operator = represent_operator_in_basis(the_operator, c2s)
        blocked_idx = np.concatenate([[
            idx,
        ] * blk.shape[1] for idx, blk in enumerate(the_blocks)])
        c2l, op_svals, c2r = analyze_operator_blockbreaking(
            blocked_operator, blocked_idx, block_labels=block_labels)
        c2l = [c2s @ s2l for s2l in c2l]
        c2r = [c2s @ s2r for s2r in c2r]
        return c2l, op_svals, c2r
    elif np.asarray(the_blocks).dtype == np.asarray(block_labels).dtype:
        the_indices = np.empty(len(the_blocks), dtype=int)
        for idx, lbl in enumerate(block_labels):
            idx_indices = (the_blocks == lbl)
            the_indices[idx_indices] = idx
        the_blocks = the_indices
    c2l = []
    c2r = []
    op_svals = []
    norbs = the_operator.shape[0]
    my_range = [
        idx for idx, bl in enumerate(block_labels) if idx in the_blocks
    ]
    for idx1, idx2 in combinations(my_range, 2):
        blk1 = block_labels[idx1]
        blk2 = block_labels[idx2]
        idx12 = np.ix_(the_blocks == idx1, the_blocks == idx2)
        lvecs = np.eye(norbs, dtype=the_operator.dtype)[:, the_blocks == idx1]
        rvecs = np.eye(norbs, dtype=the_operator.dtype)[:, the_blocks == idx2]
        mat12 = the_operator[idx12]
        if is_matrix_zero(mat12):
            c2l.append(np.zeros((norbs, 0), dtype=the_operator.dtype))
            c2r.append(np.zeros((norbs, 0), dtype=the_operator.dtype))
            op_svals.append(np.zeros((0), dtype=the_operator.dtype))
            continue
        try:
            vecs1, svals, vecs2 = matrix_svd_control_options(
                mat12, sort_vecs=-1, only_nonzero_vals=False)
            lvecs = lvecs @ vecs1
            rvecs = rvecs @ vecs2
        except ValueError as e:
            if the_operator[idx12].size > 0: raise (e)
            c2l.append(np.zeros((norbs, 0), dtype=the_operator.dtype))
            c2r.append(np.zeros((norbs, 0), dtype=the_operator.dtype))
            op_svals.append(np.zeros((0), dtype=the_operator.dtype))
            continue
        #print ("Coupling between {} and {}: {} svals, norm = {}".format (idx1, idx2, len (svals), linalg.norm (svals)))
        c2l.append(lvecs)
        c2r.append(rvecs)
        op_svals.append(svals)
    return c2l, op_svals, c2r
Exemple #3
0
    def dmet_cderi(self, loc2dmet, numAct=None):

        t0 = time.clock()
        w0 = time.time()
        norbs_aux = self.with_df.get_naoaux()
        numAct = loc2dmet.shape[1] if numAct == None else numAct
        loc2imp = loc2dmet[:, :numAct]
        assert (self.with_df is not None), "density fitting required"
        CDERI = np.empty(
            (self.with_df.get_naoaux(), numAct * (numAct + 1) // 2),
            dtype=loc2dmet.dtype)
        full_cderi_size = (norbs_aux * self.mol.nao_nr() *
                           (self.mol.nao_nr() + 1) * CDERI.itemsize // 2) / 1e6
        imp_eri_size = CDERI.itemsize * (
            numAct**4) / 1e6  # Since I don't use symmetry yet
        imp_eri_ideal_size = CDERI.itemsize * (
            numAct * (numAct + 1) // 2
        )**2 / 1e6  # Eightfold symmetry is not practical because ao2mos will have to happen
        imp_cderi_size = CDERI.size * CDERI.itemsize / 1e6
        print(
            "Size comparison: cderi is ({0},{1},{1})->{2:.0f} MB total; eri is ({1},{1},{1},{1})->{3:.0f} MB total ({4:.0f} MB ideal)"
            .format(norbs_aux, numAct, imp_cderi_size, imp_eri_size,
                    imp_eri_ideal_size))
        ao2imp = np.dot(self.ao2loc, loc2imp)
        ijmosym, mij_pair, moij, ijslice = ao2mo.incore._conc_mos(ao2imp,
                                                                  ao2imp,
                                                                  compact=True)
        b0 = 0
        for eri1 in self.with_df.loop():
            b1 = b0 + eri1.shape[0]
            eri2 = CDERI[b0:b1]
            eri2 = ao2mo._ao2mo.nr_e2(eri1,
                                      moij,
                                      ijslice,
                                      aosym='s2',
                                      mosym=ijmosym,
                                      out=eri2)
            b0 = b1
        t1 = time.clock()
        w1 = time.time()
        print(("({0}, {1}) seconds to turn {2:.0f}-MB full"
               "cderi array into {3:.0f}-MP impurity cderi array").format(
                   t1 - t0, w1 - w0, full_cderi_size, imp_cderi_size))
        sigma, vmat = matrix_svd_control_options(
            CDERI,
            sort_vecs=-1,
            only_nonzero_vals=True,
            full_matrices=False,
            num_zero_atol=sqrt(LINEAR_DEP_THR))[1:]
        imp_cderi_size = vmat.size * vmat.itemsize / 1e6
        print(
            "With SVD: {0:.0f}-MB CDERI array, compared to {1:.0f}-MB ideal eri; ({2}, {3}) seconds"
            .format(imp_cderi_size, imp_eri_ideal_size,
                    time.clock() - t1,
                    time.time() - w1))
        CDERI = np.ascontiguousarray((vmat * sigma).T)
        return CDERI
Exemple #4
0
 def _svd (self, mo_lspace, mo_rspace, s=None, **kwargs):
     if s is None: s = self._scf.get_ovlp ()
     lsymm = getattr (mo_lspace, 'orbsym', None)
     if lsymm is None:
         mo_lspace = symm.symmetrize_space (self.mol, mo_lspace)
         lsymm = symm.label_orb_symm(self.mol, self.mol.irrep_id,
             self.mol.symm_orb, mo_lspace, s=s)
     rsymm = getattr (mo_rspace, 'orbsym', None)
     if rsymm is None:
         mo_rspace = symm.symmetrize_space (self.mol, mo_rspace)
         rsymm = symm.label_orb_symm(self.mol, self.mol.irrep_id,
             self.mol.symm_orb, mo_rspace, s=s)
     decomp = matrix_svd_control_options (s,
         lspace=mo_lspace, rspace=mo_rspace, 
         lspace_symmetry=lsymm, rspace_symmetry=rsymm,
         full_matrices=True, strong_symm=True)
     mo_lvecs, svals, mo_rvecs, lsymm, rsymm = decomp
     mo_lvecs = tag_array (mo_lvecs, orbsym=lsymm)
     mo_rvecs = tag_array (mo_rvecs, orbsym=rsymm)
     return mo_lvecs, svals, mo_rvecs
Exemple #5
0
def get_overlapping_states (bra_basis, ket_basis, across_operator=None, inner_symmetry=None, outer_symmetry=(None, None), enforce_symmetry=False,
        max_nrvecs=0, max_nlvecs=0, num_zero_atol=params.num_zero_atol, only_nonzero_vals=True, full_matrices=False):
    c2p = np.asarray (bra_basis)
    c2q = np.asarray (ket_basis)
    cOc = 1 if across_operator is None else np.asarray (across_operator)
    assert (c2p.shape[0] == c2q.shape[0]), "you need to give the two spaces in the same basis"
    assert (c2p.shape[1] <= c2p.shape[0]), "you need to give the first state in a complete basis (c2p). Did you accidentally transpose it?"
    assert (c2q.shape[1] <= c2q.shape[0]), "you need to give the second state in a complete basis (c2q). Did you accidentally transpose it?"
    assert (max_nlvecs <= c2p.shape[1]), "you can't ask for more left states than are in your left space"
    assert (max_nrvecs <= c2q.shape[1]), "you can't ask for more right states than are in your right space"
    if np.any (across_operator):
        assert (c2p.shape[0] == cOc.shape[0] and c2p.shape[0] == cOc.shape[1]), "when specifying an across_operator, it's dimensions need to be the same as the external basis"
    get_labels = (not (inner_symmetry is None)) or (not (outer_symmetry[0] is None)) or (not (outer_symmetry[1] is None))

    rets = matrix_svd_control_options (cOc, lspace=c2p, rspace=c2q, full_matrices=full_matrices,
        symmetry=inner_symmetry,
        lspace_symmetry=outer_symmetry[0],
        rspace_symmetry=outer_symmetry[1],
        strong_symm=enforce_symmetry,
        sort_vecs=-1, only_nonzero_vals=only_nonzero_vals, num_zero_atol=num_zero_atol)

    c2l, svals, c2r = rets[:3]
    if get_labels: llab, rlab = rets[3:]

    # Truncate the basis if requested
    max_nlvecs = max_nlvecs or c2l.shape[1]
    max_nrvecs = max_nrvecs or c2r.shape[1]

    # But you can't truncate it smaller than it already is
    max_nlvecs = min (max_nlvecs, c2l.shape[1])
    max_nrvecs = min (max_nrvecs, c2r.shape[1])
    c2l = c2l[:,:max_nlvecs]
    c2r = c2r[:,:max_nrvecs]

    if get_labels: return c2l, c2r, svals, llab, rlab
    return c2l, c2r, svals
Exemple #6
0
 def _svd (self, mo_lspace, mo_rspace, s=None, **kwargs):
     if s is None: s = self._scf.get_ovlp ()
     return matrix_svd_control_options (s, lspace=mo_lspace, rspace=mo_rspace, full_matrices=True)[:3]
Exemple #7
0
def solve (frag, guess_1RDM, chempot_imp):

    # Augment OEI with the chemical potential
    OEI = frag.impham_OEI_C - chempot_imp

    # Do I need to get the full RHF solution?
    guess_orbs_av = len (frag.imp_cache) == 2 or frag.norbs_as > 0 

    # Get the RHF solution
    mol = gto.Mole()
    abs_2MS = int (round (2 * abs (frag.target_MS)))
    abs_2S = int (round (2 * abs (frag.target_S)))
    sign_MS = int (np.sign (frag.target_MS)) or 1
    mol.spin = abs_2MS
    mol.verbose = 0 
    if frag.mol_stdout is None:
        mol.output = frag.mol_output
        mol.verbose = 0 if frag.mol_output is None else lib.logger.DEBUG
    mol.atom.append(('H', (0, 0, 0)))
    mol.nelectron = frag.nelec_imp
    if frag.enforce_symmetry:
        mol.groupname  = frag.symmetry
        mol.symm_orb   = get_subspace_symmetry_blocks (frag.loc2imp, frag.loc2symm)
        mol.irrep_name = frag.ir_names
        mol.irrep_id   = frag.ir_ids
    mol.max_memory = frag.ints.max_memory
    mol.build ()
    if frag.mol_stdout is None:
        frag.mol_stdout = mol.stdout
    else:
        mol.stdout = frag.mol_stdout
        mol.verbose = 0 if frag.mol_output is None else lib.logger.DEBUG
    if frag.enforce_symmetry: mol.symmetry = True
    #mol.incore_anyway = True
    mf = scf.RHF(mol)
    mf.get_hcore = lambda *args: OEI
    mf.get_ovlp = lambda *args: np.eye(frag.norbs_imp)
    mf.energy_nuc = lambda *args: frag.impham_CONST
    if frag.impham_CDERI is not None:
        mf = mf.density_fit ()
        mf.with_df._cderi = frag.impham_CDERI
    else:
        mf._eri = ao2mo.restore(8, frag.impham_TEI, frag.norbs_imp)
    mf = fix_my_RHF_for_nonsinglet_env (mf, frag.impham_OEI_S)
    mf.__dict__.update (frag.mf_attr)
    if guess_orbs_av: mf.max_cycle = 2
    mf.scf (guess_1RDM)
    if (not mf.converged) and (not guess_orbs_av):
        if np.any (np.abs (frag.impham_OEI_S) > 1e-8) and mol.spin != 0:
            raise NotImplementedError('Gradient and Hessian fixes for nonsinglet environment of Newton-descent ROHF algorithm')
        print ("CASSCF RHF-step not converged on fixed-point iteration; initiating newton solver")
        mf = mf.newton ()
        mf.kernel ()

    # Instability check and repeat
    if not guess_orbs_av:
        for i in range (frag.num_mf_stab_checks):
            if np.any (np.abs (frag.impham_OEI_S) > 1e-8) and mol.spin != 0:
                raise NotImplementedError('ROHF stability-check fixes for nonsinglet environment')
            mf.mo_coeff = mf.stability ()[0]
            guess_1RDM = mf.make_rdm1 ()
            mf = scf.RHF(mol)
            mf.get_hcore = lambda *args: OEI
            mf.get_ovlp = lambda *args: np.eye(frag.norbs_imp)
            mf._eri = ao2mo.restore(8, frag.impham_TEI, frag.norbs_imp)
            mf = fix_my_RHF_for_nonsinglet_env (mf, frag.impham_OEI_S)
            mf.scf (guess_1RDM)
            if not mf.converged:
                mf = mf.newton ()
                mf.kernel ()

    E_RHF = mf.e_tot
    print ("CASSCF RHF-step energy: {}".format (E_RHF))

    # Get the CASSCF solution
    CASe = frag.active_space[0]
    CASorb = frag.active_space[1] 
    checkCAS =  (CASe <= frag.nelec_imp) and (CASorb <= frag.norbs_imp)
    if (checkCAS == False):
        CASe = frag.nelec_imp
        CASorb = frag.norbs_imp
    if (abs_2MS > abs_2S):
        CASe = ((CASe + sign_MS * abs_2S) // 2, (CASe - sign_MS * abs_2S) // 2)
    else:
        CASe = ((CASe + sign_MS * abs_2MS) // 2, (CASe - sign_MS * abs_2MS) // 2)
    if frag.impham_CDERI is not None:
        mc = mcscf.DFCASSCF(mf, CASorb, CASe)
    else:
        mc = mcscf.CASSCF(mf, CASorb, CASe)
    smult = abs_2S + 1 if frag.target_S is not None else (frag.nelec_imp % 2) + 1
    mc.fcisolver = csf_solver (mf.mol, smult, symm=frag.enforce_symmetry)
    if frag.enforce_symmetry: mc.fcisolver.wfnsym = frag.wfnsym
    mc.max_cycle_macro = 50 if frag.imp_maxiter is None else frag.imp_maxiter
    mc.conv_tol = min (1e-9, frag.conv_tol_grad**2)  
    mc.ah_start_tol = mc.conv_tol / 10
    mc.ah_conv_tol = mc.conv_tol / 10
    mc.__dict__.update (frag.corr_attr)
    mc = fix_my_CASSCF_for_nonsinglet_env (mc, frag.impham_OEI_S)
    norbs_amo = mc.ncas
    norbs_cmo = mc.ncore
    norbs_imo = frag.norbs_imp - norbs_amo
    nelec_amo = sum (mc.nelecas)
    norbs_occ = norbs_amo + norbs_cmo
    #mc.natorb = True

    # Guess orbitals
    ci0 = None
    dm_imp = frag.get_oneRDM_imp ()
    fock_imp = mf.get_fock (dm=dm_imp)
    if len (frag.imp_cache) == 2:
        imp2mo, ci0 = frag.imp_cache
        print ("Taking molecular orbitals and ci vector from cache")
    elif frag.norbs_as > 0:
        nelec_imp_guess = int (round (np.trace (frag.oneRDMas_loc)))
        norbs_cmo_guess = (frag.nelec_imp - nelec_imp_guess) // 2
        print ("Projecting stored amos (frag.loc2amo; spanning {} electrons) onto the impurity basis and filling the remainder with default guess".format (nelec_imp_guess))
        imp2mo, my_occ = project_amo_manually (frag.loc2imp, frag.loc2amo, fock_imp, norbs_cmo_guess, dm=frag.oneRDMas_loc)
    elif frag.loc2amo_guess is not None:
        print ("Projecting stored amos (frag.loc2amo_guess) onto the impurity basis (no amo dm available)")
        imp2mo, my_occ = project_amo_manually (frag.loc2imp, frag.loc2amo_guess, fock_imp, norbs_cmo, dm=None)
        frag.loc2amo_guess = None
    else:
        dm_imp = np.asarray (mf.make_rdm1 ())
        while dm_imp.ndim > 2:
            dm_imp = dm_imp.sum (0)
        imp2mo = mf.mo_coeff
        fock_imp = mf.get_fock (dm=dm_imp)
        fock_mo = represent_operator_in_basis (fock_imp, imp2mo)
        _, evecs = matrix_eigen_control_options (fock_mo, sort_vecs=1)
        imp2mo = imp2mo @ evecs
        my_occ = ((dm_imp @ imp2mo) * imp2mo).sum (0)
        print ("No stored amos; using mean-field canonical MOs as initial guess")
    # Guess orbital processing
    if callable (frag.cas_guess_callback):
        mo = reduce (np.dot, (frag.ints.ao2loc, frag.loc2imp, imp2mo))
        mo = frag.cas_guess_callback (frag.ints.mol, mc, mo)
        imp2mo = reduce (np.dot, (frag.imp2loc, frag.ints.ao2loc.conjugate ().T, frag.ints.ao_ovlp, mo))
        frag.cas_guess_callback = None

    # Guess CI vector
    if len (frag.imp_cache) != 2 and frag.ci_as is not None:
        loc2amo_guess = np.dot (frag.loc2imp, imp2mo[:,norbs_cmo:norbs_occ])
        metric = np.arange (CASorb) + 1
        gOc = np.dot (loc2amo_guess.conjugate ().T, (frag.ci_as_orb * metric[None,:]))
        umat_g, svals, umat_c = matrix_svd_control_options (gOc, sort_vecs=1, only_nonzero_vals=True)
        if (svals.size == norbs_amo):
            print ("Loading ci guess despite shifted impurity orbitals; singular value error sum: {}".format (np.sum (svals - metric)))
            imp2mo[:,norbs_cmo:norbs_occ] = np.dot (imp2mo[:,norbs_cmo:norbs_occ], umat_g)
            ci0 = transform_ci_for_orbital_rotation (frag.ci_as, CASorb, CASe, umat_c)
        else:
            print ("Discarding stored ci guess because orbitals are too different (missing {} nonzero svals)".format (norbs_amo-svals.size))

    # Symmetry align if possible
    imp2unac = frag.align_imporbs_symm (np.append (imp2mo[:,:norbs_cmo], imp2mo[:,norbs_occ:], axis=1), sorting_metric=fock_imp,
        sort_vecs=1, orbital_type='guess unactive', mol=mol)[0]
    imp2mo[:,:norbs_cmo] = imp2unac[:,:norbs_cmo]
    imp2mo[:,norbs_occ:] = imp2unac[:,norbs_cmo:]
    #imp2mo[:,:norbs_cmo] = frag.align_imporbs_symm (imp2mo[:,:norbs_cmo], sorting_metric=fock_imp, sort_vecs=1, orbital_type='guess inactive', mol=mol)[0]
    imp2mo[:,norbs_cmo:norbs_occ], umat = frag.align_imporbs_symm (imp2mo[:,norbs_cmo:norbs_occ], sorting_metric=fock_imp,
        sort_vecs=1, orbital_type='guess active', mol=mol)
    #imp2mo[:,norbs_occ:] = frag.align_imporbs_symm (imp2mo[:,norbs_occ:], sorting_metric=fock_imp, sort_vecs=1, orbital_type='guess external', mol=mol)[0]
    if frag.enforce_symmetry:
        imp2mo = cleanup_subspace_symmetry (imp2mo, mol.symm_orb)
        err_symm = measure_subspace_blockbreaking (imp2mo, mol.symm_orb)
        err_orth = measure_basis_nonorthonormality (imp2mo)
        print ("Initial symmetry error after cleanup = {}".format (err_symm))
        print ("Initial orthonormality error after cleanup = {}".format (err_orth))
    if ci0 is not None: ci0 = transform_ci_for_orbital_rotation (ci0, CASorb, CASe, umat)
        

    # Guess orbital printing
    if frag.mfmo_printed == False and frag.ints.mol.verbose:
        ao2mfmo = reduce (np.dot, [frag.ints.ao2loc, frag.loc2imp, imp2mo])
        print ("Writing {} {} orbital molden".format (frag.frag_name, 'CAS guess'))
        molden.from_mo (frag.ints.mol, frag.filehead + frag.frag_name + '_mfmorb.molden', ao2mfmo, occ=my_occ)
        frag.mfmo_printed = True
    elif len (frag.active_orb_list) > 0: # This is done AFTER everything else so that the _mfmorb.molden always has consistent ordering
        print('Applying caslst: {}'.format (frag.active_orb_list))
        imp2mo = mc.sort_mo(frag.active_orb_list, mo_coeff=imp2mo)
        frag.active_orb_list = []
    if len (frag.frozen_orb_list) > 0:
        mc.frozen = copy.copy (frag.frozen_orb_list)
        print ("Applying frozen-orbital list (this macroiteration only): {}".format (frag.frozen_orb_list))
        frag.frozen_orb_list = []

    if frag.enforce_symmetry: imp2mo = lib.tag_array (imp2mo, orbsym=label_orb_symm (mol, mol.irrep_id, mol.symm_orb, imp2mo, s=mf.get_ovlp (), check=False))

    t_start = time.time()
    E_CASSCF = mc.kernel(imp2mo, ci0)[0]
    if (not mc.converged) and np.all (np.abs (frag.impham_OEI_S) < 1e-8):
        mc = mc.newton ()
        E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0]
    if not mc.converged:
        print ('Assuming ci vector is poisoned; discarding...')
        imp2mo = mc.mo_coeff.copy ()
        mc = mcscf.CASSCF(mf, CASorb, CASe)
        smult = abs_2S + 1 if frag.target_S is not None else (frag.nelec_imp % 2) + 1
        mc.fcisolver = csf_solver (mf.mol, smult)
        E_CASSCF = mc.kernel(imp2mo)[0]
        if not mc.converged:
            if np.any (np.abs (frag.impham_OEI_S) > 1e-8):
                raise NotImplementedError('Gradient and Hessian fixes for nonsinglet environment of Newton-descent CASSCF algorithm')
            mc = mc.newton ()
            E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0]
    assert (mc.converged)

    '''
    mc.conv_tol = 1e-12
    mc.ah_start_tol = 1e-10
    mc.ah_conv_tol = 1e-12
    E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0]
    if not mc.converged:
        mc = mc.newton ()
        E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0]
    #assert (mc.converged)
    '''
    
    # Get twoRDM + oneRDM. cs: MC-SCF core, as: MC-SCF active space
    # I'm going to need to keep some representation of the active-space orbitals

    # Symmetry align if possible
    oneRDM_amo, twoRDM_amo = mc.fcisolver.make_rdm12 (mc.ci, mc.ncas, mc.nelecas)
    fock_imp = mc.get_fock ()
    mc.mo_coeff[:,:norbs_cmo] = frag.align_imporbs_symm (mc.mo_coeff[:,:norbs_cmo], sorting_metric=fock_imp, sort_vecs=1, orbital_type='optimized inactive', mol=mol)[0]
    mc.mo_coeff[:,norbs_cmo:norbs_occ], umat = frag.align_imporbs_symm (mc.mo_coeff[:,norbs_cmo:norbs_occ],
        sorting_metric=oneRDM_amo, sort_vecs=-1, orbital_type='optimized active', mol=mol)
    mc.mo_coeff[:,norbs_occ:] = frag.align_imporbs_symm (mc.mo_coeff[:,norbs_occ:], sorting_metric=fock_imp, sort_vecs=1, orbital_type='optimized external', mol=mol)[0]
    if frag.enforce_symmetry:
        amo2imp = mc.mo_coeff[:,norbs_cmo:norbs_occ].conjugate ().T
        mc.mo_coeff = cleanup_subspace_symmetry (mc.mo_coeff, mol.symm_orb)
        umat = umat @ (amo2imp @ mc.mo_coeff[:,norbs_cmo:norbs_occ])
        err_symm = measure_subspace_blockbreaking (mc.mo_coeff, mol.symm_orb)
        err_orth = measure_basis_nonorthonormality (mc.mo_coeff)
        print ("Final symmetry error after cleanup = {}".format (err_symm))
        print ("Final orthonormality error after cleanup = {}".format (err_orth))
    mc.ci = transform_ci_for_orbital_rotation (mc.ci, CASorb, CASe, umat)

    # Cache stuff
    imp2mo = mc.mo_coeff #mc.cas_natorb()[0]
    loc2mo = np.dot (frag.loc2imp, imp2mo)
    imp2amo = imp2mo[:,norbs_cmo:norbs_occ]
    loc2amo = loc2mo[:,norbs_cmo:norbs_occ]
    frag.imp_cache = [mc.mo_coeff, mc.ci]
    frag.ci_as = mc.ci
    frag.ci_as_orb = loc2amo.copy ()
    t_end = time.time()

    # oneRDM
    oneRDM_imp = mc.make_rdm1 ()

    # twoCDM
    oneRDM_amo, twoRDM_amo = mc.fcisolver.make_rdm12 (mc.ci, mc.ncas, mc.nelecas)
    oneRDMs_amo = np.stack (mc.fcisolver.make_rdm1s (mc.ci, mc.ncas, mc.nelecas), axis=0)
    oneSDM_amo = oneRDMs_amo[0] - oneRDMs_amo[1] if frag.target_MS >= 0 else oneRDMs_amo[1] - oneRDMs_amo[0]
    oneSDM_imp = represent_operator_in_basis (oneSDM_amo, imp2amo.conjugate ().T)
    print ("Norm of spin density: {}".format (linalg.norm (oneSDM_amo)))
    # Note that I do _not_ do the *real* cumulant decomposition; I do one assuming oneSDM_amo = 0.
    # This is fine as long as I keep it consistent, since it is only in the orbital gradients for this impurity that
    # the spin density matters. But it has to stay consistent!
    twoCDM_amo = get_2CDM_from_2RDM (twoRDM_amo, oneRDM_amo)
    twoCDM_imp = represent_operator_in_basis (twoCDM_amo, imp2amo.conjugate ().T)
    print('Impurity CASSCF energy (incl chempot): {}; spin multiplicity: {}; time to solve: {}'.format (E_CASSCF, spin_square (mc)[1], t_end - t_start))

    # Active-space RDM data
    frag.oneRDMas_loc  = symmetrize_tensor (represent_operator_in_basis (oneRDM_amo, loc2amo.conjugate ().T))
    frag.oneSDMas_loc  = symmetrize_tensor (represent_operator_in_basis (oneSDM_amo, loc2amo.conjugate ().T))
    frag.twoCDMimp_amo = twoCDM_amo
    frag.loc2mo  = loc2mo
    frag.loc2amo = loc2amo
    frag.E2_cum  = np.tensordot (ao2mo.restore (1, mc.get_h2eff (), mc.ncas), twoCDM_amo, axes=4) / 2
    frag.E2_cum += (mf.get_k (dm=oneSDM_imp) * oneSDM_imp).sum () / 4
    # The second line compensates for my incorrect cumulant decomposition. Anything to avoid changing the checkpoint files...

    # General impurity data
    frag.oneRDM_loc = frag.oneRDMfroz_loc + symmetrize_tensor (represent_operator_in_basis (oneRDM_imp, frag.imp2loc))
    frag.oneSDM_loc = frag.oneSDMfroz_loc + frag.oneSDMas_loc
    frag.twoCDM_imp = None # Experiment: this tensor is huge. Do I actually need to keep it? In principle, of course not.
    frag.E_imp      = E_CASSCF + np.einsum ('ab,ab->', chempot_imp, oneRDM_imp)

    return None
Exemple #8
0
def solve(frag, guess_1RDM, chempot_imp):

    # Augment OEI with the chemical potential
    OEI = frag.impham_OEI - chempot_imp

    # Do I need to get the full RHF solution?
    guess_orbs_av = len(frag.imp_cache) == 2 or frag.norbs_as > 0

    # Get the RHF solution
    mol = gto.Mole()
    mol.spin = int(round(2 * frag.target_MS))
    mol.verbose = 0 if frag.mol_output is None else lib.logger.DEBUG
    mol.output = frag.mol_output
    mol.atom.append(('H', (0, 0, 0)))
    mol.nelectron = frag.nelec_imp
    mol.build()
    #mol.incore_anyway = True
    mf = scf.RHF(mol)
    mf.get_hcore = lambda *args: OEI
    mf.get_ovlp = lambda *args: np.eye(frag.norbs_imp)
    mf.energy_nuc = lambda *args: frag.impham_CONST
    if frag.impham_CDERI is not None:
        mf = mf.density_fit()
        mf.with_df._cderi = frag.impham_CDERI
    else:
        mf._eri = ao2mo.restore(8, frag.impham_TEI, frag.norbs_imp)
    mf.__dict__.update(frag.mf_attr)
    if guess_orbs_av: mf.max_cycle = 2
    mf.scf(guess_1RDM)
    if (not mf.converged) and (not guess_orbs_av):
        print(
            "CASSCF RHF-step not converged on fixed-point iteration; initiating newton solver"
        )
        mf = mf.newton()
        mf.kernel()

    # Instability check and repeat
    if not guess_orbs_av:
        for i in range(frag.num_mf_stab_checks):
            mf.mo_coeff = mf.stability()[0]
            guess_1RDM = mf.make_rdm1()
            mf = scf.RHF(mol)
            mf.get_hcore = lambda *args: OEI
            mf.get_ovlp = lambda *args: np.eye(frag.norbs_imp)
            mf._eri = ao2mo.restore(8, frag.impham_TEI, frag.norbs_imp)
            mf.scf(guess_1RDM)
            if not mf.converged:
                mf = mf.newton()
                mf.kernel()

    print("CASSCF RHF-step energy: {}".format(mf.e_tot))
    #print(mf.mo_occ)
    '''    
    idx = mf.mo_energy.argsort()
    mf.mo_energy = mf.mo_energy[idx]
    mf.mo_coeff = mf.mo_coeff[:,idx]'''

    # Get the CASSCF solution
    CASe = frag.active_space[0]
    CASorb = frag.active_space[1]
    checkCAS = (CASe <= frag.nelec_imp) and (CASorb <= frag.norbs_imp)
    if (checkCAS == False):
        CASe = frag.nelec_imp
        CASorb = frag.norbs_imp
    if (frag.target_MS > frag.target_S):
        CASe = ((CASe // 2) + frag.target_S, (CASe // 2) - frag.target_S)
    else:
        CASe = ((CASe // 2) + frag.target_MS, (CASe // 2) - frag.target_MS)
    if frag.impham_CDERI is not None:
        mc = mcscf.DFCASSCF(mf, CASorb, CASe)
    else:
        mc = mcscf.CASSCF(mf, CASorb, CASe)
    norbs_amo = mc.ncas
    norbs_cmo = mc.ncore
    norbs_imo = frag.norbs_imp - norbs_amo
    nelec_amo = sum(mc.nelecas)
    norbs_occ = norbs_amo + norbs_cmo
    #mc.natorb = True

    # Guess orbitals
    ci0 = None
    if len(frag.imp_cache) == 2:
        imp2mo, ci0 = frag.imp_cache
        print("Taking molecular orbitals and ci vector from cache")
    elif frag.norbs_as > 0:
        nelec_imp_guess = int(round(np.trace(frag.oneRDMas_loc)))
        norbs_cmo_guess = (frag.nelec_imp - nelec_imp_guess) // 2
        print(
            "Projecting stored amos (frag.loc2amo; spanning {} electrons) onto the impurity basis and filling the remainder with default guess"
            .format(nelec_imp_guess))
        imp2mo, my_occ = project_amo_manually(
            frag.loc2imp,
            frag.loc2amo,
            mf.get_fock(dm=frag.get_oneRDM_imp()),
            norbs_cmo_guess,
            dm=frag.oneRDMas_loc)
    elif frag.loc2amo_guess is not None:
        print(
            "Projecting stored amos (frag.loc2amo_guess) onto the impurity basis (no dm available)"
        )
        imp2mo, my_occ = project_amo_manually(
            frag.loc2imp,
            frag.loc2amo_guess,
            mf.get_fock(dm=frag.get_oneRDM_imp()),
            norbs_cmo,
            dm=None)
        frag.loc2amo_guess = None
    else:
        imp2mo = mc.mo_coeff
        my_occ = mf.mo_occ
        print(
            "No stored amos; using mean-field canonical MOs as initial guess")

    # Guess orbital processing
    if callable(frag.cas_guess_callback):
        mo = reduce(np.dot, (frag.ints.ao2loc, frag.loc2imp, imp2mo))
        mo = frag.cas_guess_callback(frag.ints.mol, mc, mo)
        imp2mo = reduce(np.dot, (frag.imp2loc, frag.ints.ao2loc.conjugate().T,
                                 frag.ints.ao_ovlp, mo))
        frag.cas_guess_callback = None
    elif len(frag.active_orb_list) > 0:
        print('Applying caslst: {}'.format(frag.active_orb_list))
        imp2mo = mc.sort_mo(frag.active_orb_list, mo_coeff=imp2mo)
        frag.active_orb_list = []
    if len(frag.frozen_orb_list) > 0:
        mc.frozen = copy.copy(frag.frozen_orb_list)
        print("Applying frozen-orbital list (this macroiteration only): {}".
              format(frag.frozen_orb_list))
        frag.frozen_orb_list = []

    # Guess orbital printing
    if frag.mfmo_printed == False:
        ao2mfmo = reduce(np.dot, [frag.ints.ao2loc, frag.loc2imp, imp2mo])
        molden.from_mo(frag.ints.mol,
                       frag.filehead + frag.frag_name + '_mfmorb.molden',
                       ao2mfmo,
                       occ=my_occ)
        frag.mfmo_printed = True

    # Guess CI vector
    if len(frag.imp_cache) != 2 and frag.ci_as is not None:
        loc2amo_guess = np.dot(frag.loc2imp, imp2mo[:, norbs_cmo:norbs_occ])
        gOc = np.dot(loc2amo_guess.conjugate().T, frag.ci_as_orb)
        umat_g, svals, umat_c = matrix_svd_control_options(
            gOc, sort_vecs=-1, only_nonzero_vals=True)
        if (svals.size == norbs_amo):
            print(
                "Loading ci guess despite shifted impurity orbitals; singular value sum: {}"
                .format(np.sum(svals)))
            imp2mo[:, norbs_cmo:norbs_occ] = np.dot(
                imp2mo[:, norbs_cmo:norbs_occ], umat_g)
            ci0 = transform_ci_for_orbital_rotation(frag.ci_as, CASorb, CASe,
                                                    umat_c)
        else:
            print(
                "Discarding stored ci guess because orbitals are too different (missing {} nonzero svals)"
                .format(norbs_amo - svals.size))

    t_start = time.time()
    smult = 2 * frag.target_S + 1 if frag.target_S is not None else (
        frag.nelec_imp % 2) + 1
    mc.fcisolver = csf_solver(mf.mol, smult)
    mc.max_cycle_macro = 50 if frag.imp_maxiter is None else frag.imp_maxiter
    mc.ah_start_tol = 1e-10
    mc.ah_conv_tol = 1e-10
    mc.conv_tol = 1e-9
    mc.__dict__.update(frag.corr_attr)
    E_CASSCF = mc.kernel(imp2mo, ci0)[0]
    if not mc.converged:
        mc = mc.newton()
        E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0]
    if not mc.converged:
        print('Assuming ci vector is poisoned; discarding...')
        imp2mo = mc.mo_coeff.copy()
        mc = mcscf.CASSCF(mf, CASorb, CASe)
        smult = 2 * frag.target_S + 1 if frag.target_S is not None else (
            frag.nelec_imp % 2) + 1
        mc.fcisolver = csf_solver(mf.mol, smult)
        E_CASSCF = mc.kernel(imp2mo)[0]
        if not mc.converged:
            mc = mc.newton()
            E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0]
    assert (mc.converged)
    '''
    mc.conv_tol = 1e-12
    mc.ah_start_tol = 1e-10
    mc.ah_conv_tol = 1e-12
    E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0]
    if not mc.converged:
        mc = mc.newton ()
        E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0]
    #assert (mc.converged)
    '''

    # Get twoRDM + oneRDM. cs: MC-SCF core, as: MC-SCF active space
    # I'm going to need to keep some representation of the active-space orbitals
    imp2mo = mc.mo_coeff  #mc.cas_natorb()[0]
    loc2mo = np.dot(frag.loc2imp, imp2mo)
    imp2amo = imp2mo[:, norbs_cmo:norbs_occ]
    loc2amo = loc2mo[:, norbs_cmo:norbs_occ]
    frag.imp_cache = [mc.mo_coeff, mc.ci]
    frag.ci_as = mc.ci
    frag.ci_as_orb = loc2amo.copy()
    t_end = time.time()
    print(
        'Impurity CASSCF energy (incl chempot): {}; spin multiplicity: {}; time to solve: {}'
        .format(E_CASSCF,
                spin_square(mc)[1], t_end - t_start))

    # oneRDM
    oneRDM_imp = mc.make_rdm1()

    # twoCDM
    oneRDM_amo, twoRDM_amo = mc.fcisolver.make_rdm12(mc.ci, mc.ncas,
                                                     mc.nelecas)
    # Note that I do _not_ do the *real* cumulant decomposition; I do one assuming oneRDMs_amo_alpha = oneRDMs_amo_beta
    # This is fine as long as I keep it consistent, since it is only in the orbital gradients for this impurity that
    # the spin density matters. But it has to stay consistent!
    twoCDM_amo = get_2CDM_from_2RDM(twoRDM_amo, oneRDM_amo)
    twoCDM_imp = represent_operator_in_basis(twoCDM_amo, imp2amo.conjugate().T)

    # General impurity data
    frag.oneRDM_loc = symmetrize_tensor(
        frag.oneRDMfroz_loc +
        represent_operator_in_basis(oneRDM_imp, frag.imp2loc))
    frag.twoCDM_imp = None  # Experiment: this tensor is huge. Do I actually need to keep it? In principle, of course not.
    frag.E_imp = E_CASSCF + np.einsum('ab,ab->', chempot_imp, oneRDM_imp)

    # Active-space RDM data
    frag.oneRDMas_loc = symmetrize_tensor(
        represent_operator_in_basis(oneRDM_amo,
                                    loc2amo.conjugate().T))
    frag.twoCDMimp_amo = twoCDM_amo
    frag.loc2mo = loc2mo
    frag.loc2amo = loc2amo
    frag.E2_cum = 0.5 * np.tensordot(
        ao2mo.restore(1, mc.get_h2eff(), mc.ncas), twoCDM_amo, axes=4)

    return None
Exemple #9
0
def get_overlapping_states (bra_basis, ket_basis, across_operator=None, inner_symmetry=None, outer_symmetry=(None, None), enforce_symmetry=False,
        max_nrvecs=0, max_nlvecs=0, num_zero_atol=params.num_zero_atol, only_nonzero_vals=True, full_matrices=False):
    c2p = np.asarray (bra_basis)
    c2q = np.asarray (ket_basis)
    cOc = 1 if across_operator is None else np.asarray (across_operator)
    assert (c2p.shape[0] == c2q.shape[0]), "you need to give the two spaces in the same basis"
    assert (c2p.shape[1] <= c2p.shape[0]), "you need to give the first state in a complete basis (c2p). Did you accidentally transpose it?"
    assert (c2q.shape[1] <= c2q.shape[0]), "you need to give the second state in a complete basis (c2q). Did you accidentally transpose it?"
    assert (max_nlvecs <= c2p.shape[1]), "you can't ask for more left states than are in your left space"
    assert (max_nrvecs <= c2q.shape[1]), "you can't ask for more right states than are in your right space"
    if np.any (across_operator):
        assert (c2p.shape[0] == cOc.shape[0] and c2p.shape[0] == cOc.shape[1]), "when specifying an across_operator, it's dimensions need to be the same as the external basis"
    get_labels = (not (inner_symmetry is None)) or (not (outer_symmetry[0] is None)) or (not (outer_symmetry[1] is None))

    try:
        rets = matrix_svd_control_options (cOc, lspace=c2p, rspace=c2q, full_matrices=full_matrices,
            symmetry=inner_symmetry,
            lspace_symmetry=outer_symmetry[0],
            rspace_symmetry=outer_symmetry[1],
            strong_symm=enforce_symmetry,
            sort_vecs=-1, only_nonzero_vals=only_nonzero_vals, num_zero_atol=num_zero_atol)
        c2l, svals, c2r = rets[:3]
        if get_labels: llab, rlab = rets[3:]
    except linalg.LinAlgError as e:
        print ("LinAlgError in SVD! Analyzing...")
        if isinstance (cOc, np.ndarray):
            print ("Shape of across_operator: {}".format (cOc.shape))
            print ("Any NANs in across_operator? {}".format (np.count_nonzero (np.isnan (cOc))))
            print ("Any INFs in across_operator? {}".format (np.count_nonzero (np.isinf (cOc))))
            print ("min/max across_operator: {}/{}".format (np.amin (cOc), np.amax (cOc)))
        print ("Shape of bra_basis: {}".format (c2p.shape))
        print ("Any NANs in bra_basis? {}".format (np.count_nonzero (np.isnan (c2p))))
        print ("Any INFs in bra_basis? {}".format (np.count_nonzero (np.isinf (c2p))))
        print ("min/max bra_basis: {}/{}".format (np.amin (c2p), np.amax (c2p)))
        print ("Shape of ket_basis: {}".format (c2p.shape))
        print ("Any NANs in ket_basis? {}".format (np.count_nonzero (np.isnan (c2p))))
        print ("Any INFs in ket_basis? {}".format (np.count_nonzero (np.isinf (c2p))))
        print ("min/max ket_basis: {}/{}".format (np.amin (c2p), np.amax (c2p)))
        proj_l = c2p @ c2p.conjugate ().T
        if isinstance (cOc, np.ndarray):
            proj_l = cOc @ proj_l @ cOc
        r_symmetry = inner_symmetry if outer_symmetry[1] is None else outer_symmetry[1]
        rets = matrix_eigen_control_options (proj_l, subspace=c2q, symmetry=r_symmetry, strong_symm=enforce_symmetry, sort_vecs=-1,
            only_nonzero_vals=False, num_zero_atol=num_zero_atol)
        evals_r, c2r = rets[:2]
        if get_labels: rlab = rets[2]
        proj_r = c2q @ c2q.conjugate ().T
        if isinstance (cOc, np.ndarray):
            proj_r = cOc @ proj_r @ cOc 
        l_symmetry = inner_symmetry if outer_symmetry[0] is None else outer_symmetry[0]
        rets = matrix_eigen_control_options (proj_r, subspace=c2p, symmetry=l_symmetry, strong_symm=enforce_symmetry, sort_vecs=-1,
            only_nonzero_vals=False, num_zero_atol=num_zero_atol)
        evals_l, c2l = rets[:2]
        if get_labels: llab = rets[2]
        print ("These pairs of eigenvalues should be equal and all positive:")
        for el, er in zip (evals_l, evals_r):
            print (el, er)
        mlen = min (len (evals_l), len (evals_r))
        if len (evals_l) > mlen: print ("More left-hand eigenvalues: {}".format (evals_l[mlen:]))
        if len (evals_r) > mlen: print ("More left-hand eigenvalues: {}".format (evals_r[mlen:]))
        raise (e)

    # Truncate the basis if requested
    max_nlvecs = max_nlvecs or c2l.shape[1]
    max_nrvecs = max_nrvecs or c2r.shape[1]

    # But you can't truncate it smaller than it already is
    max_nlvecs = min (max_nlvecs, c2l.shape[1])
    max_nrvecs = min (max_nrvecs, c2r.shape[1])
    c2l = c2l[:,:max_nlvecs]
    c2r = c2r[:,:max_nrvecs]

    if get_labels: return c2l, c2r, svals, llab, rlab
    return c2l, c2r, svals
Exemple #10
0
    def dmet_cderi(self, loc2dmet, numAct=None):

        t0 = time.clock()
        w0 = time.time()
        norbs_aux = self.with_df.get_naoaux()
        numAct = loc2dmet.shape[1] if numAct == None else numAct
        loc2imp = loc2dmet[:, :numAct]
        assert (self.with_df is not None), "density fitting required"
        npair = numAct * (numAct + 1) // 2
        CDERI = np.empty((self.with_df.get_naoaux(), npair),
                         dtype=loc2dmet.dtype)
        full_cderi_size = (norbs_aux * self.mol.nao_nr() *
                           (self.mol.nao_nr() + 1) * CDERI.itemsize // 2) / 1e6
        imp_eri_size = (CDERI.itemsize * npair * (npair + 1) // 2) / 1e6
        imp_cderi_size = CDERI.size * CDERI.itemsize / 1e6
        print(
            "Size comparison: cderi is ({0},{1},{1})->{2:.0f} MB compacted; eri is ({1},{1},{1},{1})->{3:.0f} MB compacted"
            .format(norbs_aux, numAct, imp_cderi_size, imp_eri_size))
        ao2imp = np.dot(self.ao2loc, loc2imp)
        ijmosym, mij_pair, moij, ijslice = ao2mo.incore._conc_mos(ao2imp,
                                                                  ao2imp,
                                                                  compact=True)
        b0 = 0
        for eri1 in self.with_df.loop():
            b1 = b0 + eri1.shape[0]
            eri2 = CDERI[b0:b1]
            eri2 = ao2mo._ao2mo.nr_e2(eri1,
                                      moij,
                                      ijslice,
                                      aosym='s2',
                                      mosym=ijmosym,
                                      out=eri2)
            b0 = b1
        t1 = time.clock()
        w1 = time.time()
        print(("({0}, {1}) seconds to turn {2:.0f}-MB full"
               "cderi array into {3:.0f}-MP impurity cderi array").format(
                   t1 - t0, w1 - w0, full_cderi_size, imp_cderi_size))

        # Compression step 1: remove zero rows
        idx_nonzero = np.amax(np.abs(CDERI), axis=1) > sqrt(LINEAR_DEP_THR)
        print(
            "From {} auxiliary functions, {} have nonzero rows of the 3-center integral"
            .format(norbs_aux, np.count_nonzero(idx_nonzero)))
        CDERI = CDERI[idx_nonzero]

        # Compression step 2: svd
        sigma, vmat = matrix_svd_control_options(
            CDERI,
            sort_vecs=-1,
            only_nonzero_vals=True,
            full_matrices=False,
            num_zero_atol=sqrt(LINEAR_DEP_THR))[1:]
        imp_cderi_size = vmat.size * vmat.itemsize / 1e6
        print(
            "From {} nonzero aux-function rows, {} nonzero singular values found"
            .format(np.count_nonzero(idx_nonzero), len(sigma)))
        print(
            "With SVD: {0:.0f}-MB CDERI array, compared to {1:.0f}-MB eri; ({2}, {3}) seconds"
            .format(imp_cderi_size, imp_eri_size,
                    time.clock() - t1,
                    time.time() - w1))
        CDERI = np.ascontiguousarray((vmat * sigma).T)
        return CDERI