def Wooov(t1, t2, eris): t1a, t1b = t1 t2aa, t2ab, t2bb = t2 dtype = np.result_type(t1a, t1b, t2aa, t2ab, t2bb) eris_ovoo = np.asarray(eris.ovoo) eris_OVOO = np.asarray(eris.OVOO) eris_OVoo = np.asarray(eris.OVoo) eris_ovOO = np.asarray(eris.ovOO) ovoo = eris_ovoo - eris_ovoo.transpose(2,1,0,3) OVOO = eris_OVOO - eris_OVOO.transpose(2,1,0,3) wooov = np.array( ovoo.transpose(2,3,0,1), dtype=dtype) wOOOV = np.array( OVOO.transpose(2,3,0,1), dtype=dtype) wooOV = np.array(eris_OVoo.transpose(2,3,0,1), dtype=dtype) wOOov = np.array(eris_ovOO.transpose(2,3,0,1), dtype=dtype) eris_ovoo = eris_OVOO = eris_ovOO = eris_OVoo = None eris_ovov = np.asarray(eris.ovov) eris_OVOV = np.asarray(eris.OVOV) eris_ovOV = np.asarray(eris.ovOV) ovov = eris_ovov - eris_ovov.transpose(0,3,2,1) OVOV = eris_OVOV - eris_OVOV.transpose(0,3,2,1) wooov += lib.einsum('if,mfne->mine', t1a, ovov) wOOOV += lib.einsum('if,mfne->mine', t1b, OVOV) wooOV += lib.einsum('if,mfNE->miNE', t1a, eris_ovOV) wOOov += lib.einsum('IF,neMF->MIne', t1b, eris_ovOV) return wooov, wooOV, wOOov, wOOOV
def Wvvov(t1, t2, eris): t1a, t1b = t1 t2aa, t2ab, t2bb = t2 nocca, noccb, nvira, nvirb = t2ab.shape dtype = np.result_type(t1a, t1b, t2aa, t2ab, t2bb) #:Wamef = einsum('na,nmef->amef', -t1, eris.oovv) #:Wamef -= np.asarray(eris.ovvv).transpose(1,0,2,3) eris_ovov = np.asarray(eris.ovov) eris_OVOV = np.asarray(eris.OVOV) eris_ovOV = np.asarray(eris.ovOV) Waemf = lib.einsum('na,nemf->aemf',-t1a, eris_ovov) Waemf+= np.asarray(eris.get_ovvv()).transpose(2,3,0,1) Waemf = Waemf - Waemf.transpose(0,3,2,1) WaeMF = lib.einsum('na,nemf->aemf',-t1a, eris_ovOV) WaeMF+= np.asarray(eris.get_OVvv()).transpose(2,3,0,1) WAEmf = lib.einsum('na,mfne->aemf',-t1b, eris_ovOV) WAEmf+= np.asarray(eris.get_ovVV()).transpose(2,3,0,1) WAEMF = lib.einsum('na,nemf->aemf',-t1b, eris_OVOV) WAEMF+= np.asarray(eris.get_OVVV()).transpose(2,3,0,1) WAEMF = WAEMF - WAEMF.transpose(0,3,2,1) return Waemf, WaeMF, WAEmf, WAEMF
def test_spin_squre(self): ss = fci.spin_op.spin_square(ci0, norb, nelec) self.assertAlmostEqual(ss[0], 6, 9) ss = fci.spin_op.spin_square0(ci0, norb, nelec) self.assertAlmostEqual(ss[0], 6, 9) numpy.random.seed(1) u,w,v = numpy.linalg.svd(numpy.random.random((norb,6))) u = u[:,:6] h1a = h1[:6,:6] h1b = reduce(numpy.dot, (v.T, h1a, v)) h2aa = ao2mo.restore(1, h2, norb)[:6,:6,:6,:6] h2ab = lib.einsum('klpq,pi,qj->klij', h2aa, v, v) h2bb = lib.einsum('pqkl,pi,qj->ijkl', h2ab, v, v) e1, ci1 = fci.direct_uhf.kernel((h1a,h1b), (h2aa,h2ab,h2bb), 6, (3,2)) ss = fci.spin_op.spin_square(ci1, 6, (3,2), mo_coeff=(numpy.eye(6),v))[0] self.assertAlmostEqual(ss, 3.75, 8) numpy.random.seed(1) n = fci.cistring.num_strings(6,3) ci1 = numpy.random.random((n,n)) ss1 = numpy.einsum('ij,ij->', ci1, fci.spin_op.contract_ss(ci1, 6, 6)) self.assertAlmostEqual(ss1, fci.spin_op.spin_square(ci1, 6, 6)[0], 12) na = fci.cistring.num_strings(6,4) nb = fci.cistring.num_strings(6,2) ci1 = numpy.random.random((na,nb)) ss1 = numpy.einsum('ij,ij->', ci1, fci.spin_op.contract_ss(ci1, 6, (4,2))) self.assertAlmostEqual(ss1, fci.spin_op.spin_square(ci1, 6, (4,2))[0], 12) numpy.random.seed(1) n = fci.cistring.num_strings(10,5) ci1 = numpy.random.random((n,n)) ss1 = numpy.einsum('ij,ij->', ci1, fci.spin_op.contract_ss(ci1, 10, 10)) self.assertAlmostEqual(ss1, fci.spin_op.spin_square(ci1, 10, 10)[0], 8)
def test_eris_contract_vvvv_t2(self): mol = gto.Mole() nocc, nvir = 5, 12 nvir_pair = nvir*(nvir+1)//2 numpy.random.seed(9) t2 = numpy.random.random((nocc,nocc,nvir,nvir)) - .5 t2 = t2 + t2.transpose(1,0,3,2) eris = ccsd._ChemistsERIs() vvvv = numpy.random.random((nvir_pair,nvir_pair)) - .5 eris.vvvv = vvvv + vvvv.T eris.mol = mol mycc.max_memory, bak = 0, mycc.max_memory vt2 = eris._contract_vvvv_t2(mycc, t2, eris.vvvv) mycc.max_memory = bak self.assertAlmostEqual(lib.finger(vt2), -39.572579908080087, 11) vvvv = ao2mo.restore(1, eris.vvvv, nvir) ref = lib.einsum('acbd,ijcd->ijab', vvvv, t2) self.assertAlmostEqual(abs(vt2 - ref).max(), 0, 11) # _contract_s1vvvv_t2, testing complex and real mixed contraction vvvv =(numpy.random.random((nvir,nvir,nvir,nvir)) + numpy.random.random((nvir,nvir,nvir,nvir))*1j - (.5+.5j)) vvvv = vvvv + vvvv.transpose(1,0,3,2).conj() vvvv = vvvv + vvvv.transpose(2,3,0,1) eris.vvvv = vvvv eris.mol = mol mycc.max_memory, bak = 0, mycc.max_memory vt2 = eris._contract_vvvv_t2(mycc, t2, eris.vvvv) mycc.max_memory = bak self.assertAlmostEqual(lib.finger(vt2), 23.502736435296871+113.90422480013488j, 11) ref = lib.einsum('acbd,ijcd->ijab', eris.vvvv, t2) self.assertAlmostEqual(abs(vt2 - ref).max(), 0, 11)
def test_eris_contract_vvvv_t2(self): mol = gto.Mole() nocca, noccb, nvira, nvirb = 5, 4, 12, 13 nvira_pair = nvira*(nvira+1)//2 nvirb_pair = nvirb*(nvirb+1)//2 numpy.random.seed(9) t2 = numpy.random.random((nocca,noccb,nvira,nvirb)) eris = uccsd._ChemistsERIs() eris.vvVV = numpy.random.random((nvira_pair,nvirb_pair)) eris.mol = mol myucc.max_memory, bak = 0, myucc.max_memory vt2 = eris._contract_vvVV_t2(myucc, t2, eris.vvVV) myucc.max_memory = bak self.assertAlmostEqual(lib.finger(vt2), 12.00904827896089, 11) idxa = lib.square_mat_in_trilu_indices(nvira) idxb = lib.square_mat_in_trilu_indices(nvirb) vvVV = eris.vvVV[:,idxb][idxa] ref = lib.einsum('acbd,ijcd->ijab', vvVV, t2) self.assertAlmostEqual(abs(vt2 - ref).max(), 0, 11) # _contract_VVVV_t2, testing complex and real mixed contraction VVVV =(numpy.random.random((nvirb,nvirb,nvirb,nvirb)) + numpy.random.random((nvirb,nvirb,nvirb,nvirb))*1j - (.5+.5j)) VVVV = VVVV + VVVV.transpose(1,0,3,2).conj() VVVV = VVVV + VVVV.transpose(2,3,0,1) eris.VVVV = VVVV t2 = numpy.random.random((noccb,noccb,nvirb,nvirb)) t2 = t2 - t2.transpose(0,1,3,2) t2 = t2 - t2.transpose(1,0,3,2) myucc.max_memory, bak = 0, myucc.max_memory vt2 = eris._contract_VVVV_t2(myucc, t2, eris.VVVV) myucc.max_memory = bak self.assertAlmostEqual(lib.finger(vt2), 47.903883794299404-50.501573400833429j, 11) ref = lib.einsum('acbd,ijcd->ijab', eris.VVVV, t2) self.assertAlmostEqual(abs(vt2 - ref).max(), 0, 11)
def vind(xys): nz = len(xys) dm1a = numpy.empty((nz,nao,nao)) dm1b = numpy.empty((nz,nao,nao)) for i in range(nz): xa, xb, ya, yb = numpy.split(xys[i], offsets) dmx = reduce(numpy.dot, (orbva, xa.reshape(nvira,nocca) , orboa.T)) dmy = reduce(numpy.dot, (orboa, ya.reshape(nvira,nocca).T, orbva.T)) dm1a[i] = dmx + dmy # AX + BY dmx = reduce(numpy.dot, (orbvb, xb.reshape(nvirb,noccb) , orbob.T)) dmy = reduce(numpy.dot, (orbob, yb.reshape(nvirb,noccb).T, orbvb.T)) dm1b[i] = dmx + dmy # AX + BY v1ao = vresp(numpy.stack((dm1a,dm1b))) v1voa = lib.einsum('xpq,pi,qj->xij', v1ao[0], orbva, orboa).reshape(nz,-1) v1vob = lib.einsum('xpq,pi,qj->xij', v1ao[1], orbvb, orbob).reshape(nz,-1) v1ova = lib.einsum('xpq,pi,qj->xji', v1ao[0], orboa, orbva).reshape(nz,-1) v1ovb = lib.einsum('xpq,pi,qj->xji', v1ao[1], orbob, orbvb).reshape(nz,-1) for i in range(nz): xa, xb, ya, yb = numpy.split(xys[i], offsets) v1voa[i] += (e_ai_a - freq - diag[0]) * xa v1voa[i] /= diag[0] v1vob[i] += (e_ai_b - freq - diag[1]) * xb v1vob[i] /= diag[1] v1ova[i] += (e_ai_a + freq - diag[2]) * ya v1ova[i] /= diag[2] v1ovb[i] += (e_ai_b + freq - diag[3]) * yb v1ovb[i] /= diag[3] v = numpy.hstack((v1voa, v1vob, v1ova, v1ovb)) return v
def _add_vvvv_full(mycc, t1T, t2T, eris, out=None, with_ovvv=False): '''Ht2 = numpy.einsum('ijcd,acdb->ijab', t2, vvvv) without using symmetry t2[ijab] = t2[jiba] in t2 or Ht2 ''' time0 = time.clock(), time.time() log = logger.Logger(mycc.stdout, mycc.verbose) nvir_seg, nvir, nocc = t2T.shape[:3] vloc0, vloc1 = _task_location(nvir, rank) nocc2 = nocc*(nocc+1)//2 if t1T is None: tau = lib.pack_tril(t2T.reshape(nvir_seg*nvir,nocc2)) else: tau = t2T + numpy.einsum('ai,bj->abij', t1T[vloc0:vloc1], t1T) tau = lib.pack_tril(tau.reshape(nvir_seg*nvir,nocc2)) tau = tau.reshape(nvir_seg,nvir,nocc2) if mycc.direct: # AO-direct CCSD if with_ovvv: raise NotImplementedError mo = getattr(eris, 'mo_coeff', None) if mo is None: # If eris does not have the attribute mo_coeff mo = _mo_without_core(mycc, mycc.mo_coeff) ao_loc = mycc.mol.ao_loc_nr() nao, nmo = mo.shape ntasks = mpi.pool.size task_sh_locs = lib.misc._balanced_partition(ao_loc, ntasks) ao_loc0 = ao_loc[task_sh_locs[rank ]] ao_loc1 = ao_loc[task_sh_locs[rank+1]] orbv = mo[:,nocc:] tau = lib.einsum('abij,pb->apij', tau, orbv) tau_priv = numpy.zeros((ao_loc1-ao_loc0,nao,nocc,nocc)) for task_id, tau in _rotate_tensor_block(tau): loc0, loc1 = _task_location(nvir, task_id) tau_priv += lib.einsum('pa,abij->pbij', orbv[ao_loc0:ao_loc1,loc0:loc1], tau) tau = None time1 = log.timer_debug1('vvvv-tau mo2ao', *time0) buf = _contract_vvvv_t2(mycc, None, tau_priv, task_sh_locs, None, log) buf = buf.reshape(tau_priv.shape) tau_priv = None time1 = log.timer_debug1('vvvv-tau contraction', *time1) buf = lib.einsum('apij,pb->abij', buf, orbv) Ht2 = numpy.ndarray(t2T.shape, buffer=out) Ht2[:] = 0 for task_id, buf in _rotate_tensor_block(buf): ao_loc0 = ao_loc[task_sh_locs[task_id ]] ao_loc1 = ao_loc[task_sh_locs[task_id+1]] Ht2 += lib.einsum('pa,pbij->abij', orbv[ao_loc0:ao_loc1,vloc0:vloc1], buf) time1 = log.timer_debug1('vvvv-tau ao2mo', *time1) else: raise NotImplementedError return Ht2.reshape(t2T.shape)
def para(magobj, gauge_orig=None, h1=None, s1=None, with_cphf=None): '''Paramagnetic susceptibility tensor Kwargs: h1: A list of arrays. Shapes are [(3,nmo_a,nocc_a), (3,nmo_b,nocc_b)] First order Fock matrices in MO basis. s1: A list of arrays. Shapes are [(3,nmo_a,nocc_a), (3,nmo_b,nocc_b)] First order overlap matrices in MO basis. with_cphf : boolean or function(dm_mo) => v1_mo If a boolean value is given, the value determines whether CPHF equation will be solved or not. The induced potential will be generated by the function gen_vind. If a function is given, CPHF equation will be solved, and the given function is used to compute induced potential ''' log = logger.Logger(magobj.stdout, magobj.verbose) cput1 = (time.clock(), time.time()) mol = magobj.mol mf = magobj._scf mo_energy = magobj._scf.mo_energy mo_coeff = magobj._scf.mo_coeff mo_occ = magobj._scf.mo_occ orboa = mo_coeff[0][:,mo_occ[0] > 0] orbob = mo_coeff[1][:,mo_occ[1] > 0] if h1 is None: # Imaginary part of F10 dm0 = (numpy.dot(orboa, orboa.T), numpy.dot(orbob, orbob.T)) h1 = magobj.get_fock(dm0, gauge_orig) h1 = (lib.einsum('xpq,pi,qj->xij', h1[0], mo_coeff[0].conj(), orboa), lib.einsum('xpq,pi,qj->xij', h1[1], mo_coeff[1].conj(), orbob)) cput1 = log.timer('first order Fock matrix', *cput1) if s1 is None: # Imaginary part of S10 s1 = magobj.get_ovlp(mol, gauge_orig) s1 = (lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[0].conj(), orboa), lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[1].conj(), orbob)) with_cphf = magobj.cphf mo1, mo_e1 = uhf_nmr.solve_mo1(magobj, mo_energy, mo_coeff, mo_occ, h1, s1, with_cphf) cput1 = logger.timer(magobj, 'solving mo1 eqn', *cput1) occidxa = mo_occ[0] > 0 occidxb = mo_occ[1] > 0 mag_para = numpy.einsum('yji,xji->xy', mo1[0], h1[0]) mag_para+= numpy.einsum('yji,xji->xy', mo1[1], h1[1]) mag_para-= numpy.einsum('yji,xji,i->xy', mo1[0], s1[0], mo_energy[0][occidxa]) mag_para-= numpy.einsum('yji,xji,i->xy', mo1[1], s1[1], mo_energy[1][occidxb]) # + c.c. mag_para = mag_para + mag_para.conj() mag_para-= numpy.einsum('xij,yij->xy', s1[0][:,occidxa], mo_e1[0]) mag_para-= numpy.einsum('xij,yij->xy', s1[1][:,occidxb], mo_e1[1]) return -mag_para
def hyper_polarizability(polobj, with_cphf=True): from pyscf.prop.nmr import uhf as uhf_nmr log = logger.new_logger(polobj) mf = polobj._scf mol = mf.mol mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidxa = mo_occ[0] > 0 occidxb = mo_occ[1] > 0 mo0a, mo0b = mo_coeff orboa = mo0a[:, occidxa] orbva = mo0a[:,~occidxa] orbob = mo0b[:, occidxb] orbvb = mo0b[:,~occidxb] charges = mol.atom_charges() coords = mol.atom_coords() charge_center = numpy.einsum('i,ix->x', charges, coords) / charges.sum() with mol.with_common_orig(charge_center): int_r = mol.intor_symmetric('int1e_r', comp=3) h1a = lib.einsum('xpq,pi,qj->xij', int_r, mo0a.conj(), orboa) h1b = lib.einsum('xpq,pi,qj->xij', int_r, mo0b.conj(), orbob) s1a = numpy.zeros_like(h1a) s1b = numpy.zeros_like(h1b) vind = polobj.gen_vind(mf, mo_coeff, mo_occ) if with_cphf: mo1, e1 = ucphf.solve(vind, mo_energy, mo_occ, (h1a,h1b), (s1a,s1b), polobj.max_cycle_cphf, polobj.conv_tol, verbose=log) else: mo1, e1 = uhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, (h1a,h1b), (s1a,s1b)) mo1a = lib.einsum('xqi,pq->xpi', mo1[0], mo0a) mo1b = lib.einsum('xqi,pq->xpi', mo1[1], mo0b) dm1a = lib.einsum('xpi,qi->xpq', mo1a, orboa) dm1b = lib.einsum('xpi,qi->xpq', mo1b, orbob) dm1a = dm1a + dm1a.transpose(0,2,1) dm1b = dm1b + dm1b.transpose(0,2,1) vresp = _gen_uhf_response(mf, hermi=1) h1ao = int_r + vresp(numpy.stack((dm1a, dm1b))) s0 = mf.get_ovlp() e3 = lib.einsum('xpq,ypi,zqi->xyz', h1ao[0], mo1a, mo1a) e3 += lib.einsum('xpq,ypi,zqi->xyz', h1ao[1], mo1b, mo1b) e3 -= lib.einsum('pq,xpi,yqj,zij->xyz', s0, mo1a, mo1a, e1[0]) e3 -= lib.einsum('pq,xpi,yqj,zij->xyz', s0, mo1b, mo1b, e1[1]) e3 = (e3 + e3.transpose(1,2,0) + e3.transpose(2,0,1) + e3.transpose(0,2,1) + e3.transpose(1,0,2) + e3.transpose(2,1,0)) e3 = -e3 log.debug('Static hyper polarizability tensor\n%s', e3) return e3
def para(magobj, gauge_orig=None, h1=None, s1=None, with_cphf=None): '''Paramagnetic susceptibility tensor Kwargs: h1: (3,nmo,nocc) array First order Fock matrix in MO basis. s1: (3,nmo,nocc) array First order overlap matrix in MO basis. with_cphf : boolean or function(dm_mo) => v1_mo If a boolean value is given, the value determines whether CPHF equation will be solved or not. The induced potential will be generated by the function gen_vind. If a function is given, CPHF equation will be solved, and the given function is used to compute induced potential ''' log = logger.Logger(magobj.stdout, magobj.verbose) cput1 = (time.clock(), time.time()) mol = magobj.mol mf = magobj._scf mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = mo_occ > 0 orbo = mo_coeff[:,occidx] if h1 is None: # Imaginary part of F10 dm0 = mf.make_rdm1(mo_coeff, mo_occ) h1 = lib.einsum('xpq,pi,qj->xij', magobj.get_fock(dm0, gauge_orig), mo_coeff.conj(), orbo) if s1 is None: # Imaginary part of S10 s1 = lib.einsum('xpq,pi,qj->xij', magobj.get_ovlp(mol, gauge_orig), mo_coeff.conj(), orbo) cput1 = log.timer('first order Fock matrix', *cput1) with_cphf = magobj.cphf mo1, mo_e1 = rhf_nmr.solve_mo1(magobj, mo_energy, mo_coeff, mo_occ, h1, s1, with_cphf) cput1 = logger.timer(magobj, 'solving mo1 eqn', *cput1) mag_para = numpy.einsum('yji,xji->xy', mo1, h1) mag_para-= numpy.einsum('yji,xji,i->xy', mo1, s1, mo_energy[occidx]) # + c.c. mag_para = mag_para + mag_para.conj() mag_para-= numpy.einsum('xij,yij->xy', s1[:,occidx], mo_e1) # *2 for double occupancy. mag_para *= 2 return -mag_para
def vind(mo1): mo1 = mo1.reshape(-1,nmoa*nocca+nmob*noccb) mo1a = mo1[:,:nmoa*nocca].reshape(-1,nmoa,nocca) mo1b = mo1[:,nmoa*nocca:].reshape(-1,nmob,noccb) dm1a = lib.einsum('xai,pa,qi->xpq', mo1a, mo0a, orboa.conj()) dm1b = lib.einsum('xai,pa,qi->xpq', mo1b, mo0b, orbob.conj()) dm1a = dm1a + dm1a.transpose(0,2,1).conj() dm1b = dm1b + dm1b.transpose(0,2,1).conj() v1ao = vresp(numpy.stack((dm1a,dm1b))) v1a = lib.einsum('xpq,pi,qj->xij', v1ao[0], mo0a.conj(), orboa) v1b = lib.einsum('xpq,pi,qj->xij', v1ao[1], mo0b.conj(), orbob) v1mo = numpy.hstack((v1a.reshape(-1,nmoa*nocca), v1b.reshape(-1,nmob*noccb))) return v1mo.ravel()
def _make_rdm1(mycc, d1, with_frozen=True, ao_repr=False): doo, dOO = d1[0] dov, dOV = d1[1] dvo, dVO = d1[2] dvv, dVV = d1[3] nocca, nvira = dov.shape noccb, nvirb = dOV.shape nmoa = nocca + nvira nmob = noccb + nvirb dm1a = numpy.empty((nmoa,nmoa), dtype=doo.dtype) dm1a[:nocca,:nocca] = doo + doo.conj().T dm1a[:nocca,nocca:] = dov + dvo.conj().T dm1a[nocca:,:nocca] = dm1a[:nocca,nocca:].conj().T dm1a[nocca:,nocca:] = dvv + dvv.conj().T dm1a *= .5 dm1a[numpy.diag_indices(nocca)] += 1 dm1b = numpy.empty((nmob,nmob), dtype=dOO.dtype) dm1b[:noccb,:noccb] = dOO + dOO.conj().T dm1b[:noccb,noccb:] = dOV + dVO.conj().T dm1b[noccb:,:noccb] = dm1b[:noccb,noccb:].conj().T dm1b[noccb:,noccb:] = dVV + dVV.conj().T dm1b *= .5 dm1b[numpy.diag_indices(noccb)] += 1 if with_frozen and not (mycc.frozen is 0 or mycc.frozen is None): nmoa = mycc.mo_occ[0].size nmob = mycc.mo_occ[1].size nocca = numpy.count_nonzero(mycc.mo_occ[0] > 0) noccb = numpy.count_nonzero(mycc.mo_occ[1] > 0) rdm1a = numpy.zeros((nmoa,nmoa), dtype=dm1a.dtype) rdm1b = numpy.zeros((nmob,nmob), dtype=dm1b.dtype) rdm1a[numpy.diag_indices(nocca)] = 1 rdm1b[numpy.diag_indices(noccb)] = 1 moidx = mycc.get_frozen_mask() moidxa = numpy.where(moidx[0])[0] moidxb = numpy.where(moidx[1])[0] rdm1a[moidxa[:,None],moidxa] = dm1a rdm1b[moidxb[:,None],moidxb] = dm1b dm1a = rdm1a dm1b = rdm1b if ao_repr: mo_a, mo_b = mycc.mo_coeff dm1a = lib.einsum('pi,ij,qj->pq', mo_a, dm1a, mo_a) dm1b = lib.einsum('pi,ij,qj->pq', mo_b, dm1b, mo_b) return dm1a, dm1b
def kernel(method, efg_nuc=None): log = lib.logger.Logger(method.stdout, method.verbose) cell = method.cell if efg_nuc is None: efg_nuc = range(cell.natm) dm = method.make_rdm1() if isinstance(method, scf.khf.KSCF): if isinstance(dm[0][0], numpy.ndarray) and dm[0][0].ndim == 2: dm = dm[0] + dm[1] # KUHF density matrix elif isinstance(method, scf.hf.SCF): if isinstance(dm[0], numpy.ndarray) and dm[0].ndim == 2: dm = dm[0] + dm[1] # UHF density matrix else: mo = method.mo_coeff if isinstance(dm[0][0], numpy.ndarray) and dm[0][0].ndim == 2: dm_a = [lib.einsum('pi,ij,qj->pq', c, dm[0][k], c.conj()) for k, c in enumerate(mo)] dm_b = [lib.einsum('pi,ij,qj->pq', c, dm[1][k], c.conj()) for k, c in enumerate(mo)] dm = lib.asarray(dm_a) + lib.asarray(dm_b) else: dm = lib.asarray([lib.einsum('pi,ij,qj->pq', c, dm[k], c.conj()) for k, c in enumerate(mo)]) if isinstance(method, scf.hf.SCF): with_df = getattr(method, 'with_df', None) with_x2c = getattr(method, 'with_x2c', None) else: with_df = getattr(method._scf, 'with_df', None) with_x2c = getattr(method._scf, 'with_x2c', None) if with_x2c: raise NotImplementedError log.info('\nElectric Field Gradient Tensor Results') if isinstance(with_df, df.fft.FFTDF): efg_e = _fft_quad_integrals(with_df, dm, efg_nuc) else: efg_e = _aft_quad_integrals(with_df, dm, efg_nuc) efg = [] for i, atm_id in enumerate(efg_nuc): efg_nuc = _get_quad_nuc(cell, atm_id) v = efg_nuc - efg_e[i] efg.append(v) rhf_efg._analyze(cell, atm_id, v, log) return numpy.asarray(efg)
def test_uccsd_rdm2_mo2ao(self): mol = gto.Mole() mol.verbose = 0 mol.atom = [ [8 , (0. , 0. , 0.)], [1 , (0. , -0.757 , 0.587)], [1 , (0. , 0.757 , 0.587)]] mol.spin = 2 mol.basis = '631g' mol.build(0, 0) mf = scf.UHF(mol) mf.conv_tol_grad = 1e-8 mf.kernel() mycc = cc.UCCSD(mf) mycc.diis_start_cycle = 1 mycc.conv_tol = 1e-10 eris = mycc.ao2mo() ecc, t1, t2 = mycc.kernel(eris=eris) l1, l2 = mycc.solve_lambda(eris=eris) fdm2 = lib.H5TmpFile() d2 = cc.uccsd_rdm._gamma2_outcore(mycc, t1, t2, l1, l2, fdm2, True) nao = mycc.mo_coeff[0].shape[0] ref = cc.uccsd_rdm._make_rdm2(mycc, None, d2, with_dm1=False) aa = lib.einsum('ijkl,pi,qj,rk,sl->pqrs', ref[0], mycc.mo_coeff[0], mycc.mo_coeff[0], mycc.mo_coeff[0], mycc.mo_coeff[0]) ab = lib.einsum('ijkl,pi,qj,rk,sl->pqrs', ref[1], mycc.mo_coeff[0], mycc.mo_coeff[0], mycc.mo_coeff[1], mycc.mo_coeff[1]) bb = lib.einsum('ijkl,pi,qj,rk,sl->pqrs', ref[2], mycc.mo_coeff[1], mycc.mo_coeff[1], mycc.mo_coeff[1], mycc.mo_coeff[1]) aa = aa + aa.transpose(0,1,3,2) aa = aa + aa.transpose(1,0,2,3) aa = ao2mo.restore(4, aa, nao) * .5 bb = bb + bb.transpose(0,1,3,2) bb = bb + bb.transpose(1,0,2,3) bb = ao2mo.restore(4, bb, nao) * .5 ab = ab + ab.transpose(0,1,3,2) ab = ab + ab.transpose(1,0,2,3) ab = ao2mo.restore(4, ab, nao) * .5 ref = (aa+ab, bb+ab.T) rdm2 = uccsd_grad._rdm2_mo2ao(mycc, d2, mycc.mo_coeff) self.assertAlmostEqual(abs(ref[0]-rdm2[0]).max(), 0, 10) self.assertAlmostEqual(abs(ref[1]-rdm2[1]).max(), 0, 10) uccsd_grad._rdm2_mo2ao(mycc, d2, mycc.mo_coeff, fdm2) self.assertAlmostEqual(abs(ref[0]-fdm2['dm2aa+ab'].value).max(), 0, 10) self.assertAlmostEqual(abs(ref[1]-fdm2['dm2bb+ab'].value).max(), 0, 10) self.assertAlmostEqual(lib.finger(rdm2[0]), -1.6247203743431637, 7) self.assertAlmostEqual(lib.finger(rdm2[1]), -0.44062825991527471, 7)
def project_dm_nr2nr(mol1, dm1, mol2): r''' Project density matrix representation from basis set 1 (mol1) to basis set 2 (mol2). .. math:: |AO2\rangle DM_AO2 \langle AO2| = |AO2\rangle P DM_AO1 P \langle AO2| DM_AO2 = P DM_AO1 P P = S_{AO2}^{-1}\langle AO2|AO1\rangle There are three relevant functions: :func:`project_dm_nr2nr` is the projection for non-relativistic (scalar) basis. :func:`project_dm_nr2r` projects from non-relativistic to relativistic basis. :func:`project_dm_r2r` is the projection between relativistic (spinor) basis. ''' s22 = mol2.intor_symmetric('int1e_ovlp') s21 = mole.intor_cross('int1e_ovlp', mol2, mol1) p21 = lib.cho_solve(s22, s21) if isinstance(dm1, numpy.ndarray) and dm1.ndim == 2: return reduce(numpy.dot, (p21, dm1, p21.conj().T)) else: return lib.einsum('pi,nij,qj->npq', p21, dm1, p21.conj())
def get_mo_pairs_G(mydf, mo_coeffs, kpts=numpy.zeros((2,3)), q=None, compact=getattr(__config__, 'pbc_df_mo_pairs_compact', False)): '''Calculate forward fourier transform (G|ij) of all MO pairs. Args: mo_coeff: length-2 list of (nao,nmo) ndarrays The two sets of MO coefficients to use in calculating the product |ij). Returns: mo_pairs_G : (ngrids, nmoi*nmoj) ndarray The FFT of the real-space MO pairs. ''' if kpts is None: kpts = numpy.zeros((2,3)) cell = mydf.cell kpts = numpy.asarray(kpts) q = kpts[1] - kpts[0] coords = cell.gen_uniform_grids(mydf.mesh) nmoi = mo_coeffs[0].shape[1] nmoj = mo_coeffs[1].shape[1] ngrids = len(coords) mo_pairs_G = numpy.empty((ngrids,nmoi,nmoj), dtype=numpy.complex) for pqkR, pqkI, p0, p1 \ in mydf.pw_loop(mydf.mesh, kptijkl[:2], q, max_memory=max_memory, aosym='s2'): pqk = (pqkR + pqkI*1j).reshape(nao,nao,-1) mo_pairs_G[p0:p1] = lib.einsum('pqk,pi,qj->kij', pqk, *mo_coeffs[:2]) return mo_pairs_G.reshape(ngrids,nmoi*nmoj)
def _make_rdm1(mycc, d1, with_frozen=True, ao_repr=False): '''dm1[p,q] = <q_alpha^\dagger p_alpha> + <q_beta^\dagger p_beta> The convention of 1-pdm is based on McWeeney's book, Eq (5.4.20). The contraction between 1-particle Hamiltonian and rdm1 is E = einsum('pq,qp', h1, rdm1) ''' doo, dov, dvo, dvv = d1 nocc, nvir = dov.shape nmo = nocc + nvir dm1 = numpy.empty((nmo,nmo), dtype=doo.dtype) dm1[:nocc,:nocc] = doo + doo.conj().T dm1[:nocc,nocc:] = dov + dvo.conj().T dm1[nocc:,:nocc] = dm1[:nocc,nocc:].conj().T dm1[nocc:,nocc:] = dvv + dvv.conj().T dm1[numpy.diag_indices(nocc)] += 2 if with_frozen and not (mycc.frozen is 0 or mycc.frozen is None): nmo = mycc.mo_occ.size nocc = numpy.count_nonzero(mycc.mo_occ > 0) rdm1 = numpy.zeros((nmo,nmo), dtype=dm1.dtype) rdm1[numpy.diag_indices(nocc)] = 2 moidx = numpy.where(mycc.get_frozen_mask())[0] rdm1[moidx[:,None],moidx] = dm1 dm1 = rdm1 if ao_repr: mo = mycc.mo_coeff dm1 = lib.einsum('pi,ij,qj->pq', mo, dm1, mo.conj()) return dm1
def _gamma1_intermediates(mycc, t1, t2, l1, l2): nocc, nvir = t1.shape doo =-numpy.einsum('ja,ia->ij', t1, l1) dvv = numpy.einsum('ia,ib->ab', t1, l1) xtv = numpy.einsum('ie,me->im', t1, l1) dvo = t1.T - numpy.einsum('im,ma->ai', xtv, t1) theta = t2 * 2 - t2.transpose(0,1,3,2) doo -= lib.einsum('jkab,ikab->ij', theta, l2) dvv += lib.einsum('jica,jicb->ab', theta, l2) xt1 = lib.einsum('mnef,inef->mi', l2, theta) xt2 = lib.einsum('mnaf,mnef->ea', l2, theta) dvo += numpy.einsum('imae,me->ai', theta, l1) dvo -= numpy.einsum('mi,ma->ai', xt1, t1) dvo -= numpy.einsum('ie,ae->ai', t1, xt2) dov = l1 return doo, dov, dvo, dvv
def contract_2e(eri, fcivec, norb, nelec, opt=None): if isinstance(nelec, (int, numpy.integer)): nelecb = nelec//2 neleca = nelec - nelecb else: neleca, nelecb = nelec link_indexa = cistring.gen_linkstr_index(range(norb), neleca) link_indexb = cistring.gen_linkstr_index(range(norb), nelecb) na = cistring.num_strings(norb, neleca) nb = cistring.num_strings(norb, nelecb) ci0 = fcivec.reshape(na,nb) t1 = numpy.zeros((norb,norb,na,nb)) for str0, tab in enumerate(link_indexa): for a, i, str1, sign in tab: t1[a,i,str1] += sign * ci0[str0] for str0, tab in enumerate(link_indexb): for a, i, str1, sign in tab: t1[a,i,:,str1] += sign * ci0[:,str0] t1 = lib.einsum('bjai,aiAB->bjAB', eri.reshape([norb]*4), t1) fcinew = numpy.zeros_like(ci0) for str0, tab in enumerate(link_indexa): for a, i, str1, sign in tab: fcinew[str1] += sign * t1[a,i,str0] for str0, tab in enumerate(link_indexb): for a, i, str1, sign in tab: fcinew[:,str1] += sign * t1[a,i,:,str0] return fcinew.reshape(fcivec.shape)
def polarizability_with_freq(polobj, freq=None): from pyscf.prop.nmr import rhf as rhf_nmr log = logger.new_logger(polobj) mf = polobj._scf mol = mf.mol mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidx = mo_occ > 0 orbo = mo_coeff[:, occidx] orbv = mo_coeff[:,~occidx] charges = mol.atom_charges() coords = mol.atom_coords() charge_center = numpy.einsum('i,ix->x', charges, coords) / charges.sum() with mol.with_common_orig(charge_center): int_r = mol.intor_symmetric('int1e_r', comp=3) h1 = lib.einsum('xpq,pi,qj->xij', int_r, orbv.conj(), orbo) mo1 = cphf_with_freq(mf, mo_energy, mo_occ, h1, freq, polobj.max_cycle_cphf, polobj.conv_tol, verbose=log)[0] e2 = numpy.einsum('xpi,ypi->xy', h1, mo1[0]) e2 += numpy.einsum('xpi,ypi->xy', h1, mo1[1]) # *-1 from the definition of dipole moment. *2 for double occupancy e2 *= -2 log.debug('Polarizability tensor with freq %s', freq) log.debug('%s', e2) return e2
def test_add_vvVV(self): myucc = uccsd.UCCSD(mf_s2) nocca, noccb = 6,4 nmo = mf_s2.mo_occ[0].size nvira, nvirb = nmo-nocca, nmo-noccb numpy.random.seed(9) t1 = [numpy.zeros((nocca,nvira)), numpy.zeros((noccb,nvirb))] t2 = [numpy.random.random((nocca,nocca,nvira,nvira))-.9, numpy.random.random((nocca,noccb,nvira,nvirb))-.9, numpy.random.random((noccb,noccb,nvirb,nvirb))-.9] t2[0] = t2[0] - t2[0].transpose(1,0,2,3) t2[0] = t2[0] - t2[0].transpose(0,1,3,2) t2[2] = t2[2] - t2[2].transpose(1,0,2,3) t2[2] = t2[2] - t2[2].transpose(0,1,3,2) eris1 = copy.copy(eris) idxa = lib.square_mat_in_trilu_indices(nvira) idxb = lib.square_mat_in_trilu_indices(nvirb) vvVV = eris1.vvVV[:,idxb][idxa] ref = lib.einsum('acbd,ijcd->ijab', vvVV, t2[1]) t2a = myucc._add_vvVV((t1[0]*0,t1[1]*0), t2[1], eris) self.assertAlmostEqual(abs(ref-t2a).max(), 0, 12) myucc.direct = True eris1.vvvv = None # == with_ovvv=True in the call below eris1.VVVV = None eris1.vvVV = None t1 = None myucc.mo_coeff, eris1.mo_coeff = eris1.mo_coeff, None t2b = myucc._add_vvVV(t1, t2[1], eris1) self.assertAlmostEqual(abs(ref-t2b).max(), 0, 12)
def para(magobj, gauge_orig=None, h1=None, s1=None, with_cphf=None): '''Part of rotational g-tensors from the first order wavefunctions. Unit hbar/mu_N is not included. This part may be different to the conventional para-magnetic contributions of rotational g-tensors. ''' mol = magobj.mol im, mass_center = rhf_g.inertia_tensor(mol) if gauge_orig is None: # The first order Hamiltonian for rotation part is the same to the # first order Hamiltonian for magnetic field except a factor of 2. It can # be computed using the magnetizability code. mag_para = uhf_mag.para(magobj, gauge_orig, h1, s1, with_cphf) * 2 else: mf = magobj._scf mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ orboa = mo_coeff[0][:,mo_occ[0]>0] orbob = mo_coeff[1][:,mo_occ[1]>0] # for magnetic field with mol.with_common_origin(mass_center): h10 = .5 * mol.intor('int1e_cg_irxp', 3) h10a = lib.einsum('xpq,pi,qj->xij', h10, mo_coeff[0].conj(), orboa) h10b = lib.einsum('xpq,pi,qj->xij', h10, mo_coeff[1].conj(), orbob) # for rotation part with mol.with_common_origin(gauge_orig): h01 = -mol.intor('int1e_cg_irxp', 3) h01a = lib.einsum('xpq,pi,qj->xij', h01, mo_coeff[0].conj(), orboa) h01b = lib.einsum('xpq,pi,qj->xij', h01, mo_coeff[1].conj(), orbob) s10a = numpy.zeros_like(h10a) s10b = numpy.zeros_like(h10b) mo10 = uhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, (h10a,h10b), (s10a,s10b))[0] mag_para = numpy.einsum('xji,yji->xy', mo10[0].conj(), h01a) mag_para+= numpy.einsum('xji,yji->xy', mo10[1].conj(), h01b) mag_para = mag_para + mag_para.conj() mag_para = rhf_g._safe_solve(im, mag_para) # unit = hbar/mu_N, mu_N is nuclear magneton unit = -2 * nist.PROTON_MASS_AU return mag_para * unit
def grad_elec(mc, mf_grad): mf = mf_grad.base mol = mf_grad.mol mo_energy = mc.mo_energy mo_coeff = mc.mo_coeff ncore = mc.ncore ncas = mc.ncas nocc = ncore + ncas nelecas = mc.nelecas nao, nmo = mo_coeff.shape hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) casdm1, casdm2 = mc.fcisolver.make_rdm12(mc.ci, ncas, nelecas) dm1 = numpy.zeros((nmo,nmo)) dm1[numpy.diag_indices(ncore)] = 2 dm1[ncore:nocc,ncore:nocc] = casdm1 dm2 = numpy.zeros((nmo,nmo,nmo,nmo)) for i in range(ncore): for j in range(ncore): dm2[i,i,j,j] += 4 dm2[i,j,j,i] -= 2 dm2[i,i,ncore:nocc,ncore:nocc] = casdm1 * 2 dm2[ncore:nocc,ncore:nocc,i,i] = casdm1 * 2 dm2[i,ncore:nocc,ncore:nocc,i] =-casdm1 dm2[ncore:nocc,i,i,ncore:nocc] =-casdm1 dm2[ncore:nocc,ncore:nocc,ncore:nocc,ncore:nocc] = casdm2 h1 = reduce(numpy.dot, (mo_coeff.T, mc._scf.get_hcore(), mo_coeff)) h2 = ao2mo.kernel(mf._eri, mo_coeff, compact=False).reshape([nmo]*4) # Generalized Fock, according to generalized Brillouin theorm # Adv. Chem. Phys., 69, 63 gfock = numpy.dot(h1, dm1) gfock+= numpy.einsum('iqrs,qjsr->ij', h2, dm2) gfock = (gfock + gfock.T) * .5 dme0 = reduce(numpy.dot, (mo_coeff[:,:nocc], gfock[:nocc,:nocc], mo_coeff[:,:nocc].T)) dm1 = reduce(numpy.dot, (mo_coeff, dm1, mo_coeff.T)) dm2 = lib.einsum('ijkl,pi,qj,rk,sl->pqrs', dm2, mo_coeff, mo_coeff, mo_coeff, mo_coeff) eri_deriv1 = mol.intor('int2e_ip1', comp=3).reshape(3,nao,nao,nao,nao) atmlst = range(mol.natm) aoslices = mol.aoslice_by_atom() de = numpy.zeros((len(atmlst),3)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) de[k] += numpy.einsum('xij,ij->x', h1ao, dm1) de[k] -= numpy.einsum('xij,ij->x', s1[:,p0:p1], dme0[p0:p1]) * 2 de[k] -= numpy.einsum('xijkl,ijkl->x', eri_deriv1[:,p0:p1], dm2[p0:p1]) * 2 return de
def polarizability(polobj, with_cphf=True): from pyscf.prop.nmr import uhf as uhf_nmr log = logger.new_logger(polobj) mf = polobj._scf mol = mf.mol mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ occidxa = mo_occ[0] > 0 occidxb = mo_occ[1] > 0 mo0a, mo0b = mo_coeff orboa = mo0a[:, occidxa] orbva = mo0a[:,~occidxa] orbob = mo0b[:, occidxb] orbvb = mo0b[:,~occidxb] charges = mol.atom_charges() coords = mol.atom_coords() charge_center = numpy.einsum('i,ix->x', charges, coords) / charges.sum() with mol.with_common_orig(charge_center): int_r = mol.intor_symmetric('int1e_r', comp=3) h1a = lib.einsum('xpq,pi,qj->xij', int_r, mo0a.conj(), orboa) h1b = lib.einsum('xpq,pi,qj->xij', int_r, mo0b.conj(), orbob) s1a = numpy.zeros_like(h1a) s1b = numpy.zeros_like(h1b) vind = polobj.gen_vind(mf, mo_coeff, mo_occ) if with_cphf: mo1 = ucphf.solve(vind, mo_energy, mo_occ, (h1a,h1b), (s1a,s1b), polobj.max_cycle_cphf, polobj.conv_tol, verbose=log)[0] else: mo1 = uhf_nmr._solve_mo1_uncoupled(mo_energy, mo_occ, (h1a,h1b), (s1a,s1b))[0] e2 = numpy.einsum('xpi,ypi->xy', h1a, mo1[0]) e2+= numpy.einsum('xpi,ypi->xy', h1b, mo1[1]) e2 = -(e2 + e2.T) if mf.verbose >= logger.INFO: xx, yy, zz = e2.diagonal() log.note('Isotropic polarizability %.12g', (xx+yy+zz)/3) log.note('Polarizability anisotropy %.12g', (.5 * ((xx-yy)**2 + (yy-zz)**2 + (zz-xx)**2))**.5) log.debug('Static polarizability tensor\n%s', e2) return e2
def solve_mo1(nmrobj, mo_energy=None, mo_coeff=None, mo_occ=None, h1=None, s1=None, with_cphf=None): '''Solve the first order equation Kwargs: with_cphf : boolean or function(dm_mo) => v1_mo If a boolean value is given, the value determines whether CPHF equation will be solved or not. The induced potential will be generated by the function gen_vind. If a function is given, CPHF equation will be solved, and the given function is used to compute induced potential ''' cput1 = (time.clock(), time.time()) log = logger.Logger(nmrobj.stdout, nmrobj.verbose) if mo_energy is None: mo_energy = nmrobj._scf.mo_energy if mo_coeff is None: mo_coeff = nmrobj._scf.mo_coeff if mo_occ is None: mo_occ = nmrobj._scf.mo_occ if with_cphf is None: with_cphf = nmrobj.cphf mol = nmrobj.mol orboa = mo_coeff[0][:,mo_occ[0]>0] orbob = mo_coeff[1][:,mo_occ[1]>0] if h1 is None: dm0 = nmrobj._scf.make_rdm1(mo_coeff, mo_occ) h1 = nmrobj.get_fock(dm0) h1 = (lib.einsum('xpq,pi,qj->xij', h1[0], mo_coeff[0].conj(), orboa), lib.einsum('xpq,pi,qj->xij', h1[1], mo_coeff[1].conj(), orbob)) cput1 = log.timer('first order Fock matrix', *cput1) if s1 is None: s1 = nmrobj.get_ovlp(mol) s1 = (lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[0].conj(), orboa), lib.einsum('xpq,pi,qj->xij', s1, mo_coeff[1].conj(), orbob)) if with_cphf: if callable(with_cphf): vind = with_cphf else: vind = gen_vind(nmrobj._scf, mo_coeff, mo_occ) mo10, mo_e10 = ucphf.solve(vind, mo_energy, mo_occ, h1, s1, nmrobj.max_cycle_cphf, nmrobj.conv_tol, verbose=log) else: mo10, mo_e10 = _solve_mo1_uncoupled(mo_energy, mo_occ, h1, s1) logger.timer(nmrobj, 'solving mo1 eqn', *cput1) return mo10, mo_e10
def Woooo(t1, t2, eris): t1a, t1b = t1 t2aa, t2ab, t2bb = t2 eris_ovoo = np.asarray(eris.ovoo) eris_OVOO = np.asarray(eris.OVOO) eris_OVoo = np.asarray(eris.OVoo) eris_ovOO = np.asarray(eris.ovOO) ovoo = eris_ovoo - eris_ovoo.transpose(2,1,0,3) OVOO = eris_OVOO - eris_OVOO.transpose(2,1,0,3) woooo = lib.einsum('je,nemi->minj', t1a, ovoo) wOOOO = lib.einsum('je,nemi->minj', t1b, OVOO) wooOO = lib.einsum('JE,NEmi->miNJ', t1b, eris_OVoo) woOOo = lib.einsum('je,meNI->mINj',-t1a, eris_ovOO) woooo += np.asarray(eris.oooo) wOOOO += np.asarray(eris.OOOO) wooOO += np.asarray(eris.ooOO) woooo = woooo - woooo.transpose(0,3,2,1) wOOOO = wOOOO - wOOOO.transpose(0,3,2,1) wooOO = wooOO - woOOo.transpose(0,3,2,1) eris_ovov = np.asarray(eris.ovov) eris_OVOV = np.asarray(eris.OVOV) eris_ovOV = np.asarray(eris.ovOV) ovov = eris_ovov - eris_ovov.transpose(0,3,2,1) OVOV = eris_OVOV - eris_OVOV.transpose(0,3,2,1) tauaa, tauab, taubb = make_tau(t2, t1, t1) woooo += 0.5*lib.einsum('ijef,menf->minj', tauaa, ovov) wOOOO += 0.5*lib.einsum('ijef,menf->minj', taubb, OVOV) wooOO += lib.einsum('iJeF,meNF->miNJ', tauab, eris_ovOV) wOOoo = None return woooo, wooOO, wOOoo, wOOOO
def e(*args): """Numpy optimized einsum.""" for i in args: if isinstance(i, Number) and i == 0: return 0 try: return numpy.einsum(*args, optimize=True) except TypeError: return lib.einsum(*args)
def _gamma1_intermediates(mp, t2): t2aa, t2ab, t2bb = t2 dooa = lib.einsum('imef,jmef->ij', t2aa.conj(), t2aa) *-.5 dooa -= lib.einsum('imef,jmef->ij', t2ab.conj(), t2ab) doob = lib.einsum('imef,jmef->ij', t2bb.conj(), t2bb) *-.5 doob -= lib.einsum('mief,mjef->ij', t2ab.conj(), t2ab) dvva = lib.einsum('mnae,mnbe->ba', t2aa.conj(), t2aa) * .5 dvva += lib.einsum('mnae,mnbe->ba', t2ab.conj(), t2ab) dvvb = lib.einsum('mnae,mnbe->ba', t2bb.conj(), t2bb) * .5 dvvb += lib.einsum('mnea,mneb->ba', t2ab.conj(), t2ab) return ((dooa, doob), (dvva, dvvb))
def make_h1_fcsd(mol, mo_coeff, mo_occ, atmlst): '''FC + SD''' orboa = mo_coeff[0][:,mo_occ[0]> 0] orbva = mo_coeff[0][:,mo_occ[0]==0] orbob = mo_coeff[1][:,mo_occ[1]> 0] orbvb = mo_coeff[1][:,mo_occ[1]==0] nao = mo_coeff[0].shape[0] h1aa = [] h1ab = [] h1ba = [] h1bb = [] for ia in atmlst: h1ao = rhf_ssc._get_integrals_fcsd(mol, ia) # *.5 due to s = 1/2 * pauli-matrix h1aa.append(lib.einsum('xypq,pi,qj->xyij', h1ao, orbva.conj(), orboa) * .5) h1ab.append(lib.einsum('xypq,pi,qj->xyij', h1ao, orbva.conj(), orbob) * .5) h1ba.append(lib.einsum('xypq,pi,qj->xyij', h1ao, orbvb.conj(), orboa) * .5) h1bb.append(lib.einsum('xypq,pi,qj->xyij', h1ao, orbvb.conj(), orbob) *-.5) return (lib.asarray(h1aa), lib.asarray(h1ab), lib.asarray(h1ba), lib.asarray(h1bb))
def test_ao2mo_r_e2(self): n2c = mol.nao_2c() numpy.random.seed(1) mo = numpy.random.random((n2c,n2c)) + numpy.random.random((n2c,n2c))*1j tao = numpy.asarray(mol.tmap(), dtype=numpy.int32) buf = ao2mo._ao2mo.r_e1('int2e_spinor', mo, (0,4,0,3), (0, 2, 8), mol._atm, mol._bas, mol._env, tao, 's1') buf = buf.reshape(8,12).T ref = lib.einsum('pqkl,pi,qj->ijkl', eri0, mo[:,:4].conj(), mo[:,:3]) self.assertAlmostEqual(lib.finger(buf), 0.30769732102451997-0.58664393190628461j, 8) self.assertAlmostEqual(abs(buf[:,:4]-ref[:,:,:2,:2].reshape(12,4)).max(), 0, 9) self.assertAlmostEqual(abs(buf[:,4:]-ref[:,:,:2,2:4].reshape(12,4)).max(), 0, 9) buf = ao2mo._ao2mo.r_e2(eri0.reshape(n2c**2,n2c,n2c), mo, (0,2,0,4), tao, None, 's1') ref = lib.einsum('xpq,pk,ql->xkl', eri0.reshape(n2c**2,n2c,n2c), mo[:,:2].conj(), mo[:,:4]) self.assertAlmostEqual(lib.finger(buf), 14.183520455200011+10.179224253811057j, 8) self.assertAlmostEqual(abs(buf.reshape(n2c**2,2,4)-ref).max(), 0, 9) buf = ao2mo._ao2mo.r_e2(eri0.reshape(n2c**2,n2c,n2c), mo, (0,0,4,4), tao, None, 's1') self.assertEqual(buf.size, 0)
def dia(magobj, gauge_orig=None): mol = magobj.mol mf = magobj._scf mo_energy = mf.mo_energy mo_coeff = mf.mo_coeff mo_occ = mf.mo_occ orbo = mo_coeff[:, mo_occ > 0] dm0 = numpy.dot(orbo, orbo.T) * 2 dm0 = lib.tag_array(dm0, mo_coeff=mo_coeff, mo_occ=mo_occ) dme0 = numpy.dot(orbo * mo_energy[mo_occ > 0], orbo.T) * 2 e2 = rhf_mag._get_dia_1e(magobj, gauge_orig, dm0, dme0) if gauge_orig is not None: return -e2 # Computing the 2nd order Vxc integrals from GIAO grids = mf.grids ni = mf._numint xc_code = mf.xc xctype = ni._xc_type(xc_code) omega, alpha, hyb = ni.rsh_and_hybrid_coeff(xc_code, mol.spin) make_rho, nset, nao = ni._gen_rho_evaluator(mol, dm0, hermi=1) ngrids = len(grids.weights) mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory * .9 - mem_now) BLKSIZE = numint.BLKSIZE blksize = min( int(max_memory / 12 * 1e6 / 8 / nao / BLKSIZE) * BLKSIZE, ngrids) vmat = numpy.zeros((3, 3, nao, nao)) if xctype == 'LDA': ao_deriv = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, blksize=blksize): rho = make_rho(0, ao, mask, 'LDA') vxc = ni.eval_xc(xc_code, rho, 0, deriv=1)[1] vrho = vxc[0] r_ao = numpy.einsum('pi,px->pxi', ao, coords) aow = numpy.einsum('pxi,p,p->pxi', r_ao, weight, vrho) vmat += lib.einsum('pxi,pyj->xyij', r_ao, aow) rho = vxc = vrho = aow = None elif xctype == 'GGA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, blksize=blksize): rho = make_rho(0, ao, mask, 'GGA') vxc = ni.eval_xc(xc_code, rho, 0, deriv=1)[1] wv = numint._rks_gga_wv0(rho, vxc, weight) # Computing \nabla (r * AO) = r * \nabla AO + [\nabla,r]_- * AO r_ao = numpy.einsum('npi,px->npxi', ao, coords) r_ao[1, :, 0] += ao[0] r_ao[2, :, 1] += ao[0] r_ao[3, :, 2] += ao[0] aow = numpy.einsum('npxi,np->pxi', r_ao, wv) vmat += lib.einsum('pxi,pyj->xyij', r_ao[0], aow) rho = vxc = vrho = vsigma = wv = aow = None vmat = vmat + vmat.transpose(0, 1, 3, 2) elif xctype == 'MGGA': raise NotImplementedError('meta-GGA') vmat = _add_giao_phase(mol, vmat) e2 += numpy.einsum('qp,xypq->xy', dm0, vmat) vmat = None e2 = e2.ravel() # Handle the hybrid functional and the range-separated functional if abs(hyb) > 1e-10: vs = jk.get_jk(mol, [dm0] * 3, ['ijkl,ji->s2kl', 'ijkl,jk->s1il', 'ijkl,li->s1kj'], 'int2e_gg1', 's4', 9, hermi=1) e2 += numpy.einsum('xpq,qp->x', vs[0], dm0) e2 -= numpy.einsum('xpq,qp->x', vs[1], dm0) * .25 * hyb e2 -= numpy.einsum('xpq,qp->x', vs[2], dm0) * .25 * hyb vk = jk.get_jk(mol, dm0, 'ijkl,jk->s1il', 'int2e_g1g2', 'aa4', 9, hermi=0) e2 -= numpy.einsum('xpq,qp->x', vk, dm0) * .5 * hyb if abs(omega) > 1e-10: with mol.with_range_coulomb(omega): vs = jk.get_jk(mol, [dm0] * 2, ['ijkl,jk->s1il', 'ijkl,li->s1kj'], 'int2e_gg1', 's4', 9, hermi=1) e2 -= numpy.einsum('xpq,qp->x', vs[0], dm0) * .25 * (alpha - hyb) e2 -= numpy.einsum('xpq,qp->x', vs[1], dm0) * .25 * (alpha - hyb) vk = jk.get_jk(mol, dm0, 'ijkl,jk->s1il', 'int2e_g1g2', 'aa4', 9, hermi=0) e2 -= numpy.einsum('xpq,qp->x', vk, dm0) * .5 * (alpha - hyb) else: vj = jk.get_jk(mol, dm0, 'ijkl,ji->s2kl', 'int2e_gg1', 's4', 9, hermi=1) e2 += numpy.einsum('xpq,qp->x', vj, dm0) return -e2.reshape(3, 3)
def overlap(cibra, ciket, nmo, nocc, s=None): '''Overlap between two CISD wavefunctions. Args: s : 2D array The overlap matrix of non-orthogonal one-particle basis ''' if s is None: return dot(cibra, ciket, nmo, nocc) DEBUG = True nvir = nmo - nocc nov = nocc * nvir bra0, bra1, bra2 = cisdvec_to_amplitudes(cibra, nmo, nocc) ket0, ket1, ket2 = cisdvec_to_amplitudes(ciket, nmo, nocc) # Sort the ket orbitals to make the orbitals in bra one-one mapt to orbitals # in ket. if ((not DEBUG) and abs(numpy.linalg.det(s[:nocc, :nocc]) - 1) < 1e-2 and abs(numpy.linalg.det(s[nocc:, nocc:]) - 1) < 1e-2): ket_orb_idx = numpy.where(abs(s) > 0.9)[1] s = s[:, ket_orb_idx] oidx = ket_orb_idx[:nocc] vidx = ket_orb_idx[nocc:] - nocc ket1 = ket1[oidx[:, None], vidx] ket2 = ket2[oidx[:, None, None, None], oidx[:, None, None], vidx[:, None], vidx] ooidx = numpy.tril_indices(nocc, -1) vvidx = numpy.tril_indices(nvir, -1) bra2aa = bra2 - bra2.transpose(1, 0, 2, 3) bra2aa = lib.take_2d(bra2aa.reshape(nocc**2, nvir**2), ooidx[0] * nocc + ooidx[1], vvidx[0] * nvir + vvidx[1]) ket2aa = ket2 - ket2.transpose(1, 0, 2, 3) ket2aa = lib.take_2d(ket2aa.reshape(nocc**2, nvir**2), ooidx[0] * nocc + ooidx[1], vvidx[0] * nvir + vvidx[1]) occlist0 = numpy.arange(nocc).reshape(1, nocc) occlists = numpy.repeat(occlist0, 1 + nov + bra2aa.size, axis=0) occlist0 = occlists[:1] occlist1 = occlists[1:1 + nov] occlist2 = occlists[1 + nov:] ia = 0 for i in range(nocc): for a in range(nocc, nmo): occlist1[ia, i] = a ia += 1 ia = 0 for i in range(nocc): for j in range(i): for a in range(nocc, nmo): for b in range(nocc, a): occlist2[ia, i] = a occlist2[ia, j] = b ia += 1 na = len(occlists) if DEBUG: trans = numpy.empty((na, na)) for i, idx in enumerate(occlists): s_sub = s[idx].T.copy() minors = s_sub[occlists] trans[i, :] = numpy.linalg.det(minors) # Mimic the transformation einsum('ab,ap->pb', FCI, trans). # The wavefunction FCI has the [excitation_alpha,excitation_beta] # representation. The zero blocks like FCI[S_alpha,D_beta], # FCI[D_alpha,D_beta], are explicitly excluded. bra_mat = numpy.zeros((na, na)) bra_mat[0, 0] = bra0 bra_mat[0, 1:1 + nov] = bra_mat[1:1 + nov, 0] = bra1.ravel() bra_mat[0, 1 + nov:] = bra_mat[1 + nov:, 0] = bra2aa.ravel() bra_mat[1:1 + nov, 1:1 + nov] = bra2.transpose(0, 2, 1, 3).reshape(nov, nov) ket_mat = numpy.zeros((na, na)) ket_mat[0, 0] = ket0 ket_mat[0, 1:1 + nov] = ket_mat[1:1 + nov, 0] = ket1.ravel() ket_mat[0, 1 + nov:] = ket_mat[1 + nov:, 0] = ket2aa.ravel() ket_mat[1:1 + nov, 1:1 + nov] = ket2.transpose(0, 2, 1, 3).reshape(nov, nov) ovlp = lib.einsum('ab,ap,bq,pq->', bra_mat, trans, trans, ket_mat) else: nov1 = 1 + nov noovv = bra2aa.size bra_SS = numpy.zeros((nov1, nov1)) bra_SS[0, 0] = bra0 bra_SS[0, 1:] = bra_SS[1:, 0] = bra1.ravel() bra_SS[1:, 1:] = bra2.transpose(0, 2, 1, 3).reshape(nov, nov) ket_SS = numpy.zeros((nov1, nov1)) ket_SS[0, 0] = ket0 ket_SS[0, 1:] = ket_SS[1:, 0] = ket1.ravel() ket_SS[1:, 1:] = ket2.transpose(0, 2, 1, 3).reshape(nov, nov) trans_SS = numpy.empty((nov1, nov1)) trans_SD = numpy.empty((nov1, noovv)) trans_DS = numpy.empty((noovv, nov1)) occlist01 = occlists[:nov1] for i, idx in enumerate(occlist01): s_sub = s[idx].T.copy() minors = s_sub[occlist01] trans_SS[i, :] = numpy.linalg.det(minors) minors = s_sub[occlist2] trans_SD[i, :] = numpy.linalg.det(minors) s_sub = s[:, idx].copy() minors = s_sub[occlist2] trans_DS[:, i] = numpy.linalg.det(minors) ovlp = lib.einsum('ab,ap,bq,pq->', bra_SS, trans_SS, trans_SS, ket_SS) ovlp += lib.einsum('ab,a ,bq, q->', bra_SS, trans_SS[:, 0], trans_SD, ket2aa.ravel()) ovlp += lib.einsum('ab,ap,b ,p ->', bra_SS, trans_SD, trans_SS[:, 0], ket2aa.ravel()) ovlp += lib.einsum(' b, p,bq,pq->', bra2aa.ravel(), trans_SS[0, :], trans_DS, ket_SS) ovlp += lib.einsum(' b, p,b ,p ->', bra2aa.ravel(), trans_SD[0, :], trans_DS[:, 0], ket2aa.ravel()) ovlp += lib.einsum('a ,ap, q,pq->', bra2aa.ravel(), trans_DS, trans_SS[0, :], ket_SS) ovlp += lib.einsum('a ,a , q, q->', bra2aa.ravel(), trans_DS[:, 0], trans_SD[0, :], ket2aa.ravel()) # FIXME: whether to approximate the overlap between double excitation coefficients if numpy.linalg.norm(bra2aa) * numpy.linalg.norm(ket2aa) < 1e-4: # Skip the overlap if coefficients of double excitation are small enough pass if (abs(numpy.linalg.det(s[:nocc, :nocc]) - 1) < 1e-2 and abs(numpy.linalg.det(s[nocc:, nocc:]) - 1) < 1e-2): # If the overlap matrix close to identity enough, use the <D|D'> overlap # for orthogonal single-particle basis to approximate the overlap # for non-orthogonal basis. ovlp += numpy.dot(bra2aa.ravel(), ket2aa.ravel()) * trans_SS[0, 0] * 2 else: from multiprocessing import sharedctypes, Process buf_ctypes = sharedctypes.RawArray('d', noovv) trans_ket = numpy.ndarray(noovv, buffer=buf_ctypes) def trans_dot_ket(i0, i1): for i in range(i0, i1): s_sub = s[occlist2[i]].T.copy() minors = s_sub[occlist2] trans_ket[i] = numpy.linalg.det(minors).dot(ket2aa.ravel()) nproc = lib.num_threads() if nproc > 1: seg = (noovv + nproc - 1) // nproc ps = [] for i0, i1 in lib.prange(0, noovv, seg): p = Process(target=trans_dot_ket, args=(i0, i1)) ps.append(p) p.start() [p.join() for p in ps] else: trans_dot_ket(0, noovv) ovlp += numpy.dot(bra2aa.ravel(), trans_ket) * trans_SS[0, 0] * 2 return ovlp
def get_fno(mp, mo_energy=None, mo_coeff=None, eris=None, thresh_vir=THRESH_VIR, verbose=logger.NOTE): lib.logger.info(mp,"\n* Fno procedure") lib.logger.info(mp,"* Threshold for virtual occupation %g", thresh_vir) if mo_energy is None: mo_energy = mp.mo_energy[mp.get_frozen_mask()] else: mo_energy = mo_energy[mp.get_frozen_mask()] if eris is None: eris = mp.ao2mo(mo_coeff) nocc = mp.nocc nvir = mp.nmo - nocc eo = mo_energy[:nocc] ev = mo_energy[nocc:] dab = numpy.zeros((len(ev),len(ev)), dtype=numpy.complex128) vv_denom = -ev.reshape(-1,1)-ev for i in range(nocc): eps_i = eo[i] i_Qv = eris.ov[:, i, :].copy() for j in range(nocc): eps_j = eo[j] j_Qv = eris.ov[:, j, :].copy() viajb = lib.einsum('Qa,Qb->ab', i_Qv, j_Qv) vibja = lib.einsum('Qb,Qa->ab', i_Qv, j_Qv) v = viajb - vibja div = 1.0/(eps_i + eps_j + vv_denom) t2ij = v.conj()*div dab += lib.einsum('ea,eb->ab', t2ij,t2ij.conj())*0.5 dm1 = dab + dab.conj().T dm1 *= 0.5 natoccvir, natorbvir = numpy.linalg.eigh(-dm1) for i, k in enumerate(numpy.argmax(abs(natorbvir), axis=0)): if natorbvir[k,i] < 0: natorbvir[:,i] *= -1 natoccvir = -natoccvir lib.logger.debug(mp,"* Occupancies") lib.logger.debug(mp,"* %s" % natoccvir) lib.logger.debug(mp,"* The sum is %8.6f" % numpy.sum(natoccvir)) active = (thresh_vir <= natoccvir) lib.logger.info(mp,"* Natural Orbital selection") for i in range(nvir): lib.logger.debug(mp,"orb: %d %s %8.6f" % (i,active[i],natoccvir[i])) actIndices = numpy.where(active)[0] lib.logger.info(mp,"* Original active orbitals %d" % nvir) lib.logger.info(mp,"* Virtual core orbitals: %d" % (nvir-len(actIndices))) lib.logger.info(mp,"* New active orbitals %d" % len(actIndices)) lib.logger.debug(mp,"* Active orbital indices %s" % actIndices) natorbvir = natorbvir[:,actIndices] ev = mo_energy[nocc:] fvv = numpy.diag(ev) fvv = reduce(numpy.dot, (natorbvir.conj().T, fvv, natorbvir)) ev, fnov = numpy.linalg.eigh(fvv) cv = mp.mo_coeff[:,mp.get_frozen_mask()] cv = cv[:,nocc:] cv = reduce(numpy.dot, (cv, natorbvir, fnov)) co = mp.mo_coeff[:,mp.mo_occ>0] eo = mp.mo_energy[mp.mo_occ>0] coeff = numpy.hstack([co,cv]) energy = numpy.hstack([eo,ev]) occ = numpy.zeros(coeff.shape[1]) for i in range(mp.mol.nelectron): occ[i] = 1.0 return coeff, energy, occ
def grad_elec(cc_grad, t1=None, t2=None, l1=None, l2=None, eris=None, atmlst=None, d1=None, d2=None, verbose=logger.INFO): mycc = cc_grad.base if eris is not None: if (abs(eris.focka - numpy.diag(eris.focka.diagonal())).max() > 1e-3 or abs(eris.fockb - numpy.diag(eris.fockb.diagonal())).max() > 1e-3): raise RuntimeError('UCCSD gradients does not support NHF (non-canonical HF)') if t1 is None: t1 = mycc.t1 if t2 is None: t2 = mycc.t2 if l1 is None: l1 = mycc.l1 if l2 is None: l2 = mycc.l2 log = logger.new_logger(mycc, verbose) time0 = logger.process_clock(), logger.perf_counter() log.debug('Build uccsd rdm1 intermediates') if d1 is None: d1 = uccsd_rdm._gamma1_intermediates(mycc, t1, t2, l1, l2) time1 = log.timer_debug1('rdm1 intermediates', *time0) log.debug('Build uccsd rdm2 intermediates') fdm2 = lib.H5TmpFile() if d2 is None: d2 = uccsd_rdm._gamma2_outcore(mycc, t1, t2, l1, l2, fdm2, True) time1 = log.timer_debug1('rdm2 intermediates', *time1) mol = cc_grad.mol mo_a, mo_b = mycc.mo_coeff mo_ea, mo_eb = mycc._scf.mo_energy nao, nmoa = mo_a.shape nmob = mo_b.shape[1] nocca = numpy.count_nonzero(mycc.mo_occ[0] > 0) noccb = numpy.count_nonzero(mycc.mo_occ[1] > 0) with_frozen = not ((mycc.frozen is None) or (isinstance(mycc.frozen, (int, numpy.integer)) and mycc.frozen == 0) or (len(mycc.frozen) == 0)) moidx = mycc.get_frozen_mask() OA_a, VA_a, OF_a, VF_a = ccsd_grad._index_frozen_active(moidx[0], mycc.mo_occ[0]) OA_b, VA_b, OF_b, VF_b = ccsd_grad._index_frozen_active(moidx[1], mycc.mo_occ[1]) log.debug('symmetrized rdm2 and MO->AO transformation') # Roughly, dm2*2 is computed in _rdm2_mo2ao mo_active = (mo_a[:,numpy.hstack((OA_a,VA_a))], mo_b[:,numpy.hstack((OA_b,VA_b))]) _rdm2_mo2ao(mycc, d2, mo_active, fdm2) # transform the active orbitals time1 = log.timer_debug1('MO->AO transformation', *time1) hf_dm1a, hf_dm1b = mycc._scf.make_rdm1(mycc.mo_coeff, mycc.mo_occ) hf_dm1 = hf_dm1a + hf_dm1b if atmlst is None: atmlst = range(mol.natm) offsetdic = mol.offset_nr_by_atom() diagidx = numpy.arange(nao) diagidx = diagidx*(diagidx+1)//2 + diagidx de = numpy.zeros((len(atmlst),3)) Imata = numpy.zeros((nao,nao)) Imatb = numpy.zeros((nao,nao)) vhf1 = fdm2.create_dataset('vhf1', (len(atmlst),2,3,nao,nao), 'f8') # 2e AO integrals dot 2pdm max_memory = max(0, mycc.max_memory - lib.current_memory()[0]) blksize = max(1, int(max_memory*.9e6/8/(nao**3*2.5))) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] ip1 = p0 vhf = numpy.zeros((2,3,nao,nao)) for b0, b1, nf in ccsd_grad._shell_prange(mol, shl0, shl1, blksize): ip0, ip1 = ip1, ip1 + nf dm2bufa = ccsd_grad._load_block_tril(fdm2['dm2aa+ab'], ip0, ip1, nao) dm2bufb = ccsd_grad._load_block_tril(fdm2['dm2bb+ab'], ip0, ip1, nao) dm2bufa[:,:,diagidx] *= .5 dm2bufb[:,:,diagidx] *= .5 shls_slice = (b0,b1,0,mol.nbas,0,mol.nbas,0,mol.nbas) eri0 = mol.intor('int2e', aosym='s2kl', shls_slice=shls_slice) Imata += lib.einsum('ipx,iqx->pq', eri0.reshape(nf,nao,-1), dm2bufa) Imatb += lib.einsum('ipx,iqx->pq', eri0.reshape(nf,nao,-1), dm2bufb) eri0 = None eri1 = mol.intor('int2e_ip1', comp=3, aosym='s2kl', shls_slice=shls_slice).reshape(3,nf,nao,-1) de[k] -= numpy.einsum('xijk,ijk->x', eri1, dm2bufa) * 2 de[k] -= numpy.einsum('xijk,ijk->x', eri1, dm2bufb) * 2 dm2bufa = dm2bufb = None # HF part for i in range(3): eri1tmp = lib.unpack_tril(eri1[i].reshape(nf*nao,-1)) eri1tmp = eri1tmp.reshape(nf,nao,nao,nao) vhf[:,i] += numpy.einsum('ijkl,ij->kl', eri1tmp, hf_dm1[ip0:ip1]) vhf[0,i] -= numpy.einsum('ijkl,il->kj', eri1tmp, hf_dm1a[ip0:ip1]) vhf[1,i] -= numpy.einsum('ijkl,il->kj', eri1tmp, hf_dm1b[ip0:ip1]) vhf[:,i,ip0:ip1] += numpy.einsum('ijkl,kl->ij', eri1tmp, hf_dm1) vhf[0,i,ip0:ip1] -= numpy.einsum('ijkl,jk->il', eri1tmp, hf_dm1a) vhf[1,i,ip0:ip1] -= numpy.einsum('ijkl,jk->il', eri1tmp, hf_dm1b) eri1 = eri1tmp = None vhf1[k] = vhf log.debug('2e-part grad of atom %d %s = %s', ia, mol.atom_symbol(ia), de[k]) time1 = log.timer_debug1('2e-part grad of atom %d'%ia, *time1) s0 = mycc._scf.get_ovlp() Imata = reduce(numpy.dot, (mo_a.T, Imata, s0, mo_a)) * -1 Imatb = reduce(numpy.dot, (mo_b.T, Imatb, s0, mo_b)) * -1 dm1a = numpy.zeros((nmoa,nmoa)) dm1b = numpy.zeros((nmob,nmob)) doo, dOO = d1[0] dov, dOV = d1[1] dvo, dVO = d1[2] dvv, dVV = d1[3] if with_frozen: dco = Imata[OF_a[:,None],OA_a] / (mo_ea[OF_a,None] - mo_ea[OA_a]) dfv = Imata[VF_a[:,None],VA_a] / (mo_ea[VF_a,None] - mo_ea[VA_a]) dm1a[OA_a[:,None],OA_a] = (doo + doo.T) * .5 dm1a[OF_a[:,None],OA_a] = dco dm1a[OA_a[:,None],OF_a] = dco.T dm1a[VA_a[:,None],VA_a] = (dvv + dvv.T) * .5 dm1a[VF_a[:,None],VA_a] = dfv dm1a[VA_a[:,None],VF_a] = dfv.T dco = Imatb[OF_b[:,None],OA_b] / (mo_eb[OF_b,None] - mo_eb[OA_b]) dfv = Imatb[VF_b[:,None],VA_b] / (mo_eb[VF_b,None] - mo_eb[VA_b]) dm1b[OA_b[:,None],OA_b] = (dOO + dOO.T) * .5 dm1b[OF_b[:,None],OA_b] = dco dm1b[OA_b[:,None],OF_b] = dco.T dm1b[VA_b[:,None],VA_b] = (dVV + dVV.T) * .5 dm1b[VF_b[:,None],VA_b] = dfv dm1b[VA_b[:,None],VF_b] = dfv.T else: dm1a[:nocca,:nocca] = (doo + doo.T) * .5 dm1a[nocca:,nocca:] = (dvv + dvv.T) * .5 dm1b[:noccb,:noccb] = (dOO + dOO.T) * .5 dm1b[noccb:,noccb:] = (dVV + dVV.T) * .5 dm1 = (reduce(numpy.dot, (mo_a, dm1a, mo_a.T)), reduce(numpy.dot, (mo_b, dm1b, mo_b.T))) vhf = mycc._scf.get_veff(mycc.mol, dm1) Xvo = reduce(numpy.dot, (mo_a[:,nocca:].T, vhf[0], mo_a[:,:nocca])) XVO = reduce(numpy.dot, (mo_b[:,noccb:].T, vhf[1], mo_b[:,:noccb])) Xvo+= Imata[:nocca,nocca:].T - Imata[nocca:,:nocca] XVO+= Imatb[:noccb,noccb:].T - Imatb[noccb:,:noccb] dm1_resp = _response_dm1(mycc, (Xvo,XVO), eris) dm1a += dm1_resp[0] dm1b += dm1_resp[1] time1 = log.timer_debug1('response_rdm1 intermediates', *time1) Imata[nocca:,:nocca] = Imata[:nocca,nocca:].T Imatb[noccb:,:noccb] = Imatb[:noccb,noccb:].T im1 = reduce(numpy.dot, (mo_a, Imata, mo_a.T)) im1+= reduce(numpy.dot, (mo_b, Imatb, mo_b.T)) time1 = log.timer_debug1('response_rdm1', *time1) log.debug('h1 and JK1') # Initialize hcore_deriv with the underlying SCF object because some # extensions (e.g. QM/MM, solvent) modifies the SCF object only. mf_grad = cc_grad.base._scf.nuc_grad_method() hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) zeta = (mo_ea[:,None] + mo_ea) * .5 zeta[nocca:,:nocca] = mo_ea[:nocca] zeta[:nocca,nocca:] = mo_ea[:nocca].reshape(-1,1) zeta_a = reduce(numpy.dot, (mo_a, zeta*dm1a, mo_a.T)) zeta = (mo_eb[:,None] + mo_eb) * .5 zeta[noccb:,:noccb] = mo_eb[:noccb] zeta[:noccb,noccb:] = mo_eb[:noccb].reshape(-1,1) zeta_b = reduce(numpy.dot, (mo_b, zeta*dm1b, mo_b.T)) dm1 = (reduce(numpy.dot, (mo_a, dm1a, mo_a.T)), reduce(numpy.dot, (mo_b, dm1b, mo_b.T))) vhf_s1occ = mycc._scf.get_veff(mol, (dm1[0]+dm1[0].T, dm1[1]+dm1[1].T)) p1a = numpy.dot(mo_a[:,:nocca], mo_a[:,:nocca].T) p1b = numpy.dot(mo_b[:,:noccb], mo_b[:,:noccb].T) vhf_s1occ = (reduce(numpy.dot, (p1a, vhf_s1occ[0], p1a)) + reduce(numpy.dot, (p1b, vhf_s1occ[1], p1b))) * .5 time1 = log.timer_debug1('h1 and JK1', *time1) # Hartree-Fock part contribution dm1pa = hf_dm1a + dm1[0]*2 dm1pb = hf_dm1b + dm1[1]*2 dm1 = dm1[0] + dm1[1] + hf_dm1 zeta_a += rhf_grad.make_rdm1e(mo_ea, mo_a, mycc.mo_occ[0]) zeta_b += rhf_grad.make_rdm1e(mo_eb, mo_b, mycc.mo_occ[1]) zeta = zeta_a + zeta_b for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] # s[1] dot I, note matrix im1 is not hermitian de[k] += numpy.einsum('xij,ij->x', s1[:,p0:p1], im1[p0:p1]) de[k] += numpy.einsum('xji,ij->x', s1[:,p0:p1], im1[:,p0:p1]) # h[1] \dot DM, contribute to f1 h1ao = hcore_deriv(ia) de[k] += numpy.einsum('xij,ji->x', h1ao, dm1) # -s[1]*e \dot DM, contribute to f1 de[k] -= numpy.einsum('xij,ij->x', s1[:,p0:p1], zeta[p0:p1] ) de[k] -= numpy.einsum('xji,ij->x', s1[:,p0:p1], zeta[:,p0:p1]) # -vhf[s_ij[1]], contribute to f1, *2 for s1+s1.T de[k] -= numpy.einsum('xij,ij->x', s1[:,p0:p1], vhf_s1occ[p0:p1]) * 2 de[k] -= numpy.einsum('xij,ij->x', vhf1[k,0], dm1pa) de[k] -= numpy.einsum('xij,ij->x', vhf1[k,1], dm1pb) log.timer('%s gradients' % mycc.__class__.__name__, *time0) return de
def grad_elec(mc_grad, mo_coeff=None, ci=None, atmlst=None, verbose=None): mc = mc_grad.base if mo_coeff is None: mo_coeff = mc._scf.mo_coeff if ci is None: ci = mc.ci time0 = logger.process_clock(), logger.perf_counter() log = logger.new_logger(mc_grad, verbose) mol = mc_grad.mol ncore = mc.ncore ncas = mc.ncas nocc = ncore + ncas nelecas = mc.nelecas nao, nmo = mo_coeff.shape nao_pair = nao * (nao + 1) // 2 mo_energy = mc._scf.mo_energy mo_occ = mo_coeff[:, :nocc] mo_core = mo_coeff[:, :ncore] mo_cas = mo_coeff[:, ncore:nocc] neleca, nelecb = mol.nelec assert (neleca == nelecb) orbo = mo_coeff[:, :neleca] orbv = mo_coeff[:, neleca:] casdm1, casdm2 = mc.fcisolver.make_rdm12(ci, ncas, nelecas) dm_core = numpy.dot(mo_core, mo_core.T) * 2 dm_cas = reduce(numpy.dot, (mo_cas, casdm1, mo_cas.T)) aapa = ao2mo.kernel(mol, (mo_cas, mo_cas, mo_coeff, mo_cas), compact=False) aapa = aapa.reshape(ncas, ncas, nmo, ncas) vj, vk = mc._scf.get_jk(mol, (dm_core, dm_cas)) h1 = mc.get_hcore() vhf_c = vj[0] - vk[0] * .5 vhf_a = vj[1] - vk[1] * .5 # Imat = h1_{pi} gamma1_{iq} + h2_{pijk} gamma_{iqkj} Imat = numpy.zeros((nmo, nmo)) Imat[:, :nocc] = reduce(numpy.dot, (mo_coeff.T, h1 + vhf_c + vhf_a, mo_occ)) * 2 Imat[:, ncore:nocc] = reduce(numpy.dot, (mo_coeff.T, h1 + vhf_c, mo_cas, casdm1)) Imat[:, ncore:nocc] += lib.einsum('uviw,vuwt->it', aapa, casdm2) aapa = vj = vk = vhf_c = vhf_a = h1 = None ee = mo_energy[:, None] - mo_energy zvec = numpy.zeros_like(Imat) zvec[:ncore, ncore:neleca] = Imat[:ncore, ncore:neleca] / -ee[:ncore, ncore:neleca] zvec[ncore:neleca, :ncore] = Imat[ ncore:neleca, :ncore] / -ee[ncore:neleca, :ncore] zvec[nocc:, neleca:nocc] = Imat[nocc:, neleca:nocc] / -ee[nocc:, neleca:nocc] zvec[neleca:nocc, nocc:] = Imat[neleca:nocc, nocc:] / -ee[neleca:nocc, nocc:] zvec_ao = reduce(numpy.dot, (mo_coeff, zvec + zvec.T, mo_coeff.T)) vhf = mc._scf.get_veff(mol, zvec_ao) * 2 xvo = reduce(numpy.dot, (orbv.T, vhf, orbo)) xvo += Imat[neleca:, :neleca] - Imat[:neleca, neleca:].T def fvind(x): x = x.reshape(xvo.shape) dm = reduce(numpy.dot, (orbv, x, orbo.T)) v = mc._scf.get_veff(mol, dm + dm.T) v = reduce(numpy.dot, (orbv.T, v, orbo)) return v * 2 dm1resp = cphf.solve(fvind, mo_energy, mc._scf.mo_occ, xvo, max_cycle=30)[0] zvec[neleca:, :neleca] = dm1resp zeta = numpy.einsum('ij,j->ij', zvec, mo_energy) zeta = reduce(numpy.dot, (mo_coeff, zeta, mo_coeff.T)) zvec_ao = reduce(numpy.dot, (mo_coeff, zvec + zvec.T, mo_coeff.T)) p1 = numpy.dot(mo_coeff[:, :neleca], mo_coeff[:, :neleca].T) vhf_s1occ = reduce(numpy.dot, (p1, mc._scf.get_veff(mol, zvec_ao), p1)) Imat[:ncore, ncore:neleca] = 0 Imat[ncore:neleca, :ncore] = 0 Imat[nocc:, neleca:nocc] = 0 Imat[neleca:nocc, nocc:] = 0 Imat[neleca:, :neleca] = Imat[:neleca, neleca:].T im1 = reduce(numpy.dot, (mo_coeff, Imat, mo_coeff.T)) casci_dm1 = dm_core + dm_cas hf_dm1 = mc._scf.make_rdm1(mo_coeff, mc._scf.mo_occ) hcore_deriv = mc_grad.hcore_generator(mol) s1 = mc_grad.get_ovlp(mol) diag_idx = numpy.arange(nao) diag_idx = diag_idx * (diag_idx + 1) // 2 + diag_idx casdm2_cc = casdm2 + casdm2.transpose(0, 1, 3, 2) dm2buf = ao2mo._ao2mo.nr_e2(casdm2_cc.reshape(ncas**2, ncas**2), mo_cas.T, (0, nao, 0, nao)).reshape(ncas**2, nao, nao) dm2buf = lib.pack_tril(dm2buf) dm2buf[:, diag_idx] *= .5 dm2buf = dm2buf.reshape(ncas, ncas, nao_pair) casdm2 = casdm2_cc = None if atmlst is None: atmlst = range(mol.natm) aoslices = mol.aoslice_by_atom() de = numpy.zeros((len(atmlst), 3)) max_memory = mc_grad.max_memory - lib.current_memory()[0] blksize = int(max_memory * .9e6 / 8 / ((aoslices[:, 3] - aoslices[:, 2]).max() * nao_pair)) blksize = min(nao, max(2, blksize)) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) de[k] += numpy.einsum('xij,ij->x', h1ao, casci_dm1) de[k] += numpy.einsum('xij,ij->x', h1ao, zvec_ao) q1 = 0 for b0, b1, nf in _shell_prange(mol, 0, mol.nbas, blksize): q0, q1 = q1, q1 + nf dm2_ao = lib.einsum('ijw,pi,qj->pqw', dm2buf, mo_cas[p0:p1], mo_cas[q0:q1]) shls_slice = (shl0, shl1, b0, b1, 0, mol.nbas, 0, mol.nbas) eri1 = mol.intor('int2e_ip1', comp=3, aosym='s2kl', shls_slice=shls_slice).reshape( 3, p1 - p0, nf, nao_pair) de[k] -= numpy.einsum('xijw,ijw->x', eri1, dm2_ao) * 2 for i in range(3): eri1tmp = lib.unpack_tril(eri1[i].reshape((p1 - p0) * nf, -1)) eri1tmp = eri1tmp.reshape(p1 - p0, nf, nao, nao) de[k, i] -= numpy.einsum('ijkl,ij,kl', eri1tmp, hf_dm1[p0:p1, q0:q1], zvec_ao) * 2 de[k, i] -= numpy.einsum('ijkl,kl,ij', eri1tmp, hf_dm1, zvec_ao[p0:p1, q0:q1]) * 2 de[k, i] += numpy.einsum('ijkl,il,kj', eri1tmp, hf_dm1[p0:p1], zvec_ao[q0:q1]) de[k, i] += numpy.einsum('ijkl,jk,il', eri1tmp, hf_dm1[q0:q1], zvec_ao[p0:p1]) #:vhf1c, vhf1a = mc_grad.get_veff(mol, (dm_core, dm_cas)) #:de[k] += numpy.einsum('xij,ij->x', vhf1c[:,p0:p1], casci_dm1[p0:p1]) * 2 #:de[k] += numpy.einsum('xij,ij->x', vhf1a[:,p0:p1], dm_core[p0:p1]) * 2 de[k, i] -= numpy.einsum('ijkl,lk,ij', eri1tmp, dm_core[q0:q1], casci_dm1[p0:p1]) * 2 de[k, i] += numpy.einsum('ijkl,jk,il', eri1tmp, dm_core[q0:q1], casci_dm1[p0:p1]) de[k, i] -= numpy.einsum('ijkl,lk,ij', eri1tmp, dm_cas[q0:q1], dm_core[p0:p1]) * 2 de[k, i] += numpy.einsum('ijkl,jk,il', eri1tmp, dm_cas[q0:q1], dm_core[p0:p1]) eri1 = eri1tmp = None de[k] -= numpy.einsum('xij,ij->x', s1[:, p0:p1], im1[p0:p1]) de[k] -= numpy.einsum('xij,ji->x', s1[:, p0:p1], im1[:, p0:p1]) de[k] -= numpy.einsum('xij,ij->x', s1[:, p0:p1], zeta[p0:p1]) * 2 de[k] -= numpy.einsum('xij,ji->x', s1[:, p0:p1], zeta[:, p0:p1]) * 2 de[k] -= numpy.einsum('xij,ij->x', s1[:, p0:p1], vhf_s1occ[p0:p1]) * 2 de[k] -= numpy.einsum('xij,ji->x', s1[:, p0:p1], vhf_s1occ[:, p0:p1]) * 2 log.timer('CASCI nuclear gradients', *time0) return de
tdB = mfB.TDA().run() # CIS coeffcients state_id = 2 # The third excited state t1_A = tdA.xy[state_id][0] * np.sqrt(2) t1_B = tdB.xy[state_id][0] * np.sqrt(2) # The intermolecular 2e integrals molAB = molA + molB naoA = molA.nao eri = molAB.intor('int2e') eri_AABB = eri[:naoA, :naoA, naoA:, naoA:] eri_ABBA = eri[:naoA, naoA:, naoA:, :naoA] # Transform integrals to MO basis eri_iabj = lib.einsum('pqrs,pi,qa,rb,sj->iabj', eri_AABB, o_A, v_A, v_B, o_B) eri_ijba = lib.einsum('pqrs,pi,qj,rb,sa->ijba', eri_ABBA, o_A, o_B, v_B, v_A) # J-type coupling and K-type coupling cJ = np.einsum('iabj,ia,jb->', eri_iabj, t1_A, t1_B) cK = np.einsum('ijba,ia,jb->', eri_ijba, t1_A, t1_B) print(cJ, cK) # # Below is an efficient implementation # def jk_ints(molA, molB, dm_ia, dm_jb): from pyscf.scf import jk, _vhf naoA = molA.nao naoB = molB.nao
def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None): r'''A and B matrices for TDDFT response function. A[i,a,j,b] = \delta_{ab}\delta_{ij}(E_a - E_i) + (ia||bj) B[i,a,j,b] = (ia||jb) ''' if mo_energy is None: mo_energy = mf.mo_energy if mo_coeff is None: mo_coeff = mf.mo_coeff if mo_occ is None: mo_occ = mf.mo_occ assert(mo_coeff.dtype == numpy.double) mol = mf.mol nao, nmo = mo_coeff.shape occidx = numpy.where(mo_occ==2)[0] viridx = numpy.where(mo_occ==0)[0] orbv = mo_coeff[:,viridx] orbo = mo_coeff[:,occidx] nvir = orbv.shape[1] nocc = orbo.shape[1] mo = numpy.hstack((orbo,orbv)) nmo = nocc + nvir e_ia = lib.direct_sum('a-i->ia', mo_energy[viridx], mo_energy[occidx]) a = numpy.diag(e_ia.ravel()).reshape(nocc,nvir,nocc,nvir) b = numpy.zeros_like(a) def add_hf_(a, b, hyb=1): eri_mo = ao2mo.general(mol, [orbo,mo,mo,mo], compact=False) eri_mo = eri_mo.reshape(nocc,nmo,nmo,nmo) a += numpy.einsum('iabj->iajb', eri_mo[:nocc,nocc:,nocc:,:nocc]) * 2 a -= numpy.einsum('ijba->iajb', eri_mo[:nocc,:nocc,nocc:,nocc:]) * hyb b += numpy.einsum('iajb->iajb', eri_mo[:nocc,nocc:,:nocc,nocc:]) * 2 b -= numpy.einsum('jaib->iajb', eri_mo[:nocc,nocc:,:nocc,nocc:]) * hyb if getattr(mf, 'xc', None) and getattr(mf, '_numint', None): from pyscf.dft import rks from pyscf.dft import numint ni = mf._numint ni.libxc.test_deriv_order(mf.xc, 2, raise_error=True) if getattr(mf, 'nlc', '') != '': logger.warn(mf, 'NLC functional found in DFT object. Its second ' 'deriviative is not available. Its contribution is ' 'not included in the response function.') omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin) add_hf_(a, b, hyb) xctype = ni._xc_type(mf.xc) dm0 = mf.make_rdm1(mo_coeff, mo_occ) make_rho = ni._gen_rho_evaluator(mol, dm0, hermi=1)[0] mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory*.8-mem_now) if xctype == 'LDA': ao_deriv = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho = make_rho(0, ao, mask, 'LDA') fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[2] frr = fxc[0] rho_o = lib.einsum('rp,pi->ri', ao, orbo) rho_v = lib.einsum('rp,pi->ri', ao, orbv) rho_ov = numpy.einsum('ri,ra->ria', rho_o, rho_v) w_ov = numpy.einsum('ria,r->ria', rho_ov, weight*frr) iajb = lib.einsum('ria,rjb->iajb', rho_ov, w_ov) * 2 a += iajb b += iajb elif xctype == 'GGA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho = make_rho(0, ao, mask, 'GGA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vgamma = vxc[1] frho, frhogamma, fgg = fxc[:3] rho_o = lib.einsum('xrp,pi->xri', ao, orbo) rho_v = lib.einsum('xrp,pi->xri', ao, orbv) rho_ov = numpy.einsum('xri,ra->xria', rho_o, rho_v[0]) rho_ov[1:4] += numpy.einsum('ri,xra->xria', rho_o[0], rho_v[1:4]) # sigma1 ~ \nabla(\rho_\alpha+\rho_\beta) dot \nabla(|b><j|) z_{bj} sigma1 = numpy.einsum('xr,xria->ria', rho[1:4], rho_ov[1:4]) w_ov = numpy.empty_like(rho_ov) w_ov[0] = numpy.einsum('r,ria->ria', frho, rho_ov[0]) w_ov[0] += numpy.einsum('r,ria->ria', 2*frhogamma, sigma1) f_ov = numpy.einsum('r,ria->ria', 4*fgg, sigma1) f_ov+= numpy.einsum('r,ria->ria', 2*frhogamma, rho_ov[0]) w_ov[1:] = numpy.einsum('ria,xr->xria', f_ov, rho[1:4]) w_ov[1:]+= numpy.einsum('r,xria->xria', 2*vgamma, rho_ov[1:4]) w_ov *= weight[:,None,None] iajb = lib.einsum('xria,xrjb->iajb', rho_ov, w_ov) * 2 a += iajb b += iajb elif xctype == 'NLC': raise NotImplementedError('NLC') elif xctype == 'MGGA': raise NotImplementedError('meta-GGA') else: add_hf_(a, b) return a, b
def get_fno(mp, mo_energy=None, mo_coeff=None, eris=None, thresh_vir=THRESH_VIR, verbose=logger.NOTE): lib.logger.info(mp, "\n* Fno procedure") lib.logger.info(mp, "* Threshold for virtual occupation %g", thresh_vir) if mo_energy is None: mo_energy = mp.mo_energy[mp.get_frozen_mask()] else: mo_energy = mo_energy[mp.get_frozen_mask()] if eris is None: eris = mp.ao2mo(mo_coeff) nocc = mp.nocc nvir = mp.nmo - nocc eia = mo_energy[:nocc, None] - mo_energy[None, nocc:] t2 = numpy.empty((nocc, nocc, nvir, nvir), dtype=numpy.complex128) for i in range(nocc): gi = numpy.asarray(eris.oovv[i]).reshape(nocc, nvir, nvir) t2i = gi.conj() / lib.direct_sum('jb+a->jba', eia, eia[i]) t2[i] = t2i dvv = lib.einsum('mnea,mneb->ab', t2, t2.conj()) * 0.5 dm1 = dvv + dvv.conj().T dm1 *= 0.5 natoccvir, natorbvir = numpy.linalg.eigh(-dm1) for i, k in enumerate(numpy.argmax(abs(natorbvir), axis=0)): if natorbvir[k, i] < 0: natorbvir[:, i] *= -1 natoccvir = -natoccvir lib.logger.debug(mp, "* Occupancies") lib.logger.debug(mp, "* %s" % natoccvir) lib.logger.debug(mp, "* The sum is %8.6f" % numpy.sum(natoccvir)) active = (thresh_vir <= natoccvir) lib.logger.info(mp, "* Natural Orbital selection") for i in range(nvir): lib.logger.debug(mp, "orb: %d %s %8.6f" % (i, active[i], natoccvir[i])) actIndices = numpy.where(active)[0] lib.logger.info(mp, "* Original active orbitals %d" % nvir) lib.logger.info(mp, "* Virtual core orbitals: %d" % (nvir - len(actIndices))) lib.logger.info(mp, "* New active orbitals %d" % len(actIndices)) lib.logger.debug(mp, "* Active orbital indices %s" % actIndices) natorbvir = natorbvir[:, actIndices] ev = mo_energy[nocc:] fvv = numpy.diag(ev) fvv = reduce(numpy.dot, (natorbvir.conj().T, fvv, natorbvir)) ev, fnov = numpy.linalg.eigh(fvv) cv = mp.mo_coeff[:, mp.get_frozen_mask()] cv = cv[:, nocc:] cv = reduce(numpy.dot, (cv, natorbvir, fnov)) co = mp.mo_coeff[:, mp.mo_occ > 0] eo = mp.mo_energy[mp.mo_occ > 0] coeff = numpy.hstack([co, cv]) energy = numpy.hstack([eo, ev]) occ = numpy.zeros(coeff.shape[1]) for i in range(mp.mol.nelectron): occ[i] = 1.0 return coeff, energy, occ
def make_rdm1_vv(mp, t2=None): if t2 is None: t2 = mp.t2 dvv = lib.einsum('mnea,mneb->ab', t2, t2.conj()) * 0.5 dm1 = dvv + dvv.conj().T dm1 *= 0.5 return dm1
def contract(myci, civec, eris): nocc = myci.nocc nmo = myci.nmo c0, c1, c2 = cisdvec_to_amplitudes(civec, nmo, nocc) fock = eris.fock foo = fock[:nocc,:nocc] fov = fock[:nocc,nocc:] fvo = fock[nocc:,:nocc] fvv = fock[nocc:,nocc:] t1 = lib.einsum('ie,ae->ia', c1, fvv) t1 -= lib.einsum('ma,mi->ia', c1, foo) t1 += lib.einsum('imae,me->ia', c2, fov) t1 += lib.einsum('nf,nafi->ia', c1, eris.ovvo) t1 -= 0.5*lib.einsum('imef,maef->ia', c2, eris.ovvv) t1 -= 0.5*lib.einsum('mnae,mnie->ia', c2, eris.ooov) tmp = lib.einsum('ijae,be->ijab', c2, fvv) t2 = tmp - tmp.transpose(0,1,3,2) tmp = lib.einsum('imab,mj->ijab', c2, foo) t2 -= tmp - tmp.transpose(1,0,2,3) t2 += 0.5*lib.einsum('mnab,mnij->ijab', c2, eris.oooo) t2 += 0.5*lib.einsum('ijef,abef->ijab', c2, eris.vvvv) tmp = lib.einsum('imae,mbej->ijab', c2, eris.ovvo) tmp+= numpy.einsum('ia,bj->ijab', c1, fvo) tmp = tmp - tmp.transpose(0,1,3,2) t2 += tmp - tmp.transpose(1,0,2,3) tmp = lib.einsum('ie,jeba->ijab', c1, numpy.asarray(eris.ovvv).conj()) t2 += tmp - tmp.transpose(1,0,2,3) tmp = lib.einsum('ma,ijmb->ijab', c1, numpy.asarray(eris.ooov).conj()) t2 -= tmp - tmp.transpose(0,1,3,2) eris_oovv = numpy.asarray(eris.oovv) t1 += fov.conj() * c0 t2 += eris_oovv.conj() * c0 t0 = numpy.einsum('ia,ia', fov, c1) t0 += numpy.einsum('ijab,ijab', eris_oovv, c2) * .25 return amplitudes_to_cisdvec(t0, t1, t2)
def update_amps(cc, t1, t2, eris): # Ref: Hirata et al., J. Chem. Phys. 120, 2581 (2004) Eqs.(35)-(36) assert(isinstance(eris, ccsd._ChemistsERIs)) nocc, nvir = t1.shape fock = eris.fock mo_e_o = eris.mo_energy[:nocc] mo_e_v = eris.mo_energy[nocc:] + cc.level_shift fov = fock[:nocc,nocc:].copy() foo = fock[:nocc,:nocc].copy() fvv = fock[nocc:,nocc:].copy() Foo = imd.cc_Foo(t1,t2,eris) Fvv = imd.cc_Fvv(t1,t2,eris) Fov = imd.cc_Fov(t1,t2,eris) # Move energy terms to the other side Foo[np.diag_indices(nocc)] -= mo_e_o Fvv[np.diag_indices(nvir)] -= mo_e_v #occ_act = np.arange(cc.frozen_occ,nocc) occ_act = np.arange(nocc) vir_act = np.arange(cc.nvir_act) #print("occ_act =", occ_act) #print("vir_act =", vir_act) ia_act = np.ix_(occ_act,vir_act) ijab_act = np.ix_(occ_act,occ_act,vir_act,vir_act) #print("ia =", ia_act) #print("ijab =", ijab_act) # T1 equation t1new = np.copy(fov.conj()) t1new[ia_act] -= 2*np.einsum('kc,ka,ic->ia', fov, t1, t1)[ia_act] t1new[ia_act] += np.einsum('ac,ic->ia', Fvv, t1)[ia_act] t1new[ia_act] += -np.einsum('ki,ka->ia', Foo, t1)[ia_act] t1new[ia_act] += 2*np.einsum('kc,kica->ia', Fov, t2)[ia_act] t1new[ia_act] += -np.einsum('kc,ikca->ia', Fov, t2)[ia_act] t1new[ia_act] += np.einsum('kc,ic,ka->ia', Fov, t1, t1)[ia_act] t1new[ia_act] += 2*np.einsum('kcai,kc->ia', eris.ovvo, t1)[ia_act] t1new[ia_act] += -np.einsum('kiac,kc->ia', eris.oovv, t1)[ia_act] eris_ovvv = np.asarray(eris.get_ovvv()) t1new[ia_act] += 2*lib.einsum('kdac,ikcd->ia', eris_ovvv, t2)[ia_act] t1new[ia_act] += -lib.einsum('kcad,ikcd->ia', eris_ovvv, t2)[ia_act] t1new[ia_act] += 2*lib.einsum('kdac,kd,ic->ia', eris_ovvv, t1, t1)[ia_act] t1new[ia_act] += -lib.einsum('kcad,kd,ic->ia', eris_ovvv, t1, t1)[ia_act] eris_ovoo = np.asarray(eris.ovoo, order='C') t1new[ia_act] +=-2*lib.einsum('lcki,klac->ia', eris_ovoo, t2)[ia_act] t1new[ia_act] += lib.einsum('kcli,klac->ia', eris_ovoo, t2)[ia_act] t1new[ia_act] +=-2*lib.einsum('lcki,lc,ka->ia', eris_ovoo, t1, t1)[ia_act] t1new[ia_act] += lib.einsum('kcli,lc,ka->ia', eris_ovoo, t1, t1)[ia_act] # T2 equation t2new = np.copy(np.asarray(eris.ovov).conj().transpose(0,2,1,3)) tmp2 = lib.einsum('kibc,ka->abic', eris.oovv, -t1) tmp2 += np.asarray(eris_ovvv).conj().transpose(1,3,0,2) tmp = lib.einsum('abic,jc->ijab', tmp2, t1) t2new[ijab_act] += (tmp + tmp.transpose(1,0,3,2))[ijab_act] tmp2 = lib.einsum('kcai,jc->akij', eris.ovvo, t1) tmp2 += eris_ovoo.transpose(1,3,0,2).conj() tmp = lib.einsum('akij,kb->ijab', tmp2, t1) t2new[ijab_act] -= (tmp + tmp.transpose(1,0,3,2))[ijab_act] Loo = imd.Loo(t1, t2, eris) Lvv = imd.Lvv(t1, t2, eris) Loo[np.diag_indices(nocc)] -= mo_e_o Lvv[np.diag_indices(nvir)] -= mo_e_v Woooo = imd.cc_Woooo(t1, t2, eris) Wvoov = imd.cc_Wvoov(t1, t2, eris) Wvovo = imd.cc_Wvovo(t1, t2, eris) Wvvvv = imd.cc_Wvvvv(t1, t2, eris) tau = t2 + np.einsum('ia,jb->ijab', t1, t1) t2new[ijab_act] += lib.einsum('klij,klab->ijab', Woooo, tau)[ijab_act] t2new[ijab_act] += lib.einsum('abcd,ijcd->ijab', Wvvvv, tau)[ijab_act] tmp = lib.einsum('ac,ijcb->ijab', Lvv, t2) t2new[ijab_act] += (tmp + tmp.transpose(1,0,3,2))[ijab_act] tmp = lib.einsum('ki,kjab->ijab', Loo, t2) t2new[ijab_act] -= (tmp + tmp.transpose(1,0,3,2))[ijab_act] tmp = 2*lib.einsum('akic,kjcb->ijab', Wvoov, t2) tmp -= lib.einsum('akci,kjcb->ijab', Wvovo, t2) t2new[ijab_act] += (tmp + tmp.transpose(1,0,3,2))[ijab_act] tmp = lib.einsum('akic,kjbc->ijab', Wvoov, t2) t2new[ijab_act] -= (tmp + tmp.transpose(1,0,3,2))[ijab_act] tmp = lib.einsum('bkci,kjac->ijab', Wvovo, t2) t2new[ijab_act] -= (tmp + tmp.transpose(1,0,3,2))[ijab_act] eia = mo_e_o[:,None] - mo_e_v eijab = lib.direct_sum('ia,jb->ijab',eia,eia) t1new /= eia t2new /= eijab return t1new, t2new
def grad_elec_dferi (mc_grad, mo_cas=None, ci=None, dfcasdm2=None, casdm2=None, atmlst=None, max_memory=None): ''' Evaluate the (P|i'j) d_Pij contribution to the electronic gradient, where d_Pij is the DF-2RDM obtained by solve_df_rdm2. The caller must symmetrize (i.e., [(P|i'j) + (P|ij')] d_Pij / 2) if necessary. Args: mc_grad: MC-SCF gradients method object Kwargs: mc_cas: ndarray, list, or tuple containing active-space MO coefficients If a tuple of length 2, the same pair of MO sets are assumed to apply to the internally-contracted and externally-contracted indices of the DF-2rdm: (P|Q)d_Qij = (P|kl)d_ijkl -> (P|Q)d_Qij = (P|ij)d_ijij If a tuple of length 4, the 4 MO sets are applied to ijkl above in that order (first two external, last two internal). ci: ndarray, tuple, or list containing CI coefficients in mo_cas basis. Not used if dfcasdm2 is provided. dfcasdm2: ndarray, tuple, or list containing DF-2rdm in mo_cas basis. Computed by solve_df_rdm2 if omitted. casdm2: ndarray, tuple, or list containing rdm2 in mo_cas basis. Computed by mc_grad.fcisolver.make_rdm12 (ci,...) if omitted. atmlst: list of integers List of nonfrozen atoms, as in grad_elec functions. Defaults to list (range (mol.natm)) max_memory: int Maximum memory usage in MB Returns: dE: ndarray of shape (len (dfcasdm2), len (atmlst), 3) ''' if isinstance (mc_grad, GradientsBasics): mc = mc_grad.base else: mc = mc_grad mol = mc_grad.mol auxmol = mc.with_df.auxmol ncore, ncas, nao, naux, nbas = mc.ncore, mc.ncas, mol.nao, auxmol.nao, mol.nbas nocc = ncore + ncas if mo_cas is None: mo_cas = mc.mo_coeff[:,ncore:nocc] if max_memory is None: max_memory = mc_grad.max_memory if isinstance (mo_cas, np.ndarray) and mo_cas.ndim == 2: mo_cas = (mo_cas,)*4 elif len (mo_cas) == 2: mo_cas = (mo_cas[0], mo_cas[1], mo_cas[0], mo_cas[1]) elif len (mo_cas) == 4: mo_cas = tuple (mo_cas) else: raise RuntimeError ('Invalid shape of np.asarray (mo_cas): {}'.format (mo_cas.shape)) nmo = [mo.shape[1] for mo in mo_cas] if atmlst is None: atmlst = list (range (mol.natm)) if ci is None: ci = mc.ci if dfcasdm2 is None: dfcasdm2 = solve_df_rdm2 (mc, mo_cas=mo_cas[2:], ci=ci, casdm2=casdm2) # d_Pij nset = len (dfcasdm2) dE = np.zeros ((nset, nao, 3)) dfcasdm2 = np.array (dfcasdm2) # Set up (P|u'v) calculation get_int3c = _int3c_wrapper(mol, auxmol, 'int3c2e_ip1', 's1') max_memory -= lib.current_memory()[0] blklen = nao*((3*nao) + (3*nmo[1]) + (nset*nmo[1])) blksize = int (min (max (max_memory * 1e6 / 8 / blklen, 20), 240)) aux_loc = auxmol.ao_loc aux_ranges = balance_partition(aux_loc, blksize) # Iterate over auxbasis range for shl0, shl1, nL in aux_ranges: p0, p1 = aux_loc[shl0], aux_loc[shl1] int3c = get_int3c ((0, nbas, 0, nbas, shl0, shl1)) # (u'v|P); shape = (3,nao,nao,p1-p0) intbuf = lib.einsum ('xuvp,vj->xupj', int3c, mo_cas[1]) dm2buf = lib.einsum ('ui,npij->nupj', mo_cas[0], dfcasdm2[:,p0:p1,:,:]) dE -= np.einsum ('nupj,xupj->nux', dm2buf, intbuf) intbuf = dm2buf = None intbuf = lib.einsum ('xuvp,vj->xupj', int3c, mo_cas[0]) dm2buf = lib.einsum ('uj,npij->nupi', mo_cas[1], dfcasdm2[:,p0:p1,:,:]) dE -= np.einsum ('nupj,xupj->nux', dm2buf, intbuf) intbuf = dm2buf = int3c = None aoslices = mol.aoslice_by_atom () dE = np.array ([dE[:,p0:p1].sum (axis=1) for p0, p1 in aoslices[:,2:]]).transpose (1,0,2) return np.ascontiguousarray (dE)
def update_amps(self, t1, t2, eris): cc = self # Ref: Taube and Bartlett J. Chem. Phys. 130, 144112 (2009) Eq. 13 and 15 assert isinstance(eris, ccsd._ChemistsERIs) nocc, nvir = t1.shape fock = eris.fock mo_e_o = eris.mo_energy[:nocc] mo_e_v = eris.mo_energy[nocc:] + cc.level_shift fov = fock[:nocc, nocc:].copy() foo = fock[:nocc, :nocc].copy() fvv = fock[nocc:, nocc:].copy() Foo = foo Fvv = fvv Fov = fov # Move energy terms to the other side Foo[np.diag_indices(nocc)] -= mo_e_o Fvv[np.diag_indices(nvir)] -= mo_e_v ############### # T1 equation # ############### t1new = np.zeros_like(t1) # Term 1 t1new += fov.conj() # Term 2 t1new += np.einsum("ac,ic->ia", Fvv, t1) # Term 3 t1new += -np.einsum("ki,ka->ia", Foo, t1) # Term 4 t1new += 2 * np.einsum("kcai,kc->ia", eris.ovvo, t1) t1new += -np.einsum("kiac,kc->ia", eris.oovv, t1) # Term 5 eris_ovvv = np.asarray(eris.get_ovvv()) t1new += 2 * lib.einsum("kdac,ikcd->ia", eris_ovvv, t2) t1new += -lib.einsum("kcad,ikcd->ia", eris_ovvv, t2) # Term 6 eris_ovoo = np.asarray(eris.ovoo, order="C") t1new += -2 * lib.einsum("lcki,klac->ia", eris_ovoo, t2) t1new += lib.einsum("kcli,klac->ia", eris_ovoo, t2) # Term 7 t1new += 2 * np.einsum("kc,kica->ia", Fov, t2) t1new += -np.einsum("kc,ikca->ia", Fov, t2) ############### # T2 equation # ############### t2new = np.zeros_like(t2) # Term 1 t2new += np.asarray(eris.ovov).conj().transpose(0, 2, 1, 3) # Term 2 tmp = lib.einsum("ki,kjab->ijab", Foo, t2) t2new -= tmp + tmp.transpose(1, 0, 3, 2) # Term 3 tmp = lib.einsum("ac,ijcb->ijab", Fvv, t2) t2new += tmp + tmp.transpose(1, 0, 3, 2) Woooo = np.asarray(eris.oooo).transpose(0, 2, 1, 3) Wvoov = np.asarray(eris.ovvo).transpose(2, 0, 3, 1) Wvovo = np.asarray(eris.oovv).transpose(2, 0, 3, 1) Wvvvv = np.asarray(imd._get_vvvv(eris)).transpose(0, 2, 1, 3) # Term 4 t2new += lib.einsum("abcd,ijcd->ijab", Wvvvv, t2) # Term 5 t2new += lib.einsum("klij,klab->ijab", Woooo, t2) # Term 6 tmp = 2 * lib.einsum("akic,kjcb->ijab", Wvoov, t2) tmp -= lib.einsum("akci,kjcb->ijab", Wvovo, t2) t2new += tmp + tmp.transpose(1, 0, 3, 2) tmp = lib.einsum("akic,kjbc->ijab", Wvoov, t2) t2new -= tmp + tmp.transpose(1, 0, 3, 2) tmp = lib.einsum("bkci,kjac->ijab", Wvovo, t2) t2new -= tmp + tmp.transpose(1, 0, 3, 2) # Term 7 tmp2 = eris_ovoo.transpose(1, 3, 0, 2).conj() tmp = lib.einsum("akij,kb->ijab", tmp2, t1) t2new -= tmp + tmp.transpose(1, 0, 3, 2) # Term 8 tmp2 = np.asarray(eris_ovvv).conj().transpose(1, 3, 0, 2) tmp = lib.einsum("abic,jc->ijab", tmp2, t1) t2new += tmp + tmp.transpose(1, 0, 3, 2) eia = mo_e_o[:, None] - mo_e_v eijab = lib.direct_sum("ia,jb->ijab", eia, eia) t1new /= eia t2new /= eijab return t1new, t2new
def construct_tdm(self): # Indexes of td_x: # - k_transfer # - k # - o: k # - v: fw[k] # Indexes of td_y: # - k_transfer # - k # - o: k # - v: bw[k] # Original code: # tdm_oo = einsum('vxia,ipaq->vxpq', td_xy, self["oovo"]) # tdm_ov = einsum('vxia,ipaq->vxpq', td_xy, self["oovv"]) # tdm_vv = einsum('vxia,ipaq->vxpq', td_xy, self["ovvv"]) # ERI k: # ki, kp, ka=?, kq # Now fw[kp] = kq, bw[kq] = kp -> bw[ki] = ka, fw[ka] = ki # for x amplitudes, the transfer is bw[0] such that ov -> k, bw[k] # for y amplitudes, the transfer is also fw[0] such that ov -> k, bw[k] result = [] for k_transfer in range(self.nk): xy_k = self.td_xy[k_transfer] fw, bw, _, _ = get_block_k_ix(self.eri, k_transfer) result.append([[], []]) for xy_kx, ix_fw, ix_bw, storage in ( (xy_k[:, 0], fw, bw, result[k_transfer][0]), # X (xy_k[:, 1], bw, fw, result[k_transfer][1]), # Y ): for kp in range(self.nk): tdm_oo = tdm_ov = tdm_vv = 0 tdm_vo = 0 for ki in range(self.nk): x = xy_kx[:, ki] * 2 tdm_oo = tdm_oo + einsum( 'via,ipaq->vpq', x, self["oovo", ki, kp, ix_fw[ki], ix_bw[kp]]) tdm_ov = tdm_ov + einsum( 'via,ipaq->vpq', x, self["oovv", ki, kp, ix_fw[ki], ix_bw[kp]]) tdm_vv = tdm_vv + einsum( 'via,ipaq->vpq', x, self["ovvv", ki, kp, ix_fw[ki], ix_bw[kp]]) tdm_vo = tdm_vo + einsum( 'via,ipaq->vpq', x, self["ovvo", ki, kp, ix_fw[ki], ix_bw[kp]]) tdm = numpy.concatenate( (numpy.concatenate((tdm_oo, tdm_ov), axis=2), numpy.concatenate((tdm_vo, tdm_vv), axis=2)), axis=1, ) storage.append(tdm) # The output is the following: # for each kp, kq pair two 3-tensors are given # The last two indexes in each tensor correspond to kp, kq # Given fw, bw, _, _ = get_block_k_ix(self.eri, (kp, kq)), # The first index of the two tensors will correspond to tdhf.e[bw[0]], tdhf.e[fw[0]] correspondingly return numpy.array(result)
def _gamma1_intermediates(mp, t2): doo = lib.einsum('imef,jmef->ij', t2.conj(), t2) * -.5 dvv = lib.einsum('mnea,mneb->ab', t2, t2.conj()) * .5 return doo, dvv
def test_update_amps2(self): # compare to gccsd.update_amps mol = mol_s2 mf = mf_s2 myucc = uccsd.UCCSD(mf) nocca, noccb = 6, 4 nmo = mol.nao_nr() nvira, nvirb = nmo - nocca, nmo - noccb numpy.random.seed(9) t1 = [ numpy.random.random((nocca, nvira)) - .9, numpy.random.random((noccb, nvirb)) - .9 ] t2 = [ numpy.random.random((nocca, nocca, nvira, nvira)) - .9, numpy.random.random((nocca, noccb, nvira, nvirb)) - .9, numpy.random.random((noccb, noccb, nvirb, nvirb)) - .9 ] t2[0] = t2[0] - t2[0].transpose(1, 0, 2, 3) t2[0] = t2[0] - t2[0].transpose(0, 1, 3, 2) t2[2] = t2[2] - t2[2].transpose(1, 0, 2, 3) t2[2] = t2[2] - t2[2].transpose(0, 1, 3, 2) mo_a = mf.mo_coeff[0] + numpy.sin(mf.mo_coeff[0]) * .01j mo_b = mf.mo_coeff[1] + numpy.sin(mf.mo_coeff[1]) * .01j nao = mo_a.shape[0] eri = ao2mo.restore(1, mf._eri, nao) eri0aa = lib.einsum('pqrs,pi,qj,rk,sl->ijkl', eri, mo_a.conj(), mo_a, mo_a.conj(), mo_a) eri0ab = lib.einsum('pqrs,pi,qj,rk,sl->ijkl', eri, mo_a.conj(), mo_a, mo_b.conj(), mo_b) eri0bb = lib.einsum('pqrs,pi,qj,rk,sl->ijkl', eri, mo_b.conj(), mo_b, mo_b.conj(), mo_b) eri0ba = eri0ab.transpose(2, 3, 0, 1) nvira = nao - nocca nvirb = nao - noccb eris = uccsd._ChemistsERIs(mol) eris.oooo = eri0aa[:nocca, :nocca, :nocca, :nocca].copy() eris.ovoo = eri0aa[:nocca, nocca:, :nocca, :nocca].copy() eris.oovv = eri0aa[:nocca, :nocca, nocca:, nocca:].copy() eris.ovvo = eri0aa[:nocca, nocca:, nocca:, :nocca].copy() eris.ovov = eri0aa[:nocca, nocca:, :nocca, nocca:].copy() eris.ovvv = eri0aa[:nocca, nocca:, nocca:, nocca:].copy() eris.vvvv = eri0aa[nocca:, nocca:, nocca:, nocca:].copy() eris.OOOO = eri0bb[:noccb, :noccb, :noccb, :noccb].copy() eris.OVOO = eri0bb[:noccb, noccb:, :noccb, :noccb].copy() eris.OOVV = eri0bb[:noccb, :noccb, noccb:, noccb:].copy() eris.OVVO = eri0bb[:noccb, noccb:, noccb:, :noccb].copy() eris.OVOV = eri0bb[:noccb, noccb:, :noccb, noccb:].copy() eris.OVVV = eri0bb[:noccb, noccb:, noccb:, noccb:].copy() eris.VVVV = eri0bb[noccb:, noccb:, noccb:, noccb:].copy() eris.ooOO = eri0ab[:nocca, :nocca, :noccb, :noccb].copy() eris.ovOO = eri0ab[:nocca, nocca:, :noccb, :noccb].copy() eris.ooVV = eri0ab[:nocca, :nocca, noccb:, noccb:].copy() eris.ovVO = eri0ab[:nocca, nocca:, noccb:, :noccb].copy() eris.ovOV = eri0ab[:nocca, nocca:, :noccb, noccb:].copy() eris.ovVV = eri0ab[:nocca, nocca:, noccb:, noccb:].copy() eris.vvVV = eri0ab[nocca:, nocca:, noccb:, noccb:].copy() eris.OOoo = eri0ba[:noccb, :noccb, :nocca, :nocca].copy() eris.OVoo = eri0ba[:noccb, noccb:, :nocca, :nocca].copy() eris.OOvv = eri0ba[:noccb, :noccb, nocca:, nocca:].copy() eris.OVvo = eri0ba[:noccb, noccb:, nocca:, :nocca].copy() eris.OVov = eri0ba[:noccb, noccb:, :nocca, nocca:].copy() eris.OVvv = eri0ba[:noccb, noccb:, nocca:, nocca:].copy() eris.VVvv = eri0ba[noccb:, noccb:, nocca:, nocca:].copy() eris.focka = numpy.diag(mf.mo_energy[0]) eris.fockb = numpy.diag(mf.mo_energy[1]) eris.mo_energy = mf.mo_energy t1[0] = t1[0] + numpy.sin(t1[0]) * .05j t1[1] = t1[1] + numpy.sin(t1[1]) * .05j t2[0] = t2[0] + numpy.sin(t2[0]) * .05j t2[1] = t2[1] + numpy.sin(t2[1]) * .05j t2[2] = t2[2] + numpy.sin(t2[2]) * .05j t1new_ref, t2new_ref = uccsd.update_amps(myucc, t1, t2, eris) nocc = nocca + noccb orbspin = numpy.zeros(nao * 2, dtype=int) orbspin[1::2] = 1 orbspin[nocc - 1] = 0 orbspin[nocc] = 1 eri1 = numpy.zeros([nao * 2] * 4, dtype=numpy.complex128) idxa = numpy.where(orbspin == 0)[0] idxb = numpy.where(orbspin == 1)[0] eri1[idxa[:, None, None, None], idxa[:, None, None], idxa[:, None], idxa] = eri0aa eri1[idxa[:, None, None, None], idxa[:, None, None], idxb[:, None], idxb] = eri0ab eri1[idxb[:, None, None, None], idxb[:, None, None], idxa[:, None], idxa] = eri0ba eri1[idxb[:, None, None, None], idxb[:, None, None], idxb[:, None], idxb] = eri0bb eri1 = eri1.transpose(0, 2, 1, 3) - eri1.transpose(0, 2, 3, 1) erig = gccsd._PhysicistsERIs() erig.oooo = eri1[:nocc, :nocc, :nocc, :nocc].copy() erig.ooov = eri1[:nocc, :nocc, :nocc, nocc:].copy() erig.ovov = eri1[:nocc, nocc:, :nocc, nocc:].copy() erig.ovvo = eri1[:nocc, nocc:, nocc:, :nocc].copy() erig.oovv = eri1[:nocc, :nocc, nocc:, nocc:].copy() erig.ovvv = eri1[:nocc, nocc:, nocc:, nocc:].copy() erig.vvvv = eri1[nocc:, nocc:, nocc:, nocc:].copy() mo_e = numpy.empty(nao * 2) mo_e[orbspin == 0] = mf.mo_energy[0] mo_e[orbspin == 1] = mf.mo_energy[1] erig.fock = numpy.diag(mo_e) erig.mo_energy = mo_e.real myccg = gccsd.GCCSD(scf.addons.convert_to_ghf(mf)) t1 = myccg.spatial2spin(t1, orbspin) t2 = myccg.spatial2spin(t2, orbspin) t1new, t2new = gccsd.update_amps(myccg, t1, t2, erig) t1new = myccg.spin2spatial(t1new, orbspin) t2new = myccg.spin2spatial(t2new, orbspin) self.assertAlmostEqual(abs(t1new[0] - t1new_ref[0]).max(), 0, 12) self.assertAlmostEqual(abs(t1new[1] - t1new_ref[1]).max(), 0, 12) self.assertAlmostEqual(abs(t2new[0] - t2new_ref[0]).max(), 0, 12) self.assertAlmostEqual(abs(t2new[1] - t2new_ref[1]).max(), 0, 12) self.assertAlmostEqual(abs(t2new[2] - t2new_ref[2]).max(), 0, 12)
def k2s(model, grid_spec, mf_constructor, threshold=None, degeneracy_threshold=None, imaginary_threshold=None): """ Converts k-point model into a supercell with real orbitals. Args: model: a mean-field pbc model; grid_spec (Iterable): integer dimensions of the k-grid in the mean-field model; mf_constructor (Callable): a function constructing the mean-field object; threshold (float): a threshold for determining the negative k-point index; degeneracy_threshold (float): a threshold for assuming degeneracy when composing real-valued orbitals; imaginary_threshold (float): a threshold for asserting real-valued supercell orbitals; Returns: The same class where the Cell object was replaced by the supercell and all fields were adjusted accordingly. """ # This hack works as follows. Provided TRS Hamiltonian # H(k) = H(-k)*, # with same real eigenvalues and eigenfunctions related as # psi(k) = c psi(-k)*, # c - arbitrary phase, it is easy to construct real (non-Bloch) eigenvectors of the whole Hamiltonian # real1(|k|) = c* psi(k) + psi(-k) = psi(-k)* + psi(-k) # and # real2(|k|) = 1.j * (c* psi(k) - psi(-k)) = 1.j* (psi(-k)* - psi(-k)). # The coefficient c is determined as # psi(k) * psi(-k) = c psi(-k)* * psi(-k) = c if imaginary_threshold is None: imaginary_threshold = 1e-7 mk = minus_k(model, threshold=threshold, degeneracy_threshold=degeneracy_threshold) # Fix phases ovlp = model.get_ovlp() phases = {} for k1, k2 in enumerate(mk): if k1 <= k2: c1 = model.mo_coeff[k1] c2 = model.mo_coeff[k2] o = ovlp[k1] r = reduce(numpy.dot, (c2.T, o, c1)) delta = abs(abs(r) - numpy.eye(r.shape[0])).max() if delta > imaginary_threshold: raise RuntimeError( "K-points connected by time reversal {:d} and {:d} are not complex conjugate: " "the difference {:.3e} is larger than the threshold {:.3e}" .format( k1, k2, delta, imaginary_threshold, )) p = numpy.angle(numpy.diag(r)) if k1 == k2: phases[k1] = numpy.exp(-.5j * p)[numpy.newaxis, :] else: phases[k1] = numpy.exp(-1.j * p)[numpy.newaxis, :] nk = len(model.kpts) t_vecs = cartesian_prod(tuple(numpy.arange(i) for i in grid_spec)) kpts_frac = model.cell.get_scaled_kpts(model.kpts) result = mf_constructor(super_cell(model.cell, grid_spec)) result_ovlp = result.get_ovlp()[0] moe = numpy.concatenate(model.mo_energy) moo = numpy.concatenate(model.mo_occ) # Complex-valued wf in a supercell moc = [] for mo_coeff, k in zip(model.mo_coeff, kpts_frac): psi = ( mo_coeff[numpy.newaxis, ...] * numpy.exp(2.j * numpy.pi * t_vecs.dot(k))[:, numpy.newaxis, numpy.newaxis]).reshape( -1, mo_coeff.shape[1]) norms = einsum("ai,ab,bi->i", psi.conj(), result_ovlp, psi)**.5 psi /= norms[numpy.newaxis, :] moc.append(psi) moc = numpy.concatenate(moc, axis=1) rotation_matrix = sparse.dok_matrix(moc.shape, dtype=moc.dtype) inv_rotation_matrix = sparse.dok_matrix(moc.shape, dtype=moc.dtype) nvecs = (0, ) + tuple(i.shape[1] for i in model.mo_coeff) nvecs = numpy.cumsum(nvecs) k_spaces = tuple(numpy.arange(i, j) for i, j in zip(nvecs[:-1], nvecs[1:])) for k in range(nk): i = k_spaces[k] j = k_spaces[mk[k]] if k == mk[k]: rotation_matrix[i, i] = phases[k] inv_rotation_matrix[i, i] = phases[k].conj() elif k < mk[k]: rotation_matrix[i, i] = .5**.5 * phases[k] rotation_matrix[j, i] = .5**.5 rotation_matrix[i, j] = -1.j * .5**.5 * phases[k] rotation_matrix[j, j] = 1.j * .5**.5 inv_rotation_matrix[i, i] = .5**.5 * phases[k].conj() inv_rotation_matrix[j, i] = 1.j * .5**.5 * phases[k].conj() inv_rotation_matrix[i, j] = .5**.5 inv_rotation_matrix[j, j] = -1.j * .5**.5 else: pass rotation_matrix = rotation_matrix.tocsc() inv_rotation_matrix = inv_rotation_matrix.tocsc() moc = sparse_transform(moc, 1, rotation_matrix) max_imag = abs(moc.imag).max() if max_imag > imaginary_threshold: raise RuntimeError( "Failed to compose real-valued orbitals: imaginary part is {:.3e}". format(max_imag)) moc = moc.real mok = numpy.concatenate( tuple([i] * len(j) for i, j in enumerate(model.mo_energy))) moi = numpy.concatenate( tuple(numpy.arange(len(j)) for j in model.mo_energy)) order = numpy.argsort(moe) moe = moe[order] moc = moc[:, order] moo = moo[order] mok = mok[order] moi = moi[order] rotation_matrix = rotation_matrix[:, order] inv_rotation_matrix = inv_rotation_matrix[order, :] result.mo_occ = moo, result.mo_energy = moe, result.mo_coeff = moc, result.supercell_rotation = rotation_matrix result.supercell_inv_rotation = inv_rotation_matrix result.supercell_orig_k = mok result.supercell_orig_i = moi assert_scf_converged(result, model.conv_tol**.5) p1 = abs( result.supercell_rotation.dot(result.supercell_inv_rotation) - numpy.eye(rotation_matrix.shape[0])).max() p2 = abs( result.supercell_inv_rotation.dot(result.supercell_rotation) - numpy.eye(rotation_matrix.shape[0])).max() if p1 > 1e-14 or p2 > 1e-14: raise RuntimeError("Rotation matrix error: {:.3e}, {:.3e}".format( p1, p2)) return result
def make_intermediates(mycc, t1, t2, eris): t1a, t1b = t1 t2aa, t2ab, t2bb = t2 nocca, nvira = t1a.shape noccb, nvirb = t1b.shape fooa = eris.focka[:nocca,:nocca] fova = eris.focka[:nocca,nocca:] fvoa = eris.focka[nocca:,:nocca] fvva = eris.focka[nocca:,nocca:] foob = eris.fockb[:noccb,:noccb] fovb = eris.fockb[:noccb,noccb:] fvob = eris.fockb[noccb:,:noccb] fvvb = eris.fockb[noccb:,noccb:] tauaa, tauab, taubb = uccsd.make_tau(t2, t1, t1) ovov = numpy.asarray(eris.ovov) ovov = ovov - ovov.transpose(0,3,2,1) OVOV = numpy.asarray(eris.OVOV) OVOV = OVOV - OVOV.transpose(0,3,2,1) ovOV = numpy.asarray(eris.ovOV) v1a = fvva - einsum('ja,jb->ba', fova, t1a) v1b = fvvb - einsum('ja,jb->ba', fovb, t1b) v1a += einsum('jcka,jkbc->ba', ovov, tauaa) * .5 v1a -= einsum('jaKC,jKbC->ba', ovOV, tauab) * .5 v1a -= einsum('kaJC,kJbC->ba', ovOV, tauab) * .5 v1b += einsum('jcka,jkbc->ba', OVOV, taubb) * .5 v1b -= einsum('kcJA,kJcB->BA', ovOV, tauab) * .5 v1b -= einsum('jcKA,jKcB->BA', ovOV, tauab) * .5 v2a = fooa + einsum('ib,jb->ij', fova, t1a) v2b = foob + einsum('ib,jb->ij', fovb, t1b) v2a += einsum('ibkc,jkbc->ij', ovov, tauaa) * .5 v2a += einsum('ibKC,jKbC->ij', ovOV, tauab) v2b += einsum('ibkc,jkbc->ij', OVOV, taubb) * .5 v2b += einsum('kcIB,kJcB->IJ', ovOV, tauab) ovoo = numpy.asarray(eris.ovoo) ovoo = ovoo - ovoo.transpose(2,1,0,3) OVOO = numpy.asarray(eris.OVOO) OVOO = OVOO - OVOO.transpose(2,1,0,3) OVoo = numpy.asarray(eris.OVoo) ovOO = numpy.asarray(eris.ovOO) v2a -= numpy.einsum('ibkj,kb->ij', ovoo, t1a) v2a += numpy.einsum('KBij,KB->ij', OVoo, t1b) v2b -= numpy.einsum('ibkj,kb->ij', OVOO, t1b) v2b += numpy.einsum('kbIJ,kb->IJ', ovOO, t1a) v5a = fvoa + numpy.einsum('kc,jkbc->bj', fova, t2aa) v5a += numpy.einsum('KC,jKbC->bj', fovb, t2ab) v5b = fvob + numpy.einsum('kc,jkbc->bj', fovb, t2bb) v5b += numpy.einsum('kc,kJcB->BJ', fova, t2ab) tmp = fova - numpy.einsum('kdlc,ld->kc', ovov, t1a) tmp += numpy.einsum('kcLD,LD->kc', ovOV, t1b) v5a += einsum('kc,kb,jc->bj', tmp, t1a, t1a) tmp = fovb - numpy.einsum('kdlc,ld->kc', OVOV, t1b) tmp += numpy.einsum('ldKC,ld->KC', ovOV, t1a) v5b += einsum('kc,kb,jc->bj', tmp, t1b, t1b) v5a -= einsum('lckj,klbc->bj', ovoo, t2aa) * .5 v5a -= einsum('LCkj,kLbC->bj', OVoo, t2ab) v5b -= einsum('LCKJ,KLBC->BJ', OVOO, t2bb) * .5 v5b -= einsum('lcKJ,lKcB->BJ', ovOO, t2ab) oooo = numpy.asarray(eris.oooo) OOOO = numpy.asarray(eris.OOOO) ooOO = numpy.asarray(eris.ooOO) woooo = einsum('icjl,kc->ikjl', ovoo, t1a) wOOOO = einsum('icjl,kc->ikjl', OVOO, t1b) wooOO = einsum('icJL,kc->ikJL', ovOO, t1a) wooOO += einsum('JCil,KC->ilJK', OVoo, t1b) woooo += (oooo - oooo.transpose(0,3,2,1)) * .5 wOOOO += (OOOO - OOOO.transpose(0,3,2,1)) * .5 wooOO += ooOO.copy() woooo += einsum('icjd,klcd->ikjl', ovov, tauaa) * .25 wOOOO += einsum('icjd,klcd->ikjl', OVOV, taubb) * .25 wooOO += einsum('icJD,kLcD->ikJL', ovOV, tauab) v4ovvo = einsum('jbld,klcd->jbck', ovov, t2aa) v4ovvo += einsum('jbLD,kLcD->jbck', ovOV, t2ab) v4ovvo += numpy.asarray(eris.ovvo) v4ovvo -= numpy.asarray(eris.oovv).transpose(0,3,2,1) v4OVVO = einsum('jbld,klcd->jbck', OVOV, t2bb) v4OVVO += einsum('ldJB,lKdC->JBCK', ovOV, t2ab) v4OVVO += numpy.asarray(eris.OVVO) v4OVVO -= numpy.asarray(eris.OOVV).transpose(0,3,2,1) v4OVvo = einsum('ldJB,klcd->JBck', ovOV, t2aa) v4OVvo += einsum('JBLD,kLcD->JBck', OVOV, t2ab) v4OVvo += numpy.asarray(eris.OVvo) v4ovVO = einsum('jbLD,KLCD->jbCK', ovOV, t2bb) v4ovVO += einsum('jbld,lKdC->jbCK', ovov, t2ab) v4ovVO += numpy.asarray(eris.ovVO) v4oVVo = einsum('jdLB,kLdC->jBCk', ovOV, t2ab) v4oVVo -= numpy.asarray(eris.ooVV).transpose(0,3,2,1) v4OvvO = einsum('lbJD,lKcD->JbcK', ovOV, t2ab) v4OvvO -= numpy.asarray(eris.OOvv).transpose(0,3,2,1) woovo = einsum('ibck,jb->ijck', v4ovvo, t1a) wOOVO = einsum('ibck,jb->ijck', v4OVVO, t1b) wOOvo = einsum('IBck,JB->IJck', v4OVvo, t1b) wOOvo -= einsum('IbcK,jb->IKcj', v4OvvO, t1a) wooVO = einsum('ibCK,jb->ijCK', v4ovVO, t1a) wooVO -= einsum('iBCk,JB->ikCJ', v4oVVo, t1b) woovo += ovoo.conj().transpose(3,2,1,0) * .5 wOOVO += OVOO.conj().transpose(3,2,1,0) * .5 wooVO += OVoo.conj().transpose(3,2,1,0) wOOvo += ovOO.conj().transpose(3,2,1,0) woovo -= einsum('iclk,jlbc->ikbj', ovoo, t2aa) woovo += einsum('LCik,jLbC->ikbj', OVoo, t2ab) wOOVO -= einsum('iclk,jlbc->ikbj', OVOO, t2bb) wOOVO += einsum('lcIK,lJcB->IKBJ', ovOO, t2ab) wooVO -= einsum('iclk,lJcB->ikBJ', ovoo, t2ab) wooVO += einsum('LCik,JLBC->ikBJ', OVoo, t2bb) wooVO -= einsum('icLK,jLcB->ijBK', ovOO, t2ab) wOOvo -= einsum('ICLK,jLbC->IKbj', OVOO, t2ab) wOOvo += einsum('lcIK,jlbc->IKbj', ovOO, t2aa) wOOvo -= einsum('IClk,lJbC->IJbk', OVoo, t2ab) wvvvo = einsum('jack,jb->back', v4ovvo, t1a) wVVVO = einsum('jack,jb->back', v4OVVO, t1b) wVVvo = einsum('JAck,JB->BAck', v4OVvo, t1b) wVVvo -= einsum('jACk,jb->CAbk', v4oVVo, t1a) wvvVO = einsum('jaCK,jb->baCK', v4ovVO, t1a) wvvVO -= einsum('JacK,JB->caBK', v4OvvO, t1b) wvvvo += einsum('lajk,jlbc->back', .25*ovoo, tauaa) wVVVO += einsum('lajk,jlbc->back', .25*OVOO, taubb) wVVvo -= einsum('LAjk,jLcB->BAck', OVoo, tauab) wvvVO -= einsum('laJK,lJbC->baCK', ovOO, tauab) w3a = numpy.einsum('jbck,jb->ck', v4ovvo, t1a) w3a += numpy.einsum('JBck,JB->ck', v4OVvo, t1b) w3b = numpy.einsum('jbck,jb->ck', v4OVVO, t1b) w3b += numpy.einsum('jbCK,jb->CK', v4ovVO, t1a) wovvo = v4ovvo wOVVO = v4OVVO wovVO = v4ovVO wOVvo = v4OVvo woVVo = v4oVVo wOvvO = v4OvvO wovvo += lib.einsum('jbld,kd,lc->jbck', ovov, t1a, -t1a) wOVVO += lib.einsum('jbld,kd,lc->jbck', OVOV, t1b, -t1b) wovVO += lib.einsum('jbLD,KD,LC->jbCK', ovOV, t1b, -t1b) wOVvo += lib.einsum('ldJB,kd,lc->JBck', ovOV, t1a, -t1a) woVVo += lib.einsum('jdLB,kd,LC->jBCk', ovOV, t1a, t1b) wOvvO += lib.einsum('lbJD,KD,lc->JbcK', ovOV, t1b, t1a) wovvo -= einsum('jblk,lc->jbck', ovoo, t1a) wOVVO -= einsum('jblk,lc->jbck', OVOO, t1b) wovVO -= einsum('jbLK,LC->jbCK', ovOO, t1b) wOVvo -= einsum('JBlk,lc->JBck', OVoo, t1a) woVVo += einsum('LBjk,LC->jBCk', OVoo, t1b) wOvvO += einsum('lbJK,lc->JbcK', ovOO, t1a) if nvira > 0 and nocca > 0: ovvv = numpy.asarray(eris.get_ovvv()) ovvv = ovvv - ovvv.transpose(0,3,2,1) v1a -= numpy.einsum('jabc,jc->ba', ovvv, t1a) v5a += einsum('kdbc,jkcd->bj', ovvv, t2aa) * .5 woovo += einsum('idcb,kjbd->ijck', ovvv, tauaa) * .25 wovvo += einsum('jbcd,kd->jbck', ovvv, t1a) wvvvo -= ovvv.conj().transpose(3,2,1,0) * .5 wvvvo += einsum('jacd,kjbd->cabk', ovvv, t2aa) wvvVO += einsum('jacd,jKdB->caBK', ovvv, t2ab) ovvv = tmp = None if nvirb > 0 and noccb > 0: OVVV = numpy.asarray(eris.get_OVVV()) OVVV = OVVV - OVVV.transpose(0,3,2,1) v1b -= numpy.einsum('jabc,jc->ba', OVVV, t1b) v5b += einsum('KDBC,JKCD->BJ', OVVV, t2bb) * .5 wOOVO += einsum('idcb,kjbd->ijck', OVVV, taubb) * .25 wOVVO += einsum('jbcd,kd->jbck', OVVV, t1b) wVVVO -= OVVV.conj().transpose(3,2,1,0) * .5 wVVVO += einsum('jacd,kjbd->cabk', OVVV, t2bb) wVVvo += einsum('JACD,kJbD->CAbk', OVVV, t2ab) OVVV = tmp = None if nvirb > 0 and nocca > 0: OVvv = numpy.asarray(eris.get_OVvv()) v1a += numpy.einsum('JCba,JC->ba', OVvv, t1b) v5a += einsum('KDbc,jKcD->bj', OVvv, t2ab) wOOvo += einsum('IDcb,kJbD->IJck', OVvv, tauab) wOVvo += einsum('JBcd,kd->JBck', OVvv, t1a) wOvvO -= einsum('JDcb,KD->JbcK', OVvv, t1b) wvvVO -= OVvv.conj().transpose(3,2,1,0) wvvvo -= einsum('KDca,jKbD->cabj', OVvv, t2ab) wvvVO -= einsum('KDca,JKBD->caBJ', OVvv, t2bb) wVVvo += einsum('KAcd,jKdB->BAcj', OVvv, t2ab) OVvv = tmp = None if nvira > 0 and noccb > 0: ovVV = numpy.asarray(eris.get_ovVV()) v1b += numpy.einsum('jcBA,jc->BA', ovVV, t1a) v5b += einsum('kdBC,kJdC->BJ', ovVV, t2ab) wooVO += einsum('idCB,jKdB->ijCK', ovVV, tauab) wovVO += einsum('jbCD,KD->jbCK', ovVV, t1b) woVVo -= einsum('jdCB,kd->jBCk', ovVV, t1a) wVVvo -= ovVV.conj().transpose(3,2,1,0) wVVVO -= einsum('kdCA,kJdB->CABJ', ovVV, t2ab) wVVvo -= einsum('kdCA,jkbd->CAbj', ovVV, t2aa) wvvVO += einsum('kaCD,kJbD->baCJ', ovVV, t2ab) ovVV = tmp = None w3a += v5a w3b += v5b w3a += lib.einsum('cb,jb->cj', v1a, t1a) w3b += lib.einsum('cb,jb->cj', v1b, t1b) w3a -= lib.einsum('jk,jb->bk', v2a, t1a) w3b -= lib.einsum('jk,jb->bk', v2b, t1b) class _IMDS: pass imds = _IMDS() imds.ftmp = lib.H5TmpFile() dtype = numpy.result_type(t2ab, eris.vvvv).char imds.woooo = imds.ftmp.create_dataset('woooo', (nocca,nocca,nocca,nocca), dtype) imds.wooOO = imds.ftmp.create_dataset('wooOO', (nocca,nocca,noccb,noccb), dtype) imds.wOOOO = imds.ftmp.create_dataset('wOOOO', (noccb,noccb,noccb,noccb), dtype) imds.wovvo = imds.ftmp.create_dataset('wovvo', (nocca,nvira,nvira,nocca), dtype) imds.wOVVO = imds.ftmp.create_dataset('wOVVO', (noccb,nvirb,nvirb,noccb), dtype) imds.wovVO = imds.ftmp.create_dataset('wovVO', (nocca,nvira,nvirb,noccb), dtype) imds.wOVvo = imds.ftmp.create_dataset('wOVvo', (noccb,nvirb,nvira,nocca), dtype) imds.woVVo = imds.ftmp.create_dataset('woVVo', (nocca,nvirb,nvirb,nocca), dtype) imds.wOvvO = imds.ftmp.create_dataset('wOvvO', (noccb,nvira,nvira,noccb), dtype) imds.woovo = imds.ftmp.create_dataset('woovo', (nocca,nocca,nvira,nocca), dtype) imds.wOOVO = imds.ftmp.create_dataset('wOOVO', (noccb,noccb,nvirb,noccb), dtype) imds.wOOvo = imds.ftmp.create_dataset('wOOvo', (noccb,noccb,nvira,nocca), dtype) imds.wooVO = imds.ftmp.create_dataset('wooVO', (nocca,nocca,nvirb,noccb), dtype) imds.wvvvo = imds.ftmp.create_dataset('wvvvo', (nvira,nvira,nvira,nocca), dtype) imds.wVVVO = imds.ftmp.create_dataset('wVVVO', (nvirb,nvirb,nvirb,noccb), dtype) imds.wVVvo = imds.ftmp.create_dataset('wVVvo', (nvirb,nvirb,nvira,nocca), dtype) imds.wvvVO = imds.ftmp.create_dataset('wvvVO', (nvira,nvira,nvirb,noccb), dtype) imds.woooo[:] = woooo imds.wOOOO[:] = wOOOO imds.wooOO[:] = wooOO imds.wovvo[:] = wovvo imds.wOVVO[:] = wOVVO imds.wovVO[:] = wovVO imds.wOVvo[:] = wOVvo imds.woVVo[:] = woVVo imds.wOvvO[:] = wOvvO imds.woovo[:] = woovo imds.wOOVO[:] = wOOVO imds.wOOvo[:] = wOOvo imds.wooVO[:] = wooVO imds.wvvvo[:] = wvvvo imds.wVVVO[:] = wVVVO imds.wVVvo[:] = wVVvo imds.wvvVO[:] = wvvVO imds.v1a = v1a imds.v1b = v1b imds.v2a = v2a imds.v2b = v2b imds.w3a = w3a imds.w3b = w3b imds.ftmp.flush() return imds
def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None): r'''A and B matrices for TDDFT response function. A[i,a,j,b] = \delta_{ab}\delta_{ij}(E_a - E_i) + (ia||bj) B[i,a,j,b] = (ia||jb) Spin symmetry is considered in the returned A, B lists. List A has three items: (A_aaaa, A_aabb, A_bbbb). A_bbaa = A_aabb.transpose(2,3,0,1). B has three items: (B_aaaa, B_aabb, B_bbbb). B_bbaa = B_aabb.transpose(2,3,0,1). ''' if mo_energy is None: mo_energy = mf.mo_energy if mo_coeff is None: mo_coeff = mf.mo_coeff if mo_occ is None: mo_occ = mf.mo_occ mol = mf.mol nao = mol.nao_nr() occidx_a = numpy.where(mo_occ[0] == 1)[0] viridx_a = numpy.where(mo_occ[0] == 0)[0] occidx_b = numpy.where(mo_occ[1] == 1)[0] viridx_b = numpy.where(mo_occ[1] == 0)[0] orbo_a = mo_coeff[0][:, occidx_a] orbv_a = mo_coeff[0][:, viridx_a] orbo_b = mo_coeff[1][:, occidx_b] orbv_b = mo_coeff[1][:, viridx_b] nocc_a = orbo_a.shape[1] nvir_a = orbv_a.shape[1] nocc_b = orbo_b.shape[1] nvir_b = orbv_b.shape[1] mo_a = numpy.hstack((orbo_a, orbv_a)) mo_b = numpy.hstack((orbo_b, orbv_b)) nmo_a = nocc_a + nvir_a nmo_b = nocc_b + nvir_b e_ia_a = (mo_energy[0][viridx_a, None] - mo_energy[0][occidx_a]).T e_ia_b = (mo_energy[1][viridx_b, None] - mo_energy[1][occidx_b]).T a_aa = numpy.diag(e_ia_a.ravel()).reshape(nocc_a, nvir_a, nocc_a, nvir_a) a_bb = numpy.diag(e_ia_b.ravel()).reshape(nocc_b, nvir_b, nocc_b, nvir_b) a_ab = numpy.zeros((nocc_a, nvir_a, nocc_b, nvir_b)) b_aa = numpy.zeros_like(a_aa) b_ab = numpy.zeros_like(a_ab) b_bb = numpy.zeros_like(a_bb) a = (a_aa, a_ab, a_bb) b = (b_aa, b_ab, b_bb) def add_hf_(a, b, hyb=1): eri_aa = ao2mo.general(mol, [orbo_a, mo_a, mo_a, mo_a], compact=False) eri_ab = ao2mo.general(mol, [orbo_a, mo_a, mo_b, mo_b], compact=False) eri_bb = ao2mo.general(mol, [orbo_b, mo_b, mo_b, mo_b], compact=False) eri_aa = eri_aa.reshape(nocc_a, nmo_a, nmo_a, nmo_a) eri_ab = eri_ab.reshape(nocc_a, nmo_a, nmo_b, nmo_b) eri_bb = eri_bb.reshape(nocc_b, nmo_b, nmo_b, nmo_b) a_aa, a_ab, a_bb = a b_aa, b_ab, b_bb = b a_aa += numpy.einsum('iabj->iajb', eri_aa[:nocc_a, nocc_a:, nocc_a:, :nocc_a]) a_aa -= numpy.einsum('ijba->iajb', eri_aa[:nocc_a, :nocc_a, nocc_a:, nocc_a:]) * hyb b_aa += numpy.einsum('iajb->iajb', eri_aa[:nocc_a, nocc_a:, :nocc_a, nocc_a:]) b_aa -= numpy.einsum('jaib->iajb', eri_aa[:nocc_a, nocc_a:, :nocc_a, nocc_a:]) * hyb a_bb += numpy.einsum('iabj->iajb', eri_bb[:nocc_b, nocc_b:, nocc_b:, :nocc_b]) a_bb -= numpy.einsum('ijba->iajb', eri_bb[:nocc_b, :nocc_b, nocc_b:, nocc_b:]) * hyb b_bb += numpy.einsum('iajb->iajb', eri_bb[:nocc_b, nocc_b:, :nocc_b, nocc_b:]) b_bb -= numpy.einsum('jaib->iajb', eri_bb[:nocc_b, nocc_b:, :nocc_b, nocc_b:]) * hyb a_ab += numpy.einsum('iabj->iajb', eri_ab[:nocc_a, nocc_a:, nocc_b:, :nocc_b]) b_ab += numpy.einsum('iajb->iajb', eri_ab[:nocc_a, nocc_a:, :nocc_b, nocc_b:]) if getattr(mf, 'xc', None) and getattr(mf, '_numint', None): from pyscf.dft import rks from pyscf.dft import numint ni = mf._numint ni.libxc.test_deriv_order(mf.xc, 2, raise_error=True) if getattr(mf, 'nlc', '') != '': logger.warn( mf, 'NLC functional found in DFT object. Its second ' 'deriviative is not available. Its contribution is ' 'not included in the response function.') omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin) add_hf_(a, b, hyb) xctype = ni._xc_type(mf.xc) dm0 = mf.make_rdm1(mo_coeff, mo_occ) make_rho = ni._gen_rho_evaluator(mol, dm0, hermi=1)[0] mem_now = lib.current_memory()[0] max_memory = max(2000, mf.max_memory * .8 - mem_now) if xctype == 'LDA': ao_deriv = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho0a = make_rho(0, ao, mask, 'LDA') rho0b = make_rho(1, ao, mask, 'LDA') fxc = ni.eval_xc(mf.xc, (rho0a, rho0b), 1, deriv=2)[2] u_u, u_d, d_d = fxc[0].T rho_o_a = lib.einsum('rp,pi->ri', ao, orbo_a) rho_v_a = lib.einsum('rp,pi->ri', ao, orbv_a) rho_o_b = lib.einsum('rp,pi->ri', ao, orbo_b) rho_v_b = lib.einsum('rp,pi->ri', ao, orbv_b) rho_ov_a = numpy.einsum('ri,ra->ria', rho_o_a, rho_v_a) rho_ov_b = numpy.einsum('ri,ra->ria', rho_o_b, rho_v_b) w_ov = numpy.einsum('ria,r->ria', rho_ov_a, weight * u_u) iajb = lib.einsum('ria,rjb->iajb', rho_ov_a, w_ov) a_aa += iajb b_aa += iajb w_ov = numpy.einsum('ria,r->ria', rho_ov_b, weight * u_d) iajb = lib.einsum('ria,rjb->iajb', rho_ov_a, w_ov) a_ab += iajb b_ab += iajb w_ov = numpy.einsum('ria,r->ria', rho_ov_b, weight * d_d) iajb = lib.einsum('ria,rjb->iajb', rho_ov_b, w_ov) a_bb += iajb b_bb += iajb elif xctype == 'GGA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, mf.grids, nao, ao_deriv, max_memory): rho0a = make_rho(0, ao, mask, 'GGA') rho0b = make_rho(1, ao, mask, 'GGA') vxc, fxc = ni.eval_xc(mf.xc, (rho0a, rho0b), 1, deriv=2)[1:3] uu, ud, dd = vxc[1].T u_u, u_d, d_d = fxc[0].T u_uu, u_ud, u_dd, d_uu, d_ud, d_dd = fxc[1].T uu_uu, uu_ud, uu_dd, ud_ud, ud_dd, dd_dd = fxc[2].T rho_o_a = lib.einsum('xrp,pi->xri', ao, orbo_a) rho_v_a = lib.einsum('xrp,pi->xri', ao, orbv_a) rho_o_b = lib.einsum('xrp,pi->xri', ao, orbo_b) rho_v_b = lib.einsum('xrp,pi->xri', ao, orbv_b) rho_ov_a = numpy.einsum('xri,ra->xria', rho_o_a, rho_v_a[0]) rho_ov_b = numpy.einsum('xri,ra->xria', rho_o_b, rho_v_b[0]) rho_ov_a[1:4] += numpy.einsum('ri,xra->xria', rho_o_a[0], rho_v_a[1:4]) rho_ov_b[1:4] += numpy.einsum('ri,xra->xria', rho_o_b[0], rho_v_b[1:4]) # sigma1 ~ \nabla(\rho_\alpha+\rho_\beta) dot \nabla(|b><j|) z_{bj} a0a1 = numpy.einsum('xr,xria->ria', rho0a[1:4], rho_ov_a[1:4]) a0b1 = numpy.einsum('xr,xria->ria', rho0a[1:4], rho_ov_b[1:4]) b0a1 = numpy.einsum('xr,xria->ria', rho0b[1:4], rho_ov_a[1:4]) b0b1 = numpy.einsum('xr,xria->ria', rho0b[1:4], rho_ov_b[1:4]) w_ov = numpy.empty_like(rho_ov_a) w_ov[0] = numpy.einsum('r,ria->ria', u_u, rho_ov_a[0]) w_ov[0] += numpy.einsum('r,ria->ria', 2 * u_uu, a0a1) w_ov[0] += numpy.einsum('r,ria->ria', u_ud, b0a1) f_ov_a = numpy.einsum('r,ria->ria', 4 * uu_uu, a0a1) f_ov_b = numpy.einsum('r,ria->ria', 2 * uu_ud, a0a1) f_ov_a += numpy.einsum('r,ria->ria', 2 * uu_ud, b0a1) f_ov_b += numpy.einsum('r,ria->ria', ud_ud, b0a1) f_ov_a += numpy.einsum('r,ria->ria', 2 * u_uu, rho_ov_a[0]) f_ov_b += numpy.einsum('r,ria->ria', u_ud, rho_ov_a[0]) w_ov[1:] = numpy.einsum('ria,xr->xria', f_ov_a, rho0a[1:4]) w_ov[1:] += numpy.einsum('ria,xr->xria', f_ov_b, rho0b[1:4]) w_ov[1:] += numpy.einsum('r,xria->xria', 2 * uu, rho_ov_a[1:4]) w_ov *= weight[:, None, None] iajb = lib.einsum('xria,xrjb->iajb', rho_ov_a, w_ov) a_aa += iajb b_aa += iajb w_ov = numpy.empty_like(rho_ov_b) w_ov[0] = numpy.einsum('r,ria->ria', d_d, rho_ov_b[0]) w_ov[0] += numpy.einsum('r,ria->ria', 2 * d_dd, b0b1) w_ov[0] += numpy.einsum('r,ria->ria', d_ud, a0b1) f_ov_b = numpy.einsum('r,ria->ria', 4 * dd_dd, b0b1) f_ov_a = numpy.einsum('r,ria->ria', 2 * ud_dd, b0b1) f_ov_b += numpy.einsum('r,ria->ria', 2 * ud_dd, a0b1) f_ov_a += numpy.einsum('r,ria->ria', ud_ud, a0b1) f_ov_b += numpy.einsum('r,ria->ria', 2 * d_dd, rho_ov_b[0]) f_ov_a += numpy.einsum('r,ria->ria', d_ud, rho_ov_b[0]) w_ov[1:] = numpy.einsum('ria,xr->xria', f_ov_a, rho0a[1:4]) w_ov[1:] += numpy.einsum('ria,xr->xria', f_ov_b, rho0b[1:4]) w_ov[1:] += numpy.einsum('r,xria->xria', 2 * dd, rho_ov_b[1:4]) w_ov *= weight[:, None, None] iajb = lib.einsum('xria,xrjb->iajb', rho_ov_b, w_ov) a_bb += iajb b_bb += iajb w_ov = numpy.empty_like(rho_ov_b) w_ov[0] = numpy.einsum('r,ria->ria', u_d, rho_ov_b[0]) w_ov[0] += numpy.einsum('r,ria->ria', 2 * u_dd, b0b1) w_ov[0] += numpy.einsum('r,ria->ria', u_ud, a0b1) f_ov_a = numpy.einsum('r,ria->ria', 4 * uu_dd, b0b1) f_ov_b = numpy.einsum('r,ria->ria', 2 * ud_dd, b0b1) f_ov_a += numpy.einsum('r,ria->ria', 2 * uu_ud, a0b1) f_ov_b += numpy.einsum('r,ria->ria', ud_ud, a0b1) f_ov_a += numpy.einsum('r,ria->ria', 2 * d_uu, rho_ov_b[0]) f_ov_b += numpy.einsum('r,ria->ria', d_ud, rho_ov_b[0]) w_ov[1:] = numpy.einsum('ria,xr->xria', f_ov_a, rho0a[1:4]) w_ov[1:] += numpy.einsum('ria,xr->xria', f_ov_b, rho0b[1:4]) w_ov[1:] += numpy.einsum('r,xria->xria', ud, rho_ov_b[1:4]) w_ov *= weight[:, None, None] iajb = lib.einsum('xria,xrjb->iajb', rho_ov_a, w_ov) a_ab += iajb b_ab += iajb elif xctype == 'NLC': raise NotImplementedError('NLC') elif xctype == 'MGGA': raise NotImplementedError('meta-GGA') else: add_hf_(a, b) return a, b
def update_lambda(mycc, t1, t2, l1, l2, eris, imds): time0 = time.clock(), time.time() log = logger.Logger(mycc.stdout, mycc.verbose) t1a, t1b = t1 t2aa, t2ab, t2bb = t2 l1a, l1b = l1 l2aa, l2ab, l2bb = l2 nocca, nvira = t1a.shape noccb, nvirb = t1b.shape u1a = numpy.zeros_like(l1a) u1b = numpy.zeros_like(l1b) u2aa = numpy.zeros_like(l2aa) u2ab = numpy.zeros_like(l2ab) u2bb = numpy.zeros_like(l2bb) mo_ea_o = eris.mo_energy[0][:nocca] mo_ea_v = eris.mo_energy[0][nocca:] + mycc.level_shift mo_eb_o = eris.mo_energy[1][:noccb] mo_eb_v = eris.mo_energy[1][noccb:] + mycc.level_shift fova = eris.focka[:nocca,nocca:] fovb = eris.fockb[:noccb,noccb:] v1a = imds.v1a - numpy.diag(mo_ea_v) v1b = imds.v1b - numpy.diag(mo_eb_v) v2a = imds.v2a - numpy.diag(mo_ea_o) v2b = imds.v2b - numpy.diag(mo_eb_o) mvv = einsum('klca,klcb->ba', l2aa, t2aa) * .5 mvv+= einsum('lKaC,lKbC->ba', l2ab, t2ab) mVV = einsum('klca,klcb->ba', l2bb, t2bb) * .5 mVV+= einsum('kLcA,kLcB->BA', l2ab, t2ab) moo = einsum('kicd,kjcd->ij', l2aa, t2aa) * .5 moo+= einsum('iKdC,jKdC->ij', l2ab, t2ab) mOO = einsum('kicd,kjcd->ij', l2bb, t2bb) * .5 mOO+= einsum('kIcD,kJcD->IJ', l2ab, t2ab) #m3 = lib.einsum('ijcd,cdab->ijab', l2, eris.vvvv) * .5 m3aa, m3ab, m3bb = mycc._add_vvvv(None, (l2aa.conj(),l2ab.conj(),l2bb.conj()), eris) m3aa = m3aa.conj() m3ab = m3ab.conj() m3bb = m3bb.conj() m3aa += lib.einsum('klab,ikjl->ijab', l2aa, numpy.asarray(imds.woooo)) m3bb += lib.einsum('klab,ikjl->ijab', l2bb, numpy.asarray(imds.wOOOO)) m3ab += lib.einsum('kLaB,ikJL->iJaB', l2ab, numpy.asarray(imds.wooOO)) ovov = numpy.asarray(eris.ovov) ovov = ovov - ovov.transpose(0,3,2,1) OVOV = numpy.asarray(eris.OVOV) OVOV = OVOV - OVOV.transpose(0,3,2,1) ovOV = numpy.asarray(eris.ovOV) mvv1 = einsum('jc,jb->bc', l1a, t1a) + mvv mVV1 = einsum('jc,jb->bc', l1b, t1b) + mVV moo1 = einsum('ic,kc->ik', l1a, t1a) + moo mOO1 = einsum('ic,kc->ik', l1b, t1b) + mOO if nvira > 0 and nocca > 0: ovvv = numpy.asarray(eris.get_ovvv()) ovvv = ovvv - ovvv.transpose(0,3,2,1) tmp = lib.einsum('ijcd,kd->ijck', l2aa, t1a) m3aa -= lib.einsum('kbca,ijck->ijab', ovvv, tmp) tmp = einsum('ic,jbca->jiba', l1a, ovvv) tmp+= einsum('kiab,jk->ijab', l2aa, v2a) tmp-= einsum('ik,kajb->ijab', moo1, ovov) u2aa += tmp - tmp.transpose(1,0,2,3) u1a += numpy.einsum('iacb,bc->ia', ovvv, mvv1) ovvv = tmp = None if nvirb > 0 and noccb > 0: OVVV = numpy.asarray(eris.get_OVVV()) OVVV = OVVV - OVVV.transpose(0,3,2,1) tmp = lib.einsum('ijcd,kd->ijck', l2bb, t1b) m3bb -= lib.einsum('kbca,ijck->ijab', OVVV, tmp) tmp = einsum('ic,jbca->jiba', l1b, OVVV) tmp+= einsum('kiab,jk->ijab', l2bb, v2b) tmp-= einsum('ik,kajb->ijab', mOO1, OVOV) u2bb += tmp - tmp.transpose(1,0,2,3) u1b += numpy.einsum('iaCB,BC->ia', OVVV, mVV1) OVVV = tmp = None if nvirb > 0 and nocca > 0: OVvv = numpy.asarray(eris.get_OVvv()) tmp = lib.einsum('iJcD,KD->iJcK', l2ab, t1b) m3ab -= lib.einsum('KBca,iJcK->iJaB', OVvv, tmp) tmp = einsum('ic,JAcb->JibA', l1a, OVvv) tmp-= einsum('kIaB,jk->IjaB', l2ab, v2a) tmp-= einsum('IK,jaKB->IjaB', mOO1, ovOV) u2ab += tmp.transpose(1,0,2,3) u1b += numpy.einsum('iacb,bc->ia', OVvv, mvv1) OVvv = tmp = None if nvira > 0 and noccb > 0: ovVV = numpy.asarray(eris.get_ovVV()) tmp = lib.einsum('iJdC,kd->iJCk', l2ab, t1a) m3ab -= lib.einsum('kaCB,iJCk->iJaB', ovVV, tmp) tmp = einsum('IC,jbCA->jIbA', l1b, ovVV) tmp-= einsum('iKaB,JK->iJaB', l2ab, v2b) tmp-= einsum('ik,kaJB->iJaB', moo1, ovOV) u2ab += tmp u1a += numpy.einsum('iaCB,BC->ia', ovVV, mVV1) ovVV = tmp = None tauaa, tauab, taubb = uccsd.make_tau(t2, t1, t1) tmp = lib.einsum('ijcd,klcd->ijkl', l2aa, tauaa) ovov = numpy.asarray(eris.ovov) ovov = ovov - ovov.transpose(0,3,2,1) m3aa += lib.einsum('kalb,ijkl->ijab', ovov, tmp) * .25 tmp = lib.einsum('ijcd,klcd->ijkl', l2bb, taubb) OVOV = numpy.asarray(eris.OVOV) OVOV = OVOV - OVOV.transpose(0,3,2,1) m3bb += lib.einsum('kalb,ijkl->ijab', OVOV, tmp) * .25 tmp = lib.einsum('iJcD,kLcD->iJkL', l2ab, tauab) ovOV = numpy.asarray(eris.ovOV) m3ab += lib.einsum('kaLB,iJkL->iJaB', ovOV, tmp) * .5 tmp = lib.einsum('iJdC,lKdC->iJKl', l2ab, tauab) m3ab += lib.einsum('laKB,iJKl->iJaB', ovOV, tmp) * .5 u1a += numpy.einsum('ijab,jb->ia', m3aa, t1a) u1a += numpy.einsum('iJaB,JB->ia', m3ab, t1b) u1b += numpy.einsum('IJAB,JB->IA', m3bb, t1b) u1b += numpy.einsum('jIbA,jb->IA', m3ab, t1a) u2aa += m3aa u2bb += m3bb u2ab += m3ab u2aa += ovov.transpose(0,2,1,3) u2bb += OVOV.transpose(0,2,1,3) u2ab += ovOV.transpose(0,2,1,3) fov1 = fova + numpy.einsum('kcjb,kc->jb', ovov, t1a) fov1+= numpy.einsum('jbKC,KC->jb', ovOV, t1b) tmp = numpy.einsum('ia,jb->ijab', l1a, fov1) tmp+= einsum('kica,jbck->ijab', l2aa, imds.wovvo) tmp+= einsum('iKaC,jbCK->ijab', l2ab, imds.wovVO) tmp = tmp - tmp.transpose(1,0,2,3) u2aa += tmp - tmp.transpose(0,1,3,2) fov1 = fovb + numpy.einsum('kcjb,kc->jb', OVOV, t1b) fov1+= numpy.einsum('kcJB,kc->JB', ovOV, t1a) tmp = numpy.einsum('ia,jb->ijab', l1b, fov1) tmp+= einsum('kica,jbck->ijab', l2bb, imds.wOVVO) tmp+= einsum('kIcA,JBck->IJAB', l2ab, imds.wOVvo) tmp = tmp - tmp.transpose(1,0,2,3) u2bb += tmp - tmp.transpose(0,1,3,2) fov1 = fovb + numpy.einsum('kcjb,kc->jb', OVOV, t1b) fov1+= numpy.einsum('kcJB,kc->JB', ovOV, t1a) u2ab += numpy.einsum('ia,JB->iJaB', l1a, fov1) u2ab += einsum('iKaC,JBCK->iJaB', l2ab, imds.wOVVO) u2ab += einsum('kica,JBck->iJaB', l2aa, imds.wOVvo) u2ab += einsum('kIaC,jBCk->jIaB', l2ab, imds.woVVo) u2ab += einsum('iKcA,JbcK->iJbA', l2ab, imds.wOvvO) fov1 = fova + numpy.einsum('kcjb,kc->jb', ovov, t1a) fov1+= numpy.einsum('jbKC,KC->jb', ovOV, t1b) u2ab += numpy.einsum('ia,jb->jiba', l1b, fov1) u2ab += einsum('kIcA,jbck->jIbA', l2ab, imds.wovvo) u2ab += einsum('KICA,jbCK->jIbA', l2bb, imds.wovVO) ovoo = numpy.asarray(eris.ovoo) ovoo = ovoo - ovoo.transpose(2,1,0,3) OVOO = numpy.asarray(eris.OVOO) OVOO = OVOO - OVOO.transpose(2,1,0,3) OVoo = numpy.asarray(eris.OVoo) ovOO = numpy.asarray(eris.ovOO) tmp = einsum('ka,jbik->ijab', l1a, ovoo) tmp+= einsum('ijca,cb->ijab', l2aa, v1a) tmp+= einsum('ca,icjb->ijab', mvv1, ovov) u2aa -= tmp - tmp.transpose(0,1,3,2) tmp = einsum('ka,jbik->ijab', l1b, OVOO) tmp+= einsum('ijca,cb->ijab', l2bb, v1b) tmp+= einsum('ca,icjb->ijab', mVV1, OVOV) u2bb -= tmp - tmp.transpose(0,1,3,2) u2ab -= einsum('ka,JBik->iJaB', l1a, OVoo) u2ab += einsum('iJaC,CB->iJaB', l2ab, v1b) u2ab -= einsum('ca,icJB->iJaB', mvv1, ovOV) u2ab -= einsum('KA,ibJK->iJbA', l1b, ovOO) u2ab += einsum('iJcA,cb->iJbA', l2ab, v1a) u2ab -= einsum('CA,ibJC->iJbA', mVV1, ovOV) u1a += fova u1b += fovb u1a += einsum('ib,ba->ia', l1a, v1a) u1a -= einsum('ja,ij->ia', l1a, v2a) u1b += einsum('ib,ba->ia', l1b, v1b) u1b -= einsum('ja,ij->ia', l1b, v2b) u1a += numpy.einsum('jb,iabj->ia', l1a, eris.ovvo) u1a -= numpy.einsum('jb,ijba->ia', l1a, eris.oovv) u1a += numpy.einsum('JB,iaBJ->ia', l1b, eris.ovVO) u1b += numpy.einsum('jb,iabj->ia', l1b, eris.OVVO) u1b -= numpy.einsum('jb,ijba->ia', l1b, eris.OOVV) u1b += numpy.einsum('jb,iabj->ia', l1a, eris.OVvo) u1a -= einsum('kjca,ijck->ia', l2aa, imds.woovo) u1a -= einsum('jKaC,ijCK->ia', l2ab, imds.wooVO) u1b -= einsum('kjca,ijck->ia', l2bb, imds.wOOVO) u1b -= einsum('kJcA,IJck->IA', l2ab, imds.wOOvo) u1a -= einsum('ikbc,back->ia', l2aa, imds.wvvvo) u1a -= einsum('iKbC,baCK->ia', l2ab, imds.wvvVO) u1b -= einsum('IKBC,BACK->IA', l2bb, imds.wVVVO) u1b -= einsum('kIcB,BAck->IA', l2ab, imds.wVVvo) u1a += numpy.einsum('jiba,bj->ia', l2aa, imds.w3a) u1a += numpy.einsum('iJaB,BJ->ia', l2ab, imds.w3b) u1b += numpy.einsum('JIBA,BJ->IA', l2bb, imds.w3b) u1b += numpy.einsum('jIbA,bj->IA', l2ab, imds.w3a) tmpa = t1a + numpy.einsum('kc,kjcb->jb', l1a, t2aa) tmpa += numpy.einsum('KC,jKbC->jb', l1b, t2ab) tmpa -= einsum('bd,jd->jb', mvv1, t1a) tmpa -= einsum('lj,lb->jb', moo, t1a) tmpb = t1b + numpy.einsum('kc,kjcb->jb', l1b, t2bb) tmpb += numpy.einsum('kc,kJcB->JB', l1a, t2ab) tmpb -= einsum('bd,jd->jb', mVV1, t1b) tmpb -= einsum('lj,lb->jb', mOO, t1b) u1a += numpy.einsum('jbia,jb->ia', ovov, tmpa) u1a += numpy.einsum('iaJB,JB->ia', ovOV, tmpb) u1b += numpy.einsum('jbia,jb->ia', OVOV, tmpb) u1b += numpy.einsum('jbIA,jb->IA', ovOV, tmpa) u1a -= numpy.einsum('iajk,kj->ia', ovoo, moo1) u1a -= numpy.einsum('iaJK,KJ->ia', ovOO, mOO1) u1b -= numpy.einsum('iajk,kj->ia', OVOO, mOO1) u1b -= numpy.einsum('IAjk,kj->IA', OVoo, moo1) tmp = fova - numpy.einsum('kbja,jb->ka', ovov, t1a) tmp += numpy.einsum('kaJB,JB->ka', ovOV, t1b) u1a -= lib.einsum('ik,ka->ia', moo, tmp) u1a -= lib.einsum('ca,ic->ia', mvv, tmp) tmp = fovb - numpy.einsum('kbja,jb->ka', OVOV, t1b) tmp += numpy.einsum('jbKA,jb->KA', ovOV, t1a) u1b -= lib.einsum('ik,ka->ia', mOO, tmp) u1b -= lib.einsum('ca,ic->ia', mVV, tmp) eia = lib.direct_sum('i-j->ij', mo_ea_o, mo_ea_v) eIA = lib.direct_sum('i-j->ij', mo_eb_o, mo_eb_v) u1a /= eia u1b /= eIA u2aa /= lib.direct_sum('ia+jb->ijab', eia, eia) u2ab /= lib.direct_sum('ia+jb->ijab', eia, eIA) u2bb /= lib.direct_sum('ia+jb->ijab', eIA, eIA) time0 = log.timer_debug1('update l1 l2', *time0) return (u1a,u1b), (u2aa,u2ab,u2bb)
mf = x2c.RHF(mol).density_fit() dm = mf.get_init_guess() + 0.0j mf.with_df.auxbasis = 'def2-svp-jkfit' mf.kernel(dm) ncore = 2 pt = MP2(mf) pt.frozen = ncore pt.kernel() rdm1 = pt.make_rdm1() rdm2 = pt.make_rdm2() n2c = mol.nao_2c() dferi = mf.with_df._cderi.reshape(-1,n2c,n2c) eri_mo = lib.einsum('rj,Qrs->Qjs', mf.mo_coeff.conj(), dferi) eri_mo = lib.einsum('sb,Qjs->Qjb', mf.mo_coeff, eri_mo) eri_mo = lib.einsum('Qia,Qjb->iajb', eri_mo, eri_mo) hcore = mf.get_hcore() h1 = reduce(numpy.dot, (mf.mo_coeff.T.conj(), hcore, mf.mo_coeff)) e = numpy.einsum('ij,ji', h1, rdm1) e += numpy.einsum('ijkl,ijkl', eri_mo, rdm2)*0.5 e += mol.energy_nuc() print("!*** E(X2CMP2) with RDM: %s" % e) mo_coeff, mo_energy, mo_occ = pt.fno() pt = MP2(mf, mo_coeff=mo_coeff, mo_occ=mo_occ) pt.frozen = ncore pt.kernel(mo_energy=mo_energy)
mol = gto.Mole() mol.verbose = 0 mol.atom = [ [8 , (0. , 0. , 0.)], [1 , (0. , -0.757 , 0.587)], [1 , (0. , 0.757 , 0.587)]] mol.basis = '631g' mol.build() mf = scf.RHF(mol) mf.conv_tol = 1e-16 mf.scf() mo_coeff = mf.mo_coeff + np.sin(mf.mo_coeff) * .01j nao = mo_coeff.shape[0] eri = ao2mo.restore(1, mf._eri, nao) eri0 = lib.einsum('pqrs,pi,qj,rk,sl->ijkl', eri, mo_coeff.conj(), mo_coeff, mo_coeff.conj(), mo_coeff) nocc, nvir = 5, nao-5 eris = _ChemistsERIs(mol) eris.oooo = eri0[:nocc,:nocc,:nocc,:nocc].copy() eris.ovoo = eri0[:nocc,nocc:,:nocc,:nocc].copy() eris.oovv = eri0[:nocc,:nocc,nocc:,nocc:].copy() eris.ovvo = eri0[:nocc,nocc:,nocc:,:nocc].copy() eris.ovov = eri0[:nocc,nocc:,:nocc,nocc:].copy() eris.ovvv = eri0[:nocc,nocc:,nocc:,nocc:].copy() eris.vvvv = eri0[nocc:,nocc:,nocc:,nocc:].copy() eris.fock = np.diag(mf.mo_energy) eris.mo_energy = mf.mo_energy np.random.seed(1) t1 = np.random.random((nocc,nvir)) + np.random.random((nocc,nvir))*.1j - .5
def contract(myci, civec, eris): time0 = time.clock(), time.time() log = logger.Logger(myci.stdout, myci.verbose) nocc = myci.nocc nmo = myci.nmo nvir = nmo - nocc nov = nocc * nvir noo = nocc**2 c0, c1, c2 = myci.cisdvec_to_amplitudes(civec, nmo, nocc) t2 = myci._add_vvvv(c2, eris, t2sym='jiba') t2 *= .5 # due to t2+t2.transpose(1,0,3,2) in the end time1 = log.timer_debug1('vvvv', *time0) foo = eris.fock[:nocc, :nocc].copy() fov = eris.fock[:nocc, nocc:].copy() fvv = eris.fock[nocc:, nocc:].copy() t1 = fov * c0 t1 += numpy.einsum('ib,ab->ia', c1, fvv) t1 -= numpy.einsum('ja,ji->ia', c1, foo) t2 += lib.einsum('kilj,klab->ijab', _cp(eris.oooo) * .5, c2) t2 += lib.einsum('ijac,bc->ijab', c2, fvv) t2 -= lib.einsum('kj,kiba->jiba', foo, c2) t2 += numpy.einsum('ia,jb->ijab', c1, fov) unit = nocc * nvir**2 + nocc**2 * nvir * 3 + 1 max_memory = max(0, myci.max_memory - lib.current_memory()[0]) blksize = min(nvir, max(BLKMIN, int(max_memory * .9e6 / 8 / unit))) log.debug1('max_memory %d MB, nocc,nvir = %d,%d blksize = %d', max_memory, nocc, nvir, blksize) nvir_pair = nvir * (nvir + 1) // 2 for p0, p1 in lib.prange(0, nvir, blksize): eris_oVoV = _cp(_cp(eris.oovv[:, :, p0:p1]).transpose(0, 2, 1, 3)) tmp = lib.einsum('kbjc,ikca->jiba', eris_oVoV, c2) t2[:, :, p0:p1] -= tmp * .5 t2[:, :, p0:p1] -= tmp.transpose(1, 0, 2, 3) tmp = None eris_ovvo = _cp(eris.ovvo[:, p0:p1]) t2[:, :, p0:p1] += eris_ovvo.transpose(0, 3, 1, 2) * (c0 * .5) t1 += numpy.einsum('ia,iabj->jb', c1[:, p0:p1], eris_ovvo) * 2 t1[:, p0:p1] -= numpy.einsum('ib,iajb->ja', c1, eris_oVoV) ovov = -.5 * eris_oVoV ovov += eris_ovvo.transpose(3, 1, 0, 2) eris_oVoV = eris_oovv = None theta = c2[:, :, p0:p1].transpose(2, 0, 1, 3) * 2 theta -= c2[:, :, p0:p1].transpose(2, 1, 0, 3) for j in range(nocc): t2[:, j] += lib.einsum('ckb,ckia->iab', ovov[j], theta) tmp = ovov = None t1 += numpy.einsum('aijb,ia->jb', theta, fov[:, p0:p1]) eris_ovoo = _cp(eris.ovoo[:, p0:p1]) t1 -= lib.einsum('bjka,jbki->ia', theta, eris_ovoo) t2[:, :, p0:p1] -= lib.einsum('jbik,ka->jiba', eris_ovoo.conj(), c1) eris_vooo = None eris_ovvv = eris.get_ovvv(slice(None), slice(p0, p1)).conj() t1 += lib.einsum('cjib,jcba->ia', theta, eris_ovvv) t2[:, :, p0:p1] += lib.einsum('iacb,jc->ijab', eris_ovvv, c1) tmp = eris_ovvv = None #:t2 + t2.transpose(1,0,3,2) for i in range(nocc): if i > 0: t2[i, :i] += t2[:i, i].transpose(0, 2, 1) t2[:i, i] = t2[i, :i].transpose(0, 2, 1) t2[i, i] = t2[i, i] + t2[i, i].T t0 = numpy.einsum('ia,ia->', fov, c1) * 2 t0 += numpy.einsum('iabj,ijab->', eris.ovvo, c2) * 2 t0 -= numpy.einsum('iabj,jiab->', eris.ovvo, c2) cinew = numpy.hstack((t0, t1.ravel(), t2.ravel())) return cinew
def update_amps(cc, t1, t2, eris): # Ref: Hirata et al., J. Chem. Phys. 120, 2581 (2004) Eqs.(35)-(36) assert(isinstance(eris, ccsd._ChemistsERIs)) nocc, nvir = t1.shape fock = eris.fock mo_e_o = eris.mo_energy[:nocc] mo_e_v = eris.mo_energy[nocc:] + cc.level_shift fov = fock[:nocc,nocc:].copy() foo = fock[:nocc,:nocc].copy() fvv = fock[nocc:,nocc:].copy() Foo = imd.cc_Foo(t1,t2,eris) Fvv = imd.cc_Fvv(t1,t2,eris) Fov = imd.cc_Fov(t1,t2,eris) # Move energy terms to the other side Foo[np.diag_indices(nocc)] -= mo_e_o Fvv[np.diag_indices(nvir)] -= mo_e_v # T1 equation t1new =-2*np.einsum('kc,ka,ic->ia', fov, t1, t1) t1new += np.einsum('ac,ic->ia', Fvv, t1) t1new += -np.einsum('ki,ka->ia', Foo, t1) t1new += 2*np.einsum('kc,kica->ia', Fov, t2) t1new += -np.einsum('kc,ikca->ia', Fov, t2) t1new += np.einsum('kc,ic,ka->ia', Fov, t1, t1) t1new += fov.conj() t1new += 2*np.einsum('kcai,kc->ia', eris.ovvo, t1) t1new += -np.einsum('kiac,kc->ia', eris.oovv, t1) eris_ovvv = np.asarray(eris.get_ovvv()) t1new += 2*lib.einsum('kdac,ikcd->ia', eris_ovvv, t2) t1new += -lib.einsum('kcad,ikcd->ia', eris_ovvv, t2) t1new += 2*lib.einsum('kdac,kd,ic->ia', eris_ovvv, t1, t1) t1new += -lib.einsum('kcad,kd,ic->ia', eris_ovvv, t1, t1) eris_ovoo = np.asarray(eris.ovoo, order='C') t1new +=-2*lib.einsum('lcki,klac->ia', eris_ovoo, t2) t1new += lib.einsum('kcli,klac->ia', eris_ovoo, t2) t1new +=-2*lib.einsum('lcki,lc,ka->ia', eris_ovoo, t1, t1) t1new += lib.einsum('kcli,lc,ka->ia', eris_ovoo, t1, t1) # T2 equation tmp2 = lib.einsum('kibc,ka->abic', eris.oovv, -t1) tmp2 += np.asarray(eris_ovvv).conj().transpose(1,3,0,2) tmp = lib.einsum('abic,jc->ijab', tmp2, t1) t2new = tmp + tmp.transpose(1,0,3,2) tmp2 = lib.einsum('kcai,jc->akij', eris.ovvo, t1) tmp2 += eris_ovoo.transpose(1,3,0,2).conj() tmp = lib.einsum('akij,kb->ijab', tmp2, t1) t2new -= tmp + tmp.transpose(1,0,3,2) t2new += np.asarray(eris.ovov).conj().transpose(0,2,1,3) if cc.cc2: Woooo2 = np.asarray(eris.oooo).transpose(0,2,1,3).copy() Woooo2 += lib.einsum('lcki,jc->klij', eris_ovoo, t1) Woooo2 += lib.einsum('kclj,ic->klij', eris_ovoo, t1) Woooo2 += lib.einsum('kcld,ic,jd->klij', eris.ovov, t1, t1) t2new += lib.einsum('klij,ka,lb->ijab', Woooo2, t1, t1) Wvvvv = lib.einsum('kcbd,ka->abcd', eris_ovvv, -t1) Wvvvv = Wvvvv + Wvvvv.transpose(1,0,3,2) Wvvvv += np.asarray(eris.vvvv).transpose(0,2,1,3) t2new += lib.einsum('abcd,ic,jd->ijab', Wvvvv, t1, t1) Lvv2 = fvv - np.einsum('kc,ka->ac', fov, t1) Lvv2 -= np.diag(np.diag(fvv)) tmp = lib.einsum('ac,ijcb->ijab', Lvv2, t2) t2new += (tmp + tmp.transpose(1,0,3,2)) Loo2 = foo + np.einsum('kc,ic->ki', fov, t1) Loo2 -= np.diag(np.diag(foo)) tmp = lib.einsum('ki,kjab->ijab', Loo2, t2) t2new -= (tmp + tmp.transpose(1,0,3,2)) else: Loo = imd.Loo(t1, t2, eris) Lvv = imd.Lvv(t1, t2, eris) Loo[np.diag_indices(nocc)] -= mo_e_o Lvv[np.diag_indices(nvir)] -= mo_e_v Woooo = imd.cc_Woooo(t1, t2, eris) Wvoov = imd.cc_Wvoov(t1, t2, eris) Wvovo = imd.cc_Wvovo(t1, t2, eris) Wvvvv = imd.cc_Wvvvv(t1, t2, eris) tau = t2 + np.einsum('ia,jb->ijab', t1, t1) t2new += lib.einsum('klij,klab->ijab', Woooo, tau) t2new += lib.einsum('abcd,ijcd->ijab', Wvvvv, tau) tmp = lib.einsum('ac,ijcb->ijab', Lvv, t2) t2new += (tmp + tmp.transpose(1,0,3,2)) tmp = lib.einsum('ki,kjab->ijab', Loo, t2) t2new -= (tmp + tmp.transpose(1,0,3,2)) tmp = 2*lib.einsum('akic,kjcb->ijab', Wvoov, t2) tmp -= lib.einsum('akci,kjcb->ijab', Wvovo, t2) t2new += (tmp + tmp.transpose(1,0,3,2)) tmp = lib.einsum('akic,kjbc->ijab', Wvoov, t2) t2new -= (tmp + tmp.transpose(1,0,3,2)) tmp = lib.einsum('bkci,kjac->ijab', Wvovo, t2) t2new -= (tmp + tmp.transpose(1,0,3,2)) eia = mo_e_o[:,None] - mo_e_v eijab = lib.direct_sum('ia,jb->ijab',eia,eia) t1new /= eia t2new /= eijab return t1new, t2new
def _gamma2_outcore(myci, civec, nmo, nocc, h5fobj, compress_vvvv=False): log = logger.Logger(myci.stdout, myci.verbose) nocc = myci.nocc nmo = myci.nmo nvir = nmo - nocc nvir_pair = nvir * (nvir + 1) // 2 c0, c1, c2 = myci.cisdvec_to_amplitudes(civec, nmo, nocc) h5fobj['dovov'] = (2 * c0 * c2.conj().transpose(0, 2, 1, 3) - c0 * c2.conj().transpose(1, 2, 0, 3)) doooo = lib.einsum('ijab,klab->ijkl', c2.conj(), c2) h5fobj['doooo'] = doooo.transpose(0, 2, 1, 3) - doooo.transpose(1, 2, 0, 3) * .5 doooo = None dooov = -lib.einsum('ia,klac->klic', c1 * 2, c2.conj()) h5fobj['dooov'] = dooov.transpose(0, 2, 1, 3) * 2 - dooov.transpose( 1, 2, 0, 3) dooov = None #:dvovv = numpy.einsum('ia,ikcd->akcd', c1, c2) * 2 #:dvvvv = lib.einsum('ijab,ijcd->abcd', c2, c2) max_memory = max(0, myci.max_memory - lib.current_memory()[0]) unit = max(nocc**2 * nvir * 2 + nocc * nvir**2 * 3 + 1, nvir**3 * 2 + nocc * nvir**2 + 1) blksize = min(nvir, max(BLKMIN, int(max_memory * .9e6 / 8 / unit))) iobuflen = int(256e6 / 8 / blksize) log.debug1('rdm intermediates: block size = %d, nvir = %d in %d blocks', blksize, nocc, int((nvir + blksize - 1) / blksize)) dtype = numpy.result_type(civec).char dovvv = h5fobj.create_dataset('dovvv', (nocc, nvir, nvir, nvir), dtype, chunks=(nocc, min(nocc, nvir), 1, nvir)) if compress_vvvv: dvvvv = h5fobj.create_dataset('dvvvv', (nvir_pair, nvir_pair), dtype) else: dvvvv = h5fobj.create_dataset('dvvvv', (nvir, nvir, nvir, nvir), dtype) for istep, (p0, p1) in enumerate(lib.prange(0, nvir, blksize)): theta = c2[:, :, p0:p1] - c2[:, :, p0:p1].transpose(1, 0, 2, 3) * .5 gvvvv = lib.einsum('ijab,ijcd->abcd', theta.conj(), c2) if compress_vvvv: # symmetrize dvvvv because it does not affect the results of cisd_grad # dvvvv = (dvvvv+dvvvv.transpose(0,1,3,2)) * .5 # dvvvv = (dvvvv+dvvvv.transpose(1,0,2,3)) * .5 # now dvvvv == dvvvv.transpose(0,1,3,2) == dvvvv.transpose(1,0,3,2) tmp = numpy.empty((nvir, nvir, nvir)) tmpvvvv = numpy.empty((p1 - p0, nvir, nvir_pair)) for i in range(p1 - p0): tmp[:] = gvvvv[i].conj().transpose(1, 0, 2) lib.pack_tril(tmp + tmp.transpose(0, 2, 1), out=tmpvvvv[i]) # tril of (dvvvv[p0:p1,p0:p1]+dvvvv[p0:p1,p0:p1].T) for i in range(p0, p1): for j in range(p0, i): tmpvvvv[i - p0, j] += tmpvvvv[j - p0, i] tmpvvvv[i - p0, i] *= 2 for i in range(p1, nvir): off = i * (i + 1) // 2 dvvvv[off + p0:off + p1] = tmpvvvv[:, i] for i in range(p0, p1): off = i * (i + 1) // 2 if p0 > 0: tmpvvvv[i - p0, :p0] += dvvvv[off:off + p0] dvvvv[off:off + i + 1] = tmpvvvv[i - p0, :i + 1] * .25 tmp = tmpvvvv = None else: for i in range(p0, p1): dvvvv[i] = gvvvv[i - p0].conj().transpose(1, 0, 2) gvovv = numpy.einsum('ia,ikcd->akcd', c1[:, p0:p1].conj() * 2, c2) gvovv = gvovv.conj() dovvv[:, :, p0:p1] = gvovv.transpose(1, 3, 0, 2) * 2 - gvovv.transpose( 1, 2, 0, 3) theta = c2 * 2 - c2.transpose(1, 0, 2, 3) doovv = numpy.einsum('ia,kc->ikca', c1.conj(), -c1) doovv -= lib.einsum('kjcb,kica->jiab', c2.conj(), theta) doovv -= lib.einsum('ikcb,jkca->ijab', c2.conj(), theta) h5fobj['doovv'] = doovv doovv = None dovvo = lib.einsum('ikac,jkbc->iabj', theta.conj(), theta) dovvo += numpy.einsum('ia,kc->iack', c1.conj(), c1) * 2 h5fobj['dovvo'] = dovvo theta = dovvo = None dvvov = None return (h5fobj['dovov'], h5fobj['dvvvv'], h5fobj['doooo'], h5fobj['doovv'], h5fobj['dovvo'], dvvov, h5fobj['dovvv'], h5fobj['dooov'])
def update_lambda(mycc, t1, t2, l1, l2, eris=None, imds=None): if imds is None: imds = make_intermediates(mycc, t1, t2, eris) time0 = logger.process_clock(), logger.perf_counter() log = logger.Logger(mycc.stdout, mycc.verbose) nocc, nvir = t1.shape fov = eris.fock[:nocc, nocc:] mo_e_o = eris.mo_energy[:nocc] mo_e_v = eris.mo_energy[nocc:] + mycc.level_shift theta = t2 * 2 - t2.transpose(0, 1, 3, 2) mba = lib.einsum('klca,klcb->ba', l2, theta) mij = lib.einsum('ikcd,jkcd->ij', l2, theta) theta = None mba1 = numpy.einsum('jc,jb->bc', l1, t1) + mba mij1 = numpy.einsum('kb,jb->kj', l1, t1) + mij mia1 = t1 + numpy.einsum('kc,jkbc->jb', l1, t2) * 2 mia1 -= numpy.einsum('kc,jkcb->jb', l1, t2) mia1 -= reduce(numpy.dot, (t1, l1.T, t1)) mia1 -= numpy.einsum('bd,jd->jb', mba, t1) mia1 -= numpy.einsum('lj,lb->jb', mij, t1) l2new = mycc._add_vvvv(None, l2, eris, with_ovvv=False, t2sym='jiba') l1new = numpy.einsum('ijab,jb->ia', l2new, t1) * 2 l1new -= numpy.einsum('jiab,jb->ia', l2new, t1) l2new *= .5 # *.5 because of l2+l2.transpose(1,0,3,2) in the end tmp = None w1 = imds.w1 - numpy.diag(mo_e_v) w2 = imds.w2 - numpy.diag(mo_e_o) l1new += fov l1new += numpy.einsum('ib,ba->ia', l1, w1) l1new -= numpy.einsum('ja,ij->ia', l1, w2) l1new -= numpy.einsum('ik,ka->ia', mij, imds.w4) l1new -= numpy.einsum('ca,ic->ia', mba, imds.w4) l1new += numpy.einsum('ijab,bj->ia', l2, imds.w3) * 2 l1new -= numpy.einsum('ijba,bj->ia', l2, imds.w3) l2new += numpy.einsum('ia,jb->ijab', l1, imds.w4) l2new += lib.einsum('jibc,ca->jiba', l2, w1) l2new -= lib.einsum('jk,kiba->jiba', w2, l2) eris_ovoo = _cp(eris.ovoo) l1new -= numpy.einsum('iajk,kj->ia', eris_ovoo, mij1) * 2 l1new += numpy.einsum('jaik,kj->ia', eris_ovoo, mij1) l2new -= lib.einsum('jbki,ka->jiba', eris_ovoo, l1) eris_ovoo = None tau = _ccsd.make_tau(t2, t1, t1) l2tau = lib.einsum('ijcd,klcd->ijkl', l2, tau) tau = None l2t1 = lib.einsum('jidc,kc->ijkd', l2, t1) max_memory = max(0, mycc.max_memory - lib.current_memory()[0]) unit = nocc * nvir**2 * 5 blksize = min(nocc, max(ccsd.BLKMIN, int(max_memory * .95e6 / 8 / unit))) log.debug1('block size = %d, nocc = %d is divided into %d blocks', blksize, nocc, int((nocc + blksize - 1) / blksize)) l1new -= numpy.einsum('jb,jiab->ia', l1, _cp(eris.oovv)) for p0, p1 in lib.prange(0, nvir, blksize): eris_ovvv = eris.get_ovvv(slice(None), slice(p0, p1)) l1new[:, p0:p1] += numpy.einsum('iabc,bc->ia', eris_ovvv, mba1) * 2 l1new -= numpy.einsum('ibca,bc->ia', eris_ovvv, mba1[p0:p1]) l2new[:, :, p0:p1] += lib.einsum('jbac,ic->jiba', eris_ovvv, l1) m4 = lib.einsum('ijkd,kadb->ijab', l2t1, eris_ovvv) l2new[:, :, p0:p1] -= m4 l1new[:, p0:p1] -= numpy.einsum('ijab,jb->ia', m4, t1) * 2 l1new -= numpy.einsum('ijab,ia->jb', m4, t1[:, p0:p1]) * 2 l1new[:, p0:p1] += numpy.einsum('jiab,jb->ia', m4, t1) l1new += numpy.einsum('jiab,ia->jb', m4, t1[:, p0:p1]) eris_ovvv = m4 = None eris_voov = _cp(eris.ovvo[:, p0:p1].transpose(1, 0, 3, 2)) l1new[:, p0:p1] += numpy.einsum('jb,aijb->ia', l1, eris_voov) * 2 l2new[:, :, p0:p1] += eris_voov.transpose(1, 2, 0, 3) * .5 l2new[:, :, p0:p1] -= lib.einsum('bjic,ca->jiba', eris_voov, mba1) l2new[:, :, p0:p1] -= lib.einsum('bjka,ik->jiba', eris_voov, mij1) l1new[:, p0:p1] += numpy.einsum('aijb,jb->ia', eris_voov, mia1) * 2 l1new -= numpy.einsum('bija,jb->ia', eris_voov, mia1[:, p0:p1]) m4 = lib.einsum('ijkl,aklb->ijab', l2tau, eris_voov) l2new[:, :, p0:p1] += m4 * .5 l1new[:, p0:p1] += numpy.einsum('ijab,jb->ia', m4, t1) * 2 l1new -= numpy.einsum('ijba,jb->ia', m4, t1[:, p0:p1]) saved_wvooo = _cp(imds.wvooo[p0:p1]) l1new -= lib.einsum('ckij,jkca->ia', saved_wvooo, l2[:, :, p0:p1]) saved_wvovv = _cp(imds.wvvov[p0:p1]) # Watch out memory usage here, due to the l2 transpose l1new[:, p0:p1] += lib.einsum('abkc,kibc->ia', saved_wvovv, l2) saved_wvooo = saved_wvovv = None saved_wvOOv = _cp(imds.wvOOv[p0:p1]) tmp_voov = _cp(imds.wVOov[p0:p1]) * 2 tmp_voov += saved_wvOOv tmp = l2.transpose(0, 2, 1, 3) - l2.transpose(0, 3, 1, 2) * .5 l2new[:, :, p0:p1] += lib.einsum('iakc,bjkc->jiba', tmp, tmp_voov) tmp = None tmp = lib.einsum('jkca,bikc->jiba', l2, saved_wvOOv) l2new[:, :, p0:p1] += tmp l2new[:, :, p0:p1] += tmp.transpose(1, 0, 2, 3) * .5 saved_wvOOv = tmp = None saved_woooo = _cp(imds.woooo) m3 = lib.einsum('ijkl,klab->ijab', saved_woooo, l2) l2new += m3 * .5 l1new += numpy.einsum('ijab,jb->ia', m3, t1) * 2 l1new -= numpy.einsum('ijba,jb->ia', m3, t1) saved_woooo = m3 = None #time1 = log.timer_debug1('lambda pass [%d:%d]'%(p0, p1), *time1) eia = lib.direct_sum('i-a->ia', mo_e_o, mo_e_v) l1new /= eia # l2new = l2new + l2new.transpose(1,0,3,2) # l2new /= lib.direct_sum('ia+jb->ijab', eia, eia) # l2new += l2 for i in range(nocc): if i > 0: l2new[i, :i] += l2new[:i, i].transpose(0, 2, 1) l2new[i, :i] /= lib.direct_sum('a,jb->jab', eia[i], eia[:i]) l2new[:i, i] = l2new[i, :i].transpose(0, 2, 1) l2new[i, i] = l2new[i, i] + l2new[i, i].T l2new[i, i] /= lib.direct_sum('a,b->ab', eia[i], eia[i]) time0 = log.timer_debug1('update l1 l2', *time0) return l1new, l2new
def Lci_dot_dgci_dx(Lci, weights, mc, mo_coeff=None, ci=None, atmlst=None, mf_grad=None, eris=None, verbose=None): ''' Modification of pyscf.grad.casscf.kernel to compute instead the CI Lagrange term nuclear gradient (sum_IJ Lci_IJ d2_Ecas/d_lambda d_PIJ) This involves removing all core-core and nuclear-nuclear terms and making the substitution sum_I w_I<L_I|p'q|I> + c.c. -> <0|p'q|0> sum_I w_I<L_I|p'r'sq|I> + c.c. -> <0|p'r'sq|0> The active-core terms (sum_I w_I<L_I|x'iyi|I>, sum_I w_I <L_I|x'iiy|I>, c.c.) must be retained.''' if mo_coeff is None: mo_coeff = mc.mo_coeff if ci is None: ci = mc.ci if mf_grad is None: mf_grad = mc._scf.nuc_grad_method() if mc.frozen is not None: raise NotImplementedError t0 = (logger.process_clock(), logger.perf_counter()) mol = mc.mol ncore = mc.ncore ncas = mc.ncas nocc = ncore + ncas nelecas = mc.nelecas nao, nmo = mo_coeff.shape nao_pair = nao * (nao + 1) // 2 mo_occ = mo_coeff[:, :nocc] mo_core = mo_coeff[:, :ncore] mo_cas = mo_coeff[:, ncore:nocc] # MRH: TDMs + c.c. instead of RDMs; 06/30/2020: new interface in mcscf.addons makes this much more transparent casdm1, casdm2 = mc.fcisolver.trans_rdm12(Lci, ci, ncas, nelecas) casdm1 += casdm1.transpose(1, 0) casdm2 += casdm2.transpose(1, 0, 3, 2) # gfock = Generalized Fock, Adv. Chem. Phys., 69, 63 dm_core = np.dot(mo_core, mo_core.T) * 2 dm_cas = reduce(np.dot, (mo_cas, casdm1, mo_cas.T)) aapa = np.zeros((ncas, ncas, nmo, ncas), dtype=dm_cas.dtype) for i in range(nmo): aapa[:, :, i, :] = eris.ppaa[i][ncore:nocc, :, :].transpose(1, 2, 0) vj, vk = mc._scf.get_jk(mol, (dm_core, dm_cas)) h1 = mc.get_hcore() vhf_c = vj[0] - vk[0] * .5 vhf_a = vj[1] - vk[1] * .5 # MRH: delete h1 + vhf_c from the first line below (core and core-core stuff) # Also extend gfock to span the whole space gfock = np.zeros_like(dm_cas) gfock[:, :nocc] = reduce(np.dot, (mo_coeff.T, vhf_a, mo_occ)) * 2 gfock[:, ncore:nocc] = reduce(np.dot, (mo_coeff.T, h1 + vhf_c, mo_cas, casdm1)) gfock[:, ncore:nocc] += np.einsum('uvpw,vuwt->pt', aapa, casdm2) dme0 = reduce(np.dot, (mo_coeff, (gfock + gfock.T) * .5, mo_coeff.T)) aapa = vj = vk = vhf_c = vhf_a = h1 = gfock = None vj, vk = mf_grad.get_jk(mol, (dm_core, dm_cas)) vhf1c, vhf1a = vj - vk * 0.5 #vhf1c, vhf1a = mf_grad.get_veff(mol, (dm_core, dm_cas)) hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) diag_idx = np.arange(nao) diag_idx = diag_idx * (diag_idx + 1) // 2 + diag_idx casdm2_cc = casdm2 + casdm2.transpose(0, 1, 3, 2) dm2buf = ao2mo._ao2mo.nr_e2(casdm2_cc.reshape(ncas**2, ncas**2), mo_cas.T, (0, nao, 0, nao)).reshape(ncas**2, nao, nao) dm2buf = lib.pack_tril(dm2buf) dm2buf[:, diag_idx] *= .5 dm2buf = dm2buf.reshape(ncas, ncas, nao_pair) casdm2 = casdm2_cc = None if atmlst is None: atmlst = range(mol.natm) aoslices = mol.aoslice_by_atom() de_hcore = np.zeros((len(atmlst), 3)) de_renorm = np.zeros((len(atmlst), 3)) de_eri = np.zeros((len(atmlst), 3)) de = np.zeros((len(atmlst), 3)) max_memory = mc.max_memory - lib.current_memory()[0] blksize = int(max_memory * .9e6 / 8 / (4 * (aoslices[:, 3] - aoslices[:, 2]).max() * nao_pair)) # MRH: 3 components of eri array and 1 density matrix array: FOUR arrays of this size are required! blksize = min(nao, max(2, blksize)) logger.info( mc, 'SA-CASSCF Lci_dot_dgci memory remaining for eri manipulation: {} MB; using blocksize = {}' .format(max_memory, blksize)) t0 = logger.timer(mc, 'SA-CASSCF Lci_dot_dgci 1-electron part', *t0) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) # MRH: dm1 -> dm_cas in the line below de_hcore[k] += np.einsum('xij,ij->x', h1ao, dm_cas) de_renorm[k] -= np.einsum('xij,ij->x', s1[:, p0:p1], dme0[p0:p1]) * 2 q1 = 0 for b0, b1, nf in _shell_prange(mol, 0, mol.nbas, blksize): q0, q1 = q1, q1 + nf dm2_ao = lib.einsum('ijw,pi,qj->pqw', dm2buf, mo_cas[p0:p1], mo_cas[q0:q1]) shls_slice = (shl0, shl1, b0, b1, 0, mol.nbas, 0, mol.nbas) gc.collect() eri1 = mol.intor('int2e_ip1', comp=3, aosym='s2kl', shls_slice=shls_slice).reshape( 3, p1 - p0, nf, nao_pair) de_eri[k] -= np.einsum('xijw,ijw->x', eri1, dm2_ao) * 2 eri1 = dm2_ao = None gc.collect() t0 = logger.timer( mc, 'SA-CASSCF Lci_dot_dgci atom {} ({},{}|{})'.format( ia, p1 - p0, nf, nao_pair), *t0) # MRH: dm1 -> dm_cas in the line below. Also eliminate core-core terms de_eri[k] += np.einsum('xij,ij->x', vhf1c[:, p0:p1], dm_cas[p0:p1]) * 2 de_eri[k] += np.einsum('xij,ij->x', vhf1a[:, p0:p1], dm_core[p0:p1]) * 2 logger.debug(mc, "CI lagrange hcore component:\n{}".format(de_hcore)) logger.debug(mc, "CI lagrange renorm component:\n{}".format(de_renorm)) logger.debug(mc, "CI lagrange eri component:\n{}".format(de_eri)) de = de_hcore + de_renorm + de_eri return de
def make_intermediates(mycc, t1, t2, eris): log = logger.Logger(mycc.stdout, mycc.verbose) nocc, nvir = t1.shape foo = eris.fock[:nocc, :nocc] fov = eris.fock[:nocc, nocc:] #fvo = eris.fock[nocc:,:nocc] fvv = eris.fock[nocc:, nocc:] class _IMDS: pass imds = _IMDS() #TODO: mycc.incore_complete imds.ftmp = lib.H5TmpFile() imds.woooo = imds.ftmp.create_dataset('woooo', (nocc, nocc, nocc, nocc), 'f8') imds.wvooo = imds.ftmp.create_dataset('wvooo', (nvir, nocc, nocc, nocc), 'f8') imds.wVOov = imds.ftmp.create_dataset('wVOov', (nvir, nocc, nocc, nvir), 'f8') imds.wvOOv = imds.ftmp.create_dataset('wvOOv', (nvir, nocc, nocc, nvir), 'f8') imds.wvvov = imds.ftmp.create_dataset('wvvov', (nvir, nvir, nocc, nvir), 'f8') w1 = fvv - numpy.einsum('ja,jb->ba', fov, t1) w2 = foo + numpy.einsum('ib,jb->ij', fov, t1) w3 = numpy.einsum('kc,jkbc->bj', fov, t2) * 2 + fov.T w3 -= numpy.einsum('kc,kjbc->bj', fov, t2) w3 += lib.einsum('kc,kb,jc->bj', fov, t1, t1) w4 = fov.copy() unit = nocc * nvir**2 * 6 max_memory = max(0, mycc.max_memory - lib.current_memory()[0]) blksize = min( nvir, max(ccsd.BLKMIN, int((max_memory * .95e6 / 8 - nocc**4 - nvir * nocc**3) / unit))) log.debug1( 'ccsd lambda make_intermediates: block size = %d, nvir = %d in %d blocks', blksize, nvir, int((nvir + blksize - 1) // blksize)) fswap = lib.H5TmpFile() for istep, (p0, p1) in enumerate(lib.prange(0, nvir, blksize)): eris_ovvv = eris.get_ovvv(slice(None), slice(p0, p1)) fswap['vvov/%d' % istep] = eris_ovvv.transpose(2, 3, 0, 1) woooo = 0 wvooo = numpy.zeros((nvir, nocc, nocc, nocc)) for p0, p1 in lib.prange(0, nvir, blksize): eris_ovvv = eris.get_ovvv(slice(None), slice(p0, p1)) eris_vvov = numpy.empty(((p1 - p0), nvir, nocc, nvir)) for istep, (q0, q1) in enumerate(lib.prange(0, nvir, blksize)): eris_vvov[:, :, :, q0:q1] = fswap['vvov/%d' % istep][p0:p1] w1 += numpy.einsum('jcba,jc->ba', eris_ovvv, t1[:, p0:p1] * 2) w1[:, p0:p1] -= numpy.einsum('jabc,jc->ba', eris_ovvv, t1) theta = t2[:, :, :, p0:p1] * 2 - t2[:, :, :, p0:p1].transpose( 1, 0, 2, 3) w3 += lib.einsum('jkcd,kdcb->bj', theta, eris_ovvv) theta = None wVOov = lib.einsum('jbcd,kd->bjkc', eris_ovvv, t1) wvOOv = lib.einsum('cbjd,kd->cjkb', eris_vvov, -t1) g2vovv = eris_vvov.transpose(0, 2, 1, 3) * 2 - eris_vvov.transpose( 0, 2, 3, 1) for i0, i1 in lib.prange(0, nocc, blksize): tau = t2[:, i0:i1] + numpy.einsum('ia,jb->ijab', t1, t1[i0:i1]) wvooo[p0:p1, i0:i1] += lib.einsum('cibd,jkbd->ckij', g2vovv, tau) g2vovv = tau = None # Watch out memory usage here, due to the t2 transpose wvvov = lib.einsum('jabd,jkcd->abkc', eris_ovvv, t2) * -1.5 wvvov += eris_vvov.transpose(0, 3, 2, 1) * 2 wvvov -= eris_vvov g2vvov = eris_vvov * 2 - eris_ovvv.transpose(1, 2, 0, 3) for i0, i1 in lib.prange(0, nocc, blksize): theta = t2[i0:i1] * 2 - t2[i0:i1].transpose(0, 1, 3, 2) vackb = lib.einsum('acjd,kjbd->ackb', g2vvov, theta) wvvov[:, :, i0:i1] += vackb.transpose(0, 3, 2, 1) wvvov[:, :, i0:i1] -= vackb * .5 g2vvov = eris_ovvv = eris_vvov = theta = None eris_ovoo = _cp(eris.ovoo[:, p0:p1]) w2 += numpy.einsum('kbij,kb->ij', eris_ovoo, t1[:, p0:p1]) * 2 w2 -= numpy.einsum('ibkj,kb->ij', eris_ovoo, t1[:, p0:p1]) theta = t2[:, :, p0:p1].transpose(1, 0, 2, 3) * 2 - t2[:, :, p0:p1] w3 -= lib.einsum('lckj,klcb->bj', eris_ovoo, theta) tmp = lib.einsum('lc,jcik->ijkl', t1[:, p0:p1], eris_ovoo) woooo += tmp woooo += tmp.transpose(1, 0, 3, 2) theta = tmp = None wvOOv += lib.einsum('lbjk,lc->bjkc', eris_ovoo, t1) wVOov -= lib.einsum('jbkl,lc->bjkc', eris_ovoo, t1) wvooo[p0:p1] += eris_ovoo.transpose(1, 3, 2, 0) * 2 wvooo[p0:p1] -= eris_ovoo.transpose(1, 0, 2, 3) wvooo -= lib.einsum('klbc,iblj->ckij', t2[:, :, p0:p1], eris_ovoo * 1.5) g2ovoo = eris_ovoo * 2 - eris_ovoo.transpose(2, 1, 0, 3) theta = t2[:, :, :, p0:p1] * 2 - t2[:, :, :, p0:p1].transpose( 1, 0, 2, 3) vcjik = lib.einsum('jlcb,lbki->cjki', theta, g2ovoo) wvooo += vcjik.transpose(0, 3, 2, 1) wvooo -= vcjik * .5 theta = g2ovoo = None eris_voov = _cp(eris.ovvo[:, p0:p1]).transpose(1, 0, 3, 2) tau = t2[:, :, p0:p1] + numpy.einsum('ia,jb->ijab', t1[:, p0:p1], t1) woooo += lib.einsum('cijd,klcd->ijkl', eris_voov, tau) tau = None g2voov = eris_voov * 2 - eris_voov.transpose(0, 2, 1, 3) tmpw4 = numpy.einsum('ckld,ld->kc', g2voov, t1) w1 -= lib.einsum('ckja,kjcb->ba', g2voov, t2[:, :, p0:p1]) w1[:, p0:p1] -= numpy.einsum('ja,jb->ba', tmpw4, t1) w2 += lib.einsum('jkbc,bikc->ij', t2[:, :, p0:p1], g2voov) w2 += numpy.einsum('ib,jb->ij', tmpw4, t1[:, p0:p1]) w3 += reduce(numpy.dot, (t1.T, tmpw4, t1[:, p0:p1].T)) w4[:, p0:p1] += tmpw4 wvOOv += lib.einsum('bljd,kd,lc->bjkc', eris_voov, t1, t1) wVOov -= lib.einsum('bjld,kd,lc->bjkc', eris_voov, t1, t1) VOov = lib.einsum('bjld,klcd->bjkc', g2voov, t2) VOov -= lib.einsum('bjld,kldc->bjkc', eris_voov, t2) VOov += eris_voov vOOv = lib.einsum('bljd,kldc->bjkc', eris_voov, t2) vOOv -= _cp(eris.oovv[:, :, p0:p1]).transpose(2, 1, 0, 3) wVOov += VOov wvOOv += vOOv imds.wVOov[p0:p1] = wVOov imds.wvOOv[p0:p1] = wvOOv ov1 = vOOv * 2 + VOov ov2 = VOov * 2 + vOOv vOOv = VOov = None wvooo -= lib.einsum('jb,bikc->ckij', t1[:, p0:p1], ov1) wvooo += lib.einsum('kb,bijc->ckij', t1[:, p0:p1], ov2) w3 += numpy.einsum('ckjb,kc->bj', ov2, t1[:, p0:p1]) wvvov += lib.einsum('ajkc,jb->abkc', ov1, t1) wvvov -= lib.einsum('ajkb,jc->abkc', ov2, t1) eris_ovoo = _cp(eris.ovoo[:, p0:p1]) g2ovoo = eris_ovoo * 2 - eris_ovoo.transpose(2, 1, 0, 3) tau = t2 + numpy.einsum('ia,jb->ijab', t1, t1) wvvov += lib.einsum('laki,klbc->abic', g2ovoo, tau) imds.wvvov[p0:p1] = wvvov wvvov = ov1 = ov2 = g2ovoo = None woooo += _cp(eris.oooo).transpose(0, 2, 1, 3) imds.woooo[:] = woooo imds.wvooo[:] = wvooo woooo = wvooo = None w3 += numpy.einsum('bc,jc->bj', w1, t1) w3 -= numpy.einsum('kj,kb->bj', w2, t1) fswap = None imds.w1 = w1 imds.w2 = w2 imds.w3 = w3 imds.w4 = w4 imds.ftmp.flush() return imds
def grad_elec_auxresponse_dferi (mc_grad, mo_cas=None, ci=None, dfcasdm2=None, casdm2=None, atmlst=None, max_memory=None, dferi=None, incl_2c=True): ''' Evaluate the [(P'|ij) + (P'|Q) g_Qij] d_Pij contribution to the electronic gradient, where d_Pij is the DF-2RDM obtained by solve_df_rdm2 and g_Qij solves (P|Q) g_Qij = (P|ij). The caller must symmetrize if necessary (i.e., (P|Q) d_Qij = (P|kl) d_ijkl <-> (P|Q) d_Qkl = (P|ij) d_ijkl in order to get at Q'). Args: mc_grad: MC-SCF gradients method object Kwargs: mc_cas: ndarray, list, or tuple containing active-space MO coefficients If a tuple of length 2, the same pair of MO sets are assumed to apply to the internally-contracted and externally-contracted indices of the DF-2rdm: (P|Q)d_Qij = (P|kl)d_ijkl -> (P|Q)d_Qij = (P|ij)d_ijij If a tuple of length 4, the 4 MO sets are applied to ijkl above in that order (first two external, last two internal). ci: ndarray, tuple, or list containing CI coefficients in mo_cas basis. Not used if dfcasdm2 is provided. dfcasdm2: ndarray, tuple, or list containing DF-2rdm in mo_cas basis. Computed by solve_df_rdm2 if omitted. casdm2: ndarray, tuple, or list containing rdm2 in mo_cas basis. Computed by mc_grad.fcisolver.make_rdm12 (ci,...) if omitted. atmlst: list of integers List of nonfrozen atoms, as in grad_elec functions. Defaults to list (range (mol.natm)) max_memory: int Maximum memory usage in MB dferi: ndarray containing g_Pij for optional precalculation incl_2c: bool If False, omit the terms depending on (P'|Q) Returns: dE: list of ndarray of shape (len (atmlst), 3) ''' if isinstance (mc_grad, GradientsBasics): mc = mc_grad.base else: mc = mc_grad mol = mc_grad.mol auxmol = mc.with_df.auxmol ncore, ncas, nao, naux, nbas = mc.ncore, mc.ncas, mol.nao, auxmol.nao, mol.nbas nocc = ncore + ncas npair = nao * (nao + 1) // 2 if mo_cas is None: mo_cas = mc.mo_coeff[:,ncore:nocc] if max_memory is None: max_memory = mc.max_memory if isinstance (mo_cas, np.ndarray) and mo_cas.ndim == 2: mo_cas = (mo_cas,)*4 elif len (mo_cas) == 2: mo_cas = (mo_cas[0], mo_cas[1], mo_cas[0], mo_cas[1]) elif len (mo_cas) == 4: mo_cas = tuple (mo_cas) else: raise RuntimeError ('Invalid shape of np.asarray (mo_cas): {}'.format (mo_cas.shape)) nmo = [mo.shape[1] for mo in mo_cas] if atmlst is None: atmlst = list (range (mol.natm)) if ci is None: ci = mc.ci if dfcasdm2 is None: dfcasdm2 = solve_df_rdm2 (mc, mo_cas=mo_cas[2:], ci=ci, casdm2=casdm2) # d_Pij = (P|Q)^{-1} (Q|kl) d_ijkl nset = len (dfcasdm2) dE = np.zeros ((nset, naux, 3)) dfcasdm2 = np.array (dfcasdm2) # Shape dfcasdm2 mosym, nmo_pair, mo_conc, mo_slice = _conc_mos(mo_cas[0], mo_cas[1], compact=True) if 's2' in mosym: assert (nmo[0] == nmo[1]), 'How did I get {} with nmo[0] = {} and nmo[1] = {}'.format (mosym, nmo[0], nmo[1]) dfcasdm2 = dfcasdm2.reshape (nset*naux, nmo[0], nmo[1]) dfcasdm2 += dfcasdm2.transpose (0,2,1) diag_idx = np.arange(nmo[0]) diag_idx = diag_idx * (diag_idx+1) // 2 + diag_idx dfcasdm2 = lib.pack_tril (np.ascontiguousarray (dfcasdm2)) dfcasdm2[:,diag_idx] *= 0.5 dfcasdm2 = dfcasdm2.reshape (nset, naux, nmo_pair) # Do 2c part. Assume memory is no object if incl_2c: int2c = auxmol.intor('int2c2e_ip1') if (dferi is None): dferi = solve_df_eri (mc, mo_cas=mo_cas[:2]).reshape (naux, nmo_pair) # g_Pij = (P|Q)^{-1} (Q|ij) int3c = np.dot (int2c, dferi) # (P'|Q) g_Qij dE += lib.einsum ('npi,xpi->npx', dfcasdm2, int3c) # d_Pij (P'|Q) g_Qij int2c = int3c = dferi = None # Set up 3c part get_int3c = _int3c_wrapper(mol, auxmol, 'int3c2e_ip2', 's2ij') max_memory -= lib.current_memory()[0] blklen = 6*npair blksize = int (min (max (max_memory * 1e6 / 8 / blklen, 20), 240)) aux_loc = auxmol.ao_loc aux_ranges = balance_partition(aux_loc, blksize) # Iterate over auxbasis range and do 3c part for shl0, shl1, nL in aux_ranges: p0, p1 = aux_loc[shl0], aux_loc[shl1] int3c = get_int3c ((0, nbas, 0, nbas, shl0, shl1)) # (uv|P'); shape = (3,npair,p1-p0) int3c = np.ascontiguousarray (int3c.transpose (0,2,1).reshape (3*(p1-p0), npair)) int3c = _ao2mo.nr_e2(int3c, mo_conc, mo_slice, aosym='s2', mosym=mosym) int3c = int3c.reshape (3,p1-p0,nmo_pair) int3c = np.ascontiguousarray (int3c) dE[:,p0:p1,:] -= lib.einsum ('npi,xpi->npx', dfcasdm2[:,p0:p1,:], int3c) # Ravel to atoms auxslices = auxmol.aoslice_by_atom () dE = np.array ([dE[:,p0:p1].sum (axis=1) for p0, p1 in auxslices[:,2:]]).transpose (1,0,2) return np.ascontiguousarray (dE)
def Lorb_dot_dgorb_dx(Lorb, mc, mo_coeff=None, ci=None, atmlst=None, mf_grad=None, eris=None, verbose=None): ''' Modification of pyscf.grad.casscf.kernel to compute instead the orbital Lagrange term nuclear gradient (sum_pq Lorb_pq d2_Ecas/d_lambda d_kpq) This involves removing nuclear-nuclear terms and making the substitution (D_[p]q + D_p[q]) -> D_pq (d_[p]qrs + d_pq[r]s + d_p[q]rs + d_pqr[s]) -> d_pqrs Where [] around an index implies contraction with Lorb from the left, so that the external index (regardless of whether the index on the rdm is bra or ket) is always the first index of Lorb. ''' # dmo = smoT.dao.smo # dao = mo.dmo.moT t0 = (logger.process_clock(), logger.perf_counter()) if mo_coeff is None: mo_coeff = mc.mo_coeff if ci is None: ci = mc.ci if mf_grad is None: mf_grad = mc._scf.nuc_grad_method() if mc.frozen is not None: raise NotImplementedError mol = mc.mol ncore = mc.ncore ncas = mc.ncas nocc = ncore + ncas nelecas = mc.nelecas nao, nmo = mo_coeff.shape nao_pair = nao * (nao + 1) // 2 mo_core = mo_coeff[:, :ncore] mo_cas = mo_coeff[:, ncore:nocc] # MRH: new 'effective' MO coefficients including contraction from the Lagrange multipliers moL_coeff = np.dot(mo_coeff, Lorb) s0_inv = np.dot(mo_coeff, mo_coeff.T) moL_core = moL_coeff[:, :ncore] moL_cas = moL_coeff[:, ncore:nocc] # MRH: these SHOULD be state-averaged! Use the actual sacasscf object! casdm1, casdm2 = mc.fcisolver.make_rdm12(ci, ncas, nelecas) # gfock = Generalized Fock, Adv. Chem. Phys., 69, 63 # MRH: each index exactly once! dm_core = np.dot(mo_core, mo_core.T) * 2 dm_cas = reduce(np.dot, (mo_cas, casdm1, mo_cas.T)) # MRH: new density matrix terms dmL_core = np.dot(moL_core, mo_core.T) * 2 dmL_cas = reduce(np.dot, (moL_cas, casdm1, mo_cas.T)) dmL_core += dmL_core.T dmL_cas += dmL_cas.T dm1 = dm_core + dm_cas dm1L = dmL_core + dmL_cas # MRH: end new density matrix terms # MRH: wrap the integral instead of the density matrix. I THINK the sign is the same! # mo sets 0 and 2 should be transposed, 1 and 3 should be not transposed; this will lead to correct sign # Except I can't do this for the external index, because the external index is contracted to ovlp matrix, # not the 2RDM aapa = np.zeros((ncas, ncas, nmo, ncas), dtype=dm_cas.dtype) aapaL = np.zeros((ncas, ncas, nmo, ncas), dtype=dm_cas.dtype) for i in range(nmo): jbuf = eris.ppaa[i] kbuf = eris.papa[i] aapa[:, :, i, :] = jbuf[ncore:nocc, :, :].transpose(1, 2, 0) aapaL[:, :, i, :] += np.tensordot(jbuf, Lorb[:, ncore:nocc], axes=((0), (0))) kbuf = np.tensordot(kbuf, Lorb[:, ncore:nocc], axes=((1), (0))).transpose(1, 2, 0) aapaL[:, :, i, :] += kbuf + kbuf.transpose(1, 0, 2) # MRH: new vhf terms vj, vk = mc._scf.get_jk(mol, (dm_core, dm_cas)) vjL, vkL = mc._scf.get_jk(mol, (dmL_core, dmL_cas)) h1 = mc.get_hcore() vhf_c = vj[0] - vk[0] * .5 vhf_a = vj[1] - vk[1] * .5 vhfL_c = vjL[0] - vkL[0] * .5 vhfL_a = vjL[1] - vkL[1] * .5 # MRH: I rewrote this Feff calculation completely, double-check it gfock = np.dot(h1, dm1L) # h1e gfock += np.dot((vhf_c + vhf_a), dmL_core) # core-core and active-core, 2nd 1RDM linked gfock += np.dot((vhfL_c + vhfL_a), dm_core) # core-core and active-core, 1st 1RDM linked gfock += np.dot(vhfL_c, dm_cas) # core-active, 1st 1RDM linked gfock += np.dot(vhf_c, dmL_cas) # core-active, 2nd 1RDM linked gfock = np.dot( s0_inv, gfock ) # Definition of quantity is in MO's; going (AO->MO->AO) incurs an inverse ovlp gfock += reduce(np.dot, (mo_coeff, np.einsum( 'uviw,uvtw->it', aapaL, casdm2), mo_cas.T)) # active-active # MRH: I have to contract this external 2RDM index explicitly on the 2RDM but fortunately I can do so here gfock += reduce( np.dot, (mo_coeff, np.einsum('uviw,vuwt->it', aapa, casdm2), moL_cas.T)) # MRH: As of 04/18/2019, the two-body part of this is including aapaL is definitely, unambiguously correct dme0 = (gfock + gfock.T) / 2 # This transpose is for the overlap matrix later on aapa = vj = vk = vhf_c = vhf_a = None vj, vk = mf_grad.get_jk(mol, (dm_core, dm_cas, dmL_core, dmL_cas)) vhf1c, vhf1a, vhf1cL, vhf1aL = vj - vk * 0.5 #vhf1c, vhf1a, vhf1cL, vhf1aL = mf_grad.get_veff(mol, (dm_core, dm_cas, dmL_core, dmL_cas)) hcore_deriv = mf_grad.hcore_generator(mol) s1 = mf_grad.get_ovlp(mol) diag_idx = np.arange(nao) diag_idx = diag_idx * (diag_idx + 1) // 2 + diag_idx casdm2_cc = casdm2 + casdm2.transpose(0, 1, 3, 2) dm2buf = ao2mo._ao2mo.nr_e2(casdm2_cc.reshape(ncas**2, ncas**2), mo_cas.T, (0, nao, 0, nao)).reshape(ncas**2, nao, nao) # MRH: contract the final two indices of the active-active 2RDM with L as you change to AOs # note tensordot always puts indices in the order of the arguments. dm2Lbuf = np.zeros((ncas**2, nmo, nmo)) # MRH: The second line below transposes the L; the third line transposes the derivative later on # Both the L and the derivative have to explore all indices dm2Lbuf[:, :, ncore:nocc] = np.tensordot( Lorb[:, ncore:nocc], casdm2, axes=(1, 2)).transpose(1, 2, 0, 3).reshape(ncas**2, nmo, ncas) dm2Lbuf[:, ncore:nocc, :] += np.tensordot( Lorb[:, ncore:nocc], casdm2, axes=(1, 3)).transpose(1, 2, 3, 0).reshape(ncas**2, ncas, nmo) dm2Lbuf += dm2Lbuf.transpose(0, 2, 1) dm2Lbuf = np.ascontiguousarray(dm2Lbuf) dm2Lbuf = ao2mo._ao2mo.nr_e2(dm2Lbuf.reshape(ncas**2, nmo**2), mo_coeff.T, (0, nao, 0, nao)).reshape(ncas**2, nao, nao) dm2buf = lib.pack_tril(dm2buf) dm2buf[:, diag_idx] *= .5 dm2buf = dm2buf.reshape(ncas, ncas, nao_pair) dm2Lbuf = lib.pack_tril(dm2Lbuf) dm2Lbuf[:, diag_idx] *= .5 dm2Lbuf = dm2Lbuf.reshape(ncas, ncas, nao_pair) if atmlst is None: atmlst = list(range(mol.natm)) aoslices = mol.aoslice_by_atom() de_hcore = np.zeros((len(atmlst), 3)) de_renorm = np.zeros((len(atmlst), 3)) de_eri = np.zeros((len(atmlst), 3)) de = np.zeros((len(atmlst), 3)) max_memory = mc.max_memory - lib.current_memory()[0] blksize = int(max_memory * .9e6 / 8 / (4 * (aoslices[:, 3] - aoslices[:, 2]).max() * nao_pair)) # MRH: 3 components of eri array and 1 density matrix array: FOUR arrays of this size are required! blksize = min(nao, max(2, blksize)) logger.info( mc, 'SA-CASSCF Lorb_dot_dgorb memory remaining for eri manipulation: {} MB; using blocksize = {}' .format(max_memory, blksize)) t0 = logger.timer(mc, 'SA-CASSCF Lorb_dot_dgorb 1-electron part', *t0) for k, ia in enumerate(atmlst): shl0, shl1, p0, p1 = aoslices[ia] h1ao = hcore_deriv(ia) # MRH: h1e and Feff terms de_hcore[k] += np.einsum('xij,ij->x', h1ao, dm1L) de_renorm[k] -= np.einsum('xij,ij->x', s1[:, p0:p1], dme0[p0:p1]) * 2 q1 = 0 for b0, b1, nf in _shell_prange(mol, 0, mol.nbas, blksize): q0, q1 = q1, q1 + nf dm2_ao = lib.einsum('ijw,pi,qj->pqw', dm2Lbuf, mo_cas[p0:p1], mo_cas[q0:q1]) # MRH: now contract the first two indices of the active-active 2RDM with L as you go from MOs to AOs dm2_ao += lib.einsum('ijw,pi,qj->pqw', dm2buf, moL_cas[p0:p1], mo_cas[q0:q1]) dm2_ao += lib.einsum('ijw,pi,qj->pqw', dm2buf, mo_cas[p0:p1], moL_cas[q0:q1]) shls_slice = (shl0, shl1, b0, b1, 0, mol.nbas, 0, mol.nbas) gc.collect() eri1 = mol.intor('int2e_ip1', comp=3, aosym='s2kl', shls_slice=shls_slice).reshape( 3, p1 - p0, nf, nao_pair) # MRH: I still don't understand why there is a minus here! de_eri[k] -= np.einsum('xijw,ijw->x', eri1, dm2_ao) * 2 eri1 = dm2_ao = None gc.collect() t0 = logger.timer( mc, 'SA-CASSCF Lorb_dot_dgorb atom {} ({},{}|{})'.format( ia, p1 - p0, nf, nao_pair), *t0) # MRH: core-core and core-active 2RDM terms de_eri[k] += np.einsum('xij,ij->x', vhf1c[:, p0:p1], dm1L[p0:p1]) * 2 de_eri[k] += np.einsum('xij,ij->x', vhf1cL[:, p0:p1], dm1[p0:p1]) * 2 # MRH: active-core 2RDM terms de_eri[k] += np.einsum('xij,ij->x', vhf1a[:, p0:p1], dmL_core[p0:p1]) * 2 de_eri[k] += np.einsum('xij,ij->x', vhf1aL[:, p0:p1], dm_core[p0:p1]) * 2 # MRH: deleted the nuclear-nuclear part to avoid double-counting # lesson learned from debugging - mol.intor computes -1 * the derivative and only # for one index # on the other hand, mf_grad.hcore_generator computes the actual derivative of # h1 for both indices and with the correct sign logger.debug(mc, "Orb lagrange hcore component:\n{}".format(de_hcore)) logger.debug(mc, "Orb lagrange renorm component:\n{}".format(de_renorm)) logger.debug(mc, "Orb lagrange eri component:\n{}".format(de_eri)) de = de_hcore + de_renorm + de_eri return de