def _cache_and_analyze_(self, calcname, E, focka_fockb, dma_dmb, JKidem, JKcorr, oneRDMcorr_loc, loc2idem, loc2corr, nelec_idem, oneRDM_loc, oneSDM_loc): ######################################################################################################## self.e_tot = E self.activeVSPIN = (focka_fockb[0] - focka_fockb[1]) / 2 #self.activeFOCK = get_roothaan_fock (focka_fockb, dma_dmb, np.eye (self.norbs_tot)) self.activeFOCK = (focka_fockb[0] + focka_fockb[1]) / 2 self.activeJKidem = JKidem self.activeJKcorr = JKcorr self.oneRDMcorr_loc = oneRDMcorr_loc self.oneSDMcorr_loc = oneSDM_loc self.loc2idem = loc2idem self.nelec_idem = nelec_idem self.oneRDM_loc = oneRDM_loc self.oneSDM_loc = oneSDM_loc ######################################################################################################## # Analysis: 1RDM and total energy print("LASSCF trial wave function total energy: {:.9f}".format(E)) ao2molden, ene_no, occ_no = self.get_trial_nos(aobasis=True, loc2wmas=loc2corr, oneRDM_loc=oneRDM_loc, fock=self.activeFOCK, jmol_shift=True, try_symmetrize=True) if self.mol.verbose: print("Writing trial wave function molden") molden.from_mo(self.mol, calcname + '_trial_wvfn.molden', ao2molden, occ=occ_no, ene=ene_no)
def examine_wmcs (dmet_obj): loc2wmas = np.concatenate ([f.loc2amo for f in dmet_obj.fragments], axis=1) loc2wmcs = get_complementary_states (loc2wmas) print ("Examining whole-molecule active space:") loc2wmas = dmet_obj.ints.compare_basis_to_loc (loc2wmas, dmet_obj.fragments, quiet=False)[0] norbs_wmas = np.array ([f.norbs_as for f in dmet_obj.fragments]) print ("Examining whole-molecule core space:") norbs_wmcs_before = dmet_obj.ints.compare_basis_to_loc (loc2wmcs, dmet_obj.fragments, quiet=True)[1] norbs_before = norbs_wmas + norbs_wmcs_before ao2loc = dmet_obj.ints.ao2loc loc2ao = ao2loc.conjugate ().T ao2wmcs = np.dot (ao2loc, loc2wmcs) ao2wmcs_new = boys.Boys (dmet_obj.ints.mol, ao2wmcs).kernel () aoOao_inv = np.linalg.inv (np.dot (ao2loc, loc2ao)) loc2wmcs_new = reduce (np.dot, [loc2ao, aoOao_inv, ao2wmcs_new]) loc2wmcs_new, norbs_wmcs_after = dmet_obj.ints.compare_basis_to_loc (loc2wmcs_new, dmet_obj.fragments, quiet=False) norbs_after = norbs_wmas + norbs_wmcs_after loc2new = np.append (loc2wmas, loc2wmcs_new, axis=1) active_flag = np.append (np.ones (loc2wmas.shape[1]), np.zeros (loc2wmcs_new.shape[1])) print ("Is the new basis orthonormal and complete? {0}".format (is_basis_orthonormal_and_complete (loc2new))) print ("Fragment-orbital assignment breakdown:") print ("Frag Before After") for frag, bef, aft in zip (dmet_obj.fragments, norbs_before, norbs_after): print ('{:>4s} {:6d} {:5d}'.format (frag.frag_name, int (bef), int (aft))) filename = 'relocalized_basis.molden' mol = dmet_obj.ints.mol.copy () ao2new = np.dot (dmet_obj.ints.ao2loc, loc2new) molden.from_mo (mol, filename, ao2new, occ=active_flag) '''
def make_guess_molden (frag, filename, imp2mo, norbs_cmo, norbs_amo): norbs_tot = imp2mo.shape[1] mo_occ = np.zeros (norbs_tot) norbs_occ = norbs_cmo + norbs_amo mo_occ[:norbs_cmo] = 2 mo_occ[norbs_cmo:norbs_occ] = 1 mo = reduce (np.dot, (frag.ints.ao2loc, frag.loc2imp, imp2mo)) molden.from_mo (frag.ints.mol, filename, mo, occ=mo_occ) return
def test_dump_cartesian_gto_symm_orbital(self): ftmp = tempfile.NamedTemporaryFile() fname = ftmp.name pmol = mol.copy() pmol.cart = True pmol.build() mf = scf.RHF(pmol).run() molden.from_mo(pmol, fname, mf.mo_coeff) res = molden.read(fname) mo_coeff = res[2] self.assertAlmostEqual(abs(mf.mo_coeff - mo_coeff).max(), 0, 12)
def from_sa_mcscf(mc, fname, state=None, cas_natorb=False, cas_mo_energy=False, **kwargs): if state is None: return from_mcscf(mc, fname, cas_natorb=cas_natorb, **kwargs) casdm1 = mc.fcisolver.states_make_rdm1(mc.ci, mc.ncas, mc.nelecas)[state] mo_coeff, mo_ci, mo_energy = mc.canonicalize(ci=mc.ci[state], cas_natorb=cas_natorb, casdm1=casdm1) if not cas_mo_energy: mo_energy[mc.ncore:][:mc.ncas] = 0.0 # TODO: cleaner interface. Probably invent "state_make_?dm*" functions ("state" singular) # and apply them also to the StateAverageMCSCFSolver instance mo_occ = np.zeros_like(mo_energy) mo_occ[:mc.ncore] = 2.0 ci = mc.ci ci[state] = mo_ci mo_occ[mc.ncore:][:mc.ncas] = mc.fcisolver.states_make_rdm1( ci, mc.ncas, mc.nelecas)[state].diagonal() return from_mo(mc.mol, fname, mo_coeff, occ=mo_occ, ene=mo_energy, **kwargs)
def visualize_mos(mol: gto.mole.Mole, mo_coeff: np.ndarray, act_mos: list, nroot: int = 1, name: str = 'act_mo', keepmolden: bool = False, mo_occ: list = None, mo_ene: list = None): r"""Function to visualize the active MOs via Jmol. Orbitals are counted from 0! Args: mol: The molecule in PySCF's gto.Mole() format. mo_coeff (np.ndarray): The MO coeff. matrix obtained via DMRG. act_mos (list): The suggested active MOs which will be plotted. nroot (int): Number of the root that is being plotted. Only for purpose of naming. name (str): Prefix of the filename for orbitals. keepmolden (bool): Keep the molden file used for visualization. mo_occ (list): MO_occupation to be written in molden file. mo_ene (list): MO energy to be written in molden file. """ # Create molden orbitals from pyscf.tools import molden molden.from_mo(mol, 'asf_mos.molden', mo_coeff, ene=mo_ene, occ=mo_occ) # Write jmol script with open('plot.spt', 'w') as plotfile: print('initialize;\nset background [xffffff];\nset frank off;\n', 'set autoBond true;\nset bondRadiusMilliAngstroms 66;\n', 'set bondTolerance 0.5;\nset forceAutoBond false;\n', 'load asf_mos.molden;\nrotate 45 x;\nrotate 45 y;\n', 'zoom 100;' '', file=plotfile) for ii in act_mos: print('isosurface color yellow purple mo ', '%s translucent; write PNG 200 "%s_%s_%s.png"' % (ii + 1, name, nroot, ii), file=plotfile) print('exitJmol;\n', file=plotfile) os.system('jmol plot.spt') os.remove('plot.spt')
idx_h0_2s = mol.search_ao_label ('0 H 2s')[0] idx_h1_2s = mol.search_ao_label ('1 H 2s')[0] dma = np.zeros ((nao, nao)) dmb = np.zeros ((nao, nao)) dma[idx_h0_1s,idx_h0_1s] = dmb[idx_h1_1s,idx_h1_1s] = dma[idx_h0_2s,idx_h0_2s] = dmb[idx_h1_2s,idx_h1_2s] = 1 dm0 = [dma, dmb] # Restricted mean-field base of MC-SCF objects mf = scf.RHF (mol).run () # MC-PDFT objects if gsbasis: gsmo = np.load (gsmofile) mc = mcpdft.CASSCF (mf, transl_type + fnal, ncas, nelecas, grids_level = 3) mo = mcscf.project_init_guess (mc, gsmo, prev_mol=gsmol) molden.from_mo (mol, 'check_projection.molden', mo) mc.kernel (mo) mc = mc.as_scanner () else: mc = mcpdft.CASSCF (mf, transl_type + fnal, ncas, nelecas, grids_level = 3).run ().as_scanner () np.save (mofile, mc.mo_coeff) # Do MCSCF scan forwards table = np.zeros ((HHrange.size, 9)) table[:,0] = HHrange for ix, HHdist in enumerate (HHrange): geom = 'H 0 0 0; H 0 0 {:.6f}'.format (HHdist) table[ix,1] = mc (geom) table[ix,2] = mc.e_mcscf table[ix,3:] = list (mc.get_energy_decomposition ())
def solve (frag, guess_1RDM, chempot_imp): # Augment OEI with the chemical potential OEI = frag.impham_OEI_C - chempot_imp # Do I need to get the full RHF solution? guess_orbs_av = len (frag.imp_cache) == 2 or frag.norbs_as > 0 # Get the RHF solution mol = gto.Mole() abs_2MS = int (round (2 * abs (frag.target_MS))) abs_2S = int (round (2 * abs (frag.target_S))) sign_MS = int (np.sign (frag.target_MS)) or 1 mol.spin = abs_2MS mol.verbose = 0 if frag.mol_stdout is None: mol.output = frag.mol_output mol.verbose = 0 if frag.mol_output is None else lib.logger.DEBUG mol.atom.append(('H', (0, 0, 0))) mol.nelectron = frag.nelec_imp if frag.enforce_symmetry: mol.groupname = frag.symmetry mol.symm_orb = get_subspace_symmetry_blocks (frag.loc2imp, frag.loc2symm) mol.irrep_name = frag.ir_names mol.irrep_id = frag.ir_ids mol.max_memory = frag.ints.max_memory mol.build () if frag.mol_stdout is None: frag.mol_stdout = mol.stdout else: mol.stdout = frag.mol_stdout mol.verbose = 0 if frag.mol_output is None else lib.logger.DEBUG if frag.enforce_symmetry: mol.symmetry = True #mol.incore_anyway = True mf = scf.RHF(mol) mf.get_hcore = lambda *args: OEI mf.get_ovlp = lambda *args: np.eye(frag.norbs_imp) mf.energy_nuc = lambda *args: frag.impham_CONST if frag.impham_CDERI is not None: mf = mf.density_fit () mf.with_df._cderi = frag.impham_CDERI else: mf._eri = ao2mo.restore(8, frag.impham_TEI, frag.norbs_imp) mf = fix_my_RHF_for_nonsinglet_env (mf, frag.impham_OEI_S) mf.__dict__.update (frag.mf_attr) if guess_orbs_av: mf.max_cycle = 2 mf.scf (guess_1RDM) if (not mf.converged) and (not guess_orbs_av): if np.any (np.abs (frag.impham_OEI_S) > 1e-8) and mol.spin != 0: raise NotImplementedError('Gradient and Hessian fixes for nonsinglet environment of Newton-descent ROHF algorithm') print ("CASSCF RHF-step not converged on fixed-point iteration; initiating newton solver") mf = mf.newton () mf.kernel () # Instability check and repeat if not guess_orbs_av: for i in range (frag.num_mf_stab_checks): if np.any (np.abs (frag.impham_OEI_S) > 1e-8) and mol.spin != 0: raise NotImplementedError('ROHF stability-check fixes for nonsinglet environment') mf.mo_coeff = mf.stability ()[0] guess_1RDM = mf.make_rdm1 () mf = scf.RHF(mol) mf.get_hcore = lambda *args: OEI mf.get_ovlp = lambda *args: np.eye(frag.norbs_imp) mf._eri = ao2mo.restore(8, frag.impham_TEI, frag.norbs_imp) mf = fix_my_RHF_for_nonsinglet_env (mf, frag.impham_OEI_S) mf.scf (guess_1RDM) if not mf.converged: mf = mf.newton () mf.kernel () E_RHF = mf.e_tot print ("CASSCF RHF-step energy: {}".format (E_RHF)) # Get the CASSCF solution CASe = frag.active_space[0] CASorb = frag.active_space[1] checkCAS = (CASe <= frag.nelec_imp) and (CASorb <= frag.norbs_imp) if (checkCAS == False): CASe = frag.nelec_imp CASorb = frag.norbs_imp if (abs_2MS > abs_2S): CASe = ((CASe + sign_MS * abs_2S) // 2, (CASe - sign_MS * abs_2S) // 2) else: CASe = ((CASe + sign_MS * abs_2MS) // 2, (CASe - sign_MS * abs_2MS) // 2) if frag.impham_CDERI is not None: mc = mcscf.DFCASSCF(mf, CASorb, CASe) else: mc = mcscf.CASSCF(mf, CASorb, CASe) smult = abs_2S + 1 if frag.target_S is not None else (frag.nelec_imp % 2) + 1 mc.fcisolver = csf_solver (mf.mol, smult, symm=frag.enforce_symmetry) if frag.enforce_symmetry: mc.fcisolver.wfnsym = frag.wfnsym mc.max_cycle_macro = 50 if frag.imp_maxiter is None else frag.imp_maxiter mc.conv_tol = min (1e-9, frag.conv_tol_grad**2) mc.ah_start_tol = mc.conv_tol / 10 mc.ah_conv_tol = mc.conv_tol / 10 mc.__dict__.update (frag.corr_attr) mc = fix_my_CASSCF_for_nonsinglet_env (mc, frag.impham_OEI_S) norbs_amo = mc.ncas norbs_cmo = mc.ncore norbs_imo = frag.norbs_imp - norbs_amo nelec_amo = sum (mc.nelecas) norbs_occ = norbs_amo + norbs_cmo #mc.natorb = True # Guess orbitals ci0 = None dm_imp = frag.get_oneRDM_imp () fock_imp = mf.get_fock (dm=dm_imp) if len (frag.imp_cache) == 2: imp2mo, ci0 = frag.imp_cache print ("Taking molecular orbitals and ci vector from cache") elif frag.norbs_as > 0: nelec_imp_guess = int (round (np.trace (frag.oneRDMas_loc))) norbs_cmo_guess = (frag.nelec_imp - nelec_imp_guess) // 2 print ("Projecting stored amos (frag.loc2amo; spanning {} electrons) onto the impurity basis and filling the remainder with default guess".format (nelec_imp_guess)) imp2mo, my_occ = project_amo_manually (frag.loc2imp, frag.loc2amo, fock_imp, norbs_cmo_guess, dm=frag.oneRDMas_loc) elif frag.loc2amo_guess is not None: print ("Projecting stored amos (frag.loc2amo_guess) onto the impurity basis (no amo dm available)") imp2mo, my_occ = project_amo_manually (frag.loc2imp, frag.loc2amo_guess, fock_imp, norbs_cmo, dm=None) frag.loc2amo_guess = None else: dm_imp = np.asarray (mf.make_rdm1 ()) while dm_imp.ndim > 2: dm_imp = dm_imp.sum (0) imp2mo = mf.mo_coeff fock_imp = mf.get_fock (dm=dm_imp) fock_mo = represent_operator_in_basis (fock_imp, imp2mo) _, evecs = matrix_eigen_control_options (fock_mo, sort_vecs=1) imp2mo = imp2mo @ evecs my_occ = ((dm_imp @ imp2mo) * imp2mo).sum (0) print ("No stored amos; using mean-field canonical MOs as initial guess") # Guess orbital processing if callable (frag.cas_guess_callback): mo = reduce (np.dot, (frag.ints.ao2loc, frag.loc2imp, imp2mo)) mo = frag.cas_guess_callback (frag.ints.mol, mc, mo) imp2mo = reduce (np.dot, (frag.imp2loc, frag.ints.ao2loc.conjugate ().T, frag.ints.ao_ovlp, mo)) frag.cas_guess_callback = None # Guess CI vector if len (frag.imp_cache) != 2 and frag.ci_as is not None: loc2amo_guess = np.dot (frag.loc2imp, imp2mo[:,norbs_cmo:norbs_occ]) metric = np.arange (CASorb) + 1 gOc = np.dot (loc2amo_guess.conjugate ().T, (frag.ci_as_orb * metric[None,:])) umat_g, svals, umat_c = matrix_svd_control_options (gOc, sort_vecs=1, only_nonzero_vals=True) if (svals.size == norbs_amo): print ("Loading ci guess despite shifted impurity orbitals; singular value error sum: {}".format (np.sum (svals - metric))) imp2mo[:,norbs_cmo:norbs_occ] = np.dot (imp2mo[:,norbs_cmo:norbs_occ], umat_g) ci0 = transform_ci_for_orbital_rotation (frag.ci_as, CASorb, CASe, umat_c) else: print ("Discarding stored ci guess because orbitals are too different (missing {} nonzero svals)".format (norbs_amo-svals.size)) # Symmetry align if possible imp2unac = frag.align_imporbs_symm (np.append (imp2mo[:,:norbs_cmo], imp2mo[:,norbs_occ:], axis=1), sorting_metric=fock_imp, sort_vecs=1, orbital_type='guess unactive', mol=mol)[0] imp2mo[:,:norbs_cmo] = imp2unac[:,:norbs_cmo] imp2mo[:,norbs_occ:] = imp2unac[:,norbs_cmo:] #imp2mo[:,:norbs_cmo] = frag.align_imporbs_symm (imp2mo[:,:norbs_cmo], sorting_metric=fock_imp, sort_vecs=1, orbital_type='guess inactive', mol=mol)[0] imp2mo[:,norbs_cmo:norbs_occ], umat = frag.align_imporbs_symm (imp2mo[:,norbs_cmo:norbs_occ], sorting_metric=fock_imp, sort_vecs=1, orbital_type='guess active', mol=mol) #imp2mo[:,norbs_occ:] = frag.align_imporbs_symm (imp2mo[:,norbs_occ:], sorting_metric=fock_imp, sort_vecs=1, orbital_type='guess external', mol=mol)[0] if frag.enforce_symmetry: imp2mo = cleanup_subspace_symmetry (imp2mo, mol.symm_orb) err_symm = measure_subspace_blockbreaking (imp2mo, mol.symm_orb) err_orth = measure_basis_nonorthonormality (imp2mo) print ("Initial symmetry error after cleanup = {}".format (err_symm)) print ("Initial orthonormality error after cleanup = {}".format (err_orth)) if ci0 is not None: ci0 = transform_ci_for_orbital_rotation (ci0, CASorb, CASe, umat) # Guess orbital printing if frag.mfmo_printed == False and frag.ints.mol.verbose: ao2mfmo = reduce (np.dot, [frag.ints.ao2loc, frag.loc2imp, imp2mo]) print ("Writing {} {} orbital molden".format (frag.frag_name, 'CAS guess')) molden.from_mo (frag.ints.mol, frag.filehead + frag.frag_name + '_mfmorb.molden', ao2mfmo, occ=my_occ) frag.mfmo_printed = True elif len (frag.active_orb_list) > 0: # This is done AFTER everything else so that the _mfmorb.molden always has consistent ordering print('Applying caslst: {}'.format (frag.active_orb_list)) imp2mo = mc.sort_mo(frag.active_orb_list, mo_coeff=imp2mo) frag.active_orb_list = [] if len (frag.frozen_orb_list) > 0: mc.frozen = copy.copy (frag.frozen_orb_list) print ("Applying frozen-orbital list (this macroiteration only): {}".format (frag.frozen_orb_list)) frag.frozen_orb_list = [] if frag.enforce_symmetry: imp2mo = lib.tag_array (imp2mo, orbsym=label_orb_symm (mol, mol.irrep_id, mol.symm_orb, imp2mo, s=mf.get_ovlp (), check=False)) t_start = time.time() E_CASSCF = mc.kernel(imp2mo, ci0)[0] if (not mc.converged) and np.all (np.abs (frag.impham_OEI_S) < 1e-8): mc = mc.newton () E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0] if not mc.converged: print ('Assuming ci vector is poisoned; discarding...') imp2mo = mc.mo_coeff.copy () mc = mcscf.CASSCF(mf, CASorb, CASe) smult = abs_2S + 1 if frag.target_S is not None else (frag.nelec_imp % 2) + 1 mc.fcisolver = csf_solver (mf.mol, smult) E_CASSCF = mc.kernel(imp2mo)[0] if not mc.converged: if np.any (np.abs (frag.impham_OEI_S) > 1e-8): raise NotImplementedError('Gradient and Hessian fixes for nonsinglet environment of Newton-descent CASSCF algorithm') mc = mc.newton () E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0] assert (mc.converged) ''' mc.conv_tol = 1e-12 mc.ah_start_tol = 1e-10 mc.ah_conv_tol = 1e-12 E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0] if not mc.converged: mc = mc.newton () E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0] #assert (mc.converged) ''' # Get twoRDM + oneRDM. cs: MC-SCF core, as: MC-SCF active space # I'm going to need to keep some representation of the active-space orbitals # Symmetry align if possible oneRDM_amo, twoRDM_amo = mc.fcisolver.make_rdm12 (mc.ci, mc.ncas, mc.nelecas) fock_imp = mc.get_fock () mc.mo_coeff[:,:norbs_cmo] = frag.align_imporbs_symm (mc.mo_coeff[:,:norbs_cmo], sorting_metric=fock_imp, sort_vecs=1, orbital_type='optimized inactive', mol=mol)[0] mc.mo_coeff[:,norbs_cmo:norbs_occ], umat = frag.align_imporbs_symm (mc.mo_coeff[:,norbs_cmo:norbs_occ], sorting_metric=oneRDM_amo, sort_vecs=-1, orbital_type='optimized active', mol=mol) mc.mo_coeff[:,norbs_occ:] = frag.align_imporbs_symm (mc.mo_coeff[:,norbs_occ:], sorting_metric=fock_imp, sort_vecs=1, orbital_type='optimized external', mol=mol)[0] if frag.enforce_symmetry: amo2imp = mc.mo_coeff[:,norbs_cmo:norbs_occ].conjugate ().T mc.mo_coeff = cleanup_subspace_symmetry (mc.mo_coeff, mol.symm_orb) umat = umat @ (amo2imp @ mc.mo_coeff[:,norbs_cmo:norbs_occ]) err_symm = measure_subspace_blockbreaking (mc.mo_coeff, mol.symm_orb) err_orth = measure_basis_nonorthonormality (mc.mo_coeff) print ("Final symmetry error after cleanup = {}".format (err_symm)) print ("Final orthonormality error after cleanup = {}".format (err_orth)) mc.ci = transform_ci_for_orbital_rotation (mc.ci, CASorb, CASe, umat) # Cache stuff imp2mo = mc.mo_coeff #mc.cas_natorb()[0] loc2mo = np.dot (frag.loc2imp, imp2mo) imp2amo = imp2mo[:,norbs_cmo:norbs_occ] loc2amo = loc2mo[:,norbs_cmo:norbs_occ] frag.imp_cache = [mc.mo_coeff, mc.ci] frag.ci_as = mc.ci frag.ci_as_orb = loc2amo.copy () t_end = time.time() # oneRDM oneRDM_imp = mc.make_rdm1 () # twoCDM oneRDM_amo, twoRDM_amo = mc.fcisolver.make_rdm12 (mc.ci, mc.ncas, mc.nelecas) oneRDMs_amo = np.stack (mc.fcisolver.make_rdm1s (mc.ci, mc.ncas, mc.nelecas), axis=0) oneSDM_amo = oneRDMs_amo[0] - oneRDMs_amo[1] if frag.target_MS >= 0 else oneRDMs_amo[1] - oneRDMs_amo[0] oneSDM_imp = represent_operator_in_basis (oneSDM_amo, imp2amo.conjugate ().T) print ("Norm of spin density: {}".format (linalg.norm (oneSDM_amo))) # Note that I do _not_ do the *real* cumulant decomposition; I do one assuming oneSDM_amo = 0. # This is fine as long as I keep it consistent, since it is only in the orbital gradients for this impurity that # the spin density matters. But it has to stay consistent! twoCDM_amo = get_2CDM_from_2RDM (twoRDM_amo, oneRDM_amo) twoCDM_imp = represent_operator_in_basis (twoCDM_amo, imp2amo.conjugate ().T) print('Impurity CASSCF energy (incl chempot): {}; spin multiplicity: {}; time to solve: {}'.format (E_CASSCF, spin_square (mc)[1], t_end - t_start)) # Active-space RDM data frag.oneRDMas_loc = symmetrize_tensor (represent_operator_in_basis (oneRDM_amo, loc2amo.conjugate ().T)) frag.oneSDMas_loc = symmetrize_tensor (represent_operator_in_basis (oneSDM_amo, loc2amo.conjugate ().T)) frag.twoCDMimp_amo = twoCDM_amo frag.loc2mo = loc2mo frag.loc2amo = loc2amo frag.E2_cum = np.tensordot (ao2mo.restore (1, mc.get_h2eff (), mc.ncas), twoCDM_amo, axes=4) / 2 frag.E2_cum += (mf.get_k (dm=oneSDM_imp) * oneSDM_imp).sum () / 4 # The second line compensates for my incorrect cumulant decomposition. Anything to avoid changing the checkpoint files... # General impurity data frag.oneRDM_loc = frag.oneRDMfroz_loc + symmetrize_tensor (represent_operator_in_basis (oneRDM_imp, frag.imp2loc)) frag.oneSDM_loc = frag.oneSDMfroz_loc + frag.oneSDMas_loc frag.twoCDM_imp = None # Experiment: this tensor is huge. Do I actually need to keep it? In principle, of course not. frag.E_imp = E_CASSCF + np.einsum ('ab,ab->', chempot_imp, oneRDM_imp) return None
#!/usr/bin/env python # # Author: Qiming Sun <*****@*****.**> # ''' TDDFT NTO analysis. ''' from pyscf import gto, dft, tddft mol = gto.Mole() mol.build( atom='H 0 0 0; F 0 0 1.1', # in Angstrom basis='631g', symmetry=True, ) mf = dft.RKS(mol) mf.xc = 'b3lyp' mf.kernel() mytd = tddft.TDDFT(mf) mytd.kernel() weights_1, nto_1 = mytd.get_nto(state=1, verbose=4) weights_2, nto_2 = mytd.get_nto(state=2, verbose=4) weights_3, nto_3 = mytd.get_nto(state=3, verbose=4) from pyscf.tools import molden molden.from_mo(mol, 'nto-td-3.molden', nto_3)
C -1.211265339156 0.699329968382 0.000000000000 C -1.211265339156 -0.699329968382 0.000000000000 H 0.000000000000 2.491406946734 0.000000000000 H 0.000000000000 -2.491406946734 0.000000000000 H 2.157597486829 1.245660462400 0.000000000000 H 2.157597486829 -1.245660462400 0.000000000000 H -2.157597486829 1.245660462400 0.000000000000 H -2.157597486829 -1.245660462400 0.000000000000''', basis = '6-31g') mf = scf.RHF(mol) mf.chkfile = 'benzene-631g.chk' mf.kernel() pz_idx = numpy.array([17,20,21,22,23,30,36,41,42,47,48,49])-1 loc_orb = lo.Boys(mol, mf.mo_coeff[:,pz_idx]).kernel() molden.from_mo(mol, 'benzene-631g-boys.molden', loc_orb) import numpy from pyscf import lib from pyscf import tools from pyscf.tools import mo_mapping mol, mo_energy, mo_coeff, mo_occ, irrep_labels, spins = \ tools.molden.load('benzene-631g-boys.molden') comp = mo_mapping.mo_comps('C.*2p[yz]', # regular expression mol, mo_coeff) mol = lib.chkfile.load_mol('benzene-631g.chk')
mf = scf.RHF(mol) mf.kernel() # # First method is to explicit call the functions provided by molden.py # with open('C6H6mo.molden', 'w') as f1: molden.header(mol, f1) molden.orbital_coeff(mol, f1, mf.mo_coeff, ene=mf.mo_energy, occ=mf.mo_occ) # # Second method is to simply call from_mo function to write the orbitals # c_loc_orth = lo.orth.orth_ao(mol) molden.from_mo(mol, 'C6H6loc.molden', c_loc_orth) # # Molden format does not support high angular momentum basis. To handle the # orbitals which have l>=5 functions, a hacky way is to call molden.remove_high_l # function. However, the resultant orbitals may not be orthnormal. # mol = gto.M( atom = 'He 0 0 0', basis = {'He': gto.expand_etbs(((0, 3, 1., 2.), (5, 2, 1., 2.)))}) mf = scf.RHF(mol).run() try: molden.from_mo(mol, 'He_without_h.molden', mf.mo_coeff) except RuntimeError: print(' Found l=5 in basis.')
def solve(frag, guess_1RDM, chempot_imp): # Augment OEI with the chemical potential OEI = frag.impham_OEI - chempot_imp # Do I need to get the full RHF solution? guess_orbs_av = len(frag.imp_cache) == 2 or frag.norbs_as > 0 # Get the RHF solution mol = gto.Mole() mol.spin = int(round(2 * frag.target_MS)) mol.verbose = 0 if frag.mol_output is None else lib.logger.DEBUG mol.output = frag.mol_output mol.atom.append(('H', (0, 0, 0))) mol.nelectron = frag.nelec_imp mol.build() #mol.incore_anyway = True mf = scf.RHF(mol) mf.get_hcore = lambda *args: OEI mf.get_ovlp = lambda *args: np.eye(frag.norbs_imp) mf.energy_nuc = lambda *args: frag.impham_CONST if frag.impham_CDERI is not None: mf = mf.density_fit() mf.with_df._cderi = frag.impham_CDERI else: mf._eri = ao2mo.restore(8, frag.impham_TEI, frag.norbs_imp) mf.__dict__.update(frag.mf_attr) if guess_orbs_av: mf.max_cycle = 2 mf.scf(guess_1RDM) if (not mf.converged) and (not guess_orbs_av): print( "CASSCF RHF-step not converged on fixed-point iteration; initiating newton solver" ) mf = mf.newton() mf.kernel() # Instability check and repeat if not guess_orbs_av: for i in range(frag.num_mf_stab_checks): mf.mo_coeff = mf.stability()[0] guess_1RDM = mf.make_rdm1() mf = scf.RHF(mol) mf.get_hcore = lambda *args: OEI mf.get_ovlp = lambda *args: np.eye(frag.norbs_imp) mf._eri = ao2mo.restore(8, frag.impham_TEI, frag.norbs_imp) mf.scf(guess_1RDM) if not mf.converged: mf = mf.newton() mf.kernel() print("CASSCF RHF-step energy: {}".format(mf.e_tot)) #print(mf.mo_occ) ''' idx = mf.mo_energy.argsort() mf.mo_energy = mf.mo_energy[idx] mf.mo_coeff = mf.mo_coeff[:,idx]''' # Get the CASSCF solution CASe = frag.active_space[0] CASorb = frag.active_space[1] checkCAS = (CASe <= frag.nelec_imp) and (CASorb <= frag.norbs_imp) if (checkCAS == False): CASe = frag.nelec_imp CASorb = frag.norbs_imp if (frag.target_MS > frag.target_S): CASe = ((CASe // 2) + frag.target_S, (CASe // 2) - frag.target_S) else: CASe = ((CASe // 2) + frag.target_MS, (CASe // 2) - frag.target_MS) if frag.impham_CDERI is not None: mc = mcscf.DFCASSCF(mf, CASorb, CASe) else: mc = mcscf.CASSCF(mf, CASorb, CASe) norbs_amo = mc.ncas norbs_cmo = mc.ncore norbs_imo = frag.norbs_imp - norbs_amo nelec_amo = sum(mc.nelecas) norbs_occ = norbs_amo + norbs_cmo #mc.natorb = True # Guess orbitals ci0 = None if len(frag.imp_cache) == 2: imp2mo, ci0 = frag.imp_cache print("Taking molecular orbitals and ci vector from cache") elif frag.norbs_as > 0: nelec_imp_guess = int(round(np.trace(frag.oneRDMas_loc))) norbs_cmo_guess = (frag.nelec_imp - nelec_imp_guess) // 2 print( "Projecting stored amos (frag.loc2amo; spanning {} electrons) onto the impurity basis and filling the remainder with default guess" .format(nelec_imp_guess)) imp2mo, my_occ = project_amo_manually( frag.loc2imp, frag.loc2amo, mf.get_fock(dm=frag.get_oneRDM_imp()), norbs_cmo_guess, dm=frag.oneRDMas_loc) elif frag.loc2amo_guess is not None: print( "Projecting stored amos (frag.loc2amo_guess) onto the impurity basis (no dm available)" ) imp2mo, my_occ = project_amo_manually( frag.loc2imp, frag.loc2amo_guess, mf.get_fock(dm=frag.get_oneRDM_imp()), norbs_cmo, dm=None) frag.loc2amo_guess = None else: imp2mo = mc.mo_coeff my_occ = mf.mo_occ print( "No stored amos; using mean-field canonical MOs as initial guess") # Guess orbital processing if callable(frag.cas_guess_callback): mo = reduce(np.dot, (frag.ints.ao2loc, frag.loc2imp, imp2mo)) mo = frag.cas_guess_callback(frag.ints.mol, mc, mo) imp2mo = reduce(np.dot, (frag.imp2loc, frag.ints.ao2loc.conjugate().T, frag.ints.ao_ovlp, mo)) frag.cas_guess_callback = None elif len(frag.active_orb_list) > 0: print('Applying caslst: {}'.format(frag.active_orb_list)) imp2mo = mc.sort_mo(frag.active_orb_list, mo_coeff=imp2mo) frag.active_orb_list = [] if len(frag.frozen_orb_list) > 0: mc.frozen = copy.copy(frag.frozen_orb_list) print("Applying frozen-orbital list (this macroiteration only): {}". format(frag.frozen_orb_list)) frag.frozen_orb_list = [] # Guess orbital printing if frag.mfmo_printed == False: ao2mfmo = reduce(np.dot, [frag.ints.ao2loc, frag.loc2imp, imp2mo]) molden.from_mo(frag.ints.mol, frag.filehead + frag.frag_name + '_mfmorb.molden', ao2mfmo, occ=my_occ) frag.mfmo_printed = True # Guess CI vector if len(frag.imp_cache) != 2 and frag.ci_as is not None: loc2amo_guess = np.dot(frag.loc2imp, imp2mo[:, norbs_cmo:norbs_occ]) gOc = np.dot(loc2amo_guess.conjugate().T, frag.ci_as_orb) umat_g, svals, umat_c = matrix_svd_control_options( gOc, sort_vecs=-1, only_nonzero_vals=True) if (svals.size == norbs_amo): print( "Loading ci guess despite shifted impurity orbitals; singular value sum: {}" .format(np.sum(svals))) imp2mo[:, norbs_cmo:norbs_occ] = np.dot( imp2mo[:, norbs_cmo:norbs_occ], umat_g) ci0 = transform_ci_for_orbital_rotation(frag.ci_as, CASorb, CASe, umat_c) else: print( "Discarding stored ci guess because orbitals are too different (missing {} nonzero svals)" .format(norbs_amo - svals.size)) t_start = time.time() smult = 2 * frag.target_S + 1 if frag.target_S is not None else ( frag.nelec_imp % 2) + 1 mc.fcisolver = csf_solver(mf.mol, smult) mc.max_cycle_macro = 50 if frag.imp_maxiter is None else frag.imp_maxiter mc.ah_start_tol = 1e-10 mc.ah_conv_tol = 1e-10 mc.conv_tol = 1e-9 mc.__dict__.update(frag.corr_attr) E_CASSCF = mc.kernel(imp2mo, ci0)[0] if not mc.converged: mc = mc.newton() E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0] if not mc.converged: print('Assuming ci vector is poisoned; discarding...') imp2mo = mc.mo_coeff.copy() mc = mcscf.CASSCF(mf, CASorb, CASe) smult = 2 * frag.target_S + 1 if frag.target_S is not None else ( frag.nelec_imp % 2) + 1 mc.fcisolver = csf_solver(mf.mol, smult) E_CASSCF = mc.kernel(imp2mo)[0] if not mc.converged: mc = mc.newton() E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0] assert (mc.converged) ''' mc.conv_tol = 1e-12 mc.ah_start_tol = 1e-10 mc.ah_conv_tol = 1e-12 E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0] if not mc.converged: mc = mc.newton () E_CASSCF = mc.kernel(mc.mo_coeff, mc.ci)[0] #assert (mc.converged) ''' # Get twoRDM + oneRDM. cs: MC-SCF core, as: MC-SCF active space # I'm going to need to keep some representation of the active-space orbitals imp2mo = mc.mo_coeff #mc.cas_natorb()[0] loc2mo = np.dot(frag.loc2imp, imp2mo) imp2amo = imp2mo[:, norbs_cmo:norbs_occ] loc2amo = loc2mo[:, norbs_cmo:norbs_occ] frag.imp_cache = [mc.mo_coeff, mc.ci] frag.ci_as = mc.ci frag.ci_as_orb = loc2amo.copy() t_end = time.time() print( 'Impurity CASSCF energy (incl chempot): {}; spin multiplicity: {}; time to solve: {}' .format(E_CASSCF, spin_square(mc)[1], t_end - t_start)) # oneRDM oneRDM_imp = mc.make_rdm1() # twoCDM oneRDM_amo, twoRDM_amo = mc.fcisolver.make_rdm12(mc.ci, mc.ncas, mc.nelecas) # Note that I do _not_ do the *real* cumulant decomposition; I do one assuming oneRDMs_amo_alpha = oneRDMs_amo_beta # This is fine as long as I keep it consistent, since it is only in the orbital gradients for this impurity that # the spin density matters. But it has to stay consistent! twoCDM_amo = get_2CDM_from_2RDM(twoRDM_amo, oneRDM_amo) twoCDM_imp = represent_operator_in_basis(twoCDM_amo, imp2amo.conjugate().T) # General impurity data frag.oneRDM_loc = symmetrize_tensor( frag.oneRDMfroz_loc + represent_operator_in_basis(oneRDM_imp, frag.imp2loc)) frag.twoCDM_imp = None # Experiment: this tensor is huge. Do I actually need to keep it? In principle, of course not. frag.E_imp = E_CASSCF + np.einsum('ab,ab->', chempot_imp, oneRDM_imp) # Active-space RDM data frag.oneRDMas_loc = symmetrize_tensor( represent_operator_in_basis(oneRDM_amo, loc2amo.conjugate().T)) frag.twoCDMimp_amo = twoCDM_amo frag.loc2mo = loc2mo frag.loc2amo = loc2amo frag.E2_cum = 0.5 * np.tensordot( ao2mo.restore(1, mc.get_h2eff(), mc.ncas), twoCDM_amo, axes=4) return None
def from_lasscf(las, fname, **kwargs): mo_coeff, mo_ene, mo_occ = las.canonicalize()[:3] return from_mo(las.mol, fname, mo_coeff, occ=mo_occ, ene=mo_ene, **kwargs)
''' DF-MP2 natural orbitals for the allyl radical ''' from pyscf.gto import Mole from pyscf.scf import UHF from pyscf.tools import molden from pyscf.mp.dfump2_native import DFMP2 mol = Mole() mol.atom = ''' C -1.1528 -0.1151 -0.4645 C 0.2300 -0.1171 -0.3508 C 0.9378 0.2246 0.7924 H 0.4206 0.5272 1.7055 H 2.0270 0.2021 0.8159 H -1.6484 -0.3950 -1.3937 H -1.7866 0.1687 0.3784 H 0.8086 -0.4120 -1.2337 ''' mol.basis = 'def2-TZVP' mol.spin = 1 mol.build() mf = UHF(mol).run() # MP2 natural occupation numbers and natural orbitals natocc, natorb = DFMP2(mf).make_natorbs() # store the natural orbitals in a molden file molden.from_mo(mol, 'allyl_mp2nat.molden', natorb, occ=natocc)
# # Load MF orbitals # chkname = "_chk/pp_dianion_dz_b3lyp.chk" mol = chkfile.load_mol(chkname) mol.verbose = 5 mf = dft.RKS(mol) mf.__dict__.update(chkfile.load(chkname, "scf")) # # SA-MCSCF # nelecas, ncas = (4, 4) n_states = 3 weights = np.ones(n_states) / n_states mc = mcscf.CASSCF(mf, ncas, nelecas).state_average_(weights) mc.fix_spin(ss=0) mc.natorb = True mc.chkfile = "_chk/pp_dianion_dz_cas_4e_4o.chk" cas_list = [142, 143, 150, 151] mo = mcscf.sort_mo(mc, mf.mo_coeff, cas_list) mc.mc1step(mo) # # Analysis and processing # mc.analyze() molden.from_mcscf(mc, "_molden/pp_dianion_dz_cas_4e_4o.molden") molden.from_mo(mol, "_molden/pp_dianion_dz_cas_4e_4o_alt.molden", mc.mo_coeff)
# UKS comparison (initial guess must break symmetry!) pks = scf.UKS(mol) pks.xc = fnal pks.kernel(dm0) pks = pks.as_scanner() hks = scf.UKS(mol) hks.xc = kshfnal hks.kernel(dm0) hks = hks.as_scanner() # MC-PDFT objects if gsbasis: gsmo = np.load(gsmofile) mc = mcpdft.CASSCF(mf, transl_type + fnal, ncas, nelecas, grids_level=3) mo = mcscf.project_init_guess(mc, gsmo, prev_mol=gsmol) molden.from_mo(mol, 'check_projection.molden', mo) mc.kernel(mo) mc = mc.as_scanner() else: mc = mcpdft.CASSCF(mf, transl_type + fnal, ncas, nelecas, grids_level=3).run().as_scanner() mc0 = mcpdft.CASSCF(mf, otfnal0, ncas, nelecas, grids_level=3).run().as_scanner() mc1 = mcpdft.CASSCF(mf, otfnal1, ncas, nelecas, grids_level=3).run().as_scanner() mc2 = mcpdft.CASSCF(mf, otfnal2, ncas, nelecas, grids_level=3).run().as_scanner() molden.from_mcscf(mc0, moldenfile) np.save(mofile, mc.mo_coeff) # Do MCSCF scan forwards
def impurity_molden(self, tag=None, canonicalize=False, natorb=False, molorb=False, ene=None, occ=None): tag = '.' if tag == None else '_' + str(tag) + '.' filename = self.filehead + self.frag_name + tag + 'molden' mol = self.ints.mol.copy() mol.nelectron = self.nelec_imp mol.spin = int(round(2 * self.target_MS)) oneRDM = self.get_oneRDM_imp() FOCK = represent_operator_in_basis( self.ints.loc_rhf_fock_bis(self.oneRDM_loc), self.loc2imp) ao2imp = np.dot(self.ints.ao2loc, self.loc2imp) ao2molden = ao2imp if molorb: assert (not natorb) assert (not canonicalize) ao2molden = np.dot(self.ints.ao2loc, self.loc2mo) occ = np.einsum('ip,ij,jp->p', self.imp2mo.conjugate(), oneRDM, self.imp2mo) ene = np.einsum('ip,ij,jp->p', self.imp2mo.conjugate(), FOCK, self.imp2mo) if self.norbs_as > 0: ene = cas_mo_energy_shift_4_jmol(ene, self.norbs_imp, self.nelec_imp, self.norbs_as, self.nelec_as) if natorb: assert (not canonicalize) # Separate active and external (inactive + virtual) orbitals and pry their energies apart by +-1e4 Eh so Jmol sets them # in the proper order if self.norbs_as > 0: imp2xmo = get_complementary_states(self.imp2amo) FOCK_amo = represent_operator_in_basis(FOCK, self.imp2amo) FOCK_xmo = represent_operator_in_basis(FOCK, imp2xmo) oneRDM_xmo = represent_operator_in_basis(oneRDM, imp2xmo) oneRDM_amo = represent_operator_in_basis(oneRDM, self.imp2amo) ene_xmo, xmo2molden = matrix_eigen_control_options( FOCK_xmo, sort_vecs=1, only_nonzero_vals=False) occ_amo, amo2molden = matrix_eigen_control_options( oneRDM_amo, sort_vecs=-1, only_nonzero_vals=False) occ_xmo = np.einsum('ip,ij,jp->p', xmo2molden.conjugate(), oneRDM_xmo, xmo2molden) ene_amo = np.einsum('ip,ij,jp->p', amo2molden.conjugate(), FOCK_amo, amo2molden) norbs_imo = (self.nelec_imp - self.nelec_as) // 2 occ = np.concatenate( (occ_xmo[:norbs_imo], occ_amo, occ_xmo[norbs_imo:])) ene = np.concatenate( (ene_xmo[:norbs_imo], ene_amo, ene_xmo[norbs_imo:])) ene = cas_mo_energy_shift_4_jmol(ene, self.norbs_imp, self.nelec_imp, self.norbs_as, self.nelec_as) imp2molden = np.concatenate( (np.dot(imp2xmo, xmo2molden[:, :norbs_imo]), np.dot(self.imp2amo, amo2molden), np.dot(imp2xmo, xmo2molden[:, norbs_imo:])), axis=1) else: occ, imp2molden = matrix_eigen_control_options( oneRDM, sort_vecs=-1, only_nonzero_vals=False) ene = np.einsum('ip,ij,jp->p', imp2molden.conjugate(), FOCK, imp2molden) ao2molden = np.dot(ao2imp, imp2molden) elif canonicalize: # Separate active and external (inactive + virtual) orbitals and pry their energies apart by +-1e4 Eh so Jmol sets them # in the proper order if self.norbs_as > 0: imp2xmo = get_complementary_states(self.imp2amo) FOCK_amo = represent_operator_in_basis(FOCK, self.imp2amo) FOCK_xmo = represent_operator_in_basis(FOCK, imp2xmo) ene_xmo, xmo2molden = matrix_eigen_control_options( FOCK_xmo, sort_vecs=1, only_nonzero_vals=False) ene_amo, amo1molden = matrix_eigen_control_options( FOCK_amo, sort_vecs=1, only_nonzero_vals=False) norbs_imo = (self.nelec_imp - self.nelec_as) // 2 ene = np.concatenate( (ene_xmo[:norbs_imo], ene_amo, ene_xmo[norbs_imo:])) ene = cas_mo_energy_shift_4_jmol(ene, self.norbs_imp, self.nelec_imp, self.norbs_as, self.nelec_as) imp2molden = np.concatenate( (np.dot(imp2xmo, xmo2molden[:, :norbs_imo]), np.dot(self.imp2amo, amo2molden), np.dot(imp2xmo, xmo2molden[:, norbs_imo:])), axis=1) else: ene, imp2molden = matrix_eigen_control_options( FOCK, sort_vecs=-1, only_nonzero_vals=False) occ = np.einsum('ip,ij,jp->p', imp2molden.conjugate(), oneRDM, imp2molden) ao2molden = np.dot(ao2imp, imp2molden) molden.from_mo(mol, filename, ao2molden, ene=ene, occ=occ)
mf.chkfile = "_chk/pp_anion_pt_chg_dz_b3lyp.chk" mf.kernel() # mf.analyze() # # Dump orbitals # molden.dump_scf(mf, "_molden/pp_anion_pt_chg_dz_b3lyp.molden") # # SA-MCSCF # nelecas, ncas = (4, 4) n_states = 3 weights = np.ones(n_states) / n_states mc = mcscf.CASSCF(mf, ncas, nelecas).state_average_(weights) mc.fix_spin(ss=0) mc.natorb = True mc.chkfile = "_chk/pp_anion_pt_chg_dz_cas_4e_4o.chk" cas_list = [118, 119, 120, 121] mo = mcscf.sort_mo(mc, mf.mo_coeff, cas_list) mc.mc1step(mo) # # Analysis and processing # mc.analyze() molden.from_mcscf(mc, "_molden/pp_anion_pt_chg_dz_cas.molden") molden.from_mo(mol, "_molden/pp_anion_pt_chg_dz_cas_alt.molden", mc.mo_coeff)
def do_scf(inp): '''Do the requested SCF.''' from pyscf import gto, scf, dft, cc, fci, ci, ao2mo, mcscf, mrpt, lib, mp, tdscf from pyscf.cc import ccsd_t, uccsd_t import numpy as np from .fcidump import fcidump # sort out the method mol = inp.mol method = inp.scf.method.lower() # UHF if method == 'uhf': ehf, mSCF = do_hf(inp, unrestricted=True) print_energy('UHF', ehf) if inp.scf.exci is not None: inp.timer.start('TDHF') mtd = do_TDDFT(inp, mSCF) inp.timer.end('TDHF') # RHF elif method in ('rhf', 'hf'): ehf, mSCF = do_hf(inp) print_energy('RHF', ehf) if inp.scf.exci is not None: inp.timer.start('TDHF') mtd = do_TDDFT(inp, mSCF) inp.timer.end('TDHF') # CCSD and CCSD(T) elif method in ('ccsd', 'ccsd(t)', 'uccsd', 'uccsd(t)', 'eomccsd'): if 'u' in method: ehf, tSCF = do_hf(inp, unrestricted=True) print_energy('UHF', ehf) else: ehf, tSCF = do_hf(inp) print_energy('RHF', ehf) inp.timer.start('ccsd') frozen = 0 if inp.scf.freeze is not None: frozen = inp.scf.freeze if 'u' in method: mSCF = cc.UCCSD(tSCF, frozen=frozen) else: mSCF = cc.CCSD(tSCF, frozen=frozen) mSCF.max_cycle = inp.scf.maxiter eccsd, t1, t2 = mSCF.kernel() print_energy('CCSD', ehf + eccsd) inp.timer.end('ccsd') if method == 'eomccsd': inp.timer.start('eomccsd') ee = mSCF.eomee_ccsd_singlet(nroots=4)[0] inp.timer.end('eomccsd') for i in range(len(ee)): print_energy('EOM-CCSD {0} (eV)'.format(i+1), ee[i] * 27.2114) if method in ('ccsd(t)', 'uccsd(t)'): inp.timer.start('ccsd(t)') eris = mSCF.ao2mo() if method == 'ccsd(t)': e3 = ccsd_t.kernel(mSCF, eris) else: e3 = uccsd_t.kernel(mSCF, eris) print_energy('CCSD(T)', ehf + eccsd + e3) inp.timer.end('ccsd(t)') # MP2 elif method == 'mp2': ehf, tSCF = do_hf(inp) print_energy('RHF', ehf) inp.timer.start('mp2') frozen = 0 if inp.scf.freeze is not None: frozen = inp.scf.freeze mSCF = mp.MP2(tSCF, frozen=frozen) emp2, t2 = mSCF.kernel() print_energy('MP2', ehf+emp2) inp.timer.end('mp2') # CISD elif method == 'cisd' or method == 'cisd(q)': ehf, tSCF = do_hf(inp) print_energy('RHF', ehf) inp.timer.start('cisd') frozen = 0 if inp.scf.freeze is not None: frozen = inp.scf.freeze mSCF = ci.CISD(tSCF, frozen=frozen) ecisd = mSCF.kernel()[0] print_energy('CISD', ehf + ecisd) inp.timer.end('cisd') # perform Davison quadruples correction c0 = np.max(np.abs(mSCF.ci)) c02 = c0**2 ne = mSCF.mol.nelectron eq = ( 1.0 - c02 ) * ecisd print_energy('CISD(Q) Davidson', ehf + ecisd + eq) eq = ( 1.0 - c02 ) / c02 * ecisd print_energy('CISD(Q) Renomalized-Davidson', ehf + ecisd + eq) eq = ( 1.0 - c02 ) / ( 2.0 * c02 - 1.0 ) * ecisd print_energy('CISD(Q) Davison-Silver', ehf + ecisd + eq) eq = (( 2.0 * c02 ) / ((2.0*c02-1.0)*(1.0 + np.sqrt(1.0 + (8.0*c02*(1.0-c02)) / ( ne * (2.0*c02-1.0)**2 )))) - 1.0 ) * ecisd print_energy('CISD(Q) PC', ehf + ecisd + eq) eq = ( 1.0 - c02 ) / c02 * ((ne-2)*(ne-3.0)) / (ne*(ne-1.0)) * ecisd print_energy('CISD(Q) MC', ehf + ecisd + eq) if ne > 2: eq = ( 2.0 - c02 ) / (2.0 * (ne-1.0)/(ne-2.0) * c02 - 1.0) else: eq = 0.0 print_energy('CISD(Q) DD', ehf + ecisd + eq) # UKS elif method in ('uks' or 'udft'): inp.timer.start('uks') inp.timer.start('grids') grids = dft.gen_grid.Grids(mol) grids.level = inp.scf.grid grids.build() inp.timer.end('grids') mSCF = dft.UKS(mol) mSCF.grids = grids mSCF.xc = inp.scf.xc mSCF.conv_tol = inp.scf.conv mSCF.conv_tol_grad = inp.scf.grad mSCF.max_cycle = inp.scf.maxiter mSCF.init_guess = inp.scf.guess mSCF.small_rho_cutoff = 1e-20 eks = mSCF.kernel() print_energy('UKS', eks) inp.timer.end('uks') if inp.scf.exci is not None: inp.timer.start('TDDFT') mtd = do_TDDFT(inp, mSCF) inp.timer.end('TDDFT') # RKS elif method in ('rks', 'ks', 'rdft', 'dft'): inp.timer.start('ks') inp.timer.start('grids') grids = dft.gen_grid.Grids(mol) grids.level = inp.scf.grid grids.build() inp.timer.end('grids') if mol.nelectron%2 == 0: mSCF = dft.RKS(mol) else: mSCF = dft.ROKS(mol) mSCF.grids = grids mSCF.xc = inp.scf.xc mSCF.conv_tol = inp.scf.conv mSCF.conv_tol_grad = inp.scf.grad mSCF.max_cycle = inp.scf.maxiter mSCF.init_guess = inp.scf.guess mSCF.small_rho_cutoff = 1e-20 mSCF.damp = inp.scf.damp mSCF.level_shift = inp.scf.shift eks = mSCF.kernel() print_energy('RKS', eks) inp.timer.end('ks') if inp.scf.exci is not None: inp.timer.start('TDDFT') mtd = do_TDDFT(inp, mSCF) inp.timer.end('TDDFT') # Unrestricted FCI elif method == 'ufci': ehf, mSCF = do_hf(inp, unrestricted=True) print_energy('UHF', ehf) inp.timer.start('fci') cis = fci.direct_uhf.FCISolver(mol) norb = mSCF.mo_energy[0].size nea = (mol.nelectron+mol.spin) // 2 neb = (mol.nelectron-mol.spin) // 2 nelec = (nea, neb) mo_a = mSCF.mo_coeff[0] mo_b = mSCF.mo_coeff[1] h1e_a = reduce(np.dot, (mo_a.T, mSCF.get_hcore(), mo_a)) h1e_b = reduce(np.dot, (mo_b.T, mSCF.get_hcore(), mo_b)) g2e_aa = ao2mo.incore.general(mSCF._eri, (mo_a,)*4, compact=False) g2e_aa = g2e_aa.reshape(norb,norb,norb,norb) g2e_ab = ao2mo.incore.general(mSCF._eri, (mo_a,mo_a,mo_b,mo_b), compact=False) g2e_ab = g2e_ab.reshape(norb,norb,norb,norb) g2e_bb = ao2mo.incore.general(mSCF._eri, (mo_b,)*4, compact=False) g2e_bb = g2e_bb.reshape(norb,norb,norb,norb) h1e = (h1e_a, h1e_b) eri = (g2e_aa, g2e_ab, g2e_bb) eci = fci.direct_uhf.kernel(h1e, eri, norb, nelec)[0] print_energy('FCI', eci) inp.timer.end('fci') # FCI elif method in ('fci'): ehf, mSCF = do_hf(inp) print_energy('RHF', ehf) inp.timer.start('fci') if inp.scf.freeze is None: mCI = fci.FCI(mSCF) if inp.scf.roots is not None: mCI.nroots = inp.scf.roots mCI.kernel()[0] eci = mCI.eci else: nel = mol.nelectron - inp.scf.freeze * 2 ncas = mol.nao_nr() - inp.scf.freeze if mol.spin == 0: nelecas = nel mCI = mcscf.CASCI(mSCF, ncas, nelecas) mCI.fcisolver = fci.solver(mol) else: if mol.spin%2 == 0: nelecas = (nel//2+mol.spin//2, nel//2-mol.spin//2) else: nelecas = (nel//2+mol.spin//2+1, nel//2-mol.spin//2) mCI = mcscf.CASCI(mSCF, ncas, nelecas) mCI.fcisolver = fci.direct_spin1.FCISolver(mol) eci = mCI.kernel()[0] dm = mCI.make_rdm1() dip = mSCF.dip_moment(dm=dm) if inp.scf.roots is None: print_energy('FCI', eci) else: for i in range(inp.scf.roots): print_energy('FCI {0}'.format(i), eci[i]) inp.timer.end('fci') # CASCI elif method == 'casci': if inp.scf.cas is None and inp.scf.casorb is None: print ('ERROR: Must specify CAS space or CASORB') return inp ehf, mSCF = do_hf(inp) print_energy('RHF', ehf) # get cas space if inp.scf.cas is not None: if mol.spin == 0: nelecas = inp.scf.cas[0] else: nelecas = (inp.scf.cas[0]//2 + mol.spin//2, inp.scf.cas[0]//2 - mol.spin//2) ncasorb = inp.scf.cas[1] elif inp.scf.casorb is not None: ncasorb = len(inp.scf.casorb) nelecas = int(np.sum(mSCF.mo_occ[inp.scf.casorb])) if inp.scf.casspin is not None: nelecas = (nelecas//2 + inp.scf.casspin//2, nelecas//2 - inp.scf.casspin//2) inp.timer.start('casci') mCI = mcscf.CASCI(mSCF, ncasorb, nelecas) if inp.scf.casorb is not None: mo = mcscf.addons.sort_mo(mCI, np.copy(mSCF.mo_coeff), inp.scf.casorb, 0) else: mo = np.copy(mSCF.mo_coeff) eci = mCI.kernel(mo)[0] print_energy('CASCI', eci) inp.timer.end('casci') # CASSCF elif method == 'casscf' or method == 'ucasscf': if inp.scf.cas is None and inp.scf.casorb is None: print ('ERROR: Must specify CAS space or CASORB') return inp lunrestricted = (method == 'ucasscf') ehf, mSCF = do_hf(inp, unrestricted=lunrestricted) print_energy('HF', ehf) # get cas space if inp.scf.cas is not None: if mol.spin == 0: nelecas = inp.scf.cas[0] else: nelecas = (inp.scf.cas[0]//2 + mol.spin//2, inp.scf.cas[0]//2 - mol.spin//2) ncasorb = inp.scf.cas[1] elif inp.scf.casorb is not None: ncasorb = len(inp.scf.casorb) nelecas = int(np.sum(mSCF.mo_occ[inp.scf.casorb])) if inp.scf.casspin is not None: nelecas = (nelecas//2 + inp.scf.casspin//2, nelecas//2 - inp.scf.casspin//2) inp.timer.start('casscf') mCI = mcscf.CASSCF(mSCF, ncasorb, nelecas) if inp.scf.casorb is not None: mo = mcscf.addons.sort_mo(mCI, np.copy(mSCF.mo_coeff), inp.scf.casorb, 0) else: mo = np.copy(mSCF.mo_coeff) eci = mCI.kernel(mo)[0] print_energy('CASSCF', eci) inp.timer.end('casscf') # NEVPT2 elif method == 'nevpt2' or method == 'unevpt2': if inp.scf.cas is None and inp.scf.casorb is None: print ('ERROR: Must specify CAS space or CASORB') return inp ehf, mSCF = do_hf(inp) print_energy('RHF', ehf) inp.timer.start('casscf') # get cas space if inp.scf.cas is not None: if mol.spin == 0: nelecas = inp.scf.cas[0] else: nelecas = (inp.scf.cas[0]//2 + mol.spin//2, inp.scf.cas[0]//2 - mol.spin//2) ncasorb = inp.scf.cas[1] elif inp.scf.casorb is not None: ncasorb = len(inp.scf.casorb) nelecas = int(np.sum(mSCF.mo_occ[inp.scf.casorb])) if inp.scf.casspin is not None: nelecas = (nelecas//2 + inp.scf.casspin//2, nelecas//2 - inp.scf.casspin//2) mCI = mcscf.CASSCF(mSCF, ncasorb, nelecas, frozen=inp.scf.freeze) if inp.scf.casorb is not None: mo = mcscf.addons.sort_mo(mCI, np.copy(mSCF.mo_coeff), inp.scf.casorb, 0) else: mo = np.copy(mSCF.mo_coeff) eci = mCI.kernel(mo)[0] print_energy('CASSCF', eci) inp.timer.end('casscf') inp.timer.start('nevpt2') mpt2 = mrpt.NEVPT(mCI) ept2 = mpt2.kernel() + eci print_energy('NEVPT2', ept2) inp.timer.end('nevpt2') else: print ('ERROR: Unrecognized SCF method!') raise SystemExit # dump fcidump file if needed if inp.fcidump: if inp.filename[-4:].lower() == '.inp': fcifile = inp.filename[:-4] + '.fcidump' else: fcifile = inp.filename + '.fcidump' fcidump(mSCF, filename=fcifile, tol=1e-6) # plot MOs if needed if inp.mo2cube: from .mo_2_cube import save_MOs save_MOs(inp, mSCF, mSCF.mo_coeff) # save molden file if needed if inp.molden: from pyscf.tools import molden molden_file = inp.filename[:-4] + '.molden' molden.from_mo(inp.mol, molden_file, mSCF.mo_coeff, ene=mSCF.mo_energy) # save and return inp.mf = mSCF return inp
# Load MF orbitals # chkname = "_chk/pp_neutral_dz_b3lyp.chk" mol = chkfile.load_mol(chkname) mol.verbose = 5 mf = dft.RKS(mol) mf.__dict__.update(chkfile.load(chkname, "scf")) # # SA-MCSCF # nelecas, ncas = (4, 4) n_states = 3 weights = np.ones(n_states) / n_states mc = mcscf.CASSCF(mf, ncas, nelecas).state_average_(weights) mc.fix_spin(ss=0) mc.natorb = True mc.chkfile = "_chk/pp_neutral_dz_cas_4e_4o.chk" cas_list = [148, 149, 150, 151] mo = mcscf.sort_mo(mc, mf.mo_coeff, cas_list) mc.mc1step(mo) # # Analysis and processing # mc.analyze() molden.from_mo(mol, "_molden/pp_neutral_dz_cas_4e_4o_alt.molden", mc.mo_coeff) molden.from_mcscf(mc, "_molden/pp_neutral_dz_cas_4e_4o.molden")
cell.basis = 'gth-dzv' cell.pseudo = 'gth-pade' cell.verbose = 5 cell.build(unit='Angstrom') mf = scf.RHF(cell) mf.kernel() ''' generates IAOs ''' mo_occ = mf.mo_coeff[:, mf.mo_occ > 0] #a = lo.iao.iao(cell, mo_occ, minao='minao') #a = lo.iao.iao(cell, mo_occ, minao='gth-szv') a = iao.iao(cell, mo_occ, minao='gth-szv', scf_basis=True, ref_basis='gth-szv') # scf basis print "IAO shape: ", a.shape molden.from_mo(cell, 'diamondiao_szv.molden', a) # Orthogonalize IAO a = lo.vec_lowdin(a, mf.get_ovlp()) molden.from_mo(cell, 'diamondiao_szv_ortho.molden', a) loc_obj = lo.PM(cell, a) cost_before = loc_obj.cost_function() print "cost function before localization: ", cost_before loc_orb = loc_obj.kernel() molden.from_mo(cell, 'diamondiao_szv_PM.molden', loc_orb) #ibo must take the orthonormalized IAOs #ibo = lo.ibo.ibo(cell, mo_occ, a) #print "IBO shape: ", ibo.shape #molden.from_mo(cell, 'diamondibo_szv_ibo.molden', ibo)
def setup_wm_core_scf(self, fragments, calcname): self.restore_wm_full_scf() oneRDMcorr_loc = sum((frag.oneRDMas_loc for frag in fragments)) if np.all(np.isclose(oneRDMcorr_loc, 0)): print("Null correlated 1-RDM; default settings for wm wvfn") self.activeFOCK = represent_operator_in_basis( self.fullFOCKao, self.ao2loc) self.activeJKidem = self.activeFOCK - self.activeOEI self.activeJKcorr = np.zeros((self.norbs_tot, self.norbs_tot)) self.oneRDMcorr_loc = oneRDMcorr_loc self.loc2idem = np.eye(self.norbs_tot) self.nelec_idem = self.nelec_tot return loc2corr = np.concatenate([frag.loc2amo for frag in fragments], axis=1) loc2idem = get_complementary_states(loc2corr) evecs = matrix_eigen_control_options(represent_operator_in_basis( self.loc_oei(), loc2idem), sort_vecs=1, only_nonzero_vals=False)[1] loc2idem = np.dot(loc2idem, evecs) # I want to alter the outputs of self.loc_oei (), self.loc_rhf_fock (), and the get_wm_1RDM_etc () functions. # self.loc_oei () = P_idem * (activeOEI + JKcorr) * P_idem # self.loc_rhf_fock () = P_idem * (activeOEI + JKcorr + JKidem) * P_idem # The get_wm_1RDM_etc () functions will need to add oneRDMcorr_loc to their final return value # The chemical potential is so that identically zero eigenvalues from the projection into the idem space don't get confused # with numerically-zero eigenvalues in the idem space: all occupied orbitals must have negative energy # Make true output 1RDM from fragments to use as guess for wm mcscf calculation oneRDMguess_loc = np.zeros_like(oneRDMcorr_loc) for f in itertools.product(fragments, fragments): loc2frag = [i.loc2frag for i in f] oneRDMguess_loc += sum( (0.5 * project_operator_into_subspace(i.oneRDM_loc, *loc2frag) for i in f)) nelec_corr = np.trace(oneRDMcorr_loc) if is_close_to_integer(nelec_corr, 100 * params.num_zero_atol) == False: raise ValueError( "nelec_corr not an integer! {}".format(nelec_corr)) nelec_idem = int(round(self.nelec_tot - nelec_corr)) JKcorr = self.loc_rhf_jk_bis(oneRDMcorr_loc) oneRDMidem_loc = self.get_wm_1RDM_from_scf_on_OEI( self.loc_oei() + JKcorr, nelec=nelec_idem, loc2wrk=loc2idem, oneRDMguess_loc=oneRDMguess_loc, output=calcname + '_trial_wvfn.log') JKidem = self.loc_rhf_jk_bis(oneRDMidem_loc) print("trace of oneRDMcorr_loc = {}".format(np.trace(oneRDMcorr_loc))) print("trace of oneRDMidem_loc = {}".format(np.trace(oneRDMidem_loc))) print("trace of oneRDM_loc in corr basis = {}".format( np.trace( represent_operator_in_basis( oneRDMcorr_loc + oneRDMidem_loc, orthonormalize_a_basis(loc2corr))))) svals = get_overlapping_states(loc2idem, loc2corr)[2] print("trace of <idem|corr|idem> = {}".format(np.sum(svals * svals))) print(loc2corr.shape) print(loc2idem.shape) ######################################################################################################## self.activeFOCK = self.activeOEI + JKidem + JKcorr self.activeJKidem = JKidem self.activeJKcorr = JKcorr self.oneRDMcorr_loc = oneRDMcorr_loc self.loc2idem = loc2idem self.nelec_idem = nelec_idem ######################################################################################################## # Analysis: 1RDM and total energy print("Analyzing LASSCF trial wave function") oei = self.activeOEI + (JKcorr + JKidem) / 2 fock = self.activeFOCK oneRDM = oneRDMidem_loc + oneRDMcorr_loc E = self.activeCONST + np.tensordot(oei, oneRDM, axes=2) for frag in fragments: if frag.norbs_as > 0: if frag.E2_cum == 0 and np.amax(np.abs( frag.twoCDMimp_amo)) > 0: V = self.dmet_tei(frag.loc2amo) L = frag.twoCDMimp_amo frag.E2_cum = np.tensordot(V, L, axes=4) / 2 E += frag.E2_cum print("LASSCF trial wave function total energy: {:.6f}".format(E)) self.oneRDM_loc = oneRDM self.e_tot = E # Molden fock_idem = represent_operator_in_basis(fock, loc2idem) oneRDM_corr = represent_operator_in_basis(oneRDM, loc2corr) idem_evecs = matrix_eigen_control_options(fock_idem, sort_vecs=1, only_nonzero_vals=False)[1] corr_evecs = matrix_eigen_control_options(oneRDM_corr, sort_vecs=-1, only_nonzero_vals=False)[1] loc2molden = np.append(np.dot(loc2idem, idem_evecs), np.dot(loc2corr, corr_evecs), axis=1) wm_ene = np.einsum('ip,ij,jp->p', loc2molden, fock, loc2molden) wm_ene[-loc2corr.shape[1]:] = 0 wm_occ = np.einsum('ip,ij,jp->p', loc2molden, oneRDM, loc2molden) ao2molden = np.dot(self.ao2loc, loc2molden) molden.from_mo(self.mol, calcname + '_trial_wvfn.molden', ao2molden, occ=wm_occ, ene=wm_ene)
C 3.8560 2.1213 0.1612 C 1.0888 2.4099 0.1396 C 3.0401 0.9977 0.0771 C 1.6565 1.1421 0.0663 H 3.9303 4.2734 0.3007 H 1.4582 4.5312 0.2815 H 4.9448 2.0077 0.1699 H 0.0000 2.5234 0.1311 H 3.4870 0.0000 0.0197 H 1.0145 0.2578 0.0000 ''', basis = 'cc-pvdz', symmetry = 1) mf = scf.RHF(mol) mf.kernel() # # First method is to explicit call the functions provided by molden.py # with open('C6H6mo.molden', 'w') as f1: molden.header(mol, f1) molden.orbital_coeff(mol, f1, mf.mo_coeff, ene=mf.mo_energy, occ=mf.mo_occ) # # Second method is to simply call from_mo function to write the orbitals # c_loc_orth = lo.orth.orth_ao(mol) molden.from_mo(mol, 'C6H6loc.molden', c_loc_orth)
def get_mo_from_h5(mol, h5fname, symmetry=None): ''' Get MO vectors for a pyscf molecule from an h5 file written by OpenMolcas Args: mol : instance gto.mole Must be in the same point group as the OpenMolcas calculation, or set the symmetry argument h5fname : str Path to an h5 file generated by OpenMolcas containing (at least) groups 'BASIS_FUNCTION_IDS', 'MO_OCCUPATIONS', 'MO_VECTORS', and 'MO_ENERGIES' and additionally 'DESYM_MATRIX' and 'DESYM_BASIS_FUNCTION_IDS' if symmetry is used. Kwargs: symmetry : str Point group of the calculation in OpenMolcas. If not provided, mol.groupname is used instead Returns: mo_coeff : ndarray of shape (nao_nr, nao_nr) ''' if symmetry is not None: mol = mol.copy() mol.build(symmetry=symmetry) nao = mol.nao_nr() with h5py.File(h5fname, 'r') as f: try: molcas_basids = f['DESYM_BASIS_FUNCTION_IDS'][()] molcas_usymm = f['DESYM_MATRIX'][()].reshape(nao, nao) except KeyError: assert (not mol.symmetry ), "Can't find desym_ data; mol.symmetry = {}".format( mol.symmetry) molcas_basids = f['BASIS_FUNCTION_IDS'][()] molcas_coeff = f['MO_VECTORS'][()] mo_energy = f['MO_ENERGIES'][()] mo_occ = f['MO_OCCUPATIONS'][()] idx_ao = [] for (c, n, l, m) in molcas_basids: # 0-index atom list in PySCF, 1-index atom list in Molcas c -= 1 # Actual principal quantum number in PySCF, 1-indexed list in Molcas n += l # l=1, ml=(-1,0,1) is (x,y,z) in PySCF, (y,z,x) in Molcas if l == 1: m = m - 2 if m > 0 else m + 1 idx_ao.append(mol.search_ao_nr(c, l, m, n)) idx_ao = np.argsort(np.asarray(idx_ao)) if mol.symmetry: # I have to figure out what order the Molcas irreps are in on the fly # because it seems to change depending on the xyz molcas_usymm = molcas_usymm[:, idx_ao] proj = np.stack([(np.dot(molcas_usymm, ir_coeff)**2).sum(1) for ir_coeff in mol.symm_orb], axis=0) errstr = ("Can't interpret h5 symmetry information; wrong mol? " " <mol.symm_orb|desym_matrix> =\n{}").format(proj) assert (np.allclose(np.amax(proj), 1)), errstr ix_irrep = np.argmax(proj, axis=0) uniq_idx = np.sort(np.unique(ix_irrep, return_index=True)[1]) uniq_idx = np.append(uniq_idx, len(ix_irrep)) nmo_irrep = [] for ix, i in enumerate(uniq_idx[:-1]): j = uniq_idx[ix + 1] assert (len(np.unique(ix_irrep[i:j])) == 1), errstr nmo_irrep.append(j - i) nmo_irrep = np.asarray(nmo_irrep) usymm_irrep_offset = np.cumsum(nmo_irrep) - nmo_irrep coeff_irrep_offset = np.cumsum(nmo_irrep**2) - nmo_irrep**2 mo_coeff = np.zeros((nao, nao), dtype=np.float_) for m_ir, usymm_off, coeff_off in zip(nmo_irrep, usymm_irrep_offset, coeff_irrep_offset): i, j = usymm_off, usymm_off + m_ir u, v = coeff_off, coeff_off + (m_ir**2) usymm = molcas_usymm[i:j, :].T coeff = molcas_coeff[u:v].reshape(m_ir, m_ir).T mo_coeff[:, i:j] = np.dot(usymm, coeff) else: assert (molcas_coeff.shape == ( nao**2, )), 'mo_vectors.shape = {} but {} AOs'.format( molcas_coeff.shape, nao) mo_coeff = molcas_coeff.reshape(nao, nao)[:, idx_ao].T # 'mergesort' keeps degenerate or active-space orbitals in the provided order! # idx_ene = np.argsort (mo_energy, kind='mergesort') # modified by Dayou: sort by mo_occ first, then mo_energy sort_key = np.min(mo_energy) * 100000 * mo_occ + mo_energy idx_ene = np.argsort(sort_key, kind='mergesort') mo_coeff = mo_coeff[:, idx_ene] mo_occ = mo_occ[idx_ene] mo_energy = mo_energy[idx_ene] if mol.verbose > logger.INFO: fname = str(mol.output)[:-4] + "_h5debug.molden" molden.from_mo(mol, fname, mo_coeff, occ=mo_occ, ene=mo_energy) if mol.symmetry: # assert (symmetry is right) try: orbsym = label_orb_symm(mol, mol.irrep_name, mol.symm_orb, mo_coeff) except ValueError as e: raise ValueError(("Problem understanding Molcas symmetry?\n" "{}").format(str(e))) return mo_coeff
''' # # Modify the default core valence settings for Be and Al # # 1 s-shell as core, 1 s-shell + 1 p-shell as valence lo.set_atom_conf('Be', ('1s', '1s1p')) # 2 s-shells + 1 p-shell as core, 1 s-shell + 1 p-shell + 1 d-shell as valence lo.set_atom_conf('Al', ('2s1p', '1s1p1d')) # double-d shell for Fe, ie taking 3d and 4d orbitals as valence lo.set_atom_conf('Fe', 'double d') # double-d shell for Mo, ie taking 4d and 5d orbitals as valence lo.set_atom_conf('Mo', 'double d') # Put 3d orbital in valence space for Si lo.set_atom_conf('Si', 'polarize') # # Localize Be12 ring # mol = gto.M(atom = [('Be', x) for x in ring.make(12, 2.4)], basis='ccpvtz') c = lo.orth.orth_ao(mol) molden.from_mo(mol, 'be12.molden', c) # # Localize Al12 ring # mol = gto.M(atom = [('Al', x) for x in ring.make(12, 2.4)], basis='ccpvtz') c = lo.orth.orth_ao(mol) molden.from_mo(mol, 'al12.molden', c)
C -1.523996730 -0.592207689 0.138683275 H 0.609941801 0.564304456 1.384183068 H 1.228991034 1.489024155 0.015946420 H -1.242251083 1.542928348 0.046243898 H -0.662968178 0.676527364 -1.376503770 H -0.838473936 -1.344174292 0.500629028 H -2.075136399 -0.983173387 -0.703807608 H -2.212637905 -0.323898759 0.926200671 O 1.368219958 -0.565620846 -0.173113101 H 2.250134219 -0.596689848 0.204857736 ''' mol.basis = 'def2-SVP' mol.build() # Perform a Hartree-Fock calculation mf = RHF(mol) mf.kernel() # determine the number of occupied orbitals nocc = numpy.count_nonzero(mf.mo_occ > 0) # localize the occupied orbitals separately lmo_occ = cholesky_mos(mf.mo_coeff[:, :nocc]) # localize the virtual orbitals separately lmo_virt = cholesky_mos(mf.mo_coeff[:, nocc:]) # merge the MO coefficients in one matrix lmo_merged = numpy.hstack((lmo_occ, lmo_virt)) # dump the merged MO coefficients in a molden file filename = 'c3h7oh_cholesky.molden' print('Dumping the orbitals in file:', filename) molden.from_mo(mol, filename, lmo_merged, occ=mf.mo_occ)
C -1.211265339156 0.699329968382 0.000000000000 C -1.211265339156 -0.699329968382 0.000000000000 H 0.000000000000 2.491406946734 0.000000000000 H 0.000000000000 -2.491406946734 0.000000000000 H 2.157597486829 1.245660462400 0.000000000000 H 2.157597486829 -1.245660462400 0.000000000000 H -2.157597486829 1.245660462400 0.000000000000 H -2.157597486829 -1.245660462400 0.000000000000''', basis='6-31g') mf = scf.RHF(mol) mf.chkfile = 'benzene-631g.chk' mf.kernel() pz_idx = numpy.array([17, 20, 21, 22, 23, 30, 36, 41, 42, 47, 48, 49]) - 1 loc_orb = lo.Boys(mol, mf.mo_coeff[:, pz_idx]).kernel() molden.from_mo(mol, 'benzene-631g-boys.molden', loc_orb) import numpy from pyscf import lib from pyscf import tools from pyscf.tools import mo_mapping mol, mo_energy, mo_coeff, mo_occ, irrep_labels, spins = \ tools.molden.load('benzene-631g-boys.molden') comp = mo_mapping.mo_comps( 'C.*2p[yz]', # regular expression mol, mo_coeff) mol = lib.chkfile.load_mol('benzene-631g.chk')
print (si) # You can get the 1-RDMs of the SA-LASSCF states like this states_casdm1s = las.states_make_casdm1s () # You can get the 1- and 2-RDMs of the LASSI solutions like this roots_casdm1s, roots_casdm2s = lassi.roots_make_rdm12s (las, las.ci, si) # No super-convenient molden API yet # By default orbitals are state-averaged natural-orbitals at the end # of the SA-LASSCF calculation # But you can recanonicalize print ("\nlasscf_state_0-3.molden: single LAS state NOs, (strictly) unentangled") for iroot, dm1 in enumerate (states_casdm1s.sum (1)): # spin sum no_coeff, no_ene, no_occ = las.canonicalize (natorb_casdm1=dm1)[:3] molden.from_mo (las.mol, 'lasscf_state_{}.molden'.format (iroot), no_coeff, occ=no_occ, ene=no_ene) print ("lassi_root_0-3.molden: LASSI eigenstate NOs, (generally) entangled") for iroot, dm1 in enumerate (roots_casdm1s.sum (1)): # spin sum no_coeff, no_ene, no_occ = las.canonicalize (natorb_casdm1=dm1)[:3] molden.from_mo (las.mol, 'lassi_root_{}.molden'.format (iroot), no_coeff, occ=no_occ, ene=no_ene) # Beware! Don't do ~~~anything~~ to the si array before you pass it to the # function above or grab the important data from its attachments! print ("\nSurely I can type si = si * 1 without any consequences") si = si * 1 try: print ("<S**2>:",si.s2) except AttributeError as e: print ("Oh no! <S**2> disappeared and all I have now is this error message:") print ("AttributeError:", str (e))
from pyscf import lo from pyscf.tools import molden mol = gto.M( atom = ''' C 0.000000000000 1.398696930758 0.000000000000 C 0.000000000000 -1.398696930758 0.000000000000 C 1.211265339156 0.699329968382 0.000000000000 C 1.211265339156 -0.699329968382 0.000000000000 C -1.211265339156 0.699329968382 0.000000000000 C -1.211265339156 -0.699329968382 0.000000000000 H 0.000000000000 2.491406946734 0.000000000000 H 0.000000000000 -2.491406946734 0.000000000000 H 2.157597486829 1.245660462400 0.000000000000 H 2.157597486829 -1.245660462400 0.000000000000 H -2.157597486829 1.245660462400 0.000000000000 H -2.157597486829 -1.245660462400 0.000000000000''', basis = '6-31g') mf = scf.RHF(mol).run() pz_idx = numpy.array([17,20,21,22,23,30,36,41,42,47,48,49])-1 loc_orb = lo.Boys(mol, mf.mo_coeff[:,pz_idx]).kernel() molden.from_mo(mol, 'boys.molden', loc_orb) loc_orb = lo.ER(mol, mf.mo_coeff[:,pz_idx]).kernel() molden.from_mo(mol, 'edmiston.molden', loc_orb) loc_orb = lo.PM(mol, mf.mo_coeff[:,pz_idx]).kernel() molden.from_mo(mol, 'pm.molden', loc_orb)
# # Author: Qiming Sun <*****@*****.**> # ''' TDDFT NTO analysis. ''' from pyscf import gto, dft, tddft mol = gto.Mole() mol.build( atom = 'H 0 0 0; F 0 0 1.1', # in Angstrom basis = '631g', symmetry = True, ) mf = dft.RKS(mol) mf.xc = 'b3lyp' mf.kernel() mytd = tddft.TDDFT(mf) mytd.kernel() weights_1, nto_1 = mytd.get_nto(state=1, verbose=4) weights_2, nto_2 = mytd.get_nto(state=2, verbose=4) weights_3, nto_3 = mytd.get_nto(state=3, verbose=4) from pyscf.tools import molden molden.from_mo(mol, 'nto-td-3.molden', nto_3)
mf = scf.RHF(mol) mf.kernel() # # First method is to explicit call the functions provided by molden.py # with open("C6H6mo.molden", "w") as f1: molden.header(mol, f1) molden.orbital_coeff(mol, f1, mf.mo_coeff, ene=mf.mo_energy, occ=mf.mo_occ) # # Second method is to simply call from_mo function to write the orbitals # c_loc_orth = lo.orth.orth_ao(mol) molden.from_mo(mol, "C6H6loc.molden", c_loc_orth) # # Molden format does not support high angular momentum basis. To handle the # orbitals which have l>=5 functions, a hacky way is to call molden.remove_high_l # function. However, the resultant orbitals may not be orthnormal. # mol = gto.M(atom="He 0 0 0", basis={"He": gto.expand_etbs(((0, 3, 1.0, 2.0), (5, 2, 1.0, 2.0)))}) mf = scf.RHF(mol).run() try: molden.from_mo(mol, "He_without_h.molden", mf.mo_coeff) except RuntimeError: print(" Found l=5 in basis.") molden.from_mo(mol, "He_without_h.molden", mf.mo_coeff, ignore_h=True)
def setup_wm_core_scf(self, fragments, calcname): self.restore_wm_full_scf() oneRDMcorr_loc = sum((frag.oneRDMas_loc for frag in fragments)) oneSDMcorr_loc = sum((frag.oneSDMas_loc for frag in fragments)) if np.all(np.isclose(oneRDMcorr_loc, 0)): print("Null correlated 1-RDM; default settings for wm wvfn") self.oneRDMcorr_loc = oneRDMcorr_loc self.oneSDMcorr_loc = oneSDMcorr_loc return loc2corr = np.concatenate([frag.loc2amo for frag in fragments], axis=1) # Calculate E2_cum E2_cum = 0 for frag in fragments: if frag.norbs_as > 0: if frag.E2_cum == 0 and np.amax(np.abs( frag.twoCDMimp_amo)) > 0: V = self.dmet_tei(frag.loc2amo) L = frag.twoCDMimp_amo frag.E2_cum = np.tensordot(V, L, axes=4) / 2 K = self.loc_rhf_k_bis(frag.oneSDMas_loc) frag.E2_cum += (K * frag.oneSDMas_loc).sum() / 4 E2_cum += frag.E2_cum loc2idem = get_complementary_states(loc2corr) test, err = are_bases_orthogonal(loc2idem, loc2corr) print( "Testing linear algebra: overlap of active and unactive orbitals = {}" .format(linalg.norm(err))) # I want to alter the outputs of self.loc_oei (), self.loc_rhf_fock (), and the get_wm_1RDM_etc () functions. # self.loc_oei () = P_idem * (activeOEI + JKcorr) * P_idem # self.loc_rhf_fock () = P_idem * (activeOEI + JKcorr + JKidem) * P_idem # The get_wm_1RDM_etc () functions will need to add oneRDMcorr_loc to their final return value # The chemical potential is so that identically zero eigenvalues from the projection into the idem space don't get confused # with numerically-zero eigenvalues in the idem space: all occupied orbitals must have negative energy # Make true output 1RDM from fragments to use as guess for wm mcscf calculation oneRDMguess_loc = np.zeros_like(oneRDMcorr_loc) for f in itertools.product(fragments, fragments): loc2frag = [i.loc2frag for i in f] oneRDMguess_loc += sum( (0.5 * project_operator_into_subspace(i.oneRDM_loc, *loc2frag) for i in f)) nelec_corr = np.trace(oneRDMcorr_loc) if is_close_to_integer(nelec_corr, 100 * params.num_zero_atol) == False: raise ValueError( "nelec_corr not an integer! {}".format(nelec_corr)) nelec_idem = int(round(self.nelec_tot - nelec_corr)) if nelec_idem % 2: raise NotImplementedError("Odd % of unactive electrons") JKcorr = self.loc_rhf_jk_bis(oneRDMcorr_loc) oei = self.activeOEI + JKcorr / 2 vk = -self.loc_rhf_k_bis(oneSDMcorr_loc) / 2 working_const = self.activeCONST + (oei * oneRDMcorr_loc).sum() + ( vk * oneSDMcorr_loc).sum() / 2 + E2_cum oneRDMidem_loc = self.get_wm_1RDM_from_scf_on_OEI( self.loc_oei() + JKcorr, nelec=nelec_idem, loc2wrk=loc2idem, oneRDMguess_loc=oneRDMguess_loc, output=calcname + '_trial_wvfn.log', working_const=working_const) JKidem = self.loc_rhf_jk_bis(oneRDMidem_loc) print("trace of oneRDMcorr_loc = {}".format(np.trace(oneRDMcorr_loc))) print("trace of oneRDMidem_loc = {}".format(np.trace(oneRDMidem_loc))) print("trace of oneSDMcorr_loc = {}".format(np.trace(oneSDMcorr_loc))) print("trace of oneRDM_loc in corr basis = {}".format( np.trace( represent_operator_in_basis(oneRDMcorr_loc + oneRDMidem_loc, loc2corr)))) svals = get_overlapping_states(loc2idem, loc2corr)[2] print("trace of <idem|corr|idem> = {}".format(np.sum(svals * svals))) print(loc2corr.shape) print(loc2idem.shape) dma_dmb = oneRDMidem_loc + oneRDMcorr_loc dma_dmb = [(dma_dmb + oneSDMcorr_loc) / 2, (dma_dmb - oneSDMcorr_loc) / 2] focka_fockb = [JKcorr + vk, JKcorr - vk] focka_fockb = [self.activeOEI + JKidem + JK for JK in focka_fockb] oneRDM_loc = oneRDMidem_loc + oneRDMcorr_loc oneSDM_loc = oneSDMcorr_loc ######################################################################################################## self.activeFOCK = get_roothaan_fock(focka_fockb, dma_dmb, np.eye(self.norbs_tot)) self.activeJKidem = JKidem self.activeJKcorr = JKcorr self.oneRDMcorr_loc = oneRDMcorr_loc self.loc2idem = loc2idem self.nelec_idem = nelec_idem self.oneRDM_loc = oneRDM_loc self.oneSDM_loc = oneSDM_loc ######################################################################################################## # Analysis: 1RDM and total energy print("Analyzing LASSCF trial wave function") jk = np.stack([JKcorr + JKidem, -self.loc_rhf_k_bis(oneSDM_loc) / 2], axis=0) dm = np.stack([oneRDM_loc, oneSDM_loc], axis=0) E = self.activeCONST + ( self.activeOEI * oneRDM_loc).sum() + (jk * dm).sum() / 2 + E2_cum print("LASSCF trial wave function total energy: {:.6f}".format(E)) self.e_tot = E # Molden ao2molden, ene_no, occ_no = self.get_trial_nos(aobasis=True, loc2wmas=loc2corr, oneRDM_loc=oneRDM_loc, fock=self.activeFOCK, jmol_shift=True, try_symmetrize=True) print("Writing trial wave function molden") molden.from_mo(self.mol, calcname + '_trial_wvfn.molden', ao2molden, occ=occ_no, ene=ene_no)