def __init__(self, mf, frozen=None, auxbasis=None): ''' Args: mf : RHF instance frozen : number of frozen orbitals or list of frozen orbitals auxbasis : name of auxiliary basis set, otherwise determined automatically ''' if not isinstance(mf, scf.rhf.RHF): raise TypeError('Class initialization with non-RHF object') self.mo_coeff = mf.mo_coeff self.mo_energy = mf.mo_energy self.nocc = np.count_nonzero(mf.mo_occ) self.nmo = self.mo_coeff.shape[1] self.e_scf = mf.e_tot self._scf = mf # Process the frozen core option correctly as an integer or a list. # self.frozen_mask sets a flag for each orbital if it is frozen (True) or not (False). # Only occupied orbitals can be frozen. self.frozen_mask = np.zeros(self.nmo, dtype=bool) if frozen is None: pass elif lib.isinteger(frozen): if frozen > self.nocc: raise ValueError('only occupied orbitals can be frozen') self.frozen_mask[:frozen] = True elif lib.isintsequence(frozen): if max(frozen) > self.nocc - 1: raise ValueError('only occupied orbitals can be frozen') self.frozen_mask[frozen] = True else: raise TypeError('frozen must be an integer or a list of integers') # mask for occupied orbitals that are not frozen self.occ_mask = np.zeros(self.nmo, dtype=bool) self.occ_mask[:self.nocc] = True self.occ_mask[self.frozen_mask] = False self.mol = mf.mol if not auxbasis: auxbasis = df.make_auxbasis(self.mol, mp2fit=True) self.auxmol = df.make_auxmol(self.mol, auxbasis) self.verbose = self.mol.verbose self.stdout = self.mol.stdout self.max_memory = self.mol.max_memory self._intsfile = None self.e_corr = None # Spin component scaling factors self.ps = 1.0 self.pt = 1.0 self.cphf_max_cycle = 100 self.cphf_tol = mf.conv_tol
def energy_mol(newbasis, moldata): mol = moldata['mol' ] rho = moldata['rho' ] coords = moldata['coords' ] weights = moldata['weights' ] self = moldata['self' ] newmol = df.make_auxmol(mol, newbasis) ao = dft.numint.eval_ao(newmol, coords).T w = np.einsum('pi,i,i->p', ao,rho,weights) S = np.einsum('pi,qi,i->pq', ao,ao,weights) c = np.linalg.solve(S, w) E = self-c@w return E
def initialize(self, xbas=None): """Summary: Construct a fixed part of fock matrix F0 .. math:: F_{0} = T + V_{ext} + V_{h} + V_{g} """ self.get_ovlp = lambda *args: self.S self.internal_b = np.ones_like(self.b) if self.dm_aux is None: self.dm_aux = self.dm_tar if xbas is None: xbas = self.tbas if self.guide is None: self.V0 = np.zeros_like(self.dm_tar) else: fac_faxc, dft_xc = util.parse_guide(self.guide) N = self.mol.nelectron self.xmol = df.make_auxmol(self.mol, auxbasis=xbas) dm_aux_ao = scf.addons.project_dm_nr2nr(self.xmol, self.dm_aux, self.mol) J_tar = scf.hf.get_jk(self.mol, dm_aux_ao)[0] VFA = -(1./N)*(J_tar[0]+J_tar[1]) mydft = dft.UKS(self.mol) mydft.xc = dft_xc Vxcdft = mydft.get_veff(self.mol, dm=dm_aux_ao) if self.Smnt is not None: #Generate potential matrix in target DM basis representation dm_aux_tbas = scf.addons.project_dm_nr2nr(self.xmol, self.dm_aux, self.tmol) self.V_tbas = self.tmol.intor('int1e_nuc') J_tbas = scf.hf.get_jk(self.tmol, dm_aux_tbas)[0] VFA_tbas = -(1./N)*(J_tbas[0]+J_tbas[1]) mydft_tbas = dft.UKS(self.tmol) mydft_tbas.xc = dft_xc Vxcdft_tbas = mydft_tbas.get_veff(self.tmol, dm=dm_aux_tbas) self.V0_tbas = fac_faxc * VFA_tbas + Vxcdft_tbas self.V0 = fac_faxc * np.array((VFA, VFA)) + Vxcdft self.F0 = (self.T+self.V+self.V0[0], self.T+self.V+self.V0[1])
def gradient_mol(nexp, newbasis, moldata): mol = moldata['mol' ] rho = moldata['rho' ] coords = moldata['coords' ] weights = moldata['weights' ] self = moldata['self' ] idx = moldata['idx' ] centers = moldata['centers' ] distances = moldata['distances'] newmol = df.make_auxmol(mol, newbasis) ao = dft.numint.eval_ao(newmol, coords).T w = np.einsum('pi,i,i->p', ao,rho,weights) dw_da = np.zeros((nexp, newmol.nao)) for p in range(newmol.nao): iat = centers[p] r2 = distances[iat] dw_da[idx[p],p] = np.einsum('i,i,i,i->', ao[p],rho,r2,weights) S = np.einsum('pi,qi,i->pq', ao,ao,weights) dS_da = np.zeros((nexp, newmol.nao, newmol.nao)) for p in range(newmol.nao): for q in range(p,newmol.nao): ip = idx[p] iq = idx[q] iatp = centers[p] iatq = centers[q] r2p = distances[iatp] r2q = distances[iatq] ao_ao_w = np.einsum('i,i,i->i', ao[p],ao[q],weights) ip_p_q = np.einsum('i,i->', ao_ao_w,r2p) iq_p_q = np.einsum('i,i->', ao_ao_w,r2q) dS_da[ip,p,q] += ip_p_q dS_da[iq,p,q] += iq_p_q if p!=q: dS_da[ip,q,p] += ip_p_q dS_da[iq,q,p] += iq_p_q c = np.linalg.solve(S, w) part1 = np.einsum('p,ip->i', c, dw_da) part2 = np.einsum('p,ipq,q->i', c, dS_da, c) dE_da = 2.0*part1 - part2 E = self - c@w return E, dE_da
def test_rdf_rhf_eng(self): mol = gto.Mole() mol.atom = """ N 0. 0. 0. H 1.5 0. 0.2 H 0.1 1.2 0. H 0. 0. 1. """ mol.basis = "cc-pVDZ" mol.verbose = 0 mol.build() mf_scf = scf.RHF(mol).density_fit(auxbasis="cc-pVDZ-jkfit").run() mf_mp2 = mp.MP2(mf_scf) mf_mp2.with_df = df.DF(mol, auxbasis="cc-pVDZ-ri") mf_mp2.run() aux_ri = df.make_auxmol(mol, "cc-pVDZ-ri") config = {"scf_eng": mf_scf, "aux_ri": aux_ri} helper = GradDFMP2(config) assert np.allclose(helper.eng, mf_mp2.e_tot, rtol=1e-10, atol=1e-12)
def main(): xyzfile = sys.argv[1] state_id = [int(sys.argv[2]) - 1, int(sys.argv[3]) - 1] azo_id = [int(sys.argv[4]) - 1, int(sys.argv[5]) - 1] mol = readmol(xyzfile, qm_config.basis) coeff = np.load(xyzfile + '.mo.npy') X = np.load(xyzfile + '.X.npy') auxmol = df.make_auxmol(mol, qm_config.basis2) eri3c = eri_pqi(mol, auxmol) eri2c = auxmol.intor('int2c2e_sph') occ = mol.nelectron // 2 azo_ao = auxmol.offset_ao_by_atom()[azo_id[0]:azo_id[1] + 1, 2:] q = number_of_electrons_vec(auxmol) for i, state in enumerate(state_id): x_mo = X[state] x_ao = coeff[:, :occ] @ x_mo @ coeff[:, occ:].T coulomb = compute_j(mol, x_ao) b = np.einsum('ijp,ij->p', eri3c, x_ao) c = np.linalg.solve(eri2c, b) error = coulomb - np.dot(c, b) cq = c * q n = sum(cq) n1 = sum(cq[azo_ao[0, 0]:azo_ao[0, 1]]) n2 = sum(cq[azo_ao[1, 0]:azo_ao[1, 1]]) if (n1 < 0.0): c = -c print( xyzfile, 'state' + str(i + 1), "Error: % .3e Eh ( %.1e %%) Electrons: % .1e total, % .2e left N, % .2e right N" % (error, error / coulomb * 100.0, n, n1, n2)) np.savetxt(xyzfile + '.st' + str(i + 1) + '_transition_fit.dat', c)
def main(): xyzfile = sys.argv[1] mol = readmol(xyzfile, qm_config.basis) auxmol = df.make_auxmol(mol, qm_config.basis2) eri3c = eri_pqi(mol, auxmol) eri2c = auxmol.intor('int2c2e_sph') np.save(xyzfile + '.jmat.npy', eri2c) N = mol.nelectron files = (('ground', xyzfile + '.coulomb.dat', xyzfile + '.dm.dat', N, xyzfile + '.dm_fit.dat'), ('hole_1', xyzfile + '.st1_coulomb_hole.dat', xyzfile + '.st1_dm_hole.dat', 1, xyzfile + '.st1_dm_hole_fit.dat'), ('part_1', xyzfile + '.st1_coulomb_part.dat', xyzfile + '.st1_dm_part.dat', 1, xyzfile + '.st1_dm_part_fit.dat'), ('hole_2', xyzfile + '.st2_coulomb_hole.dat', xyzfile + '.st2_dm_hole.dat', 1, xyzfile + '.st2_dm_hole_fit.dat'), ('part_2', xyzfile + '.st2_coulomb_part.dat', xyzfile + '.st2_dm_part.dat', 1, xyzfile + '.st2_dm_part_fit.dat')) for i in files: (title, file_coul, file_dm, n_correct, file_out) = i dm = np.loadtxt(file_dm) ej = np.loadtxt(file_coul) b = np.einsum('ijp,ij->p', eri3c, dm) c = np.linalg.solve(eri2c, b) error = ej - np.dot(c, b) n = number_of_electrons(c, auxmol) print( xyzfile + '\t' + title, "Error: % .3e Eh ( %.1e %%) Electrons: %.3e ( % .1e )" % (error, error / ej * 100.0, n, n - n_correct)) np.savetxt(file_out, c)
def basic(mw, mol, pbas, Sijt, tbas, Smnt): """Summary: Common basic initialization function for RWY and UWY objects Args: mw : RWY or UWY object mol : an instance of :class:`Mole` pbas (dict or str) : potential basis set for WY Sijt (ndarray) : three-center overlap integral with shape ((no, no, np)) where no is the length of atomic orbital basis set defined in mol, while np is the length of potential basis set Only effective for model systems and molecular systems with user-defined pbs. Otherwise, this is ignored and analytical integration is performed. tbas (dict or str) : basis set of target density matrix Smnt (ndarray) : three-center overlap integral with shape ((nt, nt, np)) where nt is the length of atomic orbital basis set that defines target density matrix, while np is the length of potential basis set Only effective for model systems and molecular systems with user-defined pbs. Otherwise, this is ignored and analytical integration is performed. """ mw.mol = mol mw.guide = 'faxc' mw.reg = 0. mw.tol = 1e-6 mw.method = 'trust-exact' mw.verbose = mw.mol.verbose mw.stdout = mw.mol.stdout mw.Sijt = None mw.Smnt = None mw.Tp = None mw.pbas = pbas mw.tbas = tbas is_model1 = len(mw.mol._atm) == 0 is_model2 = len(mw.mol._bas) == 0 mw.model = is_model1 and is_model2 if mw.model: #Check if defined mol is a molecule or model mw.guide = None if Sijt is None: raise AssertionError("Three-center overlap integeral should be given for model system") if kf_imported: mw.Sijt = np.array(Sijt, order='F') if Smnt is not None: mw.Smnt = np.array(Smnt, order='F') else: mw.Sijt = np.array(Sijt, order='C') if Smnt is not None: mw.Smnt = np.array(Smnt, order='C') return mw.S = mw.mol.intor_symmetric('int1e_ovlp') mw.T = mw.mol.intor_symmetric('int1e_kin') mw.V = mw.mol.intor_symmetric('int1e_nuc') if tbas is None: mw.tbas = mol.basis mw.tmol = df.make_auxmol(mol, auxbasis=mw.tbas) if pbas is not None and callable(pbas[0]): #potential basis is given as a list of user-defined functions #In this case, mw.Tp should be given by the user to use regularization mw.Sijt = Sijt if Sijt is None: mw.Sijt = numint_3c2b(mol, pbas) if not gto.mole.same_basis_set(mol, mw.tmol): mw.Smnt = Smnt if Smnt is None: mw.Smnt = numint_3c2b(mw.tmol, pbas) else: #potential basis is given as a pyscf-supported format if pbas is None: mw.pbas = mol.basis mw.pmol = df.make_auxmol(mol, auxbasis=mw.pbas) mw.Tp = mw.pmol.intor_symmetric('int1e_kin') mw.Sijt = df.incore.aux_e2(mol, mw.pmol, intor='int3c1e') if not gto.mole.same_basis_set(mol, mw.tmol): mw.Smnt = df.incore.aux_e2(mw.tmol, mw.pmol, intor='int3c1e') mw.nbas = len(mw.Sijt[:, 0, 0]) mw.npot = len(mw.Sijt[0, 0, :])
def __init__(self, mf, frozen=None, auxbasis=None): ''' Args: mf : UHF instance frozen : number of frozen orbitals or list of frozen orbitals auxbasis : name of auxiliary basis set, otherwise determined automatically ''' if not isinstance(mf, scf.uhf.UHF): raise TypeError('Class initialization with non-UHF object') # UHF quantities are stored as numpy arrays self.mo_coeff = np.array(mf.mo_coeff) self.mo_energy = np.array(mf.mo_energy) self.nocc = np.array( [np.count_nonzero(mf.mo_occ[0]), np.count_nonzero(mf.mo_occ[1])]) # UHF MO coefficient matrix shape: (2, number of AOs, number of MOs) self.nmo = self.mo_coeff.shape[2] self.e_scf = mf.e_tot self._scf = mf # Process the frozen core option correctly as either an integer or two lists (alpha, beta). # self.frozen_mask sets a flag for each orbital if it is frozen (True) or not (False). # Only occupied orbitals can be frozen. self.frozen_mask = np.zeros((2, self.nmo), dtype=bool) if frozen is None: pass elif lib.isinteger(frozen): if frozen > min(self.nocc): raise ValueError('only occupied orbitals can be frozen') self.frozen_mask[:, :frozen] = True else: try: if len(frozen) != 2: raise ValueError for s in 0, 1: if not lib.isintsequence(frozen[s]): raise TypeError except (TypeError, ValueError): raise TypeError( 'frozen must be an integer or two integer lists') if len(frozen[0]) != len(frozen[1]): raise ValueError('frozen orbital lists not of equal length') for s in 0, 1: self.frozen_mask[s, frozen[s]] = True # mask for occupied orbitals that are not frozen self.occ_mask = np.zeros((2, self.nmo), dtype=bool) for s in 0, 1: self.occ_mask[s, :self.nocc[s]] = True self.occ_mask[self.frozen_mask] = False self.mol = mf.mol if not auxbasis: auxbasis = df.make_auxbasis(self.mol, mp2fit=True) self.auxmol = df.make_auxmol(self.mol, auxbasis) self.verbose = self.mol.verbose self.stdout = self.mol.stdout self.max_memory = self.mol.max_memory # _intsfile will be a list with two elements for the alpha and beta integrals self._intsfile = [] self.e_corr = None # Spin component scaling factors self.ps = 1.0 self.pt = 1.0 self.cphf_max_cycle = 100 self.cphf_tol = mf.conv_tol