Repository: pyscf/pyscf — pull request #2524 (python)
Title: Fix iterative damping error

Fixes #2523 

Resolved issues:
title: Iterative damping broken in UCCSD
body: Damping in unrestricted CCSD doesn't work. Note that RCCSD does not have this error.

```
from pyscf import gto, scf, cc
mol = gto.M(
    atom = 'H 0 0 0; F 0 0 1.1',  # in Angstrom
    basis = 'ccpvdz',
    symmetry = True,
)
mf = scf.HF(mol).run()
mycc = cc.UCCSD(mf)
mycc.iterative_damping = 0.5
mycc.run()
print('CCSD total energy', mycc.e_tot)
```
```
TypeError   
File ~/.pyenv/versions/3.12.7/envs/main_env/lib/python3.12/site-packages/pyscf/cc/ccsd.py:80, in kernel(mycc, eris, t1, t2, max_cycle, tol, tolnormt, verbose, callback)
     78 if mycc.iterative_damping < 1.0:
     79     alpha = mycc.iterative_damping
---> 80     t1new = (1-alpha) * t1 + alpha * t1new #t1new = (1-alpha) * numpy.asarray(t1) + alpha * numpy.asarray(t1new)
     81     t2new *= alpha
     82     t2new += (1-alpha) * t2

TypeError: can't multiply sequence by non-int of type 'float'
```
The solution is to modify lines 79-82 in ccsd.py to:
```
            alpha = numpy.asarray(mycc.iterative_damping)
            t1new = (1-alpha) * numpy.asarray(t1) + alpha * numpy.asarray(t1new)
            t2new *= alpha
            t2new += (1-alpha) * numpy.asarray(t2)
```

Hints:

Fix patch:
diff --git a/pyscf/cc/ccsd.py b/pyscf/cc/ccsd.py
index 383b8a8969..59157a7481 100644
--- a/pyscf/cc/ccsd.py
+++ b/pyscf/cc/ccsd.py
@@ -76,10 +76,16 @@ def kernel(mycc, eris=None, t1=None, t2=None, max_cycle=50, tol=1e-8,
         normt = numpy.linalg.norm(tmpvec)
         tmpvec = None
         if mycc.iterative_damping < 1.0:
-            alpha = mycc.iterative_damping
-            t1new = (1-alpha) * t1 + alpha * t1new
-            t2new *= alpha
-            t2new += (1-alpha) * t2
+            alpha = numpy.asarray(mycc.iterative_damping)
+            if isinstance(t1, tuple): # e.g. UCCSD
+                t1new = tuple((1-alpha) * numpy.asarray(t1_part) + alpha * numpy.asarray(t1new_part)
+                    for t1_part, t1new_part in zip(t1, t1new))
+                t2new = tuple((1-alpha) * numpy.asarray(t2_part) + alpha * numpy.asarray(t2new_part)
+                    for t2_part, t2new_part in zip(t2, t2new))
+            else:
+                t1new = (1-alpha) * numpy.asarray(t1) + alpha * numpy.asarray(t1new)
+                t2new *= alpha
+                t2new += (1-alpha) * numpy.asarray(t2)
         t1, t2 = t1new, t2new
         t1new = t2new = None
         t1, t2 = mycc.run_diis(t1, t2, istep, normt, eccsd-eold, adiis)


Test patch:
diff --git a/pyscf/cc/test/test_uccsd.py b/pyscf/cc/test/test_uccsd.py
index a05f3bb4de..162ba47af2 100644
--- a/pyscf/cc/test/test_uccsd.py
+++ b/pyscf/cc/test/test_uccsd.py
@@ -727,6 +727,20 @@ def test_ao2mo(self):
         self.assertAlmostEqual(abs(eri_incore.OVvo - eri_outcore.OVvo).max(), 0, 12)
         self.assertAlmostEqual(abs(eri_incore.OVvv - eri_outcore.OVvv).max(), 0, 12)
 
+    def test_damping(self):
+        mol = gto.M(
+            atom = 'H 0 0 0; F 0 0 1.1',  # in Angstrom
+            basis = 'ccpvdz',
+            spin=1,
+            charge=-1,
+            symmetry = True,
+            verbose = 0
+        )
+        mf = scf.UHF(mol).run()
+        mycc = cc.UCCSD(mf)
+        mycc.iterative_damping = 0.5
+        mycc.run()
+        self.assertAlmostEqual(mycc.e_tot, -100.07710261186985, 7)
 
 if __name__ == "__main__":
     print("Full Tests for UCCSD")