def _compute_multipole_potential_integrals(self, sites, orders, moments): orders = numpy.asarray(orders) if numpy.any(orders > 2): raise NotImplementedError("""Multipole potential integrals not implemented for order > 2.""") # order 0 fakemol = gto.fakemol_for_charges(sites) integral0 = df.incore.aux_e2(self.mol, fakemol, intor='int3c2e') moments_0 = numpy.array([m[0] for m in moments]) op = numpy.einsum('ijg,ga->ij', integral0, moments_0 * cppe.prefactors(0)) # order 1 if numpy.any(orders >= 1): idx = numpy.where(orders >= 1)[0] fakemol = gto.fakemol_for_charges(sites[idx]) integral1 = df.incore.aux_e2(self.mol, fakemol, intor='int3c2e_ip1') moments_1 = numpy.array([moments[i][1] for i in idx]) v = numpy.einsum('aijg,ga,a->ij', integral1, moments_1, cppe.prefactors(1)) op += v + v.T if numpy.any(orders >= 2): idx = numpy.where(orders >= 2)[0] fakemol = gto.fakemol_for_charges(sites[idx]) n_sites = idx.size # moments_2 is the lower triangler of # [[XX, XY, XZ], [YX, YY, YZ], [ZX, ZY, ZZ]] i.e. # XX, XY, XZ, YY, YZ, ZZ = 0,1,2,4,5,8 # symmetrize it to the upper triangler part # XX, YX, ZX, YY, ZY, ZZ = 0,3,6,4,7,8 m2 = numpy.einsum('ga,a->ga', [moments[i][2] for i in idx], cppe.prefactors(2)) moments_2 = numpy.zeros((n_sites, 9)) moments_2[:, [0, 1, 2, 4, 5, 8]] = m2 moments_2[:, [0, 3, 6, 4, 7, 8]] += m2 moments_2 *= .5 integral2 = df.incore.aux_e2(self.mol, fakemol, intor='int3c2e_ipip1') v = numpy.einsum('aijg,ga->ij', integral2, moments_2) op += v + v.T integral2 = df.incore.aux_e2(self.mol, fakemol, intor='int3c2e_ipvip1') op += numpy.einsum('aijg,ga->ij', integral2, moments_2) * 2 return op
def test_int1e_grids_spvsp(self): ngrids = 201 grids = numpy.random.random((ngrids, 3)) * 12 - 5 fmol = gto.fakemol_for_charges(grids) ref = df.r_incore.aux_e2(mol, fmol, intor='int3c2e_spsp1_spinor').transpose(2,0,1) j3c = mol.intor('int1e_grids_spvsp_spinor', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12)
def get_hcore(self, mol=None): if mol is None: mol = self.mol if hasattr(scf_method, 'get_hcore'): h1e = method_class.get_hcore(self, mol) else: # DO NOT modify post-HF objects to avoid the MM charges applied twice raise RuntimeError('mm_charge function cannot be applied on post-HF methods') if pyscf.DEBUG: v = 0 for i,q in enumerate(charges): mol.set_rinv_origin(coords[i]) v += mol.intor('int1e_rinv') * -q else: if mol.cart: intor = 'int3c2e_cart' else: intor = 'int3c2e_sph' nao = mol.nao max_memory = self.max_memory - lib.current_memory()[0] blksize = int(max(max_memory*1e6/8/nao**2, 400)) v = 0 for i0, i1 in lib.prange(0, charges.size, blksize): fakemol = gto.fakemol_for_charges(coords[i0:i1]) j3c = df.incore.aux_e2(mol, fakemol, intor=intor, aosym='s2ij') v += numpy.einsum('xk,k->x', j3c, -charges[i0:i1]) v = lib.unpack_tril(v) return h1e + v
def test_range_separated_coulomb_int1e_grids(self): mol1 = gto.M(atom=''' O 0.5 0.5 0. H 1. 1.2 0. H 0. 0. 1.3''', basis='ccpvtz') ngrids = 201 grids = numpy.random.random((ngrids, 3)) * 12 - 5 fmol = gto.fakemol_for_charges(grids) with mol1.with_range_coulomb(.8): ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e').transpose(2,0,1) j3c = mol1.intor('int1e_grids', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12) ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e_cart').transpose(2,0,1) j3c = mol1.intor('int1e_grids_cart', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12) ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e_spinor').transpose(2,0,1) j3c = mol1.intor('int1e_grids_spinor', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12) with mol1.with_range_coulomb(-.8): ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e').transpose(2,0,1) j3c = mol1.intor('int1e_grids', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12) ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e_cart').transpose(2,0,1) j3c = mol1.intor('int1e_grids_cart', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12) ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e_spinor').transpose(2,0,1) j3c = mol1.intor('int1e_grids_spinor', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12)
def jk_part(mol, grid_coords, dms, fg): # transfer bvv to SGXsetnr_direct_scf_blk. from _vhf.VHFOpt # need add mol._bvv in scf.mole.py c_bvv = numpy.asarray(mol._bvv, dtype=numpy.int32, order='C') nbvv = ctypes.c_int(c_bvv.shape[0]) ao_loc = make_loc(c_bas, intor) fsetqcond = getattr(libcvhf, 'SGXsetnr_direct_scf_blk') fsetqcond(vhfopt._this, getattr(libcvhf, intor), lib.c_null_ptr(), ao_loc.ctypes.data_as(ctypes.c_void_p), c_atm.ctypes.data_as(ctypes.c_void_p), natm, c_bas.ctypes.data_as(ctypes.c_void_p), nbas, c_env.ctypes.data_as(ctypes.c_void_p), c_bvv.ctypes.data_as(ctypes.c_void_p), nbvv) fakemol = gto.fakemol_for_charges(grid_coords) atm, bas, env = gto.mole.conc_env(mol._atm, mol._bas, mol._env, fakemol._atm, fakemol._bas, fakemol._env) ao_loc = moleintor.make_loc(bas, intor) shls_slice = (0, mol.nbas, 0, mol.nbas, mol.nbas, len(bas)) ngrids = grid_coords.shape[0] vj = vk = None fjk = [] dmsptr = [] vjkptr = [] if with_j: if dms[0].ndim == 1: # the value of density at each grid vj = numpy.zeros((len(dms), ncomp, nao, nao))[:, 0] for i, dm in enumerate(dms): dmsptr.append(dm.ctypes.data_as(ctypes.c_void_p)) vjkptr.append(vj[i].ctypes.data_as(ctypes.c_void_p)) fjk.append(_vhf._fpointer('SGXnr' + aosym + '_ijg_g_ij')) else: vj = numpy.zeros((len(dms), ncomp, ngrids))[:, 0] for i, dm in enumerate(dms): dmsptr.append(dm.ctypes.data_as(ctypes.c_void_p)) vjkptr.append(vj[i].ctypes.data_as(ctypes.c_void_p)) fjk.append(_vhf._fpointer('SGXnr' + aosym + '_ijg_ji_g')) if with_k: vk = numpy.zeros((len(fg), ncomp, ngrids, nao))[:, 0] for i, dm in enumerate(fg): dmsptr.append(dm.ctypes.data_as(ctypes.c_void_p)) vjkptr.append(vk[i].ctypes.data_as(ctypes.c_void_p)) fjk.append(_vhf._fpointer('SGXnr' + aosym + '_ijg_gj_gi')) n_dm = len(fjk) fjk = (ctypes.c_void_p * (n_dm))(*fjk) dmsptr = (ctypes.c_void_p * (n_dm))(*dmsptr) vjkptr = (ctypes.c_void_p * (n_dm))(*vjkptr) drv(cintor, fdot, fjk, dmsptr, vjkptr, n_dm, ncomp, (ctypes.c_int * 6)(*shls_slice), ao_loc.ctypes.data_as(ctypes.c_void_p), cintopt, vhfopt._this, atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.natm), bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.nbas), env.ctypes.data_as(ctypes.c_void_p)) return vj, vk
def _compute_field_integrals(self, sites, moments): mol = self.mol fakemol = gto.fakemol_for_charges(sites) j3c = df.incore.aux_e2(mol, fakemol, intor='int3c2e_ip1') op = numpy.einsum('aijg,nga->nij', j3c, -moments) op = op + op.transpose(0, 2, 1) return op
def _compute_field(self, sites, Ds): mol = self.mol fakemol = gto.fakemol_for_charges(sites) j3c = df.incore.aux_e2(mol, fakemol, intor='int3c2e_ip1') field = (numpy.einsum('aijg,nij->nga', j3c, Ds) + numpy.einsum('aijg,nji->nga', j3c, Ds)) return field
def get_hcore(self, mol=None): ''' (QM 1e grad) + <-d/dX i|q_mm/r_mm|j>''' if mol is None: mol = self.mol coords = self.base.mm_mol.atom_coords() charges = self.base.mm_mol.atom_charges() g_qm = grad_class.get_hcore(self, mol) nao = g_qm.shape[1] if pyscf.DEBUG: v = 0 for i, q in enumerate(charges): mol.set_rinv_origin(coords[i]) v += mol.intor('int1e_iprinv', comp=3) * q else: if mol.cart: intor = 'int3c2e_ip1_cart' else: intor = 'int3c2e_ip1_sph' nao = mol.nao max_memory = self.max_memory - lib.current_memory()[0] blksize = int(min(max_memory * 1e6 / 8 / nao**2, 200)) cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, intor) v = 0 for i0, i1 in lib.prange(0, charges.size, blksize): fakemol = gto.fakemol_for_charges(coords[i0:i1]) j3c = df.incore.aux_e2(mol, fakemol, intor, aosym='s1', comp=3, cintopt=cintopt) v += numpy.einsum('ipqk,k->ipq', j3c, charges[i0:i1]) return g_qm + v
def mep(surface, mol, dm): '''Calculate the MEP, by taking each point on the density isosurface. Returned as a NumPy array. ''' coords = np.asarray([surface[i][1:] for i in range(len(surface))]) #Nuclear potential at given points Vnuc = 0 for i in range(mol.natm): r = mol.atom_coord(i) Z = mol.atom_charge(i) rp = r - coords Vnuc += Z / np.einsum('xi,xi->x', rp, rp)**.5 #Potential of electron density Vele = np.empty_like(Vnuc) for p0, p1 in lib.prange(0, Vele.size, 600): fakemol = gto.fakemol_for_charges(coords[p0:p1]) ints = df.incore.aux_e2(mol, fakemol) Vele[p0:p1] = np.einsum('ijp,ij->p', ints, dm) MEP = Vnuc - Vele mep_arr = surface for i in range(len(mep_arr)): mep_arr[i][0] = MEP[i] return mep_arr
def get_hcore(self, mol=None): if mol is None: mol = self.mol if getattr(scf_method, 'get_hcore', None): h1e = method_class.get_hcore(self, mol) else: # DO NOT modify post-HF objects to avoid the MM charges applied twice raise RuntimeError('mm_charge function cannot be applied on post-HF methods') if pyscf.DEBUG: v = 0 for i,q in enumerate(charges): mol.set_rinv_origin(coords[i]) v += mol.intor('int1e_rinv') * -q else: if mol.cart: intor = 'int3c2e_cart' else: intor = 'int3c2e_sph' nao = mol.nao max_memory = self.max_memory - lib.current_memory()[0] blksize = int(min(max_memory*1e6/8/nao**2, 200)) v = 0 for i0, i1 in lib.prange(0, charges.size, blksize): fakemol = gto.fakemol_for_charges(coords[i0:i1]) j3c = df.incore.aux_e2(mol, fakemol, intor=intor, aosym='s2ij') v += numpy.einsum('xk,k->x', j3c, -charges[i0:i1]) v = lib.unpack_tril(v) return h1e + v
def mep(mol, outfile, dm, nx=80, ny=80, nz=80, resolution=RESOLUTION, margin=BOX_MARGIN): """Calculates the molecular electrostatic potential (MEP) and write out in cube format. Args: mol : Mole Molecule to calculate the electron density for. outfile : str Name of Cube file to be written. dm : ndarray Density matrix of molecule. Kwargs: nx : int Number of grid point divisions in x direction. Note this is function of the molecule's size; a larger molecule will have a coarser representation than a smaller one for the same value. Conflicts to keyword resolution. ny : int Number of grid point divisions in y direction. nz : int Number of grid point divisions in z direction. resolution: float Resolution of the mesh grid in the cube box. If resolution is given in the input, the input nx/ny/nz have no effects. The value of nx/ny/nz will be determined by the resolution and the cube box size. """ cc = Cube(mol, nx, ny, nz, resolution, margin) coords = cc.get_coords() # Nuclear potential at given points Vnuc = 0 for i in range(mol.natm): r = mol.atom_coord(i) Z = mol.atom_charge(i) rp = r - coords Vnuc += Z / numpy.einsum('xi,xi->x', rp, rp)**.5 # Potential of electron density Vele = numpy.empty_like(Vnuc) for p0, p1 in lib.prange(0, Vele.size, 600): fakemol = gto.fakemol_for_charges(coords[p0:p1]) ints = df.incore.aux_e2(mol, fakemol) Vele[p0:p1] = numpy.einsum('ijp,ij->p', ints, dm) MEP = Vnuc - Vele # MEP at each point MEP = MEP.reshape(cc.nx, cc.ny, cc.nz) # Write the potential cc.write(MEP, outfile, 'Molecular electrostatic potential in real space') return MEP
def batch_nuc(mol, grid_coords, out=None): fakemol = gto.fakemol_for_charges(grid_coords) j3c = aux_e2(mol, fakemol, intor='int3c2e', aosym='s2ij', cintopt=cintopt) return lib.unpack_tril(j3c.T, out=out)
def make_B(pcmobj, r_vdw, ui, ylm_1sph, cached_pol, L): '''0th order''' mol = pcmobj.mol coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] mol = pcmobj.mol natm = mol.natm nao = mol.nao lmax = pcmobj.lmax nlm = (lmax + 1)**2 atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() grids = pcmobj.grids extern_point_idx = ui > 0 cav_coords = (atom_coords.reshape(natm, 1, 3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) cav_coords = cav_coords[extern_point_idx] int3c2e = mol._add_suffix('int3c2e') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e) fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1', cintopt=cintopt) nao_pair = v_nj.shape[0] v_phi = numpy.zeros((natm, ngrid_1sph, nao, nao)) v_phi[extern_point_idx] += v_nj.transpose(2, 0, 1) phi = numpy.einsum('n,xn,jn,jnpq->jxpq', weights_1sph, ylm_1sph, ui, v_phi) Xvec = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi.reshape(natm * nlm, -1)) Xvec = Xvec.reshape(natm, nlm, nao, nao) ao = mol.eval_gto('GTOval', grids.coords) aow = numpy.einsum('gi,g->gi', ao, grids.weights) aopair = numpy.einsum('gi,gj->gij', ao, aow) psi = numpy.zeros((natm, nlm, nao, nao)) i1 = 0 for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] i0, i1 = i1, i1 + fak_pol[0].shape[1] p1 = 0 for l in range(lmax + 1): fac = 4 * numpy.pi / (l * 2 + 1) p0, p1 = p1, p1 + (l * 2 + 1) psi[ia, p0:p1] = -fac * numpy.einsum('mn,nij->mij', fak_pol[l], aopair[i0:i1]) B = lib.einsum('nlpq,nlrs->pqrs', psi, Xvec) B = B + B.transpose(2, 3, 0, 1) return B
def make_phi(pcmobj, dm, r_vdw, ui, ylm_1sph, with_nuc=True): ''' Induced potential of ddCOSMO model Kwargs: with_nuc (bool): Mute the contribution of nuclear charges when computing the second order derivatives of energy ''' mol = pcmobj.mol natm = mol.natm coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] dms = numpy.asarray(dm) is_single_dm = dms.ndim == 2 nao = dms.shape[-1] dms = dms.reshape(-1,nao,nao) n_dm = dms.shape[0] diagidx = numpy.arange(nao) diagidx = diagidx*(diagidx+1)//2 + diagidx tril_dm = lib.pack_tril(dms+dms.transpose(0,2,1)) tril_dm[:,diagidx] *= .5 atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() extern_point_idx = ui > 0 cav_coords = (atom_coords.reshape(natm,1,3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) v_phi = numpy.zeros((n_dm, natm, ngrid_1sph)) if with_nuc: for ia in range(natm): # Note (-) sign is not applied to atom_charges, because (-) is explicitly # included in rhs and L matrix d_rs = atom_coords.reshape(-1,1,3) - cav_coords[ia] v_phi[:,ia] = numpy.einsum('z,zp->p', atom_charges, 1./lib.norm(d_rs,axis=2)) max_memory = pcmobj.max_memory - lib.current_memory()[0] blksize = int(max(max_memory*.9e6/8/nao**2, 400)) cav_coords = cav_coords[extern_point_idx] v_phi_e = numpy.empty((n_dm, cav_coords.shape[0])) int3c2e = mol._add_suffix('int3c2e') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e) for i0, i1 in lib.prange(0, cav_coords.shape[0], blksize): fakemol = gto.fakemol_for_charges(cav_coords[i0:i1]) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s2ij', cintopt=cintopt) v_phi_e[:,i0:i1] = numpy.einsum('nx,xk->nk', tril_dm, v_nj) v_phi[:,extern_point_idx] -= v_phi_e phi = -numpy.einsum('n,xn,jn,ijn->ijx', weights_1sph, ylm_1sph, ui, v_phi) if is_single_dm: phi = phi[0] return phi
def make_phi(pcmobj, dm, r_vdw, ui): mol = pcmobj.mol natm = mol.natm coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): dm = dm[0] + dm[1] tril_dm = lib.pack_tril(dm + dm.T) nao = dm.shape[0] diagidx = numpy.arange(nao) diagidx = diagidx * (diagidx + 1) // 2 + diagidx tril_dm[diagidx] *= .5 atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() extern_point_idx = ui > 0 cav_coords = (atom_coords.reshape(natm, 1, 3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) v_phi = numpy.empty((natm, ngrid_1sph)) for ia in range(natm): # Note (-) sign is not applied to atom_charges, because (-) is explicitly # included in rhs and L matrix d_rs = atom_coords.reshape(-1, 1, 3) - cav_coords[ia] v_phi[ia] = numpy.einsum('z,zp->p', atom_charges, 1. / lib.norm(d_rs, axis=2)) max_memory = pcmobj.max_memory - lib.current_memory()[0] blksize = int(max(max_memory * 1e6 / 8 / nao**2, 400)) cav_coords = cav_coords[extern_point_idx] v_phi_e = numpy.empty(cav_coords.shape[0]) int3c2e = mol._add_suffix('int3c2e') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e) for i0, i1 in lib.prange(0, cav_coords.shape[0], blksize): fakemol = gto.fakemol_for_charges(cav_coords[i0:i1]) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s2ij', cintopt=cintopt) v_phi_e[i0:i1] = numpy.einsum('x,xk->k', tril_dm, v_nj) v_phi[extern_point_idx] -= v_phi_e ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True)) phi = -numpy.einsum('n,xn,jn,jn->jx', weights_1sph, ylm_1sph, ui, v_phi) return phi
def test_fakemol(self): numpy.random.seed(1) coords = numpy.random.random((6,3))*4 vref = 0 mol = mol0.copy() for c in coords: mol.set_rinv_origin(c) vref += mol.intor('int1e_rinv') fakemol = gto.fakemol_for_charges(coords) pmol = mol + fakemol shls_slice = (0, mol.nbas, 0, mol.nbas, mol.nbas, pmol.nbas) v = pmol.intor('int3c2e', comp=1, shls_slice=shls_slice) v = numpy.einsum('pqk->pq', v) self.assertAlmostEqual(abs(vref-v).max(), 0, 12)
def test_fakemol(self): numpy.random.seed(1) coords = numpy.random.random((6, 3)) * 4 vref = 0 mol = mol0.copy() for c in coords: mol.set_rinv_origin(c) vref += mol.intor('int1e_rinv') fakemol = gto.fakemol_for_charges(coords) pmol = mol + fakemol shls_slice = (0, mol.nbas, 0, mol.nbas, mol.nbas, pmol.nbas) v = pmol.intor('int3c2e', comp=1, shls_slice=shls_slice) v = numpy.einsum('pqk->pq', v) self.assertAlmostEqual(abs(vref - v).max(), 0, 12)
def test_int1e_grids_ip(self): ngrids = 201 grids = numpy.random.random((ngrids, 3)) * 12 - 5 fmol = gto.fakemol_for_charges(grids) ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e_ip1').transpose(0,3,1,2) j3c = mol1.intor('int1e_grids_ip', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12) ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e_ip1_cart').transpose(0,3,1,2) j3c = mol1.intor('int1e_grids_ip_cart', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12) ref = df.incore.aux_e2(mol1, fmol, intor='int3c2e_ip1_spinor').transpose(0,3,1,2) j3c = mol1.intor('int1e_grids_ip_spinor', grids=grids) self.assertAlmostEqual(abs(j3c - ref).max(), 0, 12)
def mep(mol, outfile, dm, nx=80, ny=80, nz=80, resolution=RESOLUTION): """Calculates the molecular electrostatic potential (MEP) and write out in cube format. Args: mol : Mole Molecule to calculate the electron density for. outfile : str Name of Cube file to be written. dm : ndarray Density matrix of molecule. Kwargs: nx : int Number of grid point divisions in x direction. Note this is function of the molecule's size; a larger molecule will have a coarser representation than a smaller one for the same value. ny : int Number of grid point divisions in y direction. nz : int Number of grid point divisions in z direction. """ cc = Cube(mol, nx, ny, nz, resolution) coords = cc.get_coords() # Nuclear potential at given points Vnuc = 0 for i in range(mol.natm): r = mol.atom_coord(i) Z = mol.atom_charge(i) rp = r - coords Vnuc += Z / numpy.einsum('xi,xi->x', rp, rp)**.5 # Potential of electron density Vele = numpy.empty_like(Vnuc) for p0, p1 in lib.prange(0, Vele.size, 600): fakemol = gto.fakemol_for_charges(coords[p0:p1]) ints = df.incore.aux_e2(mol, fakemol) Vele[p0:p1] = numpy.einsum('ijp,ij->p', ints, dm) MEP = Vnuc - Vele # MEP at each point MEP = MEP.reshape(nx,ny,nz) # Write the potential cc.write(MEP, outfile, 'Molecular electrostatic potential in real space')
def effective_dipole_operator(self): """ Compute the derivatives of induced moments wrt each coordinate and form integrals for effective dipole operator (EEF) """ dips = self.mol.intor_symmetric('int1e_r', comp=3) if self.eef: logger.info(self, "Computing effective dipole operator for EEF.") positions = self.cppe_state.positions_polarizable n_sites = positions.shape[0] induced_moments = self.cppe_state.induced_moments_eef() induced_moments = induced_moments.reshape(n_sites, 3, 3) fakemol = gto.fakemol_for_charges(positions) j3c = df.incore.aux_e2(self.mol, fakemol, intor='int3c2e_ip1') V_ind = numpy.einsum('aijg,gax->xij', j3c, -induced_moments) dips += V_ind + V_ind.transpose(0, 2, 1) return list(dips)
def jk_part(mol, grid_coords, dms, fg): fakemol = gto.fakemol_for_charges(grid_coords) atm, bas, env = gto.mole.conc_env(mol._atm, mol._bas, mol._env, fakemol._atm, fakemol._bas, fakemol._env) ao_loc = moleintor.make_loc(bas, sgxopt._intor) shls_slice = (0, mol.nbas, 0, mol.nbas, mol.nbas, len(bas)) ngrids = grid_coords.shape[0] vj = vk = None fjk = [] dmsptr = [] vjkptr = [] if with_j: if dms[0].ndim == 1: # the value of density at each grid vj = numpy.zeros((len(dms),ncomp,nao,nao))[:,0] for i, dm in enumerate(dms): dmsptr.append(dm.ctypes.data_as(ctypes.c_void_p)) vjkptr.append(vj[i].ctypes.data_as(ctypes.c_void_p)) fjk.append(_vhf._fpointer('SGXnr'+aosym+'_ijg_g_ij')) else: vj = numpy.zeros((len(dms),ncomp,ngrids))[:,0] for i, dm in enumerate(dms): dmsptr.append(dm.ctypes.data_as(ctypes.c_void_p)) vjkptr.append(vj[i].ctypes.data_as(ctypes.c_void_p)) fjk.append(_vhf._fpointer('SGXnr'+aosym+'_ijg_ji_g')) if with_k: vk = numpy.zeros((len(fg),ncomp,ngrids,nao))[:,0] for i, dm in enumerate(fg): dmsptr.append(dm.ctypes.data_as(ctypes.c_void_p)) vjkptr.append(vk[i].ctypes.data_as(ctypes.c_void_p)) fjk.append(_vhf._fpointer('SGXnr'+aosym+'_ijg_gj_gi')) n_dm = len(fjk) fjk = (ctypes.c_void_p*(n_dm))(*fjk) dmsptr = (ctypes.c_void_p*(n_dm))(*dmsptr) vjkptr = (ctypes.c_void_p*(n_dm))(*vjkptr) drv(cintor, fdot, fjk, dmsptr, vjkptr, n_dm, ncomp, (ctypes.c_int*6)(*shls_slice), ao_loc.ctypes.data_as(ctypes.c_void_p), sgxopt._cintopt, sgxopt._this, atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.natm), bas.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(mol.nbas), env.ctypes.data_as(ctypes.c_void_p)) return vj, vk
def make_phi(pcmobj, dm, r_vdw, ui): mol = pcmobj.mol natm = mol.natm coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): dm = dm[0] + dm[1] tril_dm = lib.pack_tril(dm+dm.T) nao = dm.shape[0] diagidx = numpy.arange(nao) diagidx = diagidx*(diagidx+1)//2 + diagidx tril_dm[diagidx] *= .5 atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() extern_point_idx = ui > 0 cav_coords = (atom_coords.reshape(natm,1,3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) v_phi = numpy.empty((natm,ngrid_1sph)) for ia in range(natm): # Note (-) sign is not applied to atom_charges, because (-) is explicitly # included in rhs and L matrix d_rs = atom_coords.reshape(-1,1,3) - cav_coords[ia] v_phi[ia] = numpy.einsum('z,zp->p', atom_charges, 1./lib.norm(d_rs,axis=2)) max_memory = pcmobj.max_memory - lib.current_memory()[0] blksize = int(max(max_memory*1e6/8/nao**2, 400)) cav_coords = cav_coords[extern_point_idx] v_phi_e = numpy.empty(cav_coords.shape[0]) int3c2e = mol._add_suffix('int3c2e') for i0, i1 in lib.prange(0, cav_coords.shape[0], blksize): fakemol = gto.fakemol_for_charges(cav_coords[i0:i1]) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s2ij') v_phi_e[i0:i1] = numpy.einsum('x,xk->k', tril_dm, v_nj) v_phi[extern_point_idx] -= v_phi_e ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True)) phi = -numpy.einsum('n,xn,jn,jn->jx', weights_1sph, ylm_1sph, ui, v_phi) return phi
def get_hcore(self, mol=None): ''' (QM 1e grad) + <-d/dX i|q_mm/r_mm|j>''' if mol is None: mol = self.mol g_qm = scf_grad.get_hcore(mol) nao = g_qm.shape[1] if pyscf.DEBUG: v = 0 for i, q in enumerate(charges): mol.set_rinv_origin(coords[i]) v += mol.intor('int1e_iprinv', comp=3) * q else: fakemol = gto.fakemol_for_charges(coords) j3c = df.incore.aux_e2(mol, fakemol, intor='int3c2e_ip1', aosym='s1', comp=3) v = numpy.einsum('ipqk,k->ipq', j3c, charges) return scf_grad.get_hcore(mol) + v
def get_hcore(self, mol=None): if mol is None: mol = self.mol if getattr(method_class, 'get_hcore', None): h1e = method_class.get_hcore(self, mol) else: # DO NOT modify post-HF objects to avoid the MM charges applied twice raise RuntimeError( 'mm_charge function cannot be applied on post-HF methods') coords = self.mm_mol.atom_coords() charges = self.mm_mol.atom_charges() if pyscf.DEBUG: v = 0 for i, q in enumerate(charges): mol.set_rinv_origin(coords[i]) v += mol.intor('int1e_rinv') * -q else: if mol.cart: intor = 'int3c2e_cart' else: intor = 'int3c2e_sph' nao = mol.nao max_memory = self.max_memory - lib.current_memory()[0] blksize = int(min(max_memory * 1e6 / 8 / nao**2, 200)) if max_memory <= 0: blksize = 1 logger.warn( self, 'Memory estimate for reading point charges is negative. ' 'Trying to read point charges one by one.') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, intor) v = 0 for i0, i1 in lib.prange(0, charges.size, blksize): fakemol = gto.fakemol_for_charges(coords[i0:i1]) j3c = df.incore.aux_e2(mol, fakemol, intor=intor, aosym='s2ij', cintopt=cintopt) v += numpy.einsum('xk,k->x', j3c, -charges[i0:i1]) v = lib.unpack_tril(v) return h1e + v
def _mm_pot(mol: gto.Mole, mm_mol: gto.Mole) -> np.ndarray: """ this function returns the full mm potential (adapted from: qmmm/itrf.py:get_hcore() in PySCF) """ # settings coords = mm_mol.atom_coords() charges = mm_mol.atom_charges() blksize = BLKSIZE # integrals intor = 'int3c2e_cart' if mol.cart else 'int3c2e_sph' cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, intor) # compute interaction potential mm_pot = 0 for i0, i1 in lib.prange(0, charges.size, blksize): fakemol = gto.fakemol_for_charges(coords[i0:i1]) j3c = df.incore.aux_e2(mol, fakemol, intor=intor, aosym='s2ij', cintopt=cintopt) mm_pot += np.einsum('xk,k->x', j3c, -charges[i0:i1]) mm_pot = lib.unpack_tril(mm_pot) return mm_pot
def get_hcore(self, mol=None): if mol is None: mol = self.mol if hasattr(scf_method, 'get_hcore'): h1e = method_class.get_hcore(self, mol) else: # DO NOT modify post-HF objects to avoid the MM charges applied twice raise RuntimeError( 'mm_charge function cannot be applied on post-HF methods') if pyscf.DEBUG: v = 0 for i, q in enumerate(charges): mol.set_rinv_origin(coords[i]) v += mol.intor('int1e_rinv') * -q else: fakemol = gto.fakemol_for_charges(coords) if mol.cart: intor = 'int3c2e_cart' else: intor = 'int3c2e_sph' j3c = df.incore.aux_e2(mol, fakemol, intor=intor, aosym='s2ij') v = lib.unpack_tril(numpy.einsum('xk,k->x', j3c, -charges)) return h1e + v
def inter_elecbg(mol, dm, coords, charges): r""" inter energy between electrons in real frags and background charges """ if mol.cart: intor = 'int3c2e_cart' else: intor = 'int3c2e_sph' nao = mol.nao #max_memory = mol.max_memory - lib.current_memory()[0] #blksize = int(min(max_memory * 1e6 / 8 / nao**2, 200)) #print(coords,'\n',len(coords)) vc = np.zeros((nao, nao)) for i in range(0, charges.size): fakemol = gto.fakemol_for_charges(coords[i:i + 1]) j3c = df.incore.aux_e2(mol, fakemol, intor=intor, aosym='s2ij') v = np.einsum('xk,k->x', j3c, -charges[i:i + 1]) v = lib.unpack_tril(v) #print(vc.shape, v.shape) vc += v #E = np.einsum('ij,ji', v, dm) #print("inter_elecbg: %f" % E) return vc
def get_hcore(self, mol=None): ''' (QM 1e grad) + <-d/dX i|q_mm/r_mm|j>''' if mol is None: mol = self.mol g_qm = grad_class.get_hcore(self, mol) nao = g_qm.shape[1] if pyscf.DEBUG: v = 0 for i,q in enumerate(charges): mol.set_rinv_origin(coords[i]) v += mol.intor('int1e_iprinv', comp=3) * q else: if mol.cart: intor = 'int3c2e_ip1_cart' else: intor = 'int3c2e_ip1_sph' nao = mol.nao max_memory = self.max_memory - lib.current_memory()[0] blksize = int(min(max_memory*1e6/8/nao**2, 200)) v = 0 for i0, i1 in lib.prange(0, charges.size, blksize): fakemol = gto.fakemol_for_charges(coords[i0:i1]) j3c = df.incore.aux_e2(mol, fakemol, intor, aosym='s1', comp=3) v += numpy.einsum('ipqk,k->ipq', j3c, charges[i0:i1]) return g_qm + v
def get_hcore(self, mol=None): ''' (QM 1e grad) + <-d/dX i|q_mm/r_mm|j>''' if mol is None: mol = self.mol g_qm = scf_grad.get_hcore(mol) nao = g_qm.shape[1] if pyscf.DEBUG: v = 0 for i,q in enumerate(charges): mol.set_rinv_origin(coords[i]) v += mol.intor('int1e_iprinv', comp=3) * q else: if mol.cart: intor = 'int3c2e_ip1_cart' else: intor = 'int3c2e_ip1_sph' nao = mol.nao max_memory = self.max_memory - lib.current_memory()[0] blksize = int(max(max_memory*1e6/8/nao**2, 400)) v = 0 for i0, i1 in lib.prange(0, charges.size, blksize): fakemol = gto.fakemol_for_charges(coords[i0:i1]) j3c = df.incore.aux_e2(mol, fakemol, intor, aosym='s1', comp=3) v += numpy.einsum('ipqk,k->ipq', j3c, charges[i0:i1]) return scf_grad.get_hcore(mol) + v
def make_psi_vmat(pcmobj, dm, r_vdw, ui, grids, ylm_1sph, cached_pol, L_X, L): mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax nlm = (lmax+1)**2 i1 = 0 scaled_weights = numpy.empty(grids.weights.size) for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] i0, i1 = i1, i1 + fak_pol[0].shape[1] eta_nj = 0 p1 = 0 for l in range(lmax+1): fac = 4*numpy.pi/(l*2+1) p0, p1 = p1, p1 + (l*2+1) eta_nj += fac * numpy.einsum('mn,m->n', fak_pol[l], L_X[ia,p0:p1]) scaled_weights[i0:i1] = eta_nj * grids.weights[i0:i1] if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): dm = dm[0] + dm[1] ni = numint.NumInt() max_memory = pcmobj.max_memory - lib.current_memory()[0] make_rho, nset, nao = ni._gen_rho_evaluator(mol, dm) shls_slice = (0, mol.nbas) ao_loc = mol.ao_loc_nr() den = numpy.empty(grids.weights.size) vmat = numpy.zeros((nao,nao)) p1 = 0 aow = None for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, 0, max_memory): p0, p1 = p1, p1 + weight.size den[p0:p1] = weight * make_rho(0, ao, mask, 'LDA') aow = numpy.ndarray(ao.shape, order='F', buffer=aow) aow = numpy.einsum('pi,p->pi', ao, scaled_weights[p0:p1], out=aow) vmat -= numint._dot_ao_ao(mol, ao, aow, mask, shls_slice, ao_loc) ao = aow = scaled_weights = None nelec_leak = 0 psi = numpy.empty((natm,nlm)) i1 = 0 for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] i0, i1 = i1, i1 + fak_pol[0].shape[1] nelec_leak += den[i0:i1][leak_idx].sum() p1 = 0 for l in range(lmax+1): fac = 4*numpy.pi/(l*2+1) p0, p1 = p1, p1 + (l*2+1) psi[ia,p0:p1] = -fac * numpy.einsum('n,mn->m', den[i0:i1], fak_pol[l]) # Contribution of nuclear charge to the total density # The factor numpy.sqrt(4*numpy.pi) is due to the product of 4*pi * Y_0^0 psi[ia,0] += numpy.sqrt(4*numpy.pi)/r_vdw[ia] * mol.atom_charge(ia) logger.debug(pcmobj, 'electron leak %f', nelec_leak) # <Psi, L^{-1}g> -> Psi = SL the adjoint equation to LX = g L_S = numpy.linalg.solve(L.T.reshape(natm*nlm,-1), psi.ravel()).reshape(natm,-1) coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order) # JCP, 141, 184108, Eq (39) xi_jn = numpy.einsum('n,jn,xn,jx->jn', weights_1sph, ui, ylm_1sph, L_S) extern_point_idx = ui > 0 cav_coords = (mol.atom_coords().reshape(natm,1,3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) cav_coords = cav_coords[extern_point_idx] xi_jn = xi_jn[extern_point_idx] max_memory = pcmobj.max_memory - lib.current_memory()[0] blksize = int(max(max_memory*1e6/8/nao**2, 400)) vmat_tril = 0 for i0, i1 in lib.prange(0, xi_jn.size, blksize): fakemol = gto.fakemol_for_charges(cav_coords[i0:i1]) v_nj = df.incore.aux_e2(mol, fakemol, intor='int3c2e', aosym='s2ij') vmat_tril += numpy.einsum('xn,n->x', v_nj, xi_jn[i0:i1]) vmat += lib.unpack_tril(vmat_tril) return psi, vmat, L_S
def get_jk(mol_or_mf, dm, hermi, dmcur, *args, **kwargs): '''MPI version of scf.hf.get_jk function''' #vj = get_j(mol_or_mf, dm, hermi) #vk = get_k(mol_or_mf, dm, hermi) if isinstance(mol_or_mf, gto.mole.Mole): mf = hf.SCF(mol_or_mf).view(SCF) else: mf = mol_or_mf # dm may be too big for mpi4py library to serialize. Broadcast dm here. if any(comm.allgather(isinstance(dm, str) and dm == 'SKIPPED_ARG')): dm = mpi.bcast_tagged_array_occdf(dm) mf.unpack_(comm.bcast(mf.pack())) # initial and final grids level grdlvl_i = 0 grdlvl_f = 1 # norm_ddm threshold for grids change thrd_nddm = 0.2 # set block size to adapt memory sblk = 200 # interspace betweeen v shell intsp = 1 # threshold for u and v gthrdu = 1e-10 gthrdvs = 1e-10 gthrdvd = 1e-10 global cond, wao_vx, ngridsx, coordsx, gridatm dms = numpy.asarray(dm) dm_shape = dms.shape nao = dm_shape[-1] dms = dms.reshape(-1,nao,nao) nset = dms.shape[0] vj = [0] * nset vk = [0] * nset # DF-J and sgX set mf.with_df = mf mol = mf.mol global int2c, ovlp, ao_loc, rao_loc # use mf.opt to calc int2c once, cond, dm0, and rao, ao_loc, ovlp for sgX if mf.opt is None: mf.opt = mf.init_direct_scf() cond = 0 # set auxbasis in input file, need self.auxbasis = None in __init__ of hf.py # mf.auxbasis = 'weigend' auxbasis = mf.auxbasis auxbasis = comm.bcast(auxbasis) mf.auxbasis = comm.bcast(mf.auxbasis) auxmol = df.addons.make_auxmol(mol, auxbasis) # (P|Q) int2c = auxmol.intor('int2c2e', aosym='s1', comp=1) if rank == 0: print('auxmol.basis',auxmol.basis,'number of aux basis',int2c.shape[0]) # for sgX # ao_loc and rao_loc intbn = mol._add_suffix('int3c2e') intbn = gto.moleintor.ascint3(intbn) ao_loc = gto.moleintor.make_loc(mol._bas, intbn) #print('dsssa',mol.nbas, ao_loc.shape,ao_loc[0],ao_loc[-1],ao_loc[1],ao_loc[2],ao_loc[3],ao_loc[115]) rao_loc = numpy.zeros((nao),dtype=int) for i in range(mol.nbas): for j in range(ao_loc[i],ao_loc[i+1]): rao_loc[j] = i ovlp = mol.intor_symmetric('int1e_ovlp') if rank == 0: print('thrd_nddm',thrd_nddm, 'sblk',sblk, 'intsp',intsp, 'gthrdu',gthrdu) # coase and fine grids change grdchg = 0 norm_ddm = 0 for k in range(nset): norm_ddm += numpy.linalg.norm(dms[k]) if norm_ddm < thrd_nddm and cond == 2 : cond = 1 if cond == 0: wao_vx, ngridsx, coordsx, gridatm = get_gridss(mol,grdlvl_i, sblk) if rank == 0: print('grids level at first is', grdlvl_i) cond = 2 elif cond == 1: wao_vx, ngridsx, coordsx, gridatm = get_gridss(mol,grdlvl_f, sblk) if rank == 0: print('grids level change to', grdlvl_f) dms = numpy.asarray(dmcur) dms = dms.reshape(-1,nao,nao) grdchg = 1 cond = 3 # DF-J dmtril = [] for k in range(nset): dmtril.append(lib.pack_tril(dms[k]+dms[k].T)) i = numpy.arange(nao) dmtril[k][i*(i+1)//2+i] *= .5 rho = [] b0 = 0 for eri1 in loop(mf.with_df): naux, nao_pair = eri1.shape #if rank==0: print('slice-naux',naux,'rank',rank) b1 = b0 + naux assert(nao_pair == nao*(nao+1)//2) for k in range(nset): if b0 == 0: rho.append(numpy.empty(paux[rank])) rho[k][b0:b1] = numpy.dot(eri1, dmtril[k]) b0 = b1 orho = [] rec = [] for k in range(nset): orho.append(mpi.gather(rho[k])) if rank == 0: ivj0 = scipy.linalg.solve(int2c, orho[k]) else: ivj0 = None rec.append(numpy.empty(paux[rank])) comm.Scatterv([ivj0,paux],rec[k],root=0) b0 = 0 for eri1 in loop(mf.with_df): naux, nao_pair = eri1.shape b1 = b0 + naux assert(nao_pair == nao*(nao+1)//2) for k in range(nset): vj[k] += numpy.dot(rec[k][b0:b1].T, eri1) b0 = b1 for k in range(nset): vj[k] = comm.reduce(vj[k]) # sgX wao_v = wao_vx coords = coordsx for k in range(nset): # Kuv = Sum(Xug Avt Dkt Xkg) ngrids = coords.shape[0] for ii in range(gridatm.shape[0]-1): i0 = gridatm[ii] i1 = gridatm[ii+1] # screening u by value of grids umaxg = numpy.amax(numpy.absolute(wao_v[i0:i1]), axis=0) usi = numpy.argwhere(umaxg > gthrdu).reshape(-1) # screening v by dm and ovlp then triangle matrix bn uovl = ovlp[usi, :] vmaxu = numpy.amax(numpy.absolute(uovl), axis=0) osi = numpy.argwhere(vmaxu > gthrdvs).reshape(-1) udms = dms[k][usi, :] dmaxg = numpy.amax(numpy.absolute(udms), axis=0) dsi = numpy.argwhere(dmaxg > gthrdvd).reshape(-1) vsi = numpy.intersect1d(dsi, osi) if len(vsi) != 0: vsh = numpy.unique(rao_loc[vsi]) #vshbeg = vsh[0] vshfin = vsh[-1]+1 # use gap between continurous v to save time vsh1 = vsh vsh1= numpy.delete(vsh1, 0) vsh1 = numpy.append(vsh1, [vshfin]) vshd = numpy.argwhere(vsh1-vsh > intsp) vshd = numpy.append(vshd, vsh.shape[0]-1) nvshd = vshd.shape[0] #vbeg = ao_loc[vshbeg] vfin = ao_loc[vshfin] fakemol = gto.fakemol_for_charges(coords[i0:i1]) pmol = gto.mole.conc_mol(mol, fakemol) bn = [] dmsk = [] bntp = [[0 for col in range(nvshd)] for row in range(nvshd)] for i in range(nvshd): if i==0: ii0 = vsh[0] ii1 = vsh[vshd[0]]+1 else: ii0 = vsh[vshd[i-1]+1] ii1 = vsh[vshd[i]]+1 dmsk.append(dms[k][:,ao_loc[ii0]:ao_loc[ii1]]) bnh = [] for j in range(0, i): bnh.append(bntp[j][i].swapaxes(0,1)) for j in range(i, nvshd): if j==0: jj0 = vsh[0] jj1 = vsh[vshd[0]]+1 else: jj0 = vsh[vshd[j-1]+1] jj1 = vsh[vshd[j]]+1 shls_slice = (ii0, ii1, jj0, jj1, mol.nbas, mol.nbas+fakemol.nbas) bntp[i][j] = pmol.intor(intor='int3c2e', comp=1, aosym='s1', shls_slice=shls_slice) bnh.append(bntp[i][j]) bnrow = numpy.concatenate(bnh, axis=1) bn.append(bnrow) bn = numpy.concatenate(bn, axis=0) abn = numpy.absolute(bn) #if cond==3: print(rank,'wet',numpy.amax(abn), numpy.median(abn)) dmsk = numpy.asarray(numpy.hstack(dmsk)) fg = numpy.dot(wao_v[i0:i1,usi],dmsk[usi]) gv = lib.einsum('vtg,gt->gv', bn, fg) vk0 = numpy.zeros((nao,nao)) vksp = lib.einsum('gu,gv->uv', wao_v[i0:i1,usi], gv) blen = 0 for i in range(nvshd): if i==0: ii0 = vsh[0] ii1 = vsh[vshd[0]]+1 else: ii0 = vsh[vshd[i-1]+1] ii1 = vsh[vshd[i]]+1 baa = ao_loc[ii1]-ao_loc[ii0] vk0[usi,ao_loc[ii0]:ao_loc[ii1]] = vksp[:,blen:(blen+baa)] blen += baa vk[k] += vk0 else: vk0 = numpy.zeros((nao,nao)) vk[k] += vk0 sn = lib.einsum('gu,gv->uv', wao_v, wao_v) vk[k] = comm.reduce(vk[k]) sn = comm.reduce(sn) # SSn^-1 for grids to analitic if rank == 0: snsgk = scipy.linalg.solve(sn, vk[k]) vk[k] = numpy.matmul(ovlp, snsgk) if rank == 0: vj = lib.unpack_tril(numpy.asarray(vj), 1).reshape(dm_shape) vk = numpy.asarray(vk).reshape(dm_shape) #if cond==3: cond=4 return vj, vk, grdchg
def B1_dot_x(pcmobj, dm, r_vdw, ui, ylm_1sph, cached_pol, L): mol = pcmobj.mol mol = pcmobj.mol natm = mol.natm nao = mol.nao lmax = pcmobj.lmax nlm = (lmax + 1)**2 dms = numpy.asarray(dm) is_single_dm = dms.ndim == 2 dms = dms.reshape(-1, nao, nao) n_dm = dms.shape[0] atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() aoslices = mol.aoslice_by_atom() grids = pcmobj.grids coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] extern_point_idx = ui > 0 fi0 = ddcosmo.make_fi(pcmobj, r_vdw) fi1 = ddcosmo_grad.make_fi1(pcmobj, pcmobj.get_atomic_radii()) fi1[:, :, ui == 0] = 0 ui1 = -fi1 Bx = numpy.zeros((natm, 3, nao, nao)) ao = mol.eval_gto('GTOval', grids.coords) aow = numpy.einsum('gi,g->gi', ao, grids.weights) aopair = numpy.einsum('gi,gj->gij', ao, aow) den = numpy.einsum('gij,ij->g', aopair, dm) psi0 = numpy.zeros((natm, nlm)) i1 = 0 for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] fac_pol = ddcosmo._vstack_factor_fak_pol(fak_pol, lmax) i0, i1 = i1, i1 + fac_pol.shape[1] psi0[ia] = -numpy.einsum('mn,n->m', fac_pol, den[i0:i1]) LS0 = numpy.linalg.solve(L.reshape(natm * nlm, -1).T, psi0.ravel()) LS0 = LS0.reshape(natm, nlm) phi0 = numpy.zeros((natm, nlm)) phi1 = numpy.zeros((natm, 3, natm, nlm)) int3c2e = mol._add_suffix('int3c2e') int3c2e_ip1 = mol._add_suffix('int3c2e_ip1') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e) cintopt_ip1 = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e_ip1) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph #fakemol = gto.fakemol_for_charges(cav_coords[ui[ia]>0]) fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1', cintopt=cintopt) v_phi = numpy.einsum('pqg,pq->g', v_nj, dm) phi0[ia] = numpy.einsum('n,ln,n,n->l', weights_1sph, ylm_1sph, ui[ia], v_phi) phi1[:, :, ia] += lib.einsum('n,ln,azn,n->azl', weights_1sph, ylm_1sph, ui1[:, :, ia], v_phi) Bx += lib.einsum('l,n,ln,azn,ijn->azij', LS0[ia], weights_1sph, ylm_1sph, ui1[:, :, ia], v_nj) wtmp = lib.einsum('n,ln,n->ln', weights_1sph, ylm_1sph, ui[ia]) v_e1_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e_ip1, comp=3, aosym='s1', cintopt=cintopt_ip1) vtmp = lib.einsum('l,ln,xijn->xij', LS0[ia], wtmp, v_e1_nj) Bx[ia] += vtmp Bx[ia] += vtmp.transpose(0, 2, 1) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] Bx[ja, :, p0:p1, :] -= vtmp[:, p0:p1] Bx[ja, :, :, p0:p1] -= vtmp[:, p0:p1].transpose(0, 2, 1) tmp = numpy.einsum('xijn,ij->xn', v_e1_nj[:, p0:p1], dm[p0:p1]) tmp += numpy.einsum('xijn,ji->xn', v_e1_nj[:, p0:p1], dm[:, p0:p1]) phitmp = numpy.einsum('ln,xn->xl', wtmp, tmp) phi1[ja, :, ia] -= phitmp phi1[ia, :, ia] += phitmp Xvec0 = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi0.ravel()) Xvec0 = Xvec0.reshape(natm, nlm) L1 = ddcosmo_grad.make_L1(pcmobj, r_vdw, ylm_1sph, fi0) phi1 -= lib.einsum('aziljm,jm->azil', L1, Xvec0) Xvec1 = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi1.reshape(-1, natm * nlm).T) Xvec1 = Xvec1.T.reshape(natm, 3, natm, nlm) psi1 = numpy.zeros((natm, 3, natm, nlm)) i1 = 0 for ia, (coords, weight, weight1) in enumerate(rks_grad.grids_response_cc(grids)): i0, i1 = i1, i1 + weight.size ao = mol.eval_gto('GTOval_sph_deriv1', coords) aow = numpy.einsum('gi,g->gi', ao[0], weight) aopair1 = lib.einsum('xgi,gj->xgij', ao[1:], aow) aow = numpy.einsum('gi,zxg->zxgi', ao[0], weight1) aopair0 = lib.einsum('zxgi,gj->zxgij', aow, ao[0]) den0 = numpy.einsum('zxgij,ij->zxg', aopair0, dm) den1 = numpy.empty((natm, 3, weight.size)) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] den1[ja] = numpy.einsum('xgij,ij->xg', aopair1[:, :, p0:p1], dm[p0:p1, :]) den1[ja] += numpy.einsum('xgij,ji->xg', aopair1[:, :, p0:p1], dm[:, p0:p1]) fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] fac_pol = ddcosmo._vstack_factor_fak_pol(fak_pol, lmax) scaled_weights = lib.einsum('azm,mn->azn', Xvec1[:, :, ia], fac_pol) scaled_weights *= weight aow = numpy.einsum('gi,azg->azgi', ao[0], scaled_weights) Bx -= numpy.einsum('gi,azgj->azij', ao[0], aow) tmp = numpy.einsum('mn,zxn->zxm', fac_pol, den1) psi1[:, :, ia] -= numpy.einsum('mn,zxn->zxm', fac_pol, den0) psi1[ia, :, ia] -= tmp.sum(axis=0) for ja in range(natm): psi1[ja, :, ia] += tmp[ja] eta_nj = lib.einsum('mn,m->n', fac_pol, Xvec0[ia]) Bx -= lib.einsum('n,zxnpq->zxpq', eta_nj, aopair0) vtmp = lib.einsum('n,xnpq->xpq', eta_nj, aopair1) Bx[ia] -= vtmp Bx[ia] -= vtmp.transpose(0, 2, 1) for ja in range(natm): shl0, shl1, q0, q1 = aoslices[ja] Bx[ja, :, q0:q1, :] += vtmp[:, q0:q1] Bx[ja, :, :, q0:q1] += vtmp[:, q0:q1].transpose(0, 2, 1) psi1 -= numpy.einsum('il,aziljm->azjm', LS0, L1) LS1 = numpy.linalg.solve( L.reshape(natm * nlm, -1).T, psi1.reshape(-1, natm * nlm).T) LS1 = LS1.T.reshape(natm, 3, natm, nlm) cav_coords = (atom_coords.reshape(natm, 1, 3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) cav_coords = cav_coords[extern_point_idx] fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1', cintopt=cintopt) v_phi = numpy.zeros((natm, ngrid_1sph, nao, nao)) v_phi[extern_point_idx] += v_nj.transpose(2, 0, 1) Bx += lib.einsum('azjx,n,xn,jn,jnpq->azpq', LS1, weights_1sph, ylm_1sph, ui, v_phi) return Bx
def make_phi1(pcmobj, dm, r_vdw, ui): mol = pcmobj.mol natm = mol.natm nlm = (pcmobj.lmax+1)**2 if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): dm = dm[0] + dm[1] tril_dm = lib.pack_tril(dm+dm.T) nao = dm.shape[0] diagidx = numpy.arange(nao) diagidx = diagidx*(diagidx+1)//2 + diagidx tril_dm[diagidx] *= .5 atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere(pcmobj.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True)) extern_point_idx = ui > 0 fi1 = make_fi1(pcmobj, pcmobj.get_atomic_radii()) fi1[:,:,ui==0] = 0 ui1 = -fi1 ngrid_1sph = weights_1sph.size v_phi0 = numpy.empty((natm,ngrid_1sph)) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph d_rs = atom_coords.reshape(-1,1,3) - cav_coords v_phi0[ia] = numpy.einsum('z,zp->p', atom_charges, 1./lib.norm(d_rs,axis=2)) phi1 = -numpy.einsum('n,ln,azjn,jn->azjl', weights_1sph, ylm_1sph, ui1, v_phi0) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph for ja in range(natm): rs = atom_coords[ja] - cav_coords d_rs = lib.norm(rs, axis=1) v_phi = atom_charges[ja] * numpy.einsum('px,p->px', rs, 1./d_rs**3) tmp = numpy.einsum('n,ln,n,nx->xl', weights_1sph, ylm_1sph, ui[ia], v_phi) phi1[ja,:,ia] += tmp # response of the other atoms phi1[ia,:,ia] -= tmp # response of cavity grids int3c2e = mol._add_suffix('int3c2e') int3c2e_ip1 = mol._add_suffix('int3c2e_ip1') aoslices = mol.aoslice_by_atom() for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph #fakemol = gto.fakemol_for_charges(cav_coords[ui[ia]>0]) fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1') v_phi = numpy.einsum('ij,ijk->k', dm, v_nj) phi1[:,:,ia] += numpy.einsum('n,ln,azn,n->azl', weights_1sph, ylm_1sph, ui1[:,:,ia], v_phi) v_e1_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e_ip1, comp=3, aosym='s1') v_e2_nj = v_e1_nj + v_e1_nj.transpose(0,2,1,3) phi1_e2_nj = numpy.einsum('ji,xijr->xr', dm, v_e2_nj) phi1[ia,:,ia] += numpy.einsum('n,ln,n,xn->xl', weights_1sph, ylm_1sph, ui[ia], phi1_e2_nj) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] phi1_nj = numpy.einsum('ij,xijr->xr', dm[p0:p1 ], v_e1_nj[:,p0:p1]) phi1_nj += numpy.einsum('ji,xijr->xr', dm[:,p0:p1], v_e1_nj[:,p0:p1]) phi1[ja,:,ia] -= numpy.einsum('n,ln,n,xn->xl', weights_1sph, ylm_1sph, ui[ia], phi1_nj) return phi1
def make_B(pcmobj, r_vdw, ui, ylm_1sph, cached_pol, L): mol = pcmobj.mol coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ngrid_1sph = coords_1sph.shape[0] mol = pcmobj.mol natm = mol.natm nao = mol.nao lmax = pcmobj.lmax nlm = (lmax + 1)**2 atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() grids = pcmobj.grids extern_point_idx = ui > 0 cav_coords = (atom_coords.reshape(natm, 1, 3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) max_memory = pcmobj.max_memory - lib.current_memory()[0] blksize = int(max(max_memory * .9e6 / 8 / nao**2, 400)) cav_coords = cav_coords[extern_point_idx] int3c2e = mol._add_suffix('int3c2e') cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, int3c2e) fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s2ij', cintopt=cintopt) nao_pair = v_nj.shape[0] v_phi = numpy.zeros((nao_pair, natm, ngrid_1sph)) v_phi[:, extern_point_idx] += v_nj phi = numpy.einsum('n,xn,jn,ijn->ijx', weights_1sph, ylm_1sph, ui, v_phi) Xvec = numpy.linalg.solve(L.reshape(natm * nlm, -1), phi.reshape(-1, natm * nlm).T) Xvec = Xvec.reshape(natm, nlm, nao_pair) ao = mol.eval_gto('GTOval', grids.coords) aow = numpy.einsum('gi,g->gi', ao, grids.weights) aopair = lib.pack_tril(numpy.einsum('gi,gj->gij', ao, aow)) psi = numpy.zeros((nao_pair, natm, nlm)) i1 = 0 for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] i0, i1 = i1, i1 + fak_pol[0].shape[1] p1 = 0 for l in range(lmax + 1): fac = 4 * numpy.pi / (l * 2 + 1) p0, p1 = p1, p1 + (l * 2 + 1) psi[:, ia, p0:p1] = -fac * numpy.einsum('mn,ni->im', fak_pol[l], aopair[i0:i1]) B = lib.einsum('pnl,nlq->pq', psi, Xvec) B = B + B.T B = ao2mo.restore(1, B, nao) return B
def _exec_cppe(self, dm, elec_only=False): dms = numpy.asarray(dm) is_single_dm = dms.ndim == 2 nao = dms.shape[-1] dms = dms.reshape(-1,nao,nao) n_dm = dms.shape[0] if self.V_es is None: positions = numpy.array([p.position for p in self.potentials]) moments = [] orders = [] for p in self.potentials: p_moments = [] for m in p.multipoles: m.remove_trace() p_moments.append(m.values) orders.append(m.k) moments.append(p_moments) self.V_es = self._compute_multipole_potential_integrals(positions, orders, moments) e_static = numpy.einsum('ij,xij->x', self.V_es, dms) self.cppe_state.energies["Electrostatic"]["Electronic"] = ( e_static[0] ) positions = numpy.array([p.position for p in self.potentials if p.is_polarizable]) n_sites = positions.shape[0] V_ind = numpy.zeros((n_dm, nao, nao)) e_tot = [] e_pol = [] if n_sites > 0: #:elec_fields = self._compute_field(positions, dms) fakemol = gto.fakemol_for_charges(positions) j3c = df.incore.aux_e2(self.mol, fakemol, intor='int3c2e_ip1') elec_fields = (numpy.einsum('aijg,nij->nga', j3c, dms) + numpy.einsum('aijg,nji->nga', j3c, dms)) induced_moments = numpy.empty((n_dm, n_sites * 3)) for i_dm in range(n_dm): self.cppe_state.update_induced_moments(elec_fields[i_dm].ravel(), elec_only) induced_moments[i_dm] = numpy.array(self.cppe_state.get_induced_moments()) e_tot.append(self.cppe_state.total_energy) e_pol.append(self.cppe_state.energies["Polarization"]["Electronic"]) induced_moments = induced_moments.reshape(n_dm, n_sites, 3) #:V_ind = self._compute_field_integrals(positions, induced_moments) V_ind = numpy.einsum('aijg,nga->nij', j3c, -induced_moments) V_ind = V_ind + V_ind.transpose(0, 2, 1) if not elec_only: vmat = self.V_es + V_ind e = numpy.array(e_tot) else: vmat = V_ind e = numpy.array(e_pol) if is_single_dm: e = e[0] vmat = vmat[0] return e, vmat
def make_phi1(pcmobj, dm, r_vdw, ui): mol = pcmobj.mol natm = mol.natm nlm = (pcmobj.lmax+1)**2 if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): dm = dm[0] + dm[1] tril_dm = lib.pack_tril(dm+dm.T) nao = dm.shape[0] diagidx = numpy.arange(nao) diagidx = diagidx*(diagidx+1)//2 + diagidx tril_dm[diagidx] *= .5 atom_coords = mol.atom_coords() atom_charges = mol.atom_charges() coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere(pcmobj.lebedev_order) ylm_1sph = numpy.vstack(sph.real_sph_vec(coords_1sph, pcmobj.lmax, True)) extern_point_idx = ui > 0 fi1 = make_fi1(pcmobj, pcmobj.get_atomic_radii()) fi1[:,:,ui==0] = 0 ui1 = -fi1 ngrid_1sph = weights_1sph.size v_phi0 = numpy.empty((natm,ngrid_1sph)) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph d_rs = atom_coords.reshape(-1,1,3) - cav_coords v_phi0[ia] = numpy.einsum('z,zp->p', atom_charges, 1./lib.norm(d_rs,axis=2)) phi1 = -numpy.einsum('n,ln,azjn,jn->azjl', weights_1sph, ylm_1sph, ui1, v_phi0) for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph for ja in range(natm): rs = atom_coords[ja] - cav_coords d_rs = lib.norm(rs, axis=1) v_phi = atom_charges[ja] * numpy.einsum('px,p->px', rs, 1./d_rs**3) tmp = numpy.einsum('n,ln,n,nx->xl', weights_1sph, ylm_1sph, ui[ia], v_phi) phi1[ja,:,ia] += tmp # response of the other atoms phi1[ia,:,ia] -= tmp # response of cavity grids int3c2e = mol._add_suffix('int3c2e') int3c2e_ip1 = mol._add_suffix('int3c2e_ip1') aoslices = mol.aoslice_by_atom() for ia in range(natm): cav_coords = atom_coords[ia] + r_vdw[ia] * coords_1sph #fakemol = gto.fakemol_for_charges(cav_coords[ui[ia]>0]) fakemol = gto.fakemol_for_charges(cav_coords) v_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e, aosym='s1') v_phi = numpy.einsum('ij,ijk->k', dm, v_nj) phi1[:,:,ia] += numpy.einsum('n,ln,azn,n->azl', weights_1sph, ylm_1sph, ui1[:,:,ia], v_phi) v_e1_nj = df.incore.aux_e2(mol, fakemol, intor=int3c2e_ip1, comp=3, aosym='s1') v_e2_nj = v_e1_nj + v_e1_nj.transpose(0,2,1,3) phi1_e2_nj = numpy.einsum('ji,xijr->xr', dm, v_e2_nj) phi1[ia,:,ia] += numpy.einsum('n,ln,n,xn->xl', weights_1sph, ylm_1sph, ui[ia], phi1_e2_nj) for ja in range(natm): shl0, shl1, p0, p1 = aoslices[ja] phi1_nj = numpy.einsum('ij,xijr->xr', dm[p0:p1 ], v_e1_nj[:,p0:p1]) phi1_nj += numpy.einsum('ji,xijr->xr', dm[:,p0:p1], v_e1_nj[:,p0:p1]) phi1[ja,:,ia] -= numpy.einsum('n,ln,n,xn->xl', weights_1sph, ylm_1sph, ui[ia], phi1_nj) return phi1
def make_psi_vmat(pcmobj, dm, r_vdw, ui, grids, ylm_1sph, cached_pol, L_X, L): mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax nlm = (lmax+1)**2 i1 = 0 scaled_weights = numpy.empty(grids.weights.size) for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] i0, i1 = i1, i1 + fak_pol[0].shape[1] eta_nj = 0 p1 = 0 for l in range(lmax+1): fac = 4*numpy.pi/(l*2+1) p0, p1 = p1, p1 + (l*2+1) eta_nj += fac * numpy.einsum('mn,m->n', fak_pol[l], L_X[ia,p0:p1]) scaled_weights[i0:i1] = eta_nj * grids.weights[i0:i1] if not (isinstance(dm, numpy.ndarray) and dm.ndim == 2): dm = dm[0] + dm[1] ni = numint.NumInt() max_memory = pcmobj.max_memory - lib.current_memory()[0] make_rho, nset, nao = ni._gen_rho_evaluator(mol, dm) shls_slice = (0, mol.nbas) ao_loc = mol.ao_loc_nr() den = numpy.empty(grids.weights.size) vmat = numpy.zeros((nao,nao)) p1 = 0 aow = None for ao, mask, weight, coords \ in ni.block_loop(mol, grids, nao, 0, max_memory): p0, p1 = p1, p1 + weight.size den[p0:p1] = weight * make_rho(0, ao, mask, 'LDA') aow = numpy.ndarray(ao.shape, order='F', buffer=aow) aow = numpy.einsum('pi,p->pi', ao, scaled_weights[p0:p1], out=aow) vmat -= numint._dot_ao_ao(mol, ao, aow, mask, shls_slice, ao_loc) ao = aow = scaled_weights = None nelec_leak = 0 psi = numpy.empty((natm,nlm)) i1 = 0 for ia in range(natm): fak_pol, leak_idx = cached_pol[mol.atom_symbol(ia)] i0, i1 = i1, i1 + fak_pol[0].shape[1] nelec_leak += den[i0:i1][leak_idx].sum() p1 = 0 for l in range(lmax+1): fac = 4*numpy.pi/(l*2+1) p0, p1 = p1, p1 + (l*2+1) psi[ia,p0:p1] = -fac * numpy.einsum('n,mn->m', den[i0:i1], fak_pol[l]) # Contribution of nuclear charge to the total density # The factor numpy.sqrt(4*numpy.pi) is due to the product of 4*pi * Y_0^0 psi[ia,0] += numpy.sqrt(4*numpy.pi)/r_vdw[ia] * mol.atom_charge(ia) logger.debug(pcmobj, 'electron leak %f', nelec_leak) # <Psi, L^{-1}g> -> Psi = SL the adjoint equation to LX = g L_S = numpy.linalg.solve(L.T.reshape(natm*nlm,-1), psi.ravel()).reshape(natm,-1) coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order) # JCP, 141, 184108, Eq (39) xi_jn = numpy.einsum('n,jn,xn,jx->jn', weights_1sph, ui, ylm_1sph, L_S) extern_point_idx = ui > 0 cav_coords = (mol.atom_coords().reshape(natm,1,3) + numpy.einsum('r,gx->rgx', r_vdw, coords_1sph)) cav_coords = cav_coords[extern_point_idx] xi_jn = xi_jn[extern_point_idx] max_memory = pcmobj.max_memory - lib.current_memory()[0] blksize = int(max(max_memory*1e6/8/nao**2, 400)) cintopt = gto.moleintor.make_cintopt(mol._atm, mol._bas, mol._env, 'int3c2e') vmat_tril = 0 for i0, i1 in lib.prange(0, xi_jn.size, blksize): fakemol = gto.fakemol_for_charges(cav_coords[i0:i1]) v_nj = df.incore.aux_e2(mol, fakemol, intor='int3c2e', aosym='s2ij', cintopt=cintopt) vmat_tril += numpy.einsum('xn,n->x', v_nj, xi_jn[i0:i1]) vmat += lib.unpack_tril(vmat_tril) return psi, vmat, L_S
# There are two ways to compute this potential. # Method 1 (slow): looping over r_orig and evaluating 1/|r-r_orig| for each # point. dm = mf.make_rdm1() Vele = [] for p in points: mol.set_rinv_orig_(p) Vele.append(numpy.einsum('ij,ij', mol.intor('int1e_rinv'), dm)) Vele = numpy.array(Vele) # Method 2 (fast): Mimicing the points with delta function (steep S-type # Gaussians) then calling the 3-center integral code to calculate the # interaction between points and other AOs. Below, fakemol holds the delta # functions. from pyscf import df fakemol = gto.fakemol_for_charges(points) Vele = np.einsum('ijp,ij->p', df.incore.aux_e2(mol, fakemol), dm) # # 4. MEP at each point # MEP = Vnuc - Vele print(MEP.shape) # # 5. MEP force = -d/dr MEP = -d/dr Vnuc + d/dr Vele # Fnuc = 0 for i in range(mol.natm): r = mol.atom_coord(i) Z = mol.atom_charge(i)