Ejemplo n.º 1
0
 def nelec_as(self):
     result = np.trace(self.oneRDMas_loc)
     if is_close_to_integer(result, params.num_zero_atol) == False:
         raise RuntimeError(
             "Somehow you got a non-integer number of electrons in your active space!"
         )
     return int(round(result))
Ejemplo n.º 2
0
def Schmidt_decomposition_idempotent_wrapper (working_1RDM, loc2wfrag, norbs_bath_max, bath_tol=1e-5, idempotize_thresh=0, num_zero_atol=0):
    norbs_tot = loc2wfrag.shape[0]
    norbs_wfrag = loc2wfrag.shape[1]
    loc2wemb, norbs_wbath, nelec_wimp = Schmidt_decompose_1RDM (working_1RDM, loc2wfrag, norbs_bath_max, bath_tol=bath_tol)
    norbs_wimp  = norbs_wfrag + norbs_wbath
    norbs_wcore = norbs_tot - norbs_wimp
    loc2wimp  = loc2wemb[:,:norbs_wimp]
    loc2wcore = loc2wemb[:,norbs_wimp:]
    print ("Schmidt decomposition found {0} bath orbitals for this fragment, of an allowed total of {1}".format (norbs_wbath, norbs_bath_max))
    print ("Schmidt decomposition found {0} electrons in this impurity".format (nelec_wimp))
    working_1RDM_core = np.zeros(working_1RDM.shape)
    if norbs_wcore > 0:
        working_1RDM_core = project_operator_into_subspace (working_1RDM, loc2wcore)
        if abs (idempotize_thresh) > num_zero_atol:
            working_1RDM_core, nelec_wcore_diff = idempotize_1RDM (working_1RDM_core, idempotize_thresh)
            nelec_wimp -= nelec_wcore_diff
            print ("After attempting to idempotize the core (part of the putatively idempotent guide) 1RDM with a threshold of "
            + "{0}, {1} electrons were found in the impurity".format (idempotize_thresh, nelec_wimp))
    if not is_close_to_integer (nelec_wimp / 2, num_zero_atol):
        raise RuntimeError ("Can't solve impurity problems without even-integer number of electrons! nelec_wimp={0}".format (nelec_wimp))
    return loc2wemb, norbs_wbath, int (round (nelec_wimp)), working_1RDM_core
