def get_lattice_Ls(cell, nimgs=None, rcut=None, dimension=None): '''Get the (Cartesian, unitful) lattice translation vectors for nearby images. The translation vectors can be used for the lattice summation.''' b = cell.reciprocal_vectors(norm_to=1) heights_inv = lib.norm(b, axis=1) if nimgs is None: if rcut is None: rcut = cell.rcut # plus 1 image in rcut to handle the case atoms within the adjacent cells are # close to each other rcut = rcut + min(1./heights_inv) nimgs = np.ceil(rcut*heights_inv) else: rcut = max((np.asarray(nimgs))/heights_inv) + min(1./heights_inv) # ~ the inradius if dimension is None: dimension = cell.dimension if dimension == 0: nimgs = [0, 0, 0] elif dimension == 1: nimgs = [nimgs[0], 0, 0] elif dimension == 2: nimgs = [nimgs[0], nimgs[1], 0] Ts = lib.cartesian_prod((np.arange(-nimgs[0],nimgs[0]+1), np.arange(-nimgs[1],nimgs[1]+1), np.arange(-nimgs[2],nimgs[2]+1))) Ls = np.dot(Ts, cell.lattice_vectors()) Ls = Ls[lib.norm(Ls, axis=1)<rcut] return np.asarray(Ls, order='C')
def norm_xy(w, z): zp = e_ia * z.reshape(e_ia.shape) zm = w/e_ia * z.reshape(e_ia.shape) x = (zp + zm) * .5 y = (zp - zm) * .5 norm = lib.norm(x)**2 - lib.norm(y)**2 norm = numpy.sqrt(.5/norm) # normalize to 0.5 for alpha spin return (x*norm, y*norm)
def norm_xy(w, z): zp = eai * z.reshape(eai.shape) zm = w/eai * z.reshape(eai.shape) x = (zp + zm) * .5 y = (zp - zm) * .5 norm = 2*(lib.norm(x)**2 - lib.norm(y)**2) norm = 1/numpy.sqrt(norm) return x*norm,y*norm
def search_possible_rotations(self, zaxis=None): '''If zaxis is given, the rotation axis is parallel to zaxis''' maybe_cn = [] for lst in self.group_atoms_by_distance: natm = len(lst) if natm > 1: coords = self.atoms[lst,1:] # possible C2 axis for i in range(1, natm): if abs(coords[0]+coords[i]).sum() > TOLERANCE: maybe_cn.append((coords[0]+coords[i], 2)) else: # abs(coords[0]-coords[i]).sum() > TOLERANCE: maybe_cn.append((coords[0]-coords[i], 2)) # atoms of equal distances may be associated with rotation axis > C2. r0 = coords - coords[0] distance = norm(r0, axis=1) eq_distance = abs(distance[:,None] - distance) < TOLERANCE for i in range(2, natm): for j in numpy.where(eq_distance[i,:i])[0]: cos = numpy.dot(r0[i],r0[j]) / (distance[i]*distance[j]) ang = numpy.arccos(cos) nfrac = numpy.pi*2 / (numpy.pi-ang) n = int(numpy.around(nfrac)) if abs(nfrac-n) < TOLERANCE: maybe_cn.append((numpy.cross(r0[i],r0[j]),n)) # remove zero-vectors and duplicated vectors vecs = numpy.vstack([x[0] for x in maybe_cn]) idx = norm(vecs, axis=1) > TOLERANCE ns = numpy.hstack([x[1] for x in maybe_cn]) vecs = _normalize(vecs[idx]) ns = ns[idx] if zaxis is not None: # Keep parallel rotation axes cos = numpy.dot(vecs, _normalize(zaxis)) vecs = vecs[(abs(cos-1) < TOLERANCE) | (abs(cos+1) < TOLERANCE)] ns = ns[(abs(cos-1) < TOLERANCE) | (abs(cos+1) < TOLERANCE)] possible_cn = [] seen = numpy.zeros(len(vecs), dtype=bool) for k, v in enumerate(vecs): if not seen[k]: where1 = numpy.einsum('ix->i', abs(vecs[k:] - v)) < TOLERANCE where1 = numpy.where(where1)[0] + k where2 = numpy.einsum('ix->i', abs(vecs[k:] + v)) < TOLERANCE where2 = numpy.where(where2)[0] + k seen[where1] = True seen[where2] = True vk = _normalize((numpy.einsum('ix->x', vecs[where1]) - numpy.einsum('ix->x', vecs[where2]))) for n in (set(ns[where1]) | set(ns[where2])): possible_cn.append((vk,n)) return possible_cn
def precompute_exx(cell, kpts): from pyscf.pbc import gto as pbcgto from pyscf.pbc.dft import gen_grid log = lib.logger.Logger(cell.stdout, cell.verbose) log.debug("# Precomputing Wigner-Seitz EXX kernel") Nk = get_monkhorst_pack_size(cell, kpts) log.debug("# Nk = %s", Nk) kcell = pbcgto.Cell() kcell.atom = 'H 0. 0. 0.' kcell.spin = 1 kcell.unit = 'B' kcell.verbose = 0 kcell.a = cell.lattice_vectors() * Nk Lc = 1.0/lib.norm(np.linalg.inv(kcell.a), axis=0) log.debug("# Lc = %s", Lc) Rin = Lc.min() / 2.0 log.debug("# Rin = %s", Rin) # ASE: alpha = 5./Rin # sqrt(-ln eps) / Rc, eps ~ 10^{-11} log.info("WS alpha = %s", alpha) kcell.mesh = np.array([4*int(L*alpha*3.0) for L in Lc]) # ~ [60,60,60] # QE: #alpha = 3./Rin * np.sqrt(0.5) #kcell.mesh = (4*alpha*np.linalg.norm(kcell.a,axis=1)).astype(int) log.debug("# kcell.mesh FFT = %s", kcell.mesh) kcell.build(False,False) rs = gen_grid.gen_uniform_grids(kcell) kngs = len(rs) log.debug("# kcell kngs = %d", kngs) corners = np.dot(np.indices((2,2,2)).reshape((3,8)).T, kcell.a) #vR = np.empty(kngs) #for i, rv in enumerate(rs): # # Minimum image convention to corners of kcell parallelepiped # r = lib.norm(rv-corners, axis=1).min() # if np.isclose(r, 0.): # vR[i] = 2*alpha / np.sqrt(np.pi) # else: # vR[i] = scipy.special.erf(alpha*r) / r r = np.min([lib.norm(rs-c, axis=1) for c in corners], axis=0) vR = scipy.special.erf(alpha*r) / (r+1e-200) vR[r<1e-9] = 2*alpha / np.sqrt(np.pi) vG = (kcell.vol/kngs) * fft(vR, kcell.mesh) ws_exx = {'alpha': alpha, 'kcell': kcell, 'q' : kcell.Gv, 'vq' : vG} log.debug("# Finished precomputing") return ws_exx
def vppnl_by_k(kpt): Gk = Gv + kpt G_rad = lib.norm(Gk, axis=1) aokG = ft_ao.ft_ao(cell, Gv, kpt=kpt) * (ngs / cell.vol) vppnl = 0 for ia in range(cell.natm): symb = cell.atom_symbol(ia) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = numpy.asarray(hl) fakemol._bas[0, gto.ANG_OF] = l fakemol._env[ptr + 3] = 0.5 * rl ** 2 fakemol._env[ptr + 4] = rl ** (l + 1.5) * numpy.pi ** 1.25 pYlm_part = dft.numint.eval_ao(fakemol, Gk, deriv=0) pYlm = numpy.empty((nl, l * 2 + 1, ngs)) for k in range(nl): qkl = pseudo.pp._qli(G_rad * rl, l, k) pYlm[k] = pYlm_part.T * qkl # pYlm is real SPG_lmi = numpy.einsum("g,nmg->nmg", SI[ia].conj(), pYlm) SPG_lm_aoG = numpy.einsum("nmg,gp->nmp", SPG_lmi, aokG) tmp = numpy.einsum("ij,jmp->imp", hl, SPG_lm_aoG) vppnl += numpy.einsum("imp,imq->pq", SPG_lm_aoG.conj(), tmp) return vppnl * (1.0 / ngs ** 2)
def estimate_eta(cell, cutoff=1e-12): '''The exponent of the smooth gaussian model density, requiring that at boundary, density ~ 4pi rmax^2 exp(-eta*rmax^2) ~ 1e-12 ''' rmax = max(lib.norm(cell.lattice_vectors(), axis=0)) eta = max(-numpy.log(cutoff/(4*numpy.pi*rmax**2))/rmax**2, .1) return eta
def cosmo_fock_o1(cosmo, dm): mol = cosmo.mol nao = dm.shape[0] # phi cosmo.loadsegs() coords = cosmo.cosurf[:cosmo.nps*3].reshape(-1,3) fakemol = _make_fakemol(coords) j3c = df.incore.aux_e2(mol, fakemol, intor='cint3c2e_sph', aosym='s2ij') tril_dm = lib.pack_tril(dm) * 2 diagidx = numpy.arange(nao) diagidx = diagidx*(diagidx+1)//2 + diagidx tril_dm[diagidx] *= .5 cosmo.phi = -numpy.einsum('x,xk->k', tril_dm, j3c) for ia in range(mol.natm): cosmo.phi += mol.atom_charge(ia)/lib.norm(mol.atom_coord(ia)-coords, axis=1) cosmo.savesegs() # qk cosmo.charges() # vpot cosmo.loadsegs() #X fakemol = _make_fakemol(cosmo.cosurf[:cosmo.nps*3].reshape(-1,3)) #X j3c = df.incore.aux_e2(mol, fakemol, intor='cint3c2e_sph', aosym='s2ij') fock = lib.unpack_tril(numpy.einsum('xk,k->x', j3c, -cosmo.qcos[:cosmo.nps])) fepsi = cosmo.fepsi() fock = fepsi*fock return fock
def mesh_to_cutoff(a, mesh): ''' Convert #grid points to KE cutoff ''' b = 2 * np.pi * np.linalg.inv(a.T) Gmax = lib.norm(b, axis=1) * np.asarray(mesh) * .5 return Gmax**2/2
def make_mask(cell, coords, relativity=0, shls_slice=None, verbose=None): '''Mask to indicate whether a shell is zero on grid. The resultant mask array is an extension to the mask array used in molecular code (see also pyscf.dft.numint.make_mask function). For given shell ID and block ID, the value of the extended mask array means the number of images in Ls that does not vanish. ''' coords = np.asarray(coords, order='F') natm = ctypes.c_int(cell._atm.shape[0]) nbas = ctypes.c_int(cell.nbas) ngrids = len(coords) if shls_slice is None: shls_slice = (0, cell.nbas) assert(shls_slice == (0, cell.nbas)) Ls = cell.get_lattice_Ls(dimension=3) Ls = Ls[np.argsort(lib.norm(Ls, axis=1))] non0tab = np.empty(((ngrids+BLKSIZE-1)//BLKSIZE, cell.nbas), dtype=np.uint8) libpbc.PBCnr_ao_screen(non0tab.ctypes.data_as(ctypes.c_void_p), coords.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(ngrids), Ls.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(len(Ls)), cell._atm.ctypes.data_as(ctypes.c_void_p), natm, cell._bas.ctypes.data_as(ctypes.c_void_p), nbas, cell._env.ctypes.data_as(ctypes.c_void_p)) return non0tab
def get_ewald_params(cell, precision=1e-8, gs=None): r'''Choose a reasonable value of Ewald 'eta' and 'cut' parameters. Choice is based on largest G vector and desired relative precision. The relative error in the G-space sum is given by (keeping only exponential factors) precision ~ e^{(-Gmax^2)/(4 \eta^2)} which determines eta. Then, real-space cutoff is determined by (exp. factors only) precision ~ erfc(eta*rcut) / rcut ~ e^{(-eta**2 rcut*2)} Returns: ew_eta, ew_cut : float The Ewald 'eta' and 'cut' parameters. ''' if gs is None: gs = cell.gs # See Martin, p. 85 _h = cell.lattice_vectors() Gmax = min([ 2.*np.pi*gs[i]/lib.norm(_h[i,:]) for i in range(3) ]) log_precision = np.log(precision) ew_eta = float(np.sqrt(-Gmax**2/(4*log_precision))) rcut = np.sqrt(-log_precision)/ew_eta ew_cut = cell.get_bounding_sphere(rcut) return ew_eta, ew_cut
def make_psi(mol, dm, r_vdw, lmax): grids = dft.gen_grid.Grids(mol) atom_grids_tab = grids.gen_atomic_grids(mol) grids.build() ao = dft.numint.eval_ao(mol, grids.coords) den = dft.numint.eval_rho(mol, ao, dm) den *= grids.weights natm = mol.natm nlm = (lmax+1)**2 psi = numpy.empty((natm,nlm)) i1 = 0 for ia in range(natm): xnj, w = atom_grids_tab[mol.atom_symbol(ia)] i0, i1 = i1, i1 + w.size r = lib.norm(xnj, axis=1) snj = xnj/r.reshape(-1,1) Ys = sph.real_sph_vec(snj, lmax, True) p1 = 0 for l in range(lmax+1): fac = 4*numpy.pi/(l*2+1) p0, p1 = p1, p1 + (l*2+1) rr = numpy.zeros_like(r) rr[r<=r_vdw[ia]] = r[r<=r_vdw[ia]]**l / r_vdw[ia]**(l+1) rr[r> r_vdw[ia]] = r_vdw[ia]**l / r[r>r_vdw[ia]]**(l+1) psi[ia,p0:p1] = -fac * numpy.einsum('n,n,mn->m', den[i0:i1], rr, Ys[l]) psi[ia,0] += numpy.sqrt(4*numpy.pi)/r_vdw[ia] * mol.atom_charge(ia) return psi
def get_ewald_params(cell, precision=1e-8, gs=None): r'''Choose a reasonable value of Ewald 'eta' and 'cut' parameters. Choice is based on largest G vector and desired relative precision. The relative error in the G-space sum is given by (keeping only exponential factors) precision ~ e^{(-Gmax^2)/(4 \eta^2)} which determines eta. Then, real-space cutoff is determined by (exp. factors only) precision ~ erfc(eta*rcut) / rcut ~ e^{(-eta**2 rcut*2)} Returns: ew_eta, ew_cut : float The Ewald 'eta' and 'cut' parameters. ''' if gs is None: gs = cell.gs if cell.dimension == 3: Gmax = min(np.asarray(cell.gs) * lib.norm(cell.reciprocal_vectors(), axis=1)) log_precision = np.log(precision*.1) ew_eta = np.sqrt(-Gmax**2/(4*log_precision)) ew_cut = np.sqrt(-log_precision)/ew_eta else: # Non-uniform PW grids are used for low-dimensional ewald summation. The cutoff # estimation for long range part based on exp(G^2/(4*eta^2)) does not work for # non-uniform grids. Smooth model density is preferred. ew_cut = cell.rcut ew_eta = np.sqrt(max(np.log(ew_cut**2/precision)/ew_cut**2, .1)) return ew_eta, ew_cut
def energy_nuc(self): # nuclei lattice interaction nuc = self.mol.energy_nuc() for j in range(self.mol.natm): q2, r2 = self.mol.atom_charge(j), self.mol.atom_coord(j) r = lib.norm(r2-coords, axis=1) nuc += q2*(charges/r).sum() return nuc
def energy_tot(self, dm=None, h1e=None, vhf=None): # nuclei lattice interaction nuc = 0.0 for j in range(self.mol.natm): q2, r2 = self.mol.atom_charge(j), self.mol.atom_coord(j) r = lib.norm(r2-coords, axis=1) nuc += q2*(charges/r).sum() return method_class.energy_tot(self, dm, h1e, vhf) + nuc
def makedm(mos, occs): where = [np.argmin(lib.norm(chk_kpts-kpt, axis=1)) for kpt in kpts] moa, mob = mos occa, occb = occs mos = ([fproj(moa[w], chk_kpts[w]-kpts[i]) for i,w in enumerate(where)], [fproj(mob[w], chk_kpts[w]-kpts[i]) for i,w in enumerate(where)]) occs = (occa[where],occb[where]) return make_rdm1(mos, occs)
def makedm(mos, occs): where = [np.argmin(lib.norm(chk_kpts-kpt, axis=1)) for kpt in kpts] moa, mob = mos occa, occb = occs dkpts = [chk_kpts[w]-kpts[i] for i,w in enumerate(where)] mos = (fproj([moa[w] for w in where], dkpts), fproj([mob[w] for w in where], dkpts)) occs = ([occa[i] for i in where], [occb[i] for i in where]) return make_rdm1(mos, occs)
def get_bounding_sphere(cell, rcut): '''Finds all the lattice points within a sphere of radius rcut. Defines a parallelipiped given by -N_x <= n_x <= N_x, with x in [1,3] See Martin p. 85 Args: rcut : number real space cut-off for interaction Returns: cut : ndarray of 3 ints defining N_x ''' Gmat = invh = scipy.linalg.inv(cell.lattice_vectors()) n1 = np.ceil(lib.norm(Gmat[0,:])*rcut).astype(int) n2 = np.ceil(lib.norm(Gmat[1,:])*rcut).astype(int) n3 = np.ceil(lib.norm(Gmat[2,:])*rcut).astype(int) cut = np.array([n1, n2, n3]) return cut
def get_vlocG(cell): '''Local PP kernel in G space: Vloc(G) for G!=0, 0 for G=0. Returns: (natm, ngs) ndarray ''' Gvnorm = lib.norm(cell.Gv, axis=1) vlocG = get_gth_vlocG(cell, Gvnorm) vlocG[:,0] = 0. return vlocG
def enlarge_space(myci, civec_strs, eri, norb, nelec): if isinstance(civec_strs, (tuple, list)): nelec, (strsa, strsb) = _unpack(civec_strs[0], nelec)[1:] ci_coeff = lib.asarray(civec_strs) else: ci_coeff, nelec, (strsa, strsb) = _unpack(civec_strs, nelec) na = len(strsa) nb = len(strsb) ci0 = ci_coeff.reshape(-1,na,nb) civec_a_max = lib.norm(ci0, axis=2).max(axis=0) civec_b_max = lib.norm(ci0, axis=1).max(axis=0) ci_aidx = numpy.where(civec_a_max > myci.ci_coeff_cutoff)[0] ci_bidx = numpy.where(civec_b_max > myci.ci_coeff_cutoff)[0] civec_a_max = civec_a_max[ci_aidx] civec_b_max = civec_b_max[ci_bidx] strsa = strsa[ci_aidx] strsb = strsb[ci_bidx] eri = ao2mo.restore(1, eri, norb) eri_pq_max = abs(eri.reshape(norb**2,-1)).max(axis=1).reshape(norb,norb) strsa_add = select_strs(myci, eri, eri_pq_max, civec_a_max, strsa, norb, nelec[0]) strsb_add = select_strs(myci, eri, eri_pq_max, civec_b_max, strsb, norb, nelec[1]) strsa = numpy.append(strsa, strsa_add) strsb = numpy.append(strsb, strsb_add) aidx = numpy.argsort(strsa) bidx = numpy.argsort(strsb) ci_strs = (strsa[aidx], strsb[bidx]) aidx = numpy.where(aidx < len(ci_aidx))[0] bidx = numpy.where(bidx < len(ci_bidx))[0] ma = len(strsa) mb = len(strsb) cs = [] for i in range(ci0.shape[0]): ci1 = numpy.zeros((ma,mb)) tmp = lib.take_2d(ci0[i], ci_aidx, ci_bidx) lib.takebak_2d(ci1, tmp, aidx, bidx) cs.append(_as_SCIvector(ci1, ci_strs)) if not isinstance(civec_strs, (tuple, list)) and civec_strs.ndim < 3: cs = cs[0] return cs
def cart2polar(rvec): # The rows of rvec are the 3-component vectors # i.e. rvec is N x 3 x,y,z = rvec.T r = lib.norm(rvec, axis=1) # theta is the polar angle, 0 < theta < pi # catch possible 0/0 theta = np.arccos(z/(r+1e-200)) # phi is the azimuthal angle, 0 < phi < 2pi (or -pi < phi < pi) phi = np.arctan2(y,x) return r, theta, phi
def init_guess_by_chkfile(cell, chkfile_name, project=True, kpts=None): '''Read the KHF results from checkpoint file, then project it to the basis defined by ``cell`` Returns: Density matrix, 3D ndarray ''' chk_cell, scf_rec = chkfile.load_scf(chkfile_name) if kpts is None: kpts = scf_rec['kpts'] if 'kpt' in scf_rec: chk_kpts = scf_rec['kpt'].reshape(-1,3) elif 'kpts' in scf_rec: chk_kpts = scf_rec['kpts'] else: chk_kpts = np.zeros((1,3)) mo = scf_rec['mo_coeff'] mo_occ = scf_rec['mo_occ'] if 'kpts' not in scf_rec: # gamma point or single k-point if mo.ndim == 2: mo = mo.reshape((1,)+mo.shape) mo_occ = mo_occ.reshape((1,)+mo_occ.shape) else: # UHF mo = mo.reshape((2,1)+mo.shape[1:]) mo_occ = mo_occ.reshape((2,1)+mo_occ.shape[1:]) def fproj(mo, kpt): if project: return addons.project_mo_nr2nr(chk_cell, mo, cell, kpt) else: return mo if kpts.shape == chk_kpts.shape and np.allclose(kpts, chk_kpts): def makedm(mos, occs): mos = [fproj(mo, None) for mo in mos] return make_rdm1(mos, occs) else: where = [np.argmin(lib.norm(chk_kpts-kpt, axis=1)) for kpt in kpts] def makedm(mos, occs): mos = [fproj(mos[w], chk_kpts[w]-kpts[i]) for i,w in enumerate(where)] return make_rdm1(mos, occs[where]) if mo.ndim == 3: # KRHF dm = makedm(mo, mo_occ) else: # KUHF dm = makedm(mo[0], mo_occ[0]) + makedm(mo[1], mo_occ[1]) # Real DM for gamma point if np.allclose(kpts, 0): dm = dm.real return dm
def grad_nuc(self, mol=None, atmlst=None): if mol is None: mol = method.mol g_qm = method.grad_nuc(mol, atmlst) g_mm = numpy.empty((mol.natm,3)) for i in range(mol.natm): q1 = mol.atom_charge(i) r1 = mol.atom_coord(i) r = lib.norm(r1-coords, axis=1) g_mm[i] = -q1 * numpy.einsum('i,ix,i->x', charges, r1-coords, 1/r**3) if atmlst is not None: g_mm = g_mm[atmlst] return g_qm + g_mm
def block_loop(self, cell, grids, nao, deriv=0, kpts=numpy.zeros((1,3)), kpt_band=None, max_memory=2000, non0tab=None, blksize=None): '''Define this macro to loop over grids by blocks. ''' ngrids = grids.weights.size nkpts = len(kpts) comp = (deriv+1)*(deriv+2)*(deriv+3)//6 # NOTE to index ni.non0tab, the blksize needs to be the integer multiplier of BLKSIZE if blksize is None: blksize = min(int(max_memory*1e6/(comp*2*nkpts*nao*16*BLKSIZE))*BLKSIZE, ngrids) blksize = max(blksize, BLKSIZE) if non0tab is None: non0tab = numpy.ones(((ngrids+BLKSIZE-1)//BLKSIZE,cell.nbas), dtype=numpy.int8) if kpt_band is None: kpt1 = kpt2 = kpts else: kpt1 = kpt_band kpt2 = kpts where = numpy.argmin(lib.norm(kpts-kpt1,axis=1)) if abs(kpts[where]-kpt1).sum() > 1e-9: where = None if (self.cell is None or id(cell) != id(self.cell) or self._deriv < deriv or self._kpts.shape != kpts.shape or abs(self._kpts - kpts).sum() > 1e-9 or self._coords.shape != grids.coords.shape or abs(self._coords[::64] - grids.coords[::64]).sum() > 1e-7): self.cache_ao(cell, kpts, deriv, grids.coords, nao, blksize) with h5py.File(self._ao.name, 'r') as f: for p0, p1 in prange(0, ngrids, blksize): coords = grids.coords[p0:p1] weight = grids.weights[p0:p1] non0 = non0tab[p0//BLKSIZE:] #:ao_k2 = self.eval_ao(cell, coords, kpts, deriv=deriv) if comp == 1: if self._deriv == 0: ao_k2 = [f['ao/%d'%k][p0:p1] for k in range(nkpts)] else: ao_k2 = [f['ao/%d'%k][0,p0:p1] for k in range(nkpts)] else: ao_k2 = [f['ao/%d'%k][:comp,p0:p1] for k in range(nkpts)] if kpt_band is None: ao_k1 = ao_k2 else: if where is None: ao_k1 = self.eval_ao(cell, coords, kpt1, deriv=deriv) else: ao_k1 = [ao_k2[where]] yield ao_k1, ao_k2, non0, weight, coords ao_k1 = ao_k2 = None
def init_guess_by_chkfile(cell, chkfile_name, project=None, kpt=None): '''Read the HF results from checkpoint file and make the density matrix for UHF initial guess. Returns: Density matrix, (nao,nao) ndarray ''' from pyscf import gto chk_cell, scf_rec = chkfile.load_scf(chkfile_name) if project is None: project = not gto.same_basis_set(chk_cell, cell) mo = scf_rec['mo_coeff'] mo_occ = scf_rec['mo_occ'] if kpt is None: kpt = np.zeros(3) if 'kpt' in scf_rec: chk_kpt = scf_rec['kpt'] elif 'kpts' in scf_rec: kpts = scf_rec['kpts'] # the closest kpt from KRHF results where = np.argmin(lib.norm(kpts-kpt, axis=1)) chk_kpt = kpts[where] if getattr(mo[0], 'ndim', None) == 2: # KRHF mo = mo[where] mo_occ = mo_occ[where] else: # KUHF mo = [mo[0][where], mo[1][where]] mo_occ = [mo_occ[0][where], mo_occ[1][where]] else: # from molecular code chk_kpt = np.zeros(3) if project: s = cell.pbc_intor('int1e_ovlp', kpt=kpt) def fproj(mo): if project: mo = addons.project_mo_nr2nr(chk_cell, mo, cell, chk_kpt-kpt) norm = np.einsum('pi,pi->i', mo.conj(), s.dot(mo)) mo /= np.sqrt(norm) return mo if getattr(mo, 'ndim', None) == 2: mo = fproj(mo) mo_occa = (mo_occ>1e-8).astype(np.double) mo_occb = mo_occ - mo_occa dm = mol_uhf.make_rdm1([mo,mo], [mo_occa,mo_occb]) else: # UHF dm = mol_uhf.make_rdm1([fproj(mo[0]),fproj(mo[1])], mo_occ) # Real DM for gamma point if kpt is None or np.allclose(kpt, 0): dm = dm.real return dm
def kernel(self, x0=None): '''TDHF diagonalization with non-Hermitian eigenvalue solver ''' self.check_sanity() self.dump_flags() vind, hdiag = self.get_vind(self._scf) precond = self.get_precond(hdiag) if x0 is None: x0 = self.init_guess(self._scf, self.nstates) # We only need positive eigenvalues def pickeig(w, v, nroots, envs): realidx = numpy.where((abs(w.imag) < REAL_EIG_THRESHOLD) & (w.real > POSTIVE_EIG_THRESHOLD))[0] return lib.linalg_helper._eigs_cmplx2real(w, v, realidx) self.converged, w, x1 = \ lib.davidson_nosym1(vind, x0, precond, tol=self.conv_tol, nroots=self.nstates, lindep=self.lindep, max_space=self.max_space, pick=pickeig, verbose=self.verbose) mo_occ = self._scf.mo_occ e = [] xy = [] for i, z in enumerate(x1): xs, ys = z.reshape(2,-1) norm = lib.norm(xs)**2 - lib.norm(ys)**2 if norm > 0: norm = 1/numpy.sqrt(norm) xs *= norm ys *= norm e.append(w[i]) xy.append((_unpack(xs, mo_occ), _unpack(ys, mo_occ))) self.e = numpy.array(e) self.xy = xy return self.e, self.xy
def get_pp_nl(cell, kpt=np.zeros(3)): coords = gen_grid.gen_uniform_grids(cell) aoR = numint.eval_ao(cell, coords, kpt) nao = cell.nao_nr() SI = cell.get_SI() aokG = tools.fftk(np.asarray(aoR.T, order='C'), cell.gs, np.exp(-1j*np.dot(coords, kpt))).T ngs = len(aokG) fakemol = pyscf.gto.Mole() fakemol._atm = np.zeros((1,pyscf.gto.ATM_SLOTS), dtype=np.int32) fakemol._bas = np.zeros((1,pyscf.gto.BAS_SLOTS), dtype=np.int32) ptr = pyscf.gto.PTR_ENV_START fakemol._env = np.zeros(ptr+10) fakemol._bas[0,pyscf.gto.NPRIM_OF ] = 1 fakemol._bas[0,pyscf.gto.NCTR_OF ] = 1 fakemol._bas[0,pyscf.gto.PTR_EXP ] = ptr+3 fakemol._bas[0,pyscf.gto.PTR_COEFF] = ptr+4 Gv = np.asarray(cell.Gv+kpt) G_rad = lib.norm(Gv, axis=1) vppnl = np.zeros((nao,nao), dtype=np.complex128) for ia in range(cell.natm): symb = cell.atom_symbol(ia) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: hl = np.asarray(hl) fakemol._bas[0,pyscf.gto.ANG_OF] = l fakemol._env[ptr+3] = .5*rl**2 fakemol._env[ptr+4] = rl**(l+1.5)*np.pi**1.25 pYlm_part = pyscf.dft.numint.eval_ao(fakemol, Gv, deriv=0) pYlm = np.empty((nl,l*2+1,ngs)) for k in range(nl): qkl = pseudo.pp._qli(G_rad*rl, l, k) pYlm[k] = pYlm_part.T * qkl # pYlm is real SPG_lmi = np.einsum('g,nmg->nmg', SI[ia].conj(), pYlm) SPG_lm_aoG = np.einsum('nmg,gp->nmp', SPG_lmi, aokG) tmp = np.einsum('ij,jmp->imp', hl, SPG_lm_aoG) vppnl += np.einsum('imp,imq->pq', SPG_lm_aoG.conj(), tmp) vppnl *= (1./ngs**2) if aoR.dtype == np.double: return vppnl.real else: return vppnl
def make_L1(pcmobj, r_vdw, ylm_1sph, fi): # See JCTC, 9, 3637, Eq (18) mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax eta = pcmobj.eta nlm = (lmax+1)**2 coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere(pcmobj.lebedev_order) ngrid_1sph = weights_1sph.size atom_coords = mol.atom_coords() ylm_1sph = ylm_1sph.reshape(nlm,ngrid_1sph) Lmat = numpy.zeros((natm,3,natm,nlm,natm,nlm)) fi1 = make_fi1(pcmobj, pcmobj.get_atomic_radii()) for ja in range(natm): part_weights = weights_1sph.copy() part_weights[fi[ja]>1] /= fi[ja,fi[ja]>1] part_weights1 = numpy.zeros((natm,3,ngrid_1sph)) tmp = part_weights[fi[ja]>1] / fi[ja,fi[ja]>1] part_weights1[:,:,fi[ja]>1] = -tmp * fi1[:,:,ja,fi[ja]>1] for ka in ddcosmo.atoms_with_vdw_overlap(ja, atom_coords, r_vdw): vjk = r_vdw[ja] * coords_1sph + atom_coords[ja] - atom_coords[ka] rv = lib.norm(vjk, axis=1) tjk = rv / r_vdw[ka] wjk0 = pcmobj.regularize_xt(tjk, eta, r_vdw[ka]) wjk1 = regularize_xt1(tjk, eta*r_vdw[ka]) sjk = vjk.T / rv wjk1 = 1./r_vdw[ka] * wjk1 * sjk wjk01 = wjk0 * part_weights1 wjk0 *= part_weights wjk1 *= part_weights pol0 = sph.multipoles(vjk, lmax) pol1 = multipoles1(vjk, lmax) p1 = 0 for l in range(lmax+1): fac = 4*numpy.pi/(l*2+1) / r_vdw[ka]**(l+1) p0, p1 = p1, p1 + (l*2+1) a = numpy.einsum('xn,zn,mn->zxm', ylm_1sph, wjk1, pol0[l]) a+= numpy.einsum('xn,n,zmn->zxm', ylm_1sph, wjk0, pol1[l]) Lmat[ja,:,ja,:,ka,p0:p1] += -fac * a Lmat[ka,:,ja,:,ka,p0:p1] -= -fac * a a = numpy.einsum('xn,azn,mn->azxm', ylm_1sph, wjk01, pol0[l]) Lmat[:,:,ja,:,ka,p0:p1] += -fac * a return Lmat
def eval_xc(self, xc_code, rho, spin=1, relativity=0, deriv=1, verbose=None): # JTCC, 2, 257 r, m = rho[:2] s = lib.norm(m, axis=0) rhou = (r + s) * .5 rhod = (r - s) * .5 rho = (rhou, rhod) xc = self.libxc.eval_xc(xc_code, rho, spin, relativity, deriv, verbose) exc, vxc = xc[:2] vrho = vxc[0] vr, vm = (vrho[:,0]+vrho[:,1])*.5, (vrho[:,0]-vrho[:,1])*.5 vrho[:,0] = vr vrho[:,1] = vm return xc
def get_lattice_Ls(cell, nimgs=None, rcut=None, dimension=None): '''Get the (Cartesian, unitful) lattice translation vectors for nearby images. The translation vectors can be used for the lattice summation.''' a = cell.lattice_vectors() b = cell.reciprocal_vectors(norm_to=1) heights_inv = lib.norm(b, axis=1) if nimgs is None: if rcut is None: rcut = cell.rcut # plus 1 image in rcut to handle the case atoms within the adjacent cells are # close to each other nimgs = np.ceil(rcut*heights_inv + 1.1).astype(int) else: rcut = max((np.asarray(nimgs))/heights_inv) if dimension is None: dimension = cell.dimension if dimension == 0: nimgs = [0, 0, 0] elif dimension == 1: nimgs = [nimgs[0], 0, 0] elif dimension == 2: nimgs = [nimgs[0], nimgs[1], 0] Ts = lib.cartesian_prod((np.arange(-nimgs[0],nimgs[0]+1), np.arange(-nimgs[1],nimgs[1]+1), np.arange(-nimgs[2],nimgs[2]+1))) Ls = np.dot(Ts, a) idx = np.zeros(len(Ls), dtype=bool) for ax in (-a[0], 0, a[0]): for ay in (-a[1], 0, a[1]): for az in (-a[2], 0, a[2]): idx |= lib.norm(Ls+(ax+ay+az), axis=1) < rcut Ls = Ls[idx] return np.asarray(Ls, order='C')
def _vxc2x2_to_mat(mol, ao, weight, rho, vrho, non0tab, shls_slice, ao_loc): aoa, aob = ao r, m = rho vr, vm = vrho.T aow = numpy.empty_like(aoa) # aow = numpy.einsum('pi,p->pi', aoa, weight*vr, out=aow) # mat = _dot_ao_ao(mol, aoa, aow, non0tab, shls_slice, ao_loc) # aow = numpy.einsum('pi,p->pi', aob, weight*vr, out=aow) # mat+= _dot_ao_ao(mol, aob, aow, non0tab, shls_slice, ao_loc) # # s = lib.norm(m, axis=0) # ws = vm * weight / (s+1e-300) # aow = numpy.einsum('pi,p->pi', aoa, ws*m[0], out=aow) # Mx # tmp = _dot_ao_ao(mol, aob, aow, non0tab, shls_slice, ao_loc) # mat+= tmp + tmp.T.conj() # aow = numpy.einsum('pi,p->pi', aoa, ws*m[1], out=aow) # My # tmp = _dot_ao_ao(mol, aob, aow, non0tab, shls_slice, ao_loc) # mat+= (tmp - tmp.T.conj()) * 1j # aow = numpy.einsum('pi,p->pi', aoa, ws*m[2], out=aow) # Mz # mat+= _dot_ao_ao(mol, aoa, aow, non0tab, shls_slice, ao_loc) # aow = numpy.einsum('pi,p->pi', aob, ws*m[2], out=aow) # mat-= _dot_ao_ao(mol, aob, aow, non0tab, shls_slice, ao_loc) s = lib.norm(m, axis=0) idx = s < 1e-20 with numpy.errstate(divide='ignore', invalid='ignore'): ws = vm * weight / s ws[idx] = 0 aow = numpy.einsum('pi,p->pi', aoa, ws * m[0], out=aow) # Mx tmp = _dot_ao_ao(mol, aob, aow, non0tab, shls_slice, ao_loc) mat = tmp + tmp.T.conj() aow = numpy.einsum('pi,p->pi', aoa, ws * m[1], out=aow) # My tmp = _dot_ao_ao(mol, aob, aow, non0tab, shls_slice, ao_loc) mat += (tmp - tmp.T.conj()) * 1j aow = numpy.einsum('pi,p->pi', aoa, weight * vr, out=aow) aow += numpy.einsum('pi,p->pi', aoa, ws * m[2]) # Mz mat += _dot_ao_ao(mol, aoa, aow, non0tab, shls_slice, ao_loc) aow = numpy.einsum('pi,p->pi', aob, weight * vr, out=aow) aow -= numpy.einsum('pi,p->pi', aob, ws * m[2]) # Mz mat += _dot_ao_ao(mol, aob, aow, non0tab, shls_slice, ao_loc) return mat
def vppnl_by_k(kpt): Gk = Gv + kpt G_rad = lib.norm(Gk, axis=1) aokG = ft_ao.ft_ao(cell, Gv, kpt=kpt) * (ngs/cell.vol) vppnl = 0 for ia in range(cell.natm): symb = cell.atom_symbol(ia) if symb not in cell._pseudo: continue pp = cell._pseudo[symb] p1 = 0 for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: fakemol._bas[0,gto.ANG_OF] = l fakemol._env[ptr+3] = .5*rl**2 fakemol._env[ptr+4] = rl**(l+1.5)*numpy.pi**1.25 pYlm_part = dft.numint.eval_ao(fakemol, Gk, deriv=0) p0, p1 = p1, p1+nl*(l*2+1) # pYlm is real, SI[ia] is complex pYlm = numpy.ndarray((nl,l*2+1,ngs), dtype=numpy.complex128, buffer=buf[p0:p1]) for k in range(nl): qkl = pseudo.pp._qli(G_rad*rl, l, k) pYlm[k] = pYlm_part.T * qkl #:SPG_lmi = numpy.einsum('g,nmg->nmg', SI[ia].conj(), pYlm) #:SPG_lm_aoG = numpy.einsum('nmg,gp->nmp', SPG_lmi, aokG) #:tmp = numpy.einsum('ij,jmp->imp', hl, SPG_lm_aoG) #:vppnl += numpy.einsum('imp,imq->pq', SPG_lm_aoG.conj(), tmp) SPG_lmi = buf[:p1] SPG_lmi *= SI[ia].conj() SPG_lm_aoGs = lib.zdot(SPG_lmi, aokG) p1 = 0 for l, proj in enumerate(pp[5:]): rl, nl, hl = proj if nl > 0: p0, p1 = p1, p1+nl*(l*2+1) hl = numpy.asarray(hl) SPG_lm_aoG = SPG_lm_aoGs[p0:p1].reshape(nl,l*2+1,-1) tmp = numpy.einsum('ij,jmp->imp', hl, SPG_lm_aoG) vppnl += numpy.einsum('imp,imq->pq', SPG_lm_aoG.conj(), tmp) return vppnl * (1./ngs**2)
def get_lattice_Ls(cell, nimgs=None, rcut=None, dimension=None, discard=True): '''Get the (Cartesian, unitful) lattice translation vectors for nearby images. The translation vectors can be used for the lattice summation.''' a = cell.lattice_vectors() b = cell.reciprocal_vectors(norm_to=1) heights_inv = lib.norm(b, axis=1) if nimgs is None: if rcut is None: rcut = cell.rcut # For atoms outside the cell, distance between certain basis of nearby # images may be smaller than rcut threshold even the corresponding Ls is # larger than rcut. The boundary penalty ensures that Ls would be able to # cover the basis that sitting out of the cell. # See issue https://github.com/pyscf/pyscf/issues/1017 scaled_atom_coords = cell.atom_coords().dot(b.T) boundary_penalty = np.max([ abs(scaled_atom_coords).max(axis=0), abs(1 - scaled_atom_coords).max(axis=0) ], axis=0) nimgs = np.ceil(rcut * heights_inv + boundary_penalty).astype(int) else: rcut = max((np.asarray(nimgs)) / heights_inv) if dimension is None: dimension = cell.dimension if dimension == 0: nimgs = [0, 0, 0] elif dimension == 1: nimgs = [nimgs[0], 0, 0] elif dimension == 2: nimgs = [nimgs[0], nimgs[1], 0] Ts = lib.cartesian_prod( (np.arange(-nimgs[0], nimgs[0] + 1), np.arange(-nimgs[1], nimgs[1] + 1), np.arange(-nimgs[2], nimgs[2] + 1))) Ls = np.dot(Ts, a) if discard: Ls = _discard_edge_images(cell, Ls, rcut) return np.asarray(Ls, order='C')
def init_guess_by_chkfile(cell, chkfile_name, project=True, kpt=None): '''Read the HF results from checkpoint file, then project it to the basis defined by ``cell`` Returns: Density matrix, (nao,nao) ndarray ''' chk_cell, scf_rec = chkfile.load_scf(chkfile_name) mo = scf_rec['mo_coeff'] mo_occ = scf_rec['mo_occ'] if kpt is None: kpt = np.zeros(3) if 'kpt' in scf_rec: chk_kpt = scf_rec['kpt'] elif 'kpts' in scf_rec: kpts = scf_rec['kpts'] # the closest kpt from KRHF results where = np.argmin(lib.norm(kpts-kpt, axis=1)) chk_kpt = kpts[where] if mo.ndim == 3: # KRHF: mo = mo[where] mo_occ = mo_occ[where] else: mo = mo[:,where] mo_occ = mo_occ[:,where] else: chk_kpt = np.zeros(3) def fproj(mo): if project: return addons.project_mo_nr2nr(chk_cell, mo, cell, chk_kpt-kpt) else: return mo if mo.ndim == 2: dm = pyscf.scf.hf.make_rdm1(fproj(mo), mo_occ) else: # UHF dm = np.asarray((pyscf.scf.hf.make_rdm1(fproj(mo[0]), mo_occ[0]), pyscf.scf.hf.make_rdm1(fproj(mo[1]), mo_occ[1]))) # Real DM for gamma point if kpt is None or np.allclose(kpt, 0): dm = dm.real return dm
def eval_xc(self, xc_code, rho, spin=1, relativity=0, deriv=1, verbose=None): # JTCC, 2, 257 r, m = rho[:2] s = lib.norm(m, axis=0) rhou = (r + s) * .5 rhod = (r - s) * .5 rho = (rhou, rhod) xc = self.libxc.eval_xc(xc_code, rho, spin, relativity, deriv, verbose) exc, vxc = xc[:2] vrho = vxc[0] vr, vm = (vrho[:, 0] + vrho[:, 1]) * .5, (vrho[:, 0] - vrho[:, 1]) * .5 vrho[:, 0] = vr vrho[:, 1] = vm return xc
def _e_nuc(mol: gto.Mole, mm_mol: Union[None, gto.Mole]) -> np.ndarray: """ this function returns the nuclear repulsion energy """ # coordinates and charges of nuclei coords = mol.atom_coords() charges = mol.atom_charges() # internuclear distances (with self-repulsion removed) dist = gto.inter_distance(mol) dist[np.diag_indices_from(dist)] = 1e200 e_nuc = contract('i,ij,j->i', charges, 1. / dist, charges) * .5 # possible interaction with mm sites if mm_mol is not None: mm_coords = mm_mol.atom_coords() mm_charges = mm_mol.atom_charges() for j in range(mol.natm): q2, r2 = charges[j], coords[j] r = lib.norm(r2 - mm_coords, axis=1) e_nuc[j] += q2 * np.sum(mm_charges / r) return e_nuc
def cutoff_to_mesh(a, cutoff): r''' Convert KE cutoff to FFT-mesh uses KE = k^2 / 2, where k_max ~ \pi / grid_spacing Args: a : (3,3) ndarray The real-space unit cell lattice vectors. Each row represents a lattice vector. cutoff : float KE energy cutoff in a.u. Returns: mesh : (3,) array ''' b = 2 * np.pi * np.linalg.inv(a.T) cutoff = cutoff * _cubic2nonorth_factor(a) mesh = np.ceil(np.sqrt(2 * cutoff) / lib.norm(b, axis=1) * 2).astype(int) return mesh
def cosmo_occ_o1(cosmo, dm): mol = cosmo.mol nao = dm.shape[0] #cosmo.check() cosmo.occ0() cosmo.loadsegs() #cosmo.check() ioff = 3*cosmo.nps coords = cosmo.cosurf[ioff:ioff+cosmo.npspher*3].reshape(-1,3) fakemol = _make_fakemol(coords) j3c = df.incore.aux_e2(mol, fakemol, intor='cint3c2e_sph', aosym='s2ij') tril_dm = lib.pack_tril(dm) * 2 diagidx = numpy.arange(nao) diagidx = diagidx*(diagidx+1)//2 + diagidx tril_dm[diagidx] *= .5 cosmo.phio = -numpy.einsum('x,xk->k', tril_dm, j3c) for ia in range(mol.natm): cosmo.phio += mol.atom_charge(ia)/lib.norm(mol.atom_coord(ia)-coords, axis=1) cosmo.savesegs() return cosmo.occ1()
def cutoff_to_gs(a, cutoff): ''' Convert KE cutoff to #grid points (gs variable) for FFT-mesh uses KE = k^2 / 2, where k_max ~ \pi / grid_spacing Args: a : (3,3) ndarray The real-space unit cell lattice vectors. Each row represents a lattice vector. cutoff : float KE energy cutoff in a.u. Returns: gs : (3,) array ''' grid_spacing = np.pi / np.sqrt(2 * cutoff) # number of grid points is 2gs+1 (~ 2 gs) along each direction gs = np.ceil(lib.norm(a, axis=1) / (2 * grid_spacing)).astype(int) return gs
def get_bounding_sphere(cell, rcut): '''Finds all the lattice points within a sphere of radius rcut. Defines a parallelipiped given by -N_x <= n_x <= N_x, with x in [1,3] See Martin p. 85 Args: rcut : number real space cut-off for interaction Returns: cut : ndarray of 3 ints defining N_x ''' #Gmat = cell.reciprocal_vectors(norm_to=1) #n1 = np.ceil(lib.norm(Gmat[0,:])*rcut) #n2 = np.ceil(lib.norm(Gmat[1,:])*rcut) #n3 = np.ceil(lib.norm(Gmat[2,:])*rcut) #cut = np.array([n1, n2, n3]).astype(int) b = cell.reciprocal_vectors(norm_to=1) heights_inv = lib.norm(b, axis=1) return np.ceil(rcut * heights_inv).astype(int)
def __init__(self, atoms, basis=None): self.atomtypes = mole.atom_types(atoms, basis) # fake systems, which treates the atoms of different basis as different atoms. # the fake systems do not have the same symmetry as the potential # it's only used to determine the main (Z-)axis chg1 = numpy.pi - 2 coords = [] fake_chgs = [] idx = [] for k, lst in self.atomtypes.items(): idx.append(lst) coords.append([atoms[i][1] for i in lst]) ksymb = mole._rm_digit(k) if ksymb != k: # Put random charges on the decorated atoms fake_chgs.append([chg1] * len(lst)) chg1 *= numpy.pi - 2 elif 'GHOST' in ksymb: ksymb = mole._remove_prefix_ghost(ksymb) fake_chgs.append([mole._charge(ksymb) + .3] * len(lst)) else: fake_chgs.append([mole._charge(ksymb)] * len(lst)) coords = numpy.array(numpy.vstack(coords), dtype=float) fake_chgs = numpy.hstack(fake_chgs) self.charge_center = numpy.einsum('i,ij->j', fake_chgs, coords) / fake_chgs.sum() coords = coords - self.charge_center idx = numpy.argsort(numpy.hstack(idx)) self.atoms = numpy.hstack((fake_chgs.reshape(-1, 1), coords))[idx] self.group_atoms_by_distance = [] decimals = int(-numpy.log10(TOLERANCE)) - 1 for index in self.atomtypes.values(): index = numpy.asarray(index) c = self.atoms[index, 1:] dists = numpy.around(norm(c, axis=1), decimals) u, idx = numpy.unique(dists, return_inverse=True) for i, s in enumerate(u): self.group_atoms_by_distance.append(index[idx == i])
def test_make_ylm(self): numpy.random.seed(1) lmax = 6 r = numpy.random.random((100, 3)) - numpy.ones(3) * .5 r = r / lib.norm(r, axis=1).reshape(-1, 1) ngrid = r.shape[0] cosphi = r[:, 2] sinphi = (1 - cosphi**2)**.5 costheta = numpy.ones(ngrid) sintheta = numpy.zeros(ngrid) costheta[sinphi != 0] = r[sinphi != 0, 0] / sinphi[sinphi != 0] sintheta[sinphi != 0] = r[sinphi != 0, 1] / sinphi[sinphi != 0] costheta[costheta > 1] = 1 costheta[costheta < -1] = -1 sintheta[sintheta > 1] = 1 sintheta[sintheta < -1] = -1 varphi = numpy.arccos(cosphi) theta = numpy.arccos(costheta) theta[sintheta < 0] = 2 * numpy.pi - theta[sintheta < 0] ylmref = [] for l in range(lmax + 1): ylm = numpy.empty((l * 2 + 1, ngrid)) ylm[l] = scipy.special.sph_harm(0, l, theta, varphi).real for m in range(1, l + 1): f1 = scipy.special.sph_harm(-m, l, theta, varphi) f2 = scipy.special.sph_harm(m, l, theta, varphi) # complex to real spherical functions if m % 2 == 1: ylm[l - m] = (-f1.imag - f2.imag) / numpy.sqrt(2) ylm[l + m] = (f1.real - f2.real) / numpy.sqrt(2) else: ylm[l - m] = (-f1.imag + f2.imag) / numpy.sqrt(2) ylm[l + m] = (f1.real + f2.real) / numpy.sqrt(2) if l == 1: ylm = ylm[[2, 0, 1]] ylmref.append(ylm) ylmref = numpy.vstack(ylmref) ylm = numpy.vstack(sph.real_sph_vec(r, lmax, True)) self.assertTrue(abs(ylmref - ylm).max() < 1e-14)
def make_L(pcmobj, r_vdw, lebedev_order, lmax, eta=0.1): mol = pcmobj.mol natm = mol.natm nlm = (lmax + 1)**2 leb_coords, leb_weights = ddcosmo.make_grids_one_sphere(lebedev_order) nleb_grid = leb_weights.size atom_coords = mol.atom_coords() Ylm_sphere = numpy.vstack(sph.real_sph_vec(leb_coords, lmax, True)) fi = ddcosmo.make_fi(pcmobj, r_vdw) L_diag = numpy.zeros((natm, nlm)) p1 = 0 for l in range(lmax + 1): p0, p1 = p1, p1 + (l * 2 + 1) L_diag[:, p0:p1] = 4 * numpy.pi / (l * 2 + 1) L_diag /= r_vdw.reshape(-1, 1) L = numpy.diag(L_diag.ravel()).reshape(natm, nlm, natm, nlm) for ja in range(natm): for ka in range(natm): if ja == ka: continue vjk = r_vdw[ja] * leb_coords + atom_coords[ja] - atom_coords[ka] v = lib.norm(vjk, axis=1) tjk = v / r_vdw[ka] sjk = vjk / v.reshape(-1, 1) Ys = sph.real_sph_vec(sjk, lmax, True) # scale the weight, see JCTC 9, 3637, Eq (16) wjk = pcmobj.regularize_xt(tjk, eta, r_vdw[ka]) wjk[fi[ja] > 1] /= fi[ja, fi[ja] > 1] tt = numpy.ones_like(wjk) p1 = 0 for l in range(lmax + 1): fac = 4 * numpy.pi / (l * 2 + 1) / r_vdw[ka] p0, p1 = p1, p1 + (l * 2 + 1) val = numpy.einsum('n,xn,n,mn->xm', leb_weights, Ylm_sphere, wjk * tt, Ys[l]) L[ja, :, ka, p0:p1] += -fac * val tt *= tjk return L.reshape(natm * nlm, natm * nlm)
def make_vmat(pcm, r_vdw, lebedev_order, lmax, LX, LS): mol = pcm.mol grids = dft.gen_grid.Grids(mol) atom_grids_tab = grids.gen_atomic_grids(mol) grids.build() coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere(lebedev_order) ao = dft.numint.eval_ao(mol, grids.coords) nao = ao.shape[1] vmat = numpy.zeros((nao, nao)) i1 = 0 for ia in range(mol.natm): xnj, w = atom_grids_tab[mol.atom_symbol(ia)] i0, i1 = i1, i1 + w.size r = lib.norm(xnj, axis=1) Ys = sph.real_sph_vec(xnj / r.reshape(-1, 1), lmax, True) p1 = 0 for l in range(lmax + 1): fac = 4 * numpy.pi / (l * 2 + 1) p0, p1 = p1, p1 + (l * 2 + 1) rr = numpy.zeros_like(r) rr[r <= r_vdw[ia]] = r[r <= r_vdw[ia]]**l / r_vdw[ia]**(l + 1) rr[r > r_vdw[ia]] = r_vdw[ia]**l / r[r > r_vdw[ia]]**(l + 1) eta_nj = fac * numpy.einsum('n,mn,m->n', rr, Ys[l], LX[ia, p0:p1]) vmat -= numpy.einsum('n,np,nq->pq', grids.weights[i0:i1] * eta_nj, ao[i0:i1], ao[i0:i1]) atom_coords = mol.atom_coords() Ylm_sphere = numpy.vstack(sph.real_sph_vec(coords_1sph, lmax, True)) fi = ddcosmo.make_fi(pcm, r_vdw) ui = 1 - fi ui[ui < 0] = 0 xi_nj = numpy.einsum('n,jn,xn,jx->jn', weights_1sph, ui, Ylm_sphere, LS) pmol = mol.copy() for ia in range(mol.natm): for i, c in enumerate(coords_1sph): r = atom_coords[ia] + r_vdw[ia] * c pmol.set_rinv_orig(r) vmat += pmol.intor('int1e_rinv') * xi_nj[ia, i] return vmat
def get_ewald_params(cell, precision=1e-8, gs=None): r'''Choose a reasonable value of Ewald 'eta' and 'cut' parameters. Choice is based on largest G vector and desired relative precision. The relative error in the G-space sum is given by precision ~ 4\pi Gmax^2 e^{(-Gmax^2)/(4 \eta^2)} which determines eta. Then, real-space cutoff is determined by (exp. factors only) precision ~ erfc(eta*rcut) / rcut ~ e^{(-eta**2 rcut*2)} Returns: ew_eta, ew_cut : float The Ewald 'eta' and 'cut' parameters. ''' if cell.natm == 0: return 0, 0 elif cell.dimension == 3: if gs is None: gs = 5 else: gs = np.copy(gs) gs[gs > 40] = 40 Gmax = min( np.asarray(gs) * lib.norm(cell.reciprocal_vectors(), axis=1)) log_precision = np.log(precision / (4 * np.pi * Gmax**2)) ew_eta = np.sqrt(-Gmax**2 / (4 * log_precision)) ew_cut = _estimate_rcut(ew_eta**2, 0, 1., precision) else: # Non-uniform PW grids are used for low-dimensional ewald summation. The cutoff # estimation for long range part based on exp(G^2/(4*eta^2)) does not work for # non-uniform grids. Smooth model density is preferred. ew_cut = cell.rcut ew_eta = np.sqrt( max(np.log(4 * np.pi * ew_cut**2 / precision) / ew_cut**2, .1)) return ew_eta, ew_cut
def make_fi1(pcmobj, r_vdw): coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere(pcmobj.lebedev_order) mol = pcmobj.mol eta = pcmobj.eta natm = mol.natm atom_coords = mol.atom_coords() ngrid_1sph = coords_1sph.shape[0] fi1 = numpy.zeros((natm,3,natm,ngrid_1sph)) for ia in range(natm): for ja in ddcosmo.atoms_with_vdw_overlap(ia, atom_coords, r_vdw): v = r_vdw[ia]*coords_1sph + atom_coords[ia] - atom_coords[ja] rv = lib.norm(v, axis=1) t = rv / r_vdw[ja] xt1 = regularize_xt1(t, eta*r_vdw[ja]) s_ij = v.T / rv xt1 = 1./r_vdw[ja] * xt1 * s_ij fi1[ia,:,ia] += xt1 fi1[ja,:,ia] -= xt1 fi = ddcosmo.make_fi(pcmobj, r_vdw) fi1[:,:,fi<1e-20] = 0 return fi1
def get_nimgs(cell, precision=None): r'''Choose number of basis function images in lattice sums to include for given precision in overlap, using precision ~ 4 * pi * r^2 * e^{-\alpha r^2} where \alpha is the smallest exponent in the basis. Note that assumes an isolated exponent in the middle of the box, so it adds one additional lattice vector to be safe. ''' if precision is None: precision = cell.precision min_exp = np.min([np.min(cell.bas_exp(ib)) for ib in range(cell.nbas)]) def fn(r): return np.log(4 * np.pi * r**2) - min_exp * r**2 - np.log(precision) guess = np.sqrt((5 - np.log(precision)) / min_exp) rcut = scipy.optimize.fsolve(fn, guess, xtol=1e-4)[0] rlengths = lib.norm(cell.lattice_vectors(), axis=1) + 1e-200 nimgs = np.ceil(np.reshape(rcut / rlengths, rlengths.shape[0])).astype(int) return nimgs + 1 # additional lattice vector to take into account
def make_fi(pcmobj, r_vdw): coords_1sph, weights_1sph = make_grids_one_sphere(pcmobj.lebedev_order) mol = pcmobj.mol eta = pcmobj.eta natm = mol.natm natm_tot = natm atom_coords = mol.atom_coords() ngrid_1sph = coords_1sph.shape[0] if pcmobj.mm_mol is not None: atom_coords = numpy.vstack((atom_coords, pcmobj.mm_mol.atom_coords())) natm_tot += pcmobj.mm_mol.natm ngrid_1sph = coords_1sph.shape[0] fi = numpy.zeros((natm_tot, ngrid_1sph)) for ia in range(natm_tot): for ja in atoms_with_vdw_overlap(ia, atom_coords, r_vdw): v = r_vdw[ia] * coords_1sph + atom_coords[ia] - atom_coords[ja] rv = lib.norm(v, axis=1) t = rv / r_vdw[ja] xt = pcmobj.regularize_xt(t, eta, r_vdw[ja]) fi[ia] += xt fi[fi < 1e-20] = 0 return fi
def get_pp_loc_part2(cell, kpt=np.zeros(3)): coords = gen_grid.gen_uniform_grids(cell) aoR = numint.eval_ao(cell, coords, kpt) nao = cell.nao_nr() SI = cell.get_SI() G = lib.norm(cell.Gv, axis=1) vlocG = np.zeros((cell.natm,len(G))) for ia in range(cell.natm): Zia = cell.atom_charge(ia) symb = cell.atom_symbol(ia) if symb not in cell._pseudo: vlocG[ia] = 0 continue pp = cell._pseudo[symb] rloc, nexp, cexp = pp[1:3+1] G_red = G*rloc cfacs = np.array( [1*G_red**0, 3 - G_red**2, 15 - 10*G_red**2 + G_red**4, 105 - 105*G_red**2 + 21*G_red**4 - G_red**6]) with np.errstate(divide='ignore'): # Note the signs -- potential here is positive vlocG[ia,:] = (# 4*np.pi * Zia * np.exp(-0.5*G_red**2)/G**2 - (2*np.pi)**(3/2.)*rloc**3*np.exp(-0.5*G_red**2)*( np.dot(cexp, cfacs[:nexp])) ) vpplocG = -np.sum(SI * vlocG, axis=0) vpplocR = tools.ifft(vpplocG, cell.gs).real vpploc = np.dot(aoR.T.conj(), vpplocR.reshape(-1,1)*aoR) if aoR.dtype == np.double: return vpploc.real else: return vpploc
def _ncol_lda_vxc_mat(mol, ao, weight, rho, vxc, mask, shls_slice, ao_loc, hermi): '''Vxc matrix of non-collinear LDA''' # NOTE vxc in u/d representation r, mx, my, mz = rho vxc = xc_deriv.ud2ts(vxc) vr, vs = vxc[:,0] s = lib.norm(rho[1:4], axis=0) wv = weight * vr with np.errstate(divide='ignore',invalid='ignore'): ws = vs * weight / s ws[s < 1e-20] = 0 # * .5 because of v+v.conj().T in r_vxc if hermi: wv *= .5 ws *= .5 aow = None aow = _scale_ao(ao, ws*mx, out=aow) # Mx tmpx = _dot_ao_ao(mol, ao, aow, mask, shls_slice, ao_loc) aow = _scale_ao(ao, ws*my, out=aow) # My tmpy = _dot_ao_ao(mol, ao, aow, mask, shls_slice, ao_loc) if hermi: # conj(mx+my*1j) == mx-my*1j, tmpx and tmpy should be real matba = (tmpx + tmpx.T) + (tmpy + tmpy.T) * 1j matab = np.zeros_like(matba) else: # conj(mx+my*1j) != mx-my*1j, tmpx and tmpy should be complex matba = tmpx + tmpy * 1j matab = tmpx - tmpy * 1j tmpx = tmpy = None aow = _scale_ao(ao, wv+ws*mz, out=aow) # Mz mataa = _dot_ao_ao(mol, ao, aow, mask, shls_slice, ao_loc) aow = _scale_ao(ao, wv-ws*mz, out=aow) # Mz matbb = _dot_ao_ao(mol, ao, aow, mask, shls_slice, ao_loc) mat = np.block([[mataa, matab], [matba, matbb]]) return mat
def search_c2x(self, zaxis, n): '''C2 axis which is perpendicular to z-axis''' decimals = int(-numpy.log10(TOLERANCE)) - 1 for lst in self.group_atoms_by_distance: if len(lst) > 1: r0 = self.atoms[lst, 1:] zcos = numpy.around(numpy.einsum('ij,j->i', r0, zaxis), decimals=decimals) uniq_zcos = numpy.unique(zcos) maybe_c2x = [] for d in uniq_zcos: if d > TOLERANCE: mirrord = abs(zcos + d) < TOLERANCE if mirrord.sum() == (zcos == d).sum(): above = r0[zcos == d] below = r0[mirrord] nelem = len(below) maybe_c2x.extend( [above[0] + below[i] for i in range(nelem)]) elif abs(d) < TOLERANCE: # plane which crosses the orig r1 = r0[zcos == d][0] maybe_c2x.append(r1) r2 = numpy.dot(rotation_mat(zaxis, numpy.pi * 2 / n), r1) if abs(r1 + r2).sum() > TOLERANCE: maybe_c2x.append(r1 + r2) else: maybe_c2x.append(r2 - r1) if len(maybe_c2x) > 0: idx = norm(maybe_c2x, axis=1) > TOLERANCE maybe_c2x = _normalize(maybe_c2x)[idx] maybe_c2x = _remove_dupvec(maybe_c2x) for c2x in maybe_c2x: if (not parallel_vectors(c2x, zaxis) and self.has_rotation(c2x, 2)): return c2x
def make_A(pcmobj, r_vdw, ylm_1sph, ui): # Part of A matrix defined in JCP, 144, 054101, Eq (43), (44) mol = pcmobj.mol natm = mol.natm lmax = pcmobj.lmax eta = pcmobj.eta nlm = (lmax + 1)**2 coords_1sph, weights_1sph = ddcosmo.make_grids_one_sphere( pcmobj.lebedev_order) ngrid_1sph = weights_1sph.size atom_coords = mol.atom_coords() ylm_1sph = ylm_1sph.reshape(nlm, ngrid_1sph) Amat = numpy.zeros((natm, nlm, natm, nlm)) for ja in range(natm): # w_u = precontract w_n U_j w_u = weights_1sph * ui[ja] p1 = 0 for l in range(lmax + 1): fac = 2 * numpy.pi / (l * 2 + 1) p0, p1 = p1, p1 + (l * 2 + 1) a = numpy.einsum('xn,n,mn->xm', ylm_1sph, w_u, ylm_1sph[p0:p1]) Amat[ja, :, ja, p0:p1] += -fac * a for ka in ddcosmo.atoms_with_vdw_overlap(ja, atom_coords, r_vdw): vjk = r_vdw[ja] * coords_1sph + atom_coords[ja] - atom_coords[ka] rjk = lib.norm(vjk, axis=1) pol = sph.multipoles(vjk, lmax) p1 = 0 weights = w_u / rjk**(l * 2 + 1) for l in range(lmax + 1): fac = 4 * numpy.pi * l / (l * 2 + 1) * r_vdw[ka]**(l + 1) p0, p1 = p1, p1 + (l * 2 + 1) a = numpy.einsum('xn,n,mn->xm', ylm_1sph, weights, pol[l]) Amat[ja, :, ka, p0:p1] += -fac * a return Amat
def cache_fake_multipoles(grids, r_vdw, lmax): # For each type of atoms, cache the product of last two terms in # JCP, 141, 184108, Eq (31): # x_{<}^{l} / x_{>}^{l+1} Y_l^m mol = grids.mol atom_grids_tab = grids.gen_atomic_grids(mol) r_vdw_type = {} for ia in range(mol.natm): symb = mol.atom_symbol(ia) if symb not in r_vdw_type: r_vdw_type[symb] = r_vdw[ia] cached_pol = {} for symb in atom_grids_tab: x_nj, w = atom_grids_tab[symb] r = lib.norm(x_nj, axis=1) # Different equations are used in JCTC, 9, 3637. r*Ys (the fake_pole) # is computed as r^l/r_vdw. "leak_idx" is not needed. # Here, the implementation is based on JCP, 141, 184108 leak_idx = r > r_vdw_type[symb] pol = sph.multipoles(x_nj, lmax) fak_pol = [] for l in range(lmax + 1): # x_{<}^{l} / x_{>}^{l+1} Y_l^m in JCP, 141, 184108, Eq (31) #:Ys = sph.real_sph_vec(x_nj/r.reshape(-1,1), lmax, True) #:rr = numpy.zeros_like(r) #:rr[r<=r_vdw[ia]] = r[r<=r_vdw[ia]]**l / r_vdw[ia]**(l+1) #:rr[r> r_vdw[ia]] = r_vdw[ia]**l / r[r>r_vdw[ia]]**(l+1) #:xx_ylm = numpy.einsum('n,mn->mn', rr, Ys[l]) xx_ylm = pol[l] * (1. / r_vdw_type[symb]**(l + 1)) # The line below is not needed for JCTC, 9, 3637 xx_ylm[:, leak_idx] *= (r_vdw_type[symb] / r[leak_idx])**(2 * l + 1) fak_pol.append(xx_ylm) cached_pol[symb] = (fak_pol, leak_idx) return cached_pol
def eval_xc(self, xc_code, rho, spin=1, relativity=0, deriv=1, omega=None, verbose=None): if omega is None: omega = self.omega # JTCC, 2, 257 r, m = rho[:2] s = lib.norm(m, axis=0) rhou = (r + s) * .5 rhod = (r - s) * .5 rho = (rhou, rhod) xc = self.libxc.eval_xc(xc_code, rho, 1, relativity, deriv, omega, verbose) exc, vxc = xc[:2] # update vxc[0] inplace vrho = vxc[0] vr, vm = (vrho[:, 0] + vrho[:, 1]) * .5, (vrho[:, 0] - vrho[:, 1]) * .5 vrho[:, 0] = vr vrho[:, 1] = vm return xc
def nimgs(self, x): b = self.reciprocal_vectors(norm_to=1) heights_inv = lib.norm(b, axis=1) self.rcut = max((np.asarray(x) + 1) / heights_inv)
def ewald(cell, ew_eta=None, ew_cut=None): '''Perform real (R) and reciprocal (G) space Ewald sum for the energy. Formulation of Martin, App. F2. Returns: float The Ewald energy consisting of overlap, self, and G-space sum. See Also: pyscf.pbc.gto.get_ewald_params ''' if ew_eta is None: ew_eta = cell.ew_eta if ew_cut is None: ew_cut = cell.ew_cut chargs = cell.atom_charges() coords = cell.atom_coords() Lall = cell.get_lattice_Ls(rcut=ew_cut) ewovrl = 0. for i, qi in enumerate(chargs): ri = coords[i] for j in range(i): qj = chargs[j] rj = coords[j] r1 = ri - rj + Lall r = np.sqrt(np.einsum('ji,ji->j', r1, r1)) ewovrl += (qi * qj / r * scipy.special.erfc(ew_eta * r)).sum() # exclude the point where Lall == 0 r = lib.norm(Lall, axis=1) r[r < 1e-16] = 1e200 ewovrl += .5 * (chargs** 2).sum() * (1. / r * scipy.special.erfc(ew_eta * r)).sum() # last line of Eq. (F.5) in Martin ewself = -.5 * np.dot(chargs, chargs) * 2 * ew_eta / np.sqrt(np.pi) if cell.dimension == 3: ewself += -.5 * np.sum(chargs)**2 * np.pi / (ew_eta**2 * cell.vol) # g-space sum (using g grid) (Eq. (F.6) in Martin, but note errors as below) # Eq. (F.6) in Martin is off by a factor of 2, the # exponent is wrong (8->4) and the square is in the wrong place # # Formula should be # 1/2 * 4\pi / Omega \sum_I \sum_{G\neq 0} |ZS_I(G)|^2 \exp[-|G|^2/4\eta^2] # where # ZS_I(G) = \sum_a Z_a exp (i G.R_a) # See also Eq. (32) of ewald.pdf at # http://www.fisica.uniud.it/~giannozz/public/ewald.pdf gs = cell.gs Gv, Gvbase, weights = cell.get_Gv_weights(gs) absG2 = np.einsum('gi,gi->g', Gv, Gv) absG2[absG2 == 0] = 1e200 coulG = 4 * np.pi / absG2 coulG *= weights JexpG2 = np.exp(-absG2 / (4 * ew_eta**2)) * coulG ZSI = np.einsum("i,ij->j", chargs, cell.get_SI(Gv)) ZSIG2 = np.abs(ZSI)**2 ewg = .5 * np.dot(ZSIG2, JexpG2) logger.debug(cell, 'Ewald components = %.15g, %.15g, %.15g', ewovrl, ewself, ewg) return ewovrl + ewself + ewg
def norm_xy(z): x, y = z.reshape(2, nocc, nvir) norm = lib.norm(x)**2 - lib.norm(y)**2 norm = numpy.sqrt(.5 / norm) # normalize to 0.5 for alpha spin return x * norm, y * norm
def build(self): t0 = (time.clock(), time.time()) lib.logger.TIMER_LEVEL = 3 cell = libpbc.chkfile.load_cell(self.chkfile) cell.ecp = None self.cell = cell self.a = self.cell.lattice_vectors() self.b = self.cell.reciprocal_vectors() self.vol = self.cell.vol self.nelectron = self.cell.nelectron self.charge = self.cell.charge self.spin = self.cell.spin self.natm = self.cell.natm self.kpts = lib.chkfile.load(self.chkfile, 'kcell/kpts') self.nkpts = len(self.kpts) self.ls = cell.get_lattice_Ls(dimension=3) self.ls = self.ls[numpy.argsort(lib.norm(self.ls, axis=1))] self.atm = numpy.asarray(cell._atm, dtype=numpy.int32, order='C') self.bas = numpy.asarray(cell._bas, dtype=numpy.int32, order='C') self.env = numpy.asarray(cell._env, dtype=numpy.double, order='C') self.nbas = self.bas.shape[0] self.ao_loc = cell.ao_loc_nr() self.shls_slice = (0, self.nbas) sh0, sh1 = self.shls_slice self.nao = self.ao_loc[sh1] - self.ao_loc[sh0] self.non0tab = numpy.empty((1,self.nbas), dtype=numpy.int8) # non0tab stores the number of images to be summed in real space. # Initializing it to 255 means all images are summed self.non0tab[:] = 0xff self.coords = numpy.asarray([(numpy.asarray(atom[1])).tolist() for atom in cell._atom]) self.charges = cell.atom_charges() self.mo_coeff = lib.chkfile.load(self.chkfile, 'scf/mo_coeff') self.mo_occ = lib.chkfile.load(self.chkfile, 'scf/mo_occ') nprims, nmo = self.mo_coeff[0].shape self.nprims = nprims self.nmo = nmo self.cart = cell.cart if (not self.leb): self.npang = self.npphi*self.nptheta self.rcut = _estimate_rcut(self) kpts = numpy.reshape(self.kpts, (-1,3)) kpts_lst = numpy.reshape(kpts, (-1,3)) self.explk = numpy.exp(1j * numpy.asarray(numpy.dot(self.ls, kpts_lst.T), order='C')) if (self.ntrial%2 == 0): self.ntrial += 1 geofac = numpy.power(((self.rmaxsurf-0.1)/self.rprimer),(1.0/(self.ntrial-1.0))) self.rpru = numpy.zeros((self.ntrial)) for i in range(self.ntrial): self.rpru[i] = self.rprimer*numpy.power(geofac,(i+1)-1) self.rsurf = numpy.zeros((self.npang,self.ntrial), order='C') self.nlimsurf = numpy.zeros((self.npang), dtype=numpy.int32) if self.verbose >= logger.WARN: self.check_sanity() if self.verbose > logger.NOTE: self.dump_input() if (self.iqudt == 'legendre'): self.iqudt = 1 if (self.leb): self.grids = grid.lebgrid(self.npang) else: self.grids = grid.anggrid(self.iqudt,self.nptheta,self.npphi) self.xyzrho = numpy.zeros((self.natm,3)) t = time.time() logger.info(self,'Time finding nucleus %.3f (sec)' % (time.time()-t)) if (self.backend == 'rkck'): backend = 1 elif (self.backend == 'rkdp'): backend = 2 else: raise NotImplementedError('Only rkck or rkdp ODE solver yet available') ct_ = numpy.asarray(self.grids[:,0], order='C') st_ = numpy.asarray(self.grids[:,1], order='C') cp_ = numpy.asarray(self.grids[:,2], order='C') sp_ = numpy.asarray(self.grids[:,3], order='C') mo_coeff = numpy.zeros((self.nkpts,self.nprims,self.nmo), dtype=numpy.complex128) mo_occ = numpy.zeros((self.nkpts,self.nmo)) for k in range(self.nkpts): mo_coeff[k,:,:] = self.mo_coeff[k][:,:] mo_occ[k,:] = self.mo_occ[k][:] t = time.time() feval = 'surf_driver' drv = getattr(libaim, feval) with lib.with_omp_threads(self.nthreads): drv(ctypes.c_int(self.inuc), self.xyzrho.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.npang), ct_.ctypes.data_as(ctypes.c_void_p), st_.ctypes.data_as(ctypes.c_void_p), cp_.ctypes.data_as(ctypes.c_void_p), sp_.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.ntrial), self.rpru.ctypes.data_as(ctypes.c_void_p), ctypes.c_double(self.epsiscp), ctypes.c_double(self.epsroot), ctypes.c_double(self.rmaxsurf), ctypes.c_int(backend), ctypes.c_double(self.epsilon), ctypes.c_double(self.step), ctypes.c_int(self.mstep), ctypes.c_int(self.natm), self.coords.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.cart), ctypes.c_int(self.nmo), ctypes.c_int(self.nprims), self.atm.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.nbas), self.bas.ctypes.data_as(ctypes.c_void_p), self.env.ctypes.data_as(ctypes.c_void_p), self.ao_loc.ctypes.data_as(ctypes.c_void_p), mo_coeff.ctypes.data_as(ctypes.c_void_p), mo_occ.ctypes.data_as(ctypes.c_void_p), ctypes.c_double(self.occdrop), # self.a.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(len(self.ls)), self.ls.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(self.nkpts), self.explk.ctypes.data_as(ctypes.c_void_p), self.rcut.ctypes.data_as(ctypes.c_void_p), self.non0tab.ctypes.data_as(ctypes.c_void_p), # self.nlimsurf.ctypes.data_as(ctypes.c_void_p), self.rsurf.ctypes.data_as(ctypes.c_void_p)) for i in range(self.nkpts): print k,self.mo_occ[k][:] logger.info(self,'Time finding surface %.3f (sec)' % (time.time()-t)) r = numpy.array([0.00000, 0.00000, 0.00000]) r = numpy.reshape(r, (-1,3)) ao = dft.numint.eval_ao_kpts(self.cell, r, kpts=self.kpts, deriv=1) print rhograd(self,[0,0,0]) logger.info(self,'Surface of atom %d saved',self.inuc) logger.timer(self,'BaderSurf build', *t0) return self
occup = 2.0 norb = cell.nelectron // 2 for i in range(norb): fspt.write('%i %i %.8f\n' % ((i + 1), (i + 1), occup)) fspt.write('t2_iajb:\n') for i in range(nocc): for j in range(nvir): for k in range(nocc): for l in range(nvir): if (abs(t2[i, j, k, l]) > 1e-8): fspt.write('%i %i %i %i %.10f\n' % ((i+1+ncore), \ (j+1+nocc+ncore), (k+1+ncore), (l+1+nocc+ncore), \ t2[i,j,k,l]*2.0)) a = cell.a t = cell.get_lattice_Ls() t = t[numpy.argsort(lib.norm(t, axis=1))] kpts = numpy.asarray([0.0, 0.0, 0.0]) fspt.write('CRYSTAL\n') fspt.write('GAMMA %11.8f %11.8f %11.8f\n' % (kpts[0], kpts[1], kpts[2])) fspt.write('CELL\n') fspt.write(' %11.8f %11.8f %11.8f\n' % (a[0][0], a[0][1], a[0][2])) fspt.write(' %11.8f %11.8f %11.8f\n' % (a[1][0], a[1][1], a[1][2])) fspt.write(' %11.8f %11.8f %11.8f\n' % (a[2][0], a[2][1], a[2][2])) fspt.write('T-VECTORS %3d\n' % len(t)) for i in range(len(t)): fspt.write(' %11.8f %11.8f %11.8f\n' % (t[i][0], t[i][1], t[i][2])) fspt.close() #cv, ev = utils.getdffno(mf,ncore,eri_mo,thresh_vir=1e-4) #lib.logger.info(mf,"* FNO GAMMA point MP2 ") #nvir = len(ev)
def _normalize(vecs): vecs = numpy.asarray(vecs) if vecs.ndim == 1: return vecs / (numpy.linalg.norm(vecs) + 1e-200) else: return vecs / (norm(vecs, axis=1).reshape(-1, 1) + 1e-200)