def tdm_cvs_adc2(mp, amplitude, intermediates): # Get CVS-ADC(1) result (same as CVS-ADC(0)) dm = tdm_adc0(mp, amplitude, intermediates) if "d" not in amplitude.blocks: raise ValueError( "transition_dm at ADC(2) level and beyond " "expects an excitation amplitude with a singles and a " "doubles part.") u1 = amplitude["s"] u2 = amplitude["d"] if u2.subspaces != [b.o, b.c, b.v, b.v]: raise ValueError("Mismatch in subspaces doubles part " f"(== {u2.subspaces}), where " f"{b.o}{b.c}{b.v}{b.v} was expected.") t2 = mp.t2(b.oovv) p0_ov = intermediates.cv_p_ov p0_vv = intermediates.cv_p_vv # Compute CVS-ADC(2) tdm dm[b.oc] = ( # cvs_adc2_dp0_oc -einsum("ja,Ia->jI", p0_ov, u1) + (1 / sqrt(2)) * einsum("kIab,jkab->jI", u2, t2)) # cvs_adc2_dp0_vc dm[b.vc] = u1.transpose() - einsum("ab,Ib->aI", p0_vv, u1) return dm
def apply(ampl): return AmplitudeVector(phhh=( + einsum("il,jkla->ijka", ampl.hh, hf.ooov).antisymmetrise(0, 1) - einsum("kila,lj->ijka", hf.ooov, ampl.hh).antisymmetrise(0, 1) + einsum("ijla,kl->ijka", hf.ooov, ampl.hh) # Possible symmetrisation? - einsum("ijla,lk->ijka", hf.ooov, ampl.hh) ))
def cvs_adc3_i2(hf, mp, intermediates): cvs_p0 = intermediates.cvs_p0 return ( + 2.0 * einsum("kIJa,ka->IJ", hf.occv, cvs_p0.ov).symmetrise() - 1.0 * einsum("kIlJ,kl->IJ", hf.ococ, cvs_p0.oo) - 1.0 * einsum("IaJb,ab->IJ", hf.cvcv, cvs_p0.vv) )
def apply(ampl): return AmplitudeVector(ph=( + einsum("ib,ab->ia", ampl.ph, i1) - einsum("ij,ja->ia", i2, ampl.ph) - einsum("jaib,jb->ia", hf.ovov, ampl.ph) # 1 - 0.5 * einsum("ikac,kc->ia", term_t2_eri, ampl.ph) # 2 ))
def apply(ampl): return AmplitudeVector( pphh=(1 / sqrt(2)) * (-2.0 * einsum("jIKa,Kb->jIab", pia_occv, ampl.ph).antisymmetrise(2, 3) - einsum("Ic,jcab->jIab", ampl.ph, pib_ovvv) - einsum("lKIc,Kc,jlab->jIab", hf.occv, ampl.ph, mp.t2oo)))
def apply(ampl): return AmplitudeVector(ph=( + einsum("jkib,jkab->ia", pia_ooov, ampl.pphh) + einsum("ijbc,jabc->ia", ampl.pphh, pib_ovvv) + einsum("icab,jkcd,jkbd->ia", hf.ovvv, ampl.pphh, mp.t2oo) # 2nd + einsum("ijka,jlbc,klbc->ia", hf.ooov, mp.t2oo, ampl.pphh) # 2nd ))
def apply(ampl): return AmplitudeVector(pphh=(( +einsum("ic,jcab->ijab", ampl.ph, pib_ovvv) + einsum("lkic,kc,jlab->ijab", hf.ooov, ampl.ph, mp.t2oo) # 2st ).antisymmetrise(0, 1) + ( -einsum("ijka,kb->ijab", pia_ooov, ampl.ph) - einsum("ijac,kbcd,kd->ijab", mp.t2oo, hf.ovvv, ampl.ph) # 2st ).antisymmetrise(2, 3)))
def s2s_tdm_adc0(mp, amplitude_l, amplitude_r, intermediates): check_singles_amplitudes([b.o, b.v], amplitude_l, amplitude_r) ul1 = amplitude_l.ph ur1 = amplitude_r.ph dm = OneParticleOperator(mp, is_symmetric=False) dm.oo = -einsum('ja,ia->ij', ul1, ur1) dm.vv = einsum('ia,ib->ab', ul1, ur1) return dm
def diffdm_adc0(mp, amplitude, intermediates): # C is either c(ore) or o(ccupied) C = b.c if mp.has_core_occupied_space else b.o check_singles_amplitudes([C, b.v], amplitude) u1 = amplitude.ph dm = OneParticleOperator(mp, is_symmetric=True) dm[C + C] = -einsum("ia,ja->ij", u1, u1) dm.vv = einsum("ia,ib->ab", u1, u1) return dm
def cvs_adc3_m11(hf, mp, intermediates): i1 = adc3_i1(hf, mp, intermediates).evaluate() i2 = cvs_adc3_i2(hf, mp, intermediates).evaluate() t2sq = einsum("ikac,jkbc->iajb", mp.t2oo, mp.t2oo).evaluate() # Build two Kronecker deltas d_cc = zeros_like(hf.fcc) d_vv = zeros_like(hf.fvv) d_cc.set_mask("II", 1.0) d_vv.set_mask("aa", 1.0) return ( + einsum("IJ,ab->IaJb", d_cc, hf.fvv + i1) - einsum("IJ,ab->IaJb", hf.fcc - i2, d_vv) - einsum("JaIb->IaJb", hf.cvcv) + ( # symmetrise I<>J and a<>b + einsum("JaIc,bc->IaJb", hf.cvcv, intermediates.cvs_p0.vv) - einsum("kIJa,kb->IaJb", hf.occv, 2.0 * intermediates.cvs_p0.ov) ).symmetrise((0, 2), (1, 3)) # TODO This hack is done to avoid opt_einsum being smart and instantiating # a tensor of dimension 6 (to avoid the vvvv tensor) in some cases, # which is the right thing to do, but not yet supported. # + 0.5 * einsum("IcJd,klac,klbd->IaJb", hf.cvcv, mp.t2oo, mp.t2oo) + 0.5 * einsum("IcJd,acbd->IaJb", hf.cvcv, einsum("klac,klbd->acbd", mp.t2oo, mp.t2oo)) - einsum("lIkJ,kalb->IaJb", hf.ococ, t2sq) )
def apply(ampl): return AmplitudeVector(pphh=( # 0th order + 2 * einsum("ijac,bc->ijab", ampl.pphh, hf.fvv).antisymmetrise(2, 3) - 2 * einsum("ik,kjab->ijab", hf.foo, ampl.pphh).antisymmetrise(0, 1) # 1st order + ( -4 * einsum("ikac,kbjc->ijab", ampl.pphh, hf.ovov) ).antisymmetrise(0, 1).antisymmetrise(2, 3) + 0.5 * einsum("ijkl,klab->ijab", hf.oooo, ampl.pphh) + 0.5 * einsum("ijcd,abcd->ijab", ampl.pphh, hf.vvvv) ))
def adc3_i2(hf, mp, intermediates): # Used only for general td2 = mp.td2(b.oovv) p0 = mp.mp2_diffdm # t2eri4 + t2eri3 / 4 t2eri_sum = mp.t2eri(b.oovv, b.ov) + 0.25 * mp.t2eri(b.oovv, b.oo) return (( # symmetrise i<>j +0.5 * einsum("ikab,jkab->ij", mp.t2oo + td2, hf.oovv) - 1.0 * einsum("ikab,jkab->ij", mp.t2oo, t2eri_sum) + 2.0 * einsum("kija,ka->ij", hf.ooov, p0.ov)).symmetrise() - einsum("ikjl,kl->ij", hf.oooo, p0.oo) - einsum("iajb,ab->ij", hf.ovov, p0.vv))
def tdm_adc2(mp, amplitude, intermediates): dm = tdm_adc1(mp, amplitude, intermediates) # Get ADC(1) result if "d" not in amplitude.blocks: raise ValueError( "transition_dm at ADC(2) level and beyond " "expects an excitation amplitude with a singles and a " "doubles part.") u1 = amplitude["s"] u2 = amplitude["d"] if u2.subspaces != [b.o, b.o, b.v, b.v]: raise ValueError("Mismatch in subspaces doubles part " f"(== {u2.subspaces}), where " f"{b.o}{b.o}{b.v}{b.v} was expected.") t2 = mp.t2(b.oovv) td2 = mp.td2(b.oovv) p0_ov = mp.mp2_diffdm[b.ov] p0_oo = mp.mp2_diffdm[b.oo] p0_vv = mp.mp2_diffdm[b.vv] # Compute ADC(2) tdm dm[b.oo] = ( # adc2_dp0_oo -einsum("ia,ja->ij", p0_ov, u1) - einsum("ikab,jkab->ij", u2, t2)) dm[b.vv] = ( # adc2_dp0_vv +einsum("ia,ib->ab", u1, p0_ov) + einsum("ijac,ijbc->ab", u2, t2)) dm[b.ov] -= einsum("ijab,jb->ia", td2, u1) # adc2_dp0_ov dm[b.vo] += 0.5 * ( # adc2_dp0_vo +einsum("ijab,jkbc,kc->ai", t2, t2, u1) - einsum("ab,ib->ai", p0_vv, u1) + einsum("ja,ij->ai", u1, p0_oo)) return dm
def diffdm_adc0(mp, amplitude, intermediates): if "s" not in amplitude.blocks: raise ValueError("state_diffdm at ADC(0) level and beyond expects " "an excitation amplitude with a singles part.") # C is either c(ore) or o(ccupied) C = b.c if mp.has_core_occupied_space else b.o u1 = amplitude["s"] if u1.subspaces != [C, b.v]: raise ValueError("Mismatch in subspaces singles part " f"(== {u1.subspaces}), where {C}{b.v} was expected") dm = OneParticleOperator(mp, is_symmetric=True) dm[C + C] = -einsum("ia,ja->ij", u1, u1) dm[b.vv] = einsum("ia,ib->ab", u1, u1) return dm
def tdm_cvs_adc2(mp, amplitude, intermediates): # Get CVS-ADC(1) result (same as CVS-ADC(0)) dm = tdm_adc0(mp, amplitude, intermediates) check_doubles_amplitudes([b.o, b.c, b.v, b.v], amplitude) u1 = amplitude.ph u2 = amplitude.pphh t2 = mp.t2(b.oovv) p0 = intermediates.cvs_p0 # Compute CVS-ADC(2) tdm dm.oc = ( # cvs_adc2_dp0_oc -einsum("ja,Ia->jI", p0.ov, u1) + (1 / sqrt(2)) * einsum("kIab,jkab->jI", u2, t2)) # cvs_adc2_dp0_vc dm.vc = u1.transpose() - einsum("ab,Ib->aI", p0.vv, u1) return dm
def diagonal_pphh_pphh_1(hf): # Fock matrix and ovov diagonal term (sometimes called "intermediate diagonal") dinterm_ov = (direct_sum("a-i->ia", hf.fvv.diagonal(), hf.foo.diagonal()) - 2.0 * einsum("iaia->ia", hf.ovov)).evaluate() if hf.has_core_occupied_space: dinterm_Cv = (direct_sum("a-I->Ia", hf.fvv.diagonal(), hf.fcc.diagonal()) - 2.0 * einsum("IaIa->Ia", hf.cvcv)).evaluate() diag_oC = einsum("iJiJ->iJ", hf.ococ) else: dinterm_Cv = dinterm_ov diag_oC = einsum("ijij->ij", hf.oooo).symmetrise() diag_vv = einsum("abab->ab", hf.vvvv).symmetrise() return AmplitudeVector(pphh=( + direct_sum("ia+Jb->iJab", dinterm_ov, dinterm_Cv).symmetrise(2, 3) + direct_sum("iJ+ab->iJab", diag_oC, diag_vv) ))
def mtm_adc2(mp, dipop, intermediates): t2 = mp.t2(b.oovv) p0 = mp.mp2_diffdm f1 = (+dipop.ov - einsum("ijab,jb->ia", t2, +dipop.ov - 0.5 * einsum("jkbc,kc->jb", t2, dipop.ov)) + 0.5 * einsum("ij,ja->ia", p0.oo, dipop.ov) - 0.5 * einsum("ib,ab->ia", dipop.ov, p0.vv) + einsum("ib,ab->ia", p0.ov, dipop.vv) - einsum("ij,ja->ia", dipop.oo, p0.ov) - einsum("ijab,jb->ia", mp.td2(b.oovv), dipop.ov)) f2 = (+einsum("ijac,bc->ijab", t2, dipop.vv).antisymmetrise(2, 3) - einsum("ik,kjab->ijab", dipop.oo, t2).antisymmetrise(0, 1)) return AmplitudeVector(ph=f1, pphh=f2)
def block_ph_ph_3(hf, mp, intermediates): if hf.has_core_occupied_space: m11 = intermediates.cvs_adc3_m11 else: m11 = intermediates.adc3_m11 diagonal = AmplitudeVector(ph=einsum("iaia->ia", m11)) def apply(ampl): return AmplitudeVector(ph=einsum("iajb,jb->ia", m11, ampl.ph)) return AdcBlock(apply, diagonal)
def block_cvs_ph_ph_2(hf, mp, intermediates): i1 = intermediates.adc2_i1 diagonal = AmplitudeVector( ph=(+direct_sum("a-i->ia", i1.diagonal(), hf.fcc.diagonal()) - einsum("IaIa->Ia", hf.cvcv))) def apply(ampl): return AmplitudeVector(ph=(+einsum("ib,ab->ia", ampl.ph, i1) - einsum("ij,ja->ia", hf.fcc, ampl.ph) - einsum("JaIb,Jb->Ia", hf.cvcv, ampl.ph))) return AdcBlock(apply, diagonal)
def block_ph_ph_2(hf, mp, intermediates): i1 = intermediates.adc2_i1 i2 = intermediates.adc2_i2 diagonal = AmplitudeVector( ph=(+direct_sum("a-i->ia", i1.diagonal(), i2.diagonal()) - einsum("IaIa->Ia", hf.ovov) - einsum("ikac,ikac->ia", mp.t2oo, hf.oovv))) # Not used anywhere else, so kept as an anonymous intermediate term_t2_eri = (+einsum("ijab,jkbc->ikac", mp.t2oo, hf.oovv) + einsum("ijab,jkbc->ikac", hf.oovv, mp.t2oo)).evaluate() def apply(ampl): return AmplitudeVector(ph=( +einsum("ib,ab->ia", ampl.ph, i1) - einsum("ij,ja->ia", i2, ampl.ph) - einsum("jaib,jb->ia", hf.ovov, ampl.ph) # 1 - 0.5 * einsum("ikac,kc->ia", term_t2_eri, ampl.ph) # 2 )) return AdcBlock(apply, diagonal)
def apply(ampl): return AmplitudeVector(pphh=( # 0th order +2.0 * einsum("iJac,bc->iJab", ampl.pphh, hf.fvv).antisymmetrise(2, 3) - 1.0 * einsum("ik,kJab->iJab", hf.foo, ampl.pphh) - 1.0 * einsum("JK,iKab->iJab", hf.fcc, ampl.pphh) # 1st order + (-2.0 * einsum("iKac,KbJc->iJab", ampl.pphh, hf.cvcv) + 2.0 * einsum("icka,kJbc->iJab", hf.ovov, ampl.pphh) ).antisymmetrise(2, 3) + 1.0 * einsum("iJlK,lKab->iJab", hf.ococ, ampl.pphh) + 0.5 * einsum("iJcd,abcd->iJab", ampl.pphh, hf.vvvv)))
def block_hh_hh_2(hf, mp, intermediates): # Not sure if this will work directly... itm = intermediates.adc2_itm diagonal = Amplitude(hh=( + direct_sum("-i-k->ki", hf.foo.diagonal(), hf.foo.diagonal()) - hf.foooo.diagonal() - itm.diagonal() + 0.5 * einsum("ikab,jlab->ik", mp.t2oo, hf.oovv) )) def apply(ampl): return NotImplemented return AdcBlock(apply, diagonal)
def block_ph_ph_1(hf, mp, intermediates): fCC = hf.fcc if hf.has_core_occupied_space else hf.foo CvCv = hf.cvcv if hf.has_core_occupied_space else hf.ovov diagonal = AmplitudeVector(ph=( + direct_sum("a-i->ia", hf.fvv.diagonal(), fCC.diagonal()) # order 0 - einsum("IaIa->Ia", CvCv) # order 1 )) def apply(ampl): return AmplitudeVector(ph=( # PT order + einsum("ib,ab->ia", ampl.ph, hf.fvv) # 0 - einsum("IJ,Ja->Ia", fCC, ampl.ph) # 0 - einsum("JaIb,Jb->Ia", CvCv, ampl.ph) # 1 )) return AdcBlock(apply, diagonal)
def tdm_adc2(mp, amplitude, intermediates): dm = tdm_adc1(mp, amplitude, intermediates) # Get ADC(1) result check_doubles_amplitudes([b.o, b.o, b.v, b.v], amplitude) u1 = amplitude.ph u2 = amplitude.pphh t2 = mp.t2(b.oovv) td2 = mp.td2(b.oovv) p0 = mp.mp2_diffdm # Compute ADC(2) tdm dm.oo = ( # adc2_dp0_oo -einsum("ia,ja->ij", p0.ov, u1) - einsum("ikab,jkab->ij", u2, t2)) dm.vv = ( # adc2_dp0_vv +einsum("ia,ib->ab", u1, p0.ov) + einsum("ijac,ijbc->ab", u2, t2)) dm.ov -= einsum("ijab,jb->ia", td2, u1) # adc2_dp0_ov dm.vo += 0.5 * ( # adc2_dp0_vo +einsum("ijab,jkbc,kc->ai", t2, t2, u1) - einsum("ab,ib->ai", p0.vv, u1) + einsum("ja,ij->ai", u1, p0.oo)) return dm
def adc3_i1(hf, mp, intermediates): # Used for both CVS and general td2 = mp.td2(b.oovv) p0 = intermediates.cvs_p0 if hf.has_core_occupied_space else mp.mp2_diffdm t2eri_sum = ( +einsum("jicb->ijcb", mp.t2eri(b.oovv, b.ov)) # t2eri4 - 0.25 * mp.t2eri(b.oovv, b.vv) # t2eri5 ) return (( # symmetrise a<>b +0.5 * einsum("ijac,ijbc->ab", mp.t2oo + td2, hf.oovv) - 1.0 * einsum("ijac,ijcb->ab", mp.t2oo, t2eri_sum) - 2.0 * einsum("iabc,ic->ab", hf.ovvv, p0.ov)).symmetrise() + einsum("iajb,ij->ab", hf.ovov, p0.oo) + einsum("acbd,cd->ab", hf.vvvv, p0.vv))
def diffdm_cvs_adc2(mp, amplitude, intermediates): dm = diffdm_adc0(mp, amplitude, intermediates) # Get ADC(1) result check_doubles_amplitudes([b.o, b.c, b.v, b.v], amplitude) u1, u2 = amplitude.ph, amplitude.pphh t2 = mp.t2(b.oovv) p0 = intermediates.cvs_p0 p1_vv = dm.vv.evaluate() # ADC(1) diffdm # Zeroth order doubles contributions p2_ov = -sqrt(2) * einsum("jb,ijab->ia", u1, u2) p2_vo = -sqrt(2) * einsum("ijab,jb->ai", u2, u1) p2_oo = -einsum("ljab,kjab->kl", u2, u2) p2_vv = 2 * einsum("ijac,ijbc->ab", u2, u2) # Second order contributions # cvs_adc2_dp_oo dm.oo = p2_oo + einsum("ab,ikac,jkbc->ij", p1_vv, t2, t2) dm.ov = p2_ov + ( # cvs_adc2_dp_ov -einsum("ka,ab->kb", p0.ov, p1_vv) - einsum("lkdb,dl->kb", t2, p2_vo) + 1 / sqrt(2) * einsum("ib,klad,liad->kb", u1, t2, u2)) dm.vv = p1_vv + p2_vv - 0.5 * ( # cvs_adc2_dp_vv +einsum("cb,ac->ab", p1_vv, p0.vv) + einsum("cb,ac->ab", p0.vv, p1_vv) + einsum("ijbc,ijad,cd->ab", t2, t2, p1_vv)) # Add 2nd order correction to CVS-ADC(1) diffdm dm.cc -= einsum("kIab,kJab->IJ", u2, u2) return dm
def diffdm_adc2(mp, amplitude, intermediates): dm = diffdm_adc0(mp, amplitude, intermediates) # Get ADC(1) result check_doubles_amplitudes([b.o, b.o, b.v, b.v], amplitude) u1, u2 = amplitude.ph, amplitude.pphh t2 = mp.t2(b.oovv) p0 = mp.mp2_diffdm p1_oo = dm.oo.evaluate() # ADC(1) diffdm p1_vv = dm.vv.evaluate() # ADC(1) diffdm # Zeroth order doubles contributions p2_oo = -einsum("ikab,jkab->ij", u2, u2) p2_vv = einsum("ijac,ijbc->ab", u2, u2) p2_ov = -2 * einsum("jb,ijab->ia", u1, u2).evaluate() # ADC(2) ISR intermediate (TODO Move to intermediates) ru1 = einsum("ijab,jb->ia", t2, u1).evaluate() # Compute second-order contributions to the density matrix dm.oo = ( # adc2_p_oo p1_oo + 2 * p2_oo - einsum("ia,ja->ij", ru1, ru1) + (+einsum("ik,kj->ij", p1_oo, p0.oo) - einsum( "ikcd,jkcd->ij", t2, +0.5 * einsum("lk,jlcd->jkcd", p1_oo, t2) - einsum("jkcb,db->jkcd", t2, p1_vv)) - einsum("ia,jkac,kc->ij", u1, t2, ru1)).symmetrise()) dm.vv = ( # adc2_p_vv p1_vv + 2 * p2_vv + einsum("ia,ib->ab", ru1, ru1) - (+einsum("ac,cb->ab", p1_vv, p0.vv) + einsum( "klbc,klac->ab", t2, +0.5 * einsum("klad,cd->klac", t2, p1_vv) - einsum("jk,jlac->klac", p1_oo, t2)) - einsum("ikac,kc,ib->ab", t2, ru1, u1)).symmetrise()) dm.ov = ( # adc2_p_ov +p2_ov - einsum("ijab,jb->ia", t2, p2_ov) - einsum("ib,ba->ia", p0.ov, p1_vv) + einsum("ij,ja->ia", p1_oo, p0.ov) - einsum("ib,klca,klcb->ia", u1, t2, u2) - einsum("ikcd,jkcd,ja->ia", t2, u2, u1)) return dm
def tdm_adc1(mp, amplitude, intermediates): dm = tdm_adc0(mp, amplitude, intermediates) # Get ADC(0) result # adc1_dp0_ov dm[b.ov] = -einsum("ijab,jb->ia", mp.t2(b.oovv), amplitude["s"]) return dm
def apply(ampl): return AmplitudeVector(ph=( + einsum("ib,ab->ia", ampl.ph, hf.fvv) - einsum("IJ,Ja->Ia", fCC, ampl.ph) ))
def cvs_adc3_pia(hf, mp, intermediates): # Perturbation theory in CVS-ADC coupling block: # 1st 2nd return hf.occv - einsum("jlac,lKIc->jIKa", mp.t2oo, hf.occv)