def run(r, xc, ot_name, chkfile): r /= 2 mol = gto.M(atom=f'H 0 0 {r}; H 0 0 -{r}', basis='cc-pvtz', symmetry=False, verbose=0) mf = scf.RHF(mol) mf.kernel() mc = mcdcft.CASSCF(mf, xc, 2, 2, ot_name=ot_name, grids_level=6) mc.fcisolver = csf_solver(mol, smult=1) mc.chkfile = chkfile mc.kernel() mc.dump_mcdcft_chk(chkfile) return mc.e_tot
def get_mc_ref(mol, ri=False, sa2=False): mf = scf.RHF(mol) if ri: mf = mf.density_fit(auxbasis=df.aug_etb(mol)) mc = mcpdft.CASSCF(mf.run(), 'tPBE', 6, 6, grids_level=6) if sa2: fcisolvers = [csf_solver(mol, smult=((2 * i) + 1)) for i in (0, 1)] if mol.symmetry: fcisolvers[0].wfnsym = 'A1' fcisolvers[1].wfnsym = 'A2' mc = mc.state_average_mix_(fcisolvers, [0.5, 0.5]) ref = np.load('h2co_sa2_tpbe66_631g_grad_num.npy').reshape(2, 2, 4, 3)[int(ri)] else: ref = np.load('h2co_tpbe66_631g_grad_num.npy')[int(ri)] return mc.run(), ref
def get_init_guess (fci, norb, nelec, norb_f, h1, h2, nelec_f=None, smult_f=None): if nelec_f is None: nelec_f = _guess_nelec_f (fci, norb, nelec, norb_f, h1, h2) if smult_f is None: smult_f = [abs(n[0]-n[1])+1 for n in nelec_f] h2 = ao2mo.restore (1, h2, norb) i = 0 ci0_f = [] for no, ne, s in zip (norb_f, nelec_f, smult_f): j = i + no h1_i = h1[i:j,i:j] h2_i = h2[i:j,i:j,i:j,i:j] i = j csf = csf_solver (fci.mol, smult=s) hdiag = csf.make_hdiag_csf (h1_i, h2_i, no, ne) ci = csf.get_init_guess (no, ne, 1, hdiag)[0] ci = np.squeeze (fockspace.hilbert2fock (ci, no, ne)) ci0_f.append (ci) return ci0_f
print("eta = {:.2f} degrees".format(out_of_plane_angle(carts, 0, 2, 3, 1))) # Energy calculation at initial geometry h2co_casscf66_631g_xyz = '''C 0.534004 0.000000 0.000000 O -0.676110 0.000000 0.000000 H 1.102430 0.000000 0.920125 H 1.102430 0.000000 -0.920125''' mol = gto.M(atom=h2co_casscf66_631g_xyz, basis='6-31g', symmetry=False, verbose=logger.INFO, output='h2co_sa2_tpbe66_631g_opt0.log') mf = scf.RHF(mol).run() mc = mcpdft.CASSCF(mf, 'tPBE', 6, 6, grids_level=9) mc.fcisolver = csf_solver(mol, smult=1) mc.state_average_([0.5, 0.5]) mc.kernel() # Geometry optimization (my_call is optional; it just prints the geometry in internal coordinates every iteration) print("Initial geometry: ") h2co_geom_analysis(mol.atom_coords() * BOHR) print("Initial energy: {:.8e}".format(mc.e_states[0])) def my_call(env): carts = env['mol'].atom_coords() * BOHR h2co_geom_analysis(carts) conv_params = {
from mrh.my_pyscf.df.grad import dfsacasscf as casscf_grad from mrh.my_pyscf.grad import numeric as numeric_grad from mrh.my_pyscf.fci import csf_solver h2co_casscf66_631g_xyz = '''C 0.534004 0.000000 0.000000 O -0.676110 0.000000 0.000000 H 1.102430 0.000000 0.920125 H 1.102430 0.000000 -0.920125''' mol = gto.M(atom=h2co_casscf66_631g_xyz, basis='6-31g', symmetry=False, verbose=lib.logger.INFO, output='h2co_sa2_casscf66_631g_grad.log') mf_conv = scf.RHF(mol).run() mc_conv = mcscf.CASSCF(mf_conv, 6, 6) mc_conv.fcisolver = csf_solver(mol, smult=1) mc_conv = mc_conv.state_average_([0.5, 0.5]) mc_conv.conv_tol = 1e-10 mc_conv.kernel() mf = scf.RHF(mol).density_fit(auxbasis=df.aug_etb(mol)).run() mc = mcscf.CASSCF(mf, 6, 6) mc.fcisolver = csf_solver(mol, smult=1) mc = mc.state_average_([0.5, 0.5]) mc.conv_tol = 1e-10 mc.kernel() numgrad_conv = numeric_grad.Gradients(mc_conv).run() print("First state") de_conv = mc_conv.nuc_grad_method().kernel(state=0) print("Conventional ERI analytic:\n", de_conv)
from mrh.my_pyscf.fci import csf_solver import unittest Natom = scf.RHF( gto.M(atom='N 0 0 0', basis='cc-pvtz', spin=3, symmetry='Dooh', output='/dev/null')).run() Beatom = scf.RHF( gto.M(atom='Be 0 0 0', basis='cc-pvtz', spin=2, symmetry=False, output='/dev/null')).run() Natom_hs = mcscf.CASSCF(Natom, 4, (4, 1)).set(fcisolver=csf_solver(Natom.mol, smult=4), conv_tol=1e-10).run() Natom_ls = mcscf.CASSCF(Natom, 4, (3, 2)).set(fcisolver=csf_solver(Natom.mol, smult=2), conv_tol=1e-10).run() Beatom_ls = mcscf.CASSCF(Beatom, 4, (1, 1)).set(fcisolver=csf_solver(Beatom.mol, smult=1), conv_tol=1e-10).run() Beatom_hs = mcscf.CASSCF(Beatom, 4, (2, 0)).set(fcisolver=csf_solver(Beatom.mol, smult=3), conv_tol=1e-10).run() def get_gap(gs, es, fnal): e0 = mcpdft.CASSCF(gs._scf, fnal, gs.ncas, gs.nelecas, grids_level=9).set(fcisolver=gs.fcisolver,
conv_params = { 'convergence_energy': 1e-6, # Eh 'convergence_grms': 5.0e-5, # Eh/Bohr 'convergence_gmax': 7.5e-5, # Eh/Bohr 'convergence_drms': 1.0e-4, # Angstrom 'convergence_dmax': 1.5e-4, # Angstrom } h2co_casscf66_631g_xyz = '''C 0.534004 0.000000 0.000000 O -0.676110 0.000000 0.000000 H 1.102430 0.000000 0.920125 H 1.102430 0.000000 -0.920125''' mol = gto.M (atom = h2co_casscf66_631g_xyz, basis = '6-31g', symmetry = True, verbose = lib.logger.INFO, output = 'h2co_sa2_tpbe66_631g_symm_opt.log') mf_conv = scf.RHF (mol).run () mc_conv = mcpdft.CASSCF (mf_conv, 'tPBE', 6, 6, grids_level=6) fcisolvers = [csf_solver (mol, smult=1) for i in (0,1)] fcisolvers[0].wfnsym = 'A1' fcisolvers[1].wfnsym = 'A2' mc_conv = mc_conv.state_average_mix_(fcisolvers, [0.5,0.5]) mc_conv.conv_tol = 1e-10 mc_conv.kernel () mf = scf.RHF (mol).density_fit (auxbasis = df.aug_etb (mol)).run () mc_df = mcpdft.CASSCF (mf, 'tPBE', 6, 6, grids_level=6) fcisolvers = [csf_solver (mol, smult=1) for i in (0,1)] fcisolvers[0].wfnsym = 'A1' fcisolvers[1].wfnsym = 'A2' mc_df = mc_df.state_average_mix_(fcisolvers, [0.5,0.5]) mc_df.conv_tol = 1e-10 mc_df.kernel ()
import numpy as np from pyscf import gto, scf, mcscf, lib from mrh.my_pyscf.fci import csf_solver from mrh.exploratory.unitary_cc import uccsd_sym0 from mrh.exploratory.unitary_cc import uccsd_sym1 import unittest, math mol = gto.M (atom = 'H 0 0 0; H 1.5 0 0', basis='6-31g', verbose=0, output='/dev/null') rhf = scf.RHF (mol).run () uhf = scf.UHF (mol) dm_a, dm_b = uhf.get_init_guess () dm_b[:2,:2] = 0.0 uhf.kernel ((dm_a, dm_b)) fci = mcscf.CASSCF (rhf, 4, 2).set (fcisolver = csf_solver (mol, smult=1)).run () def tearDownModule(): global mol, rhf, uhf, fci mol.stdout.close () del mol, rhf, uhf, fci class KnownValues(unittest.TestCase): def test_sym0_uccs (self): np.random.seed (1) x0 = (1 - 2*np.random.rand (28))*math.pi/2 uccs = uccsd_sym0.UCCS (mol).run (x=x0) self.assertAlmostEqual (uhf.e_tot, uccs.e_tot, 6) def test_sym0_uccsd (self): uccsd = uccsd_sym0.UCCSD (mol).run () self.assertAlmostEqual (uccsd.e_tot, fci.e_tot, 6)
from mrh.my_pyscf.tools import molden as molden from mrh.my_pyscf.fci import csf_solver from mrh.my_pyscf.mcscf.lasscf_o0 import LASSCF from mrh.exploratory.citools.lasci_ominus1 import FCISolver as lasci from mrh.exploratory.unitary_cc.lasuccsd import FCISolver as lasucc from mrh.exploratory.citools import fockspace norb = 8 nelec = 8 norb_f = (4,4) nelec_f = ((2,2),(2,2)) mol = structure (0.0, 0.0, output='c4h6_equil_631g.log', verbose=logger.DEBUG) mf = scf.RHF (mol).run () # CASSCF (for orbital initialization) mc = mcscf.CASSCF (mf, norb, nelec).set (fcisolver = csf_solver (mol, smult=1)) mo_coeff = mc.sort_mo ([11,12,14,15,16,17,21,24]) mc.kernel (mo_coeff) mo_coeff = mc.mo_coeff.copy () # LASSCF (for comparison) las = LASSCF (mf, norb_f, nelec_f, spin_sub=(1,1)).set (mo_coeff=mo_coeff) mo_loc = las.localize_init_guess ([[0,1,2,3,4],[5,6,7,8,9]]) ncore, ncas, nmo = las.ncore, las.ncas, mo_coeff.shape[1] e_las = las.kernel (mo_loc)[0] #mo_loc = las.localize_init_guess ([[0,1,2,3,4],[5,6,7,8,9]], # freeze_cas_spaces=True) mo_loc = las.mo_coeff.copy () molden.from_lasscf (las, 'c4h6_equil_lasscf88_631g.molden') # CASCI (for comparison)
# code in this block will only execute if you run this python script as the # input directly: "python cmspdft3.py". from pyscf import scf from mrh.my_pyscf.tools import molden # My version is better for MC-SCF from mrh.my_pyscf.fci import csf_solver xyz = '''O 0.00000000 0.08111156 0.00000000 H 0.78620605 0.66349738 0.00000000 H -0.78620605 0.66349738 0.00000000''' mol = gto.M(atom=xyz, basis='sto-3g', symmetry=False, output='cmspdft3.log', verbose=lib.logger.DEBUG) mf = scf.RHF(mol).run() mc = mcpdft.CASSCF(mf, 'tPBE', 4, 4).set(fcisolver=csf_solver(mol, 1)) mc = mc.state_average([ 1.0 / 3, ] * 3).run() molden.from_sa_mcscf(mc, 'h2o_sapdft_sa.molden', cas_natorb=True) # ^ molden file with state-averaged NOs for i in range(3): fname = 'h2o_sapdft_ref{}.molden'.format(i) # ^ molden file with ith reference state NOs molden.from_sa_mcscf(mc, fname, state=i, cas_natorb=True) conv, E_int, ci_int = kernel(mc, 3) print("The iteration did{} converge".format((' not', '')[int(conv)])) print("The intermediate-state energies are", E_int) print(("Molden files with intermediate-state NOs are in " "h2o_sapdft_int?.molden"))
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
from mrh.exploratory.unitary_cc.lasuccsd import FCISolver as lasucc from mrh.exploratory.citools import fockspace norb = 8 nelec = 8 norb_f = (4, 4) nelec_f = ((2, 2), (2, 2)) mol = structure(3.0, 3.0, output='c4h6_stretched_631g.log', verbose=logger.DEBUG) mf = scf.RHF(mol).run() # CASSCF (for orbital initialization) mc = mcscf.CASSCF(mf, norb, nelec).set(fcisolver=csf_solver(mol, smult=1)).run() mo_coeff = mc.mo_coeff.copy() # LASSCF (for comparison) las = LASSCF(mf, norb_f, nelec_f, spin_sub=(1, 1)).set(mo_coeff=mo_coeff) mo_loc = las.localize_init_guess([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) ncore, ncas, nmo = las.ncore, las.ncas, mo_coeff.shape[1] e_las = las.kernel(mo_loc)[0] mo_loc = las.localize_init_guess([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]], freeze_cas_spaces=True) molden.from_lasscf(las, 'c4h6_stretched_lasscf88_631g.molden') # CASCI (for comparison) mc = mcscf.CASCI(mf, 8, 8).set(mo_coeff=mo_loc, fcisolver=csf_solver(mol, smult=1)).run() e_cas = mc.e_tot
import unittest from pyscf import gto, scf, mcscf, lib from mrh.my_pyscf.fci import csf_solver from mrh.my_pyscf.mcscf.addons import state_average_n_mix mol = gto.M(atom='O 0 0 0; H 1.145 0 0', basis='6-31g', symmetry=True, charge=-1, spin=0, verbose=0, output='/dev/null') mf = scf.RHF(mol).set(conv_tol=1e-10).run() mc = mcscf.CASSCF(mf, 8, 8).set(conv_tol=1e-10).run() anion = csf_solver(mol, smult=1) anion.wfnsym = 'A1' rad1 = csf_solver(mol, smult=2) rad1.spin = 1 rad1.charge = 1 rad1.wfnsym = 'E1x' rad2 = csf_solver(mol, smult=2) rad2.spin = 1 rad2.charge = 1 rad2.wfnsym = 'E1y' mc = state_average_n_mix(mc, [anion, rad1, rad2], [ 1.0 / 3.0, ] * 3)
import numpy as np from pyscf import lib, gto, scf, dft, fci, mcscf, df from pyscf.mcscf import newton_casscf from pyscf.mcscf.addons import state_average_mix from me2n2_struct import structure as struct from mrh.my_pyscf.mcscf.lasscf_testing import LASSCF from mrh.my_pyscf.fci import csf_solver r_nn = 3.0 mol = struct(3.0, '6-31g') mol.output = 'test_me2n2_sa.log' mol.verbose = lib.logger.DEBUG mol.build() mf = scf.RHF(mol).run() mc = state_average_mix(mcscf.CASSCF( mf, 4, 4), [csf_solver(mol, smult=m2 + 1).set(spin=m2) for m2 in (0, 2)], [0.5, 0.5]).run() mf_df = mf.density_fit(auxbasis=df.aug_etb(mol)).run() mc_df = state_average_mix(mcscf.CASSCF( mf_df, 4, 4), [csf_solver(mol, smult=m2 + 1).set(spin=m2) for m2 in (0, 2)], [0.5, 0.5]).run() def tearDownModule(): global mol, mf, mf_df, mc, mc_df mol.stdout.close() del mol, mf, mf_df, mc, mc_df class KnownValues(unittest.TestCase):
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