Skip to content

Commit

Permalink
A number of small fixes:
Browse files Browse the repository at this point in the history
- solver keyword is now case-sensitive in input, so fix for example 20-dump-clusters.py which was broken by this.
- In CAS fragmentation, allow orbitals to not be ordered by energy, to allow picking of orbitals non-energetically (after explicit reordering by user – this could be improved further later).
- A number of fixes for both cRPA and mRPA screening of the integrals to allow systems where there are no alpha or beta excitations in the cluster.
  • Loading branch information
George Booth committed Feb 23, 2024
1 parent edd363a commit 0710e9a
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 28 deletions.
4 changes: 2 additions & 2 deletions examples/ewf/molecules/20-dump-clusters.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

# Embedding class to form fragment, bath, and cluster spaces
emb = vayesta.ewf.EWF(
mf, solver="Dump", bath_options=dict(threshold=1e-6), solver_options=dict(dumpfile="clusters-rhf.h5")
mf, solver="DUMP", bath_options=dict(threshold=1e-6), solver_options=dict(dumpfile="clusters-rhf.h5")
)
emb.kernel()

Expand All @@ -46,7 +46,7 @@

# Embedding class to form fragment, bath, and cluster spaces
emb = vayesta.ewf.EWF(
mf, solver="Dump", bath_options=dict(threshold=1e-6), solver_options=dict(dumpfile="clusters-uhf.h5")
mf, solver="DUMP", bath_options=dict(threshold=1e-6), solver_options=dict(dumpfile="clusters-uhf.h5")
)
emb.kernel()

Expand Down
4 changes: 2 additions & 2 deletions vayesta/core/fragmentation/cas.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def check_for_degen(energies, po, pv, name=""):
# Shouldn't reach this as would require CAS to have more electrons than the full system.
raise ValueError("CAS would contain more electrons than full system.")

if ogap < degen_tol:
if abs(ogap) < degen_tol:
raise ValueError("Requested %sCAS splits degenerate occupied orbitals." % name)

try:
Expand All @@ -99,7 +99,7 @@ def check_for_degen(energies, po, pv, name=""):
vgap = np.inf
else:
self.log.info("%sCAS virtual energy gap: %s", name, energy_string(vgap))
if vgap < degen_tol:
if abs(vgap) < degen_tol:
raise ValueError("Requested CAS splits degenerate virtual orbitals.")

if self.emb.is_rhf:
Expand Down
21 changes: 18 additions & 3 deletions vayesta/core/screening/screening_crpa.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,29 @@ def construct_loc_rot(f):
rv = (rv, rv)

rot_ova = einsum("Ij,Ab->IAjb", ro[0], rv[0])
rot_ova = rot_ova.reshape((rot_ova.shape[0] * rot_ova.shape[1], -1))
if rot_ova.size == 0:
rot_ova = np.empty((0, ro[0].shape[1]*rv[0].shape[1]))
else:
rot_ova = rot_ova.reshape((rot_ova.shape[0] * rot_ova.shape[1], -1))

rot_ovb = einsum("Ij,Ab->IAjb", ro[1], rv[1])
rot_ovb = rot_ovb.reshape((rot_ovb.shape[0] * rot_ovb.shape[1], -1))
if rot_ovb.size == 0:
rot_ovb = np.empty((0, ro[1].shape[1]*rv[1].shape[1]))
else:
rot_ovb = rot_ovb.reshape((rot_ovb.shape[0] * rot_ovb.shape[1], -1))

return rot_ova, rot_ovb