Ejemplo n.º 3
0
    def setup_wm_core_scf (self, fragments, calcname):

        self.restore_wm_full_scf ()
        oneRDMcorr_loc = sum ((frag.oneRDMas_loc for frag in fragments))
        oneSDMcorr_loc = sum ((frag.oneSDMas_loc for frag in fragments))
        if np.all (np.isclose (oneRDMcorr_loc, 0)):
            print ("Null correlated 1-RDM; default settings for wm wvfn")
            self.oneRDMcorr_loc = oneRDMcorr_loc
            self.oneSDMcorr_loc = oneSDMcorr_loc
            return

        loc2corr = np.concatenate ([frag.loc2amo for frag in fragments], axis=1)

        # Calculate E2_cum            
        E2_cum = 0
        for frag in fragments:
            if frag.norbs_as > 0:
                if frag.E2_cum == 0 and np.amax (np.abs (frag.twoCDMimp_amo)) > 0:
                    V  = self.dmet_tei (frag.loc2amo)
                    L  = frag.twoCDMimp_amo
                    frag.E2_cum  = np.tensordot (V, L, axes=4) / 2
                    K  = self.loc_rhf_k_bis (frag.oneSDMas_loc)
                    frag.E2_cum += (K * frag.oneSDMas_loc).sum () / 4
                E2_cum += frag.E2_cum
            
        loc2idem = get_complementary_states (loc2corr)
        test, err = are_bases_orthogonal (loc2idem, loc2corr)
        print ("Testing linear algebra: overlap of active and unactive orbitals = {}".format (linalg.norm (err)))

        # I want to alter the outputs of self.loc_oei (), self.loc_rhf_fock (), and the get_wm_1RDM_etc () functions.
        # self.loc_oei ()      = P_idem * (activeOEI + JKcorr) * P_idem
        # self.loc_rhf_fock () = P_idem * (activeOEI + JKcorr + JKidem) * P_idem
        # The get_wm_1RDM_etc () functions will need to add oneRDMcorr_loc to their final return value
        # The chemical potential is so that identically zero eigenvalues from the projection into the idem space don't get confused
        # with numerically-zero eigenvalues in the idem space: all occupied orbitals must have negative energy
        
        # Make true output 1RDM from fragments to use as guess for wm mcscf calculation
        oneRDMguess_loc = np.zeros_like (oneRDMcorr_loc)
        for f in itertools.product (fragments, fragments):
            loc2frag         = [i.loc2frag for i in f] 
            oneRDMguess_loc += sum ((0.5 * project_operator_into_subspace (i.oneRDM_loc, *loc2frag) for i in f))

        nelec_corr     = np.trace (oneRDMcorr_loc)
        if is_close_to_integer (nelec_corr, 100*params.num_zero_atol) == False:
            raise ValueError ("nelec_corr not an integer! {}".format (nelec_corr))
        nelec_idem     = int (round (self.nelec_tot - nelec_corr))
        if nelec_idem % 2: raise NotImplementedError ("Odd % of unactive electrons")
        JKcorr         = self.loc_rhf_jk_bis (oneRDMcorr_loc)
        oei            = self.activeOEI + JKcorr/2
        vk             = -self.loc_rhf_k_bis (oneSDMcorr_loc)/2
        working_const  = self.activeCONST + (oei * oneRDMcorr_loc).sum () + (vk * oneSDMcorr_loc).sum ()/2 + E2_cum
        oneRDMidem_loc = self.get_wm_1RDM_from_scf_on_OEI (self.loc_oei () + JKcorr, nelec=nelec_idem, loc2wrk=loc2idem, oneRDMguess_loc=oneRDMguess_loc,
            output = calcname + '_trial_wvfn.log', working_const=working_const)
        JKidem         = self.loc_rhf_jk_bis (oneRDMidem_loc)
        print ("trace of oneRDMcorr_loc = {}".format (np.trace (oneRDMcorr_loc)))
        print ("trace of oneRDMidem_loc = {}".format (np.trace (oneRDMidem_loc)))
        print ("trace of oneSDMcorr_loc = {}".format (np.trace (oneSDMcorr_loc)))
        print ("trace of oneRDM_loc in corr basis = {}".format (np.trace (represent_operator_in_basis (oneRDMcorr_loc + oneRDMidem_loc, loc2corr))))
        svals = get_overlapping_states (loc2idem, loc2corr)[2]
        print ("trace of <idem|corr|idem> = {}".format (np.sum (svals * svals)))
        print (loc2corr.shape)
        print (loc2idem.shape)
        dma_dmb = oneRDMidem_loc + oneRDMcorr_loc
        dma_dmb = [(dma_dmb + oneSDMcorr_loc)/2, (dma_dmb - oneSDMcorr_loc)/2]
        focka_fockb = [JKcorr + vk, JKcorr - vk]
        focka_fockb = [self.activeOEI + JKidem + JK for JK in focka_fockb]
        oneRDM_loc  = oneRDMidem_loc + oneRDMcorr_loc
        oneSDM_loc  = oneSDMcorr_loc
        E  = self.activeCONST + E2_cum 
        E += ((self.activeOEI + (JKcorr + JKidem)/2) * oneRDM_loc).sum ()
        E += (vk * oneSDM_loc).sum ()/2
        self._cache_and_analyze_(calcname, E, focka_fockb, dma_dmb, JKidem, JKcorr, oneRDMcorr_loc, loc2idem, loc2corr, nelec_idem, oneRDM_loc, oneSDM_loc)
