Repository: pyscf/pyscf — pull request #1426 (python)
Title: Fix EOM-EE RCCSD intermediates

* Fix EOM-EE RCCSD intermediates Fov
* Update spin2spatial and spatial2spin functions for various eom methods (issue #1208)

Resolved issues:
title: Spatial2Spin for EOM-RCCSD?
body: Hello,
I noticed that there are functions in [cc.addons](https://github.com/pyscf/pyscf/blob/1de8c145abb3e1a7392df9118e8062e6fe6bde00/pyscf/cc/addons.py#L19) and [eom_uccsd](https://github.com/pyscf/pyscf/blob/1de8c145abb3e1a7392df9118e8062e6fe6bde00/pyscf/cc/eom_uccsd.py#L78) for converting between spatial and spin orbital representations of coupled cluster amplitudes. The latter does not work with EOM-RCCSD amplitudes, at least out of the box. Is there a way one could hack it together to make it work? I know there is also EOM-GCCSD, which does things in the spin orbital representation, but it is quite a bit slower, and it would be nice to just make the conversion from EOM-RCCSD instead. Here is a snippet of my code:

```python
from pyscf import gto, scf, cc
from pyscf.cc import ccsd
from pyscf.cc.addons import spatial2spin,spin2spatial
from pyscf.cc.eom_uccsd import spatial2spin_ip,spatial2spin_ea

mol = gto.M(
            atom = '    N 0.0000000000 0.0000000000 0.548756750;\
            N 0.0000000000 0.0000000000 -0.548756750;',
            basis = 'cc-pvdz' )
mol.verbose = 4
mol.build()
mf = mol.RHF().run()

mycc = ccsd.CCSD(mf)
mycc.kernel()
t1 = mycc.t1
t2 = mycc.t2

t1_spin = spatial2spin(t1)
t2_spin = spatial2spin(t2)

nstates = 5
myeom = mycc.eomea_method()
e_r, r_eom = mycc.eaccsd(nroots=nstates)
e_l, l_eom = mycc.eaccsd(nroots=nstates,left=True)

r1,r2 = myeom.vector_to_amplitudes(r_eom[0],myeom.nmo,myeom.nocc)
#r1,r2 = spatial2spin_ea(r1,r2)
# yields ValueError: too many values to unpack (expected 2)
```



### Minimal API referenced by tests (typed signatures)
_Added only when tests call brand‑new symbols introduced by the fix; types reflect annotations present in the repo or `Unknown` if not annotated._

- Function in `pyscf/cc/eom_rccsd.py`: `def spatial2spin_eomsf(rx, orbspin) -> numpy.ndarray: ...`
  **Inputs:** rx: numpy.ndarray, orbspin: numpy.ndarray
  **Output:** numpy.ndarray

- Function in `pyscf/cc/eom_uccsd.py`: `def spatial2spin_eomsf(rx, orbspin) -> numpy.ndarray: ...`
  **Inputs:** rx: numpy.ndarray, orbspin: numpy.ndarray
  **Output:** numpy.ndarray

```python
def spatial2spin_eomsf(rx, orbspin) -> numpy.ndarray: ...
def spatial2spin_eomsf(rx, orbspin) -> numpy.ndarray: ...
```

Hints:

Fix patch:
diff --git a/pyscf/cc/addons.py b/pyscf/cc/addons.py
index 3869cd41cc..3c2c93fdc2 100644
--- a/pyscf/cc/addons.py
+++ b/pyscf/cc/addons.py
@@ -25,17 +25,20 @@ def spatial2spin(tx, orbspin=None):
         return spatial2spin((tx,tx), orbspin)
     elif isinstance(tx, numpy.ndarray) and tx.ndim == 4:
         # RCCSD t2 amplitudes
-        t2aa = tx - tx.transpose(0,1,3,2)
+        t2aa = tx - tx.transpose(1,0,2,3)
         return spatial2spin((t2aa,tx,t2aa), orbspin)
     elif len(tx) == 2:  # t1
         t1a, t1b = tx
         nocc_a, nvir_a = t1a.shape
         nocc_b, nvir_b = t1b.shape
-    else:
+    elif len(tx) == 3:  # t2
         t2aa, t2ab, t2bb = tx
         nocc_a, nocc_b, nvir_a, nvir_b = t2ab.shape
+    else:
+        raise RuntimeError('Unknown T amplitudes')
 
     if orbspin is None:
+        assert nocc_a == nocc_b
         orbspin = numpy.zeros((nocc_a+nvir_a)*2, dtype=int)
         orbspin[1::2] = 1
 
@@ -79,10 +82,14 @@ def spatial2spin(tx, orbspin=None):
 spatial2spinorb = spatial2spin
 
 def spin2spatial(tx, orbspin):
+    '''Convert T1/T2 in spin-orbital basis to T1/T2 in spatial orbital basis
+    '''
     if tx.ndim == 2:  # t1
         nocc, nvir = tx.shape
-    else:
+    elif tx.ndim == 4:
         nocc, nvir = tx.shape[1:3]
+    else:
+        raise RuntimeError('Unknown T amplitudes')
 
     idxoa = numpy.where(orbspin[:nocc] == 0)[0]
     idxob = numpy.where(orbspin[:nocc] == 1)[0]
diff --git a/pyscf/cc/eom_gccsd.py b/pyscf/cc/eom_gccsd.py
index 8bc85b83af..fab78ae266 100644
--- a/pyscf/cc/eom_gccsd.py
+++ b/pyscf/cc/eom_gccsd.py
@@ -17,7 +17,7 @@
 import numpy as np
 
 from pyscf import lib
-from pyscf.lib import logger
+from pyscf.lib import logger, module_method
 from pyscf.cc import ccsd
 from pyscf.cc import eom_rccsd
 from pyscf.cc import gccsd
@@ -46,7 +46,7 @@ def ipccsd_matvec(eom, vector, imds=None, diag=None):
     if imds is None: imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
-    r1, r2 = vector_to_amplitudes_ip(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     # Eq. (8)
     Hr1 = -np.einsum('mi,m->i', imds.Foo, r1)
@@ -62,7 +62,7 @@ def ipccsd_matvec(eom, vector, imds=None, diag=None):
     Hr2 += tmp2 - tmp2.transpose(1,0,2)
     Hr2 += 0.5*lib.einsum('mnef,mnf,ijae->ija', imds.Woovv, r2, imds.t2)
 
-    vector = amplitudes_to_vector_ip(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def lipccsd_matvec(eom, vector, imds=None, diag=None):
@@ -73,7 +73,7 @@ def lipccsd_matvec(eom, vector, imds=None, diag=None):
         imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
-    r1, r2 = vector_to_amplitudes_ip(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     Hr1 = -lib.einsum('mi,i->m', imds.Foo, r1)
     Hr1 += -0.5 * lib.einsum('maji,ija->m', imds.Wovoo, r2)
@@ -89,7 +89,7 @@ def lipccsd_matvec(eom, vector, imds=None, diag=None):
     Hr2 += (tmp2 - tmp2.transpose(1, 0, 2))
     Hr2 += 0.5 * lib.einsum('mnef,ija,ijae->mnf', imds.Woovv, r2, imds.t2)
 
-    vector = amplitudes_to_vector_ip(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def ipccsd_diag(eom, imds=None):
@@ -111,7 +111,7 @@ def ipccsd_diag(eom, imds=None):
                 Hr2[i,j,a] += 0.5*(np.dot(imds.Woovv[i,j,:,a], t2[i,j,a,:]) -
                                    np.dot(imds.Woovv[j,i,:,a], t2[i,j,a,:]))
 
-    vector = amplitudes_to_vector_ip(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def ipccsd_star_contract(eom, ipccsd_evals, ipccsd_evecs, lipccsd_evecs, imds=None):
@@ -145,14 +145,14 @@ def ipccsd_star_contract(eom, ipccsd_evals, ipccsd_evecs, lipccsd_evecs, imds=No
     foo = fock[:nocc, :nocc].diagonal()
     fvv = fock[nocc:, nocc:].diagonal()
 
-    oovv = _cp(eris.oovv)
-    ovvv = _cp(eris.ovvv)
-    ovov = _cp(eris.ovov)
-    #ovvo = -_cp(eris.ovov).transpose(0,1,3,2)
-    ooov = _cp(eris.ooov)
-    vooo = _cp(ooov).conj().transpose(3,2,1,0)
-    vvvo = _cp(ovvv).conj().transpose(3,2,1,0)
-    oooo = _cp(eris.oooo)
+    oovv = np.asarray(eris.oovv)
+    ovvv = np.asarray(eris.ovvv)
+    ovov = np.asarray(eris.ovov)
+    #ovvo = -np.asarray(eris.ovov).transpose(0,1,3,2)
+    ooov = np.asarray(eris.ooov)
+    vooo = np.asarray(ooov).conj().transpose(3,2,1,0)
+    vvvo = np.asarray(ovvv).conj().transpose(3,2,1,0)
+    oooo = np.asarray(eris.oooo)
 
     # Create denominator
     eijk = foo[:, None, None] + foo[None, :, None] + foo[None, None, :]
@@ -179,8 +179,8 @@ def pij(tmp):
     ipccsd_evals = np.atleast_1d(ipccsd_evals)
     for ip_eval, ip_evec, ip_levec in zip(ipccsd_evals, ipccsd_evecs, lipccsd_evecs):
         # Enforcing <L|R> = 1
-        l1, l2 = vector_to_amplitudes_ip(ip_levec, nmo, nocc)
-        r1, r2 = vector_to_amplitudes_ip(ip_evec, nmo, nocc)
+        l1, l2 = eom.vector_to_amplitudes(ip_levec, nmo, nocc)
+        r1, r2 = eom.vector_to_amplitudes(ip_evec, nmo, nocc)
         ldotr = np.dot(l1, r1) + 0.5 * np.dot(l2.ravel(), r2.ravel())
 
         logger.info(eom, 'Left-right amplitude overlap : %14.8e', ldotr)
@@ -229,13 +229,9 @@ class EOMIP(eom_rccsd.EOMIP):
     get_diag = ipccsd_diag
     ccsd_star_contract = ipccsd_star_contract
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_ip(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_ip(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_ip)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_ip,
+                                         absences=['nmo', 'nocc'])
 
     def vector_size(self):
         nocc = self.nocc
@@ -277,7 +273,7 @@ def eaccsd_matvec(eom, vector, imds=None, diag=None):
     if imds is None: imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
-    r1, r2 = vector_to_amplitudes_ea(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     # Eq. (30)
     Hr1  = np.einsum('ac,c->a', imds.Fvv, r1)
@@ -293,7 +289,7 @@ def eaccsd_matvec(eom, vector, imds=None, diag=None):
     Hr2 += 0.5*lib.einsum('abcd,jcd->jab', imds.Wvvvv, r2)
     Hr2 -= 0.5*lib.einsum('klcd,lcd,kjab->jab', imds.Woovv, r2, imds.t2)
 
-    vector = amplitudes_to_vector_ea(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def leaccsd_matvec(eom, vector, imds=None, diag=None):
@@ -305,7 +301,7 @@ def leaccsd_matvec(eom, vector, imds=None, diag=None):
         imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
-    r1, r2 = vector_to_amplitudes_ea(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     # Eq. (32)
     Hr1 = lib.einsum('ac,a->c',imds.Fvv,r1)
@@ -322,7 +318,7 @@ def leaccsd_matvec(eom, vector, imds=None, diag=None):
     Hr2 += 0.5*lib.einsum('abcd,jab->jcd',imds.Wvvvv,r2)
     Hr2 += -0.5*lib.einsum('klcd,jab,kjab->lcd',imds.Woovv,r2,imds.t2)
 
-    vector = amplitudes_to_vector_ea(Hr1,Hr2)
+    vector = eom.amplitudes_to_vector(Hr1,Hr2)
     return vector
 
 def eaccsd_diag(eom, imds=None):
@@ -345,7 +341,7 @@ def eaccsd_diag(eom, imds=None):
                 Hr2[j,a,b] -= 0.5*(np.dot(imds.Woovv[:,j,a,b], t2[:,j,a,b]) -
                                    np.dot(imds.Woovv[:,j,b,a], t2[:,j,a,b]))
 
-    vector = amplitudes_to_vector_ea(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def eaccsd_star_contract(eom, eaccsd_evals, eaccsd_evecs, leaccsd_evecs, imds=None):
@@ -374,14 +370,14 @@ def eaccsd_star_contract(eom, eaccsd_evals, eaccsd_evecs, leaccsd_evecs, imds=No
     foo = fock[:nocc, :nocc].diagonal()
     fvv = fock[nocc:, nocc:].diagonal()
 
-    vvvv = _cp(eris.vvvv)
-    oovv = _cp(eris.oovv)
-    ovvv = _cp(eris.ovvv)
-    ovov = _cp(eris.ovov)
-    #ovvo = -_cp(eris.ovov).transpose(0,1,3,2)
-    ooov = _cp(eris.ooov)
-    vooo = _cp(ooov).conj().transpose(3,2,1,0)
-    vvvo = _cp(ovvv).conj().transpose(3,2,1,0)
+    vvvv = np.asarray(eris.vvvv)
+    oovv = np.asarray(eris.oovv)
+    ovvv = np.asarray(eris.ovvv)
+    ovov = np.asarray(eris.ovov)
+    #ovvo = -np.asarray(eris.ovov).transpose(0,1,3,2)
+    ooov = np.asarray(eris.ooov)
+    vooo = np.asarray(ooov).conj().transpose(3,2,1,0)
+    vvvo = np.asarray(ovvv).conj().transpose(3,2,1,0)
 
     # Create denominator
     eabc = fvv[:, None, None] + fvv[None, :, None] + fvv[None, None, :]
@@ -408,8 +404,8 @@ def pab(tmp):
     eaccsd_evals = np.atleast_1d(eaccsd_evals)
     for ea_eval, ea_evec, ea_levec in zip(eaccsd_evals, eaccsd_evecs, leaccsd_evecs):
         # Enforcing <L|R> = 1
-        l1, l2 = vector_to_amplitudes_ea(ea_levec, nmo, nocc)
-        r1, r2 = vector_to_amplitudes_ea(ea_evec, nmo, nocc)
+        l1, l2 = eom.vector_to_amplitudes(ea_levec, nmo, nocc)
+        r1, r2 = eom.vector_to_amplitudes(ea_evec, nmo, nocc)
         ldotr = np.dot(l1, r1) + 0.5 * np.dot(l2.ravel(), r2.ravel())
 
         logger.info(eom, 'Left-right amplitude overlap : %14.8e', ldotr)
@@ -460,13 +456,9 @@ class EOMEA(eom_rccsd.EOMEA):
     get_diag = eaccsd_diag
     ccsd_star_contract = eaccsd_star_contract
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_ea(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_ea(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_ea)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_ea,
+                                         absences=['nmo', 'nocc'])
 
     def vector_size(self):
         nocc = self.nocc
@@ -500,7 +492,7 @@ def eeccsd_matvec(eom, vector, imds=None, diag=None):
     if imds is None: imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
-    r1, r2 = vector_to_amplitudes_ee(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     # Eq. (9)
     Hr1  = lib.einsum('ae,ie->ia', imds.Fvv, r1)
@@ -529,7 +521,7 @@ def eeccsd_matvec(eom, vector, imds=None, diag=None):
     Hr2 += 0.5*lib.einsum('mnij,mnab->ijab', imds.Woooo, r2)
     Hr2 += 0.5*lib.einsum('abef,ijef->ijab', imds.Wvvvv, r2)
 
-    vector = amplitudes_to_vector_ee(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def eeccsd_diag(eom, imds=None):
@@ -564,7 +556,7 @@ def eeccsd_diag(eom, imds=None):
         for j in range(i):
             Hr2[i,j,:,:] += 0.5*(imds.Woooo[i,j,i,j]-imds.Woooo[j,i,i,j])
 
-    vector = amplitudes_to_vector_ee(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 
@@ -596,13 +588,9 @@ def gen_matvec(self, imds=None, **kwargs):
         matvec = lambda xs: [self.matvec(x, imds) for x in xs]
         return matvec, diag
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_ee(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_ee(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_ee)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_ee,
+                                         absences=['nmo', 'nocc'])
 
     def vector_size(self):
         '''size of the vector based on spin-orbital basis'''
@@ -747,41 +735,3 @@ def make_ee(self):
         self.made_ee_imds = True
         logger.timer(self, 'EOM-CCSD EE intermediates', *cput0)
         return self
-
-def _cp(a):
-    return np.array(a, copy=False, order='C')
-
-if __name__ == '__main__':
-    from pyscf import scf
-    from pyscf import gto
-    from pyscf.cc import gccsd
-    mol = gto.Mole()
-    mol.atom = [
-        [8 , (0. , 0.     , 0.)],
-        [1 , (0. , -0.757 , 0.587)],
-        [1 , (0. , 0.757  , 0.587)]]
-    mol.basis = 'cc-pvdz'
-    mol.spin = 0
-    mol.build()
-    mf = scf.UHF(mol).run()
-    mf = scf.addons.convert_to_ghf(mf)
-
-    mycc = gccsd.GCCSD(mf)
-    ecc, t1, t2 = mycc.kernel()
-    print(ecc - -0.2133432712431435)
-    e,v = mycc.ipccsd(nroots=8)
-    print(e[0] - 0.4335604332073799)
-    print(e[2] - 0.5187659896045407)
-    print(e[4] - 0.6782876002229172)
-
-    #mycc.verbose = 5
-    e,v = mycc.eaccsd(nroots=8)
-    print(e[0] - 0.16737886338859731)
-    print(e[2] - 0.24027613852009164)
-    print(e[4] - 0.51006797826488071)
-
-    e,v = mycc.eeccsd(nroots=4)
-    print(e[0] - 0.2757159395886167)
-    print(e[1] - 0.2757159395886167)
-    print(e[2] - 0.2757159395886167)
-    print(e[3] - 0.3005716731825082)
diff --git a/pyscf/cc/eom_rccsd.py b/pyscf/cc/eom_rccsd.py
index 7a2467dd1a..b0cb3f2c1f 100644
--- a/pyscf/cc/eom_rccsd.py
+++ b/pyscf/cc/eom_rccsd.py
@@ -23,7 +23,7 @@
 
 from pyscf import lib
 from pyscf import ao2mo
-from pyscf.lib import logger
+from pyscf.lib import logger, module_method
 from pyscf.cc import ccsd
 from pyscf.cc import rintermediates as imd
 from pyscf import __config__
@@ -274,12 +274,22 @@ def amplitudes_to_vector_ip(r1, r2):
     vector = np.hstack((r1, r2.ravel()))
     return vector
 
+def spatial2spin_ip(rx, orbspin=None):
+    from pyscf.cc import eom_uccsd
+    if rx.ndim == 1:
+        r1 = (rx, np.zeros_like(rx))
+        return eom_uccsd.spatial2spin_ip(r1, orbspin)
+    else:
+        rx0 = np.zeros_like(rx)
+        r2 = (rx.transpose(1,0,2)-rx, rx0, -rx, rx0)
+        return eom_uccsd.spatial2spin_ip(r2, orbspin)
+
 def ipccsd_matvec(eom, vector, imds=None, diag=None):
     # Ref: Nooijen and Snijders, J. Chem. Phys. 102, 1681 (1995) Eqs.(8)-(9)
     if imds is None: imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
-    r1, r2 = vector_to_amplitudes_ip(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     # 1h-1h block
     Hr1 = -np.einsum('ki,k->i', imds.Loo, r1)
@@ -300,7 +310,7 @@ def ipccsd_matvec(eom, vector, imds=None, diag=None):
         Hr2 += -lib.einsum('ki,kjb->ijb', foo, r2)
         Hr2 += -lib.einsum('lj,ilb->ijb', foo, r2)
     elif eom.partition == 'full':
-        diag_matrix2 = vector_to_amplitudes_ip(diag, nmo, nocc)[1]
+        diag_matrix2 = eom.vector_to_amplitudes(diag, nmo, nocc)[1]
         Hr2 += diag_matrix2 * r2
     else:
         Hr2 += lib.einsum('bd,ijd->ijb', imds.Lvv, r2)
@@ -315,7 +325,7 @@ def ipccsd_matvec(eom, vector, imds=None, diag=None):
         tmp += -np.einsum('kldc,kld->c', imds.Woovv, r2)
         Hr2 += -np.einsum('c,ijcb->ijb', tmp, imds.t2)
 
-    vector = amplitudes_to_vector_ip(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def lipccsd_matvec(eom, vector, imds=None, diag=None):
@@ -327,7 +337,7 @@ def lipccsd_matvec(eom, vector, imds=None, diag=None):
     if imds is None: imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
-    r1, r2 = vector_to_amplitudes_ip(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     # 1h-1h block
     Hr1 = -np.einsum('ki,i->k', imds.Loo, r1)
@@ -347,7 +357,7 @@ def lipccsd_matvec(eom, vector, imds=None, diag=None):
         Hr2 += -lib.einsum('ki,ild->kld', foo, r2)
         Hr2 += -lib.einsum('lj,kjd->kld', foo, r2)
     elif eom.partition == 'full':
-        diag_matrix2 = vector_to_amplitudes_ip(diag, nmo, nocc)[1]
+        diag_matrix2 = eom.vector_to_amplitudes(diag, nmo, nocc)[1]
         Hr2 += diag_matrix2 * r2
     else:
         Hr2 += lib.einsum('bd,klb->kld', imds.Lvv, r2)
@@ -360,7 +370,7 @@ def lipccsd_matvec(eom, vector, imds=None, diag=None):
         tmp = np.einsum('ijcb,ijb->c', imds.t2, r2)
         Hr2 += -np.einsum('lkdc,c->kld', 2.*imds.Woovv-imds.Woovv.transpose(1,0,2,3), tmp)
 
-    vector = amplitudes_to_vector_ip(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def ipccsd_diag(eom, imds=None):
@@ -393,7 +403,7 @@ def ipccsd_diag(eom, imds=None):
                     Hr2[i,j,b] += -2*np.dot(imds.Woovv[j,i,b,:], t2[i,j,:,b])
                     Hr2[i,j,b] += np.dot(imds.Woovv[i,j,b,:], t2[i,j,:,b])
 
-    vector = amplitudes_to_vector_ip(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def ipccsd_star_contract(eom, ipccsd_evals, ipccsd_evecs, lipccsd_evecs, imds=None):
@@ -555,13 +565,10 @@ def gen_matvec(self, imds=None, left=False, **kwargs):
             matvec = lambda xs: [self.matvec(x, imds, diag) for x in xs]
         return matvec, diag
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_ip(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_ip(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_ip)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_ip,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_ip)
 
     def vector_size(self):
         nocc = self.nocc
@@ -619,13 +626,23 @@ def amplitudes_to_vector_ea(r1, r2):
     vector = np.hstack((r1, r2.ravel()))
     return vector
 
+def spatial2spin_ea(rx, orbspin=None):
+    from pyscf.cc import eom_uccsd
+    if rx.ndim == 1:
+        r1 = (rx, np.zeros_like(rx))
+        return eom_uccsd.spatial2spin_ea(r1, orbspin)
+    else:
+        rx0 = np.zeros_like(rx)
+        r2 = (rx-rx.transpose(0,2,1), rx0, rx, rx0)
+        return eom_uccsd.spatial2spin_ea(r2, orbspin)
+
 def eaccsd_matvec(eom, vector, imds=None, diag=None):
     # Ref: Nooijen and Bartlett, J. Chem. Phys. 102, 3629 (1995) Eqs.(30)-(31)
     if imds is None: imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
     nvir = nmo - nocc
-    r1, r2 = vector_to_amplitudes_ea(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     # Eq. (37)
     # 1p-1p block
@@ -646,7 +663,7 @@ def eaccsd_matvec(eom, vector, imds=None, diag=None):
         Hr2 +=  lib.einsum('bd,jad->jab', fvv, r2)
         Hr2 += -lib.einsum('lj,lab->jab', foo, r2)
     elif eom.partition == 'full':
-        diag_matrix2 = vector_to_amplitudes_ea(diag, nmo, nocc)[1]
+        diag_matrix2 = eom.vector_to_amplitudes(diag, nmo, nocc)[1]
         Hr2 += diag_matrix2 * r2
     else:
         Hr2 +=  lib.einsum('ac,jcb->jab', imds.Lvv, r2)
@@ -660,7 +677,7 @@ def eaccsd_matvec(eom, vector, imds=None, diag=None):
         tmp = np.einsum('klcd,lcd->k', 2.*imds.Woovv-imds.Woovv.transpose(0,1,3,2), r2)
         Hr2 += -np.einsum('k,kjab->jab', tmp, imds.t2)
 
-    vector = amplitudes_to_vector_ea(Hr1,Hr2)
+    vector = eom.amplitudes_to_vector(Hr1,Hr2)
     return vector
 
 def leaccsd_matvec(eom, vector, imds=None, diag=None):
@@ -672,7 +689,7 @@ def leaccsd_matvec(eom, vector, imds=None, diag=None):
     nocc = eom.nocc
     nmo = eom.nmo
     nvir = nmo - nocc
-    r1, r2 = vector_to_amplitudes_ea(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
 
     # Eq. (30)
     # 1p-1p block
@@ -693,7 +710,7 @@ def leaccsd_matvec(eom, vector, imds=None, diag=None):
         Hr2 += lib.einsum('lcb,bd->lcd', r2, fvv)
         Hr2 += -lib.einsum('jcd,lj->lcd', r2, foo)
     elif eom.partition == 'full':
-        diag_matrix2 = vector_to_amplitudes_ea(diag, nmo, nocc)[1]
+        diag_matrix2 = eom.vector_to_amplitudes(diag, nmo, nocc)[1]
         Hr2 += diag_matrix2 * r2
     else:
         Hr2 += lib.einsum('lad,ac->lcd', r2, imds.Lvv)
@@ -707,7 +724,7 @@ def leaccsd_matvec(eom, vector, imds=None, diag=None):
         tmp = np.einsum('ijcb,ibc->j', imds.t2, r2)
         Hr2 += -np.einsum('kjfe,j->kef', 2.*imds.Woovv-imds.Woovv.transpose(0,1,3,2),tmp)
 
-    vector = amplitudes_to_vector_ea(Hr1,Hr2)
+    vector = eom.amplitudes_to_vector(Hr1,Hr2)
     return vector
 
 def eaccsd_diag(eom, imds=None):
@@ -743,7 +760,7 @@ def eaccsd_diag(eom, imds=None):
                     Hr2[j,a,b] += -2*np.dot(imds.Woovv[:,j,a,b], t2[:,j,a,b])
                     Hr2[j,a,b] += np.dot(imds.Woovv[:,j,b,a], t2[:,j,a,b])
 
-    vector = amplitudes_to_vector_ea(Hr1,Hr2)
+    vector = eom.amplitudes_to_vector(Hr1,Hr2)
     return vector
 
 def eaccsd_star_contract(eom, eaccsd_evals, eaccsd_evecs, leaccsd_evecs, imds=None):
@@ -914,13 +931,10 @@ def gen_matvec(self, imds=None, left=False, **kwargs):
             matvec = lambda xs: [self.matvec(x, imds, diag) for x in xs]
         return matvec, diag
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_ea(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_ea(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_ea)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_ea,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_ea)
 
     def vector_size(self):
         nocc = self.nocc
@@ -1068,6 +1082,18 @@ def eomsf_ccsd(eom, nroots=1, koopmans=False, guess=None,
 vector_to_amplitudes_ee = vector_to_amplitudes_singlet = ccsd.vector_to_amplitudes
 amplitudes_to_vector_ee = amplitudes_to_vector_singlet = ccsd.amplitudes_to_vector
 
+def spatial2spin_singlet(rx, orbspin=None):
+    from pyscf.cc import eom_uccsd
+    if rx.ndim == 2:
+        r1a = rx * .5**.5
+        r1 = (r1a, r1a)
+        return eom_uccsd.spatial2spin_eomee(r1, orbspin)
+    else:
+        r2ab = rx * .5**.5
+        r2aa = r2ab - r2ab.transpose(1,0,2,3)
+        r2 = (r2aa, r2ab, r2aa)
+        return eom_uccsd.spatial2spin_eomee(r2, orbspin)
+
 def amplitudes_to_vector_eomsf(t1, t2, out=None):
     nocc, nvir = t1.shape
     t2baaa, t2aaba = t2
@@ -1102,6 +1128,16 @@ def vector_to_amplitudes_eomsf(vector, nmo, nocc):
     t2aaba = t2aaba.reshape(nocc,nocc,nvir,nvir)
     return t1, (t2baaa, t2aaba)
 
+def spatial2spin_eomsf(rx, orbspin=None):
+    from pyscf.cc import eom_uccsd
+    if isinstance(rx, np.ndarray) and rx.ndim == 2:
+        r1 = (rx, np.zeros_like(rx))
+        return eom_uccsd.spatial2spin_eomsf(r1, orbspin)
+    else:
+        rx0 = np.zeros_like(rx[0])
+        r2 = (rx0, rx[1], rx[0], rx0)
+        return eom_uccsd.spatial2spin_eomsf(r2, orbspin)
+
 def amplitudes_to_vector_triplet(t1, t2, out=None):
     t2aa, t2ab = t2
     dtype = np.result_type(t1, t2aa, t2ab)
@@ -1125,13 +1161,26 @@ def vector_to_amplitudes_triplet(vector, nmo, nocc):
     t2ab = t2ab.reshape(nocc,nvir,nocc,nvir).transpose(0,2,1,3).copy()
     return t1, (t2aa, t2ab)
 
+def spatial2spin_triplet(rx, orbspin=None):
+    from pyscf.cc import eom_uccsd
+    if isinstance(rx, np.ndarray) and rx.ndim == 2:
+        r1a = rx * .5**.5
+        r1 = (r1a, r1a)
+        return eom_uccsd.spatial2spin_eomee(r1, orbspin)
+    else:
+        r2ab = rx * .5**.5
+        r2aa, r2ab = rx
+        r2aa = r2ab - r2ab.transpose(1,0,2,3)
+        r2 = (r2aa, r2ab, -r2aa)
+        return eom_uccsd.spatial2spin_eomee(r2, orbspin)
+
 def eeccsd_matvec_singlet(eom, vector, imds=None):
     if imds is None: imds = eom.make_imds()
     nocc = eom.nocc
     nmo = eom.nmo
     nvir = nmo - nocc
 
-    r1, r2 = vector_to_amplitudes_singlet(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
     t1, t2, eris = imds.t1, imds.t2, imds.eris
     nocc, nvir = t1.shape
 
@@ -1219,7 +1268,7 @@ def eeccsd_matvec_singlet(eom, vector, imds=None):
     tau = tmp = eris_ovov = None
 
     Hr2 = Hr2 + Hr2.transpose(1,0,3,2)
-    vector = amplitudes_to_vector_ee(Hr1, Hr2)
+    vector = eom.amplitudes_to_vector(Hr1, Hr2)
     return vector
 
 def eeccsd_matvec_triplet(eom, vector, imds=None):
@@ -1228,7 +1277,7 @@ def eeccsd_matvec_triplet(eom, vector, imds=None):
     nmo = eom.nmo
     nvir = nmo - nocc
 
-    r1, r2 = vector_to_amplitudes_triplet(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
     r2aa, r2ab = r2
     t1, t2, eris = imds.t1, imds.t2, imds.eris
     nocc, nvir = t1.shape
@@ -1287,10 +1336,11 @@ def eeccsd_matvec_triplet(eom, vector, imds=None):
     Hr2ab += lib.einsum('MBEJ,iMEa->iJaB', woVVo, r2aa)
     Hr2ab += lib.einsum('MbeJ,iMeA->iJbA', woVVo, r2ab)
 
-    woVVo = woVVo + np.asarray(imds.woVvO)
+    woVvO = np.asarray(imds.woVvO)
+    wovvo = woVVo + woVvO
     theta = r2aa + r2ab
-    tmp = lib.einsum('mbej,imae->ijab', woVVo, theta)
-    woVVo = None
+    tmp = lib.einsum('mbej,imae->ijab', wovvo, theta)
+    woVVo = woVvO = wovvo = None
 
     woOoV = np.asarray(imds.woOoV)
     Hr1 -= lib.einsum('mnie,mnae->ia', woOoV, theta)
@@ -1344,7 +1394,7 @@ def eeccsd_matvec_triplet(eom, vector, imds=None):
     Hr2aa = Hr2aa - Hr2aa.transpose(0,1,3,2)
     Hr2aa = Hr2aa - Hr2aa.transpose(1,0,2,3)
     Hr2ab = Hr2ab - Hr2ab.transpose(1,0,3,2)
-    vector = amplitudes_to_vector_triplet(Hr1, (Hr2aa,Hr2ab))
+    vector = eom.amplitudes_to_vector(Hr1, (Hr2aa,Hr2ab))
     return vector
 
 def eeccsd_matvec_sf(eom, vector, imds=None):
@@ -1355,7 +1405,7 @@ def eeccsd_matvec_sf(eom, vector, imds=None):
     nvir = nmo - nocc
 
     t1, t2, eris = imds.t1, imds.t2, imds.eris
-    r1, r2 = vector_to_amplitudes_eomsf(vector, nmo, nocc)
+    r1, r2 = eom.vector_to_amplitudes(vector, nmo, nocc)
     r2baaa, r2aaba = r2
     nocc, nvir = t1.shape
 
@@ -1493,7 +1543,7 @@ def eeccsd_matvec_sf(eom, vector, imds=None):
 
     Hr2baaa = Hr2baaa - Hr2baaa.transpose(0,1,3,2)
     Hr2aaba = Hr2aaba - Hr2aaba.transpose(1,0,2,3)
-    vector = amplitudes_to_vector_eomsf(Hr1, (Hr2baaa,Hr2aaba))
+    vector = eom.amplitudes_to_vector(Hr1, (Hr2baaa,Hr2aaba))
     return vector
 
 def eeccsd_diag(eom, imds=None):
@@ -1655,13 +1705,10 @@ def gen_matvec(self, imds=None, diag=None, **kwargs):
         matvec = lambda xs: [self.matvec(x, imds) for x in xs]
         return matvec, diag
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_singlet(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_singlet(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_singlet)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_singlet,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_singlet)
 
     def vector_size(self):
         nocc = self.nocc
@@ -1681,13 +1728,10 @@ def gen_matvec(self, imds=None, diag=None, **kwargs):
         matvec = lambda xs: [self.matvec(x, imds) for x in xs]
         return matvec, diag
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_triplet(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_triplet(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_triplet)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_triplet,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_triplet)
 
     def vector_size(self):
         nocc = self.nocc
@@ -1707,13 +1751,10 @@ def gen_matvec(self, imds=None, diag=None, **kwargs):
         matvec = lambda xs: [self.matvec(x, imds) for x in xs]
         return matvec, diag
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_eomsf(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_eomsf(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_eomsf)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_eomsf,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_eomsf)
 
     def vector_size(self):
         nocc = self.nocc
@@ -1934,6 +1975,7 @@ def make_ee(self):
             self.woVvO[p0:p1] = woVvO
             self.woVVo[p0:p1] = woVVo
 
+        self.Fov += fov
         self.Foo += foo + 0.5*np.einsum('me,ie->mi', self.Fov+fov, t1)
         self.Fvv += fvv - 0.5*np.einsum('me,ma->ae', self.Fov+fov, t1)
 
@@ -2041,157 +2083,3 @@ def _make_tau(t2, t1, r1, fac=1, out=None):
     tau *= fac * .5
     tau += t2
     return tau
-
-def _cp(a):
-    return np.array(a, copy=False, order='C')
-
-
-if __name__ == '__main__':
-    from pyscf import scf
-    from pyscf import gto
-    from pyscf.cc import rccsd
-
-    mol = gto.Mole()
-    mol.atom = [
-        [8 , (0. , 0.     , 0.)],
-        [1 , (0. , -0.757 , 0.587)],
-        [1 , (0. , 0.757  , 0.587)]]
-    mol.basis = 'cc-pvdz'
-    mol.verbose = 0
-    mol.spin = 0
-    mol.build()
-    mf = scf.RHF(mol).run(conv_tol=1e-14)
-
-    mycc = rccsd.RCCSD(mf)
-    ecc, t1, t2 = mycc.kernel()
-    print(ecc - -0.21334326214236796)
-
-    myeom = EOMIP(mycc)
-    print("IP energies... (right eigenvector)")
-    e,v = ipccsd(myeom, nroots=3)
-    print(e[0] - 0.43356041409195489)
-    print(e[1] - 0.51876598058509493)
-    print(e[2] - 0.6782879569941862 )
-
-    print("IP energies... (left eigenvector)")
-    le,lv = ipccsd(myeom, nroots=3,left=True)
-    print(le[0] - 0.43356040428879794)
-    print(le[1] - 0.51876597800180335)
-    print(le[2] - 0.67828755013874864)
-
-    e = myeom.ipccsd_star_contract(e, v, lv)
-    print(e[0] - 0.43793202073189047)
-    print(e[1] - 0.52287073446559729)
-    print(e[2] - 0.67994597948852287)
-
-    myeom = EOMEA(mycc)
-    print("EA energies... (right eigenvector)")
-    e,v = eaccsd(myeom, nroots=3)
-    print(e[0] - 0.16737886282063008)
-    print(e[1] - 0.24027622989542635)
-    print(e[2] - 0.51006796667905585)
-
-    print("EA energies... (left eigenvector)")
-    le,lv = eaccsd(myeom, nroots=3, left=True)
-    print(le[0] - 0.16737896537079733)
-    print(le[1] - 0.24027634198123343)
-    print(le[2] - 0.51006809015066612)
-
-    e = myeom.eaccsd_star_contract(e,v,lv)
-    print(e[0] - 0.16656250953550664)
-    print(e[1] - 0.23944144521387614)
-    print(e[2] - 0.41399436888830721)
-
-    myeom = EOMEESpinFlip(mycc)
-    np.random.seed(1)
-    v = np.random.random(myeom.vector_size())
-    r1, r2 = vector_to_amplitudes_eomsf(v, myeom.nmo, myeom.nocc)
-    print(lib.finger(r1)    - 0.017703197938757409)
-    print(lib.finger(r2[0]) --21.605764517401415)
-    print(lib.finger(r2[1]) - 6.5857056438834842)
-    print(abs(amplitudes_to_vector_eomsf(r1, r2) - v).max())
-
-    myeom = EOMEE(mycc)
-    e,v = myeom.eeccsd(nroots=1)
-    print(e - 0.2757159395886167)
-
-    e,v = myeom.eeccsd(nroots=4)
-    print(e[0] - 0.2757159395886167)
-    print(e[1] - 0.2757159395886167)
-    print(e[2] - 0.2757159395886167)
-    print(e[3] - 0.3005716731825082)
-
-    e,v = myeom.eeccsd(nroots=4, koopmans=True)
-    print(e[0] - 0.2757159395886167)
-    print(e[1] - 0.2757159395886167)
-    print(e[2] - 0.2757159395886167)
-    print(e[3] - 0.3005716731825082)
-
-    e,v = myeom.eeccsd(nroots=4, guess=v[:4])
-    print(e[0] - 0.2757159395886167)
-    print(e[1] - 0.2757159395886167)
-    print(e[2] - 0.2757159395886167)
-    print(e[3] - 0.3005716731825082)
-
-
-    mycc = ccsd.CCSD(mf)
-    ecc, t1, t2 = mycc.kernel()
-    print(ecc - -0.21334326214236796)
-
-    myeom = EOMIP(mycc)
-    print("IP energies... (right eigenvector)")
-    e,v = ipccsd(myeom, nroots=3)
-    print(e[0] - 0.43356041409195489)
-    print(e[1] - 0.51876598058509493)
-    print(e[2] - 0.6782879569941862 )
-
-    print("IP energies... (left eigenvector)")
-    le,lv = ipccsd(myeom, nroots=3,left=True)
-    print(le[0] - 0.43356040428879794)
-    print(le[1] - 0.51876597800180335)
-    print(le[2] - 0.67828755013874864)
-
-    e = myeom.ipccsd_star_contract(e, v, lv)
-    print(e[0] - 0.43793202073189047)
-    print(e[1] - 0.52287073446559729)
-    print(e[2] - 0.67994597948852287)
-
-    myeom = EOMEA(mycc)
-    print("EA energies... (right eigenvector)")
-    e,v = eaccsd(myeom, nroots=3)
-    print(e[0] - 0.16737886282063008)
-    print(e[1] - 0.24027622989542635)
-    print(e[2] - 0.51006796667905585)
-
-    print("EA energies... (left eigenvector)")
-    le,lv = eaccsd(myeom, nroots=3, left=True)
-    print(le[0] - 0.16737896537079733)
-    print(le[1] - 0.24027634198123343)
-    print(le[2] - 0.51006809015066612)
-
-    e = myeom.eaccsd_star_contract(e,v,lv)
-    print(e[0] - 0.16656250953550664)
-    print(e[1] - 0.23944144521387614)
-    print(e[2] - 0.41399436888830721)
-
-    myeom = EOMEE(mycc)
-    e,v = myeom.eeccsd(nroots=1)
-    print(e - 0.2757159395886167)
-
-    e,v = myeom.eeccsd(nroots=4)
-    print(e[0] - 0.2757159395886167)
-    print(e[1] - 0.2757159395886167)
-    print(e[2] - 0.2757159395886167)
-    print(e[3] - 0.3005716731825082)
-
-    e,v = myeom.eeccsd(nroots=4, koopmans=True)
-    print(e[0] - 0.2757159395886167)
-    print(e[1] - 0.2757159395886167)
-    print(e[2] - 0.2757159395886167)
-    print(e[3] - 0.3005716731825082)
-
-    e,v = myeom.eeccsd(nroots=4, guess=v[:4])
-    print(e[0] - 0.2757159395886167)
-    print(e[1] - 0.2757159395886167)
-    print(e[2] - 0.2757159395886167)
-    print(e[3] - 0.3005716731825082)
diff --git a/pyscf/cc/eom_uccsd.py b/pyscf/cc/eom_uccsd.py
index d2870749a2..46ccde6491 100644
--- a/pyscf/cc/eom_uccsd.py
+++ b/pyscf/cc/eom_uccsd.py
@@ -25,10 +25,11 @@
 import numpy as np
 
 from pyscf import lib
-from pyscf.lib import logger
+from pyscf.lib import logger, module_method
 from pyscf import ao2mo
 from pyscf.cc import ccsd
 from pyscf.cc import uccsd
+from pyscf.cc import addons
 from pyscf.cc import eom_rccsd
 from pyscf.cc import uintermediates
 
@@ -75,16 +76,30 @@ def amplitudes_to_vector_ip(r1, r2):
                       r2aaa[idxa].ravel(), r2baa.ravel(),
                       r2abb.ravel(), r2bbb[idxb].ravel()))
 
-def spatial2spin_ip(r1, r2, orbspin=None):
-    '''Convert R1/R2 of spatial orbital representation to R1/R2 of
-    spin-orbital representation
-    '''
-    r1a, r1b = r1
-    r2aaa, r2baa, r2abb, r2bbb = r2
+def spatial2spin_ip(rx, orbspin=None):
+    '''Convert EOMIP spatial-orbital R1/R2 to spin-orbital R1/R2'''
+    if len(rx) == 2:  # r1
+        r1a, r1b = rx
+        nocc_a = r1a.size
+        nocc_b = r1b.size
+        nocc = nocc_a + nocc_b
+
+        r1 = np.zeros(nocc, dtype=r1a.dtype)
+        if orbspin is None:
+            assert nocc_a == nocc_b
+            r1[0::2] = r1a
+            r1[1::2] = r1b
+        else:
+            r1[orbspin[:nocc] == 0] = r1a
+            r1[orbspin[:nocc] == 1] = r1b
+        return r1
+
+    r2aaa, r2baa, r2abb, r2bbb = rx
     nocc_a, nvir_a = r2aaa.shape[1:]
     nocc_b, nvir_b = r2bbb.shape[1:]
 
     if orbspin is None:
+        assert nocc_a == nocc_b
         orbspin = np.zeros((nocc_a+nvir_a)*2, dtype=int)
         orbspin[1::2] = 1
 
@@ -95,10 +110,6 @@ def spatial2spin_ip(r1, r2, orbspin=None):
     idxva = np.where(orbspin[nocc:] == 0)[0]
     idxvb = np.where(orbspin[nocc:] == 1)[0]
 
-    r1 = np.zeros((nocc), dtype=r1a.dtype)
-    r1[idxoa] = r1a
-    r1[idxob] = r1b
-
     r2 = np.zeros((nocc**2, nvir), dtype=r2aaa.dtype)
     idxoaa = idxoa[:,None] * nocc + idxoa
     idxoab = idxoa[:,None] * nocc + idxob
@@ -120,10 +131,17 @@ def spatial2spin_ip(r1, r2, orbspin=None):
     r2bab = -r2abb
     lib.takebak_2d(r2, r2aba, idxoab.T.ravel(), idxva.ravel())
     lib.takebak_2d(r2, r2bab, idxoba.T.ravel(), idxvb.ravel())
-    return r1, r2.reshape(nocc, nocc, nvir)
+    return r2.reshape(nocc, nocc, nvir)
 
-def spin2spatial_ip(r1, r2, orbspin):
-    nocc, nvir = r2.shape[1:]
+def spin2spatial_ip(rx, orbspin):
+    '''Convert EOMIP spin-orbital R1/R2 to spatial-orbital R1/R2'''
+    if rx.ndim == 1:
+        nocc = rx.size
+        r1a = rx[orbspin[:nocc] == 0]
+        r1b = rx[orbspin[:nocc] == 1]
+        return r1a, r1b
+
+    nocc, nvir = rx.shape[1:]
 
     idxoa = np.where(orbspin[:nocc] == 0)[0]
     idxob = np.where(orbspin[:nocc] == 1)[0]
@@ -134,9 +152,6 @@ def spin2spatial_ip(r1, r2, orbspin):
     nvir_a = len(idxva)
     nvir_b = len(idxvb)
 
-    r1a = r1[idxoa]
-    r1b = r1[idxob]
-
     idxoaa = idxoa[:,None] * nocc + idxoa
     idxoab = idxoa[:,None] * nocc + idxob
     idxoba = idxob[:,None] * nocc + idxoa
@@ -146,7 +161,7 @@ def spin2spatial_ip(r1, r2, orbspin):
     #idxvba = idxvb[:,None] * nvir + idxva
     #idxvbb = idxvb[:,None] * nvir + idxvb
 
-    r2 = r2.reshape(nocc**2, nvir)
+    r2 = rx.reshape(nocc**2, nvir)
     r2aaa = lib.take_2d(r2, idxoaa.ravel(), idxva.ravel())
     r2baa = lib.take_2d(r2, idxoba.ravel(), idxva.ravel())
     r2abb = lib.take_2d(r2, idxoab.ravel(), idxvb.ravel())
@@ -156,7 +171,7 @@ def spin2spatial_ip(r1, r2, orbspin):
     r2baa = r2baa.reshape(nocc_b, nocc_a, nvir_a)
     r2abb = r2abb.reshape(nocc_a, nocc_b, nvir_b)
     r2bbb = r2bbb.reshape(nocc_b, nocc_b, nvir_b)
-    return [r1a, r1b], [r2aaa, r2baa, r2abb, r2bbb]
+    return r2aaa, r2baa, r2abb, r2bbb
 
 def ipccsd_matvec(eom, vector, imds=None, diag=None):
     '''For spin orbitals
@@ -168,7 +183,7 @@ def ipccsd_matvec(eom, vector, imds=None, diag=None):
     t2aa, t2ab, t2bb = t2
     nocca, noccb, nvira, nvirb = t2ab.shape
     nmoa, nmob = nocca+nvira, noccb+nvirb
-    r1, r2 = vector_to_amplitudes_ip(vector, (nmoa,nmob), (nocca,noccb))
+    r1, r2 = eom.vector_to_amplitudes(vector, (nmoa,nmob), (nocca,noccb))
     r1a, r1b = r1
     r2aaa, r2baa, r2abb, r2bbb = r2
 
@@ -329,13 +344,11 @@ def get_init_guess(self, nroots=1, koopmans=True, diag=None):
             guess.append(g)
         return guess
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_ip(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_ip(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_ip)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_ip,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_ip)
+    spin2spatial = staticmethod(spin2spatial_ip)
 
     def vector_size(self):
         '''size of the vector based on spin-orbital basis'''
@@ -393,16 +406,30 @@ def amplitudes_to_vector_ea(r1, r2):
                       r2aba.ravel(), r2bab.ravel(),
                       r2bbb[:,idxb[0],idxb[1]].ravel()))
 
-def spatial2spin_ea(r1, r2, orbspin=None):
-    '''Convert R1/R2 of spatial orbital representation to R1/R2 of
-    spin-orbital representation
-    '''
-    r1a, r1b = r1
-    r2aaa, r2aba, r2bab, r2bbb = r2
+def spatial2spin_ea(rx, orbspin=None):
+    '''Convert EOMEA spatial-orbital R1/R2 to spin-orbital R1/R2'''
+    if len(rx) == 2:  # r1
+        r1a, r1b = rx
+        nvir_a = r1a.size
+        nvir_b = r1b.size
+        nvir = nvir_a + nvir_b
+
+        r1 = np.zeros(nvir, dtype=r1a.dtype)
+        if orbspin is None:
+            assert nvir_a == nvir_b
+            r1[0::2] = r1a
+            r1[1::2] = r1b
+        else:
+            r1[orbspin[-nvir:] == 0] = r1a
+            r1[orbspin[-nvir:] == 1] = r1b
+        return r1
+
+    r2aaa, r2aba, r2bab, r2bbb = rx
     nocc_a, nvir_a = r2aaa.shape[:2]
     nocc_b, nvir_b = r2bbb.shape[:2]
 
     if orbspin is None:
+        assert nvir_a == nvir_b
         orbspin = np.zeros((nocc_a+nvir_a)*2, dtype=int)
         orbspin[1::2] = 1
 
@@ -413,10 +440,6 @@ def spatial2spin_ea(r1, r2, orbspin=None):
     idxva = np.where(orbspin[nocc:] == 0)[0]
     idxvb = np.where(orbspin[nocc:] == 1)[0]
 
-    r1 = np.zeros((nvir), dtype=r1a.dtype)
-    r1[idxva] = r1a
-    r1[idxvb] = r1b
-
     r2 = np.zeros((nocc, nvir**2), dtype=r2aaa.dtype)
     #idxoaa = idxoa[:,None] * nocc + idxoa
     #idxoab = idxoa[:,None] * nocc + idxob
@@ -441,10 +464,17 @@ def spatial2spin_ea(r1, r2, orbspin=None):
     lib.takebak_2d(r2, r2bba, idxob.ravel(), idxvba.T.ravel())
     lib.takebak_2d(r2, r2aab, idxoa.ravel(), idxvab.T.ravel())
     r2 = r2.reshape(nocc, nvir, nvir)
-    return r1, r2
+    return r2
 
-def spin2spatial_ea(r1, r2, orbspin):
-    nocc, nvir = r2.shape[:2]
+def spin2spatial_ea(rx, orbspin):
+    '''Convert EOMEA spin-orbital R1/R2 to spatial-orbital R1/R2'''
+    if rx.ndim == 1:
+        nvir = rx.size
+        r1a = rx[orbspin[-nvir:] == 0]
+        r1b = rx[orbspin[-nvir:] == 1]
+        return r1a, r1b
+
+    nocc, nvir = rx.shape[:2]
 
     idxoa = np.where(orbspin[:nocc] == 0)[0]
     idxob = np.where(orbspin[:nocc] == 1)[0]
@@ -455,19 +485,12 @@ def spin2spatial_ea(r1, r2, orbspin):
     nvir_a = len(idxva)
     nvir_b = len(idxvb)
 
-    r1a = r1[idxva]
-    r1b = r1[idxvb]
-
-    #idxoaa = idxoa[:,None] * nocc + idxoa
-    #idxoab = idxoa[:,None] * nocc + idxob
-    #idxoba = idxob[:,None] * nocc + idxoa
-    #idxobb = idxob[:,None] * nocc + idxob
     idxvaa = idxva[:,None] * nvir + idxva
     idxvab = idxva[:,None] * nvir + idxvb
     idxvba = idxvb[:,None] * nvir + idxva
     idxvbb = idxvb[:,None] * nvir + idxvb
 
-    r2 = r2.reshape(nocc, nvir**2)
+    r2 = rx.reshape(nocc, nvir**2)
     r2aaa = lib.take_2d(r2, idxoa.ravel(), idxvaa.ravel())
     r2aba = lib.take_2d(r2, idxoa.ravel(), idxvba.ravel())
     r2bab = lib.take_2d(r2, idxob.ravel(), idxvab.ravel())
@@ -477,7 +500,7 @@ def spin2spatial_ea(r1, r2, orbspin):
     r2aba = r2aba.reshape(nocc_a, nvir_b, nvir_a)
     r2bab = r2bab.reshape(nocc_b, nvir_a, nvir_b)
     r2bbb = r2bbb.reshape(nocc_b, nvir_b, nvir_b)
-    return [r1a, r1b], [r2aaa, r2aba, r2bab, r2bbb]
+    return r2aaa, r2aba, r2bab, r2bbb
 
 def eaccsd_matvec(eom, vector, imds=None, diag=None):
     '''For spin orbitals.
@@ -490,7 +513,7 @@ def eaccsd_matvec(eom, vector, imds=None, diag=None):
     t2aa, t2ab, t2bb = t2
     nocca, noccb, nvira, nvirb = t2ab.shape
     nmoa, nmob = nocca+nvira, noccb+nvirb
-    r1, r2 = vector_to_amplitudes_ea(vector, (nmoa,nmob), (nocca,noccb))
+    r1, r2 = eom.vector_to_amplitudes(vector, (nmoa,nmob), (nocca,noccb))
     r1a, r1b = r1
     r2aaa, r2aba, r2bab, r2bbb = r2
 
@@ -848,13 +871,11 @@ def get_init_guess(self, nroots=1, koopmans=True, diag=None):
             guess.append(g)
         return guess
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_ea(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_ea(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_ea)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_ea,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_ea)
+    spin2spatial = staticmethod(spin2spatial_ea)
 
     def vector_size(self):
         '''size of the vector based on spin-orbital basis'''
@@ -982,8 +1003,8 @@ def eomsf_ccsd(eom, nroots=1, koopmans=False, guess=None,
     '''
     return eomee_ccsd(eom, nroots, koopmans, guess, eris, imds, diag)
 
-amplitudes_to_vector_ee = uccsd.amplitudes_to_vector
-vector_to_amplitudes_ee = uccsd.vector_to_amplitudes
+amplitudes_to_vector_ee = amplitudes_to_vector_eomee = uccsd.amplitudes_to_vector
+vector_to_amplitudes_ee = vector_to_amplitudes_eomee = uccsd.vector_to_amplitudes
 
 def amplitudes_to_vector_eomsf(t1, t2, out=None):
     t1ab, t1ba = t1
@@ -1049,8 +1070,11 @@ def vector_to_amplitudes_eomsf(vector, nmo, nocc):
     t2bbab = t2bbab.reshape(noccb,noccb,nvira,nvirb)
     return (t1ab,t1ba), (t2baaa, t2aaba, t2abbb, t2bbab)
 
-def spatial2spin_eomsf(rx, orbspin):
-    '''Convert EOM spatial R1,R2 to spin-orbital R1,R2'''
+spatial2spin_eomee = addons.spatial2spin
+spin2spatial_eomee = addons.spin2spatial
+
+def spatial2spin_eomsf(rx, orbspin=None):
+    '''Convert spin-flip EOMEE spatial-orbital R1/R2 to spin-orbital R1/R2'''
     if len(rx) == 2:  # r1
         r1ab, r1ba = rx
         nocca, nvirb = r1ab.shape
@@ -1062,6 +1086,11 @@ def spatial2spin_eomsf(rx, orbspin):
 
     nocc = nocca + noccb
     nvir = nvira + nvirb
+    if orbspin is None:
+        assert nocca == noccb
+        orbspin = np.zeros(nocc+nvir, dtype=int)
+        orbspin[1::2] = 1
+
     idxoa = np.where(orbspin[:nocc] == 0)[0]
     idxob = np.where(orbspin[:nocc] == 1)[0]
     idxva = np.where(orbspin[nocc:] == 0)[0]
@@ -1098,7 +1127,7 @@ def spatial2spin_eomsf(rx, orbspin):
         return r2.reshape(nocc,nocc,nvir,nvir)
 
 def spin2spatial_eomsf(rx, orbspin):
-    '''Convert EOM spin-orbital R1,R2 to spatial R1,R2'''
+    '''Convert EOMEE spin-orbital R1/R2 to spin-flip EOMEE spatial-orbital R1/R2'''
     if rx.ndim == 2:  # r1
         nocc, nvir = rx.shape
     else:
@@ -1148,7 +1177,7 @@ def eomee_ccsd_matvec(eom, vector, imds=None):
     t2aa, t2ab, t2bb = t2
     nocca, noccb, nvira, nvirb = t2ab.shape
     nmoa, nmob = nocca+nvira, noccb+nvirb
-    r1, r2 = vector_to_amplitudes_ee(vector, (nmoa,nmob), (nocca,noccb))
+    r1, r2 = eom.vector_to_amplitudes(vector, (nmoa,nmob), (nocca,noccb))
     r1a, r1b = r1
     r2aa, r2ab, r2bb = r2
 
@@ -1369,7 +1398,7 @@ def eomsf_ccsd_matvec(eom, vector, imds=None):
     t2aa, t2ab, t2bb = t2
     nocca, noccb, nvira, nvirb = t2ab.shape
     nmoa, nmob = nocca+nvira, noccb+nvirb
-    r1, r2 = vector_to_amplitudes_eomsf(vector, (nmoa,nmob), (nocca,noccb))
+    r1, r2 = eom.vector_to_amplitudes(vector, (nmoa,nmob), (nocca,noccb))
     r1ab, r1ba = r1
     r2baaa, r2aaba, r2abbb, r2bbab = r2
 
@@ -1853,13 +1882,11 @@ def gen_matvec(self, imds=None, diag=None, **kwargs):
         matvec = lambda xs: [self.matvec(x, imds) for x in xs]
         return matvec, diag
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_ee(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_ee(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_ee)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_ee,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_eomee)
+    spin2spatial = staticmethod(spin2spatial_eomee)
 
     def vector_size(self):
         '''size of the vector based on spin-orbital basis'''
@@ -1901,13 +1928,11 @@ def gen_matvec(self, imds=None, diag=None, **kwargs):
         matvec = lambda xs: [self.matvec(x, imds) for x in xs]
         return matvec, diag
 
-    def vector_to_amplitudes(self, vector, nmo=None, nocc=None):
-        if nmo is None: nmo = self.nmo
-        if nocc is None: nocc = self.nocc
-        return vector_to_amplitudes_eomsf(vector, nmo, nocc)
-
-    def amplitudes_to_vector(self, r1, r2):
-        return amplitudes_to_vector_eomsf(r1, r2)
+    amplitudes_to_vector = staticmethod(amplitudes_to_vector_eomsf)
+    vector_to_amplitudes = module_method(vector_to_amplitudes_eomsf,
+                                         absences=['nmo', 'nocc'])
+    spatial2spin = staticmethod(spatial2spin_eomsf)
+    spin2spatial = staticmethod(spin2spatial_eomsf)
 
     def vector_size(self):
         '''size of the vector based on spin-orbital basis'''
@@ -2604,229 +2629,3 @@ def make_ee(self):
 
         self.made_ee_imds = True
         log.timer('EOM-UCCSD EE intermediates', *cput0)
-
-def rand_mf(mol, seed=1):
-    from pyscf import scf
-    from pyscf import gto
-    from pyscf import lo
-    mol = gto.Mole()
-    mol.atom = [
-        [8 , (0. , 0.     , 0.)],
-        [1 , (0. , -0.757 , 0.587)],
-        [1 , (0. , 0.757  , 0.587)]]
-    mol.basis = 'sto-3g'
-    mol.verbose = 0
-    mol.spin = 0
-    mol.build()
-
-    np.random.seed(seed)
-
-    mf = scf.UHF(mol).run(conv_tol=1e-14)
-    nmo = mol.nao_nr()
-    mf.mo_occ = np.zeros((2,nmo))
-    mf.mo_occ[0,:4] = 1
-    mf.mo_occ[1,:2] = 1
-    mf.mo_energy = np.arange(nmo) + np.random.random((2,nmo)) * .3
-    mf.mo_energy[mf.mo_occ == 0] += 2
-
-    mo = np.random.random((2,nmo,nmo))
-    s = mf.get_ovlp()
-    mf.mo_coeff = np.empty_like(mo)
-    mf.mo_coeff[0] = lo.orth.vec_lowdin(mo[0], s)
-    mf.mo_coeff[1] = lo.orth.vec_lowdin(mo[1], s)
-    return mf
-
-def rand_cc_t1_t2(mf, seed=1):
-    from pyscf import ao2mo
-    from pyscf.cc import uccsd
-    mycc = uccsd.UCCSD(mf)
-
-    nocca, noccb = mycc.nocc
-    nmoa, nmob = mycc.nmo
-    nvira, nvirb = nmoa - nocca, nmob - noccb
-    def my_ao2mo(mo):
-        eris = ao2mo.kernel(mycc._scf._eri, mo, compact=False)
-        eris = ao2mo.restore(1, eris, mf.mol.nao_nr())
-
-        eris = eris + np.cos(eris)*1j
-        eris = eris + eris.transpose(1, 0, 3, 2)
-        eris = eris + eris.conj().transpose(2, 3, 0, 1)
-        return eris
-    eris = uccsd._make_eris_incore(mycc)#, ao2mofn=my_ao2mo)
-
-    np.random.seed(seed)
-    t1a = (np.random.random((nocca,nvira)) +
-           np.random.random((nocca,nvira))*1j - .5 - .5j)
-    t1b = (np.random.random((noccb,nvirb)) +
-           np.random.random((noccb,nvirb))*1j - .5 - .5j)
-    t2aa = (np.random.random((nocca,nocca,nvira,nvira)) +
-            np.random.random((nocca,nocca,nvira,nvira))*1j - .5 - .5j)
-    t2aa = t2aa - t2aa.transpose(1, 0, 2, 3)
-    t2aa = t2aa - t2aa.transpose(0, 1, 3, 2)
-
-    t2ab = (np.random.random((nocca,noccb,nvira,nvirb)) +
-            np.random.random((nocca,noccb,nvira,nvirb))*1j - .5 - .5j)
-
-    t2bb = (np.random.random((noccb,noccb,nvirb,nvirb)) +
-            np.random.random((noccb,noccb,nvirb,nvirb))*1j - .5 - .5j)
-    t2bb = t2bb - t2bb.transpose(1, 0, 2, 3)
-    t2bb = t2bb - t2bb.transpose(0, 1, 3, 2)
-
-    t1 = (t1a, t1b)
-    t2 = (t2aa, t2ab, t2bb)
-    return mycc, eris, t1, t2
-
-def enforce_symm_2p_spin(r1, r2, orbspin, excitation):
-    assert (excitation in ['ip', 'ea'])
-    if excitation == 'ip':
-        nocc, nvir = r2.shape[1:]
-    elif excitation == 'ea':
-        nocc, nvir = r2.shape[:2]
-    else:
-        raise NotImplementedError
-
-    idxoa = np.where(orbspin[:nocc] == 0)[0]
-    idxob = np.where(orbspin[:nocc] == 1)[0]
-    idxva = np.where(orbspin[nocc:] == 0)[0]
-    idxvb = np.where(orbspin[nocc:] == 1)[0]
-
-    idxoaa = idxoa[:,None] * nocc + idxoa
-    idxobb = idxob[:,None] * nocc + idxob
-    idxvaa = idxva[:,None] * nvir + idxva
-    idxvbb = idxvb[:,None] * nvir + idxvb
-
-    if excitation == 'ip':
-        r2 = r2 - r2.transpose(1, 0, 2)
-
-        r2 = r2.reshape(nocc**2, nvir)
-        r2[idxobb.ravel()[:, None], idxva.ravel()] = 0.0
-        r2[idxoaa.ravel()[:, None], idxvb.ravel()] = 0.0
-        r2 = r2.reshape(nocc, nocc, nvir)
-
-    if excitation == 'ea':
-        r2 = r2 - r2.transpose(0, 2, 1)
-
-        r2 = r2.reshape(nocc, nvir**2)
-        r2[idxoa.ravel(), idxvbb.ravel()[:, None]] = 0.0
-        r2[idxob.ravel(), idxvaa.ravel()[:, None]] = 0.0
-        r2 = r2.reshape(nocc, nvir, nvir)
-
-    return r1, r2
-
-def enforce_symm_2p_spin_ip(r1, r2, orbspin):
-    return enforce_symm_2p_spin(r1, r2, orbspin, 'ip')
-
-def enforce_symm_2p_spin_ea(r1, r2, orbspin):
-    return enforce_symm_2p_spin(r1, r2, orbspin, 'ea')
-
-if __name__ == '__main__':
-    from pyscf import gto
-    #from pyscf import scf
-    #from pyscf.cc import rccsd
-
-    mol = gto.Mole()
-    mol.atom = [
-        [8 , (0. , 0.     , 0.)],
-        [1 , (0. , -0.757 , 0.587)],
-        [1 , (0. , 0.757  , 0.587)]]
-    mol.basis = 'sto-3g'
-    mol.verbose = 0
-    mol.spin = 0
-    mol.build()
-
-    mf = rand_mf(mol)
-    mycc, eris, t1, t2 = rand_cc_t1_t2(mf)
-    mycc.t1 = t1
-    mycc.t2 = t2
-
-    nocca, noccb = mycc.nocc
-    nmoa, nmob = mycc.nmo
-    nvira, nvirb = nmoa - nocca, nmob - noccb
-    nocc = nocca + noccb
-    nvir = nvira + nvirb
-    nmo = nocc + nvir
-
-    def my_ao2mo(mo):
-        nao, nmo = mo.shape
-        orbspin = mo.orbspin
-
-#        eris = ao2mo.kernel(mygcc._scf._eri, mo_a + mo_b)
-#        sym_forbid = (orbspin[:,None] != orbspin)[np.tril_indices(nmo)]
-#        eris[sym_forbid,:] = 0
-#        eris[:,sym_forbid] = 0
-#        eris = ao2mo.restore(1, eris, nao)
-#        return eris
-        eris =(np.random.random((nmo,nmo,nmo,nmo)) +
-               np.random.random((nmo,nmo,nmo,nmo)) * 1j)
-
-        eris = eris + np.cos(eris)*1j
-        eris = eris + eris.transpose(1, 0, 3, 2)
-        eris = eris + eris.conj().transpose(2, 3, 0, 1)
-        eris[orbspin[:,None] != orbspin] = 0
-        eris[:,:,orbspin[:,None] != orbspin] = 0
-        return eris
-
-    import pyscf.cc.addons
-    from pyscf.cc import gccsd
-    mygcc = pyscf.cc.addons.convert_to_gccsd(mycc)
-    mygcc._ucc = mycc
-    mygcc._ucc_eris = eris
-    eris = gccsd._make_eris_incore(mygcc)#, ao2mofn=my_ao2mo)
-    orbspin = eris.orbspin
-
-    ## EOM-IP
-    myeom = EOMIP(mycc)
-    imds = myeom.make_imds()
-
-    np.random.seed(1)
-    r1 = np.random.rand(nocc)*1j + np.random.rand(nocc) - 0.5 - 0.5*1j
-    r2 = np.random.rand(nocc**2 * nvir)*1j + np.random.rand(nocc**2 * nvir) - 0.5 - 0.5*1j
-    r2 = r2.reshape(nocc, nocc, nvir)
-    r1, r2 = enforce_symm_2p_spin_ip(r1, r2, orbspin)
-    r1, r2 = spin2spatial_ip(r1, r2, orbspin)
-
-    vector = myeom.amplitudes_to_vector(r1, r2)
-    r1x, r2x = myeom.vector_to_amplitudes(vector)
-    print(abs(r1[0]-r1x[0]).max() < 1e-13 and
-          abs(r1[1]-r1x[1]).max() < 1e-13 and
-          abs(r2[0]-r2x[0]).max() < 1e-13 and
-          abs(r2[1]-r2x[1]).max() < 1e-13 and
-          abs(r2[2]-r2x[2]).max() < 1e-13 and
-          abs(r2[3]-r2x[3]).max() < 1e-13)
-    Hvector = myeom.matvec(vector, imds=imds)
-    print('ip', lib.finger(Hvector) - (21.67127462317093-19.068987454261908j))
-    print('diag', lib.finger(myeom.get_diag()) - (-9.6676217223549763+9.325219825942975j))
-
-    # EOM-EA
-    myeom = EOMEA(mycc)
-    imds = myeom.make_imds()
-
-    np.random.seed(1)
-    r1 = np.random.rand(nvir)*1j + np.random.rand(nvir) - 0.5 - 0.5*1j
-    r2 = np.random.rand(nocc * nvir**2)*1j + np.random.rand(nocc * nvir**2) - 0.5 - 0.5*1j
-    r2 = r2.reshape(nocc, nvir, nvir)
-    r1, r2 = enforce_symm_2p_spin_ea(r1, r2, orbspin)
-    r1, r2 = spin2spatial_ea(r1, r2, orbspin)
-
-    vector = myeom.amplitudes_to_vector(r1, r2)
-    r1x, r2x = myeom.vector_to_amplitudes(vector)
-    print(abs(r1[0]-r1x[0]).max() < 1e-13 and
-          abs(r1[1]-r1x[1]).max() < 1e-13 and
-          abs(r2[0]-r2x[0]).max() < 1e-13 and
-          abs(r2[1]-r2x[1]).max() < 1e-13 and
-          abs(r2[2]-r2x[2]).max() < 1e-13 and
-          abs(r2[3]-r2x[3]).max() < 1e-13)
-    Hvector = myeom.matvec(vector, imds=imds)
-    print('ea', lib.finger(Hvector) - (6.5543877287461187-13.175055314063574j))
-    print('diag', lib.finger(myeom.get_diag()) - (-57.353207240857785+1.4052857730841204j))
-
-    mycc = uccsd.UCCSD(mol.UHF().run())
-    ecc, t1, t2 = mycc.kernel()
-    print(ecc - -0.04946750711013597)
-    e,v = mycc.ipccsd(nroots=6)
-    print(e[0] - 0.3092874511803249)
-    print(e[1] - 0.3092874511803249)
-    print(e[2] - 0.4011171373779585)
-    print(e[3] - 0.4011171373779585)
-    print(e[4] - 0.6107409208314764)
-    print(e[5] - 0.6107409208314764)
diff --git a/pyscf/cc/gintermediates.py b/pyscf/cc/gintermediates.py
index a40e022f51..55cf7ec972 100644
--- a/pyscf/cc/gintermediates.py
+++ b/pyscf/cc/gintermediates.py
@@ -166,9 +166,6 @@ def Wvvvo(t1, t2, eris, _Wvvvv=None):
 # T3[2] related contributions to T1/T2
 ########################################
 
-def _cp(a):
-    return np.array(a, copy=False, order='C')
-
 def get_t3p2_imds_slow(cc, t1, t2, eris=None, t3p2_ip_out=None, t3p2_ea_out=None):
     """Calculates T1, T2 amplitudes corrected by second-order T3 contribution
     and intermediates used in IP/EA-CCSD(T)a
@@ -214,12 +211,12 @@ def get_t3p2_imds_slow(cc, t1, t2, eris=None, t3p2_ip_out=None, t3p2_ea_out=None
     mo_e_o = eris.mo_energy[:nocc]
     mo_e_v = eris.mo_energy[nocc:]
 
-    oovv = _cp(eris.oovv)
-    ovvv = _cp(eris.ovvv)
-    ooov = _cp(eris.ooov)
-    oovv = _cp(eris.oovv)
-    vooo = _cp(ooov).conj().transpose(3, 2, 1, 0)
-    vvvo = _cp(ovvv).conj().transpose(3, 2, 1, 0)
+    oovv = np.asarray(eris.oovv)
+    ovvv = np.asarray(eris.ovvv)
+    ooov = np.asarray(eris.ooov)
+    oovv = np.asarray(eris.oovv)
+    vooo = np.asarray(ooov).conj().transpose(3, 2, 1, 0)
+    vvvo = np.asarray(ovvv).conj().transpose(3, 2, 1, 0)
 
     ccsd_energy = cc.energy(t1, t2, eris)
     dtype = np.result_type(t1, t2)
diff --git a/pyscf/cc/rintermediates.py b/pyscf/cc/rintermediates.py
index 718ffb0cf1..ebdb4d7460 100644
--- a/pyscf/cc/rintermediates.py
+++ b/pyscf/cc/rintermediates.py
@@ -236,9 +236,6 @@ def _get_vvvv(eris):
     else:
         return eris.vvvv
 
-def _cp(a):
-    return np.array(a, copy=False, order='C')
-
 def get_t3p2_imds_slow(cc, t1, t2, eris=None, t3p2_ip_out=None, t3p2_ea_out=None):
     """Calculates T1, T2 amplitudes corrected by second-order T3 contribution
     and intermediates used in IP/EA-CCSD(T)a
@@ -261,8 +258,8 @@ def get_t3p2_imds_slow(cc, t1, t2, eris=None, t3p2_ip_out=None, t3p2_ea_out=None
     mo_e_o = eris.mo_energy[:nocc]
     mo_e_v = eris.mo_energy[nocc:]
 
-    ovov = _cp(eris.ovov)
-    ovvv = _cp(eris.get_ovvv())
+    ovov = np.asarray(eris.ovov)
+    ovvv = np.asarray(eris.get_ovvv())
     eris_vvov = eris.get_ovvv().conj().transpose(1,3,0,2)  # Physicist notation
     eris_vooo = eris.ovoo[:].conj().transpose(1,0,3,2)  # Chemist notation
 


Test patch:
diff --git a/pyscf/cc/test/test_dfccsd.py b/pyscf/cc/test/test_dfccsd.py
index fac0b39431..f1aa92486d 100644
--- a/pyscf/cc/test/test_dfccsd.py
+++ b/pyscf/cc/test/test_dfccsd.py
@@ -201,8 +201,8 @@ def test_df_eomee_ccsd_matvec_singlet(self):
         imds = myeom.make_imds(eris1)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1), -11001.96269563921, 7)
-        self.assertAlmostEqual(lib.fp(r2), 10145.408880409095, 7)
+        self.assertAlmostEqual(lib.fp(r1), -29298.85295742222, 7)
+        self.assertAlmostEqual(lib.fp(r2), 10145.543907318603, 7)
 
     def test_df_eomee_ccsd_matvec_triplet(self):
         numpy.random.seed(10)
@@ -216,9 +216,9 @@ def test_df_eomee_ccsd_matvec_triplet(self):
         imds = myeom.make_imds(eris1)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1   ), 214.90035498814302, 9)
-        self.assertAlmostEqual(lib.fp(r2[0]), 37033.183886562998, 7)
-        self.assertAlmostEqual(lib.fp(r2[1]), 4164.1657912277242, 7)
+        self.assertAlmostEqual(lib.fp(r1   ), -6923.975705203359, 8)
+        self.assertAlmostEqual(lib.fp(r2[0]), 37033.47500554715 , 7)
+        self.assertAlmostEqual(lib.fp(r2[1]), 4164.221159944544, 7)
 
     def test_df_eomsf_ccsd_matvec(self):
         numpy.random.seed(10)
@@ -229,15 +229,15 @@ def test_df_eomsf_ccsd_matvec(self):
         imds = myeom.make_imds(eris1)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1   ), 1929.9270950777639, 8)
-        self.assertAlmostEqual(lib.fp(r2[0]), 15571.714806853948, 7)
-        self.assertAlmostEqual(lib.fp(r2[1]),-12949.619613624538, 7)
+        self.assertAlmostEqual(lib.fp(r1   ), 133.93692998558186, 8)
+        self.assertAlmostEqual(lib.fp(r2[0]), 15572.228624905263, 7)
+        self.assertAlmostEqual(lib.fp(r2[1]),-12949.86945323115 , 7)
 
     def test_df_eomee_diag(self):
         vec1S, vec1T, vec2 = eom_rccsd.EOMEE(mycc1).get_diag()
-        self.assertAlmostEqual(lib.fp(vec1S), 213.16715890265095, 9)
-        self.assertAlmostEqual(lib.fp(vec1T),-857.23800705535234, 9)
-        self.assertAlmostEqual(lib.fp(vec2) , 14.360296355284504, 9)
+        self.assertAlmostEqual(lib.fp(vec1S), 213.17116636400607, 9)
+        self.assertAlmostEqual(lib.fp(vec1T),-857.2458742624522 , 9)
+        self.assertAlmostEqual(lib.fp(vec2) , 14.357453812621733, 9)
 
     def test_ao2mo(self):
         numpy.random.seed(2)
diff --git a/pyscf/cc/test/test_eom_rccsd.py b/pyscf/cc/test/test_eom_rccsd.py
index c417e4f28d..b1210ac7b3 100644
--- a/pyscf/cc/test/test_eom_rccsd.py
+++ b/pyscf/cc/test/test_eom_rccsd.py
@@ -277,11 +277,21 @@ def test_eomee_ccsd_matvec_singlet(self):
         r2 = r2 + r2.transpose(1,0,3,2)
         myeom = eom_rccsd.EOMEESinglet(mycc1)
         vec = myeom.amplitudes_to_vector(r1,r2)
-        imds = myeom.make_imds(eris1)
-        vec1 = myeom.matvec(vec, imds)
-        r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1), -112883.3791497977, 7)
-        self.assertAlmostEqual(lib.fp(r2), -268199.3475813322, 7)
+        vec1 = myeom.matvec(vec)
+        v1, v2 = myeom.vector_to_amplitudes(vec1)
+        self.assertAlmostEqual(lib.fp(v1), -145152.78511963107, 7)
+        self.assertAlmostEqual(lib.fp(v2), -268196.0471308574, 7)
+
+        gcc1 = cc.addons.convert_to_gccsd(mycc1)
+        gee1 = gcc1.EOMEE()
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        gr1 = myeom.spatial2spin(r1, orbspin)
+        gr2 = myeom.spatial2spin(r2, orbspin)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+        vecref = gee1.matvec(gvec)
+        gr1, gr2 = gee1.vector_to_amplitudes(vecref)
+        self.assertAlmostEqual(abs(gr1-myeom.spatial2spin(v1, orbspin)).max(), 0, 8)
+        self.assertAlmostEqual(abs(gr2-myeom.spatial2spin(v2, orbspin)).max(), 0, 8)
 
     def test_eomee_ccsd_matvec_triplet(self):
         numpy.random.seed(10)
@@ -294,10 +304,24 @@ def test_eomee_ccsd_matvec_triplet(self):
         vec = myeom.amplitudes_to_vector(r1, r2)
         imds = myeom.make_imds(eris1)
         vec1 = myeom.matvec(vec, imds)
-        r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1   ), 3550.5250670914056, 8)
-        self.assertAlmostEqual(lib.fp(r2[0]), -237433.03756895234,7)
-        self.assertAlmostEqual(lib.fp(r2[1]), 127680.0182437716 , 7)
+        v1, v2 = myeom.vector_to_amplitudes(vec1)
+        self.assertAlmostEqual(lib.fp(v1   ), -5616.12199728998, 8)
+        self.assertAlmostEqual(lib.fp(v2[0]), -237430.14342594685,7)
+        self.assertAlmostEqual(lib.fp(v2[1]), 127682.76151592708, 7)
+
+        gcc1 = cc.addons.convert_to_uccsd(mycc1)
+        gee1 = gcc1.EOMEESpinKeep()
+        gr1 = (r1*.5**.5, -r1*.5**.5)
+        raa = r2[0]*.5**.5
+        rx = r2[1]*.5**.5
+        gr2 = (raa, rx, -raa)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+        vecref = gee1.matvec(gvec)
+        gr1, gr2 = gee1.vector_to_amplitudes(vecref)
+        self.assertAlmostEqual(abs(gr1[0]*2**.5- v1).max(), 0, 9)
+        self.assertAlmostEqual(abs(gr2[0]*2**.5- v2[0]).max(), 0, 9)
+        self.assertAlmostEqual(abs(gr2[1]*2**.5- v2[1]).max(), 0, 9)
+        self.assertAlmostEqual(abs(-gr2[2]*2**.5- v2[0]).max(), 0, 9)
 
     def test_eomsf_ccsd_matvec(self):
         numpy.random.seed(10)
@@ -307,24 +331,56 @@ def test_eomsf_ccsd_matvec(self):
         vec = myeom.amplitudes_to_vector(r1,r2)
         imds = myeom.make_imds(eris1)
         vec1 = myeom.matvec(vec, imds)
-        r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1   ), -19368.729268465482, 8)
-        self.assertAlmostEqual(lib.fp(r2[0]), 84325.863680611626 , 7)
-        self.assertAlmostEqual(lib.fp(r2[1]), 6715.9574457836134 , 8)
+        v1, v2 = myeom.vector_to_amplitudes(vec1)
+
+        self.assertAlmostEqual(lib.fp(v1   ), -6213.095578988824, 7)
+        self.assertAlmostEqual(lib.fp(v2[0]), 84329.40539995288 , 7)
+        self.assertAlmostEqual(lib.fp(v2[1]), 6719.930458652292 , 7)
+
+        numpy.random.seed(10)
+        vec = numpy.random.random(myeom.vector_size()) - .9
+        r1, r2 = myeom.vector_to_amplitudes(vec)
+        vec1 = myeom.matvec(vec, imds)
+        v1, v2 = myeom.vector_to_amplitudes(vec1)
+
+        gcc1 = cc.addons.convert_to_gccsd(mycc1)
+        gee1 = gcc1.EOMEE()
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        gr1 = myeom.spatial2spin(r1, orbspin)
+        gr2 = myeom.spatial2spin(r2, orbspin)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+        vecref = gee1.matvec(gvec)
+        gr1, gr2 = gee1.vector_to_amplitudes(vecref)
+        self.assertAlmostEqual(abs(gr1-myeom.spatial2spin(v1, orbspin)).max(), 0, 9)
+        self.assertAlmostEqual(abs(gr2-myeom.spatial2spin(v2, orbspin)).max(), 0, 9)
 
     def test_eomee_diag(self):
         vec1S, vec1T, vec2 = eom_rccsd.EOMEE(mycc1).get_diag()
-        self.assertAlmostEqual(lib.fp(vec1S),-4714.9854130015719, 8)
-        self.assertAlmostEqual(lib.fp(vec1T), 2221.3155272953709, 8)
-        self.assertAlmostEqual(lib.fp(vec2) ,-5486.1611871545592, 8)
+        self.assertAlmostEqual(lib.fp(vec1S), -4714.969920334639, 8)
+        self.assertAlmostEqual(lib.fp(vec1T),  2221.322839866705, 8)
+        self.assertAlmostEqual(lib.fp(vec2) , -5486.124838268124, 8)
 
     def test_ip_matvec(self):
         numpy.random.seed(12)
         r1 = numpy.random.random((no)) - .9
         r2 = numpy.random.random((no,no,nv)) - .9
-        myeom = eom_rccsd.EOMIP(mycc1)
+        myeom = mycc1.EOMIP()
         vec = myeom.amplitudes_to_vector(r1,r2)
         r1,r2 = myeom.vector_to_amplitudes(vec)
+
+        gcc1 = cc.addons.convert_to_gccsd(mycc1)
+        gee1 = gcc1.EOMIP()
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        gr1 = myeom.spatial2spin(r1, orbspin)
+        gr2 = myeom.spatial2spin(r2, orbspin)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+        vecref = gee1.matvec(gvec)
+        gr1, gr2 = gee1.vector_to_amplitudes(vecref)
+        vec1 = myeom.matvec(vec)
+        v1, v2 = myeom.vector_to_amplitudes(vec1)
+        self.assertAlmostEqual(abs(gr1-myeom.spatial2spin(v1, orbspin)).max(), 0, 9)
+        self.assertAlmostEqual(abs(gr2-myeom.spatial2spin(v2, orbspin)).max(), 0, 9)
+
         myeom.partition = 'mp'
         self.assertAlmostEqual(lib.fp(r1), 0.37404344676857076, 11)
         self.assertAlmostEqual(lib.fp(r2), -1.1568913404570922, 11)
@@ -347,6 +403,20 @@ def test_ea_matvec(self):
         myeom = eom_rccsd.EOMEA(mycc1)
         vec = myeom.amplitudes_to_vector(r1,r2)
         r1,r2 = myeom.vector_to_amplitudes(vec)
+
+        gcc1 = cc.addons.convert_to_gccsd(mycc1)
+        gee1 = gcc1.EOMEA()
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        gr1 = myeom.spatial2spin(r1, orbspin)
+        gr2 = myeom.spatial2spin(r2, orbspin)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+        vecref = gee1.matvec(gvec)
+        gr1, gr2 = gee1.vector_to_amplitudes(vecref)
+        vec1 = myeom.matvec(vec)
+        v1, v2 = myeom.vector_to_amplitudes(vec1)
+        self.assertAlmostEqual(abs(gr1-myeom.spatial2spin(v1, orbspin)).max(), 0, 9)
+        self.assertAlmostEqual(abs(gr2-myeom.spatial2spin(v2, orbspin)).max(), 0, 9)
+
         myeom.partition = 'mp'
         self.assertAlmostEqual(lib.fp(r1), 1.4488291275539353, 11)
         self.assertAlmostEqual(lib.fp(r2), 0.97080165032287469, 11)
@@ -506,8 +576,8 @@ def test_eomee_ccsd_matvec_singlet2(self):
         imds = myeom.make_imds(eris21)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1), -112883.3791497977, 7)
-        self.assertAlmostEqual(lib.fp(r2), -268199.3475813322, 7)
+        self.assertAlmostEqual(lib.fp(r1), -145152.7851196310, 7)
+        self.assertAlmostEqual(lib.fp(r2), -268196.0471308578, 7)
 
     def test_eomee_ccsd_matvec_triplet2(self):
         numpy.random.seed(10)
@@ -521,9 +591,9 @@ def test_eomee_ccsd_matvec_triplet2(self):
         imds = myeom.make_imds(eris21)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1   ), 3550.5250670914056, 8)
-        self.assertAlmostEqual(lib.fp(r2[0]), -237433.03756895234,7)
-        self.assertAlmostEqual(lib.fp(r2[1]), 127680.0182437716 , 7)
+        self.assertAlmostEqual(lib.fp(r1   ), -5616.12199728998, 8)
+        self.assertAlmostEqual(lib.fp(r2[0]), -237430.14342594685,7)
+        self.assertAlmostEqual(lib.fp(r2[1]), 127682.76151592708, 7)
 
     def test_eomsf_ccsd_matvec2(self):
         numpy.random.seed(10)
@@ -534,15 +604,15 @@ def test_eomsf_ccsd_matvec2(self):
         imds = myeom.make_imds(eris21)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1   ), -19368.729268465482, 7)
-        self.assertAlmostEqual(lib.fp(r2[0]), 84325.863680611626 , 7)
-        self.assertAlmostEqual(lib.fp(r2[1]), 6715.9574457836134 , 7)
+        self.assertAlmostEqual(lib.fp(r1   ), -6213.095578988824, 7)
+        self.assertAlmostEqual(lib.fp(r2[0]), 84329.40539995288 , 7)
+        self.assertAlmostEqual(lib.fp(r2[1]), 6719.930458652292 , 7)
 
     def test_eomee_diag2(self):
         vec1S, vec1T, vec2 = eom_rccsd.EOMEE(mycc21).get_diag()
-        self.assertAlmostEqual(lib.fp(vec1S),-4714.9854130015719, 8)
-        self.assertAlmostEqual(lib.fp(vec1T), 2221.3155272953709, 8)
-        self.assertAlmostEqual(lib.fp(vec2) ,-5486.1611871545592, 8)
+        self.assertAlmostEqual(lib.fp(vec1S), -4714.969920334639, 8)
+        self.assertAlmostEqual(lib.fp(vec1T),  2221.322839866705, 8)
+        self.assertAlmostEqual(lib.fp(vec2) , -5486.124838268124, 8)
 
 
     def test_ip_matvec2(self):
@@ -705,8 +775,8 @@ def test_eomee_ccsd_matvec_singlet3(self):
         imds = myeom.make_imds(eris31)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1), -112883.3791497977, 7)
-        self.assertAlmostEqual(lib.fp(r2), -268199.3475813322, 7)
+        self.assertAlmostEqual(lib.fp(r1), -145152.7851196310, 7)
+        self.assertAlmostEqual(lib.fp(r2), -268196.0471308578, 7)
 
     def test_eomee_ccsd_matvec_triplet3(self):
         numpy.random.seed(10)
@@ -720,9 +790,9 @@ def test_eomee_ccsd_matvec_triplet3(self):
         imds = myeom.make_imds(eris31)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1   ), 3550.5250670914056, 8)
-        self.assertAlmostEqual(lib.fp(r2[0]), -237433.03756895234,7)
-        self.assertAlmostEqual(lib.fp(r2[1]), 127680.0182437716 , 7)
+        self.assertAlmostEqual(lib.fp(r1   ), -5616.12199728998, 8)
+        self.assertAlmostEqual(lib.fp(r2[0]), -237430.14342594685,7)
+        self.assertAlmostEqual(lib.fp(r2[1]), 127682.76151592708, 7)
 
     def test_eomsf_ccsd_matvec3(self):
         numpy.random.seed(10)
@@ -733,15 +803,15 @@ def test_eomsf_ccsd_matvec3(self):
         imds = myeom.make_imds(eris31)
         vec1 = myeom.matvec(vec, imds)
         r1, r2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(lib.fp(r1   ), -19368.729268465482, 7)
-        self.assertAlmostEqual(lib.fp(r2[0]), 84325.863680611626 , 7)
-        self.assertAlmostEqual(lib.fp(r2[1]), 6715.9574457836134 , 7)
+        self.assertAlmostEqual(lib.fp(r1   ), -6213.095578988824, 7)
+        self.assertAlmostEqual(lib.fp(r2[0]), 84329.40539995288 , 7)
+        self.assertAlmostEqual(lib.fp(r2[1]), 6719.930458652292 , 7)
 
     def test_eomee_diag3(self):
         vec1S, vec1T, vec2 = eom_rccsd.EOMEE(mycc31).get_diag()
-        self.assertAlmostEqual(lib.fp(vec1S),-2881.6804563818432, 8)
-        self.assertAlmostEqual(lib.fp(vec1T), 2039.7385969969259, 8)
-        self.assertAlmostEqual(lib.fp(vec2) ,-4271.6230465236358, 8)
+        self.assertAlmostEqual(lib.fp(vec1S), -2881.664963714903, 8)
+        self.assertAlmostEqual(lib.fp(vec1T),  2039.745909568253, 8)
+        self.assertAlmostEqual(lib.fp(vec2) , -4271.586697637197, 8)
 
 
     def test_ip_matvec3(self):
diff --git a/pyscf/cc/test/test_eom_uccsd.py b/pyscf/cc/test/test_eom_uccsd.py
index 7ec38eadae..754eeb873e 100644
--- a/pyscf/cc/test/test_eom_uccsd.py
+++ b/pyscf/cc/test/test_eom_uccsd.py
@@ -16,6 +16,7 @@
 import copy
 import unittest
 import numpy
+import numpy as np
 from functools import reduce
 
 from pyscf import gto
@@ -29,8 +30,8 @@
 from pyscf.cc import eom_gccsd
 
 def setUpModule():
-    global mol, mf, mol1, mf0, mf1, gmf, ucc, ucc0, ucc1, eris1
-    global ecc, orbspin, nocca, noccb, nvira, nvirb, r1, r2
+    global mol, mf, mol1, mf0, mf1, gmf, ucc, ucc0, ucc1
+    global orbspin, nocca, noccb, nvira, nvirb, r1, r2
     mol = gto.Mole()
     mol.verbose = 0
     mol.atom = [
@@ -57,7 +58,6 @@ def setUpModule():
     orbspin = gmf.mo_coeff.orbspin
 
     ucc1 = cc.UCCSD(mf1)
-    eris1 = ucc1.ao2mo()
 
     numpy.random.seed(11)
     no = nocca + noccb
@@ -76,16 +76,17 @@ def setUpModule():
     ucc = cc.UCCSD(mf)
     ucc.max_space = 0
     ucc.conv_tol = 1e-8
-    ecc = ucc.kernel()[0]
+    ucc.kernel()[0]
 
     ucc0 = cc.UCCSD(mf0)
     ucc0.conv_tol = 1e-8
     ucc0.direct = True
     ucc0.kernel()
 
+
 def tearDownModule():
-    global mol, mf, mol1, mf0, mf1, gmf, ucc, ucc0, ucc1, eris1
-    del mol, mf, mol1, mf0, mf1, gmf, ucc, ucc0, ucc1, eris1
+    global mol, mf, mol1, mf0, mf1, gmf, ucc, ucc0, ucc1
+    del mol, mf, mol1, mf0, mf1, gmf, ucc, ucc0, ucc1
 
 class KnownValues(unittest.TestCase):
     def test_ipccsd(self):
@@ -130,7 +131,7 @@ def test_eaccsd_koopmans(self):
 
 
     def test_eomee(self):
-        self.assertAlmostEqual(ecc, -0.13539788719099638, 5)
+        self.assertAlmostEqual(ucc.e_corr, -0.13539788719099638, 5)
         eom = ucc.eomee_method()
         e,v = eom.kernel(nroots=1, koopmans=False)
         self.assertAlmostEqual(e, 0.28114509667240556, 5)
@@ -164,11 +165,13 @@ def test_eomsf_ccsd(self):
 
     def test_ucc_update_amps(self):
         gcc1 = gccsd.GCCSD(gmf)
+        orbspin = gcc1._scf.mo_coeff.orbspin
         r1g = gcc1.spatial2spin(ucc1.t1, orbspin)
         r2g = gcc1.spatial2spin(ucc1.t2, orbspin)
         r1g, r2g = gcc1.update_amps(r1g, r2g, gcc1.ao2mo())
         u1g = gcc1.spin2spatial(r1g, orbspin)
         u2g = gcc1.spin2spatial(r2g, orbspin)
+        eris1 = ucc1.ao2mo()
         t1, t2 = ucc1.update_amps(ucc1.t1, ucc1.t2, eris1)
         self.assertAlmostEqual(abs(u1g[0]-t1[0]).max(), 0, 7)
         self.assertAlmostEqual(abs(u1g[1]-t1[1]).max(), 0, 7)
@@ -199,29 +202,59 @@ def test_ucc_eomee_ccsd_matvec(self):
         gr1 = gcc1.spatial2spin(r1)
         gr2 = gcc1.spatial2spin(r2)
         gee1 = eom_gccsd.EOMEE(gcc1)
-        gvec = eom_gccsd.amplitudes_to_vector_ee(gr1, gr2)
-        vecref = eom_gccsd.eeccsd_matvec(gee1, gvec)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+        vecref = gee1.matvec(gvec)
 
-        vec = eom_uccsd.amplitudes_to_vector_ee(r1,r2)
         uee1 = eom_uccsd.EOMEESpinKeep(ucc1)
-        vec1 = eom_uccsd.eomee_ccsd_matvec(uee1, vec)
-
-        uv = eom_uccsd.amplitudes_to_vector_ee(r1, r2)
-        gv = eom_gccsd.amplitudes_to_vector_ee(gr1, gr2)
-        r1, r2 = uee1.vector_to_amplitudes(uee1.matvec(uv))
-        gr1, gr2 = gee1.vector_to_amplitudes(gee1.matvec(gv))
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        r1 = uee1.spin2spatial(uee1.spatial2spin(r1, orbspin), orbspin)
+        r2 = uee1.spin2spatial(uee1.spatial2spin(r2, orbspin), orbspin)
+        vec = uee1.amplitudes_to_vector(r1,r2)
+        vec1 = uee1.matvec(vec)
 
         r1, r2 = uee1.vector_to_amplitudes(vec1)
         gr1, gr2 = gee1.vector_to_amplitudes(vecref)
-        self.assertAlmostEqual(float(abs(gr1-gcc1.spatial2spin(r1)).max()), 0, 9)
-        self.assertAlmostEqual(float(abs(gr2-gcc1.spatial2spin(r2)).max()), 0, 9)
+        self.assertAlmostEqual(float(abs(gr1-uee1.spatial2spin(r1, orbspin)).max()), 0, 9)
+        self.assertAlmostEqual(float(abs(gr2-uee1.spatial2spin(r2, orbspin)).max()), 0, 9)
+        self.assertAlmostEqual(lib.fp(vec1), 49.499911123484523, 9)
+
+        ucc2 = copy.copy(ucc1)
+        ucc2.direct = True
+        uee1 = eom_uccsd.EOMEESpinKeep(ucc2)
+        vec1 = uee1.matvec(vec)
         self.assertAlmostEqual(lib.fp(vec1), 49.499911123484523, 9)
 
-    def test_ucc_eomee_ccsd_diag(self):  # FIXME: compare to EOMEE-GCCSD diag
+    def test_ucc_eomee_ccsd_diag(self):
         vec1, vec2 = eom_uccsd.EOMEE(ucc1).get_diag()
         self.assertAlmostEqual(lib.fp(vec1), 62.767648620751018, 9)
         self.assertAlmostEqual(lib.fp(vec2), 156.2976365433517, 9)
 
+        gcc1 = cc.addons.convert_to_gccsd(ucc1)
+        gee1 = eom_gccsd.EOMEE(gcc1)
+        gvec = gee1.get_diag()
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        gv1, gv2 = gee1.vector_to_amplitudes(gvec)
+
+        nmo = ucc1.nmo
+        nocc = ucc1.nocc
+        v1, v2 = eom_uccsd.vector_to_amplitudes_eomee(vec1, nmo, nocc)
+        r1 = eom_uccsd.spin2spatial_eomee(gv1, orbspin)
+        r2 = eom_uccsd.spin2spatial_eomee(gv2, orbspin)
+        self.assertAlmostEqual(abs(abs(v1[0])-abs(r1[0])).max(), 0, 9)
+        self.assertAlmostEqual(abs(abs(v1[1])-abs(r1[1])).max(), 0, 9)
+        self.assertAlmostEqual(abs(abs(v2[0])-abs(r2[0])).max(), 0, 9)
+        self.assertAlmostEqual(abs(abs(v2[1])-abs(r2[1])).max(), 0, 9)
+        self.assertAlmostEqual(abs(abs(v2[2])-abs(r2[2])).max(), 0, 9)
+
+        v1, v2 = eom_uccsd.vector_to_amplitudes_eomsf(vec2, nmo, nocc)
+        r1 = eom_uccsd.spin2spatial_eomsf(gv1, orbspin)
+        r2 = eom_uccsd.spin2spatial_eomsf(gv2, orbspin)
+        self.assertAlmostEqual(abs(abs(v1[0])-abs(r1[0])).max(), 0, 9)
+        self.assertAlmostEqual(abs(abs(v1[1])-abs(r1[1])).max(), 0, 9)
+        self.assertAlmostEqual(abs(abs(v2[0])-abs(r2[0])).max(), 0, 9)
+        self.assertAlmostEqual(abs(abs(v2[1])-abs(r2[1])).max(), 0, 9)
+        self.assertAlmostEqual(abs(abs(v2[2])-abs(r2[2])).max(), 0, 9)
+
     def test_ucc_eomee_init_guess(self):
         uee = eom_uccsd.EOMEESpinKeep(ucc1)
         diag = uee.get_diag()[0]
@@ -241,25 +274,88 @@ def test_ucc_eomsf_ccsd_matvec(self):
         numpy.random.seed(10)
         myeom = eom_uccsd.EOMEESpinFlip(ucc1)
         vec = numpy.random.random(myeom.vector_size()) - .9
-        vec1 = eom_uccsd.eomsf_ccsd_matvec(myeom, vec)
+        vec1 = myeom.matvec(vec)
+        self.assertAlmostEqual(lib.fp(vec1), -1655.5564756993756, 8)
+
+        gcc1 = cc.addons.convert_to_gccsd(ucc1)
+        gee1 = eom_gccsd.EOMEE(gcc1)
+        r1, r2 = myeom.vector_to_amplitudes(vec)
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        r1 = myeom.spin2spatial(myeom.spatial2spin(r1, orbspin), orbspin)
+        r2 = myeom.spin2spatial(myeom.spatial2spin(r2, orbspin), orbspin)
+        gr1 = myeom.spatial2spin(r1, orbspin)
+        gr2 = myeom.spatial2spin(r2, orbspin)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+
+        vecref = gee1.matvec(gvec)
+        gr1, gr2 = gee1.vector_to_amplitudes(vecref)
+        v1, v2 = myeom.vector_to_amplitudes(vec1)
+        self.assertAlmostEqual(float(abs(gr1-myeom.spatial2spin(v1, orbspin)).max()), 0, 9)
+        self.assertAlmostEqual(float(abs(gr2-myeom.spatial2spin(v2, orbspin)).max()), 0, 9)
+
+        ucc2 = copy.copy(ucc1)
+        ucc2.direct = True
+        myeom = eom_uccsd.EOMEESpinFlip(ucc2)
+        vec1 = myeom.matvec(vec)
         self.assertAlmostEqual(lib.fp(vec1), -1655.5564756993756, 8)
 
+    def test_ucc_eomip_matvec(self):
+        numpy.random.seed(10)
+        myeom = eom_uccsd.EOMIP(ucc1)
+        vec = numpy.random.random(myeom.vector_size()) - .9
+        vec1 = myeom.matvec(vec)
+        self.assertAlmostEqual(lib.fp(vec1), -216.54704385639815, 8)
+
+        gcc1 = cc.addons.convert_to_gccsd(ucc1)
+        gee1 = eom_gccsd.EOMIP(gcc1)
         r1, r2 = myeom.vector_to_amplitudes(vec)
-        gr1 = eom_uccsd.spatial2spin_eomsf(r1, orbspin)
-        gr2 = eom_uccsd.spatial2spin_eomsf(r2, orbspin)
-        gvec = eom_gccsd.amplitudes_to_vector_ee(gr1, gr2)
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        r1 = myeom.spin2spatial(myeom.spatial2spin(r1, orbspin), orbspin)
+        r2 = myeom.spin2spatial(myeom.spatial2spin(r2, orbspin), orbspin)
+        gr1 = myeom.spatial2spin(r1, orbspin)
+        gr2 = myeom.spatial2spin(r2, orbspin)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+
+        vecref = gee1.matvec(gvec)
+        gr1, gr2 = gee1.vector_to_amplitudes(vecref)
+        v1, v2 = myeom.vector_to_amplitudes(vec1)
+        self.assertAlmostEqual(float(abs(gr1-myeom.spatial2spin(v1, orbspin)).max()), 0, 9)
+        self.assertAlmostEqual(float(abs(gr2-myeom.spatial2spin(v2, orbspin)).max()), 0, 9)
+
+        ucc2 = copy.copy(ucc1)
+        ucc2.direct = True
+        myeom = eom_uccsd.EOMIP(ucc2)
+        vec1 = myeom.matvec(vec)
+        self.assertAlmostEqual(lib.fp(vec1), -216.54704385639815, 8)
+
+    def test_ucc_eomea_matvec(self):
+        numpy.random.seed(10)
+        myeom = eom_uccsd.EOMEA(ucc1)
+        vec = numpy.random.random(myeom.vector_size()) - .9
+        vec1 = myeom.matvec(vec)
+        self.assertAlmostEqual(lib.fp(vec1), -110.5193188685705, 8)
 
         gcc1 = cc.addons.convert_to_gccsd(ucc1)
-        gee1 = eom_gccsd.EOMEE(gcc1)
-        vecref = eom_gccsd.eeccsd_matvec(gee1, gvec)
+        gee1 = eom_gccsd.EOMEA(gcc1)
+        r1, r2 = myeom.vector_to_amplitudes(vec)
+        orbspin = gcc1._scf.mo_coeff.orbspin
+        r1 = myeom.spin2spatial(myeom.spatial2spin(r1, orbspin), orbspin)
+        r2 = myeom.spin2spatial(myeom.spatial2spin(r2, orbspin), orbspin)
+        gr1 = myeom.spatial2spin(r1, orbspin)
+        gr2 = myeom.spatial2spin(r2, orbspin)
+        gvec = gee1.amplitudes_to_vector(gr1, gr2)
+
+        vecref = gee1.matvec(gvec)
         gr1, gr2 = gee1.vector_to_amplitudes(vecref)
         v1, v2 = myeom.vector_to_amplitudes(vec1)
-        self.assertAlmostEqual(float(abs(gr1-eom_uccsd.spatial2spin_eomsf(v1, orbspin)).max()), 0, 9)
-        self.assertAlmostEqual(float(abs(gr2-eom_uccsd.spatial2spin_eomsf(v2, orbspin)).max()), 0, 9)
+        self.assertAlmostEqual(float(abs(gr1-myeom.spatial2spin(v1, orbspin)).max()), 0, 9)
+        self.assertAlmostEqual(float(abs(gr2-myeom.spatial2spin(v2, orbspin)).max()), 0, 9)
 
-#    def test_ucc_eomip_matvec(self):
-#
-#    def test_ucc_eomea_matvec(self):
+        ucc2 = copy.copy(ucc1)
+        ucc2.direct = True
+        myeom = eom_uccsd.EOMEA(ucc2)
+        vec1 = myeom.matvec(vec)
+        self.assertAlmostEqual(lib.fp(vec1), -110.5193188685705, 8)
 
 ########################################
 # With 4-fold symmetry in integrals
@@ -289,8 +385,8 @@ def test_spatial2spin_eomsf(self):
         size = eomsf.vector_size()
         v = numpy.random.random(size)
         r1, r2 = eomsf.vector_to_amplitudes(v)
-        v1 = eom_uccsd.spin2spatial_eomsf(eom_uccsd.spatial2spin_eomsf(r1, orbspin), orbspin)
-        v2 = eom_uccsd.spin2spatial_eomsf(eom_uccsd.spatial2spin_eomsf(r2, orbspin), orbspin)
+        v1 = eomsf.spin2spatial(eomsf.spatial2spin(r1, orbspin), orbspin)
+        v2 = eomsf.spin2spatial(eomsf.spatial2spin(r2, orbspin), orbspin)
         self.assertAlmostEqual(abs(r1[0]-v1[0]).max(), 0, 12)
         self.assertAlmostEqual(abs(r1[1]-v1[1]).max(), 0, 12)
         self.assertAlmostEqual(abs(r2[0]-v2[0]).max(), 0, 12)