rot_loc = construct_loc_rot(f)
rot_ov = scipy.linalg.null_space(rot_loc[0]).T, scipy.linalg.null_space(rot_loc[1]).T
if rot_loc[0].size > 0:
rot_ov_a = scipy.linalg.null_space(rot_loc[0]).T
else:
rot_ov_a = np.eye(rot_loc[0].shape[1])
if rot_loc[1].size > 0:
rot_ov_b = scipy.linalg.null_space(rot_loc[1]).T
else:
rot_ov_b = np.eye(rot_loc[1].shape[1])
rot_ov = (rot_ov_a, rot_ov_b)
if rot_ov[0].shape[0] == 0 and rot_ov[1].shape[0] == 0:
log.warning("cRPA space contains no excitations! Interactions will be unscreened.")
raise cRPAError("cRPA space contains no excitations!")
Expand Down
10 changes: 7 additions & 3 deletions vayesta/core/screening/screening_moment.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ def build_screened_eris(emb, fragments=None, cderi_ov=None, store_m0=True, npoin
r_virs = [f.get_overlap("mo[vir]|cluster[vir]") for f in fragments]
target_rots, ovs_active = _get_target_rot(r_occs, r_virs)

# target_rots is a list of transformations to the local ph space, with alpha and beta blocked in the same matrix
local_moments = calc_moms_RIRPA(emb.mf, target_rots, ovs_active, log, cderi_ov, npoints)
# Could generate moments using N^6 moments instead, but just for debugging.
# local_moments, erpa = calc_moms_RPA(emb.mf, target_rots, ovs_active, log, cderi_ov, calc_e, npoints)
# local_moments, erpa = calc_moms_RPA(emb.mf, target_rots, ovs_active, log, cderi_ov, npoints)

# Then construct the RPA coupling matrix A-B, given by the diagonal matrix of energy differences.
no = np.array(sum(emb.mf.mo_occ.T > 0))
Expand Down Expand Up @@ -135,7 +136,7 @@ def calc_moms_RIRPA(mf, target_rots, ovs_active, log, cderi_ov, npoints):
return local_moments


def calc_moms_RPA(mf, target_rots, ovs_active, log, cderi_ov, calc_e, npoints):
def calc_moms_RPA(mf, target_rots, ovs_active, log, cderi_ov, npoints):
rpa = ssRPA(mf, log=log)
erpa = rpa.kernel()
mom0 = rpa.gen_moms(0)[0]
Expand Down Expand Up @@ -244,7 +245,10 @@ def get_target_rot_spat(ro, rv):
no = ro.shape[1]
nv = rv.shape[1]
ov_active = no * nv
rot = einsum("iJ,aB->JBia", ro, rv).reshape((ov_active, -1))
if ov_active == 0:
rot = np.empty((0,ro.shape[0]*rv.shape[0]))
else:
rot = einsum("iJ,aB->JBia", ro, rv).reshape((ov_active, -1))
return rot, ov_active

nfrag = len(r_active_occs)
Expand Down
10 changes: 5 additions & 5 deletions vayesta/rpa/ssrpa.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,18 @@ def kernel(self, xc_kernel=None, alpha=1.0):
XpY = np.einsum("n,pq,qn->pn", self.freqs_ss ** (-0.5), AmBrt, c)
XmY = np.einsum("n,pq,qn->pn", self.freqs_ss ** (0.5), AmBrtinv, c)

nov = self.ova
nova = self.ova
if self.ov_rot is not None:
nov = self.ov_rot[0].shape[0]
nova = self.ov_rot[0].shape[0]

self.XpY_ss = (XpY[:nov], XpY[nov:])
self.XmY_ss = (XmY[:nov], XmY[nov:])
self.XpY_ss = (XpY[:nova], XpY[nova:])
self.XmY_ss = (XmY[:nova], XmY[nova:])

self.freqs_sf = None
self.log.timing("Time to solve RPA problem: %s", time_string(timer() - t0))

if xc_kernel is None:
self.e_corr_ss = (sum(self.freqs_ss) - sum(eps[0] + eps[1]) - v.trace()) / 2
self.e_corr_ss = (sum(self.freqs_ss) - sum(eps[0]) - sum(eps[1]) - v.trace()) / 2
else:
self.e_corr_ss = self.calc_energy_correction(xc_kernel=xc_kernel, version=3)

Expand Down
37 changes: 24 additions & 13 deletions vayesta/rpa/ssurpa.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def _gen_eps(self):
epsa = (epsa.T - self.mf.mo_energy[0][:nocc_a]).T
epsa = epsa.reshape((self.ova,))

epsb = np.zeros((nocc_a, nvir_a))
epsb = np.zeros((nocc_b, nvir_b))
epsb = epsb + self.mf.mo_energy[1][nocc_b:]
epsb = (epsb.T - self.mf.mo_energy[1][:nocc_b]).T
epsb = epsb.reshape((self.ovb,))
Expand All @@ -63,25 +63,36 @@ def _gen_arrays(self, xc_kernel=None, alpha=1.0):
epsa, epsb = self._gen_eps()

if self.ov_rot is not None:
epsa = einsum("pn,n,qn->pq", self.ov_rot[0], epsa, self.ov_rot[0])
try:
epsa, ca = scipy.linalg.eigh(epsa)
except Exception as e:
print(epsa)
raise e
epsb = einsum("pn,n,qn->pq", self.ov_rot[1], epsb, self.ov_rot[1])
try:
epsb, cb = scipy.linalg.eigh(epsb)
except Exception as e:
print(epsb)
raise e
if self.ov_rot[0].size > 0:
epsa = einsum("pn,n,qn->pq", self.ov_rot[0], epsa, self.ov_rot[0])
try:
epsa, ca = scipy.linalg.eigh(epsa)
except Exception as e:
print(epsa)
raise e
else:
epsa = np.empty((0))
ca = np.empty((0,0))
if self.ov_rot[1].size > 0:
epsb = einsum("pn,n,qn->pq", self.ov_rot[1], epsb, self.ov_rot[1])
try:
epsb, cb = scipy.linalg.eigh(epsb)
except Exception as e:
print(epsb)
raise e
else:
epsb = np.empty((0))
cb = np.empty((0,0))
self.ov_rot = (dot(ca.T, self.ov_rot[0]), dot(cb.T, self.ov_rot[1]))

AmB = np.concatenate([epsa, epsb])
fullv = self.get_k()
ApB = 2 * fullv * alpha
if self.ov_rot is not None:
fullrot = scipy.linalg.block_diag(self.ov_rot[0], self.ov_rot[1])
#print("Alpha rot: ", self.ov_rot[0].shape)
#print("Beta rot: ", self.ov_rot[1].shape)
#print("Size of full rot: ",fullrot.shape)
ApB = dot(fullrot, ApB, fullrot.T)

# At this point AmB is just epsilon so add in.
Expand Down

0 comments on commit 0710e9a

Please sign in to comment.