Ejemplo n.º 4
0
    def setup_wm_core_scf(self, fragments, calcname):

        self.restore_wm_full_scf()
        oneRDMcorr_loc = sum((frag.oneRDMas_loc for frag in fragments))
        if np.all(np.isclose(oneRDMcorr_loc, 0)):
            print("Null correlated 1-RDM; default settings for wm wvfn")
            self.activeFOCK = represent_operator_in_basis(
                self.fullFOCKao, self.ao2loc)
            self.activeJKidem = self.activeFOCK - self.activeOEI
            self.activeJKcorr = np.zeros((self.norbs_tot, self.norbs_tot))
            self.oneRDMcorr_loc = oneRDMcorr_loc
            self.loc2idem = np.eye(self.norbs_tot)
            self.nelec_idem = self.nelec_tot
            return

        loc2corr = np.concatenate([frag.loc2amo for frag in fragments], axis=1)
        loc2idem = get_complementary_states(loc2corr)
        evecs = matrix_eigen_control_options(represent_operator_in_basis(
            self.loc_oei(), loc2idem),
                                             sort_vecs=1,
                                             only_nonzero_vals=False)[1]
        loc2idem = np.dot(loc2idem, evecs)

        # I want to alter the outputs of self.loc_oei (), self.loc_rhf_fock (), and the get_wm_1RDM_etc () functions.
        # self.loc_oei ()      = P_idem * (activeOEI + JKcorr) * P_idem
        # self.loc_rhf_fock () = P_idem * (activeOEI + JKcorr + JKidem) * P_idem
        # The get_wm_1RDM_etc () functions will need to add oneRDMcorr_loc to their final return value
        # The chemical potential is so that identically zero eigenvalues from the projection into the idem space don't get confused
        # with numerically-zero eigenvalues in the idem space: all occupied orbitals must have negative energy

        # Make true output 1RDM from fragments to use as guess for wm mcscf calculation
        oneRDMguess_loc = np.zeros_like(oneRDMcorr_loc)
        for f in itertools.product(fragments, fragments):
            loc2frag = [i.loc2frag for i in f]
            oneRDMguess_loc += sum(
                (0.5 * project_operator_into_subspace(i.oneRDM_loc, *loc2frag)
                 for i in f))

        nelec_corr = np.trace(oneRDMcorr_loc)
        if is_close_to_integer(nelec_corr,
                               100 * params.num_zero_atol) == False:
            raise ValueError(
                "nelec_corr not an integer! {}".format(nelec_corr))
        nelec_idem = int(round(self.nelec_tot - nelec_corr))
        JKcorr = self.loc_rhf_jk_bis(oneRDMcorr_loc)
        oneRDMidem_loc = self.get_wm_1RDM_from_scf_on_OEI(
            self.loc_oei() + JKcorr,
            nelec=nelec_idem,
            loc2wrk=loc2idem,
            oneRDMguess_loc=oneRDMguess_loc,
            output=calcname + '_trial_wvfn.log')
        JKidem = self.loc_rhf_jk_bis(oneRDMidem_loc)
        print("trace of oneRDMcorr_loc = {}".format(np.trace(oneRDMcorr_loc)))
        print("trace of oneRDMidem_loc = {}".format(np.trace(oneRDMidem_loc)))
        print("trace of oneRDM_loc in corr basis = {}".format(
            np.trace(
                represent_operator_in_basis(
                    oneRDMcorr_loc + oneRDMidem_loc,
                    orthonormalize_a_basis(loc2corr)))))
        svals = get_overlapping_states(loc2idem, loc2corr)[2]
        print("trace of <idem|corr|idem> = {}".format(np.sum(svals * svals)))
        print(loc2corr.shape)
        print(loc2idem.shape)

        ########################################################################################################
        self.activeFOCK = self.activeOEI + JKidem + JKcorr
        self.activeJKidem = JKidem
        self.activeJKcorr = JKcorr
        self.oneRDMcorr_loc = oneRDMcorr_loc
        self.loc2idem = loc2idem
        self.nelec_idem = nelec_idem
        ########################################################################################################

        # Analysis: 1RDM and total energy
        print("Analyzing LASSCF trial wave function")
        oei = self.activeOEI + (JKcorr + JKidem) / 2
        fock = self.activeFOCK
        oneRDM = oneRDMidem_loc + oneRDMcorr_loc
        E = self.activeCONST + np.tensordot(oei, oneRDM, axes=2)
        for frag in fragments:
            if frag.norbs_as > 0:
                if frag.E2_cum == 0 and np.amax(np.abs(
                        frag.twoCDMimp_amo)) > 0:
                    V = self.dmet_tei(frag.loc2amo)
                    L = frag.twoCDMimp_amo
                    frag.E2_cum = np.tensordot(V, L, axes=4) / 2
                E += frag.E2_cum
        print("LASSCF trial wave function total energy: {:.6f}".format(E))
        self.oneRDM_loc = oneRDM
        self.e_tot = E

        # Molden
        fock_idem = represent_operator_in_basis(fock, loc2idem)
        oneRDM_corr = represent_operator_in_basis(oneRDM, loc2corr)
        idem_evecs = matrix_eigen_control_options(fock_idem,
                                                  sort_vecs=1,
                                                  only_nonzero_vals=False)[1]
        corr_evecs = matrix_eigen_control_options(oneRDM_corr,
                                                  sort_vecs=-1,
                                                  only_nonzero_vals=False)[1]
        loc2molden = np.append(np.dot(loc2idem, idem_evecs),
                               np.dot(loc2corr, corr_evecs),
                               axis=1)
        wm_ene = np.einsum('ip,ij,jp->p', loc2molden, fock, loc2molden)
        wm_ene[-loc2corr.shape[1]:] = 0
        wm_occ = np.einsum('ip,ij,jp->p', loc2molden, oneRDM, loc2molden)
        ao2molden = np.dot(self.ao2loc, loc2molden)
        molden.from_mo(self.mol,
                       calcname + '_trial_wvfn.molden',
                       ao2molden,
                       occ=wm_occ,
                       ene=wm_ene)