Skip to content

Commit

Permalink
Added an experimental EA-EOMCC(P;Q) method. I'm not sure if this is w…
Browse files Browse the repository at this point in the history
…orking properly because it seems to overshoot the correction for 2p1h-dominated states.
  • Loading branch information
kgururangan committed Apr 14, 2024
1 parent 1db8aa2 commit e350b3f
Show file tree
Hide file tree
Showing 11 changed files with 1,020 additions and 24 deletions.
8 changes: 8 additions & 0 deletions ccpy/drivers/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,14 @@ def run_eaccp3(self, method, state_index=[0], two_body_approx=True, num_active=1
_, self.deltap3[i] = calc_creacc23(self.T, self.R[i], self.L[i],
self.vertical_excitation_energy[i], self.correlation_energy, self.hamiltonian, self.fock,
self.system, self.options["RHF_symmetry"])
if method.lower() == "eaccp3":
from ccpy.moments.eaccp3 import calc_eaccp3_full
# Ensure that HBar is set upon entry
assert self.flag_hbar
# Perform 3p-2h correction for a specific state index
_, self.deltap3[state_index] = calc_eaccp3_full(self.T, self.R[state_index], self.L[state_index], r3_excitations,
self.vertical_excitation_energy[state_index], self.correlation_energy,
self.hamiltonian, self.fock, self.system, self.options["RHF_symmetry"])

def run_ccp4(self, method, state_index=[0], two_body_approx=True):

Expand Down
2 changes: 1 addition & 1 deletion ccpy/left/left_eaeom3_p.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def LH_fun(dL, L, T, H, flag_RHF, system, t3_excitations, l3_excitations):
do_l3["abb"] = False

# Get intermediates
X = get_lefteaeom3_p_intermediates(L, l3_excitations, T, system)
X = get_lefteaeom3_p_intermediates(L, l3_excitations, T, do_l3, system)
# update R1
dL = build_LH_1A(dL, L, l3_excitations, H, X)
# update R2
Expand Down
17 changes: 11 additions & 6 deletions ccpy/left/left_eaeom_intermediates.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def get_lefteaeom3_intermediates(L, T, system):
)
return X

def get_lefteaeom3_p_intermediates(L, l3_excitations, T, system):
def get_lefteaeom3_p_intermediates(L, l3_excitations, T, do_l3, system):
"""Calculate the L*T intermediates used in the left-EA-EOMCCSD(3p-2h) equations"""

X = {"a": {}, "aa": {}, "ab": {}}
Expand All @@ -56,21 +56,26 @@ def get_lefteaeom3_p_intermediates(L, l3_excitations, T, system):
# x2a(ibj)
X["aa"]["ovo"] = lefteaeom3_p_intermediates.lefteaeom3_p_intermediates.get_x2a_ovo(L.aaa, l3_excitations["aaa"],
L.aab, l3_excitations["aab"],
T.aa, T.ab)
T.aa, T.ab,
do_l3["aaa"], do_l3["aab"])
# x2a(abe)
X["aa"]["vvv"] = lefteaeom3_p_intermediates.lefteaeom3_p_intermediates.get_x2a_vvv(L.aaa, l3_excitations["aaa"],
L.aab, l3_excitations["aab"],
T.aa, T.ab)
T.aa, T.ab,
do_l3["aaa"], do_l3["aab"])
# x2b(ib~j~)
X["ab"]["ovo"] = lefteaeom3_p_intermediates.lefteaeom3_p_intermediates.get_x2b_ovo(L.aab, l3_excitations["aab"],
L.abb, l3_excitations["abb"],
T.aa, T.ab)
T.aa, T.ab,
do_l3["aab"], do_l3["abb"])
# x2b(ak~m~)
X["ab"]["voo"] = lefteaeom3_p_intermediates.lefteaeom3_p_intermediates.get_x2b_voo(L.aab, l3_excitations["aab"],
L.abb, l3_excitations["abb"],
T.ab, T.bb)
T.ab, T.bb,
do_l3["aab"], do_l3["abb"])
# x2b(ae~b~)
X["ab"]["vvv"] = lefteaeom3_p_intermediates.lefteaeom3_p_intermediates.get_x2b_vvv(L.aab, l3_excitations["aab"],
L.abb, l3_excitations["abb"],
T.ab, T.bb)
T.ab, T.bb,
do_l3["aab"], do_l3["abb"])
return X
217 changes: 217 additions & 0 deletions ccpy/moments/eaccp3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
"""Functions to calculate the EA-EOMCC(P;Q) 3p-2h correction to EA-EOMCC(P)."""
import time
import numpy as np

