def make_h1(mf, mo_coeff, mo_occ, chkfile=None, atmlst=None, verbose=logger.WARN): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mf.stdout, mf.verbose) mol = mf.mol if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:, mo_occ > 0] dm0 = numpy.dot(mocc, mocc.T) * 2 h1a = -(mol.intor('int1e_ipkin', comp=3) + mol.intor('int1e_ipnuc', comp=3)) offsetdic = mol.offset_nr_by_atom() h1aos = [] int2e_ip1 = mol._add_suffix('int2e_ip1') for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] mol.set_rinv_origin(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor('int1e_iprinv', comp=3) h1ao[:, p0:p1] += h1a[:, p0:p1] h1ao = h1ao + h1ao.transpose(0, 2, 1) shls_slice = (shl0, shl1) + (0, mol.nbas) * 3 vj1, vj2, vk1, vk2 = \ _vhf.direct_bindm(int2e_ip1, 's2kl', ('ji->s2kl', 'lk->s1ij', 'li->s1kj', 'jk->s1il'), (-dm0[:,p0:p1], -dm0, -dm0[:,p0:p1], -dm0), 3, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) for i in range(3): lib.hermi_triu(vj1[i], 1) vhf = vj1 - vk1 * .5 vhf[:, p0:p1] += vj2 - vk2 * .5 vhf = vhf + vhf.transpose(0, 2, 1) if chkfile is None: h1aos.append(h1ao + vhf) else: key = 'scf_h1ao/%d' % ia lib.chkfile.save(chkfile, key, h1ao + vhf) if chkfile is None: return h1aos else: return chkfile
def test_direct_bindm(self): numpy.random.seed(1) dm = numpy.random.random((nao, nao)) vj0, vk0 = _vhf.direct_mapdm('int2e_ip1_sph', 's2kl', ('lk->s1ij', 'jk->s1il'), dm, 3, mol._atm, mol._bas, mol._env) dms = (dm, dm) vj1, vk1 = _vhf.direct_bindm('int2e_ip1_sph', 's2kl', ('lk->s1ij', 'jk->s1il'), dms, 3, mol._atm, mol._bas, mol._env) self.assertTrue(numpy.allclose(vj0, vj1)) self.assertTrue(numpy.allclose(vk0, vk1))
def test_direct_bindm(self): numpy.random.seed(1) dm = numpy.random.random((nao,nao)) vj0, vk0 = _vhf.direct_mapdm('cint2e_ip1_sph', 's2kl', ('lk->s1ij', 'jk->s1il'), dm, 3, mol._atm, mol._bas, mol._env) dms = (dm,dm) vj1, vk1 = _vhf.direct_bindm('cint2e_ip1_sph', 's2kl', ('lk->s1ij', 'jk->s1il'), dms, 3, mol._atm, mol._bas, mol._env) self.assertTrue(numpy.allclose(vj0,vj1)) self.assertTrue(numpy.allclose(vk0,vk1))
def test_direct_bindm1(self): numpy.random.seed(1) nao = mol.nao_nr(cart=True) dm = numpy.random.random((nao,nao)) vhfopt = _vhf.VHFOpt(mol, 'int2e_cart', 'CVHFnrs8_prescreen', 'CVHFsetnr_direct_scf', 'CVHFsetnr_direct_scf_dm') vj0, vk0 = _vhf.direct(dm, mol._atm, mol._bas, mol._env, vhfopt=vhfopt, hermi=0, cart=True) vj = _vhf.direct_bindm('int2e_cart', 's1', 'kl->s1ij', dm, 1, mol._atm, mol._bas, mol._env, vhfopt) self.assertTrue(numpy.allclose(vj0,vj))
def make_h1(mf, mo_coeff, mo_occ, chkfile=None, atmlst=None, verbose=logger.WARN): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mf.stdout, mf.verbose) mol = mf.mol if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] dm0 = numpy.dot(mocc, mocc.T) * 2 h1a =-(mol.intor('cint1e_ipkin_sph', comp=3) + mol.intor('cint1e_ipnuc_sph', comp=3)) offsetdic = mol.offset_nr_by_atom() h1aos = [] for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] mol.set_rinv_origin(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor('cint1e_iprinv_sph', comp=3) h1ao[:,p0:p1] += h1a[:,p0:p1] h1ao = h1ao + h1ao.transpose(0,2,1) shls_slice = (shl0, shl1) + (0, mol.nbas)*3 vj1, vj2, vk1, vk2 = \ _vhf.direct_bindm('cint2e_ip1_sph', 's2kl', ('ji->s2kl', 'lk->s1ij', 'li->s1kj', 'jk->s1il'), (-dm0[:,p0:p1], -dm0, -dm0[:,p0:p1], -dm0), 3, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) for i in range(3): lib.hermi_triu(vj1[i], 1) vhf = vj1 - vk1*.5 vhf[:,p0:p1] += vj2 - vk2*.5 vhf = vhf + vhf.transpose(0,2,1) if chkfile is None: h1aos.append(h1ao+vhf) else: key = 'scf_h1ao/%d' % ia lib.chkfile.save(chkfile, key, h1ao+vhf) if chkfile is None: return h1aos else: return chkfile
def _get_jk(mol, intor, comp, aosym, script_dms, shls_slice=None, cintopt=None, vhfopt=None): intor = mol._add_suffix(intor) scripts = script_dms[::2] dms = script_dms[1::2] vs = _vhf.direct_bindm(intor, aosym, scripts, dms, comp, mol._atm, mol._bas, mol._env, vhfopt=vhfopt, cintopt=cintopt, shls_slice=shls_slice) for k, script in enumerate(scripts): if 's2' in script: hermi = 1 elif 'a2' in script: hermi = 2 else: continue shape = vs[k].shape if shape[-2] == shape[-1]: if comp > 1: for i in range(comp): lib.hermi_triu(vs[k][i], hermi=hermi, inplace=True) else: lib.hermi_triu(vs[k], hermi=hermi, inplace=True) return vs
def _get_jk(mol, intor, comp, aosym, script_dms, shls_slice=None, cintopt=None): intor = mol._add_suffix(intor) scripts = script_dms[::2] dms = script_dms[1::2] vs = _vhf.direct_bindm(intor, aosym, scripts, dms, comp, mol._atm, mol._bas, mol._env, cintopt=cintopt, shls_slice=shls_slice) for k, script in enumerate(scripts): if 's2' in script: hermi = 1 elif 'a2' in script: hermi = 2 else: continue shape = vs[k].shape if shape[-2] == shape[-1]: if comp > 1: for i in range(comp): lib.hermi_triu(vs[k][i], hermi=hermi, inplace=True) else: lib.hermi_triu(vs[k], hermi=hermi, inplace=True) return vs
def hess_elec(hess_mf, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None, max_memory=4000, verbose=None): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(hess_mf.stdout, hess_mf.verbose) time0 = (time.clock(), time.time()) mf = hess_mf._scf mol = hess_mf.mol if mo_energy is None: mo_energy = mf.mo_energy if mo_occ is None: mo_occ = mf.mo_occ if mo_coeff is None: mo_coeff = mf.mo_coeff if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] nocc = mocc.shape[1] dm0 = numpy.dot(mocc, mocc.T) * 2 h1aos = hess_mf.make_h1(mo_coeff, mo_occ, hess_mf.chkfile, atmlst, log) t1 = log.timer('making H1', *time0) mo1s, e1s = hess_mf.solve_mo1(mo_energy, mo_coeff, mo_occ, h1aos, None, atmlst, max_memory, log) t1 = log.timer('solving MO1', *t1) tmpf = tempfile.NamedTemporaryFile(dir=lib.param.TMPDIR) with h5py.File(tmpf.name, 'w') as f: for i0, ia in enumerate(atmlst): mol.set_rinv_origin(mol.atom_coord(ia)) f['rinv2aa/%d'%ia] = (mol.atom_charge(ia) * mol.intor('cint1e_ipiprinv_sph', comp=9)) f['rinv2ab/%d'%ia] = (mol.atom_charge(ia) * mol.intor('cint1e_iprinvip_sph', comp=9)) h1aa =(mol.intor('cint1e_ipipkin_sph', comp=9) + mol.intor('cint1e_ipipnuc_sph', comp=9)) h1ab =(mol.intor('cint1e_ipkinip_sph', comp=9) + mol.intor('cint1e_ipnucip_sph', comp=9)) s1aa = mol.intor('cint1e_ipipovlp_sph', comp=9) s1ab = mol.intor('cint1e_ipovlpip_sph', comp=9) s1a =-mol.intor('cint1e_ipovlp_sph', comp=3) # Energy weighted density matrix dme0 = numpy.einsum('pi,qi,i->pq', mocc, mocc, mo_energy[:nocc]) * 2 vj1, vk1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl', ('lk->s1ij', 'jk->s1il'), dm0, 9, mol._atm, mol._bas, mol._env) vhf1ii = vj1 - vk1*.5 vj1 = vk1 = None t1 = log.timer('contracting cint2e_ipip1_sph', *t1) offsetdic = mol.offset_nr_by_atom() frinv = h5py.File(tmpf.name, 'r') rinv2aa = frinv['rinv2aa'] rinv2ab = frinv['rinv2ab'] de2 = numpy.zeros((mol.natm,mol.natm,3,3)) for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] h_2 = rinv2ab[str(ia)] + rinv2aa[str(ia)].value.transpose(0,2,1) h_2[:,p0:p1] += h1ab[:,p0:p1] s1ao = numpy.zeros((3,nao,nao)) s1ao[:,p0:p1] += s1a[:,p0:p1] s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1oo = numpy.einsum('xpq,pi,qj->xij', s1ao, mocc, mocc) shls_slice = (shl0, shl1) + (0, mol.nbas)*3 vj1, vk1, vk2 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1', ('ji->s1kl', 'li->s1kj', 'lj->s1ki'), (dm0[:,p0:p1], dm0[:,p0:p1], dm0), 9, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) vhf2 = vj1 * 2 - vk1 * .5 vhf2[:,:,p0:p1] -= vk2 * .5 t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1) vj1, vk1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl', ('lk->s1ij', 'li->s1kj'), (dm0, dm0[:,p0:p1]), 9, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) vhf2[:,:,p0:p1] += vj1.transpose(0,2,1) vhf2 -= vk1.transpose(0,2,1) * .5 vj1 = vk1 = vk2 = None t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1) for j0, ja in enumerate(atmlst): q0, q1 = offsetdic[ja][2:] # *2 for double occupancy, *2 for +c.c. mo1 = lib.chkfile.load(hess_mf.chkfile, 'scf_mo1/%d'%ja) h1ao = lib.chkfile.load(hess_mf.chkfile, 'scf_h1ao/%d'%ia) dm1 = numpy.einsum('ypi,qi->ypq', mo1, mocc) de = numpy.einsum('xpq,ypq->xy', h1ao, dm1) * 4 dm1 = numpy.einsum('ypi,qi,i->ypq', mo1, mocc, mo_energy[:nocc]) de -= numpy.einsum('xpq,ypq->xy', s1ao, dm1) * 4 de -= numpy.einsum('xpq,ypq->xy', s1oo, e1s[j0]) * 2 de = de.reshape(-1) v2aa = rinv2aa[str(ja)].value v2ab = rinv2ab[str(ja)].value de += numpy.einsum('xpq,pq->x', v2aa[:,p0:p1], dm0[p0:p1])*2 de += numpy.einsum('xpq,pq->x', v2ab[:,p0:p1], dm0[p0:p1])*2 de += numpy.einsum('xpq,pq->x', h_2[:,:,q0:q1], dm0[:,q0:q1])*2 de += numpy.einsum('xpq,pq->x', vhf2[:,q0:q1], dm0[q0:q1])*2 de -= numpy.einsum('xpq,pq->x', s1ab[:,p0:p1,q0:q1], dme0[p0:p1,q0:q1])*2 if ia == ja: de += numpy.einsum('xpq,pq->x', h1aa[:,p0:p1], dm0[p0:p1])*2 de -= numpy.einsum('xpq,pq->x', v2aa, dm0)*2 de -= numpy.einsum('xpq,pq->x', v2ab, dm0)*2 de += numpy.einsum('xpq,pq->x', vhf1ii[:,p0:p1], dm0[p0:p1])*2 de -= numpy.einsum('xpq,pq->x', s1aa[:,p0:p1], dme0[p0:p1])*2 de2[i0,j0] = de.reshape(3,3) frinv.close() log.timer('RHF hessian', *time0) return de2
def get_jk(mols, dms, scripts=['ijkl,ji->kl'], intor='int2e_sph', aosym='s1', comp=1, hermi=0, shls_slice=None, verbose=logger.WARN): '''Compute J/K matrices for the given density matrix Args: mols : an instance of :class:`Mole` or a list of `Mole` objects dms : ndarray or list of ndarrays A density matrix or a list of density matrices Kwargs: hermi : int Whether J/K matrix is hermitian | 0 : no hermitian or symmetric | 1 : hermitian | 2 : anti-hermitian intor : str 2-electron integral name. See :func:`getints` for the complete list of available 2-electron integral names aosym : int or str Permutation symmetry for the AO integrals | 4 or '4' or 's4': 4-fold symmetry (default) | '2ij' or 's2ij' : symmetry between i, j in (ij|kl) | '2kl' or 's2kl' : symmetry between k, l in (ij|kl) | 1 or '1' or 's1': no symmetry | 'a4ij' : 4-fold symmetry with anti-symmetry between i, j in (ij|kl) | 'a4kl' : 4-fold symmetry with anti-symmetry between k, l in (ij|kl) | 'a2ij' : anti-symmetry between i, j in (ij|kl) | 'a2kl' : anti-symmetry between k, l in (ij|kl) comp : int Components of the integrals, e.g. cint2e_ip_sph has 3 components. scripts : a list of strings Contraction description (following numpy.einsum convention) based on letters [ijkl]. Each script will be one-to-one applied to each entry of dms. So it must have the same number of elements as the dms, len(scripts) == len(dms). shls_slice : 8-element list (ish_start, ish_end, jsh_start, jsh_end, ksh_start, ksh_end, lsh_start, lsh_end) Returns: Depending on the number of density matrices, the function returns one J/K matrix or a list of J/K matrices (the same number of entries as the input dms). Each JK matrices may be a 2D array or 3D array if the AO integral has multiple components. Examples: >>> from pyscf import gto >>> mol = gto.M(atom='H 0 -.5 0; H 0 .5 0', basis='cc-pvdz') >>> nao = mol.nao_nr() >>> dm = numpy.random.random((nao,nao)) >>> # Default, Coulomb matrix >>> vj = get_jk(mol, dm) >>> # Coulomb matrix with 8-fold permutation symmetry for AO integrals >>> vj = get_jk(mol, dm, 'ijkl,ji->kl', aosym='s8') >>> # Exchange matrix with 8-fold permutation symmetry for AO integrals >>> vk = get_jk(mol, dm, 'ijkl,jk->il', aosym='s8') >>> # Compute coulomb and exchange matrices together >>> vj, vk = get_jk(mol, (dm,dm), ('ijkl,ji->kl','ijkl,li->kj'), aosym='s8') >>> # Analytical gradients for coulomb matrix >>> j1 = get_jk(mol, dm, 'ijkl,lk->ij', intor='int2e_ip1_sph', aosym='s2kl', comp=3) >>> # contraction across two molecules >>> mol1 = gto.M(atom='He 2 0 0', basis='6-31g') >>> nao1 = mol1.nao_nr() >>> dm1 = numpy.random.random((nao1,nao1)) >>> # Coulomb interaction between two molecules, note 4-fold symmetry can be applied >>> jcross = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', aosym='s4') >>> ecoul = numpy.einsum('ij,ij', jcross, dm1) >>> # Exchange interaction between two molecules, no symmetry can be used >>> kcross = get_jk((mol1,mol,mol,mol1), dm, scripts='ijkl,jk->il') >>> ex = numpy.einsum('ij,ji', kcross, dm1) >>> # Analytical gradients for coulomb matrix between two molecules >>> jcros1 = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', intor='int2e_ip1_sph', comp=3) >>> # Analytical gradients for coulomb interaction between 1s density and the other molecule >>> jpart1 = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', intor='int2e_ip1_sph', comp=3, ... shls_slice=(0,1,0,1,0,mol.nbas,0,mol.nbas)) ''' if isinstance(mols, (tuple, list)): assert(len(mols) == 4) assert(mols[0].cart == mols[1].cart == mols[2].cart == mols[3].cart) if shls_slice is None: shls_slice = numpy.array([(0, mol.nbas) for mol in mols]) else: shls_slice = numpy.asarray(shls_slice).reshape(4,2) # concatenate unique mols and build corresponding shls_slice mol_ids = [id(mol) for mol in mols] atm, bas, env = mols[0]._atm, mols[0]._bas, mols[0]._env bas_start = numpy.zeros(4, dtype=int) for m in range(1,4): first = mol_ids.index(mol_ids[m]) if first == m: # the unique mol bas_start[m] = bas.shape[0] atm, bas, env = gto.conc_env(atm, bas, env, mols[m]._atm, mols[m]._bas, mols[m]._env) else: bas_start[m] = bas_start[first] shls_slice[m] += bas_start[m] shls_slice = shls_slice.flatten() else: atm, bas, env = mols._atm, mols._bas, mols._env if shls_slice is None: shls_slice = (0, mols.nbas) * 4 if isinstance(scripts, str): scripts = [scripts] if isinstance(dms, numpy.ndarray) and dms.ndim == 2: dms = [dms] assert(len(scripts) == len(dms)) #format scripts descript = [] for script in scripts: dmsym, vsym = script.lower().split(',')[1].split('->') if hermi == 0: descript.append('->'.join((dmsym,'s1'+vsym))) else: descript.append('->'.join((dmsym,'s2'+vsym))) vs = _vhf.direct_bindm(intor, aosym, descript, dms, comp, atm, bas, env, shls_slice=shls_slice) if hermi != 0: for v in vs: if v.ndim == 3: for vi in v: pyscf.lib.hermi_triu(vi, hermi, inplace=True) else: pyscf.lib.hermi_triu(v, hermi, inplace=True) return vs
def hess_elec(hess_mf, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None, max_memory=4000, verbose=None): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(hess_mf.stdout, hess_mf.verbose) time0 = (time.clock(), time.time()) mf = hess_mf._scf mol = hess_mf.mol if mo_energy is None: mo_energy = mf.mo_energy if mo_occ is None: mo_occ = mf.mo_occ if mo_coeff is None: mo_coeff = mf.mo_coeff if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] nocc = mocc.shape[1] dm0 = numpy.dot(mocc, mocc.T) * 2 h1aos = hess_mf.make_h1(mo_coeff, mo_occ, hess_mf.chkfile, atmlst, log) t1 = log.timer('making H1', *time0) mo1s, e1s = hess_mf.solve_mo1(mo_energy, mo_coeff, mo_occ, h1aos, None, atmlst, max_memory, log) t1 = log.timer('solving MO1', *t1) tmpf = tempfile.NamedTemporaryFile() with h5py.File(tmpf.name, 'w') as f: for i0, ia in enumerate(atmlst): mol.set_rinv_origin(mol.atom_coord(ia)) f['rinv2aa/%d'%ia] = (mol.atom_charge(ia) * mol.intor('cint1e_ipiprinv_sph', comp=9)) f['rinv2ab/%d'%ia] = (mol.atom_charge(ia) * mol.intor('cint1e_iprinvip_sph', comp=9)) h1aa =(mol.intor('cint1e_ipipkin_sph', comp=9) + mol.intor('cint1e_ipipnuc_sph', comp=9)) h1ab =(mol.intor('cint1e_ipkinip_sph', comp=9) + mol.intor('cint1e_ipnucip_sph', comp=9)) s1aa = mol.intor('cint1e_ipipovlp_sph', comp=9) s1ab = mol.intor('cint1e_ipovlpip_sph', comp=9) s1a =-mol.intor('cint1e_ipovlp_sph', comp=3) # Energy weighted density matrix dme0 = numpy.einsum('pi,qi,i->pq', mocc, mocc, mo_energy[:nocc]) * 2 vj1, vk1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl', ('lk->s1ij', 'jk->s1il'), dm0, 9, mol._atm, mol._bas, mol._env) vhf1ii = vj1 - vk1*.5 vj1 = vk1 = None t1 = log.timer('contracting cint2e_ipip1_sph', *t1) offsetdic = mol.offset_nr_by_atom() frinv = h5py.File(tmpf.name, 'r') rinv2aa = frinv['rinv2aa'] rinv2ab = frinv['rinv2ab'] de2 = numpy.zeros((mol.natm,mol.natm,3,3)) for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] h_2 = rinv2ab[str(ia)] + rinv2aa[str(ia)].value.transpose(0,2,1) h_2[:,p0:p1] += h1ab[:,p0:p1] s1ao = numpy.zeros((3,nao,nao)) s1ao[:,p0:p1] += s1a[:,p0:p1] s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1oo = numpy.einsum('xpq,pi,qj->xij', s1ao, mocc, mocc) shls_slice = (shl0, shl1) + (0, mol.nbas)*3 vj1, vk1, vk2 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1', ('ji->s1kl', 'li->s1kj', 'lj->s1ki'), (dm0[:,p0:p1], dm0[:,p0:p1], dm0), 9, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) vhf2 = vj1 * 2 - vk1 * .5 vhf2[:,:,p0:p1] -= vk2 * .5 t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1) vj1, vk1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl', ('lk->s1ij', 'li->s1kj'), (dm0, dm0[:,p0:p1]), 9, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) vhf2[:,:,p0:p1] += vj1.transpose(0,2,1) vhf2 -= vk1.transpose(0,2,1) * .5 vj1 = vk1 = vk2 = None t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1) for j0, ja in enumerate(atmlst): q0, q1 = offsetdic[ja][2:] # *2 for double occupancy, *2 for +c.c. mo1 = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_mo1/%d'%ja) h1ao = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_h1ao/%d'%ia) dm1 = numpy.einsum('ypi,qi->ypq', mo1, mocc) de = numpy.einsum('xpq,ypq->xy', h1ao, dm1) * 4 dm1 = numpy.einsum('ypi,qi,i->ypq', mo1, mocc, mo_energy[:nocc]) de -= numpy.einsum('xpq,ypq->xy', s1ao, dm1) * 4 de -= numpy.einsum('xpq,ypq->xy', s1oo, e1s[j0]) * 2 de = de.reshape(-1) v2aa = rinv2aa[str(ja)].value v2ab = rinv2ab[str(ja)].value de += numpy.einsum('xpq,pq->x', v2aa[:,p0:p1], dm0[p0:p1])*2 de += numpy.einsum('xpq,pq->x', v2ab[:,p0:p1], dm0[p0:p1])*2 de += numpy.einsum('xpq,pq->x', h_2[:,:,q0:q1], dm0[:,q0:q1])*2 de += numpy.einsum('xpq,pq->x', vhf2[:,q0:q1], dm0[q0:q1])*2 de -= numpy.einsum('xpq,pq->x', s1ab[:,p0:p1,q0:q1], dme0[p0:p1,q0:q1])*2 if ia == ja: de += numpy.einsum('xpq,pq->x', h1aa[:,p0:p1], dm0[p0:p1])*2 de -= numpy.einsum('xpq,pq->x', v2aa, dm0)*2 de -= numpy.einsum('xpq,pq->x', v2ab, dm0)*2 de += numpy.einsum('xpq,pq->x', vhf1ii[:,p0:p1], dm0[p0:p1])*2 de -= numpy.einsum('xpq,pq->x', s1aa[:,p0:p1], dme0[p0:p1])*2 de2[i0,j0] = de.reshape(3,3) frinv.close() log.timer('RHF hessian', *time0) return de2
def make_h1(mf, mo_coeff, mo_occ, chkfile=None, atmlst=None, verbose=logger.WARN): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mf.stdout, mf.verbose) mol = mf.mol if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] dm0 = numpy.dot(mocc, mocc.T) * 2 ni = copy.copy(mf._numint) if USE_XCFUN: try: ni.libxc = dft.xcfun xctype = ni._xc_type(mf.xc) except (ImportError, KeyError, NotImplementedError): ni.libxc = dft.libxc xctype = ni._xc_type(mf.xc) else: xctype = ni._xc_type(mf.xc) grids = mf.grids hyb = ni.libxc.hybrid_coeff(mf.xc) max_memory = 4000 h1a =-(mol.intor('cint1e_ipkin_sph', comp=3) + mol.intor('cint1e_ipnuc_sph', comp=3)) offsetdic = mol.offset_nr_by_atom() h1aos = [] for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] mol.set_rinv_origin(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor('cint1e_iprinv_sph', comp=3) h1ao[:,p0:p1] += h1a[:,p0:p1] h1ao = h1ao + h1ao.transpose(0,2,1) shls_slice = (shl0, shl1) + (0, mol.nbas)*3 if abs(hyb) > 1e-10: vj1, vj2, vk1, vk2 = \ _vhf.direct_bindm('cint2e_ip1_sph', 's2kl', ('ji->s2kl', 'lk->s1ij', 'li->s1kj', 'jk->s1il'), (-dm0[:,p0:p1], -dm0, -dm0[:,p0:p1], -dm0), 3, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) for i in range(3): pyscf.lib.hermi_triu(vj1[i], 1) veff = vj1 - hyb*.5*vk1 veff[:,p0:p1] += vj2 - hyb*.5*vk2 else: vj1, vj2 = \ _vhf.direct_bindm('cint2e_ip1_sph', 's2kl', ('ji->s2kl', 'lk->s1ij'), (-dm0[:,p0:p1], -dm0), 3, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) for i in range(3): pyscf.lib.hermi_triu(vj1[i], 1) veff = vj1 veff[:,p0:p1] += vj2 if xctype == 'LDA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vrho = vxc[0] frr = fxc[0] half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy()) rho1 = numpy.einsum('xpi,pi->xp', ao[1:,:,p0:p1], half) aow = numpy.einsum('pi,xp->xpi', ao[0], weight*frr*rho1) aow1 = numpy.einsum('xpi,p->xpi', ao[1:,:,p0:p1], weight*vrho) aow[:,:,p0:p1] += aow1 veff[0] += pyscf.lib.dot(-aow[0].T, ao[0]) veff[1] += pyscf.lib.dot(-aow[1].T, ao[0]) veff[2] += pyscf.lib.dot(-aow[2].T, ao[0]) half = aow = aow1 = None elif xctype == 'GGA': def get_wv(rho, rho1, weight, vxc, fxc): vgamma = vxc[1] frr, frg, fgg = fxc[:3] ngrid = weight.size sigma1 = numpy.einsum('xi,xi->i', rho[1:], rho1[1:]) wv = numpy.empty((4,ngrid)) wv[0] = frr * rho1[0] wv[0] += frg * sigma1 * 2 wv[1:] = (fgg * sigma1 * 4 + frg * rho1[0] * 2) * rho[1:] wv[1:] += vgamma * rho1[1:] * 2 wv *= weight return wv ao_deriv = 2 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vrho, vgamma = vxc[:2] # (d_X \nabla_x mu) nu DM_{mu,nu} half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy()) rho1X = numpy.einsum('xpi,pi->xp', ao[[1,XX,XY,XZ],:,p0:p1], half) rho1Y = numpy.einsum('xpi,pi->xp', ao[[2,YX,YY,YZ],:,p0:p1], half) rho1Z = numpy.einsum('xpi,pi->xp', ao[[3,ZX,ZY,ZZ],:,p0:p1], half) # (d_X mu) (\nabla_x nu) DM_{mu,nu} half = pyscf.lib.dot(ao[1], dm0[:,p0:p1].copy()) rho1X[1] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[1] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[1] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) half = pyscf.lib.dot(ao[2], dm0[:,p0:p1].copy()) rho1X[2] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[2] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[2] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) half = pyscf.lib.dot(ao[3], dm0[:,p0:p1].copy()) rho1X[3] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[3] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[3] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) wv = get_wv(rho, rho1X, weight, vxc, fxc) wv[0] *= .5 aow = numpy.einsum('npi,np->pi', ao[:4], wv) veff[0] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0])) wv = get_wv(rho, rho1Y, weight, vxc, fxc) wv[0] *= .5 aow = numpy.einsum('npi,np->pi', ao[:4], wv) veff[1] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0])) wv = get_wv(rho, rho1Z, weight, vxc, fxc) wv[0] *= .5 aow = numpy.einsum('npi,np->pi', ao[:4], wv) veff[2] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0])) wv = numpy.empty_like(rho) wv[0] = weight * vrho wv[1:] = rho[1:] * (weight * vgamma * 2) aow = numpy.einsum('npi,np->pi', ao[:4], wv) veff[0,p0:p1] -= pyscf.lib.dot(ao[1,:,p0:p1].T.copy(), aow) veff[1,p0:p1] -= pyscf.lib.dot(ao[2,:,p0:p1].T.copy(), aow) veff[2,p0:p1] -= pyscf.lib.dot(ao[3,:,p0:p1].T.copy(), aow) aow = numpy.einsum('npi,np->pi', ao[[XX,XY,XZ],:,p0:p1], wv[1:4]) veff[0,p0:p1] -= pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[YX,YY,YZ],:,p0:p1], wv[1:4]) veff[1,p0:p1] -= pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[ZX,ZY,ZZ],:,p0:p1], wv[1:4]) veff[2,p0:p1] -= pyscf.lib.dot(aow.T, ao[0]) else: raise NotImplementedError('meta-GGA') veff = veff + veff.transpose(0,2,1) if chkfile is None: h1aos.append(h1ao+veff) else: key = 'scf_h1ao/%d' % ia pyscf.lib.chkfile.save(chkfile, key, h1ao+veff) if chkfile is None: return h1aos else: return chkfile
def hess_elec(hess_mf, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None, max_memory=4000, verbose=None): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(hess_mf.stdout, hess_mf.verbose) time0 = (time.clock(), time.time()) mf = hess_mf._scf mol = hess_mf.mol if mo_energy is None: mo_energy = mf.mo_energy if mo_occ is None: mo_occ = mf.mo_occ if mo_coeff is None: mo_coeff = mf.mo_coeff if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape nocc = int(mo_occ.sum()) // 2 mocc = mo_coeff[:,:nocc] dm0 = mf.make_rdm1(mo_coeff, mo_occ) ni = copy.copy(mf._numint) if USE_XCFUN: try: ni.libxc = dft.xcfun xctype = ni._xc_type(mf.xc) except (ImportError, KeyError, NotImplementedError): ni.libxc = dft.libxc xctype = ni._xc_type(mf.xc) else: xctype = ni._xc_type(mf.xc) grids = mf.grids hyb = ni.libxc.hybrid_coeff(mf.xc) max_memory = 4000 h1aos = hess_mf.make_h1(mo_coeff, mo_occ, hess_mf.chkfile, atmlst, log) t1 = log.timer('making H1', *time0) def fx(mo1): # *2 for alpha + beta dm1 = numpy.einsum('xai,pa,qi->xpq', mo1, mo_coeff, mocc*2) dm1 = dm1 + dm1.transpose(0,2,1) vindxc = _contract_xc_kernel(mf, mf.xc, dm1, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm1) veff = vj - hyb * .5 * vk + vindxc else: vj = mf.get_j(mol, dm1) veff = vj + vindxc v1 = numpy.einsum('xpq,pa,qi->xai', veff, mo_coeff, mocc) return v1.reshape(v1.shape[0],-1) mo1s, e1s = hess_mf.solve_mo1(mo_energy, mo_coeff, mo_occ, h1aos, fx, atmlst, max_memory, log) t1 = log.timer('solving MO1', *t1) tmpf = tempfile.NamedTemporaryFile() with h5py.File(tmpf.name, 'w') as f: for i0, ia in enumerate(atmlst): mol.set_rinv_origin(mol.atom_coord(ia)) f['rinv2aa/%d'%ia] = (mol.atom_charge(ia) * mol.intor('cint1e_ipiprinv_sph', comp=9)) f['rinv2ab/%d'%ia] = (mol.atom_charge(ia) * mol.intor('cint1e_iprinvip_sph', comp=9)) h1aa =(mol.intor('cint1e_ipipkin_sph', comp=9) + mol.intor('cint1e_ipipnuc_sph', comp=9)) h1ab =(mol.intor('cint1e_ipkinip_sph', comp=9) + mol.intor('cint1e_ipnucip_sph', comp=9)) s1aa = mol.intor('cint1e_ipipovlp_sph', comp=9) s1ab = mol.intor('cint1e_ipovlpip_sph', comp=9) s1a =-mol.intor('cint1e_ipovlp_sph', comp=3) # Energy weighted density matrix dme0 = numpy.einsum('pi,qi,i->pq', mocc, mocc, mo_energy[:nocc]) * 2 if abs(hyb) > 1e-10: vj1, vk1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl', ('lk->s1ij', 'jk->s1il'), dm0, 9, mol._atm, mol._bas, mol._env) veff1ii = vj1 - hyb * .5 * vk1 else: vj1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl', 'lk->s1ij', dm0, 9, mol._atm, mol._bas, mol._env) veff1ii = vj1.copy() vj1[:] = 0 if xctype == 'LDA': ao_deriv = 2 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA') vxc = ni.eval_xc(mf.xc, rho, 0, deriv=1)[1] vrho = vxc[0] aow = numpy.einsum('pi,p->pi', ao[0], weight*vrho) for i in range(6): vj1[i] += pyscf.lib.dot(ao[i+4].T, aow) aow = aow1 = None elif xctype == 'GGA': ao_deriv = 3 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA') vxc = ni.eval_xc(mf.xc, rho, 0, deriv=1)[1] vrho, vgamma = vxc[:2] wv = numpy.empty_like(rho) wv[0] = weight * vrho wv[1:] = rho[1:] * (weight * vgamma * 2) aow = numpy.einsum('npi,np->pi', ao[:4], wv) for i in range(6): vj1[i] += pyscf.lib.dot(ao[i+4].T, aow) aow = numpy.einsum('npi,np->pi', ao[[XXX,XXY,XXZ]], wv[1:4]) vj1[0] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XXY,XYY,XYZ]], wv[1:4]) vj1[1] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XXZ,XYZ,XZZ]], wv[1:4]) vj1[2] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XYY,YYY,YYZ]], wv[1:4]) vj1[3] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XYZ,YYZ,YZZ]], wv[1:4]) vj1[4] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XZZ,YZZ,ZZZ]], wv[1:4]) vj1[5] += pyscf.lib.dot(aow.T, ao[0]) rho = vxc = vrho = vgamma = wv = aow = None else: raise NotImplementedError('meta-GGA') veff1ii += vj1[[0,1,2,1,3,4,2,4,5]] vj1 = vk1 = None t1 = log.timer('contracting cint2e_ipip1_sph', *t1) offsetdic = mol.offset_nr_by_atom() frinv = h5py.File(tmpf.name, 'r') rinv2aa = frinv['rinv2aa'] rinv2ab = frinv['rinv2ab'] de2 = numpy.zeros((mol.natm,mol.natm,3,3)) for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] h_2 = rinv2ab[str(ia)] + rinv2aa[str(ia)].value.transpose(0,2,1) h_2[:,p0:p1] += h1ab[:,p0:p1] s1ao = numpy.zeros((3,nao,nao)) s1ao[:,p0:p1] += s1a[:,p0:p1] s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1oo = numpy.einsum('xpq,pi,qj->xij', s1ao, mocc, mocc) shls_slice = (shl0, shl1) + (0, mol.nbas)*3 if abs(hyb) > 1e-10: vj1, vk1, vk2 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1', ('ji->s1kl', 'li->s1kj', 'lj->s1ki'), (dm0[:,p0:p1], dm0[:,p0:p1], dm0), 9, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) veff2 = vj1 * 2 - hyb * .5 * vk1 veff2[:,:,p0:p1] -= hyb * .5 * vk2 t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1) vj1, vk1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl', ('lk->s1ij', 'li->s1kj'), (dm0, dm0[:,p0:p1]), 9, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) veff2[:,:,p0:p1] += vj1.transpose(0,2,1) veff2 -= hyb * .5 * vk1.transpose(0,2,1) vj1 = vk1 = vk2 = None t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1) else: vj1 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1', 'ji->s1kl', dm0[:,p0:p1], 9, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) veff2 = vj1 * 2 t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1) vj1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl', 'lk->s1ij', dm0, 9, mol._atm, mol._bas, mol._env, shls_slice=shls_slice) veff2[:,:,p0:p1] += vj1.transpose(0,2,1) t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1) if xctype == 'LDA': ao_deriv = 1 vj1[:] = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vrho = vxc[0] frr = fxc[0] half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy()) rho1 = numpy.einsum('xpi,pi->xp', ao[1:,:,p0:p1], half) aow = numpy.einsum('pi,xp->xpi', ao[0], weight*frr*rho1) veff2[0] += pyscf.lib.dot(ao[1].T, aow[0]) * 2 veff2[1] += pyscf.lib.dot(ao[1].T, aow[1]) * 2 veff2[2] += pyscf.lib.dot(ao[1].T, aow[2]) * 2 veff2[3] += pyscf.lib.dot(ao[2].T, aow[0]) * 2 veff2[4] += pyscf.lib.dot(ao[2].T, aow[1]) * 2 veff2[5] += pyscf.lib.dot(ao[2].T, aow[2]) * 2 veff2[6] += pyscf.lib.dot(ao[3].T, aow[0]) * 2 veff2[7] += pyscf.lib.dot(ao[3].T, aow[1]) * 2 veff2[8] += pyscf.lib.dot(ao[3].T, aow[2]) * 2 aow = numpy.einsum('xpi,p->xpi', ao[1:,:,p0:p1], weight*vrho) vj1[0] += pyscf.lib.dot(aow[0].T, ao[1]) vj1[1] += pyscf.lib.dot(aow[0].T, ao[2]) vj1[2] += pyscf.lib.dot(aow[0].T, ao[3]) vj1[3] += pyscf.lib.dot(aow[1].T, ao[1]) vj1[4] += pyscf.lib.dot(aow[1].T, ao[2]) vj1[5] += pyscf.lib.dot(aow[1].T, ao[3]) vj1[6] += pyscf.lib.dot(aow[2].T, ao[1]) vj1[7] += pyscf.lib.dot(aow[2].T, ao[2]) vj1[8] += pyscf.lib.dot(aow[2].T, ao[3]) half = aow = None veff2[:,:,p0:p1] += vj1.transpose(0,2,1) elif xctype == 'GGA': def get_wv(rho, rho1, weight, vxc, fxc): vgamma = vxc[1] frr, frg, fgg = fxc[:3] ngrid = weight.size sigma1 = numpy.einsum('xi,xi->i', rho[1:], rho1[1:]) wv = numpy.empty((4,ngrid)) wv[0] = frr * rho1[0] wv[0] += frg * sigma1 * 2 wv[1:] = (fgg * sigma1 * 4 + frg * rho1[0] * 2) * rho[1:] wv[1:] += vgamma * rho1[1:] * 2 wv *= weight return wv ao_deriv = 2 vj1[:] = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vrho, vgamma = vxc[:2] # (d_X \nabla_x mu) nu DM_{mu,nu} half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy()) rho1X = numpy.einsum('xpi,pi->xp', ao[[1,XX,XY,XZ],:,p0:p1], half) rho1Y = numpy.einsum('xpi,pi->xp', ao[[2,YX,YY,YZ],:,p0:p1], half) rho1Z = numpy.einsum('xpi,pi->xp', ao[[3,ZX,ZY,ZZ],:,p0:p1], half) # (d_X mu) (\nabla_x nu) DM_{mu,nu} half = pyscf.lib.dot(ao[1], dm0[:,p0:p1].copy()) rho1X[1] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[1] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[1] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) half = pyscf.lib.dot(ao[2], dm0[:,p0:p1].copy()) rho1X[2] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[2] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[2] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) half = pyscf.lib.dot(ao[3], dm0[:,p0:p1].copy()) rho1X[3] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[3] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[3] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) wv = get_wv(rho, rho1X, weight, vxc, fxc) * 2 # ~ vj1*2 aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv) # dX veff2[0] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv) # dY veff2[3] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv) # dZ veff2[6] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4]) veff2[0] += pyscf.lib.dot(ao[1].T, aow) veff2[3] += pyscf.lib.dot(ao[2].T, aow) veff2[6] += pyscf.lib.dot(ao[3].T, aow) wv = get_wv(rho, rho1Y, weight, vxc, fxc) * 2 aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv) veff2[1] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv) veff2[4] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv) veff2[7] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4]) veff2[1] += pyscf.lib.dot(ao[1].T, aow) veff2[4] += pyscf.lib.dot(ao[2].T, aow) veff2[7] += pyscf.lib.dot(ao[3].T, aow) wv = get_wv(rho, rho1Z, weight, vxc, fxc) * 2 aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv) veff2[2] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv) veff2[5] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv) veff2[8] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4]) veff2[2] += pyscf.lib.dot(ao[1].T, aow) veff2[5] += pyscf.lib.dot(ao[2].T, aow) veff2[8] += pyscf.lib.dot(ao[3].T, aow) wv = numpy.empty_like(rho) wv[0] = weight * vrho * .5 wv[1:] = rho[1:] * (weight * vgamma * 2) aowx = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv) aowy = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv) aowz = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv) ao1 = aowx[:,p0:p1].T.copy() ao2 = aowy[:,p0:p1].T.copy() ao3 = aowz[:,p0:p1].T.copy() vj1[0] += pyscf.lib.dot(ao1, ao[1]) vj1[1] += pyscf.lib.dot(ao1, ao[2]) vj1[2] += pyscf.lib.dot(ao1, ao[3]) vj1[3] += pyscf.lib.dot(ao2, ao[1]) vj1[4] += pyscf.lib.dot(ao2, ao[2]) vj1[5] += pyscf.lib.dot(ao2, ao[3]) vj1[6] += pyscf.lib.dot(ao3, ao[1]) vj1[7] += pyscf.lib.dot(ao3, ao[2]) vj1[8] += pyscf.lib.dot(ao3, ao[3]) ao1 = ao[1,:,p0:p1].T.copy() ao2 = ao[2,:,p0:p1].T.copy() ao3 = ao[3,:,p0:p1].T.copy() vj1[0] += pyscf.lib.dot(ao1, aowx) vj1[1] += pyscf.lib.dot(ao1, aowy) vj1[2] += pyscf.lib.dot(ao1, aowz) vj1[3] += pyscf.lib.dot(ao2, aowx) vj1[4] += pyscf.lib.dot(ao2, aowy) vj1[5] += pyscf.lib.dot(ao2, aowz) vj1[6] += pyscf.lib.dot(ao3, aowx) vj1[7] += pyscf.lib.dot(ao3, aowy) vj1[8] += pyscf.lib.dot(ao3, aowz) veff2[:,:,p0:p1] += vj1.transpose(0,2,1) else: raise NotImplementedError('meta-GGA') for j0, ja in enumerate(atmlst): q0, q1 = offsetdic[ja][2:] # *2 for double occupancy, *2 for +c.c. mo1 = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_mo1/%d'%ja) h1ao = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_h1ao/%d'%ia) dm1 = numpy.einsum('ypi,qi->ypq', mo1, mocc) de = numpy.einsum('xpq,ypq->xy', h1ao, dm1) * 4 dm1 = numpy.einsum('ypi,qi,i->ypq', mo1, mocc, mo_energy[:nocc]) de -= numpy.einsum('xpq,ypq->xy', s1ao, dm1) * 4 de -= numpy.einsum('xpq,ypq->xy', s1oo, e1s[j0]) * 2 de = de.reshape(-1) v2aa = rinv2aa[str(ja)].value v2ab = rinv2ab[str(ja)].value de += numpy.einsum('xpq,pq->x', v2aa[:,p0:p1], dm0[p0:p1])*2 de += numpy.einsum('xpq,pq->x', v2ab[:,p0:p1], dm0[p0:p1])*2 de += numpy.einsum('xpq,pq->x', h_2[:,:,q0:q1], dm0[:,q0:q1])*2 de += numpy.einsum('xpq,pq->x', veff2[:,q0:q1], dm0[q0:q1])*2 de -= numpy.einsum('xpq,pq->x', s1ab[:,p0:p1,q0:q1], dme0[p0:p1,q0:q1])*2 if ia == ja: de += numpy.einsum('xpq,pq->x', h1aa[:,p0:p1], dm0[p0:p1])*2 de -= numpy.einsum('xpq,pq->x', v2aa, dm0)*2 de -= numpy.einsum('xpq,pq->x', v2ab, dm0)*2 de += numpy.einsum('xpq,pq->x', veff1ii[:,p0:p1], dm0[p0:p1])*2 de -= numpy.einsum('xpq,pq->x', s1aa[:,p0:p1], dme0[p0:p1])*2 de2[i0,j0] = de.reshape(3,3) frinv.close() log.timer('RHF hessian', *time0) return de2
def get_jk(mols, dms, scripts=['ijkl,ji->kl'], intor='cint2e_sph', aosym='s1', comp=1, hermi=0, shls_slice=None, verbose=logger.WARN): '''Compute J/K matrices for the given density matrix Args: mols : an instance of :class:`Mole` or a list of `Mole` objects dms : ndarray or list of ndarrays A density matrix or a list of density matrices Kwargs: hermi : int Whether J/K matrix is hermitian | 0 : no hermitian or symmetric | 1 : hermitian | 2 : anti-hermitian intor : str 2-electron integral name. See :func:`getints` for the complete list of available 2-electron integral names aosym : int or str Permutation symmetry for the AO integrals | 4 or '4' or 's4': 4-fold symmetry (default) | '2ij' or 's2ij' : symmetry between i, j in (ij|kl) | '2kl' or 's2kl' : symmetry between k, l in (ij|kl) | 1 or '1' or 's1': no symmetry | 'a4ij' : 4-fold symmetry with anti-symmetry between i, j in (ij|kl) | 'a4kl' : 4-fold symmetry with anti-symmetry between k, l in (ij|kl) | 'a2ij' : anti-symmetry between i, j in (ij|kl) | 'a2kl' : anti-symmetry between k, l in (ij|kl) comp : int Components of the integrals, e.g. cint2e_ip_sph has 3 components. scripts : a list of strings Contraction description (following numpy.einsum convention) based on letters [ijkl]. Each script will be one-to-one applied to each entry of dms. So it must have the same number of elements as the dms, len(scripts) == len(dms). shls_slice : 8-element list (ish_start, ish_end, jsh_start, jsh_end, ksh_start, ksh_end, lsh_start, lsh_end) Returns: Depending on the number of density matrices, the function returns one J/K matrix or a list of J/K matrices (the same number of entries as the input dms). Each JK matrices may be a 2D array or 3D array if the AO integral has multiple components. Examples: >>> from pyscf import gto >>> mol = gto.M(atom='H 0 -.5 0; H 0 .5 0', basis='cc-pvdz') >>> nao = mol.nao_nr() >>> dm = numpy.random.random((nao,nao)) >>> # Default, Coulomb matrix >>> vj = get_jk(mol, dm) >>> # Coulomb matrix with 8-fold permutation symmetry for AO integrals >>> vj = get_jk(mol, dm, 'ijkl,ji->kl', aosym='s8') >>> # Exchange matrix with 8-fold permutation symmetry for AO integrals >>> vk = get_jk(mol, dm, 'ijkl,jk->il', aosym='s8') >>> # Compute coulomb and exchange matrices together >>> vj, vk = get_jk(mol, (dm,dm), ('ijkl,ji->kl','ijkl,li->kj'), aosym='s8') >>> # Analytical gradients for coulomb matrix >>> j1 = get_jk(mol, dm, 'ijkl,lk->ij', intor='cint2e_ip1_sph', aosym='s2kl', comp=3) >>> # contraction across two molecules >>> mol1 = gto.M(atom='He 2 0 0', basis='6-31g') >>> nao1 = mol1.nao_nr() >>> dm1 = numpy.random.random((nao1,nao1)) >>> # Coulomb interaction between two molecules, note 4-fold symmetry can be applied >>> jcross = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', aosym='s4') >>> ecoul = numpy.einsum('ij,ij', jcross, dm1) >>> # Exchange interaction between two molecules, no symmetry can be used >>> kcross = get_jk((mol1,mol,mol,mol1), dm, scripts='ijkl,jk->il') >>> ex = numpy.einsum('ij,ji', kcross, dm1) >>> # Analytical gradients for coulomb matrix between two molecules >>> jcros1 = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', intor='cint2e_ip1_sph', comp=3) >>> # Analytical gradients for coulomb interaction between 1s density and the other molecule >>> jpart1 = get_jk((mol1,mol1,mol,mol), dm, scripts='ijkl,lk->ij', intor='cint2e_ip1_sph', comp=3, ... shls_slice=(0,1,0,1,0,mol.nbas,0,mol.nbas)) ''' if isinstance(mols, (tuple, list)): assert(len(mols) == 4) if shls_slice is None: shls_slice = numpy.array([(0, mol.nbas) for mol in mols]) else: shls_slice = numpy.asarray(shls_slice).reshape(4,2) # concatenate unique mols and build corresponding shls_slice mol_ids = [id(mol) for mol in mols] atm, bas, env = mols[0]._atm, mols[0]._bas, mols[0]._env bas_start = numpy.zeros(4, dtype=int) for m in range(1,4): first = mol_ids.index(mol_ids[m]) if first == m: # the unique mol bas_start[m] = bas.shape[0] atm, bas, env = gto.conc_env(atm, bas, env, mols[m]._atm, mols[m]._bas, mols[m]._env) else: bas_start[m] = bas_start[first] shls_slice[m] += bas_start[m] shls_slice = shls_slice.flatten() else: atm, bas, env = mols._atm, mols._bas, mols._env if shls_slice is None: shls_slice = (0, mols.nbas) * 4 if isinstance(scripts, str): scripts = [scripts] if isinstance(dms, numpy.ndarray) and dms.ndim == 2: dms = [dms] assert(len(scripts) == len(dms)) #format scripts descript = [] for script in scripts: dmsym, vsym = script.lower().split(',')[1].split('->') if hermi == 0: descript.append('->'.join((dmsym,'s1'+vsym))) else: descript.append('->'.join((dmsym,'s2'+vsym))) vs = _vhf.direct_bindm(intor, aosym, descript, dms, comp, atm, bas, env, shls_slice=shls_slice) if hermi != 0: for v in vs: if v.ndim == 3: for vi in v: pyscf.lib.hermi_triu(vi, hermi, inplace=True) else: pyscf.lib.hermi_triu(v, hermi, inplace=True) return vs
def make_h1(mf, mo_coeff, mo_occ, chkfile=None, atmlst=None, verbose=logger.WARN): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mf.stdout, mf.verbose) mol = mf.mol if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape mocc = mo_coeff[:,mo_occ>0] dm0 = numpy.dot(mocc, mocc.T) * 2 ni = copy.copy(mf._numint) if USE_XCFUN: try: ni.libxc = dft.xcfun xctype = ni._xc_type(mf.xc) except (ImportError, KeyError, NotImplementedError): ni.libxc = dft.libxc xctype = ni._xc_type(mf.xc) else: xctype = ni._xc_type(mf.xc) grids = mf.grids hyb = ni.libxc.hybrid_coeff(mf.xc) max_memory = 4000 h1a =-(mol.intor('cint1e_ipkin_sph', comp=3) + mol.intor('cint1e_ipnuc_sph', comp=3)) offsetdic = mol.offset_nr_by_atom() h1aos = [] for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] mol.set_rinv_origin_(mol.atom_coord(ia)) h1ao = -mol.atom_charge(ia) * mol.intor('cint1e_iprinv_sph', comp=3) h1ao[:,p0:p1] += h1a[:,p0:p1] h1ao = h1ao + h1ao.transpose(0,2,1) shls_offset = (shl0, shl1) + (0, mol.nbas)*3 if abs(hyb) > 1e-10: vj1, vj2, vk1, vk2 = \ _vhf.direct_bindm('cint2e_ip1_sph', 's2kl', ('ji->s2kl', 'lk->s1ij', 'li->s1kj', 'jk->s1il'), (-dm0[:,p0:p1], -dm0, -dm0[:,p0:p1], -dm0), 3, mol._atm, mol._bas, mol._env, shls_offset=shls_offset) for i in range(3): pyscf.lib.hermi_triu_(vj1[i], 1) veff = vj1 - hyb*.5*vk1 veff[:,p0:p1] += vj2 - hyb*.5*vk2 else: vj1, vj2 = \ _vhf.direct_bindm('cint2e_ip1_sph', 's2kl', ('ji->s2kl', 'lk->s1ij'), (-dm0[:,p0:p1], -dm0), 3, mol._atm, mol._bas, mol._env, shls_offset=shls_offset) for i in range(3): pyscf.lib.hermi_triu_(vj1[i], 1) veff = vj1 veff[:,p0:p1] += vj2 if xctype == 'LDA': ao_deriv = 1 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vrho = vxc[0] frr = fxc[0] half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy()) rho1 = numpy.einsum('xpi,pi->xp', ao[1:,:,p0:p1], half) aow = numpy.einsum('pi,xp->xpi', ao[0], weight*frr*rho1) aow1 = numpy.einsum('xpi,p->xpi', ao[1:,:,p0:p1], weight*vrho) aow[:,:,p0:p1] += aow1 veff[0] += pyscf.lib.dot(-aow[0].T, ao[0]) veff[1] += pyscf.lib.dot(-aow[1].T, ao[0]) veff[2] += pyscf.lib.dot(-aow[2].T, ao[0]) half = aow = aow1 = None elif xctype == 'GGA': def get_wv(rho, rho1, weight, vxc, fxc): vgamma = vxc[1] frr, frg, fgg = fxc[:3] ngrid = weight.size sigma1 = numpy.einsum('xi,xi->i', rho[1:], rho1[1:]) wv = numpy.empty((4,ngrid)) wv[0] = frr * rho1[0] wv[0] += frg * sigma1 * 2 wv[1:] = (fgg * sigma1 * 4 + frg * rho1[0] * 2) * rho[1:] wv[1:] += vgamma * rho1[1:] * 2 wv *= weight return wv ao_deriv = 2 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vrho, vgamma = vxc[:2] # (d_X \nabla_x mu) nu DM_{mu,nu} half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy()) rho1X = numpy.einsum('xpi,pi->xp', ao[[1,XX,XY,XZ],:,p0:p1], half) rho1Y = numpy.einsum('xpi,pi->xp', ao[[2,YX,YY,YZ],:,p0:p1], half) rho1Z = numpy.einsum('xpi,pi->xp', ao[[3,ZX,ZY,ZZ],:,p0:p1], half) # (d_X mu) (\nabla_x nu) DM_{mu,nu} half = pyscf.lib.dot(ao[1], dm0[:,p0:p1].copy()) rho1X[1] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[1] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[1] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) half = pyscf.lib.dot(ao[2], dm0[:,p0:p1].copy()) rho1X[2] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[2] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[2] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) half = pyscf.lib.dot(ao[3], dm0[:,p0:p1].copy()) rho1X[3] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[3] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[3] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) wv = get_wv(rho, rho1X, weight, vxc, fxc) wv[0] *= .5 aow = numpy.einsum('npi,np->pi', ao[:4], wv) veff[0] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0])) wv = get_wv(rho, rho1Y, weight, vxc, fxc) wv[0] *= .5 aow = numpy.einsum('npi,np->pi', ao[:4], wv) veff[1] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0])) wv = get_wv(rho, rho1Z, weight, vxc, fxc) wv[0] *= .5 aow = numpy.einsum('npi,np->pi', ao[:4], wv) veff[2] -= pyscf.lib.transpose_sum(pyscf.lib.dot(aow.T, ao[0])) wv = numpy.empty_like(rho) wv[0] = weight * vrho wv[1:] = rho[1:] * (weight * vgamma * 2) aow = numpy.einsum('npi,np->pi', ao[:4], wv) veff[0,p0:p1] -= pyscf.lib.dot(ao[1,:,p0:p1].T.copy(), aow) veff[1,p0:p1] -= pyscf.lib.dot(ao[2,:,p0:p1].T.copy(), aow) veff[2,p0:p1] -= pyscf.lib.dot(ao[3,:,p0:p1].T.copy(), aow) aow = numpy.einsum('npi,np->pi', ao[[XX,XY,XZ],:,p0:p1], wv[1:4]) veff[0,p0:p1] -= pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[YX,YY,YZ],:,p0:p1], wv[1:4]) veff[1,p0:p1] -= pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[ZX,ZY,ZZ],:,p0:p1], wv[1:4]) veff[2,p0:p1] -= pyscf.lib.dot(aow.T, ao[0]) else: raise NotImplementedError('meta-GGA') veff = veff + veff.transpose(0,2,1) if chkfile is None: h1aos.append(h1ao+veff) else: key = 'scf_h1ao/%d' % ia pyscf.lib.chkfile.save(chkfile, key, h1ao+veff) if chkfile is None: return h1aos else: return chkfile
def hess_elec(hess_mf, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None, max_memory=4000, verbose=None): if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(hess_mf.stdout, hess_mf.verbose) time0 = (time.clock(), time.time()) mf = hess_mf._scf mol = hess_mf.mol if mo_energy is None: mo_energy = mf.mo_energy if mo_occ is None: mo_occ = mf.mo_occ if mo_coeff is None: mo_coeff = mf.mo_coeff if atmlst is None: atmlst = range(mol.natm) nao, nmo = mo_coeff.shape nocc = int(mo_occ.sum()) // 2 mocc = mo_coeff[:,:nocc] dm0 = mf.make_rdm1(mo_coeff, mo_occ) ni = copy.copy(mf._numint) if USE_XCFUN: try: ni.libxc = dft.xcfun xctype = ni._xc_type(mf.xc) except (ImportError, KeyError, NotImplementedError): ni.libxc = dft.libxc xctype = ni._xc_type(mf.xc) else: xctype = ni._xc_type(mf.xc) grids = mf.grids hyb = ni.libxc.hybrid_coeff(mf.xc) max_memory = 4000 h1aos = hess_mf.make_h1(mo_coeff, mo_occ, hess_mf.chkfile, atmlst, log) t1 = log.timer('making H1', *time0) def fx(mo1): # *2 for alpha + beta dm1 = numpy.einsum('xai,pa,qi->xpq', mo1, mo_coeff, mocc*2) dm1 = dm1 + dm1.transpose(0,2,1) vindxc = _contract_xc_kernel(mf, mf.xc, dm1, max_memory) if abs(hyb) > 1e-10: vj, vk = mf.get_jk(mol, dm1) veff = vj - hyb * .5 * vk + vindxc else: vj = mf.get_j(mol, dm1) veff = vj + vindxc v1 = numpy.einsum('xpq,pa,qi->xai', veff, mo_coeff, mocc) return v1.reshape(v1.shape[0],-1) mo1s, e1s = hess_mf.solve_mo1(mo_energy, mo_coeff, mo_occ, h1aos, fx, atmlst, max_memory, log) t1 = log.timer('solving MO1', *t1) tmpf = tempfile.NamedTemporaryFile() with h5py.File(tmpf.name, 'w') as f: for i0, ia in enumerate(atmlst): mol.set_rinv_origin_(mol.atom_coord(ia)) f['rinv2aa/%d'%ia] = (mol.atom_charge(ia) * mol.intor('cint1e_ipiprinv_sph', comp=9)) f['rinv2ab/%d'%ia] = (mol.atom_charge(ia) * mol.intor('cint1e_iprinvip_sph', comp=9)) h1aa =(mol.intor('cint1e_ipipkin_sph', comp=9) + mol.intor('cint1e_ipipnuc_sph', comp=9)) h1ab =(mol.intor('cint1e_ipkinip_sph', comp=9) + mol.intor('cint1e_ipnucip_sph', comp=9)) s1aa = mol.intor('cint1e_ipipovlp_sph', comp=9) s1ab = mol.intor('cint1e_ipovlpip_sph', comp=9) s1a =-mol.intor('cint1e_ipovlp_sph', comp=3) # Energy weighted density matrix dme0 = numpy.einsum('pi,qi,i->pq', mocc, mocc, mo_energy[:nocc]) * 2 if abs(hyb) > 1e-10: vj1, vk1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl', ('lk->s1ij', 'jk->s1il'), dm0, 9, mol._atm, mol._bas, mol._env) veff1ii = vj1 - hyb * .5 * vk1 else: vj1 = _vhf.direct_mapdm('cint2e_ipip1_sph', 's2kl', 'lk->s1ij', dm0, 9, mol._atm, mol._bas, mol._env) veff1ii = vj1.copy() vj1[:] = 0 if xctype == 'LDA': ao_deriv = 2 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA') vxc = ni.eval_xc(mf.xc, rho, 0, deriv=1)[1] vrho = vxc[0] aow = numpy.einsum('pi,p->pi', ao[0], weight*vrho) for i in range(6): vj1[i] += pyscf.lib.dot(ao[i+4].T, aow) aow = aow1 = None elif xctype == 'GGA': ao_deriv = 3 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA') vxc = ni.eval_xc(mf.xc, rho, 0, deriv=1)[1] vrho, vgamma = vxc[:2] wv = numpy.empty_like(rho) wv[0] = weight * vrho wv[1:] = rho[1:] * (weight * vgamma * 2) aow = numpy.einsum('npi,np->pi', ao[:4], wv) for i in range(6): vj1[i] += pyscf.lib.dot(ao[i+4].T, aow) aow = numpy.einsum('npi,np->pi', ao[[XXX,XXY,XXZ]], wv[1:4]) vj1[0] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XXY,XYY,XYZ]], wv[1:4]) vj1[1] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XXZ,XYZ,XZZ]], wv[1:4]) vj1[2] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XYY,YYY,YYZ]], wv[1:4]) vj1[3] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XYZ,YYZ,YZZ]], wv[1:4]) vj1[4] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[XZZ,YZZ,ZZZ]], wv[1:4]) vj1[5] += pyscf.lib.dot(aow.T, ao[0]) rho = vxc = vrho = vgamma = wv = aow = None else: raise NotImplementedError('meta-GGA') veff1ii += vj1[[0,1,2,1,3,4,2,4,5]] vj1 = vk1 = None t1 = log.timer('contracting cint2e_ipip1_sph', *t1) offsetdic = mol.offset_nr_by_atom() frinv = h5py.File(tmpf.name, 'r') rinv2aa = frinv['rinv2aa'] rinv2ab = frinv['rinv2ab'] de2 = numpy.zeros((mol.natm,mol.natm,3,3)) for i0, ia in enumerate(atmlst): shl0, shl1, p0, p1 = offsetdic[ia] h_2 = rinv2ab[str(ia)] + rinv2aa[str(ia)].value.transpose(0,2,1) h_2[:,p0:p1] += h1ab[:,p0:p1] s1ao = numpy.zeros((3,nao,nao)) s1ao[:,p0:p1] += s1a[:,p0:p1] s1ao[:,:,p0:p1] += s1a[:,p0:p1].transpose(0,2,1) s1oo = numpy.einsum('xpq,pi,qj->xij', s1ao, mocc, mocc) shls_offset = (shl0, shl1) + (0, mol.nbas)*3 if abs(hyb) > 1e-10: vj1, vk1, vk2 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1', ('ji->s1kl', 'li->s1kj', 'lj->s1ki'), (dm0[:,p0:p1], dm0[:,p0:p1], dm0), 9, mol._atm, mol._bas, mol._env, shls_offset=shls_offset) veff2 = vj1 * 2 - hyb * .5 * vk1 veff2[:,:,p0:p1] -= hyb * .5 * vk2 t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1) vj1, vk1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl', ('lk->s1ij', 'li->s1kj'), (dm0, dm0[:,p0:p1]), 9, mol._atm, mol._bas, mol._env, shls_offset=shls_offset) veff2[:,:,p0:p1] += vj1.transpose(0,2,1) veff2 -= hyb * .5 * vk1.transpose(0,2,1) vj1 = vk1 = vk2 = None t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1) else: vj1 = _vhf.direct_bindm('cint2e_ip1ip2_sph', 's1', 'ji->s1kl', dm0[:,p0:p1], 9, mol._atm, mol._bas, mol._env, shls_offset=shls_offset) veff2 = vj1 * 2 t1 = log.timer('contracting cint2e_ip1ip2_sph for atom %d'%ia, *t1) vj1 = _vhf.direct_bindm('cint2e_ipvip1_sph', 's2kl', 'lk->s1ij', dm0, 9, mol._atm, mol._bas, mol._env, shls_offset=shls_offset) veff2[:,:,p0:p1] += vj1.transpose(0,2,1) t1 = log.timer('contracting cint2e_ipvip1_sph for atom %d'%ia, *t1) if xctype == 'LDA': ao_deriv = 1 vj1[:] = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[0], mo_coeff, mo_occ, mask, 'LDA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vrho = vxc[0] frr = fxc[0] half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy()) rho1 = numpy.einsum('xpi,pi->xp', ao[1:,:,p0:p1], half) aow = numpy.einsum('pi,xp->xpi', ao[0], weight*frr*rho1) veff2[0] += pyscf.lib.dot(ao[1].T, aow[0]) * 2 veff2[1] += pyscf.lib.dot(ao[1].T, aow[1]) * 2 veff2[2] += pyscf.lib.dot(ao[1].T, aow[2]) * 2 veff2[3] += pyscf.lib.dot(ao[2].T, aow[0]) * 2 veff2[4] += pyscf.lib.dot(ao[2].T, aow[1]) * 2 veff2[5] += pyscf.lib.dot(ao[2].T, aow[2]) * 2 veff2[6] += pyscf.lib.dot(ao[3].T, aow[0]) * 2 veff2[7] += pyscf.lib.dot(ao[3].T, aow[1]) * 2 veff2[8] += pyscf.lib.dot(ao[3].T, aow[2]) * 2 aow = numpy.einsum('xpi,p->xpi', ao[1:,:,p0:p1], weight*vrho) vj1[0] += pyscf.lib.dot(aow[0].T, ao[1]) vj1[1] += pyscf.lib.dot(aow[0].T, ao[2]) vj1[2] += pyscf.lib.dot(aow[0].T, ao[3]) vj1[3] += pyscf.lib.dot(aow[1].T, ao[1]) vj1[4] += pyscf.lib.dot(aow[1].T, ao[2]) vj1[5] += pyscf.lib.dot(aow[1].T, ao[3]) vj1[6] += pyscf.lib.dot(aow[2].T, ao[1]) vj1[7] += pyscf.lib.dot(aow[2].T, ao[2]) vj1[8] += pyscf.lib.dot(aow[2].T, ao[3]) half = aow = None veff2[:,:,p0:p1] += vj1.transpose(0,2,1) elif xctype == 'GGA': def get_wv(rho, rho1, weight, vxc, fxc): vgamma = vxc[1] frr, frg, fgg = fxc[:3] ngrid = weight.size sigma1 = numpy.einsum('xi,xi->i', rho[1:], rho1[1:]) wv = numpy.empty((4,ngrid)) wv[0] = frr * rho1[0] wv[0] += frg * sigma1 * 2 wv[1:] = (fgg * sigma1 * 4 + frg * rho1[0] * 2) * rho[1:] wv[1:] += vgamma * rho1[1:] * 2 wv *= weight return wv ao_deriv = 2 vj1[:] = 0 for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, ao_deriv, max_memory, ni.non0tab): rho = ni.eval_rho2(mol, ao[:4], mo_coeff, mo_occ, mask, 'GGA') vxc, fxc = ni.eval_xc(mf.xc, rho, 0, deriv=2)[1:3] vrho, vgamma = vxc[:2] # (d_X \nabla_x mu) nu DM_{mu,nu} half = pyscf.lib.dot(ao[0], dm0[:,p0:p1].copy()) rho1X = numpy.einsum('xpi,pi->xp', ao[[1,XX,XY,XZ],:,p0:p1], half) rho1Y = numpy.einsum('xpi,pi->xp', ao[[2,YX,YY,YZ],:,p0:p1], half) rho1Z = numpy.einsum('xpi,pi->xp', ao[[3,ZX,ZY,ZZ],:,p0:p1], half) # (d_X mu) (\nabla_x nu) DM_{mu,nu} half = pyscf.lib.dot(ao[1], dm0[:,p0:p1].copy()) rho1X[1] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[1] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[1] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) half = pyscf.lib.dot(ao[2], dm0[:,p0:p1].copy()) rho1X[2] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[2] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[2] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) half = pyscf.lib.dot(ao[3], dm0[:,p0:p1].copy()) rho1X[3] += numpy.einsum('pi,pi->p', ao[1,:,p0:p1], half) rho1Y[3] += numpy.einsum('pi,pi->p', ao[2,:,p0:p1], half) rho1Z[3] += numpy.einsum('pi,pi->p', ao[3,:,p0:p1], half) wv = get_wv(rho, rho1X, weight, vxc, fxc) * 2 # ~ vj1*2 aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv) # dX veff2[0] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv) # dY veff2[3] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv) # dZ veff2[6] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4]) veff2[0] += pyscf.lib.dot(ao[1].T, aow) veff2[3] += pyscf.lib.dot(ao[2].T, aow) veff2[6] += pyscf.lib.dot(ao[3].T, aow) wv = get_wv(rho, rho1Y, weight, vxc, fxc) * 2 aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv) veff2[1] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv) veff2[4] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv) veff2[7] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4]) veff2[1] += pyscf.lib.dot(ao[1].T, aow) veff2[4] += pyscf.lib.dot(ao[2].T, aow) veff2[7] += pyscf.lib.dot(ao[3].T, aow) wv = get_wv(rho, rho1Z, weight, vxc, fxc) * 2 aow = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv) veff2[2] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv) veff2[5] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv) veff2[8] += pyscf.lib.dot(aow.T, ao[0]) aow = numpy.einsum('npi,np->pi', ao[1:4], wv[1:4]) veff2[2] += pyscf.lib.dot(ao[1].T, aow) veff2[5] += pyscf.lib.dot(ao[2].T, aow) veff2[8] += pyscf.lib.dot(ao[3].T, aow) wv = numpy.empty_like(rho) wv[0] = weight * vrho * .5 wv[1:] = rho[1:] * (weight * vgamma * 2) aowx = numpy.einsum('npi,np->pi', ao[[1,XX,XY,XZ]], wv) aowy = numpy.einsum('npi,np->pi', ao[[2,YX,YY,YZ]], wv) aowz = numpy.einsum('npi,np->pi', ao[[3,ZX,ZY,ZZ]], wv) ao1 = aowx[:,p0:p1].T.copy() ao2 = aowy[:,p0:p1].T.copy() ao3 = aowz[:,p0:p1].T.copy() vj1[0] += pyscf.lib.dot(ao1, ao[1]) vj1[1] += pyscf.lib.dot(ao1, ao[2]) vj1[2] += pyscf.lib.dot(ao1, ao[3]) vj1[3] += pyscf.lib.dot(ao2, ao[1]) vj1[4] += pyscf.lib.dot(ao2, ao[2]) vj1[5] += pyscf.lib.dot(ao2, ao[3]) vj1[6] += pyscf.lib.dot(ao3, ao[1]) vj1[7] += pyscf.lib.dot(ao3, ao[2]) vj1[8] += pyscf.lib.dot(ao3, ao[3]) ao1 = ao[1,:,p0:p1].T.copy() ao2 = ao[2,:,p0:p1].T.copy() ao3 = ao[3,:,p0:p1].T.copy() vj1[0] += pyscf.lib.dot(ao1, aowx) vj1[1] += pyscf.lib.dot(ao1, aowy) vj1[2] += pyscf.lib.dot(ao1, aowz) vj1[3] += pyscf.lib.dot(ao2, aowx) vj1[4] += pyscf.lib.dot(ao2, aowy) vj1[5] += pyscf.lib.dot(ao2, aowz) vj1[6] += pyscf.lib.dot(ao3, aowx) vj1[7] += pyscf.lib.dot(ao3, aowy) vj1[8] += pyscf.lib.dot(ao3, aowz) veff2[:,:,p0:p1] += vj1.transpose(0,2,1) else: raise NotImplementedError('meta-GGA') for j0, ja in enumerate(atmlst): q0, q1 = offsetdic[ja][2:] # *2 for double occupancy, *2 for +c.c. mo1 = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_mo1/%d'%ja) h1ao = pyscf.lib.chkfile.load(hess_mf.chkfile, 'scf_h1ao/%d'%ia) dm1 = numpy.einsum('ypi,qi->ypq', mo1, mocc) de = numpy.einsum('xpq,ypq->xy', h1ao, dm1) * 4 dm1 = numpy.einsum('ypi,qi,i->ypq', mo1, mocc, mo_energy[:nocc]) de -= numpy.einsum('xpq,ypq->xy', s1ao, dm1) * 4 de -= numpy.einsum('xpq,ypq->xy', s1oo, e1s[j0]) * 2 de = de.reshape(-1) v2aa = rinv2aa[str(ja)].value v2ab = rinv2ab[str(ja)].value de += numpy.einsum('xpq,pq->x', v2aa[:,p0:p1], dm0[p0:p1])*2 de += numpy.einsum('xpq,pq->x', v2ab[:,p0:p1], dm0[p0:p1])*2 de += numpy.einsum('xpq,pq->x', h_2[:,:,q0:q1], dm0[:,q0:q1])*2 de += numpy.einsum('xpq,pq->x', veff2[:,q0:q1], dm0[q0:q1])*2 de -= numpy.einsum('xpq,pq->x', s1ab[:,p0:p1,q0:q1], dme0[p0:p1,q0:q1])*2 if ia == ja: de += numpy.einsum('xpq,pq->x', h1aa[:,p0:p1], dm0[p0:p1])*2 de -= numpy.einsum('xpq,pq->x', v2aa, dm0)*2 de -= numpy.einsum('xpq,pq->x', v2ab, dm0)*2 de += numpy.einsum('xpq,pq->x', veff1ii[:,p0:p1], dm0[p0:p1])*2 de -= numpy.einsum('xpq,pq->x', s1aa[:,p0:p1], dme0[p0:p1])*2 de2[i0,j0] = de.reshape(3,3) frinv.close() log.timer('RHF hessian', *time0) return de2