def init_guess_by_chkfile(mol, chkfile_name, project=None): '''Read SCF chkfile and make the density matrix for UHF initial guess. Kwargs: project : None or bool Whether to project chkfile's orbitals to the new basis. Note when the geometry of the chkfile and the given molecule are very different, this projection can produce very poor initial guess. In PES scanning, it is recommended to swith off project. If project is set to None, the projection is only applied when the basis sets of the chkfile's molecule are different to the basis sets of the given molecule (regardless whether the geometry of the two molecules are different). Note the basis sets are considered to be different if the two molecules are derived from the same molecule with different ordering of atoms. ''' from pyscf.scf import addons chk_mol, scf_rec = chkfile.load_scf(chkfile_name) if project is None: project = not gto.same_basis_set(chk_mol, mol) # Check whether the two molecules are similar im1 = scipy.linalg.eigvalsh(mol.inertia_moment()) im2 = scipy.linalg.eigvalsh(chk_mol.inertia_moment()) # im1+1e-7 to avoid 'divide by zero' error if abs((im1 - im2) / (im1 + 1e-7)).max() > 0.01: logger.warn( mol, "Large deviations found between the input " "molecule and the molecule from chkfile\n" "Initial guess density matrix may have large error.") if project: s = hf.get_ovlp(mol) def fproj(mo): if project: mo = addons.project_mo_nr2nr(chk_mol, mo, mol) norm = numpy.einsum('pi,pi->i', mo.conj(), s.dot(mo)) mo /= numpy.sqrt(norm) return mo mo = scf_rec['mo_coeff'] mo_occ = scf_rec['mo_occ'] if getattr(mo[0], 'ndim', None) == 1: # RHF if numpy.iscomplexobj(mo): raise NotImplementedError( 'TODO: project DHF orbital to UHF orbital') mo_coeff = fproj(mo) mo_occa = (mo_occ > 1e-8).astype(numpy.double) mo_occb = mo_occ - mo_occa dm = make_rdm1([mo_coeff, mo_coeff], [mo_occa, mo_occb]) else: #UHF if getattr(mo[0][0], 'ndim', None) == 2: # KUHF logger.warn( mol, 'k-point UHF results are found. Density matrix ' 'at Gamma point is used for the molecular SCF initial guess') mo = mo[0] dm = make_rdm1([fproj(mo[0]), fproj(mo[1])], mo_occ) return dm
def init_guess_by_chkfile(mol, chkfile_name, project=None): '''Read SCF chkfile and make the density matrix for UHF initial guess. Kwargs: project : None or bool Whether to project chkfile's orbitals to the new basis. Note when the geometry of the chkfile and the given molecule are very different, this projection can produce very poor initial guess. In PES scanning, it is recommended to swith off project. If project is set to None, the projection is only applied when the basis sets of the chkfile's molecule are different to the basis sets of the given molecule (regardless whether the geometry of the two molecules are different). Note the basis sets are considered to be different if the two molecules are derived from the same molecule with different ordering of atoms. ''' from pyscf.scf import addons chk_mol, scf_rec = chkfile.load_scf(chkfile_name) if project is None: project = not gto.same_basis_set(chk_mol, mol) # Check whether the two molecules are similar im1 = scipy.linalg.eigvalsh(mol.inertia_moment()) im2 = scipy.linalg.eigvalsh(chk_mol.inertia_moment()) # im1+1e-7 to avoid 'divide by zero' error if abs((im1-im2)/(im1+1e-7)).max() > 0.01: logger.warn(mol, "Large deviations found between the input " "molecule and the molecule from chkfile\n" "Initial guess density matrix may have large error.") if project: s = hf.get_ovlp(mol) def fproj(mo): if project: mo = addons.project_mo_nr2nr(chk_mol, mo, mol) norm = numpy.einsum('pi,pi->i', mo.conj(), s.dot(mo)) mo /= numpy.sqrt(norm) return mo mo = scf_rec['mo_coeff'] mo_occ = scf_rec['mo_occ'] if getattr(mo[0], 'ndim', None) == 1: # RHF if numpy.iscomplexobj(mo): raise NotImplementedError('TODO: project DHF orbital to UHF orbital') mo_coeff = fproj(mo) mo_occa = (mo_occ>1e-8).astype(numpy.double) mo_occb = mo_occ - mo_occa dm = make_rdm1([mo_coeff,mo_coeff], [mo_occa,mo_occb]) else: #UHF if getattr(mo[0][0], 'ndim', None) == 2: # KUHF logger.warn(mol, 'k-point UHF results are found. Density matrix ' 'at Gamma point is used for the molecular SCF initial guess') mo = mo[0] dm = make_rdm1([fproj(mo[0]),fproj(mo[1])], mo_occ) return dm
def init_guess_by_chkfile(mol, chkfile_name, project=None): '''Read SCF chkfile and make the density matrix for 4C-DHF initial guess. Kwargs: project : None or bool Whether to project chkfile's orbitals to the new basis. Note when the geometry of the chkfile and the given molecule are very different, this projection can produce very poor initial guess. In PES scanning, it is recommended to swith off project. If project is set to None, the projection is only applied when the basis sets of the chkfile's molecule are different to the basis sets of the given molecule (regardless whether the geometry of the two molecules are different). Note the basis sets are considered to be different if the two molecules are derived from the same molecule with different ordering of atoms. ''' from pyscf.scf import addons chk_mol, scf_rec = chkfile.load_scf(chkfile_name) if project is None: project = not gto.same_basis_set(chk_mol, mol) # Check whether the two molecules are similar def inertia_momentum(mol): im = gto.inertia_momentum(mol._atom, mol.atom_charges(), mol.atom_coords()) return scipy.linalg.eigh(im)[0] if abs(inertia_momentum(mol) - inertia_momentum(chk_mol)).sum() > 0.5: logger.warn( mol, "Large deviations found between the input " "molecule and the molecule from chkfile\n" "Initial guess density matrix may have large error.") if project: s = get_ovlp(mol) def fproj(mo): #TODO: check if mo is GHF orbital if project: mo = addons.project_mo_r2r(chk_mol, mo, mol) norm = numpy.einsum('pi,pi->i', mo.conj(), s.dot(mo)) mo /= numpy.sqrt(norm) return mo mo = scf_rec['mo_coeff'] mo_occ = scf_rec['mo_occ'] if numpy.iscomplexobj(mo[0]): # DHF dm = make_rdm1(fproj(mo), mo_occ) else: if mo[0].ndim == 1: # nr-RHF dm = reduce(numpy.dot, (mo * mo_occ, mo.T)) else: # nr-UHF dm = reduce(numpy.dot, (mo[0]*mo_occ[0], mo[0].T)) \ + reduce(numpy.dot, (mo[1]*mo_occ[1], mo[1].T)) dm = _proj_dmll(chk_mol, dm, mol) return dm
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 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 init_guess_by_chkfile(mol, chkfile_name, project=None): '''Read SCF chkfile and make the density matrix for 4C-DHF initial guess. Kwargs: project : None or bool Whether to project chkfile's orbitals to the new basis. Note when the geometry of the chkfile and the given molecule are very different, this projection can produce very poor initial guess. In PES scanning, it is recommended to swith off project. If project is set to None, the projection is only applied when the basis sets of the chkfile's molecule are different to the basis sets of the given molecule (regardless whether the geometry of the two molecules are different). Note the basis sets are considered to be different if the two molecules are derived from the same molecule with different ordering of atoms. ''' from pyscf.scf import addons chk_mol, scf_rec = chkfile.load_scf(chkfile_name) if project is None: project = not gto.same_basis_set(chk_mol, mol) # Check whether the two molecules are similar if abs(mol.inertia_moment() - chk_mol.inertia_moment()).sum() > 0.5: logger.warn(mol, "Large deviations found between the input " "molecule and the molecule from chkfile\n" "Initial guess density matrix may have large error.") if project: s = get_ovlp(mol) def fproj(mo): #TODO: check if mo is GHF orbital if project: mo = addons.project_mo_r2r(chk_mol, mo, mol) norm = numpy.einsum('pi,pi->i', mo.conj(), s.dot(mo)) mo /= numpy.sqrt(norm) return mo mo = scf_rec['mo_coeff'] mo_occ = scf_rec['mo_occ'] if numpy.iscomplexobj(mo[0]): # DHF dm = make_rdm1(fproj(mo), mo_occ) else: if mo[0].ndim == 1: # nr-RHF dm = reduce(numpy.dot, (mo*mo_occ, mo.T)) else: # nr-UHF dm = reduce(numpy.dot, (mo[0]*mo_occ[0], mo[0].T)) \ + reduce(numpy.dot, (mo[1]*mo_occ[1], mo[1].T)) dm = _proj_dmll(chk_mol, dm, mol) return dm
def test_remove_ovlp(self): test_mol_16 = helpers.concat_mols([self.mol1, self.mol6]) corr_mol16 = gto.M() corr_mol16.atom = """ H-0 -1.06 0.0 0.0 C-0 0.0 0.0 0.0 C-1 1.2 0.0 0.0 H-1 2.26 0.0 0.0 """ corr_mol16.basis = { 'C-0': 'sto-3g', 'H-0': 'sto-3g', 'C-1': '6-311g', 'H-1': '6-311g' } with self.assertRaises(AssertionError): test_mol_166 = helpers.concat_mols([test_mol_16, self.mol6]) test_mol_378 = helpers.concat_mols([self.mol3, self.mol7, self.mol8]) corr_mol378 = gto.M() corr_mol378.atom = """ O-0 -1.16 0.0 0.0 GHOST-C-1 2.0 0.0 0.0 O-1 0.0 1.16 0.0 C-2 0.0 0.0 0.0 """ corr_mol378.basis = { 'O-0': 'sto-3g', 'O-1': 'cc-pVTZ', 'GHOST-C-1': 'aug-cc-pVDZ', 'C-2': 'cc-pVDZ' } corr_mol378.build() self.assertTrue(gto.same_basis_set(test_mol_378, corr_mol378)) self.assertTrue(gto.same_mol(test_mol_378, corr_mol378))
def test_basic(self): test_mol_12 = helpers.concat_mols([self.mol1, self.mol2]) corr_mol12 = gto.M() corr_mol12.atom = """ H-0 -1.06 0.0 0.0 C-0 0.0 0.0 0.0 C-1 1.2 0.0 0.0 H-1 2.26 0.0 0.0 """ corr_mol12.spin = 0 corr_mol12.basis = { 'C-0': 'sto-3g', 'H-0': 'sto-3g', 'C-1': '6-311g', 'H-1': '6-311g' } corr_mol12.build() self.assertEqual(test_mol_12.spin, corr_mol12.spin) self.assertTrue(gto.same_mol(test_mol_12, corr_mol12)) self.assertTrue(gto.same_mol(test_mol_12, corr_mol12)) test_mol_345 = helpers.concat_mols([self.mol3, self.mol4, self.mol5]) corr_mol345 = gto.M() corr_mol345.atom = """ O-0 -1.16 0.0 0.0 C-1 0.0 0.0 0.0 O-2 1.16 0.0 0.0 """ corr_mol345.basis = {'O-0': 'sto-3g', 'C-1': '6-311g', 'O-2': 'sto-3g'} corr_mol345.build() self.assertTrue(gto.same_basis_set(test_mol_345, corr_mol345)) self.assertTrue(gto.same_mol(test_mol_345, corr_mol345))
def project_init_guess(casscf, init_mo, prev_mol=None): '''Project the given initial guess to the current CASSCF problem. The projected initial guess has two parts. The core orbitals are directly taken from the Hartree-Fock orbitals, and the active orbitals are projected from the given initial guess. Args: casscf : an :class:`CASSCF` or :class:`CASCI` object init_mo : ndarray or list of ndarray Initial guess orbitals which are not orth-normal for the current molecule. When the casscf is UHF-CASSCF, the init_mo needs to be a list of two ndarrays, for alpha and beta orbitals Kwargs: prev_mol : an instance of :class:`Mole` If given, the inital guess orbitals are associated to the geometry and basis of prev_mol. Otherwise, the orbitals are based of the geometry and basis of casscf.mol Returns: New orthogonal initial guess orbitals with the core taken from Hartree-Fock orbitals and projected active space from original initial guess orbitals Examples: .. code:: python import numpy from pyscf import gto, scf, mcscf mol = gto.Mole() mol.build(atom='H 0 0 0; F 0 0 0.8', basis='ccpvdz', verbose=0) mf = scf.RHF(mol) mf.scf() mc = mcscf.CASSCF(mf, 6, 6) mo = mcscf.sort_mo(mc, mf.mo_coeff, [3,4,5,6,8,9]) print('E(0.8) = %.12f' % mc.kernel(mo)[0]) init_mo = mc.mo_coeff for b in numpy.arange(1.0, 3., .2): mol.atom = [['H', (0, 0, 0)], ['F', (0, 0, b)]] mol.build(0, 0) mf = scf.RHF(mol) mf.scf() mc = mcscf.CASSCF(mf, 6, 6) mo = mcscf.project_init_guess(mc, init_mo) print('E(%2.1f) = %.12f' % (b, mc.kernel(mo)[0])) init_mo = mc.mo_coeff ''' from pyscf import lo def project(mfmo, init_mo, ncore, s): s_init_mo = numpy.einsum('pi,pi->i', init_mo.conj(), s.dot(init_mo)) if abs(s_init_mo - 1).max() < 1e-7 and mfmo.shape[1] == init_mo.shape[1]: # Initial guess orbitals are orthonormal return init_mo # TODO: test whether the canonicalized orbitals are better than the projected orbitals # Be careful that the ordering of the canonicalized orbitals may be very different # to the CASSCF orbitals. # else: # fock = casscf.get_fock(mc, init_mo, casscf.ci) # return casscf._scf.eig(fock, s)[1] nocc = ncore + casscf.ncas if ncore > 0: mo0core = init_mo[:, :ncore] s1 = reduce(numpy.dot, (mfmo.T, s, mo0core)) s1core = reduce(numpy.dot, (mo0core.T, s, mo0core)) coreocc = numpy.einsum('ij,ji->i', s1, lib.cho_solve(s1core, s1.T)) coreidx = numpy.sort(numpy.argsort(-coreocc)[:ncore]) logger.debug(casscf, 'Core indices %s', coreidx) logger.debug(casscf, 'Core components %s', coreocc[coreidx]) # take HF core mocore = mfmo[:, coreidx] # take projected CAS space mocas = init_mo[:,ncore:nocc] \ - reduce(numpy.dot, (mocore, mocore.T, s, init_mo[:,ncore:nocc])) mocc = lo.orth.vec_lowdin(numpy.hstack((mocore, mocas)), s) else: mocc = lo.orth.vec_lowdin(init_mo[:, :nocc], s) # remove core and active space from rest if mocc.shape[1] < mfmo.shape[1]: if casscf.mol.symmetry: restorb = [] orbsym = scf.hf_symm.get_orbsym(casscf.mol, mfmo, s) for ir in set(orbsym): mo_ir = mfmo[:, orbsym == ir] rest = mo_ir - reduce(numpy.dot, (mocc, mocc.T, s, mo_ir)) e, u = numpy.linalg.eigh( reduce(numpy.dot, (rest.T, s, rest))) restorb.append(numpy.dot(rest, u[:, e > 1e-7])) restorb = numpy.hstack(restorb) else: rest = mfmo - reduce(numpy.dot, (mocc, mocc.T, s, mfmo)) e, u = numpy.linalg.eigh(reduce(numpy.dot, (rest.T, s, rest))) restorb = numpy.dot(rest, u[:, e > 1e-7]) mo = numpy.hstack((mocc, restorb)) else: mo = mocc if casscf.verbose >= logger.DEBUG: s1 = reduce(numpy.dot, (mo[:, ncore:nocc].T, s, mfmo)) idx = numpy.argwhere(abs(s1) > 0.4) for i, j in idx: logger.debug(casscf, 'Init guess <mo-CAS|mo-hf> %d %d %12.8f', ncore + i + 1, j + 1, s1[i, j]) return mo ncore = casscf.ncore mfmo = casscf._scf.mo_coeff s = casscf._scf.get_ovlp() if prev_mol is None: if init_mo.shape[0] != mfmo.shape[0]: raise RuntimeError('Initial guess orbitals has wrong dimension') elif gto.same_mol(prev_mol, casscf.mol, cmp_basis=False): if isinstance(ncore, (int, numpy.integer)): # RHF init_mo = scf.addons.project_mo_nr2nr(prev_mol, init_mo, casscf.mol) else: init_mo = (scf.addons.project_mo_nr2nr(prev_mol, init_mo[0], casscf.mol), scf.addons.project_mo_nr2nr(prev_mol, init_mo[1], casscf.mol)) elif gto.same_basis_set(prev_mol, casscf.mol): if isinstance(ncore, (int, numpy.integer)): # RHF fock = casscf.get_fock(init_mo, casscf.ci) return casscf._scf.eig(fock, s)[1] else: raise NotImplementedError('Project initial for UHF orbitals.') else: raise NotImplementedError( 'Project initial guess from different system.') # Be careful with the orbital projection. The projection may lead to bad # initial guess orbitals if the geometry is dramatically changed. if isinstance(ncore, (int, numpy.integer)): mo = project(mfmo, init_mo, ncore, s) else: # UHF-based CASSCF mo = (project(mfmo[0], init_mo[0], ncore[0], s), project(mfmo[1], init_mo[1], ncore[1], s)) return mo
def init_guess_by_chkfile(cell, chkfile_name, project=None, kpts=None): '''Read the KHF results from checkpoint file, then project it to the basis defined by ``cell`` Returns: Density matrix, 3D 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) 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 = np.expand_dims(mo, axis=0) mo_occ = np.expand_dims(mo_occ, axis=0) else: # UHF mo = [np.expand_dims(mo[0], axis=0), np.expand_dims(mo[1], axis=0)] mo_occ = [ np.expand_dims(mo_occ[0], axis=0), np.expand_dims(mo_occ[1], axis=0) ] if project: s = cell.pbc_intor('int1e_ovlp', kpts=kpts) def fproj(mo, kpts): if project: mo = addons.project_mo_nr2nr(chk_cell, mo, cell, kpts) for k, c in enumerate(mo): norm = np.einsum('pi,pi->i', c.conj(), s[k].dot(c)) mo[k] /= np.sqrt(norm) return mo if kpts.shape == chk_kpts.shape and np.allclose(kpts, chk_kpts): def makedm(mos, occs): moa, mob = mos mos = ([fproj(mo, None) for mo in moa], [fproj(mo, None) for mo in mob]) return make_rdm1(mos, occs) else: 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) if getattr(mo[0], 'ndim', None) == 2: # KRHF mo_occa = [(occ > 1e-8).astype(np.double) for occ in mo_occ] mo_occb = [occ - mo_occa[k] for k, occ in enumerate(mo_occ)] dm = makedm((mo, mo), (mo_occa, mo_occb)) else: # KUHF dm = makedm(mo, mo_occ) # Real DM for gamma point if np.allclose(kpts, 0): dm = dm.real return dm
def init_guess_by_chkfile(mol, chkfile_name, project=None): '''Read SCF chkfile and make the density matrix for GHF initial guess. Kwargs: project : None or bool Whether to project chkfile's orbitals to the new basis. Note when the geometry of the chkfile and the given molecule are very different, this projection can produce very poor initial guess. In PES scanning, it is recommended to swith off project. If project is set to None, the projection is only applied when the basis sets of the chkfile's molecule are different to the basis sets of the given molecule (regardless whether the geometry of the two molecules are different). Note the basis sets are considered to be different if the two molecules are derived from the same molecule with different ordering of atoms. ''' from pyscf.scf import addons chk_mol, scf_rec = chkfile.load_scf(chkfile_name) if project is None: project = not gto.same_basis_set(chk_mol, mol) # Check whether the two molecules are similar enough def inertia_momentum(mol): im = gto.inertia_momentum(mol._atom, mol.atom_charges(), mol.atom_coords()) return scipy.linalg.eigh(im)[0] if abs(inertia_momentum(mol) - inertia_momentum(chk_mol)).sum() > 0.5: logger.warn( mol, "Large deviations found between the input " "molecule and the molecule from chkfile\n" "Initial guess density matrix may have large error.") if project: s = hf.get_ovlp(mol) def fproj(mo): if project: mo = addons.project_mo_nr2nr(chk_mol, mo, mol) norm = numpy.einsum('pi,pi->i', mo.conj(), s.dot(mo)) mo /= numpy.sqrt(norm) return mo nao = chk_mol.nao_nr() mo = scf_rec['mo_coeff'] mo_occ = scf_rec['mo_occ'] if hasattr(mo[0], 'ndim') and mo[0].ndim == 1: # RHF/GHF/DHF if nao * 2 == mo.shape[0]: # GHF or DHF if project: raise NotImplementedError('Project initial guess from ' 'different geometry') else: dm = hf.make_rdm1(mo, mo_occ) else: # RHF mo_coeff = fproj(mo) mo_occa = (mo_occ > 1e-8).astype(numpy.double) mo_occb = mo_occ - mo_occa dma, dmb = uhf.make_rdm1([mo_coeff] * 2, (mo_occa, mo_occb)) dm = scipy.linalg.block_diag(dma, dmb) else: #UHF if hasattr(mo[0][0], 'ndim') and mo[0][0].ndim == 2: # KUHF logger.warn( mol, 'k-point UHF results are found. Density matrix ' 'at Gamma point is used for the molecular SCF initial guess') mo = mo[0] dma, dmb = uhf.make_rdm1([fproj(mo[0]), fproj(mo[1])], mo_occ) dm = scipy.linalg.block_diag(dma, dmb) return dm
def project_init_guess(casscf, init_mo, prev_mol=None): '''Project the given initial guess to the current CASSCF problem. The projected initial guess has two parts. The core orbitals are directly taken from the Hartree-Fock orbitals, and the active orbitals are projected from the given initial guess. Args: casscf : an :class:`CASSCF` or :class:`CASCI` object init_mo : ndarray or list of ndarray Initial guess orbitals which are not orth-normal for the current molecule. When the casscf is UHF-CASSCF, the init_mo needs to be a list of two ndarrays, for alpha and beta orbitals Kwargs: prev_mol : an instance of :class:`Mole` If given, the inital guess orbitals are associated to the geometry and basis of prev_mol. Otherwise, the orbitals are based of the geometry and basis of casscf.mol Returns: New orthogonal initial guess orbitals with the core taken from Hartree-Fock orbitals and projected active space from original initial guess orbitals Examples: .. code:: python import numpy from pyscf import gto, scf, mcscf mol = gto.Mole() mol.build(atom='H 0 0 0; F 0 0 0.8', basis='ccpvdz', verbose=0) mf = scf.RHF(mol) mf.scf() mc = mcscf.CASSCF(mf, 6, 6) mo = mcscf.sort_mo(mc, mf.mo_coeff, [3,4,5,6,8,9]) print('E(0.8) = %.12f' % mc.kernel(mo)[0]) init_mo = mc.mo_coeff for b in numpy.arange(1.0, 3., .2): mol.atom = [['H', (0, 0, 0)], ['F', (0, 0, b)]] mol.build(0, 0) mf = scf.RHF(mol) mf.scf() mc = mcscf.CASSCF(mf, 6, 6) mo = mcscf.project_init_guess(mc, init_mo) print('E(%2.1f) = %.12f' % (b, mc.kernel(mo)[0])) init_mo = mc.mo_coeff ''' from pyscf import lo def project(mfmo, init_mo, ncore, s): s_init_mo = numpy.einsum('pi,pi->i', init_mo.conj(), s.dot(init_mo)) if abs(s_init_mo - 1).max() < 1e-7 and mfmo.shape[1] == init_mo.shape[1]: # Initial guess orbitals are orthonormal return init_mo # TODO: test whether the canonicalized orbitals are better than the projected orbitals # Be careful that the ordering of the canonicalized orbitals may be very different # to the CASSCF orbitals. # else: # fock = casscf.get_fock(mc, init_mo, casscf.ci) # return casscf._scf.eig(fock, s)[1] nocc = ncore + casscf.ncas if ncore > 0: mo0core = init_mo[:,:ncore] s1 = reduce(numpy.dot, (mfmo.T, s, mo0core)) s1core = reduce(numpy.dot, (mo0core.T, s, mo0core)) coreocc = numpy.einsum('ij,ji->i', s1, lib.cho_solve(s1core, s1.T)) coreidx = numpy.sort(numpy.argsort(-coreocc)[:ncore]) logger.debug(casscf, 'Core indices %s', coreidx) logger.debug(casscf, 'Core components %s', coreocc[coreidx]) # take HF core mocore = mfmo[:,coreidx] # take projected CAS space mocas = init_mo[:,ncore:nocc] \ - reduce(numpy.dot, (mocore, mocore.T, s, init_mo[:,ncore:nocc])) mocc = lo.orth.vec_lowdin(numpy.hstack((mocore, mocas)), s) else: mocc = lo.orth.vec_lowdin(init_mo[:,:nocc], s) # remove core and active space from rest if mocc.shape[1] < mfmo.shape[1]: if casscf.mol.symmetry: restorb = [] orbsym = scf.hf_symm.get_orbsym(casscf.mol, mfmo, s) for ir in set(orbsym): mo_ir = mfmo[:,orbsym==ir] rest = mo_ir - reduce(numpy.dot, (mocc, mocc.T, s, mo_ir)) e, u = numpy.linalg.eigh(reduce(numpy.dot, (rest.T, s, rest))) restorb.append(numpy.dot(rest, u[:,e>1e-7])) restorb = numpy.hstack(restorb) else: rest = mfmo - reduce(numpy.dot, (mocc, mocc.T, s, mfmo)) e, u = numpy.linalg.eigh(reduce(numpy.dot, (rest.T, s, rest))) restorb = numpy.dot(rest, u[:,e>1e-7]) mo = numpy.hstack((mocc, restorb)) else: mo = mocc if casscf.verbose >= logger.DEBUG: s1 = reduce(numpy.dot, (mo[:,ncore:nocc].T, s, mfmo)) idx = numpy.argwhere(abs(s1) > 0.4) for i,j in idx: logger.debug(casscf, 'Init guess <mo-CAS|mo-hf> %d %d %12.8f', ncore+i+1, j+1, s1[i,j]) return mo ncore = casscf.ncore mfmo = casscf._scf.mo_coeff s = casscf._scf.get_ovlp() if prev_mol is None: if init_mo.shape[0] != mfmo.shape[0]: raise RuntimeError('Initial guess orbitals has wrong dimension') elif gto.same_mol(prev_mol, casscf.mol, cmp_basis=False): if isinstance(ncore, (int, numpy.integer)): # RHF init_mo = scf.addons.project_mo_nr2nr(prev_mol, init_mo, casscf.mol) else: init_mo = (scf.addons.project_mo_nr2nr(prev_mol, init_mo[0], casscf.mol), scf.addons.project_mo_nr2nr(prev_mol, init_mo[1], casscf.mol)) elif gto.same_basis_set(prev_mol, casscf.mol): if isinstance(ncore, (int, numpy.integer)): # RHF fock = casscf.get_fock(init_mo, casscf.ci) return casscf._scf.eig(fock, s)[1] else: raise NotImplementedError('Project initial for UHF orbitals.') else: raise NotImplementedError('Project initial guess from different system.') # Be careful with the orbital projection. The projection may lead to bad # initial guess orbitals if the geometry is dramatically changed. if isinstance(ncore, (int, numpy.integer)): mo = project(mfmo, init_mo, ncore, s) else: # UHF-based CASSCF mo = (project(mfmo[0], init_mo[0], ncore[0], s), project(mfmo[1], init_mo[1], ncore[1], s)) return mo
def init_guess_by_chkfile(cell, chkfile_name, project=None, kpts=None): '''Read the KHF results from checkpoint file, then project it to the basis defined by ``cell`` Returns: Density matrix, 3D 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) 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 = np.expand_dims(mo, axis=0) mo_occ = np.expand_dims(mo_occ, axis=0) else: # UHF mo = [np.expand_dims(mo[0], axis=0), np.expand_dims(mo[1], axis=0)] mo_occ = [np.expand_dims(mo_occ[0], axis=0), np.expand_dims(mo_occ[1], axis=0)] if project: s = cell.pbc_intor('int1e_ovlp', kpts=kpts) def fproj(mo, kpts): if project: mo = addons.project_mo_nr2nr(chk_cell, mo, cell, kpts) for k, c in enumerate(mo): norm = np.einsum('pi,pi->i', c.conj(), s[k].dot(c)) mo[k] /= np.sqrt(norm) return mo if kpts.shape == chk_kpts.shape and np.allclose(kpts, chk_kpts): def makedm(mos, occs): moa, mob = mos mos =([fproj(mo, None) for mo in moa], [fproj(mo, None) for mo in mob]) return make_rdm1(mos, occs) else: 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) if getattr(mo[0], 'ndim', None) == 2: # KRHF mo_occa = [(occ>1e-8).astype(np.double) for occ in mo_occ] mo_occb = [occ-mo_occa[k] for k,occ in enumerate(mo_occ)] dm = makedm((mo, mo), (mo_occa, mo_occb)) else: # KUHF dm = makedm(mo, mo_occ) # Real DM for gamma point if np.allclose(kpts, 0): dm = dm.real return dm