from ccpy.constants.constants import hartreetoeV
from ccpy.hbar.diagonal import aaa_H3_aaa_diagonal, abb_H3_abb_diagonal, aab_H3_aab_diagonal, bbb_H3_bbb_diagonal
from ccpy.utilities.updates import eaccp3_loops
from ccpy.eomcc.eaeom3_intermediates import get_eaeom3_p_intermediates
from ccpy.left.left_eaeom_intermediates import get_lefteaeom3_p_intermediates
from ccpy.eomcc.eaeom3 import build_HR_3A, build_HR_3B, build_HR_3C
from ccpy.utilities.utilities import unravel_3p2h_amplitudes

def calc_eaccp3_full(T, R, L, r3_excitations, omega, corr_energy, H, H0, system, use_RHF=False):
"""
Calculate the excited-state EA-EOMCC(P;Q) 3p-2h correction to the EA-EOMCC(P) energy.
"""
t_start = time.perf_counter()
t_cpu_start = time.process_time()

# get the Hbar 3-body diagonal
d3aaa_v, d3aaa_o = aaa_H3_aaa_diagonal(T, H, system)
d3aab_v, d3aab_o = aab_H3_aab_diagonal(T, H, system)
d3abb_v, d3abb_o = abb_H3_abb_diagonal(T, H, system)
d3bbb_v, d3bbb_o = bbb_H3_bbb_diagonal(T, H, system)

# get L(P)*T(P) intermediates
# determine whether l3 updates and l3*t3 intermediates should be done. Stupid compatibility with
# empty sections of t3_excitations or l3_excitations. L3 ordering matches T3 at this point.
do_l3 = {"aaa": True, "aab": True, "abb": True}
if np.array_equal(r3_excitations["aaa"][0, :], np.array([1., 1., 1., 1., 1.])):
do_l3["aaa"] = False
if np.array_equal(r3_excitations["aab"][0, :], np.array([1., 1., 1., 1., 1.])):
do_l3["aab"] = False
if np.array_equal(r3_excitations["abb"][0, :], np.array([1., 1., 1., 1., 1.])):
do_l3["abb"] = False

# Get intermediates
X_right = get_eaeom3_p_intermediates(H, R, r3_excitations)
X_left = get_lefteaeom3_p_intermediates(L, r3_excitations, T, do_l3, system)

# unravel triples vector into r3(abcijk) and l3(abcijk)
R_unravel = unravel_3p2h_amplitudes(R, r3_excitations, system, do_l3)
L_unravel = unravel_3p2h_amplitudes(L, r3_excitations, system, do_l3)

#### aaa correction ####
# Moments and left vector
M3A = build_HR_3A(R_unravel, T, X_right, H)
L3A = build_LH_3A(L_unravel, H, X_left)
# perform correction in-loop
dA_aaa, dB_aaa, dC_aaa, dD_aaa = eaccp3_loops.eaccp3_loops.eaccp3a_full(
M3A, L3A, r3_excitations["aaa"],
omega,
H0.a.oo, H0.a.vv, H.a.oo, H.a.vv,
H.aa.vvvv, H.aa.oooo, H.aa.voov,
d3aaa_o, d3aaa_v,
)
#### aab correction ####
# moments and left vector
M3B = build_HR_3B(R_unravel, T, X_right, H)
L3B = build_LH_3B(L_unravel, H, X_left)
# perform correction in-loop
dA_aab, dB_aab, dC_aab, dD_aab = eaccp3_loops.eaccp3_loops.eaccp3b_full(
M3B, L3B, r3_excitations["aab"],
omega,
H0.a.oo, H0.a.vv, H0.b.oo, H0.b.vv,
H.a.oo, H.a.vv, H.b.oo, H.b.vv,
H.aa.vvvv, H.aa.voov,
H.ab.vvvv, H.ab.oooo, H.ab.ovov, H.ab.vovo,
H.bb.voov,
d3aaa_o, d3aaa_v, d3aab_o, d3aab_v, d3abb_o, d3abb_v,
)
#### abb correction ####
# moments and left vector
M3C = build_HR_3C(R_unravel, T, X_right, H)
L3C = build_LH_3C(L_unravel, H, X_left)
dA_abb, dB_abb, dC_abb, dD_abb = eaccp3_loops.eaccp3_loops.eaccp3c_full(
M3C, L3C, r3_excitations["abb"],
omega,
H0.a.oo, H0.a.vv, H0.b.oo, H0.b.vv,
H.a.oo, H.a.vv, H.b.oo, H.b.vv,
H.ab.vvvv, H.ab.ovov, H.ab.vovo,
H.bb.vvvv, H.bb.oooo, H.bb.voov,
d3aab_o, d3aab_v, d3abb_o, d3abb_v, d3bbb_o, d3bbb_v,
)

