Repository: pyscf/pyscf — pull request #2396 (python)
Title: Fix bug in GHF-X2C dipole function

Fix #2393 

Resolved issues:
title: ValueError in x2c dip_moment picture change with GHF and GKS
body: When I apply the .x2c() decoration method for a GHF or GKS object, calculating dipole moments always seems to raise the following:
"ValueError: could not broadcast input array from shape (3,6,6) into shape (3,2,2)"

Here is the input:
`from pyscf import gto, scf, dft

mol = gto.M(
    verbose = 0,
    atom='H 0 0 0',
    basis='STO-3G',
    spin = 1)

mf = scf.GHF(mol).x2c()
#mf = dft.GKS(mol).x2c()
mf.kernel()
mf.dip_moment()`

And here is the full error message:
`Traceback (most recent call last):
  File "---/ghf_x2c_h_atom.py", line 13, in <module>
    mf.dip_moment()
  File "---/anaconda3/envs/Python/lib/python3.12/site-packages/pyscf/x2c/x2c.py", line 785, in dip_moment
    ao_dip = self.with_x2c.picture_change((ao_dip, prp))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "---/anaconda3/envs/Python/lib/python3.12/site-packages/pyscf/x2c/x2c.py", line 338, in picture_change
    pc_mat = self._picture_change(xmol, even_operator, odd_operator)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "---/anaconda3/envs/Python/lib/python3.12/site-packages/pyscf/x2c/x2c.py", line 182, in _picture_change
    mat[:,nao:,nao:] = w_op
    ~~~^^^^^^^^^^^^^
ValueError: could not broadcast input array from shape (3,6,6) into shape (3,2,2)`


Hints:

Fix patch:
diff --git a/pyscf/x2c/x2c.py b/pyscf/x2c/x2c.py
index 4bd83298d3..d1b0e34ed6 100644
--- a/pyscf/x2c/x2c.py
+++ b/pyscf/x2c/x2c.py
@@ -774,17 +774,22 @@ def dip_moment(self, mol=None, dm=None, unit='Debye', verbose=logger.NOTE,
         charges = mol.atom_charges()
         coords  = mol.atom_coords()
         nucl_dip = numpy.einsum('i,ix->x', charges, coords)
-        with mol.with_common_orig(nucl_dip):
-            r = mol.intor_symmetric('int1e_r')
-            ao_dip = numpy.array([_block_diag(x) for x in r])
+        with mol.with_common_orig((0,0,0)):
             if picture_change:
                 xmol = self.with_x2c.get_xmol()[0]
                 nao = xmol.nao
-                prp = xmol.intor_symmetric('int1e_sprsp').reshape(3,4,nao,nao)[:,0]
-                prp = numpy.array([_block_diag(x) for x in prp])
-                ao_dip = self.with_x2c.picture_change((ao_dip, prp))
+                r = xmol.intor_symmetric('int1e_r')
+                r = numpy.array([_block_diag(x) for x in r])
+                c1 = 0.5/lib.param.LIGHT_SPEED
+                prp = xmol.intor_symmetric('int1e_sprsp').reshape(3,4,nao,nao)
+                prp = numpy.array([_sigma_dot(x*c1**2) for x in prp])
+                ao_dip = self.with_x2c.picture_change((r, prp))
+            else:
+                r = mol.intor_symmetric('int1e_r')
+                ao_dip = numpy.array([_block_diag(x) for x in r])
 
-        mol_dip = -numpy.einsum('xij,ji->x', ao_dip, dm).real
+        el_dip = numpy.einsum('xij,ji->x', ao_dip, dm).real
+        mol_dip = nucl_dip - el_dip
 
         if unit.upper() == 'DEBYE':
             mol_dip *= nist.AU2DEBYE


Test patch:
diff --git a/pyscf/x2c/test/test_x2c.py b/pyscf/x2c/test/test_x2c.py
index f1d963f88a..ddca2b3206 100644
--- a/pyscf/x2c/test/test_x2c.py
+++ b/pyscf/x2c/test/test_x2c.py
@@ -215,6 +215,7 @@ def test_ghf(self):
         mf.kernel(dm0=dm)
         self.assertTrue(mf.converged)
         self.assertAlmostEqual(mf.e_tot, ref.e_tot, 9)
+        self.assertAlmostEqual(abs(mf.dip_moment() - ref.dip_moment()).max(), 0, 9)
 
     def test_undo_x2c(self):
         mf = mol.RHF().x2c().density_fit()