diff --git a/examples/mcscf/18-o2_spatial_spin_symmetry.py b/examples/mcscf/18-o2_spatial_spin_symmetry.py index 7363b36db4..94fda18d8e 100644 --- a/examples/mcscf/18-o2_spatial_spin_symmetry.py +++ b/examples/mcscf/18-o2_spatial_spin_symmetry.py @@ -7,42 +7,53 @@ from pyscf import gto, scf, mcscf, fci -# -# Starting from a triplet SCF calculation -# mol = gto.M(atom='O; O 1 1.2', basis='ccpvdz', spin=2, symmetry=1) mf = scf.RHF(mol).run() norb = 4 -nelec = 6 +nelec = 6 # leads to 4 alpha electrons and 2 beta electons due to spin=2 (Sz=1) mc = mcscf.CASSCF(mf, norb, nelec) try: mc.kernel() -except IndexError as e: +except RuntimeError as e: print('When symmetry is enabled, FCI solver optimize the wfn of A1g symmetry by default.') - print('In this CAS space, wfn of A1g symmetry does not exist. This leads to error') + print('In this CAS space, wfn of A1g (Sigma^+_g) symmetry for Sz=1 does not exist.') print(e) -# Ground state is A2g +# Target the ground state is A2g (Sigma^-_g) with Sz=0. +# Specify 3 alpha electrons and 3 beta electrons for CASSCF calculation. +# The Sz value for CASCI/CASSCF does not have to be the same to the mol.spin. +nelec = (3, 3) +mc = mcscf.CASSCF(mf, norb, nelec) mc.fcisolver.wfnsym = 'A2g' mc.kernel() - # -# Starting from a singlet SCF calculation +# Print out the largest CI coefficients # -# SCF calculation for singlet state does not converge if mol.symmetry is -# enabled. Starting from a symmetry-broken SCF initial guess, the CASSCF -# solver can converge to the solution with correct symmetry, with more -# iterations. -mol = gto.M(atom='O; O 1 1.2', basis='ccpvdz', spin=0) -mf = scf.RHF(mol).run() -nalpha = 4 -nbeta = 2 -mc = mcscf.CASSCF(mf, norb, (nalpha,nbeta)) -mc.kernel() +for c, deta, detb in fci.addons.large_ci(mc.ci, norb, nelec, tol=.01, return_strs=False): + print(deta.tolist(), detb.tolist(), c) # -# Print out the largest CI coefficients +# The default FCI solver utilize the D2h symmetry to mimic the cylindrical symmetry. +# It may incorrectly remove the initial guess of A2g symmetry with Sz=1 or Sz=-1 . +# direct_spin1_cyl_sym can be used to solve this problem. This module is +# designed for the cylindrical symmetry. By specifying the different Sz and +# wfnsym, the CASSCF can produce three degenerated results. # -for c, deta, detb in fci.addons.large_ci(mc.ci, norb, (nalpha, nbeta), - tol=.01, return_strs=False): - print(deta.tolist(), detb.tolist(), c) +from pyscf.fci import direct_spin1_cyl_sym +nelec = (4, 2) # Sz=1 +mc = mcscf.CASSCF(mf, norb, nelec) +mc.fcisolver = direct_spin1_cyl_sym.FCI(mol) +mc.fcisolver.wfnsym = 'A2g' +mc.kernel() + +nelec = (3, 3) # Sz=0 +mc = mcscf.CASSCF(mf, norb, nelec) +mc.fcisolver = direct_spin1_cyl_sym.FCI(mol) +mc.fcisolver.wfnsym = 'A2g' +mc.kernel() + +nelec = (2, 4) # Sz=-1 +mc = mcscf.CASSCF(mf, norb, nelec) +mc.fcisolver = direct_spin1_cyl_sym.FCI(mol) +mc.fcisolver.wfnsym = 'A2g' +mc.kernel() diff --git a/pyscf/fci/direct_spin1_symm.py b/pyscf/fci/direct_spin1_symm.py index ee10487b8f..81df538ba2 100644 --- a/pyscf/fci/direct_spin1_symm.py +++ b/pyscf/fci/direct_spin1_symm.py @@ -310,6 +310,13 @@ def get_init_guess_cyl_sym(norb, nelec, nroots, hdiag, orbsym, wfnsym=0): addra1, sign_a = _sv_associated_det(strsa[addra], degen_mapping) addrb1, sign_b = _sv_associated_det(strsb[addrb], degen_mapping) if wfnsym in (1, 4) and addra == addra1 and addrb == addrb1: + # Remove the A1 repr from initial guess. + # The product of two E reprs can produce A1, A2 and another E repr. + # addra == addra1 and addrb == addrb1 can be found in the A1 repr. + # However, this may also incorrectly remove the A2 repr, see the + # explanation in issue #2291. + # In this case, the direct_spin1_cyl_sym solver can be used to + # solve A2. See example mcscf/18-o2_spatial_spin_symmetry.py continue x = ca[:,None] * cb diff --git a/pyscf/fci/test/test_spin1_cyl_sym.py b/pyscf/fci/test/test_spin1_cyl_sym.py index 0648528e31..65d1efff82 100644 --- a/pyscf/fci/test/test_spin1_cyl_sym.py +++ b/pyscf/fci/test/test_spin1_cyl_sym.py @@ -221,6 +221,22 @@ def test_incomplete_orbsym(self): with self.assertRaises(lib.exceptions.PointGroupSymmetryError): sol.kernel(h1, h2, no, ne, orbsym=orbsym) + # issue 2291 + def test_triplet_degeneracy(self): + mol = gto.M(atom='O; O 1 1.2', basis='631g', spin=2, symmetry=1) + mf = mol.RHF().run() + + def casci(nelec): + norb = 4 + mc = mcscf.CASCI(mf, norb, nelec) + mc.fcisolver = direct_spin1_cyl_sym.FCI(mol) + mc.fcisolver.wfnsym = 'A2g' + mc.kernel() + return mc.e_tot + self.assertAlmostEqual(casci((4, 2)), -149.56827649707, 9) + self.assertAlmostEqual(casci((3, 3)), -149.56827649707, 9) + self.assertAlmostEqual(casci((2, 4)), -149.56827649707, 9) + if __name__ == "__main__": print("Full Tests for spin1-symm") unittest.main() diff --git a/pyscf/lib/mcscf/fci_contract.c b/pyscf/lib/mcscf/fci_contract.c index 045eb2fed9..7b94f04a9a 100644 --- a/pyscf/lib/mcscf/fci_contract.c +++ b/pyscf/lib/mcscf/fci_contract.c @@ -1003,7 +1003,7 @@ void FCIcontract_2e_cyl_sym(double *eris, double *ci0, double *ci1, strb_ir = IRREP_OF(strb_l, strb_g); mb = nbs[strb_ir]; } - if (nas[intera_ir] > 0 && nas[interb_ir] > 0 && + if (nas[intera_ir] > 0 && nbs[interb_ir] > 0 && (ma > 0 || mb > 0)) { // clinka for intera*ai -> stra. pick_link_by_irrep(clinka, linka+linka_loc[intera_ir], nas[intera_ir], nlinka, ai_ir);