correction_A = dA_aaa + dA_aab + dA_abb
correction_B = dB_aaa + dB_aab + dB_abb
correction_C = dC_aaa + dC_aab + dC_abb
correction_D = dD_aaa + dD_aab + dD_abb

t_end = time.perf_counter()
t_cpu_end = time.process_time()
minutes, seconds = divmod(t_end - t_start, 60)

energy_A = corr_energy + omega + correction_A
energy_B = corr_energy + omega + correction_B
energy_C = corr_energy + omega + correction_C
energy_D = corr_energy + omega + correction_D

total_energy_A = system.reference_energy + energy_A
total_energy_B = system.reference_energy + energy_B
total_energy_C = system.reference_energy + energy_C
total_energy_D = system.reference_energy + energy_D

print(' EA-EOMCC(P;Q) Calculation Summary')
print(' -------------------------------------------------')
print(" Total wall time: {:0.2f}m {:0.2f}s".format(minutes, seconds))
print(f" Total CPU time: {t_cpu_end - t_cpu_start} seconds\n")
print(" EA-EOMCC(P) = {:>10.10f} ω = {:>10.10f} VEE = {:>10.5f} eV".format(system.reference_energy + corr_energy + omega, omega, hartreetoeV * omega))
print(
" EA-EOMCC(P;Q)_A = {:>10.10f} ΔE_A = {:>10.10f} δ_A = {:>10.10f}".format(
total_energy_A, energy_A, correction_A
)
)
print(
" EA-EOMCC(P;Q)_B = {:>10.10f} ΔE_B = {:>10.10f} δ_B = {:>10.10f}".format(
total_energy_B, energy_B, correction_B
)
)
print(
" EA-EOMCC(P;Q)_C = {:>10.10f} ΔE_C = {:>10.10f} δ_C = {:>10.10f}".format(
total_energy_C, energy_C, correction_C
)
)
print(
" EA-EOMCC(P;Q)_D = {:>10.10f} ΔE_D = {:>10.10f} δ_D = {:>10.10f}".format(
total_energy_D, energy_D, correction_D
)
)
print("")

Ecrcc23 = {"A": total_energy_A, "B": total_energy_B, "C": total_energy_C, "D": total_energy_D}
delta23 = {"A": correction_A, "B": correction_B, "C": correction_C, "D": correction_D}

return Ecrcc23, delta23

def build_LH_3A(L, H, X):
"""Calculate the projection < 0 | (L1p+L2p1h+L3p2h)*(H_N e^(T1+T2))_C | jkabc >."""
# moment-like terms < 0 | (L1p+L2p1h)*(H_N e^(T1+T2))_C | jkabc >
X3A = (3.0 / 12.0) * np.einsum("a,jkbc->abcjk", L.a, H.aa.oovv, optimize=True)
X3A += (6.0 / 12.0) * np.einsum("abj,kc->abcjk", L.aa, H.a.ov, optimize=True)
X3A -= (3.0 / 12.0) * np.einsum("abm,jkmc->abcjk", L.aa, H.aa.ooov, optimize=True)
X3A += (6.0 / 12.0) * np.einsum("eck,ejab->abcjk", L.aa, H.aa.vovv, optimize=True)
# <0|L3p2h*(H_N e^(T1+T2))_C | jkabc>
X3A -= (2.0 / 12.0) * np.einsum("jm,abcmk->abcjk", H.a.oo, L.aaa, optimize=True)
X3A += (3.0 / 12.0) * np.einsum("eb,aecjk->abcjk", H.a.vv, L.aaa, optimize=True)
X3A += (1.0 / 24.0) * np.einsum("jkmn,abcmn->abcjk", H.aa.oooo, L.aaa, optimize=True)
X3A += (3.0 / 24.0) * np.einsum("efbc,aefjk->abcjk", H.aa.vvvv, L.aaa, optimize=True)
X3A += (6.0 / 12.0) * np.einsum("ejmb,acekm->abcjk", H.aa.voov, L.aaa, optimize=True)
X3A += (6.0 / 12.0) * np.einsum("jebm,acekm->abcjk", H.ab.ovvo, L.aab, optimize=True)
# three-body Hbar terms (verified against explicit 3-body hbars)
X3A -= (6.0 / 12.0) * np.einsum("mck,mjab->abcjk", X["aa"]["ovo"], H.aa.oovv, optimize=True)
X3A += (3.0 / 12.0) * np.einsum("aeb,jkec->abcjk", X["aa"]["vvv"], H.aa.oovv, optimize=True)
X3A -= np.transpose(X3A, (1, 0, 2, 3, 4)) + np.transpose(X3A, (2, 1, 0, 3, 4)) # antisymmetrize A(a/bc)
X3A -= np.transpose(X3A, (0, 2, 1, 3, 4)) # antisymmetrize A(bc)
X3A -= np.transpose(X3A, (0, 1, 2, 4, 3)) # antisymmetrize A(jk)
return X3A

