def get_full_t3p2(mycc, t1, t2, eris): '''Build the entire T3[2] array in memory. ''' nkpts = mycc.nkpts nocc = mycc.nocc nmo = mycc.nmo nvir = nmo - nocc kconserv = mycc.khelper.kconserv def get_wijkabc(ki, kj, kk, ka, kb, kc): '''Build T3[2] for `ijkabc` at a given set of k-points''' km = kconserv[kc, kk, kb] kf = kconserv[kk, kc, kj] ret = einsum('kjcf,ifab->ijkabc', t2[kk, kj, kc], eris.ovvv[ki, kf, ka].conj()) ret = ret - einsum('jima,mkbc->ijkabc', eris.ooov[kj, ki, km].conj(), t2[km, kk, kb]) return ret #fock = eris.fock #fov = fock[:, :nocc, nocc:] #foo = numpy.array([fock[ikpt, :nocc, :nocc].diagonal() for ikpt in range(nkpts)]) #fvv = numpy.array([fock[ikpt, nocc:, nocc:].diagonal() for ikpt in range(nkpts)]) mo_energy_occ = numpy.array( [eris.mo_energy[ki][:nocc] for ki in range(nkpts)]) mo_energy_vir = numpy.array( [eris.mo_energy[ki][nocc:] for ki in range(nkpts)]) mo_e_o = mo_energy_occ mo_e_v = mo_energy_vir # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(mycc, kind="split") t3 = numpy.empty((nkpts, nkpts, nkpts, nkpts, nkpts, nocc, nocc, nocc, nvir, nvir, nvir), dtype=t2.dtype) for ki, kj, kk, ka, kb in product(range(nkpts), repeat=5): kc = kpts_helper.get_kconserv3(mycc._scf.cell, mycc.kpts, [ki, kj, kk, ka, kb]) # Perform P(abc) t3[ki, kj, kk, ka, kb] = get_wijkabc(ki, kj, kk, ka, kb, kc) t3[ki, kj, kk, ka, kb] += get_wijkabc(ki, kj, kk, kb, kc, ka).transpose(0, 1, 2, 5, 3, 4) t3[ki, kj, kk, ka, kb] += get_wijkabc(ki, kj, kk, kc, ka, kb).transpose(0, 1, 2, 4, 5, 3) # Perform P(ijk) t3 = (t3.transpose(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + t3.transpose(1, 2, 0, 3, 4, 6, 7, 5, 8, 9, 10) + t3.transpose(2, 0, 1, 3, 4, 7, 5, 6, 8, 9, 10)) for ki, kj, kk in product(range(nkpts), repeat=3): eijk = _get_epqr([0, nocc, ki, mo_e_o, nonzero_opadding], [0, nocc, kj, mo_e_o, nonzero_opadding], [0, nocc, kk, mo_e_o, nonzero_opadding]) for ka, kb in product(range(nkpts), repeat=2): kc = kpts_helper.get_kconserv3(mycc._scf.cell, mycc.kpts, [ki, kj, kk, ka, kb]) eabc = _get_epqr([0, nvir, ka, mo_e_v, nonzero_vpadding], [0, nvir, kb, mo_e_v, nonzero_vpadding], [0, nvir, kc, mo_e_v, nonzero_vpadding], fac=[-1., -1., -1.]) eijkabc = eijk[:, :, :, None, None, None] + eabc[None, None, None, :, :, :] t3[ki, kj, kk, ka, kb] /= eijkabc return t3
def get_t3p2_imds(mycc, t1, t2, eris=None, t3p2_ip_out=None, t3p2_ea_out=None): """For a description of arguments, see `get_t3p2_imds_slow` in the corresponding `kintermediates.py`. """ from pyscf.pbc.cc.kccsd_t_rhf import _get_epqr cpu1 = cpu0 = (logger.process_clock(), logger.perf_counter()) if eris is None: eris = mycc.ao2mo() fock = eris.fock nkpts, nocc, nvir = t1.shape cell = mycc._scf.cell kpts = mycc.kpts kconserv = mycc.khelper.kconserv dtype = np.result_type(t1, t2) fov = fock[:, :nocc, nocc:] #foo = np.asarray([fock[ikpt, :nocc, :nocc].diagonal() for ikpt in range(nkpts)]) #fvv = np.asarray([fock[ikpt, nocc:, nocc:].diagonal() for ikpt in range(nkpts)]) mo_energy_occ = np.array( [eris.mo_energy[ki][:nocc] for ki in range(nkpts)]) mo_energy_vir = np.array( [eris.mo_energy[ki][nocc:] for ki in range(nkpts)]) mo_e_o = mo_energy_occ mo_e_v = mo_energy_vir ccsd_energy = mycc.energy(t1, t2, eris) if t3p2_ip_out is None: t3p2_ip_out = np.zeros((nkpts, nkpts, nkpts, nocc, nvir, nocc, nocc), dtype=dtype) Wmcik = t3p2_ip_out if t3p2_ea_out is None: t3p2_ea_out = np.zeros((nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc), dtype=dtype) Wacek = t3p2_ea_out # Create necessary temporary eris for fast read from pyscf.pbc.cc.kccsd_t_rhf import create_t3_eris, get_data_slices feri_tmp, t2T, eris_vvop, eris_vooo_C = create_t3_eris( mycc, kconserv, [eris.vovv, eris.oovv, eris.ooov, t2]) #t1T = np.array([x.T for x in t1], dtype=np.complex, order='C') #fvo = np.array([x.T for x in fov], dtype=np.complex, order='C') cpu1 = logger.timer_debug1(mycc, 'CCSD(T) tmp eri creation', *cpu1) def get_w(ki, kj, kk, ka, kb, kc, a0, a1, b0, b1, c0, c1): '''Wijkabc intermediate as described in Scuseria paper before Pijkabc acts Function copied for `kccsd_t_rhf.py`''' km = kconserv[kc, kk, kb] kf = kconserv[kk, kc, kj] out = einsum('cfjk,abif->abcijk', t2T[kc, kf, kj, c0:c1, :, :, :], eris_vvop[ka, kb, ki, a0:a1, b0:b1, :, nocc:]) out = out - einsum('cbmk,aijm->abcijk', t2T[kc, kb, km, c0:c1, b0:b1, :, :], eris_vooo_C[ka, ki, kj, a0:a1, :, :, :]) return out def get_permuted_w(ki, kj, kk, ka, kb, kc, orb_indices): '''Pijkabc operating on Wijkabc intermediate as described in Scuseria paper Function copied for `kccsd_t_rhf.py`''' a0, a1, b0, b1, c0, c1 = orb_indices out = get_w(ki, kj, kk, ka, kb, kc, a0, a1, b0, b1, c0, c1) out = out + get_w(kj, kk, ki, kb, kc, ka, b0, b1, c0, c1, a0, a1).transpose(2, 0, 1, 5, 3, 4) out = out + get_w(kk, ki, kj, kc, ka, kb, c0, c1, a0, a1, b0, b1).transpose(1, 2, 0, 4, 5, 3) out = out + get_w(ki, kk, kj, ka, kc, kb, a0, a1, c0, c1, b0, b1).transpose(0, 2, 1, 3, 5, 4) out = out + get_w(kk, kj, ki, kc, kb, ka, c0, c1, b0, b1, a0, a1).transpose(2, 1, 0, 5, 4, 3) out = out + get_w(kj, ki, kk, kb, ka, kc, b0, b1, a0, a1, c0, c1).transpose(1, 0, 2, 4, 3, 5) return out def get_data(kpt_indices): idx_args = get_data_slices(kpt_indices, task, kconserv) vvop_indices, vooo_indices, t2T_vvop_indices, t2T_vooo_indices = idx_args vvop_data = [eris_vvop[tuple(x)] for x in vvop_indices] vooo_data = [eris_vooo_C[tuple(x)] for x in vooo_indices] t2T_vvop_data = [t2T[tuple(x)] for x in t2T_vvop_indices] t2T_vooo_data = [t2T[tuple(x)] for x in t2T_vooo_indices] data = [vvop_data, vooo_data, t2T_vvop_data, t2T_vooo_data] return data def add_and_permute(kpt_indices, orb_indices, data): '''Performs permutation and addition of t3 temporary arrays.''' ki, kj, kk, ka, kb, kc = kpt_indices a0, a1, b0, b1, c0, c1 = orb_indices tmp_t3Tv_ijk = np.asarray(data[0], dtype=dtype, order='C') tmp_t3Tv_jik = np.asarray(data[1], dtype=dtype, order='C') tmp_t3Tv_kji = np.asarray(data[2], dtype=dtype, order='C') #out_ijk = np.empty(data[0].shape, dtype=dtype, order='C') #drv = _ccsd.libcc.MPICCadd_and_permute_t3T #drv(ctypes.c_int(nocc), ctypes.c_int(nvir), # ctypes.c_int(0), # out_ijk.ctypes.data_as(ctypes.c_void_p), # tmp_t3Tv_ijk.ctypes.data_as(ctypes.c_void_p), # tmp_t3Tv_jik.ctypes.data_as(ctypes.c_void_p), # tmp_t3Tv_kji.ctypes.data_as(ctypes.c_void_p), # mo_offset.ctypes.data_as(ctypes.c_void_p), # slices.ctypes.data_as(ctypes.c_void_p)) return (2. * tmp_t3Tv_ijk - tmp_t3Tv_jik.transpose(0, 1, 2, 4, 3, 5) - tmp_t3Tv_kji.transpose(0, 1, 2, 5, 4, 3)) #return out_ijk # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(mycc, kind="split") mem_now = lib.current_memory()[0] max_memory = max(0, mycc.max_memory - mem_now) blkmin = 4 # temporary t3 array is size: nkpts**3 * blksize**3 * nocc**3 * 16 vir_blksize = min( nvir, max(blkmin, int( (max_memory * .9e6 / 16 / nocc**3 / nkpts**3)**(1. / 3)))) tasks = [] logger.debug(mycc, 'max_memory %d MB (%d MB in use)', max_memory, mem_now) logger.debug(mycc, 'virtual blksize = %d (nvir = %d)', vir_blksize, nvir) for a0, a1 in lib.prange(0, nvir, vir_blksize): for b0, b1 in lib.prange(0, nvir, vir_blksize): for c0, c1 in lib.prange(0, nvir, vir_blksize): tasks.append((a0, a1, b0, b1, c0, c1)) eaa = [] for ka in range(nkpts): eaa.append(mo_e_o[ka][:, None] - mo_e_v[ka][None, :]) pt1 = np.zeros((nkpts, nocc, nvir), dtype=dtype) pt2 = np.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=dtype) for ka, kb in product(range(nkpts), repeat=2): for task_id, task in enumerate(tasks): cput2 = (logger.process_clock(), logger.perf_counter()) a0, a1, b0, b1, c0, c1 = task my_permuted_w = np.zeros( (nkpts, ) * 3 + (a1 - a0, b1 - b0, c1 - c0) + (nocc, ) * 3, dtype=dtype) for ki, kj, kk in product(range(nkpts), repeat=3): # Find momentum conservation condition for triples # amplitude t3ijkabc kc = kpts_helper.get_kconserv3(cell, kpts, [ki, kj, kk, ka, kb]) kpt_indices = [ki, kj, kk, ka, kb, kc] #data = get_data(kpt_indices) my_permuted_w[ki, kj, kk] = get_permuted_w(ki, kj, kk, ka, kb, kc, task) for ki, kj, kk in product(range(nkpts), repeat=3): # eigenvalue denominator: e(i) + e(j) + e(k) eijk = _get_epqr([0, nocc, ki, mo_e_o, nonzero_opadding], [0, nocc, kj, mo_e_o, nonzero_opadding], [0, nocc, kk, mo_e_o, nonzero_opadding]) # Find momentum conservation condition for triples # amplitude t3ijkabc kc = kpts_helper.get_kconserv3(cell, kpts, [ki, kj, kk, ka, kb]) eabc = _get_epqr([a0, a1, ka, mo_e_v, nonzero_vpadding], [b0, b1, kb, mo_e_v, nonzero_vpadding], [c0, c1, kc, mo_e_v, nonzero_vpadding], fac=[-1., -1., -1.]) kpt_indices = [ki, kj, kk, ka, kb, kc] eabcijk = (eijk[None, None, None, :, :, :] + eabc[:, :, :, None, None, None]) tmp_t3Tv_ijk = my_permuted_w[ki, kj, kk] tmp_t3Tv_jik = my_permuted_w[kj, ki, kk] tmp_t3Tv_kji = my_permuted_w[kk, kj, ki] Ptmp_t3Tv = add_and_permute( kpt_indices, task, (tmp_t3Tv_ijk, tmp_t3Tv_jik, tmp_t3Tv_kji)) Ptmp_t3Tv /= eabcijk # Contribution to T1 amplitudes if ki == ka and kc == kconserv[kj, kb, kk]: eris_Soovv = ( 2. * eris.oovv[kj, kk, kb, :, :, b0:b1, c0:c1] - eris.oovv[kj, kk, kc, :, :, c0:c1, b0:b1].transpose( 0, 1, 3, 2)) pt1[ka, :, a0:a1] += 0.5 * einsum('abcijk,jkbc->ia', Ptmp_t3Tv, eris_Soovv) # Contribution to T2 amplitudes if ki == ka and kc == kconserv[kj, kb, kk]: tmp = einsum('abcijk,ia->jkbc', Ptmp_t3Tv, 0.5 * fov[ki, :, a0:a1]) _add_pt2(pt2, nkpts, kconserv, [kj, kk, kb], [None, None, (b0, b1), (c0, c1)], tmp) kd = kconserv[ka, ki, kb] eris_vovv = eris.vovv[kd, ki, kb, :, :, b0:b1, a0:a1] tmp = einsum('abcijk,diba->jkdc', Ptmp_t3Tv, eris_vovv) _add_pt2(pt2, nkpts, kconserv, [kj, kk, kd], [None, None, None, (c0, c1)], tmp) km = kconserv[kc, kk, kb] eris_ooov = eris.ooov[kj, ki, km, :, :, :, a0:a1] tmp = einsum('abcijk,jima->mkbc', Ptmp_t3Tv, eris_ooov) _add_pt2(pt2, nkpts, kconserv, [km, kk, kb], [None, None, (b0, b1), (c0, c1)], -1. * tmp) # Contribution to Wovoo array km = kconserv[ka, ki, kc] eris_oovv = eris.oovv[km, ki, kc, :, :, c0:c1, a0:a1] tmp = einsum('abcijk,mica->mbkj', Ptmp_t3Tv, eris_oovv) Wmcik[km, kb, kk, :, b0:b1, :, :] += tmp # Contribution to Wvvoo array ke = kconserv[ki, ka, kk] eris_oovv = eris.oovv[ki, kk, ka, :, :, a0:a1, :] tmp = einsum('abcijk,ikae->cbej', Ptmp_t3Tv, eris_oovv) Wacek[kc, kb, ke, c0:c1, b0:b1, :, :] -= tmp logger.timer_debug1( mycc, 'EOM-CCSD T3[2] ka,kb,vir=(%d,%d,%d/%d) [total=%d]' % (ka, kb, task_id, len(tasks), nkpts**5), *cput2) for ki in range(nkpts): ka = ki eia = LARGE_DENOM * np.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = np.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:, None] - mo_e_v[ka])[n0_ovp_ia] pt1[ki] /= eia for ki, ka in product(range(nkpts), repeat=2): eia = LARGE_DENOM * np.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = np.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:, None] - mo_e_v[ka])[n0_ovp_ia] for kj in range(nkpts): kb = kconserv[ki, ka, kj] ejb = LARGE_DENOM * np.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_jb = np.ix_(nonzero_opadding[kj], nonzero_vpadding[kb]) ejb[n0_ovp_jb] = (mo_e_o[kj][:, None] - mo_e_v[kb])[n0_ovp_jb] eijab = eia[:, None, :, None] + ejb[:, None, :] pt2[ki, kj, ka] /= eijab pt1 += t1 pt2 += t2 logger.timer(mycc, 'EOM-CCSD(T) imds', *cpu0) delta_ccsd_energy = mycc.energy(pt1, pt2, eris) - ccsd_energy logger.info(mycc, 'CCSD energy T3[2] correction : %16.12e', delta_ccsd_energy) return delta_ccsd_energy, pt1, pt2, Wmcik, Wacek
def kernel(mycc, eris, t1=None, t2=None, max_memory=2000, verbose=logger.INFO): '''Returns the CCSD(T) for general spin-orbital integrals with k-points. Note: Returns real part of the CCSD(T) energy, raises warning if there is a complex part. Args: mycc (:class:`GCCSD`): Coupled-cluster object storing results of a coupled-cluster calculation. eris (:class:`_ERIS`): Integral object holding the relevant electron- repulsion integrals and Fock matrix elements t1 (:obj:`ndarray`): t1 coupled-cluster amplitudes t2 (:obj:`ndarray`): t2 coupled-cluster amplitudes max_memory (float): Maximum memory used in calculation (NOT USED) verbose (int, :class:`Logger`): verbosity of calculation Returns: energy_t (float): The real-part of the k-point CCSD(T) energy. ''' assert isinstance(mycc, pyscf.pbc.cc.kccsd.GCCSD) if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mycc.stdout, verbose) if t1 is None: t1 = mycc.t1 if t2 is None: t2 = mycc.t2 if t1 is None or t2 is None: raise TypeError( 'Must pass in t1/t2 amplitudes to k-point CCSD(T)! (Maybe ' 'need to run `.ccsd()` on the ccsd object?)') cell = mycc._scf.cell kpts = mycc.kpts # The dtype of any local arrays that will be created dtype = t1.dtype nkpts, nocc, nvir = t1.shape mo_energy_occ = [eris.mo_energy[ki][:nocc] for ki in range(nkpts)] mo_energy_vir = [eris.mo_energy[ki][nocc:] for ki in range(nkpts)] fov = eris.fock[:, :nocc, nocc:] mo_e_o = mo_energy_occ mo_e_v = mo_energy_vir # Set up class for k-point conservation kconserv = kpts_helper.get_kconserv(cell, kpts) # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(mycc, kind="split") energy_t = 0.0 for ki in range(nkpts): for kj in range(ki + 1): for kk in range(kj + 1): # eigenvalue denominator: e(i) + e(j) + e(k) eijk = _get_epqr([0, nocc, ki, mo_e_o, nonzero_opadding], [0, nocc, kj, mo_e_o, nonzero_opadding], [0, nocc, kk, mo_e_o, nonzero_opadding]) # Factors to include for permutational symmetry among k-points for occupied space if ki == kj and kj == kk: symm_ijk_kpt = 1. # only one degeneracy elif ki == kj or kj == kk: symm_ijk_kpt = 3. # 3 degeneracies when only one k-point is unique else: symm_ijk_kpt = 6. # 3! combinations of arranging 3 distinct k-points for ka in range(nkpts): for kb in range(ka + 1): # Find momentum conservation condition for triples # amplitude t3ijkabc kc = kpts_helper.get_kconserv3(cell, kpts, [ki, kj, kk, ka, kb]) if kc not in range(kb + 1): continue # -1.0 so the LARGE_DENOM does not cancel with the one from eijk eabc = _get_epqr( [0, nvir, ka, mo_e_v, nonzero_vpadding], [0, nvir, kb, mo_e_v, nonzero_vpadding], [0, nvir, kc, mo_e_v, nonzero_vpadding], fac=[-1., -1., -1.]) # Factors to include for permutational symmetry among k-points for virtual space if ka == kb and kb == kc: symm_abc_kpt = 1. # one unique combination of (ka, kb, kc) elif ka == kb or kb == kc: symm_abc_kpt = 3. # 3 unique combinations of (ka, kb, kc) else: symm_abc_kpt = 6. # 6 unique combinations of (ka, kb, kc) # Determine the a, b, c indices we will loop over as # determined by the k-point symmetry. abc_indices = cartesian_prod([range(nvir)] * 3) symm_3d = symm_2d_ab = symm_2d_bc = False if ka == kc: # == kb from lower triangular summation abc_indices = tril_product( range(nvir), repeat=3, tril_idx=[0, 1, 2]) # loop a >= b >= c symm_3d = True elif ka == kb: abc_indices = tril_product( range(nvir), repeat=3, tril_idx=[0, 1]) # loop a >= b symm_2d_ab = True elif kb == kc: abc_indices = tril_product( range(nvir), repeat=3, tril_idx=[1, 2]) # loop b >= c symm_2d_bc = True for a, b, c in abc_indices: # See symm_3d and abc_indices above for description of factors symm_abc = 1. if symm_3d: if a == b == c: symm_abc = 1. elif a == b or b == c: symm_abc = 3. else: symm_abc = 6. elif symm_2d_ab: if a == b: symm_abc = 1. else: symm_abc = 2. elif symm_2d_bc: if b == c: symm_abc = 1. else: symm_abc = 2. # Form energy denominator eijkabc = (eijk[:, :, :] + eabc[a, b, c]) # Form connected triple excitation amplitude t3c = np.zeros((nocc, nocc, nocc), dtype=dtype) # First term: 1 - p(ij) - p(ik) ke = kconserv[kj, ka, kk] t3c = t3c + einsum( 'jke,ie->ijk', t2[kj, kk, ka, :, :, a, :], -eris.ovvv[ki, ke, kc, :, :, c, b].conj()) ke = kconserv[ki, ka, kk] t3c = t3c - einsum( 'ike,je->ijk', t2[ki, kk, ka, :, :, a, :], -eris.ovvv[kj, ke, kc, :, :, c, b].conj()) ke = kconserv[kj, ka, ki] t3c = t3c - einsum( 'jie,ke->ijk', t2[kj, ki, ka, :, :, a, :], -eris.ovvv[kk, ke, kc, :, :, c, b].conj()) km = kconserv[kb, ki, kc] t3c = t3c - einsum( 'mi,jkm->ijk', t2[km, ki, kb, :, :, b, c], eris.ooov[kj, kk, km, :, :, :, a].conj()) km = kconserv[kb, kj, kc] t3c = t3c + einsum( 'mj,ikm->ijk', t2[km, kj, kb, :, :, b, c], eris.ooov[ki, kk, km, :, :, :, a].conj()) km = kconserv[kb, kk, kc] t3c = t3c + einsum( 'mk,jim->ijk', t2[km, kk, kb, :, :, b, c], eris.ooov[kj, ki, km, :, :, :, a].conj()) # Second term: - p(ab) + p(ab) p(ij) + p(ab) p(ik) ke = kconserv[kj, kb, kk] t3c = t3c - einsum( 'jke,ie->ijk', t2[kj, kk, kb, :, :, b, :], -eris.ovvv[ki, ke, kc, :, :, c, a].conj()) ke = kconserv[ki, kb, kk] t3c = t3c + einsum( 'ike,je->ijk', t2[ki, kk, kb, :, :, b, :], -eris.ovvv[kj, ke, kc, :, :, c, a].conj()) ke = kconserv[kj, kb, ki] t3c = t3c + einsum( 'jie,ke->ijk', t2[kj, ki, kb, :, :, b, :], -eris.ovvv[kk, ke, kc, :, :, c, a].conj()) km = kconserv[ka, ki, kc] t3c = t3c + einsum( 'mi,jkm->ijk', t2[km, ki, ka, :, :, a, c], eris.ooov[kj, kk, km, :, :, :, b].conj()) km = kconserv[ka, kj, kc] t3c = t3c - einsum( 'mj,ikm->ijk', t2[km, kj, ka, :, :, a, c], eris.ooov[ki, kk, km, :, :, :, b].conj()) km = kconserv[ka, kk, kc] t3c = t3c - einsum( 'mk,jim->ijk', t2[km, kk, ka, :, :, a, c], eris.ooov[kj, ki, km, :, :, :, b].conj()) # Third term: - p(ac) + p(ac) p(ij) + p(ac) p(ik) ke = kconserv[kj, kc, kk] t3c = t3c - einsum( 'jke,ie->ijk', t2[kj, kk, kc, :, :, c, :], -eris.ovvv[ki, ke, ka, :, :, a, b].conj()) ke = kconserv[ki, kc, kk] t3c = t3c + einsum( 'ike,je->ijk', t2[ki, kk, kc, :, :, c, :], -eris.ovvv[kj, ke, ka, :, :, a, b].conj()) ke = kconserv[kj, kc, ki] t3c = t3c + einsum( 'jie,ke->ijk', t2[kj, ki, kc, :, :, c, :], -eris.ovvv[kk, ke, ka, :, :, a, b].conj()) km = kconserv[kb, ki, ka] t3c = t3c + einsum( 'mi,jkm->ijk', t2[km, ki, kb, :, :, b, a], eris.ooov[kj, kk, km, :, :, :, c].conj()) km = kconserv[kb, kj, ka] t3c = t3c - einsum( 'mj,ikm->ijk', t2[km, kj, kb, :, :, b, a], eris.ooov[ki, kk, km, :, :, :, c].conj()) km = kconserv[kb, kk, ka] t3c = t3c - einsum( 'mk,jim->ijk', t2[km, kk, kb, :, :, b, a], eris.ooov[kj, ki, km, :, :, :, c].conj()) # Form disconnected triple excitation amplitude contribution t3d = np.zeros((nocc, nocc, nocc), dtype=dtype) # First term: 1 - p(ij) - p(ik) if ki == ka: t3d = t3d + einsum( 'i,jk->ijk', t1[ki, :, a], -eris.oovv[kj, kk, kb, :, :, b, c].conj()) t3d = t3d + einsum('i,jk->ijk', -fov[ki, :, a], t2[kj, kk, kb, :, :, b, c]) if kj == ka: t3d = t3d - einsum( 'j,ik->ijk', t1[kj, :, a], -eris.oovv[ki, kk, kb, :, :, b, c].conj()) t3d = t3d - einsum('j,ik->ijk', -fov[kj, :, a], t2[ki, kk, kb, :, :, b, c]) if kk == ka: t3d = t3d - einsum( 'k,ji->ijk', t1[kk, :, a], -eris.oovv[kj, ki, kb, :, :, b, c].conj()) t3d = t3d - einsum('k,ji->ijk', -fov[kk, :, a], t2[kj, ki, kb, :, :, b, c]) # Second term: - p(ab) + p(ab) p(ij) + p(ab) p(ik) if ki == kb: t3d = t3d - einsum( 'i,jk->ijk', t1[ki, :, b], -eris.oovv[kj, kk, ka, :, :, a, c].conj()) t3d = t3d - einsum('i,jk->ijk', -fov[ki, :, b], t2[kj, kk, ka, :, :, a, c]) if kj == kb: t3d = t3d + einsum( 'j,ik->ijk', t1[kj, :, b], -eris.oovv[ki, kk, ka, :, :, a, c].conj()) t3d = t3d + einsum('j,ik->ijk', -fov[kj, :, b], t2[ki, kk, ka, :, :, a, c]) if kk == kb: t3d = t3d + einsum( 'k,ji->ijk', t1[kk, :, b], -eris.oovv[kj, ki, ka, :, :, a, c].conj()) t3d = t3d + einsum('k,ji->ijk', -fov[kk, :, b], t2[kj, ki, ka, :, :, a, c]) # Third term: - p(ac) + p(ac) p(ij) + p(ac) p(ik) if ki == kc: t3d = t3d - einsum( 'i,jk->ijk', t1[ki, :, c], -eris.oovv[kj, kk, kb, :, :, b, a].conj()) t3d = t3d - einsum('i,jk->ijk', -fov[ki, :, c], t2[kj, kk, kb, :, :, b, a]) if kj == kc: t3d = t3d + einsum( 'j,ik->ijk', t1[kj, :, c], -eris.oovv[ki, kk, kb, :, :, b, a].conj()) t3d = t3d + einsum('j,ik->ijk', -fov[kj, :, c], t2[ki, kk, kb, :, :, b, a]) if kk == kc: t3d = t3d + einsum( 'k,ji->ijk', t1[kk, :, c], -eris.oovv[kj, ki, kb, :, :, b, a].conj()) t3d = t3d + einsum('k,ji->ijk', -fov[kk, :, c], t2[kj, ki, kb, :, :, b, a]) t3c_plus_d = t3c + t3d t3c_plus_d /= eijkabc energy_t += symm_abc_kpt * symm_ijk_kpt * symm_abc * einsum( 'ijk,ijk', t3c, t3c_plus_d.conj()) energy_t = (1. / 36) * energy_t / nkpts if abs(energy_t.imag) > 1e-4: log.warn('Non-zero imaginary part of CCSD(T) energy was found %s', energy_t.imag) log.note('CCSD(T) correction per cell = %.15g', energy_t.real) return energy_t.real
def get_t3p2_imds_slow(cc, t1, t2, eris=None, t3p2_ip_out=None, t3p2_ea_out=None): """For a description of arguments, see `get_t3p2_imds_slow` in the corresponding `kintermediates.py`. """ from pyscf.pbc.cc.kccsd_t_rhf import _get_epqr if eris is None: eris = cc.ao2mo() fock = eris.fock nkpts, nocc, nvir = t1.shape kconserv = cc.khelper.kconserv dtype = np.result_type(t1, t2) fov = fock[:, :nocc, nocc:] #foo = [fock[ikpt, :nocc, :nocc].diagonal() for ikpt in range(nkpts)] #fvv = [fock[ikpt, nocc:, nocc:].diagonal() for ikpt in range(nkpts)] mo_energy_occ = np.array( [eris.mo_energy[ki][:nocc] for ki in range(nkpts)]) mo_energy_vir = np.array( [eris.mo_energy[ki][nocc:] for ki in range(nkpts)]) mo_e_o = mo_energy_occ mo_e_v = mo_energy_vir # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(cc, kind="split") ccsd_energy = cc.energy(t1, t2, eris) if t3p2_ip_out is None: t3p2_ip_out = np.zeros((nkpts, nkpts, nkpts, nocc, nvir, nocc, nocc), dtype=dtype) Wmcik = t3p2_ip_out if t3p2_ea_out is None: t3p2_ea_out = np.zeros((nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc), dtype=dtype) Wacek = t3p2_ea_out from itertools import product tmp_t3 = np.empty((nkpts, nkpts, nkpts, nkpts, nkpts, nocc, nocc, nocc, nvir, nvir, nvir), dtype=t2.dtype) def get_w(ki, kj, kk, ka, kb, kc): kf = kconserv[ka, ki, kb] ret = lib.einsum('fiba,kjcf->ijkabc', eris.vovv[kf, ki, kb].conj(), t2[kk, kj, kc]) km = kconserv[kc, kk, kb] ret -= lib.einsum('jima,mkbc->ijkabc', eris.ooov[kj, ki, km].conj(), t2[km, kk, kb]) return ret for ki, kj, kk, ka, kb in product(range(nkpts), repeat=5): kc = kpts_helper.get_kconserv3(cc._scf.cell, cc.kpts, [ki, kj, kk, ka, kb]) tmp_t3[ki, kj, kk, ka, kb] = get_w(ki, kj, kk, ka, kb, kc) tmp_t3[ki, kj, kk, ka, kb] += get_w(ki, kk, kj, ka, kc, kb).transpose(0, 2, 1, 3, 5, 4) tmp_t3[ki, kj, kk, ka, kb] += get_w(kj, ki, kk, kb, ka, kc).transpose(1, 0, 2, 4, 3, 5) tmp_t3[ki, kj, kk, ka, kb] += get_w(kj, kk, ki, kb, kc, ka).transpose(2, 0, 1, 5, 3, 4) tmp_t3[ki, kj, kk, ka, kb] += get_w(kk, ki, kj, kc, ka, kb).transpose(1, 2, 0, 4, 5, 3) tmp_t3[ki, kj, kk, ka, kb] += get_w(kk, kj, ki, kc, kb, ka).transpose(2, 1, 0, 5, 4, 3) eijk = _get_epqr([0, nocc, ki, mo_e_o, nonzero_opadding], [0, nocc, kj, mo_e_o, nonzero_opadding], [0, nocc, kk, mo_e_o, nonzero_opadding]) eabc = _get_epqr([0, nvir, ka, mo_e_v, nonzero_vpadding], [0, nvir, kb, mo_e_v, nonzero_vpadding], [0, nvir, kc, mo_e_v, nonzero_vpadding], fac=[-1., -1., -1.]) eijkabc = eijk[:, :, :, None, None, None] + eabc[None, None, None, :, :, :] tmp_t3[ki, kj, kk, ka, kb] /= eijkabc pt1 = np.zeros((nkpts, nocc, nvir), dtype=t2.dtype) for ki in range(nkpts): for km, kn, ke in product(range(nkpts), repeat=3): kf = kconserv[km, ke, kn] Soovv = 2. * eris.oovv[km, kn, ke] - eris.oovv[km, kn, kf].transpose( 0, 1, 3, 2) St3 = (tmp_t3[ki, km, kn, ki, ke] - tmp_t3[ki, km, kn, ke, ki].transpose(0, 1, 2, 4, 3, 5)) pt1[ki] += lib.einsum('mnef,imnaef->ia', Soovv, St3) pt2 = np.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=t2.dtype) for ki, kj, ka in product(range(nkpts), repeat=3): kb = kconserv[ki, ka, kj] for km in range(nkpts): for kn in range(nkpts): # (ia,jb) -> (ia,jb) ke = kconserv[km, kj, kn] pt2[ki, kj, ka] += -2. * lib.einsum( 'imnabe,mnje->ijab', tmp_t3[ki, km, kn, ka, kb], eris.ooov[km, kn, kj]) pt2[ki, kj, ka] += lib.einsum('imnabe,nmje->ijab', tmp_t3[ki, km, kn, ka, kb], eris.ooov[kn, km, kj]) pt2[ki, kj, ka] += lib.einsum('inmeab,mnje->ijab', tmp_t3[ki, kn, km, ke, ka], eris.ooov[km, kn, kj]) # (ia,jb) -> (jb,ia) ke = kconserv[km, ki, kn] pt2[ki, kj, ka] += -2. * lib.einsum( 'jmnbae,mnie->ijab', tmp_t3[kj, km, kn, kb, ka], eris.ooov[km, kn, ki]) pt2[ki, kj, ka] += lib.einsum('jmnbae,nmie->ijab', tmp_t3[kj, km, kn, kb, ka], eris.ooov[kn, km, ki]) pt2[ki, kj, ka] += lib.einsum('jnmeba,mnie->ijab', tmp_t3[kj, kn, km, ke, kb], eris.ooov[km, kn, ki]) # (ia,jb) -> (ia,jb) pt2[ki, kj, ka] += lib.einsum('ijmabe,me->ijab', tmp_t3[ki, kj, km, ka, kb], fov[km]) pt2[ki, kj, ka] -= lib.einsum('ijmaeb,me->ijab', tmp_t3[ki, kj, km, ka, km], fov[km]) # (ia,jb) -> (jb,ia) pt2[ki, kj, ka] += lib.einsum('jimbae,me->ijab', tmp_t3[kj, ki, km, kb, ka], fov[km]) pt2[ki, kj, ka] -= lib.einsum('jimbea,me->ijab', tmp_t3[kj, ki, km, kb, km], fov[km]) for ke in range(nkpts): # (ia,jb) -> (ia,jb) kf = kconserv[km, ke, kb] pt2[ki, kj, ka] += 2. * lib.einsum( 'ijmaef,bmef->ijab', tmp_t3[ki, kj, km, ka, ke], eris.vovv[kb, km, ke]) pt2[ki, kj, ka] -= lib.einsum('ijmaef,bmfe->ijab', tmp_t3[ki, kj, km, ka, ke], eris.vovv[kb, km, kf]) pt2[ki, kj, ka] -= lib.einsum('imjfae,bmef->ijab', tmp_t3[ki, km, kj, kf, ka], eris.vovv[kb, km, ke]) # (ia,jb) -> (jb,ia) kf = kconserv[km, ke, ka] pt2[ki, kj, ka] += 2. * lib.einsum( 'jimbef,amef->ijab', tmp_t3[kj, ki, km, kb, ke], eris.vovv[ka, km, ke]) pt2[ki, kj, ka] -= lib.einsum('jimbef,amfe->ijab', tmp_t3[kj, ki, km, kb, ke], eris.vovv[ka, km, kf]) pt2[ki, kj, ka] -= lib.einsum('jmifbe,amef->ijab', tmp_t3[kj, km, ki, kf, kb], eris.vovv[ka, km, ke]) for ki in range(nkpts): ka = ki eia = LARGE_DENOM * np.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = np.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:, None] - mo_e_v[ka])[n0_ovp_ia] pt1[ki] /= eia for ki, ka in product(range(nkpts), repeat=2): eia = LARGE_DENOM * np.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = np.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:, None] - mo_e_v[ka])[n0_ovp_ia] for kj in range(nkpts): kb = kconserv[ki, ka, kj] ejb = LARGE_DENOM * np.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_jb = np.ix_(nonzero_opadding[kj], nonzero_vpadding[kb]) ejb[n0_ovp_jb] = (mo_e_o[kj][:, None] - mo_e_v[kb])[n0_ovp_jb] eijab = eia[:, None, :, None] + ejb[:, None, :] pt2[ki, kj, ka] /= eijab pt1 += t1 pt2 += t2 for ki, kj, kk, ka, kb in product(range(nkpts), repeat=5): kc = kpts_helper.get_kconserv3(cc._scf.cell, cc.kpts, [ki, kj, kk, ka, kb]) km = kconserv[kc, ki, ka] _oovv = eris.oovv[km, ki, kc] Wmcik[km, kb, kk] += 2. * lib.einsum('ijkabc,mica->mbkj', tmp_t3[ki, kj, kk, ka, kb], _oovv) Wmcik[km, kb, kk] -= lib.einsum('jikabc,mica->mbkj', tmp_t3[kj, ki, kk, ka, kb], _oovv) Wmcik[km, kb, kk] -= lib.einsum('kjiabc,mica->mbkj', tmp_t3[kk, kj, ki, ka, kb], _oovv) for ki, kj, kk, ka, kb in product(range(nkpts), repeat=5): kc = kpts_helper.get_kconserv3(cc._scf.cell, cc.kpts, [ki, kj, kk, ka, kb]) ke = kconserv[ki, ka, kk] _oovv = eris.oovv[ki, kk, ka] Wacek[kc, kb, ke] -= 2. * lib.einsum('ijkabc,ikae->cbej', tmp_t3[ki, kj, kk, ka, kb], _oovv) Wacek[kc, kb, ke] += lib.einsum('jikabc,ikae->cbej', tmp_t3[kj, ki, kk, ka, kb], _oovv) Wacek[kc, kb, ke] += lib.einsum('kjiabc,ikae->cbej', tmp_t3[kk, kj, ki, ka, kb], _oovv) delta_ccsd_energy = cc.energy(pt1, pt2, eris) - ccsd_energy lib.logger.info(cc, 'CCSD energy T3[2] correction : %16.12e', delta_ccsd_energy) return delta_ccsd_energy, pt1, pt2, Wmcik, Wacek