def test_derivatives(self): np.random.seed(1) las = LASSCF(mf, (4, ), (4, ), spin_sub=(1, )).set(max_cycle_macro=1, ah_level_shift=0).run() ugg = las.get_ugg() ci0_csf = np.random.rand(ugg.ncsf_sub[0][0]) ci0_csf /= np.linalg.norm(ci0_csf) ci0 = ugg.ci_transformers[0][0].vec_csf2det(ci0_csf) las_gorb, las_gci = las.get_grad(mo_coeff=mf.mo_coeff, ci=[[ci0]])[:2] las_grad = np.append(las_gorb, las_gci) las_hess = las.get_hop(ugg=ugg, mo_coeff=mf.mo_coeff, ci=[[ci0]]) self.assertAlmostEqual(lib.fp(las_grad), lib.fp(las_hess.get_grad()), 8) cas_grad, _, cas_hess, _ = newton_casscf.gen_g_hop( mc, mf.mo_coeff, ci0, mc.ao2mo(mf.mo_coeff)) _pack_ci, _unpack_ci = newton_casscf._pack_ci_get_H( mc, mf.mo_coeff, ci0)[-2:] def pack_cas(kappa, ci1): return np.append(mc.pack_uniq_var(kappa), _pack_ci(ci1)) def unpack_cas(x): return mc.unpack_uniq_var(x[:ugg.nvar_orb]), _unpack_ci( x[ugg.nvar_orb:]) def cas2las(y, mode='hx'): yorb, yci = unpack_cas(y) yc = yci[0].ravel().dot(ci0.ravel()) yci[0] -= yc * ci0 yorb *= (0.5 if mode == 'hx' else 1) return ugg.pack(yorb, [yci]) def las2cas(y, mode='x'): yorb, yci = ugg.unpack(y) yc = yci[0][0].ravel().dot(ci0.ravel()) yci[0][0] -= yc * ci0 yorb *= (0.5 if mode == 'x' else 1) return pack_cas(yorb, yci[0]) cas_grad = cas2las(cas_grad) self.assertAlmostEqual(lib.fp(las_grad), lib.fp(cas_grad), 8) x = np.random.rand(ugg.nvar_tot) # orb on input x_las = x.copy() x_las[ugg.nvar_orb:] = 0.0 x_cas = las2cas(x_las, mode='x') hx_las = las_hess._matvec(x_las) hx_cas = cas2las(cas_hess(x_cas), mode='x') self.assertAlmostEqual(lib.fp(hx_las), lib.fp(hx_cas), 8) # CI on input x_las = x.copy() x_las[:ugg.nvar_orb] = 0.0 x_cas = las2cas(x_las, mode='hx') hx_las = las_hess._matvec(x_las) hx_cas = cas2las(cas_hess(x_cas), mode='hx') self.assertAlmostEqual(lib.fp(hx_las), lib.fp(hx_cas), 8)
def test_derivatives (self): np.random.seed(1) las = LASSCF (mf, (4,), (4,), spin_sub=(1,)).set (max_cycle_macro=1, ah_level_shift=0) las.state_average_(weights=[0.5,0.5], charges=[0,0], spins=[0,2], smults=[1,3]).run () ugg = las.get_ugg () ci0_csf = [np.random.rand (ncsf) for ncsf in ugg.ncsf_sub[0]] ci0_csf = [c / np.linalg.norm (c) for c in ci0_csf] ci0 = [t.vec_csf2det (c) for t, c in zip (ugg.ci_transformers[0], ci0_csf)] las_gorb, las_gci = las.get_grad (mo_coeff=mf.mo_coeff, ci=[ci0])[:2] las_grad = np.append (las_gorb, las_gci) las_hess = las.get_hop (ugg=ugg, mo_coeff=mf.mo_coeff, ci=[ci0]) self.assertAlmostEqual (lib.fp (las_grad), lib.fp (las_hess.get_grad ()), 8) cas_grad, _, cas_hess, _ = newton_casscf.gen_g_hop (mc, mf.mo_coeff, ci0, mc.ao2mo (mf.mo_coeff)) _pack_ci, _unpack_ci = newton_casscf._pack_ci_get_H (mc, mf.mo_coeff, ci0)[-2:] def pack_cas (kappa, ci1): return np.append (mc.pack_uniq_var (kappa), _pack_ci (ci1)) def unpack_cas (x): return mc.unpack_uniq_var (x[:ugg.nvar_orb]), _unpack_ci (x[ugg.nvar_orb:]) def cas2las (y, mode='hx'): yorb, yci = unpack_cas (y) yci = [2 * (yc - c * c.ravel ().dot (yc.ravel ())) for c, yc in zip (ci0, yci)] yorb *= (0.5 if mode=='hx' else 1) return ugg.pack (yorb, [yci]) def las2cas (y, mode='x'): yorb, yci = ugg.unpack (y) yci = [yc - c * c.ravel ().dot (yc.ravel ()) for c, yc in zip (ci0, yci[0])] yorb *= (0.5 if mode=='x' else 1) return pack_cas (yorb, yci) cas_grad = cas2las (cas_grad) self.assertAlmostEqual (lib.fp (las_grad), lib.fp (cas_grad), 8) x = np.random.rand (ugg.nvar_tot) # orb on input x_las = x.copy () x_las[ugg.nvar_orb:] = 0.0 x_cas = las2cas (x_las, mode='x') hx_las = las_hess._matvec (x_las) hx_cas = cas2las (cas_hess (x_cas), mode='x') self.assertAlmostEqual (lib.fp (hx_las), lib.fp (hx_cas), 8) # CI on input x_las = x.copy () x_las[:ugg.nvar_orb] = 0.0 x_cas = las2cas (x_las, mode='hx') hx_las = las_hess._matvec (x_las) hx_cas = cas2las (cas_hess (x_cas), mode='hx') self.assertAlmostEqual (lib.fp (hx_las), lib.fp (hx_cas), 8)
import unittest import numpy as np from scipy import linalg from pyscf import lib, gto, scf, dft, fci, mcscf, df from pyscf.tools import molden from c2h4n4_struct import structure as struct from mrh.my_pyscf.mcscf.lasscf_o0 import LASSCF dr_nn = 2.0 mol = struct(dr_nn, dr_nn, '6-31g', symmetry=False) mol.verbose = lib.logger.DEBUG mol.output = '/dev/null' mol.spin = 0 mol.build() mf = scf.RHF(mol).run() las = LASSCF(mf, (4, 4), ((3, 1), (1, 3)), spin_sub=(3, 3)) las.max_cycle_macro = 1 las.kernel() las.mo_coeff = np.loadtxt('test_lasci_mo.dat') las.ci = [[np.loadtxt('test_lasci_ci0.dat')], [-np.loadtxt('test_lasci_ci1.dat').T]] ugg = las.get_ugg() h_op = las.get_hop(ugg=ugg) nmo, ncore, nocc = h_op.nmo, h_op.ncore, h_op.nocc np.random.seed(0) x = np.random.rand(ugg.nvar_tot) offs_ci1 = ugg.nvar_orb offs_ci2 = offs_ci1 + np.squeeze(ugg.ncsf_sub)[0] xorb, xci = ugg.unpack(x) xci0 = [[ np.zeros(16),
def test_af_df(self): las = LASSCF(mf_hs_df, (4, 4), ((4, 0), (0, 4)), spin_sub=(5, 5)) mo_coeff = las.localize_init_guess(frags) las.kernel(mo_coeff) self.assertAlmostEqual(las.e_tot, -295.4466638852035, 7)
def test_ferro_df(self): las = LASSCF(mf_hs_df, (4, 4), ((4, 0), (4, 0)), spin_sub=(5, 5)) mo_coeff = las.localize_init_guess(frags) las.kernel(mo_coeff) self.assertAlmostEqual(las.e_tot, mf_hs_df.e_tot, 7)
def test_dia_df(self): las = LASSCF(mf_df, (4, 4), (4, 4), spin_sub=(1, 1)) mo_coeff = las.localize_init_guess(frags) las.kernel(mo_coeff) self.assertAlmostEqual(las.e_tot, -295.44716017803967, 7)
def test_dia(self): las = LASSCF(mf, (4, 4), (4, 4), spin_sub=(1, 1)) mo_coeff = las.localize_init_guess(frags) las.kernel(mo_coeff) self.assertAlmostEqual(las.e_tot, -295.44779578419946, 7)
from scipy import linalg from pyscf import lib, gto, scf, dft, fci, mcscf, df from pyscf.tools import molden from c2h4n4_struct import structure as struct from mrh.my_pyscf.mcscf.lasscf_o0 import LASSCF from mrh.my_pyscf.mcscf.lassi import roots_make_rdm12s, make_stdm12s, ham_2q dr_nn = 2.0 mol = struct (dr_nn, dr_nn, '6-31g', symmetry='Cs') mol.verbose = lib.logger.DEBUG mol.output = 'test_lassi_symm.log' mol.spin = 0 mol.symmetry = 'Cs' mol.build () mf = scf.RHF (mol).run () las = LASSCF (mf, (4,4), (4,4), spin_sub=(1,1)) las.state_average_(weights=[1.0/7.0,]*7, spins=[[0,0],[0,0],[2,-2],[-2,2],[0,0],[0,0],[2,2]], smults=[[1,1],[3,3],[3,3],[3,3],[1,1],[1,1],[3,3]], wfnsyms=[['A\'','A\''],]*4+[['A"','A\''],['A\'','A"'],['A\'','A\'']]) las.frozen = list (range (las.mo_coeff.shape[-1])) ugg = las.get_ugg () las.mo_coeff = las.label_symmetry_(np.loadtxt ('test_lassi_symm_mo.dat')) las.ci = ugg.unpack (np.loadtxt ('test_lassi_symm_ci.dat'))[1] #las.set (conv_tol_grad=1e-8).run () las.e_states = las.energy_nuc () + las.states_energy_elec () e_roots, si = las.lassi () rdm1s, rdm2s = roots_make_rdm12s (las, las.ci, si) def tearDownModule(): global mol, mf, las
lib.logger.TIMER_LEVEL = lib.logger.INFO mol = struct(3.0, 3.0, 'cc-pvtz', symmetry=False) mol.verbose = lib.logger.INFO mol.output = 'debug_tz_df_o0.log' mol.build() my_aux = df.aug_etb(mol) mf = scf.RHF(mol).density_fit(auxbasis=my_aux).run() # 1. Diamagnetic singlet ''' The constructor arguments are 1) SCF object 2) List or tuple of ncas for each fragment 3) List or tuple of nelec for each fragment A list or tuple of total-spin multiplicity is supplied in "spin_sub".''' las = LASSCF(mf, (4, 4), (4, 4), spin_sub=(1, 1)) ''' The class doesn't know anything about "fragments" at all. The active space is only "localized" provided one offers an initial guess for the active orbitals that is localized. That is the purpose of the localize_init_guess function. It requires a sequence of sequence of atom numbers, and it projects the orbitals in the ncore:nocc columns into the space of those atoms' AOs. The orbitals in the range ncore:ncore+ncas_sub[0] are the first active subspace, those in the range ncore+ncas_sub[0]:ncore+sum(ncas_sub[:2]) are the second active subspace, and so on.''' frag_atom_list = (list(range(3)), list(range(7, 10))) mo_coeff = las.localize_init_guess(frag_atom_list, mf.mo_coeff) ''' Right now, this function can only (roughly) reproduce the "force_imp=False, confine_guess=True" behavior of the old orbital guess builder. I might add the complement later,
def test_energy_hs_df(self): las = LASSCF(mf_hs_df, (4, ), ((4, 0), ), spin_sub=(5, )).set(conv_tol_grad=1e-5).run() self.assertAlmostEqual(las.e_tot, mf_hs_df.e_tot, 8)
def test_energy(self): las = LASSCF(mf, (4, ), (4, ), spin_sub=(1, )).set(conv_tol_grad=1e-5).run() self.assertAlmostEqual(las.e_tot, mc.e_tot, 8)
mol.verbose = lib.logger.INFO mol.build () mf = scf.RHF (mol).run () # SA-LASSCF object # The first positional argument of "state_average" is the orbital weighting function # Note that there are four states and two fragments and the weights sum to 1 # "Spins" is neleca - nelecb (= 2m for the sake of being an integer) # "Smults" is the desired local spin quantum *MULTIPLICITY* (2s+1) # "Wfnsyms" can also be the names of the irreps but I got lazy # "Charges" modifies the number of electrons in ncas_sub (third argument of LASSCF constructor) # For fragment i in state j: # neleca = (sum(las.ncas_sub[i]) - charges[j][i] + spins[j][i]) / 2 # nelecb = (sum(las.ncas_sub[i]) - charges[j][i] - spins[j][i]) / 2 # If your molecule doesn't have point-group symmetry turned on then don't pass "wfnsyms" las = LASSCF (mf, (5,5), ((3,2),(2,3))) las = las.state_average ([0.5,0.5,0.0,0.0], spins=[[1,-1],[-1,1],[0,0],[0,0]], smults=[[2,2],[2,2],[1,1],[1,1]], charges=[[0,0],[0,0],[-1,1],[1,-1]], wfnsyms=[[1,1],[1,1],[0,0],[0,0]]) mo_loc = las.localize_init_guess ((list (range (5)), list (range (5,10))), mf.mo_coeff) las.kernel (mo_loc) print ("\n---SA-LASSCF---") print ("Energy:", las.e_states) # For now, the LASSI diagonalizer is just a post-hoc function call # It returns eigenvalues (energies) in the first position and # eigenvectors (here, a 4-by-4 vector) e_roots, si = las.lassi ()
def test_energy_df (self): las = LASSCF (mf_df, (4,), (4,), spin_sub=(1,)).set (conv_tol_grad=1e-5) las.state_average_(weights=[0.5,0.5], charges=[0,0], spins=[0,2], smults=[1,3]).run () self.assertAlmostEqual (las.e_tot, mc_df.e_tot, 8) self.assertAlmostEqual (las.e_states[0], mc_df.e_states[0], 7) self.assertAlmostEqual (las.e_states[1], mc_df.e_states[1], 7)
import numpy as np from pyscf import gto, scf, tools from c2h6n4_struct import structure as struct from mrh.my_pyscf.mcscf.lasscf_o0 import LASSCF rnn0 = 1.23681571 mol = struct(3.0, 3.0, '6-31g', symmetry=False) mf = scf.RHF(mol).run() las = LASSCF(mf, (4, 4), (4, 4), spin_sub=(1, 1)) frag_atom_list = (list(range(3)), list(range(9, 12))) mo0 = las.localize_init_guess(frag_atom_list) las.kernel(mo0) las_scanner = las.as_scanner() pes = np.loadtxt('c2h6n4_pes_old.dat')[:34, :] pes = np.hstack((pes, np.zeros((34, 1)))) pes[33, 3] = las.e_tot # ISN'T THIS SO MUCH BETTER RIDDHISH????? for ix, dr_nn in enumerate(np.arange(2.9, -0.301, -0.1)): mol1 = struct(dr_nn, dr_nn, '6-31g', symmetry=False) pes[32 - ix, 3] = las_scanner(mol1) print(" r_NN {:>11s} {:>13s} {:>13s}".format("CASSCF", "vLASSCF(v1)", "vLASSCF(test)")) for row in pes: print(" {:5.3f} {:11.6f} {:13.8f} {:13.8f}".format(*row))
from mrh.my_pyscf.mcscf.lasscf_o0 import LASSCF mol = struct(3.0, 3.0, '6-31g', symmetry=False) mol.verbose = lib.logger.INFO mol.output = 'c2h4n4_spin.log' mol.build() mf = scf.RHF(mol).run() # 1. Diamagnetic singlet ''' The constructor arguments are 1) SCF object 2) List or tuple of ncas for each fragment 3) List or tuple of nelec for each fragment A list or tuple of total-spin multiplicity is supplied in "spin_sub".''' las = LASSCF(mf, (4, 4), (4, 4), spin_sub=(1, 1)) ''' The class doesn't know anything about "fragments" at all. The active space is only "localized" provided one offers an initial guess for the active orbitals that is localized. That is the purpose of the localize_init_guess function. It requires a sequence of sequence of atom numbers, and it projects the orbitals in the ncore:nocc columns into the space of those atoms' AOs. The orbitals in the range ncore:ncore+ncas_sub[0] are the first active subspace, those in the range ncore+ncas_sub[0]:ncore+sum(ncas_sub[:2]) are the second active subspace, and so on.''' frag_atom_list = (list(range(3)), list(range(7, 10))) mo_coeff = las.localize_init_guess(frag_atom_list, mf.mo_coeff) ''' Right now, this function can only (roughly) reproduce the "force_imp=False, confine_guess=True" behavior of the old orbital guess builder. I might add the complement later,
states7[field] = [[row[2], row[0], row[1]] for row in states5[field]] for d in [states1, states2, states3, states4, states5, states6, states7]: for field in ('charges', 'spins', 'smults', 'wfnsyms'): states[field] = states[field] + d[field] weights = [1.0,] + [0.0,]*56 nroots = 57 # End building crazy state list dr_nn = 2.0 mol = struct (dr_nn, dr_nn, '6-31g', symmetry='Cs') mol.verbose = lib.logger.INFO mol.output = 'test_lassi_op.log' mol.spin = 0 mol.build () mf = scf.RHF (mol).run () las = LASSCF (mf, (4,2,4), (4,2,4)) las.state_average_(weights=weights, **states) las.mo_coeff = las.localize_init_guess ((list (range (3)), list (range (3,7)), list (range (7,10))), mf.mo_coeff) las.ci = get_init_guess_ci (las, las.mo_coeff, las.get_h2eff (las.mo_coeff)) np.random.seed (1) for c in las.ci: for iroot in range (len (c)): c[iroot] = np.random.rand (*c[iroot].shape) c[iroot] /= linalg.norm (c[iroot]) orbsym = getattr (las.mo_coeff, 'orbsym', None) if orbsym is None and callable (getattr (las, 'label_symmetry_', None)): orbsym = las.label_symmetry_(las.mo_coeff).orbsym if orbsym is not None: orbsym = orbsym[las.ncore:las.ncore+las.ncas] wfnsym = 0
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) mc = mcscf.CASCI (mf, 8, 8).set (mo_coeff = mo_loc, fcisolver = csf_solver (mol, smult=1)).run () e_cas = mc.e_tot molden.from_mcscf (mc, 'c4h6_equil_casci88_631g.molden', cas_natorb=True) # LASUCCSD
import numpy as np from pyscf import gto, scf, mcscf from pyscf.fci import direct_spin1 from mrh.my_pyscf.mcscf.lasscf_o0 import LASSCF from mrh.exploratory.unitary_cc import lasuccsd from mrh.exploratory.citools import lasci_ominus1, fockspace import unittest xyz = '''H 0.0 0.0 0.0 H 1.0 0.0 0.0 H 0.2 3.9 0.1 H 1.159166 4.1 -0.1''' mol = gto.M (atom = xyz, basis = 'sto-3g', output='/dev/null', verbose=0) mf = scf.RHF (mol).run () ref = mcscf.CASSCF (mf, 4, 4).run () # = FCI las = LASSCF (mf, (2,2), (2,2), spin_sub=(1,1)) las.kernel (las.localize_init_guess (((0,1), (2,3)), mf.mo_coeff)) def tearDownModule(): global mol, mf, ref, las mol.stdout.close () del mol, mf, ref, las class KnownValues(unittest.TestCase): def test_lasci_ominus1 (self): mc = mcscf.CASCI (mf, 4, 4) mc.mo_coeff = las.mo_coeff mc.fcisolver = lasci_ominus1.FCISolver (mol) mc.fcisolver.norb_f = [2,2] mc.kernel ()
def __enter__(self): self.savedPath = os.getcwd() os.chdir(self.newPath) def __exit__(self, etype, value, traceback): os.chdir(self.savedPath) from mrh.examples.lasscf.c2h6n4.c2h6n4_struct import structure as struct with cd("/home/herme068/gits/mrh/examples/lasscf/c2h6n4"): mol = struct(2.0, 2.0, '6-31g', symmetry=False) mol.verbose = lib.logger.DEBUG mol.output = 'sa_lasscf_slow_ham.log' mol.build() mf = scf.RHF(mol).run() tol = 1e-6 if len(sys.argv) < 2 else float(sys.argv[1]) las = LASSCF(mf, (4, 4), (4, 4)).set(conv_tol_grad=tol) mo = las.localize_init_guess((list(range(3)), list(range(9, 12))), mo_coeff=mf.mo_coeff) las.state_average_(weights=[0.5, 0.5], spins=[[0, 0], [2, -2]]) h2eff_sub, veff = las.kernel(mo)[-2:] e_states = las.e_states ncore, ncas, nocc = las.ncore, las.ncas, las.ncore + las.ncas mo_coeff = las.mo_coeff mo_core = mo_coeff[:, :ncore] mo_cas = mo_coeff[:, ncore:nocc] e0 = las._scf.energy_nuc() + 2 * (( (las._scf.get_hcore() + veff.c / 2) @ mo_core) * mo_core).sum() h1 = mo_cas.conj().T @ (las._scf.get_hcore() + veff.c) @ mo_cas h2 = h2eff_sub[ncore:nocc].reshape(ncas * ncas, ncas * (ncas + 1) // 2) h2 = lib.numpy_helper.unpack_tril(h2).reshape(ncas, ncas, ncas, ncas)
import numpy as np from scipy import linalg from pyscf import lib, gto, scf, dft, fci, mcscf, df from pyscf.tools import molden from c2h4n4_struct import structure as struct from mrh.my_pyscf.mcscf.lasscf_o0 import LASSCF from mrh.my_pyscf.mcscf.lassi import roots_make_rdm12s, make_stdm12s, ham_2q dr_nn = 2.0 mol = struct(dr_nn, dr_nn, '6-31g', symmetry=False) mol.verbose = lib.logger.DEBUG mol.output = 'test_lassi.log' mol.spin = 0 mol.build() mf = scf.RHF(mol).run() las = LASSCF(mf, (4, 4), (4, 4), spin_sub=(1, 1)) las.state_average_(weights=[ 1.0 / 5.0, ] * 5, spins=[[0, 0], [0, 0], [2, -2], [-2, 2], [2, 2]], smults=[[1, 1], [3, 3], [3, 3], [3, 3], [3, 3]]) las.frozen = list(range(las.mo_coeff.shape[-1])) ugg = las.get_ugg() las.mo_coeff = np.loadtxt('test_lassi_mo.dat') las.ci = ugg.unpack(np.loadtxt('test_lassi_ci.dat'))[1] #las.set (conv_tol_grad=1e-8).run () #np.savetxt ('test_lassi_mo.dat', las.mo_coeff) #np.savetxt ('test_lassi_ci.dat', ugg.pack (las.mo_coeff, las.ci)) las.e_states = las.energy_nuc() + las.states_energy_elec() e_roots, si = las.lassi() rdm1s, rdm2s = roots_make_rdm12s(las, las.ci, si)