def build_LH_3B(L, H, X):
"""Calculate the projection < 0 | (L1p+L2p1h+L3p2h)(H_N e^(T1+T2))_C | jk~abc~ >."""
# moment-like terms < 0 | (L1p+L2p1h)*(H_N e^(T1+T2))_C | jk~abc~ >
X3B = np.einsum("a,jkbc->abcjk", L.a, H.ab.oovv, optimize=True)
X3B += (1.0 / 2.0) * np.einsum("abj,kc->abcjk", L.aa, H.b.ov, optimize=True)
X3B += np.einsum("ack,jb->abcjk", L.ab, H.a.ov, optimize=True)
X3B -= (1.0 / 2.0) * np.einsum("abm,jkmc->abcjk", L.aa, H.ab.ooov, optimize=True)
X3B -= np.einsum("acm,jkbm->abcjk", L.ab, H.ab.oovo, optimize=True)
X3B += np.einsum("aej,ekbc->abcjk", L.aa, H.ab.vovv, optimize=True)
X3B += np.einsum("aek,jebc->abcjk", L.ab, H.ab.ovvv, optimize=True)
X3B += (1.0 / 2.0) * np.einsum("eck,ejab->abcjk", L.ab, H.aa.vovv, optimize=True)
# < 0 | L3p2h*(H_N e^(T1+T2))_C | jk~abc~ >
X3B -= (1.0 / 2.0) * np.einsum("jm,abcmk->abcjk", H.a.oo, L.aab, optimize=True) # (1)
X3B -= (1.0 / 2.0) * np.einsum("km,abcjm->abcjk", H.b.oo, L.aab, optimize=True) # (2)
X3B += np.einsum("ea,ebcjk->abcjk", H.a.vv, L.aab, optimize=True) # (3)
X3B += (1.0 / 2.0) * np.einsum("ec,abejk->abcjk", H.b.vv, L.aab, optimize=True) # (4)
X3B += (1.0 / 2.0) * np.einsum("jkmn,abcmn->abcjk", H.ab.oooo, L.aab, optimize=True) # (5)
X3B += (1.0 / 4.0) * np.einsum("efab,efcjk->abcjk", H.aa.vvvv, L.aab, optimize=True) # (6)
X3B += np.einsum("efbc,aefjk->abcjk", H.ab.vvvv, L.aab, optimize=True) # (7)
X3B += np.einsum("ejmb,aecmk->abcjk", H.aa.voov, L.aab, optimize=True) # (8) !
X3B += np.einsum("jebm,aecmk->abcjk", H.ab.ovvo, L.abb, optimize=True) # (9)
X3B += (1.0 / 2.0) * np.einsum("ekmc,abejm->abcjk", H.ab.voov, L.aaa, optimize=True) # (10)
X3B += (1.0 / 2.0) * np.einsum("ekmc,abejm->abcjk", H.bb.voov, L.aab, optimize=True) # (11)
X3B -= (1.0 / 2.0) * np.einsum("jemc,abemk->abcjk", H.ab.ovov, L.aab, optimize=True) # (12)
X3B -= np.einsum("ekbm,aecjm->abcjk", H.ab.vovo, L.aab, optimize=True) # (13)
# three-body Hbar terms
X3B -= np.einsum("akm,jmbc->abcjk", X["ab"]["voo"], H.ab.oovv, optimize=True) # (1)
X3B -= (1.0 / 2.0) * np.einsum("mck,mjab->abcjk", X["ab"]["ovo"], H.aa.oovv, optimize=True) # (2)
X3B -= np.einsum("mbj,mkac->abcjk", X["aa"]["ovo"], H.ab.oovv, optimize=True) # (3)
X3B += (1.0 / 2.0) * np.einsum("aeb,jkec->abcjk", X["aa"]["vvv"], H.ab.oovv, optimize=True) # (4)
X3B += np.einsum("aec,jkbe->abcjk", X["ab"]["vvv"], H.ab.oovv, optimize=True) # (5)
X3B -= np.transpose(X3B, (1, 0, 2, 3, 4)) # antisymmetrize A(ab)
return X3B

