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))
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
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)
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)