def build_LH_3C(L, H, X):
"""Calculate the projection < 0 | (L1p+L2p1h+L3p2h)(H_N e^(T1+T2))_C | j~k~ab~c~ >."""
# moment-like terms < 0 | (L1p+L2p1h)*(H_N e^(T1+T2))_C | j~k~ab~c~ >
X3C = (1.0 / 4.0) * np.einsum("a,jkbc->abcjk", L.a, H.bb.oovv, optimize=True)
X3C += np.einsum("abj,kc->abcjk", L.ab, H.b.ov, optimize=True)
X3C -= (2.0 / 4.0) * np.einsum("abm,jkmc->abcjk", L.ab, H.bb.ooov, optimize=True)
X3C += (2.0 / 4.0) * np.einsum("aej,ekbc->abcjk", L.ab, H.bb.vovv, optimize=True)
X3C += np.einsum("eck,ejab->abcjk", L.ab, H.ab.vovv, optimize=True) # !
# < 0 | L3p2h*(H_N e^(T1+T2))_C | j!k~ab!c~ >
X3C -= (2.0 / 4.0) * np.einsum("jm,abcmk->abcjk", H.b.oo, L.abb, optimize=True)
X3C += (2.0 / 4.0) * np.einsum("eb,aecjk->abcjk", H.b.vv, L.abb, optimize=True)
X3C += (1.0 / 4.0) * np.einsum("ea,ebcjk->abcjk", H.a.vv, L.abb, optimize=True)
X3C += (1.0 / 8.0) * np.einsum("jkmn,abcmn->abcjk", H.bb.oooo, L.abb, optimize=True)
X3C += (2.0 / 4.0) * np.einsum("efab,efcjk->abcjk", H.ab.vvvv, L.abb, optimize=True)
X3C += (1.0 / 8.0) * np.einsum("efbc,aefjk->abcjk", H.bb.vvvv, L.abb, optimize=True)
X3C += np.einsum("ejmb,aecmk->abcjk", H.ab.voov, L.aab, optimize=True)
X3C += np.einsum("ejmb,aecmk->abcjk", H.bb.voov, L.abb, optimize=True)
X3C -= (2.0 / 4.0) * np.einsum("ejam,ebcmk->abcjk", H.ab.vovo, L.abb, optimize=True)
# three-body Hbar terms
X3C -= np.einsum("mck,mjab->abcjk", X["ab"]["ovo"], H.ab.oovv, optimize=True)
X3C -= (2.0 / 4.0) * np.einsum("ajm,mkbc->abcjk", X["ab"]["voo"], H.bb.oovv, optimize=True)
X3C += (2.0 / 4.0) * np.einsum("aeb,jkec->abcjk", X["ab"]["vvv"], H.bb.oovv, optimize=True)
X3C -= np.transpose(X3C, (0, 2, 1, 3, 4)) # antisymmetrize A(bc)
X3C -= np.transpose(X3C, (0, 1, 2, 4, 3)) # antisymmetrize A(jk)
return X3C
1 change: 1 addition & 0 deletions ccpy/utilities/updates/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ MODULES := cc_loops \
ccp3_loops \
ccp3_opt_loops \
ccp3_adaptive_loops \
eaccp3_loops \
clusteranalysis \
ecccp3_loops \
reorder \
Expand Down
Loading

0 comments on commit e350b3f

Please sign in to comment.