Issue:
Refactor: error checks in C code and updates for GPU4PySCF library

Small updates includes:
* Error msg for basis parser.
* Error checks for malloc function in C code.
* Update libcint version due to bugs in qcint library.
* Rewrite some SCF functions for GPU4PySCF to reuse.
* Update example scf/02-ghf.py for issue #1970

---

Handle magmom in Mole serialization

Fix issue #2026 

---

DIIS with damping

## Highlight
Many of us have found SCF convergence issues for metallic systems with DIIS in PySCF even when smearing is used. By contrast, most other codes (QE, VASP, FHI-aims) do not have such a problem. The main reason is found to be the use of damping on top of DIIS in other codes. See e.g.,
- Eqn 92 in [10.1016/0927-0256(96)00008-0](https://doi.org/10.1016/0927-0256(96)00008-0) for VASP
- Eqn 43 in [10.1016/j.cpc.2009.06.022](https://doi.org/10.1016/j.cpc.2009.06.022) for FHI-aims

This PR modifies the current DIIS implementation in PySCF to enable using damping by simply
```
mf.diis_damp = 0.9
```
The SCF convergence for metallic systems is significantly improved as demonstrated in the plots below for two representative systems: ethylene carbonate adsorption on lithium and CO adsorption on copper. In both cases, the regular DIIS (black) struggles with converging SCF, while simple linear damping (blue) shows monotonic convergence at a very slow rate. By contrast, DIIS with damping (green) converges as fast as in many gapped systems.

<img width="600" alt="scf_conv_compare" src="https://github.com/pyscf/pyscf/assets/12220457/2d017f37-4835-4ba1-9901-07a422efcdc1">

Note: the `damping` function is also updated to be the simple linear damping, i.e.,
```
F = Fnew * (1-damp) + Fold * damp
```

## Math

For a fixed point problem
```
f(x) = x
```
The regular DIIS as currently employed in PySCF mixes `h` previous output vectors
```
x_{m+1} = \sum_{i=m-h}^{m} c_i f(x_i)
```
while the damped DIIS also mixes the input vectors with a factor `damp`
```
x_{m+1} = \sum_{i=m-h}^{m} c_i [ f(x_i) * (1 - damp) + x_i * damp ]
```
---
Many thanks to @tberkel, @welltemperedpaprika, and @minyez for helpful discussion and @sohangkundu and @zhutianyu1991 for suggestions on test systems.

---

UKS gradient fails w/ density fitting

Here's a minimal reproducible example, on the allyl radical: 

```
import pyscf

xyz = """ C         -0.86337805    0.49973124    0.70910031
 C          0.15258387    0.40261370   -0.20812769
 C          0.75922269   -0.77472711   -0.56700188
 H         -1.30923057    1.44465208    0.95942545
 H         -1.24385452   -0.37533224    1.20633972
 H          0.49822196    1.31479859   -0.67961425
 H          0.45403495   -1.70891595   -0.12897521
 H          1.55239964   -0.80282021   -1.29114640"""

mol = pyscf.M(
    atom=xyz,
    basis="6-31G(d)",
    charge=0,
    spin=1,
    symmetry=True
)

mf = pyscf.scf.KS(mol)
mf.xc = "B3LYP"

mf = mf.density_fit()

energy = mf.kernel()
grad = mf.Gradients().kernel()
```

When I run this (pyscf 2.4.0 py311h38a7831_1 conda-forge), I get this error:

```
Traceback (most recent call last):
  File "/Users/cwagen/business_code/pyscf/uks_grad.py", line 26, in <module>
    grad = mf.Gradients().kernel()
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/grad/rhf.py", line 415, in kernel
    de = self.grad_elec(mo_energy, mo_coeff, mo_occ, atmlst)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/grad/uhf.py", line 51, in grad_elec
    vhf = mf_grad.get_veff(mol, dm0)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/df/grad/uks.py", line 84, in get_veff
    vj, vk = ks_grad.get_jk(mol, dm)
             ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/df/grad/rhf.py", line 498, in get_jk
    return get_jk(self, mol, dm, hermi, with_j, with_k)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/df/grad/rhf.py", line 96, in get_jk
    orbol, orbor = _decompose_rdm1 (mf_grad, mol, dm)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/df/grad/rhf.py", line 359, in _decompose_rdm1
    nmo = mo_occ.shape[-1]
          ^^^^^^^^^^^^
AttributeError: 'tuple' object has no attribute 'shape'
```

It looks like there's a missing call to ``np.stack()`` somewhere? 

The code runs fine if I don't use density fitting. 

---

`WARN: len(magmom) != natm. Set magmom to zero` when running `00-input_cell.py` example.

When a `MoleBase` instance is initialized (which happens for example when a `Cell` instance is initialized), `magmom = []` https://github.com/pyscf/pyscf/blob/0e0345b751a44023c56dcdaa4f4b69075a547443/pyscf/gto/mole.py#L2328 . If no custom `magmom` is passed, this empty list doesn't pass this check https://github.com/pyscf/pyscf/blob/0e0345b751a44023c56dcdaa4f4b69075a547443/pyscf/gto/mole.py#L2582 in `build`. Should `magmom` not be initialized first and only set to `[0,] * self.natm` when in `build`?  What is the advantage of having set `magmom = []`? On first glance, it seems better not just to initialize it to an empty list, so maybe this line can simply be deleted?

---

Density Fitting + Atom Guess + ECPs Break

Here's a minimal reproducible example:

```
import pyscf

xyz = """ H    0    0    -1.403
Br   0    0    0.040"""

mol = pyscf.M(
    atom=xyz,
    basis={"H": "6-31G(d)", "Br": "LANL2DZ"},
    ecp={"Br": "LANL2DZ"},
    charge=0,
    spin=0,
    symmetry=True
)

mf = pyscf.scf.KS(mol)
mf.xc = "B3LYP"
mf.init_guess = 'atom'
mf = mf.density_fit()

energy = mf.kernel()
````

When I run this (pyscf 2.4.0 py311h38a7831_1 conda-forge), I get this error:

```
  File "/Users/cwagen/business_code/pyscf/ecp_atom_guess.py", line 21, in <module>
    energy = mf.kernel()
             ^^^^^^^^^^^
  File "<string>", line 2, in kernel
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/scf/hf.py", line 1718, in scf
    kernel(self, self.conv_tol, self.conv_tol_grad,
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/scf/hf.py", line 124, in kernel
    vhf = mf.get_veff(mol, dm)
          ^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/dft/rks.py", line 119, in get_veff
    vj, vk = ks.get_jk(mol, dm, hermi)
             ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/df/df_jk.py", line 156, in get_jk
    vj, vk = self.with_df.get_jk(dm, hermi, with_j, with_dfk,
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/df/df.py", line 239, in get_jk
    return df_jk.get_jk(self, dm, hermi, with_j, with_k, direct_scf_tol)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/miniconda3/envs/aimnet2/lib/python3.11/site-packages/pyscf/df/df_jk.py", line 268, in get_jk
    mo_coeff = mo_coeff.reshape(-1,nao,nmo)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: cannot reshape array of size 100 into shape (10,8)
```

If I don't use SAD initial guess, or I don't use density fitting, this works fine. 


---

Remove the implicit dependency to mpi4py in __init__.py (issue #1888)

---

Fix a bug for checking numpy version and two typos.

I found a bug for comparing numpy version string. String comparison is based on "alphabetical order" rules applied to digits.


---

Master

I found a bug for comparing numpy version string. String comparison is based on "alphabetical order" rules applied to digits.


---

Update dmrgnevpt2 testfile

---

MakeAngularGrid with nPoints = 1

At https://github.com/pyscf/pyscf/blob/6f8ce439fbe0c26ec4d226e2225b28c7f668f922/pyscf/lib/dft/CxLebedevGrid.c#L5094, should `case 0:` be `case 1:`? It seems like this is the case of "1 point", and we set `N = 1` just below.

---

Add method, test and example to carry out electronic coupling calculation based on mom-SCF.

Implement direct electronic coupling calculation scheme based on diabatic state calculated by mom-SCF. 


---

Master

```
Add electron number check exception for det_ovlp.
```


---

Bugfix pengdl

---

uncontracted basis 

---

Add codes and tests for calculating dipole moment calculation. Fix a doc.

Implement dipole moment calculation.


---

what is gfortran for? 

make demands access to gfortran compiler which is not on the list of dependencies.  Is there a way around this on mac OS X (el cap)?


---

Move LebedevGrid C code to Python code; fix issue #2073

---

multigrid DFT version 2

This is part of PR #1340, which allows for large supercell pure DFT energy and nuclear gradient calculations.
Current limitations:
1. Gamma-point only,
2. orthorhombic lattice systems only,
3. no MPI support.

---

A dependence problem for compiling libxc_itrf.so

Compiling libxc_itrf.so need the dependence of libxc.so which is in  deps/lib64. However, in CMakeLists.txt, the link_directories is set as :

 link_directories(${PROJECT_SOURCE_DIR}/deps/lib)

So  the link.txt in xc_itrf.dir has not correct link path. It can not find -lxc.

I added the deps/lib64 path in link_directories. But I feel it is ugly. It should have  an elegant solution?  I am not sure, maybe find_library() or target_link_libraries().  

Thank you :)


---

DFT wrapper supporting conventional DFT methods

This PR
- supports some conventional DFT methods combining XC and dispersion correction/nonlocal correction, e.g wb97m-d3bj = wb97m-v + d3bj, b3lyp-d3bj = b3lyp + d3bj
- is backward compatible. No API changes for users.
- works through `mf=rks.RKS(mol, xc='wb97m-d3bj')` only, not `mf.xc=wb97m-d3bj`. `mf.xc` is defined as the same as before. `mf.xc` and `mf.disp` are used for customizing DFT methods.
- replaces `ni.libxc.is_nlc` with `ni.is_nlc` such that `ni.is_nlc` can be customized.

---

Fix transform_ci for more than 64 orbitals

The `transform_ci` function in `pyscf/fci/addons.py` was not implemented for over 64 orbitals, leading to a runtime error.

---

Fixed small bugs in scf/addons.py

Hi there,

Here are the changes I made:

1. Fixed a small bug regarding given mu0 in the `get_occ()` function of the `_SmearingSCF` class. 
2. Still in the `get_occ()` function of the `_SmearingSCF` class: In model systems, the `mol.tot_electrons()` might not be defined, so I added a line to get electron number from `mol.nelec` if the original approach fails.
3. Added an example of running UHF for the Hubbard model.

Please let me know if this works!
Chong

---

Add tests for ndarray_pointer_2d function

---

Improve memory usage for RPA

- outcore direct RPA
- try to raise something when loading libpbc.get_Gv



---

MCSCF Doc String Default Parameters Differ From Actual Default

Doc string in `mcscf/__init__.py` [here](https://github.com/pyscf/pyscf/blob/a40064009cd3865bce6315d9f87323340e3f343c/pyscf/mcscf/__init__.py#L78-L137) has outdated default parameters as compared to `mc1step.py`. 

Doc string in `mcscf/mc1step.py` [here](https://github.com/pyscf/pyscf/blob/a40064009cd3865bce6315d9f87323340e3f343c/pyscf/mcscf/mc1step.py#L594-L626) has outdated parameters:

| attribute          | doc  | actual                        |
|--------------------|------|-------------------------------|
| `conv_tol_grad`    | 1e-4 |  `None` [but 1e-4 in kwargs]  |
| `max_stepsize`     | 0.03 | 0.02                          |
| `max_cycle_micro`  | 3    | 4                             |
| `ah_start_tol`     | 0.2  | 2.5                           |
| `ah_start_cycle`   | 2    | 3.                            |


Additionally, `max_cycle_micro_inner` and `max_ci_stepsize` do not exist anymore. 

---

More type checks in fci solver

* More type checks in FCI solver
* Fix mcscf doc string (fix #2119)

---

Improve to_gpu

The to_gpu method is changed to a more general implementation, and it is added to many modules. The new general function assumes the gpu4pyscf package has the same layout as the pyscf package.

---

bug fix for RCCSD(T) with complex orbitals

It is found that complex-orbital RCCSD(T) energy does not reduce correctly to real-orbital RCCSD(T) energy (e.g., in case of a single molecule in a large box with a single shifted k-point). This is traced back to the incorrect order of the `vooo` integrals. The correct contraction is (see eqn 2 of [10.1063/1.460359](https://doi.org/10.1063/1.460359))
```
\sum_{m} (ia|jm) T^{bc}_{mk} = \sum_{m} conj((ai|mj)) T^{bc}_{mk}
```
while PySCF currently does
```
\sum_{m} conj((ai|jm)) T^{bc}_{mk}
```
This PR fixes the said bug and adds a test.

A similar bug in the QCISD(T) code is also fixed. The UCCSD(T) and GCCSD(T) codes don't have this bug.

------
Thanks to @tberkel and @verena-neufeld for helpful discussions.

---

move static configurations from setup.py to pyproject.toml

Changes in this pull request:

- Simple package metadata is moved from setup.py to pyproject.toml where possible
- The number of parallel jobs for `cmake --build` is not hardcoded anymore in setup.py and can be set with the environment variable CMAKE_BUILD_PARALLEL_LEVEL, or MAKEFLAGS when using the makefiles generator, if a parallel build is desired. Before, changing this required editing setup.py. The conda build script is also set to -j4 so that it does not take longer.
    - Github Action runners have 16 GB RAM, and no libxc functional currently uses more than 1.6 GB RAM to compile, so there is little risk of OOM errors.
- Because `python setup.py sdist` is [not supported anymore](https://setuptools.pypa.io/en/latest/deprecated/commands.html), and in fact sometimes gives inconsistent results, it is replaced with `python -m build` as recommended by the setuptools maintainers.

Incorporates suggestions from #2132

---

debug and simplify to_gpu

- add `built` attribute in `_OmniObject`, avoid building `mol` objects
- add `to_gpu` the base class and avoid to redefine `to_gpu` in each class

---

KeyError in pyscf.pbc.df.df_jk?

With
```
from pyscf.pbc import gto, scf

cell = gto.Cell()
cell.atom='''
C 0.000000000000   0.000000000000   0.000000000000
C 1.685068664391   1.685068664391   1.685068664391
'''
cell.basis = 'gth-szv'
cell.pseudo = 'gth-pade'
cell.a = '''
0.000000000, 3.370137329, 3.370137329
3.370137329, 0.000000000, 3.370137329
3.370137329, 3.370137329, 0.000000000'''
cell.unit = 'B'
cell.verbose = 5
cell.build()

#
# KDFT and KGW with 2x2x2 k-points
#
kpts = cell.make_kpts([2,2,2])
kmf = scf.KRKS(cell, xc='pbe').density_fit()
kmf.kpts = kpts
emf = kmf.kernel()

myrhf = kmf.to_hf()
veff = myrhf.get_veff()

```

I get the following error:

```
Traceback (most recent call last):
  File "/home/chillenb/src/gwscripts/kpttest.py", line 28, in <module>
    veff = myrhf.get_veff()
           ^^^^^^^^^^^^^^^^
  File "/home/chillenb/mambaforge/envs/rttddft/lib/python3.11/site-packages/pyscf/pbc/scf/khf.py", line 541, in get_veff
    vj, vk = self.get_jk(cell, dm_kpts, hermi, kpts, kpts_band)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/chillenb/mambaforge/envs/rttddft/lib/python3.11/site-packages/pyscf/pbc/scf/khf.py", line 529, in get_jk
    vj, vk = self.with_df.get_jk(dm_kpts, hermi, kpts, kpts_band,
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/chillenb/mambaforge/envs/rttddft/lib/python3.11/site-packages/pyscf/pbc/df/df.py", line 443, in get_jk
    vk = df_jk.get_k_kpts(self, dm, hermi, kpts, kpts_band, exxdiv)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/chillenb/mambaforge/envs/rttddft/lib/python3.11/site-packages/pyscf/pbc/df/df_jk.py", line 613, in get_k_kpts
    make_kpt(ki, kj, True)
  File "/home/chillenb/mambaforge/envs/rttddft/lib/python3.11/site-packages/pyscf/pbc/df/df_jk.py", line 446, in make_kpt
    for LpqR, LpqI, sign in mydf.sr_loop((kpti,kptj), max_memory, False):
  File "/home/chillenb/mambaforge/envs/rttddft/lib/python3.11/site-packages/pyscf/pbc/df/df.py", line 355, in sr_loop
    with _load3c(self._cderi, self._dataname, kpti_kptj) as j3c:
  File "/home/chillenb/mambaforge/envs/rttddft/lib/python3.11/site-packages/pyscf/pbc/df/df.py", line 692, in __enter__
    return self.getitem(*self.kpti_kptj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/chillenb/mambaforge/envs/rttddft/lib/python3.11/site-packages/pyscf/pbc/df/df.py", line 746, in getitem
    raise KeyError(f'Key {key} not found')
KeyError: 'Key j3c/8 not found'
```


The fact that the 3c2e integrals should now be computed, and `_j_only` reset, is not getting detected. Is there a recommended way to do this manually?

Would it be bad design to add an option to scf.KRKS.density_fit() so that, if I need to calculate Vk later, I can override the default value of _j_only?


(PySCF 2.5.0 installed from conda-forge)



---

DFTD3 & DFTD4 builder

- remove the dependencies of dftd3 and dftd4 from pypi
- build dftd3 and dftd4 w/o openmp, in pyscf/dispersion
- add more unit tests for dispersion corrections

---

reset enuc in _build_supcell_

In PR #2078, the nuclear energy in periodic HF was changed from `cell.energy_nuc()` to `cell.enuc`. The latter allows reusing previously calculated nuclear energy saved in `cell._enuc`. This causes a bug when making a supercell from a unit cell where `_enuc` is already set because the supercell inherits `_enuc` from the unit cell. This PR fixes the bug.

---

Bug fix for single k-point JK-build in PBC DF

The current implementation of the single-k-point J-build in `pbc/df/df_jk/get_jk`
```
einsum('Lpq,xpq->xL', Lpq, dms)
```
is incorrect: the indices for dms should be `xqp`. This leads to incorrect Coulomb energy for SCF calculations using a single twisted angle. This PR fixed the bug and added a test requiring `df.get_jk` results to match those from `mol_hf.dot_eri_dm`.

Doing similar checks on other PBC DF modules (single k-point JK builds must match k-points JK builds), I also found a bug in the single k-point K-build in AFTDF, which was also fixed by this PR (and a test was added).

---

SMD model and PCM Hessian

- add SMD model (in fortran)
- refactor PCM models, and add PCM Hessian
- fix a bug in PCM models
- add more unit tests for solvent models
- support `to_gpu` and `to_cpu` for solvent models

---

fix: infinite recursion atom_hf call when ECP with super-heavy atoms (>Cm)

Hi devs!

A small bug fix, which is gracefully found by @X1X1010.

## Problem Description

When performing computing on super-heavy atoms (charge > 96, or > Cm), using the default `minao` with ECP, the following example code will fall into inifinite recursion:
```python
from pyscf import gto, scf
import basis_set_exchange as bse

mol = gto.Mole(
    atom="Bk", spin=5,
    basis=bse.get_basis("Stuttgart RLC", elements=["Bk"], fmt="NWChem"),
    ecp=bse.get_basis("Stuttgart RLC ECP", elements=["Bk"], fmt="NWChem")).build()
scf.UHF(mol).run()
```
The error message can be different, depending on when python stops recursion:
```
File ~/miniconda3/envs/pyscf-pip/lib/python3.10/ctypes/__init__.py:510, in cast(obj, typ)
    509 def cast(obj, typ):
--> 510     return _cast(obj, obj, typ)

ArgumentError: argument 1: RecursionError: ???
```

## Solution

Simply change the following code, make the number of electrons to be the actual one (instead of ECP truncated), then it works.

## Notes on CI tests

At the time creating this pull request, [CI tests fails](https://github.com/ajz34/pyscf/actions/runs/8833606479/job/24253310452), and that's not deliberated.
CI may probably fails in the [agf2 module](https://github.com/pyscf/pyscf/blob/6d3b24bb64e2a5edb7990b6e3304068981a33f54/pyscf/agf2/test/test_c_agf2.py#L39-L46) (deviation at 2e-10). This code involves (seeded) random array.

~~I will try to run CI test again and see whether all tasks passes.~~ It fails again. I bet that's because the version of tested MacOS (14.4 instead of 12.7), without any sound evidence.

---

improve DFT APIs

Added functionalities
- Enhance DFT methods with dispersion correction, such as `mf = rks.RKS(mol, xc='wb97m-d3bj')`. 
- Support the customization of DFT methods via specifying the attributes of mean-field objects
  - Disable nlc contributions with `mf.nlc = False`.
  - Specify DFT xc methods and dispersion correction with `mf.xc='b3lyp'` and `mf.disp = 'd3bj'`. 
  - Specify DFT xc method with `mf.xc='b3lyp-d3bj'`.


---

move auxbasis_response out of __init__

---

Run CASCI and CASSCF without symmetry if symmetry is C1

Fixes #2194 

---

Very strange bug when pyscf deal with ANO-like full segmented basis in DFT calculation


[pyscf_bug_input.txt](https://github.com/pyscf/pyscf/files/15206636/pyscf_bug_input.txt)
Hi all,

I have found a Very strange bug when pyscf deal with ANO-like full segmented basis in DFT calculation.

Below is the input file:
```
from pyscf import gto, scf, mp
import numpy as np
from pyscf.geomopt.geometric_solver import optimize
from pyscf.mp.dfmp2_native import DFRMP2
from pyscf.mp.dfump2_native import DFUMP2

x2c_dyall_aeqz = gto.basis.parse("""
#########  Au  dyall_aeqz
#########   34   30   19   14   10    5    1
ANO-like
""")

x2c_dyall_aeqz_dc = gto.basis.parse("""
######### Au dyall_aeqz
######### 34 30 19 14 10 5 1
Au  S
   6.209103150000000E+07  1.000000000000000E+00
Au  S
   1.653101960000000E+07  1.000000000000000E+00
Au  S
   5.666622670000000E+06  1.000000000000000E+00
Au  S
   2.162568840000000E+06  1.000000000000000E+00
Au  S
   9.042883170000000E+05  1.000000000000000E+00
Au  S
   4.004710760000000E+05  1.000000000000000E+00
Au  S
   1.861301960000000E+05  1.000000000000000E+00
Au  S
   8.940102720000000E+04  1.000000000000000E+00
Au  S
   4.411686720000000E+04  1.000000000000000E+00
Au  S
   2.225786780000000E+04  1.000000000000000E+00
Au  S
   1.146669210000000E+04  1.000000000000000E+00
Au  S
   6.023272710000000E+03  1.000000000000000E+00
Au  S
   3.225023020000000E+03  1.000000000000000E+00
Au  S
   1.762350660000000E+03  1.000000000000000E+00
Au  S
   9.863889450000000E+02  1.000000000000000E+00
Au  S
   5.698000400000000E+02  1.000000000000000E+00
Au  S
   3.474391230000000E+02  1.000000000000000E+00
Au  S
   2.185944320000000E+02  1.000000000000000E+00
Au  S
   1.372532670000000E+02  1.000000000000000E+00
Au  S
   8.486206360000000E+01  1.000000000000000E+00
Au  S
   5.206830770000000E+01  1.000000000000000E+00
Au  S
   3.296204500000000E+01  1.000000000000000E+00
Au  S
   2.056422680000000E+01  1.000000000000000E+00
Au  S
   1.235418440000000E+01  1.000000000000000E+00
Au  S
   7.564121700000000E+00  1.000000000000000E+00
Au  S
   4.573992500000000E+00  1.000000000000000E+00
Au  S
   2.739648970000000E+00  1.000000000000000E+00
Au  S
   1.545869700000000E+00  1.000000000000000E+00
Au  S
   8.598988410000000E-01  1.000000000000000E+00
Au  S
   4.582615130000000E-01  1.000000000000000E+00
Au  S
   2.430874440000000E-01  1.000000000000000E+00
Au  S
   1.215257330000000E-01  1.000000000000000E+00
Au  S
   6.089330790000000E-02  1.000000000000000E+00
Au  S
   3.018529570000000E-02  1.000000000000000E+00
Au  P
   5.755348480000000E+07  1.000000000000000E+00
Au  P
   1.691248560000000E+07  1.000000000000000E+00
Au  P
   5.377806840000000E+06  1.000000000000000E+00
Au  P
   1.839687300000000E+06  1.000000000000000E+00
Au  P
   6.670125919999999E+05  1.000000000000000E+00
Au  P
   2.541515750000000E+05  1.000000000000000E+00
Au  P
   1.012219880000000E+05  1.000000000000000E+00
Au  P
   4.203473500000000E+04  1.000000000000000E+00
Au  P
   1.819664630000000E+04  1.000000000000000E+00
Au  P
   8.217448700000001E+03  1.000000000000000E+00
Au  P
   3.870391550000000E+03  1.000000000000000E+00
Au  P
   1.897150890000000E+03  1.000000000000000E+00
Au  P
   9.642372070000000E+02  1.000000000000000E+00
Au  P
   5.054206470000000E+02  1.000000000000000E+00
Au  P
   2.718612890000000E+02  1.000000000000000E+00
Au  P
   1.492447710000000E+02  1.000000000000000E+00
Au  P
   8.314046279999999E+01  1.000000000000000E+00
Au  P
   4.713148250000000E+01  1.000000000000000E+00
Au  P
   2.722911550000000E+01  1.000000000000000E+00
Au  P
   1.567590180000000E+01  1.000000000000000E+00
Au  P
   8.829868830000001E+00  1.000000000000000E+00
Au  P
   4.991040060000000E+00  1.000000000000000E+00
Au  P
   2.757979600000000E+00  1.000000000000000E+00
Au  P
   1.502152200000000E+00  1.000000000000000E+00
Au  P
   8.009997030000000E-01  1.000000000000000E+00
Au  P
   4.161589730000000E-01  1.000000000000000E+00
Au  P
   1.885710550000000E-01  1.000000000000000E+00
Au  P
   8.755511780000000E-02  1.000000000000000E+00
Au  P
   4.063389780000000E-02  1.000000000000000E+00
Au  P
   1.875527470000000E-02  1.000000000000000E+00
Au  D
   7.308519500000001E+04  1.000000000000000E+00
Au  D
   1.748346500000000E+04  1.000000000000000E+00
Au  D
   5.791219250000000E+03  1.000000000000000E+00
Au  D
   2.295507860000000E+03  1.000000000000000E+00
Au  D
   1.023437670000000E+03  1.000000000000000E+00
Au  D
   4.950643630000000E+02  1.000000000000000E+00
Au  D
   2.533670530000000E+02  1.000000000000000E+00
Au  D
   1.352569120000000E+02  1.000000000000000E+00
Au  D
   7.416643759999999E+01  1.000000000000000E+00
Au  D
   4.151001110000000E+01  1.000000000000000E+00
Au  D
   2.340297360000000E+01  1.000000000000000E+00
Au  D
   1.309012410000000E+01  1.000000000000000E+00
Au  D
   7.243630750000000E+00  1.000000000000000E+00
Au  D
   3.959147190000000E+00  1.000000000000000E+00
Au  D
   2.093719000000000E+00  1.000000000000000E+00
Au  D
   1.065585580000000E+00  1.000000000000000E+00
Au  D
   5.192894430000000E-01  1.000000000000000E+00
Au  D
   2.399383640000000E-01  1.000000000000000E+00
Au  D
   1.027115780000000E-01  1.000000000000000E+00
Au  F
   8.210167799999999E+03  1.000000000000000E+00
Au  F
   1.598452870000000E+03  1.000000000000000E+00
Au  F
   5.402367050000000E+02  1.000000000000000E+00
Au  F
   2.301503290000000E+02  1.000000000000000E+00
Au  F
   1.104482570000000E+02  1.000000000000000E+00
Au  F
   5.653591940000000E+01  1.000000000000000E+00
Au  F
   3.005511950000000E+01  1.000000000000000E+00
Au  F
   1.626524220000000E+01  1.000000000000000E+00
Au  F
   8.716937700000001E+00  1.000000000000000E+00
Au  F
   4.540748730000000E+00  1.000000000000000E+00
Au  F
   2.222080920000000E+00  1.000000000000000E+00
Au  F
   9.696551560000000E-01  1.000000000000000E+00
Au  F
   3.870026460000000E-01  1.000000000000000E+00
Au  F
   1.544580600000000E-01  1.000000000000000E+00
Au  G
   5.807258000000000E+02  1.000000000000000E+00
Au  G
   1.545337600000000E+02  1.000000000000000E+00
Au  G
   5.994404600000000E+01  1.000000000000000E+00
Au  G
   3.253628400000000E+01  1.000000000000000E+00
Au  G
   1.222618200000000E+01  1.000000000000000E+00
Au  G
   4.659343800000000E+00  1.000000000000000E+00
Au  G
   2.927018800000000E+00  1.000000000000000E+00
Au  G
   1.838765160000000E+00  1.000000000000000E+00
Au  G
   7.021073710000000E-01  1.000000000000000E+00
Au  G
   2.680901100000000E-01  1.000000000000000E+00
Au  H
   1.074946400000000E+02  1.000000000000000E+00
Au  H
   2.286925400000000E+01  1.000000000000000E+00
Au  H
   8.296031299999999E+00  1.000000000000000E+00
Au  H
   1.400449750000000E+00  1.000000000000000E+00
Au  H
   5.347426199999999E-01  1.000000000000000E+00
Au  I
   1.516653600000000E+01  1.000000000000000E+00
""")

x2c_jkc_small_k = gto.basis.parse("""
......
""")

mol = gto.M(atom='''
                 Au
                 Au 1 2.510
                 ''',
                symmetry='dooh',
                basis=x2c_dyall_aeqz, spin=0, charge=0, verbose=9)

mf3 = scf.RKS(mol).x2c().density_fit(auxbasis=x2c_jkc_small_k)
#mf3 = scf.RHF(mol).x2c().density_fit(auxbasis=x2c_jkc_small_k)
mf3.xc = 'PBE'
mf3.conv_tol = 1e-8
mf3.max_cycle = 20
mf3.conv_check = False
mf3.grids.atom_grid = {'Au': (192, 590)}
mf3.kernel()
```

**x2c_dyall_aeqz** means general contraction ANO-like full segmented basis sets with NWCHEM format,
 **x2c_dyall_aeqz_dc** full segmented contraction basis sets with NWCHEM format. These two basis sets should/must be identical exactly.

However, if one use the **x2c_dyall_aeqz** to a DFT calculation,  **pyscf** would give a error:
```
.......
tot_boxes 1053, boxes in each direction [11  7  7]
Padding 0 grids
tot grids = 108720
free(): invalid next size (normal)
free(): invalid next size (normal)
free(): invalid next size (normal)
double free or corruption (!prev)
Aborted (core dumped)
```

Bud if you use **x2c_dyall_aeqz_dc**, the DFT calculation will run smoothy.
Then if you run HF calculations with **x2c_dyall_aeqz** , the code is also good without error.

I have also checked full ANO basis like ANO-RCC basis sets, the DFT calculations with these ANO-RCC basis sets are good without error, So it seems this error/bug only comes with  DFT calculations/ANO-like full segmented basis sets.

The above calculations under pyscf 2.5.0/conda version/Ubuntu 22.04

---

improve the consistency in DF modules

- Use the same linear dependence threshold in DF modules, SCF, Gradient, and Hessian.
- Add conv_tol_cpscf in mf to control the convergence of CPSCF.
- Remove the repeated definitions of grid_response in RKS and UKS.

---

Density fitting performance optimization (re issue #1915)

This pull request incorporates enhancements to density fitting proposed in #1915 by @ajz34 .

- Replace unoptimized `np.einsum` with `gemm` via `numpy.matmul`
- Replace `scipy.linalg.triangular_solve` with `?trsm` in order to avoid a single-threaded array transpose and related issues surrounding Fortran vs C order
- Since with trsm, setting `overwrite_b=True` actually _does_ cause `b` to get overwritten, we have to use `map` rather than `lib.map_with_prefetch` when writing the cderi chunks to disk
- Use of `read_direct` in `_load_from_h5g` avoids an unnecessary copy and reads the data right where they need to go

The test case is the same as in the issue: [here](https://github.com/pyscf/pyscf/files/13063667/benchmark_code.py.txt)

Benchmark, 48 cores cascade lake (CPU: 2x 24-core Intel Xeon Gold 6252N)
PySCF compiled with gcc. NumPy installed from conda-forge along with Intel MKL.

1087 cGTOs
| Task | Before | After |
| --- | --- | --- |
| density fitted RHF | 87.5568 s |  31.4202 s |
| CPU time for cholesky_eri | 25.96 s | 8.41 s |
| CPU time for df vj and vk  | 31.67 s |  11.24 s |
| `df.outcore.cholesky_eri_b` | 11.8159 s |  4.2692 s |
| `df.outcore.cholesky_eri` | 22.12 s |  10.08 s |


---

Restore functionality for CDFT example

I'm sure this example worked when it was authored, but that is no longer the case. This patch restores functionality.

Line 200 would raise if the number of alpha and beta restrictions was different. The separated2sum() method rightly allows for this, so I just take the real part of each channel separately.

---

Fix frozen for FNO

In the previous implementation of `FNOCCSD`, the input `frozen` argument was not passed to the MP2 calculation used to generate FNOs. The FNOs generated this way are okay but the ∆MP2 composite correction is wrong. This PR fixes the bug. 

See the figure below for the convergence of the FNOCCSD correlation energy for benzene/cc-pVDZ with carbon 1s electrons being frozen. The uncorrected FNOCCSD energy from the old code is okay compared to the new one, but only the new PT2-corrected energy converges to the correct limit.

![fno_cmp](https://github.com/pyscf/pyscf/assets/12220457/2d8f9749-768c-4247-ae51-917d97478058)

The `make_fno` function was rewritten to handle general `frozen` (integer or list) for both RMP2 and UMP2. Tests are added for both.


NOTE: for UMP2, the natural orbital occupation number for each spin is multiplied by 2 (see [this line](https://github.com/pyscf/pyscf/pull/2217/files#diff-2413d646fb7c38c96523d14de45c6e41aae20d8f32021f21b52af8121fa8810bR318)) so that when the same `thresh` is used, RHF and UHF based FNO calculations generate the same results. I believe that this is a nice behavior but suggestions are appreciated.


---

allow passing in options when creating HDF5 files

I am trying to add a way to specify extra options when creating HDF5 files, and this is a first attempt. It hasn't been tested. Are there cleaner / more consistent ways to do it?

---

Choice of basis sets for multi-grid density fitting (NaCl)

Hi all,

Can someone please shed some light on why this simple test crashes? This is pretty much based on `examples/pbc/27-multigrid.py`, but I might easily still be doing something very stupid.

```
#!/usr/bin/env python

import numpy as np
from pyscf.pbc import df, dft, gto
from pyscf.pbc.dft import multigrid

cell = gto.Cell()
cell.atom = 'Cl 0 0 1; Na 0 1 0'
cell.a = np.eye(3) * 4.
cell.basis = 'gth-dzvp'
cell.pseudo = 'gth-pbe'
cell.verbose = 4
cell.build()

mf = dft.KRKS(cell)
mf.xc = 'pbe'
mf.with_df = multigrid.MultiGridFFTDF(cell)
mf.verbose = 4
mf.kernel()
```

I'm getting the following traceback:

```
******** PBC SCF flags ********
N kpts = 1
Exchange divergence treatment (exxdiv) = ewald
    madelung (= occupied orbital energy shift) = 0.3753582916854765
    Total energy shift due to Ewald probe charge = -1/2 * Nelec*madelung = -3.00286633348
DF object = <pyscf.pbc.dft.multigrid.MultiGridFFTDF object at 0x19f261b50>
XC functionals = pbe
small_rho_cutoff = 1e-07
Uniform grid, mesh = [113 113 113]
<class 'pyscf.pbc.dft.krks.KRKS'> does not have attributes  nlcgrids nlc
Set gradient conv threshold to 0.000316228
Traceback (most recent call last):
  File "/Users/janus/calculations/pyscf/pbc/test_multigrid.py", line 19, in <module>
    mf.kernel()
  File "<string>", line 2, in kernel
  File "/Users/janus/programs/pyscf/pyscf/scf/hf.py", line 1691, in scf
    kernel(self, self.conv_tol, self.conv_tol_grad,
  File "/Users/janus/programs/pyscf/pyscf/scf/hf.py", line 127, in kernel
    h1e = mf.get_hcore(mol)
  File "/Users/janus/programs/pyscf/pyscf/pbc/scf/khf.py", line 99, in get_hcore
    nuc = lib.asarray(mf.with_df.get_pp(kpts))
  File "/Users/janus/programs/pyscf/pyscf/pbc/dft/multigrid.py", line 385, in get_pp
    vpp = _get_j_pass2(mydf, vpplocG, hermi, kpts_lst)[0]
  File "/Users/janus/programs/pyscf/pyscf/pbc/dft/multigrid.py", line 856, in _get_j_pass2
    t_cell, coeff = t_cell.to_uncontracted_cartesian_basis()
  File "/Users/janus/programs/pyscf/pyscf/gto/mole.py", line 559, in to_uncontracted_cartesian_basis
    return decontract_basis(mol, to_cart=True)
  File "/Users/janus/programs/pyscf/pyscf/gto/mole.py", line 634, in decontract_basis
    lmax = mol._bas[ib0:ib1,ANG_OF].max()
  File "/Users/janus/anaconda3/envs/my-rdkit-env/lib/python3.9/site-packages/numpy/core/_methods.py", line 39, in _amax
    return umr_maximum(a, axis, None, out, keepdims, initial, where)
ValueError: zero-size array to reduction operation maximum which has no identity
```

HEAD is at 6eb7542afc713 from yesterday. Thanks in advance.

---

Some classmethods defined elsewhere cannot be called normally

1. `mf = mol.X2C_KS()` does not work with an AttributeError like this
```python
>>> from pyscf import gto
>>> mol = gto.M(atom='Li', basis='sto-3g', spin=1)
>>> mf = mol.X2C_KS()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/share/home/liuxx/miniconda3/lib/python3.12/site-packages/pyscf/gto/mole.py", line 3735, in __getattr__
    raise AttributeError(f'Mole object has no attribute {key}')
AttributeError: Mole object has no attribute X2C_KS. Did you mean: 'X2C_HF'?
```
though the attribute I've found is defined in https://github.com/pyscf/pyscf/blob/7d94887d2ca817287226c51371845037f4469325/pyscf/dft/__init__.py#L120-L128.
It's worth noting that `mol.X2C_KS()` could be normally called without any errors raised if PySCF is manually built from source.

2. Similarly, `mf.gen_response()` in X2C-SCF approach cannot be called either, and it says there's no attribute 'gen_response' found,
```python
>>> from pyscf import gto
>>> mol = gto.M(atom='Li', basis='sto-3g', spin=1)
>>> mf = mol.X2C()
>>> mf.kernel()

WARN: HOMO -0.0463389858396905 == LUMO -0.0463389858347049

converged SCF energy = -7.31595504150337
-7.3159550415033685
>>> mf.gen_response()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'UHF' object has no attribute 'gen_response'
```
while it occurs in https://github.com/pyscf/pyscf/blob/7d94887d2ca817287226c51371845037f4469325/pyscf/x2c/_response_functions.py#L23-L31.

---

change default basis linear dependence threshold

1e-9 -> 1e-7

---

Inconsistent Default Units and Lack of Specification in Examples

Your default use of Angstroms for the mol specification (https://pyscf.org/user/gto.html) is entirely reasonable and uses the canonical unit across computational chemistry packages...Yay!
However, in all of your documentation about optimization (https://pyscf.org/user/geomopt.html, https://github.com/pyscf/pyscf/blob/master/examples/geomopt/01-pyberny.py, etc) where you then get the final coordinates using mol_eq.atom_coords() the default unit has now changed to Bohr for this one output, despite every optimization step outputting results in Angstroms. 
This is just downright confusing and quite difficult to track down as there would be no reason to expect a sudden unannounced change to the default units. 

I suggest two remedy options:
1. Make the default for the .atom_coords() function consistent with the angstrom default used everywhere else.
or 
2. Update your tutorial documentation to specify in the code comments by the function usage that the default unit is Bohr and how to change it to Angstrom.

That will hopefully save other people the hour it took me to track down this inconsistency.

Thanks.

---

Density fitting with range separated functional ωB97X fails with HDF IO error.

Running a range separated hybrid functional with density fitting fails with a `KeyError` from HDF IO: `"Unable to synchronously open object (object '352' doesn't exist)"`.


### Reproducer

<details><summary>Input</summary>

````python
from pyscf import gto, dft

# System from S66x8
mol = gto.M(
    atom=[
        ('N', [ 2.60196602,  1.58689273,  1.94191269]),
        ('H', [ 1.98763739,  2.61958343,  3.43239769]),
        ('C', [ 2.47361884,  2.75433218, -0.43022260]),
        ('O', [ 1.73960886,  4.93422189, -0.62925184]),
        ('N', [ 3.80103848, -2.29263143,  0.36834387]),
        ('H', [ 3.26409657,  1.87242132, -4.38228352]),
        ('C', [ 3.82808790, -1.31746269, -2.02466467]),
        ('H', [ 4.34167788, -2.62872251, -3.50100927]),
        ('C', [ 3.23995879,  1.11860033, -2.49348649]),
        ('H', [ 4.02408528, -4.16027159,  0.66106423]),
        ('C', [ 3.11038534, -0.91690641,  2.47877135]),
        ('O', [ 2.95008174, -1.83646680,  4.57842857]),
        ('N', [-2.60196602, -1.58689273,  1.94191269]),
        ('H', [-1.98763739, -2.61958343,  3.43239769]),
        ('C', [-2.47361884, -2.75433218, -0.43022260]),
        ('O', [-1.73960886, -4.93422189, -0.62925184]),
        ('N', [-3.80103848,  2.29263143,  0.36834387]),
        ('H', [-3.26409657, -1.87242132, -4.38228352]),
        ('C', [-3.82808790,  1.31746269, -2.02466467]),
        ('H', [-4.34167788,  2.62872251, -3.50100927]),
        ('C', [-3.23995879, -1.11860033, -2.49348649]),
        ('H', [-4.02408528,  4.16027159,  0.66106423]),
        ('C', [-3.11038534,  0.91690641,  2.47877135]),
        ('O', [-2.95008174,  1.83646680,  4.57842857]),
    ],
    charge=0,
    spin=0,
    basis="def2-qzvp",
    unit="Bohr",
    max_memory=4000,
    verbose=4,
)

ks = dft.KS(mol, xc="wb97x").density_fit()
ks.kernel()
````
</details>


### Logs

<details><summary>Output</summary>

````
System: uname_result(system='Linux', node='saw2210', release='5.15.146.1-microsoft-standard-WSL2', version='#1 SMP Thu Jan 11 04:09:03 UTC 2024', machine='x86_64')  Threads 4
Python 3.10.13 | packaged by conda-forge | (main, Dec 23 2023, 15:36:39) [GCC 12.3.0]
numpy 1.23.5  scipy 1.11.4
Date: Fri May 31 12:05:44 2024
PySCF version 2.5.0
PySCF path  /home/sehlert/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf

[CONFIG] conf_file None
[INPUT] verbose = 4
[INPUT] num. atoms = 24
[INPUT] num. electrons = 116
[INPUT] charge = 0
[INPUT] spin (= nelec alpha-beta = 2S) = 0
[INPUT] symmetry False subgroup None
[INPUT] Mole.unit = Bohr
[INPUT] Symbol           X                Y                Z      unit          X                Y                Z       unit  Magmom
[INPUT]  1 N      1.376901121372   0.839747468891   1.027615941144 AA    2.601966020000   1.586892730000   1.941912690000 Bohr   0.0
[INPUT]  2 H      1.051812410361   1.386223853260   1.816346636362 AA    1.987637390000   2.619583430000   3.432397690000 Bohr   0.0
[INPUT]  3 C      1.308982718630   1.457529820960  -0.227663995543 AA    2.473618840000   2.754332180000  -0.430222600000 Bohr   0.0
[INPUT]  4 O      0.920561364627   2.611077777811  -0.332985733657 AA    1.739608860000   4.934221890000  -0.629251840000 Bohr   0.0
[INPUT]  5 N      2.011422941446  -1.213208305795   0.194919181786 AA    3.801038480000  -2.292631430000   0.368343870000 Bohr   0.0
[INPUT]  6 H      1.727285519086   0.990842691785  -2.319004570574 AA    3.264096570000   1.872421320000  -4.382283520000 Bohr   0.0
[INPUT]  7 C      2.025736878079  -0.697171231785  -1.071406403119 AA    3.828087900000  -1.317462690000  -2.024664670000 Bohr   0.0
[INPUT]  8 H      2.297516991251  -1.391060046124  -1.852654320904 AA    4.341677880000  -2.628722510000  -3.501009270000 Bohr   0.0
[INPUT]  9 C      1.714512355988   0.591937802764  -1.319496226245 AA    3.239958790000   1.118600330000  -2.493486490000 Bohr   0.0
[INPUT] 10 H      2.129454224975  -2.201520916666   0.349820125470 AA    4.024085280000  -4.160271590000   0.661064230000 Bohr   0.0
[INPUT] 11 C      1.645945039108  -0.485205976718   1.311709309501 AA    3.110385340000  -0.916906410000   2.478771350000 Bohr   0.0
[INPUT] 12 O      1.561116027159  -0.971816379171   2.422800061069 AA    2.950081740000  -1.836466800000   4.578428570000 Bohr   0.0
[INPUT] 13 N     -1.376901121372  -0.839747468891   1.027615941144 AA   -2.601966020000  -1.586892730000   1.941912690000 Bohr   0.0
[INPUT] 14 H     -1.051812410361  -1.386223853260   1.816346636362 AA   -1.987637390000  -2.619583430000   3.432397690000 Bohr   0.0
[INPUT] 15 C     -1.308982718630  -1.457529820960  -0.227663995543 AA   -2.473618840000  -2.754332180000  -0.430222600000 Bohr   0.0
[INPUT] 16 O     -0.920561364627  -2.611077777811  -0.332985733657 AA   -1.739608860000  -4.934221890000  -0.629251840000 Bohr   0.0
[INPUT] 17 N     -2.011422941446   1.213208305795   0.194919181786 AA   -3.801038480000   2.292631430000   0.368343870000 Bohr   0.0
[INPUT] 18 H     -1.727285519086  -0.990842691785  -2.319004570574 AA   -3.264096570000  -1.872421320000  -4.382283520000 Bohr   0.0
[INPUT] 19 C     -2.025736878079   0.697171231785  -1.071406403119 AA   -3.828087900000   1.317462690000  -2.024664670000 Bohr   0.0
[INPUT] 20 H     -2.297516991251   1.391060046124  -1.852654320904 AA   -4.341677880000   2.628722510000  -3.501009270000 Bohr   0.0
[INPUT] 21 C     -1.714512355988  -0.591937802764  -1.319496226245 AA   -3.239958790000  -1.118600330000  -2.493486490000 Bohr   0.0
[INPUT] 22 H     -2.129454224975   2.201520916666   0.349820125470 AA   -4.024085280000   4.160271590000   0.661064230000 Bohr   0.0
[INPUT] 23 C     -1.645945039108   0.485205976718   1.311709309501 AA   -3.110385340000   0.916906410000   2.478771350000 Bohr   0.0
[INPUT] 24 O     -1.561116027159   0.971816379171   2.422800061069 AA   -2.950081740000   1.836466800000   4.578428570000 Bohr   0.0

nuclear repulsion = 1161.46958672045
number of shells = 352
number of NR pGTOs = 1496
number of NR cGTOs = 1152
basis = def2-qzvp
ecp = {}
CPU time:       643.32


******** <class 'pyscf.df.df_jk.DFRKS'> ********
method = DFRKS
initial guess = minao
damping factor = 0
level_shift factor = 0
DIIS = <class 'pyscf.scf.diis.CDIIS'>
diis_start_cycle = 1
diis_space = 8
diis_damp = 0
SCF conv_tol = 1e-09
SCF conv_tol_grad = None
SCF max_cycles = 50
direct_scf = False
chkfile to save SCF result = /tmp/tmpea6snclz
max_memory 4000 MB (current use 4668 MB)
XC library pyscf.dft.libxc version 6.2.2
    S. Lehtola, C. Steigemann, M. J.T. Oliveira, and M. A.L. Marques.,  SoftwareX 7, 1–5 (2018)
XC functionals = wb97x
    J.-D. Chai and M. Head-Gordon.,  J. Chem. Phys. 128, 084106 (2008)
radial grids: 
    Treutler-Ahlrichs [JCP 102, 346 (1995); DOI:10.1063/1.469408] (M4) radial grids
    
becke partition: Becke, JCP 88, 2547 (1988); DOI:10.1063/1.454033
pruning grids: <function nwchem_prune at 0x7f123555cdc0>
grids dens level: 3
symmetrized grids: False
atomic radii adjust function: <function treutler_atomic_radii_adjust at 0x7f123555cca0>
small_rho_cutoff = 1e-07
Set gradient conv threshold to 3.16228e-05
Initial guess from minao.
tot grids = 304640
******** <class 'pyscf.df.df.DF'> ********
auxbasis = None
max_memory = 4000
Default auxbasis def2-qzvp-jkfit is used for H def2-qzvp
Default auxbasis def2-qzvp-jkfit is used for N def2-qzvp
Default auxbasis def2-qzvp-jkfit is used for O def2-qzvp
Default auxbasis def2-qzvp-jkfit is used for C def2-qzvp
_cderi_to_save = /tmp/tmpautj_2sb
Create RSH-DF object <pyscf.df.df.DF object at 0x7f120dd26a70> for omega=0.3
******** <class 'pyscf.df.df.DF'> ********
auxbasis = auxmol.basis = {'H': 'def2-qzvp-jkfit', 'N': 'def2-qzvp-jkfit', 'O': 'def2-qzvp-jkfit', 'C': 'def2-qzvp-jkfit'}
max_memory = 4000
Default auxbasis def2-qzvp-jkfit is used for H def2-qzvp
Default auxbasis def2-qzvp-jkfit is used for N def2-qzvp
Default auxbasis def2-qzvp-jkfit is used for O def2-qzvp
Default auxbasis def2-qzvp-jkfit is used for C def2-qzvp
_cderi_to_save = /tmp/tmpautj_2sb
init E= -833.585842895839
  HOMO = -0.254622262220667  LUMO = -0.0488112477693612
````
</details>

<details><summary>Error</summary>

````python
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[1], line 39
      3 mol = gto.M(
      4     atom=[
      5         ('N', [ 2.60196602,  1.58689273,  1.94191269]),
   (...)
     35     verbose=4,
     36 )
     38 ks = dft.KS(mol, xc="wb97x").density_fit()
---> 39 ks.kernel()

File <string>:2, in kernel(self, dm0, **kwargs)

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/scf/hf.py:1779, in SCF.scf(self, dm0, **kwargs)
   1774 self.build(self.mol)
   1776 if self.max_cycle > 0 or self.mo_coeff is None:
   1777     self.converged, self.e_tot, \
   1778             self.mo_energy, self.mo_coeff, self.mo_occ = \
-> 1779             kernel(self, self.conv_tol, self.conv_tol_grad,
   1780                    dm0=dm0, callback=self.callback,
   1781                    conv_check=self.conv_check, **kwargs)
   1782 else:
   1783     # Avoid to update SCF orbitals in the non-SCF initialization
   1784     # (issue #495).  But run regular SCF for initial guess if SCF was
   1785     # not initialized.
   1786     self.e_tot = kernel(self, self.conv_tol, self.conv_tol_grad,
   1787                         dm0=dm0, callback=self.callback,
   1788                         conv_check=self.conv_check, **kwargs)[1]

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/scf/hf.py:180, in kernel(mf, conv_tol, conv_tol_grad, dump_chk, dm0, callback, conv_check, **kwargs)
    178 mo_occ = mf.get_occ(mo_energy, mo_coeff)
    179 dm = mf.make_rdm1(mo_coeff, mo_occ)
--> 180 vhf = mf.get_veff(mol, dm, dm_last, vhf)
    181 e_tot = mf.energy_tot(dm, h1e, vhf)
    183 # Here Fock matrix is h1e + vhf, without DIIS.  Calling get_fock
    184 # instead of the statement "fock = h1e + vhf" because Fock matrix may
    185 # be modified in some methods.

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/dft/rks.py:119, in get_veff(ks, mol, dm, dm_last, vhf_last, hermi)
    117     vk += vhf_last.vk
    118 else:
--> 119     vj, vk = ks.get_jk(mol, dm, hermi)
    120     vk *= hyb
    121     if omega != 0:

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/df/df_jk.py:155, in _DFHF.get_jk(self, mol, dm, hermi, with_j, with_k, omega)
    152     vj, vk = scf.ghf.get_jk(mol, dm, hermi, with_j, with_dfk,
    153                             jkbuild, omega)
    154 else:
--> 155     vj, vk = self.with_df.get_jk(dm, hermi, with_j, with_dfk,
    156                                  self.direct_scf_tol, omega)
    157 if with_k and not with_dfk:
    158     vk = super().get_jk(mol, dm, hermi, False, True, omega)[1]

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/df/df.py:239, in DF.get_jk(self, dm, hermi, with_j, with_k, direct_scf_tol, omega)
    235 def get_jk(self, dm, hermi=1, with_j=True, with_k=True,
    236            direct_scf_tol=getattr(__config__, 'scf_hf_SCF_direct_scf_tol', 1e-13),
    237            omega=None):
    238     if omega is None:
--> 239         return df_jk.get_jk(self, dm, hermi, with_j, with_k, direct_scf_tol)
    241     # A temporary treatment for RSH-DF integrals
    242     with self.range_coulomb(omega) as rsh_df:

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/df/df_jk.py:290, in get_jk(dfobj, dm, hermi, with_j, with_k, direct_scf_tol)
    288 blksize = max(4, int(min(dfobj.blockdim, max_memory*.3e6/8/nao**2)))
    289 buf = numpy.empty((blksize*nao,nao))
--> 290 for eri1 in dfobj.loop(blksize):
    291     naux, nao_pair = eri1.shape
    292     assert (nao_pair == nao*(nao+1)//2)

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/df/df.py:216, in DF.loop(self, blksize)
    213         b0, b1 = aux_slice
    214         return numpy.asarray(feri[b0:b1])
--> 216 for dat in lib.map_with_prefetch(load, self.prange(0, naoaux, blksize)):
    217     yield dat
    218     dat = None

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/lib/misc.py:375, in map_with_prefetch(func, *iterables)
    373     future = executor.submit(func, *task)
    374 else:
--> 375     result = future.result()
    376     future = executor.submit(func, *task)
    377     yield result

File ~/software/opt/conda/envs/pyscf/lib/python3.10/concurrent/futures/_base.py:458, in Future.result(self, timeout)
    456     raise CancelledError()
    457 elif self._state == FINISHED:
--> 458     return self.__get_result()
    459 else:
    460     raise TimeoutError()

File ~/software/opt/conda/envs/pyscf/lib/python3.10/concurrent/futures/_base.py:403, in Future.__get_result(self)
    401 if self._exception:
    402     try:
--> 403         raise self._exception
    404     finally:
    405         # Break a reference cycle with the exception in self._exception
    406         self = None

File ~/software/opt/conda/envs/pyscf/lib/python3.10/concurrent/futures/thread.py:58, in _WorkItem.run(self)
     55     return
     57 try:
---> 58     result = self.fn(*self.args, **self.kwargs)
     59 except BaseException as exc:
     60     self.future.set_exception(exc)

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/df/df.py:209, in DF.loop.<locals>.load(aux_slice)
    207 def load(aux_slice):
    208     b0, b1 = aux_slice
--> 209     return _load_from_h5g(feri, b0, b1)

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/ao2mo/outcore.py:484, in _load_from_h5g(h5group, row0, row1, out)
    482 nkeys = len(h5group)
    483 dat = h5group['0']
--> 484 ncol = sum(h5group[str(key)].shape[-1] for key in range(nkeys))
    485 if dat.ndim == 2:
    486     out = numpy.ndarray((row1-row0, ncol), dat.dtype, buffer=out)

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/pyscf/ao2mo/outcore.py:484, in <genexpr>(.0)
    482 nkeys = len(h5group)
    483 dat = h5group['0']
--> 484 ncol = sum(h5group[str(key)].shape[-1] for key in range(nkeys))
    485 if dat.ndim == 2:
    486     out = numpy.ndarray((row1-row0, ncol), dat.dtype, buffer=out)

File h5py/_objects.pyx:54, in h5py._objects.with_phil.wrapper()

File h5py/_objects.pyx:55, in h5py._objects.with_phil.wrapper()

File ~/software/opt/conda/envs/pyscf/lib/python3.10/site-packages/h5py/_hl/group.py:357, in Group.__getitem__(self, name)
    355         raise ValueError("Invalid HDF5 object reference")
    356 elif isinstance(name, (bytes, str)):
--> 357     oid = h5o.open(self.id, self._e(name), lapl=self._lapl)
    358 else:
    359     raise TypeError("Accessing a group is done with bytes or str, "
    360                     "not {}".format(type(name)))

File h5py/_objects.pyx:54, in h5py._objects.with_phil.wrapper()

File h5py/_objects.pyx:55, in h5py._objects.with_phil.wrapper()

File h5py/h5o.pyx:189, in h5py.h5o.open()

KeyError: "Unable to synchronously open object (object '352' doesn't exist)"
````
</details>

### Versions

````
ipython                   8.19.0             pyh707e725_0    conda-forge
numpy                     1.23.5          py310h53a5b5f_0    conda-forge
python                    3.10.13         hd12c33a_1_cpython    conda-forge
pyscf                     2.5.0           py310h322b0e4_0    conda-forge
scipy                     1.11.4          py310hb13e2d6_0    conda-forge
````

---

Is there a formal error in the H_cc sector of newton_casscf.gen_g_hop?

In differentiating with respect to an infinitesimal transformation of the CI vectors, we parameterize the energy as

<a href="https://www.codecogs.com/eqnedit.php?latex=E(x)=\langle0|e^{-\hat{P}}\hat{H}e^{\hat{P}}|0\rangle" target="_blank"><img src="https://latex.codecogs.com/gif.latex?E(x)=\langle0|e^{-\hat{P}}\hat{H}e^{\hat{P}}|0\rangle" title="E(x)=\langle0|e^{-\hat{P}}\hat{H}e^{\hat{P}}|0\rangle" /></a>

with

<a href="https://www.codecogs.com/eqnedit.php?latex=\hat{P}\equiv\sum_{\vec{n}}|\vec{n}\rangle\langle0|-|0\rangle\langle\vec{n}|" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\hat{P}\equiv\sum_{\vec{n}}x_{\vec{n}}(|\vec{n}\rangle\langle0|-|0\rangle\langle\vec{n}|)" title="\hat{P}\equiv\sum_{\vec{n}}x_{\vec{n}}(|\vec{n}\rangle\langle0|-|0\rangle\langle\vec{n}|)" /></a>

The second derivative of the energy is

<a href="https://www.codecogs.com/eqnedit.php?latex=\frac{\partial^2&space;E}{\partial&space;x_{\vec{n}}\partial&space;x_{\vec{n}^\prime}}=\langle\vec{n}|\hat{Q}(\hat{H}-E_0)\hat{Q}|\vec{n}^\prime\rangle" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\frac{\partial^2&space;E}{\partial&space;x_{\vec{n}}\partial&space;x_{\vec{n}^\prime}}=\langle\vec{n}|\hat{Q}(\hat{H}-E_0)\hat{Q}|\vec{n}^\prime\rangle" title="\frac{\partial^2 E}{\partial x_{\vec{n}}\partial x_{\vec{n}^\prime}}=\langle\vec{n}|\hat{Q}(\hat{H}-E_0)\hat{Q}|\vec{n}^\prime\rangle" /></a>

with

<a href="https://www.codecogs.com/eqnedit.php?latex=\hat{Q}\equiv1-|0\rangle\langle0|" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\hat{Q}\equiv1-|0\rangle\langle0|" title="\hat{Q}\equiv1-|0\rangle\langle0|" /></a>
<a href="https://www.codecogs.com/eqnedit.php?latex=E_0\equiv\langle0|\hat{H}|0\rangle" target="_blank"><img src="https://latex.codecogs.com/gif.latex?E_0\equiv\langle0|\hat{H}|0\rangle" title="E_0\equiv\langle0|\hat{H}|0\rangle" /></a>

or, if we can forgive a bit of notational handwaving,

<a href="https://www.codecogs.com/eqnedit.php?latex=\partial^2&space;E|\vec{x}\rangle=(\hat{H}-E_0)|\vec{x}\rangle-|0\rangle\langle0|(\hat{H}-E_0)|\vec{x}\rangle-(\hat{H}-E_0)|0\rangle\langle0|\vec{x}\rangle" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\partial^2&space;E|\vec{x}\rangle=(\hat{H}-E_0)|\vec{x}\rangle-|0\rangle\langle0|(\hat{H}-E_0)|\vec{x}\rangle-(\hat{H}-E_0)|0\rangle\langle0|\vec{x}\rangle" title="\partial^2 E|\vec{x}\rangle=(\hat{H}-E_0)|\vec{x}\rangle-|0\rangle\langle0|(\hat{H}-E_0)|\vec{x}\rangle-(\hat{H}-E_0)|0\rangle\langle0|\vec{x}\rangle" /></a>

But what's programmed in newton_casscf.py appears to be

<a href="https://www.codecogs.com/eqnedit.php?latex=\partial^2&space;E|\vec{x}\rangle=(\hat{H}-E_0)|\vec{x}\rangle-2|0\rangle\langle0|(\hat{H}-E_0)|\vec{x}\rangle-2(\hat{H}-E_0)|0\rangle\langle0|\vec{x}\rangle" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\partial^2&space;E|\vec{x}\rangle=(\hat{H}-E_0)|\vec{x}\rangle-2|0\rangle\langle0|(\hat{H}-E_0)|\vec{x}\rangle-2(\hat{H}-E_0)|0\rangle\langle0|\vec{x}\rangle" title="\partial^2 E|\vec{x}\rangle=(\hat{H}-E_0)|\vec{x}\rangle-2|0\rangle\langle0|(\hat{H}-E_0)|\vec{x}\rangle-2(\hat{H}-E_0)|0\rangle\langle0|\vec{x}\rangle" /></a>

in both hop and hdiag. I would understand a factor of 2 convention difference (EDIT: actually all three of my second-derivative expressions up there should have a +h.c. that I dropped), but this isn't a factor of 2, unless I've gotten confused about what (H-E0) is. In fact, it spoils intermediate normalization (we should have <0|x>=0 at all times; the component of P along the trial vector |0> is undefined by construction):

```
import numpy
from pyscf import gto, scf, lib, fci
from pyscf.mcscf import newton_casscf, CASSCF, addons

mol = gto.Mole()
mol.verbose = lib.logger.DEBUG
mol.output = '/dev/null'
mol.atom = [
    ['H', ( 5.,-1.    , 1.   )],
    ['H', ( 0.,-5.    ,-2.   )],
    ['H', ( 4.,-0.5   ,-3.   )],
    ['H', ( 0.,-4.5   ,-1.   )],
    ['H', ( 3.,-0.5   ,-0.   )],
    ['H', ( 0.,-3.    ,-1.   )],
    ['H', ( 2.,-2.5   , 0.   )],
    ['H', ( 1., 1.    , 3.   )],
]
mol.basis = 'sto-3g'
mol.build()
mf = scf.RHF(mol)
mf.max_cycle = 3
mf.kernel()
mc = newton_casscf.CASSCF(mf, 4, 4)
mc.fcisolver = fci.direct_spin1.FCI(mol)
mc.kernel()

numpy.random.seed(1)
mo = numpy.random.random(mf.mo_coeff.shape)
ci0 = numpy.random.random((6,6))
ci0/= numpy.linalg.norm(ci0)
gall, gop, hop, hdiag = newton_casscf.gen_g_hop(mc, mo, ci0, mc.ao2mo(mo))
x = numpy.random.random(gall.size)
hx = hop (x)
print ("|hx_ci| =",numpy.linalg.norm (hx[-36:]),"<0|hx> =", ci0.ravel ().dot (hx[-36:]))
```

yields

```
|hx_ci| = 73.30773999100957 <0|hx> = 4.13369273110702
```

I think this has minimal effects on the results of calculations because 1) the extract_rotation function forcibly normalizes the new output CI vector after every Newton-CG step, and the s10 business in the H_oc sector corrects for the effect of the spurious <0|x> component on the orbitals, so all this does is attenuate CI vector evolution almost like a trust radius, and 2) the coupled-perturbed solver for the state-average analytical gradient calculation that I added has a preconditioner that enforces <0|x> = 0 post hoc. But I wanted to ask about it to see if I was missing something, especially since changing it would make at least one test fail.



---

DF dataset naming issue for rsh xc (fix #2236)

---

bugfix in dispersion hessian

- Fixed a bug in dispersion hessian
- Added unit tests for the consistency of DFT apis

---

Abandon ROHF gradients and ROHF hessian

For issue #2250 

---

Issue calculating static polarizability using RSH exchange-correlation functionals

Hello, everyone. I need to have access and freedom to work with the A and B matrices from coupled-perturbed KS. So, I'm trying to use the following code together with the CAM-B3LYP functional for static polarizability. However, the code doesn't work for this functional or any other RSH tested. It is curious since the code works properly for any other XC functionals, e.g., GGA, Hybrids, etc. I see someone with a similar issue and the fix was to change from LibXC to XCfun. But, this is not working for me. Can someone help me, please?

Results using the attached code:
Static polarizability from reference: 1.4907486930182852 (the right answer)
Static polarizability is: 1.3051766863495733

PS1: I also tried "a, b = tddft.TDDFT(mf).get_ab()". I still have the same issue with RSHs.

PS2: Using "rks.Polarizability(mf).polarizability()" works with RSH functionals (that's how I debug the results, i.e., reference). However, I don't know how to or if I have access to A and B using this code.

Thanks.

[cpks.zip](https://github.com/user-attachments/files/15873707/cpks.zip)


---

Add ruff check

Also updates the legacy code due to numpy 2.0 release and cleans up tests (issue #2260)

---

Update doc strings

---

Improve pypi build pipeline

Ensures the docker job runs last

---

Update BFD pseudo potential and bases

The existing BFD pp and bases are poor for H and alkali elements. They can be updated using the one developed by Burkatzki, Claudia, and Michael Dolg


---

Cannot import name 'bulk' from 'ase.lattice'

I just tried to call the member function `from_ase()` with `ase 3.23.0` and `pyscf 2.6.1` and got an error. I guess `ase` has changed the lattice module. Simply removing the import works, as the function `bulk` is not used anywhere in `pyscf_ase.py`.

https://github.com/pyscf/pyscf/blob/d4ce357503bc865d43a956c8f540f8c0f38ef5cb/pyscf/pbc/tools/pyscf_ase.py#L27

---

Updates due to NumPy 2.0 API changes

* Fix all calls to `np.unqiue` when parameter `axis` and `return_inverse` are both specified
* Fix all calls to `np.array` with `copy=False`

---

Fix wheel build for setuptools 70

---

Remove the ase module bulk from pyscf_ase (fix #2271)

Fix pyscf_ase (fix #2271)
Fix the TDDFT get_ab method for RSH functions (fix #2261)

---

Bug fix for PBC DF

Two bugs are fixed in this PR:
1. In PR #[1620](https://github.com/pyscf/pyscf/pull/1620), the default behavior of Mole was changed to sort the input basis sets by angular momentum for each atom, which makes `mol._bas` and `mol._basis` not necessarily agree with each other. The mismatch causes bugs in various places in `pbc/df/rsdf_helper.py`, leading to inaccurate DF integrals when using RSDF. This PR fixes the bug. A minimal demo is provided below.
2. The PBC DF-based J-build has a bug in [L129](https://github.com/pyscf/pyscf/blob/master/pyscf/pbc/df/df_jk.py#L129). When an non-Hermitian density matrix is input, the J matrix is not Hermitian and aosymm must be False in the DF loop function. This leads to failure in e.g., k-based TDDFT calculations. This PR fixes the bug.

PBE total energy for water in a box (details below) with different DF methods.
| DF methods | Energy |
| ------------ | ------- |
| RSDF (before fix) | -76.3338831107 |
| RSDF (after fix) | -76.3338642530 |
| GDF (RS builder) | -76.3338642530 |
| GDF (CC builder) | -76.3338642530 |

``` Python
atom = '''
O          0.00000        0.00000        0.11779
H          0.00000        0.75545       -0.47116
H          0.00000       -0.75545       -0.47116
'''
basis = 'cc-pvdz'
a = np.eye(3) * 6
kmesh = [3,1,1]
cell = gto.M(atom=atom, a=a, basis=basis)
cell.precision = 1e-12
```

---

Fix integer overflow for large ano basis

Fix #2201

---

Fix addons.smearing RHF electron number

Fixes #2289.

---

Possible bug in get_init_guess_cyl_sym

Hi everyone,

I have identified a possible bug in the get_init_guess_cyl_sym function in fci/direct_spin1_symm. It seems like simple linear open-shell systems in small active spaces targeting higher spin states, e.g., the example in examples/mcscf/18-o2_spatial_spin_symmetry.py, crash with the following error:
`RuntimeError: Initial guess for symmetry 1 not found`

As far as I can tell the issue is in line 303:
```
if wfnsym in (1, 4) and addra == addra1 and addrb == addrb1:
    continue
```

If I interpret the code correctly, the vertical mirror plane which switches the $\pi_x$ and $\pi_y$ orbitals is applied to the possible determinant candidates. Whenever the desired wavefunction is antisymmetric with respect to this vertical mirror plane (wavefunction irreps with a „-„ exponent, wfnsym is 1 or 4), the determinant candidates that will produce the same determinant when the $\pi_x$- and $\pi_y$-orbitals are switched will be skipped.

Looking at the $\mathrm{O}_2$ example, there are three possible states that can arise from the double occupation of the antibonding $\pi$-orbitals: $^3\Sigma_g^-$, $^1\Sigma_g^+$ and $^1\Delta_g$. The $^3\Sigma_g^-$ state can be described by two high-spin determinants with $S_z=-1$ and $S_z=+1$ and by the difference of two low-spin determinants, resulting in the $S_z=0$ state. The $^1\Sigma_g^+$ state can be described by the sum of the two low-spin determinants. 

Switching the $\pi_x$ and $\pi_y$ orbitals for the low-spin determinants will transform one to the other while the high-spin determinants are invariant to this operation. 

It appears that targeting the $^3\Sigma_g^-$ state in the $S_z=-1$ and $S_z=+1$ manifolds will trigger line 303 and therefore not find the correct guess determinant. It does however appear to work when targeting the triplet state through the $S_z=0$ manifold because line 303 is not triggered.

So summarizing:
$^3\Sigma_g^-$ state with $S_z=\pm1$: `wfnsym in (1, 4) and addra == addra1 and addrb == addrb1`
$^3\Sigma_g^-$ state with $S_z=0$: `wfnsym in (1, 4) and addra != addra1 and addrb != addrb1`
$^1\Sigma_g^+$ state: `wfnsym in (0, 5) and addra != addra1 and addrb != addrb1`

It could be changed to:
```
if wfnsym in (0, 5) and addra == addra1 and addrb == addrb1:
    continue
```
I am not sure if that was the intention though. On the other hand this would cause issues for closed-shell systems (e.g., $\mathrm{N}_2$). Therefore I think the two lines should just be removed?

When an additional virtual orbital is added to the active space (CAS(6, 5)), the calculation does not crash but it constructs the "wrong" guess determinant which doubly occupies the virtual orbital and includes one set of high-spin $\pi$-orbitals and one set of low-spin $\pi$-orbitals. This is a determinant from an excited $^3\Sigma_g^-$ CSF.

Targeting a different symmetry state, e.g., the $^3\Sigma_u^-$ state in 18-spatial_spin_symmetry.py, does work because in this state the $\pi_x$ and $\pi_y$ orbitals are differently occupied and therefore: `addra != addra1 and addrb != addrb1`.

On another note, I think the first section of example 18-o2_spatial_spin_symmetry.py is also no longer up to date since the fci module does produce the correct wfnsym through _id_wfnsym.

Please let me know if I have misinterpreted anything.

---

PySCF >=v2.2.1 fci.direct_spin1 davidson solver issue

Hello

I have the following minimal example using FCI to solve a given Hamiltonian which produces an error when using a PySCF version greater than or equal to v2.2.1.
``` python
from pyscf import fci
import numpy as np

norb=4
nelec=(2, 2)
nroots=36 # (4 choose 2)*(4 choose 2)

e = -0.5
t = -0.1
h1 = np.array([[e, t, 0, 0],
               [t, e, t, 0],
               [0, t, e, t],
               [0, 0, t, e],
              ])

U = 0.1
h2 = np.zeros((norb, norb, norb, norb))
for i in range(norb):
    h2[i,i,i,i] = U

e, fcivec = fci.direct_spin1.kernel(h1, h2, norb, nelec, nroots=nroots, max_space=30, max_cycle=100,
                                    davidson_only=True,
                                   )

print("Energies:", e)
```

The error message:
``` bash
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 257, in kernel
    return _kfactory(FCISolver, h1e, eri, norb, nelec, ci0, level_shift,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 281, in _kfactory
    e, c = cis.kernel(h1e, eri, norb, nelec, ci0, ecore=ecore, **unknown)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 842, in kernel
    e, c = kernel_ms1(self, h1e, eri, norb, nelec, ci0, link_index,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 612, in kernel_ms1
    e, c = fci.eig(hop, ci0, precond, tol=tol, lindep=lindep,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 810, in eig
    lib.davidson1(lambda xs: [op(x) for x in xs],
  File "/lib/python3.11/site-packages/pyscf/lib/linalg_helper.py", line 388, in davidson1
    x0 = x0()
         ^^^^
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 580, in init_guess
    return fci.get_init_guess(norb, nelec, nroots, hdiag)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 829, in get_init_guess
    return get_init_guess(norb, nelec, nroots, hdiag)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 469, in get_init_guess
    return _get_init_guess(na, nb, nroots, hdiag, nelec)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/pyscf/fci/direct_spin1.py", line 444, in _get_init_guess
    addrs = numpy.argpartition(lib.pack_tril(hdiag), nroots-1)[:nroots]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/numpy/_core/fromnumeric.py", line 908, in argpartition
    return _wrapfunc(a, 'argpartition', kth, axis=axis, kind=kind, order=order)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/lib/python3.11/site-packages/numpy/_core/fromnumeric.py", line 57, in _wrapfunc
    return bound(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^^
ValueError: kth(=35) out of bounds (21)
```

I have only encountered this error with versions of PySCF >=v2.2.1, the versions before that run with the correct output. I believe the issue is related to `davidson_only=True` as setting `davidson_only=False` for >=v2.2.1 also does not produce an error.

Is this a bug with the davidson solver?

Thanks!

---

Fix Hessian atmlst and example

- fixed the problem in running `examples/hessian/01-scf_hessian.py`;
- add the `atmlst` option to `examples/hessian/01-scf_hessian.py` and `examples/grad/01-scf_grad.py`;
- fixed the problem when `atmlst` option is specified for `Hessian` objects. 

---

Implement another variant of the Hückel guess 

Implements another variant of the Hückel guess based on the updated GWH rule from [doi:10.1021/ja00480a005](https://doi.org/10.1021/ja00480a005)

---

allow modifying tol and nroots in stability

* allow user modifying Davidson solver tolerance in stability. It is important to use tight tol for some hard cases, as shown in the example. And this is part of #1416.
* allow user modifying nroots of Davidson solver of stability and set the default value to 3 instead of 1, as suggested and tested by #1587.
* print the eigenvalues by default (at verbose 4). So the user can see if the current eigenvalues is close to zero.

---

Superposition of Atomic Potentials (SAP) initial guess implementation for HF-SCF calculations

Added VSAP (superposition of atomic potentials) initial guess implementation for Hartree-Fock SCF calculations (described by S. Lehtola here: https://doi.org/10.1021/acs.jctc.8b01089)
Modified fakemol_for_charges to be usable for SAP 3C2E (three-center two-electron) integrals.
Supplied sap_grasp coefficients computed by S. Lehtola to the basis sets.

---

contract_2e gives inconsistent results on complex vector

The following code generates a two-body tensor and a random complex-valued FCI vector, and then contracts the two-body tensor with the vector in two ways:
- Directly using `contract_2e`
- Using `contract_2e` on the real and imaginary parts of the vector and adding the results

These should give the same result, but they don't.

```python
import math

import numpy as np
import pyscf
import pyscf.mcscf
from pyscf.fci.direct_nosym import absorb_h1e, contract_2e

# Generate a two-body tensor
mol = pyscf.gto.Mole()
mol.build(
    atom=[["H", (0, 0, 0)], ["H", (1.0, 0, 0)]],
    basis="sto-6g",
    symmetry="Dooh",
    verbose=0,
)
scf = pyscf.scf.RHF(mol).run()
n_electrons = int(sum(scf.mo_occ))
n_alpha = (n_electrons + mol.spin) // 2
n_beta = (n_electrons - mol.spin) // 2
nelec = (n_alpha, n_beta)
norb = mol.nao_nr()
cas = pyscf.mcscf.CASCI(scf, norb, nelec)
h1e, _ = cas.get_h1cas()
h2e = cas.get_h2cas()
eri = absorb_h1e(h1e, h2e, norb, nelec, 0.5)

# Generate a random state vector
rng = np.random.default_rng(1234)
dim = math.comb(norb, n_alpha) * math.comb(norb, n_beta)
vec = rng.standard_normal(dim) + 1j * rng.standard_normal(dim)
vec /= np.linalg.norm(vec)

# Contract directly
result = contract_2e(eri, vec, norb, nelec)
# Contract real and imaginary parts separately
result_alt = contract_2e(eri, vec.real, norb, nelec) + 1j * contract_2e(
    eri, vec.imag, norb, nelec
)

print(np.allclose(result, result_alt))
print(np.linalg.norm(result - result_alt))
```
```
False
1.0875338674395465
```

---

[Ready for review] Complete implementation of pbc/tdscf

This PR completes the implementation of the `pbc/tdscf` module (thanks to @tberkel and @xwang862 for helpful discussions):
1. Support for non-zero particle-hole momentum transfer for `GDF/RSDF` (same as the `kshift` used in pbc eom-ee-ccsd)
2. Support for twisted boundary conditions (both single k-point and  k-point mesh).
4. Fix finite-size correction (1/Nk convergence to TDL and agreement with molecular code).
5. Add tests and examples.

Regarding the finite-size correction, one can show (thanks to @tberkel for discussion) that the TDSCF equations are independent of treatment of the Coulomb singularity at G = 0. As a result, one should either include or exclude such treatments everywhere. The existing pbc tdscf code (see issue #[1187](https://github.com/pyscf/pyscf/issues/1187)) uses `exxdiv = None` for the J/K build, but does not remove the Madelung constant shift in the occupied orbital energy when `exxdiv = 'ewald'`. The new implementation forces the removal of the latter inside the tdscf code. Doing so leads to `1/Nk` convergence of pbc excitation energies to the TDL as well as agreement with molecular excitation energies. This also applies to hybrid DFT. Non-hybrid DFT, which already satisfies these, is not affected by this change as no exxdiv treatment is needed.

A small change was made to the molecular `tdscf` module's init guess (which applies to pbc as well). The previous implementation uses a fixed tolerance of 1e-6 Ha for selecting degenerate particle-hole pairs as init guess vectors. This threshold is too tight and can miss roots beyond the first root. The new implementation increases the default value to 1e-3 Ha and allows user to alter it via the `deg_eia_thresh` variable. If the number of init vectors generated this way exceeds `nroots`, `trunc_workspace` is called to truncate the working space to `nroots` before entering the Davidson solver. An example is added `example/tdscf/04-tddft_missing_roots.py`.

Two questions:
1. To allow for non-Gamma single k-point calculations, I have to comment out `assert (mo_coeff.dtype == numpy.double)` a few places in the molecular code (`tdscf/rhf.py` and `tdscf/rks.py`). I checked that all existing linear algebra is correct in terms of `.conj()` and needs no changes. But I am not so sure about other parts, e.g., blocks that check and operate on symmetry. Please let me know if there are potential conflicts.
2. For a KS-DFT reference, the following two sanity checks do not pass for all xc functionals.
- First, there are two ways of running TDDFT that should give the same answer:
```
td1 = mf.TDDFT().run()
```
calls the specialized `CasidaTDDFT` code while
```
from pyscf.tdscf import rhf   # similar for pbc.tdscf.rhf and pbc.tdscf.krhf
td2 = rhf.TDHF(mf).run()
```
calls the `TDHF` code.
- Second, as box size becomes large, pbc code (both single k-point or k-points) should reproduce the molecular code results.

This [script](https://github.com/pyscf/pyscf/files/11995573/test_tddft.py.zip) examines the two sanity checks for different xc's and the results are summarized below. One can see that both the molecular code (column 1) and the k-points pbc code (column 5-7) are good, but the single k-point code (column 2-4) is problematic and this depends on xc. My suspect is that `fxc` term is calculated differently in the molecular code and the pbc code but I am not so sure.

(`mtd`, `std`, and `ktd` means molecular, single-kpt, and k-point code; `1` and `2` label the two different ways of running TDDFT calculations; `True` if two codes predict excitation energies < 0.01 eV)
| xc | `mtd1.e == mtd2.e` | `std1.e == std2.e` | `std1.e == mtd1.e` | `std2.e == mtd1.e` | `ktd1.e == ktd2.e` | `ktd1.e == mtd1.e` | `ktd2.e == mtd1.e` |
| -- | -------------------- | ------------------ | ------------------ | ------------------- | ------------------ | ----------- | ---|
| LDA | True | True | True | True | True | True | True |
| PBE | True | False | True | False | True | True | True |
| BLYP | True | False | True | False | True | True | True |
| PBE0 | True | True | False | False | True | True | True |
| B3LYP | True | True | True | True | True | True | True |

---

scipy version comparison line behavior

https://github.com/pyscf/pyscf/blob/beb7b1bcb40dec578392322d20126826f2d3e6ad/pyscf/grad/lagrange.py#L195

This evaluates to "True" if the scipy version is between 1.2 and 1.10, which seems like not the desired behavior. Is there a reason these aren't casted to integers for the comparison?

---

CCSD doesn't clean up temporary files

**Steps to reproduce**

1. Create `repro.py`:
```python
import pyscf
import pyscf.cc

mol = pyscf.gto.Mole()
mol.build(
    atom=[("H", (0, 0, 0)), ("H", (1, 0.0, 0.0))], basis="sto-6g", symmetry="Dooh"
)
scf = pyscf.scf.RHF(mol).run()
ccsd = pyscf.cc.RCCSD(scf).run()
```
2. Run it with the temporary directory set to the current directory.
```bash
TMPDIR="." python repro.py
```
3. Observe your current directory being filled with temporary files, even after the program has exited. E.g.
```
% ls
4yuc0gzd  6gm1i18c  bitvow4s  jfn4rd0w  lhuqcsi6  ny3jxku8  qthivsd4  repro.py  riuvukmw  rqan75l7
```

---

Selected CI gives wrong results for a CAS of (2,2)

Dear developers,

I was trying to use selected CI as my CASCI solver by looking at the following example: https://github.com/pyscf/pyscf.github.io/blob/master/examples/mcscf/50-casscf_with_selected_ci.py

However, the selected CI results were wrong when I choose a CAS of (2,2):
```
from pyscf import gto, scf, mcscf, fci

b = 1.2
mol = gto.M(
    atom = 'N 0 0 0; N 0 0 %f'%b,
    basis = 'cc-pvdz',
)
mf = scf.RHF(mol).run()
mc = mcscf.CASCI(mf, 2, 2).run()

#
# Use SCI (Selected CI) to replace fcisolver
#
mc = mcscf.CASCI(mf, 2, 2)
mc.fcisolver = fci.SCI(mol)
mc.kernel() 
```

Here are the results. I am using pyscf version `2.1.1`
```
converged SCF energy = -108.914051975052

CASCI E = -108.94356411985  E(CI) = -1.71486588690826  S^2 = 0.0000000

CASCI E = -108.914051975052  E(CI) = -1.68535374211038  S^2 = 0.0000000
```
The selected CI seems to have only the doubly occupied determinant and misses the other doubly excited determinant. I know this is an edge case but thought of bringing this to your attention nevertheless. Thanks!


---

Use weakref for automatic deletion of tmpfiles (to fix #2318)

This is intended to fix #2318 using weakref-based finalizers (see the example in https://docs.python.org/3/library/weakref.html)

---

Fix bug in symm cas methods

These methods might raise error if `mo_coeff` not given.

---

added NVT BOMD and example

This PR adds NVT ensemble to the md module. I have implemented the Berendsen thermostat.

---

Fix to kscf for dft

`pyscf.pbc.scf.addons.convert_to_kscf` is not updating `_numint` to k-points version.

---

Fix MP2 FNO bug when pct_occ=1

When MP2 FNOs are made using kwarg `pct_occ=1`, not all virtuals are included due to a floating point comparison of `1<1`. This bugfix ensures that all virtuals are included in this limiting case.

---

GHF with fractional occupancy

* Allow GHF run with fractional occupancy.
* Remove unused code in X2C
* Fix setup.py

---

fix some typos (found using codespell)

Just fixing some typos, and not all of them. There are many everywhere.

---

some fixes for rst syntax in the doc of tdscf

this fixes all issues with `rst` syntax in the doc of `tdscf` folder

---

some pep8 fixes as suggested by pycodestyle

just fixing a few of the most rare warnings issued by `pycodestyle`

see #1833



---

Fix the edge case CAS(2,2) for Selected CI (issue #1808)

---

Error in PBC 2D GDF build

We've been getting errors when running KRHF calculations in 2D with GDF on the latest master; the same errors aren't present when run on v2.3.0. I've since noticed the same error occurs in the examples `pbc/31-low_dimensional_pbc.py` and `pbc/32-graphene.py` (both also when running 2D GDF).

MWE is
```
import numpy as np
import pyscf
import pyscf.pbc
import pyscf.pbc.scf

a = 2*np.eye(3)
a[2,2] = 15.0
dimension = 2
kmesh=[2,2,1]

cell = pyscf.pbc.gto.Cell()
cell.atom = 'H 0 0 0 ; H 0 0 0.74'
cell.a = a
cell.basis = "def2-svp"
cell.verbose=4
cell.dimension = dimension
cell.build()

kpts = cell.make_kpts(kmesh)

# Hartree-Fock with GDF
mf = pyscf.pbc.scf.KRHF(cell, kpts)
mf = mf.density_fit(auxbasis="def2-svp-ri")
mf.kernel()
```
which gives the exception during the DF build of 
```
  File "/home/charlie/miniconda3/envs/pyscf_test/lib/python3.11/site-packages/pyscf/pbc/df/df.py", line 337, in load
    LpqR = lib.unpack_tril(LpqR).reshape(naux,nao**2)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: cannot reshape array of size 100 into shape (27,100)
```
Swapping out both the basis and auxbasis for STO-3G gives a different but I'm guessing related error at the same point
```
  File "/home/charlie/miniconda3/envs/pyscf_test/lib/python3.11/site-packages/pyscf/lib/numpy_helper.py", line 715, in ddot
    return _dgemm(trans_a, trans_b, m, n, k, a, b, c, alpha, beta)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/charlie/miniconda3/envs/pyscf_test/lib/python3.11/site-packages/pyscf/lib/numpy_helper.py", line 841, in _dgemm
    c[:] = 0
    ~^^^
ValueError: assignment destination is read-only
```

Any help on this would be appreciated; I can't see any interface changes in the interrim!
Cheers,
Charlie


---

New features and code refactoring

Add new features:
* multi-collinear functional for PBC DFT
* non-local functional (VV10) for PBC DFT
* "undo" method for dynamic classes. This method can revert the action for conversion methods such as "density_fit()", "x2c()", "newton()", "as_scanner()", etc.
* Merged basis parser for molecular GTO basis and GTH basis. GTH basis can be assigned to Mole object directly.
* Merged ECP  and PP parser. PP can be assigned to Mole object directly.

Refactor:
* The layout of the Mole class and Cell class. Remove the inheritance between Cell and Mole.
* The layout of various SCF classes and the conversion methods (to_ks, to_hf, to_uhf, to_ghf, etc.) between different SCF objects.
* The layout of various MCSCF classes.
* New style to generate dynamic class for DF methods, X2C, QMMM, SOSCF, Solvent model, StateAverageMCSCF, Scanner methods, etc.
* SCF smearing method.
* Make Mole and Cell object picklable (issue #1801, #1806)
* Fix various deprecated warnings from numpy

---

Newton casscf hcc (issue #701)

This merge request fixes the errors in mcscf.newton_casscf.gen_g_hop in the calculation of the CI vector second derivative of the (state-averaged) energy [here](https://github.com/pyscf/pyscf/blob/master/pyscf/mcscf/newton_casscf.py#L296-L313) as described in issue #701. The newton_casscf algorithm does not directly use the CI trial vector computed by the gradient-descent step using this function to update the result CI vector without first running the actual FCI kernel, and the coupling between the orbital and CI degrees of freedom likewise used a robust expression that had the effect of canceling the erroneous contribution, so these errors did not lead to erroneous results in the sense that converged MC-SCF calculations were always correctly converged. This fix should therefore not change the outcome of any calculations in which the MC-SCF iteration converges to the correct stationary point, and the only unittest changes are to meaningless arbitrary reference points. However, this fix does cause the function to finally _do what it says it does,_ which IMO is important. For completeness, and since my original issue page used a third-party plugin for equations that may not render correctly for everyone, I now repeat the derivation using the native markdown latex support.

The first and second derivatives of an expectation value such as the with respect to some sort of unitary transformation are obtained by expressing the unitary operator as the exponential of the corresponding antihermitian unitary group generators,

$$
E = \langle 0|e^{-\hat{G}} \hat{H} e^{\hat{G}}|0\rangle
$$

For the CI vector part of an MC-SCF wave function in pyscf.mcscf.newton_casscf.py, the Hamiltonian-vector product is functionally abstracted, so we don't need to think too hard about the form of $\hat{G}$; we can just use the basic bra-ket language and the definition of antihermiticity:

$$
\hat{G} = \sum_{I} g_I (|I\rangle\langle0| - |0\rangle\langle I|) = |\vec{g}\rangle\langle 0| - |0\rangle\langle\vec{g}|
$$

It follows after some straightforward tedium that the first and second derivatives with respect to the generators are

$$
\frac{\partial E}{\partial g_I} = \langle I|\hat{H} - E_0|0\rangle + \textrm{h.c.}
$$

$$
\frac{\partial^2 E}{\partial g_I\partial g_J} = \langle I|\hat{Q}(\hat{H}-E_0)\hat{Q}|J\rangle + \textrm{h.c.}
$$

with

$$
\hat{Q} = 1 - |0\rangle\langle 0| ; E_0 = \langle 0|\hat{H}|0\rangle
$$

Using that $\langle 0|\hat{H}-E_0|0\rangle=0$ and that for real wave functions $\langle I|0\rangle = \langle 0|I\rangle = c_I$, the CI vector for the keyframe state $|0\rangle$, the second derivative is expanded as

$$
\frac{\partial^2 E}{\partial g_I\partial g_J} = \langle I|\hat{H}-E_0|J\rangle -\frac{1}{2}(c_I\frac{\partial E}{\partial g_J} + \frac{\partial E}{\partial g_I}c_J) + \textrm{h.c.}
$$

Note that "+ h.c." in both the first and second derivatives are accounted for by factors of 2 [here](https://github.com/pyscf/pyscf/blob/master/pyscf/mcscf/newton_casscf.py#L303) and [here](https://github.com/pyscf/pyscf/blob/master/pyscf/mcscf/newton_casscf.py#L384) that are applied at the end of the calculation. This means that `gci` at [this](https://github.com/pyscf/pyscf/blob/master/pyscf/mcscf/newton_casscf.py#L296C15-L296C15) point in the function stores $\frac{1}{2}\frac{\partial E}{\partial g_I}$. Hopefully it is now clear why the factor of 4 on [this](https://github.com/pyscf/pyscf/blob/master/pyscf/mcscf/newton_casscf.py#L296C15-L296C15) line is incorrect and should be a factor of 2. For the other two erroneous factors [here](https://github.com/pyscf/pyscf/blob/master/pyscf/mcscf/newton_casscf.py#L312-L313), we can determine the correct expression by treating the second derivative as an operator, $\langle I|\partial^2 E|J\rangle \equiv \frac{\partial^2 E}{\partial g_I\partial g_J}$:

$$
\partial^2 E|I\rangle = (\hat{H} - E_0)\ket{I} - (\hat{H} - E_0)\ket{0}\braket{0|I} - \ket{0}\braket{0|\hat{H}-E_0|I} + \mathrm{h.c.}
$$

Again, "+ h.c." is accounted for later in the function. Hopefully it is clear that factors of 2 simply should not be [here](https://github.com/pyscf/pyscf/blob/master/pyscf/mcscf/newton_casscf.py#L312-L313).

---

Optimize JK builder for short-range ERIs

* Optimize molecular JK builder for short-range ERIs
* Refactor _vhf.VHFOpt class. The memory management code for precomputed data was written in C. This PR moves the memory management code to Python.
* Refactor scf._vhf module.
* Update libcint to 6.0 and update relevant integral functions in PBC module.

---

add pcm solvent models

- added PCM family solvent models including C-PCM, COSMO, IEF-PCM, SS(V)PE
- added their analytical gradients

---

fix and activate W391

another fix, for empty lines near the end of files ;

NOT activated as a new check in the linter ;

done using the script autopep8

---

cistring should use int64 everywhere

Partly a question. Why does `fci.cistring` use `int32` in some places instead of `int64` everywhere? For example, `make_strings` returns a list of `int64`, but `gen_occslst` and `gen_linkstr_index` return arrays of `int32`. I think using `int64` everywhere would be more consistent and support more use cases.

---

Import pyscf.grad w/ installed mpi4py package initializes MPI

Dear developers,

importing `pyscf.grad` when the `mpi4py` package is available seems to initialize MPI. Please see the script and output below:

```python
import os

print("before pyscf import")
print(os.system("env | grep PMIX"))

print("after pyscf.grad import")
import pyscf.grad

# This has the same effect
# print("after MPI import from mpi4py")
# from mpi4py import MPI

print(os.system("env | grep PMIX"))
```
produces
```bash
 2023-10-04 11:26:42 ⌚  notebook in ~/tmp/577_pyscf_grad
○ → python ps.py 
before pyscf import
256
after pyscf.grad import
/home/johannes/.pyenv/versions/pyscf_grad/lib/python3.11/site-packages/pyscf/dft/libxc.py:772: UserWarning: Since PySCF-2.3, B3LYP (and B3P86) are changed to the VWN-RPA variant, the same to the B3LYP functional in Gaussian and ORCA (issue 1480). To restore the VWN5 definition, you can put the setting "B3LYP_WITH_VWN5 = True" in pyscf_conf.py
  warnings.warn('Since PySCF-2.3, B3LYP (and B3P86) are changed to the VWN-RPA variant, '
PMIX_MCA_mca_base_component_show_load_errors=1
PMIX_HOSTNAME=notebook
PMIX_SECURITY_MODE=native
PMIX_GDS_MODULE=ds21,ds12,hash
PMIX_SYSTEM_TMPDIR=/tmp
PMIX_SERVER_URI41=1800273920.0;tcp4://127.0.0.1:44791
PMIX_BFROP_BUFFER_TYPE=PMIX_BFROP_BUFFER_NON_DESC
PMIX_DSTORE_21_BASE_PATH=/tmp/ompi.notebook.1000/pid.320935/pmix_dstor_ds21_320935
PMIX_VERSION=4.2.6
PMIX_MCA_psec=native
PMIX_RANK=0
PMIX_SERVER_URI2=1800273920.0;tcp4://127.0.0.1:44791
PMIX_SERVER_URI3=1800273920.0;tcp4://127.0.0.1:44791
PMIX_SERVER_URI4=1800273920.0;tcp4://127.0.0.1:44791
PMIX_SERVER_URI21=1800273920.0;tcp4://127.0.0.1:44791
PMIX_DSTORE_ESH_BASE_PATH=/tmp/ompi.notebook.1000/pid.320935/pmix_dstor_ds12_320935
PMIX_SERVER_TMPDIR=/tmp/ompi.notebook.1000/pid.320935
PMIX_NAMESPACE=1800273921
0
```

When the `mpi4py` package is not installed in the python environment MPI is not initialized.

Is this intended behavior and if so, can the MPI initalization be disabled somehow? For me, the unintended MPI initalization breaks a few things, e.g., I can't execute subprocesses with `mpirun`. I run into the same issues as described in this [StackOverflow post](https://stackoverflow.com/a/60070753).

The problem occurs on the following system
```
Linux notebook 5.10.194-1-MANJARO #1 SMP PREEMPT Sat Sep 2 20:55:57 UTC 2023 x86_64 GNU/Linux

mpirun --version
  mpirun (Open MPI) 4.1.5

Python 3.11.5 (freshly compiled via pyenv)

python -m pip freeze (pyscf installation from PyPI)
  h5py==3.9.0
  mpi4py==3.1.5
  numpy==1.26.0
  pyscf==2.3.0
  scipy==1.11.3
```

As far as I can tell the MPI functionality of PySCF lives in a different package, which I did not install. So the MPI initialization is quite unexpected for me.

All the best
Johannes

---

Support using DF-CCSD and frozen for FNO-CCSD

Support using 1. DF-CCSD and 2. frozen for FNO-CCSD

---

Fix TDDFT initial guess

* The treatment of degeneracy TDDFT initial guess include unnecessary states. They are removed in this PR. It should fix test fail #1871 
* Another TDDFT fxc integral bug fix depends on the PR #1859 

---

Improve wheel

* Fix issue #973 #934 
* Improve bdist wheel compilation. Release py3 type wheel to support all Python3 versions.
* Remove some CI test pipelines

---

To gpu

* Add to_gpu method for some mean-field methods. It converts pyscf objects to its GPU variant
* Change the mean-field class inheritance hierarchy. The mean-field classes of molecule, Gamma-point PBC, k-point PBC are independent classes now. Refactor the initialization functions of cc, tddft, etc regarding to this change.
* Add an istype method for mean-field class to test if a mean-field class subject to the molecule or gamma-point PBC class.
* Fix the undo_soscf method when it works with density fitting model

---

Release 2.4

New features and bugfixes can be found in CHANGELOG.

---

Allow to turn off AO symmetry for PBC KS calculations

---

ValueError when calculating CASCI gradients.

PySCF Version 2.0.1 and 2.4.0
## Minimal working example:
```
from pyscf import M
from pyscf.mcscf import CASCI


geom_str = """
    H                 -0.00021900   -0.20486000   -2.17721200
    H                 -0.00035900   -1.27718700   -2.17669400
    """

mol = M(
    atom = geom_str,
    basis='6-31G',
    charge=0,
    spin=0)

hf = mol.HF()
print(hf.kernel())
casci = CASCI(hf, 2, 2)
print(casci.kernel()[0])
grad = casci.nuc_grad_method()
grad.max_memory = 0
nuc_grad = grad.kernel()
print(nuc_grad)

```
## Error output
```
  File "XXX", line 35, in <module>
    nuc_grad = grad.kernel()
  File "/XXX/site-packages/pyscf/grad/casci.py", line 305, in kernel
    de = self.grad_elec(mo_coeff, ci, atmlst, log)
  File "/XXX/site-packages/pyscf/grad/casci.py", line 161, in grad_elec
    de[k,i] += numpy.einsum('ijkl,il,kj', eri1tmp, hf_dm1[p0:p1], zvec_ao[q0:q1])
  File "<__array_function__ internals>", line 6, in einsum
  File "/XXX/site-packages/numpy/core/einsumfunc.py", line 1361, in einsum
    return c_einsum(*operands, **kwargs)
ValueError: operands could not be broadcast together with remapped shapes [original->remapped]: (2,2,4,4)->(2,2,4,4) (2,4)->(2,newaxis,newaxis,4) (2,4)->(4,2,newaxis) 
python-BaseException
```
## Analysis
The indices for the einsum in `grad_elec` line 161 seem to be incorrect.
`eri1tmp` is reshaped by
```
eri1tmp = eri1tmp.reshape(p1-p0,nf,nao,nao)
```
The shape of `hf_dm1[p0:p1]` is `(p1-p0, nao)` and the shape of `zvec_ao[q0:q1]` is `(nf, nao)`.
It seems the correct einsum index should be `'ijkl,il,jk'` instead of `'ijkl,il,kj'`.

The bug will cause a `ValueError` when calculating the gradient for large molecules or the max memory is set to a small value.
Note that the same bug (if it truly is) is also present in the code after `grad_elec` line 161.

---

PBC with GDF density fitting: difference in energy between a cell with k-points and a corresponding supercell in PySCF v2.3.0

Hi. 

I'm trying to compute total DFT energy for AlAs using GDF density fitting, and I get a significant different between a calculation using k-points and that of a corresponding supercell. 
Additionally, there are two ways to ask for GDF:
Option 1: `kmf = dft.KRKS(cell, kpts).density_fit()`
Option 2: `kmf.with_df = df.df.DF(cell, kpts)`
Option 3: `kmf.with_df = df.rsdf.RSGDF(cell, kpts)`

Option 1 especially results in a rather dramatic difference in energies. 
It seem to make little difference if I use range-separated or default GDF, i.e. Option 2 or 3.

Here is my minimal example, running through all three options:
```python
import sys
import numpy as np
from pyscf.pbc import df, dft, gto
from pyscf.pbc.tools import super_cell

XC = 'pbe,pbe'
DF_TYPE = 'GDF'
PP = 'gth-pbe'
BASIS = 'gth-szv-molopt-sr'

# cell
cell = gto.Cell()
cell.atom = '''
 Al  0.000000  0.000000  0.000000
 As  6.081570  3.511190  2.482790
'''
cell.basis = BASIS
cell.pseudo = PP
cell.a = np.eye(3) * 4.05438
cell.a[1, 0], cell.a[2, 0] = 2.02719, 2.02719
cell.a[1, 1] = 3.51119
cell.a[2, 1] = 1.17040
cell.a[2, 2] = 3.31039
cell.verbose = 4
cell.build()

# kmesh
nk = [2,2,2]
nkpts = np.prod(nk)
kpts = cell.make_kpts(nk)

# build supercell
nk1 = np.array([1,1,1])
supcell = super_cell(cell, nk)
gamma_kpt = supcell.make_kpts(nk1)

for i in [1, 2, 3]:
    DF_OPT = i
    # run SCF calculation
    if DF_OPT == 1:
        kmf = dft.KRKS(cell, kpts).density_fit(auxbasis = "weigend")
    elif DF_OPT == 2:
        kmf = dft.KRKS(cell, kpts)
        kmf.with_df = df.df.DF(cell, kpts)
        kmf.with_df.auxbasis = "weigend"
    elif DF_OPT == 3:
        kmf = dft.KRKS(cell, kpts)
        kmf.with_df = df.rsdf.RSGDF(cell, kpts)
        kmf.with_df.auxbasis = "weigend"
    else:
        kmf = dft.KRKS(cell, kpts)
    kmf.xc = XC
    kmf.verbose = 4
    e_kmf = kmf.kernel()

    # run supercell SCF calculation
    if DF_OPT == 1:
        print('1 rks DFT_OP = ', DF_OPT)
        mf = dft.RKS(supcell, gamma_kpt).density_fit(auxbasis = "weigend")
    elif DF_OPT == 2:
        print('2 rks DFT_OP = ', DF_OPT)
        mf = dft.RKS(supcell, gamma_kpt)
        mf.with_df = df.df.DF(supcell, gamma_kpt)
        mf.with_df.auxbasis = "weigend"
    elif DF_OPT == 3:
        print('3 rks DFT_OP = ', DF_OPT)
        mf = dft.RKS(supcell, gamma_kpt)
        mf.with_df = df.rsdf.RSGDF(supcell, gamma_kpt)
        mf.with_df.auxbasis = "weigend"
    else:
        print('4 rks DFT_OP = ', DF_OPT)
        mf = dft.RKS(supcell, gamma_kpt)
    mf.xc = XC
    mf.verbose = 4
    e_mf = mf.kernel()

    print('DF_OPT = ', DF_OPT)
    print('E_kmf = ', e_kmf * nkpts)
    print('E_mf = ', e_mf)
    print('E_kmf - E_mf = ', e_kmf * nkpts - e_mf)
```

And here are the energies I get when running the minimal example script with PySCF v2.3.0:
(I named the energy computed with k-points E_kmf and that of a supercell E_mf)
```
AlAs_pyscf230_opt_1.out:E_kmf =  -66.53058616857375
AlAs_pyscf230_opt_1.out-E_mf =  -66.68625150929245
AlAs_pyscf230_opt_1.out:E_kmf - E_mf =  0.15566534071869853

AlAs_pyscf230_opt_2.out:E_kmf =  -66.53060046615727
AlAs_pyscf230_opt_2.out-E_mf =  -66.52820303055472
AlAs_pyscf230_opt_2.out:E_kmf - E_mf =  -0.0023974356025462384

AlAs_pyscf230_opt_3.out:E_kmf =  -66.53060046481129
AlAs_pyscf230_opt_3.out-E_mf =  -66.52818288663258
AlAs_pyscf230_opt_3.out:E_kmf - E_mf =  -0.002417578178707913
```

Using the previous version, PySCF v2.2.1, does not result in such difference, as long as Option 2 or 3 is chosen:
```
AlAs_pyscf221_opt_1.out:E_kmf =  -66.53057746274987
AlAs_pyscf221_opt_1.out-E_mf =  -66.68861566834636
AlAs_pyscf221_opt_1.out:E_kmf - E_mf =  0.1580382055964833

AlAs_pyscf221_opt_2.out:E_kmf =  -66.53059173124741
AlAs_pyscf221_opt_2.out-E_mf =  -66.5305917994923
AlAs_pyscf221_opt_2.out:E_kmf - E_mf =  6.824488707479759e-08

AlAs_pyscf221_opt_3.out:E_kmf =  -66.53059952672413
AlAs_pyscf221_opt_3.out-E_mf =  -66.53059960688681
AlAs_pyscf221_opt_3.out:E_kmf - E_mf =  8.01626782731546e-08
```

My suspicion is that it might have to do with the electron-nuclei term in the energy and pseudopotentials, as I don't get the same difference in energy when computing it for HF, a system with only s- and p-shells. 
Input cell in this case is:
```python
cell = gto.Cell()
cell.atom = '''
 H   0.81252   1.47613   2.81966
 H   1.18600   1.19690   0.22918
 F   0.11649   1.99653   3.20061
 F   1.88203   0.67651   0.61013
'''
cell.basis = BASIS
cell.pseudo = PP
cell.a = np.eye(3) * 2.78686
cell.a[1, 1] = 2.67303
cell.a[1, 0] = -0.78834
cell.a[2, 2] = 5.18096
cell.build()
```


What is the difference when asking for density fitting in the two different ways as in Option 1 and 2?
And why is there a difference in energies no matter how ones asks for GDF in the newest version?

I would really appreciate any insights/help.



 

---

Fix CASCI grad

Fix #1909 

---

Potential efficiency improvement of density-fitting (cderi, get_jk)

Hi devs!

While performing RI-JK (SCF) computations, I found two possible efficiency bottlenecks. These problems may be alleviated by minor code modifications.

For some remarks below, I think I think I'm not ready to propose a pull request for this issue.

## Coulomb integral not paralleled using `numpy.einsum` without `optimize=True`

For evaluation of coulomb integrals, codes like https://github.com/pyscf/pyscf/blob/231da24f746d3a7988a4c48c9237c4788bda6a36/pyscf/df/df_jk.py#L260-L261 and https://github.com/pyscf/pyscf/blob/231da24f746d3a7988a4c48c9237c4788bda6a36/pyscf/df/df_jk.py#L290-L291 envokes `numpy.einsum`, which have optional parameter `optimize=False`.

For `optimize=False`, `numpy.einsum` just contract tensors or matrices without parallel. That could be great efficiency loss when using more CPU threads.

Simply add `optimize=True` to `numpy.einsum` will resolve this problem.

Since many codes in PySCF uses `numpy.einsum` without `optimize=True`, I think that this is not only a problem of RI-JK SCF, but also other tasks.

## Cholesky decomposed ERI with `scipy.linalg.solve_triangular`

I found that, probably, `scipy.linalg.solve_triangular` just copies or transposes the large 3c-2e integrals `ints` $J_{P, \mu \nu}$ to $J_{\mu \nu, P}$. Since NumPy/SciPy often performs copy or transposition with only one thread, this can be extremely slow.

For evaluation of cholesky decomposed ERI $Y_{Q, \mu \nu}$ (`mf.with_df._cderi`, discuss incore case for simplicity)
$$\sum_{Q} L_{PQ} Y_{Q, \mu \nu} = J_{P, \mu \nu} \text{ or } \mathbf{L} \mathbf{Y} = \mathbf{J}$$
where $L_{PQ}$ is the lower triangular matrix of cholesky-decomposed 2c-2e ERI $J_{PQ}$, as well as $J_{P, \mu \nu}$ the 3c-2e ERI
$$\sum_{R} L_{PR} L_{QR} = J_{PQ} \text{ or } \mathbf{L} \mathbf{L}^\dagger = \mathbf{J}$$

https://github.com/pyscf/pyscf/blob/231da24f746d3a7988a4c48c9237c4788bda6a36/pyscf/df/incore.py#L180-L188

PySCF's `gto.moleintor.getints3c` will probably generates `ints` $J_{P, \mu \nu}$ as C-contiguous matrix, or $J_{\mu \nu, P}$ as F-contiguous matrix.

SciPy seems only accepts fortran-type array as arguments of its BLAS interface. If matrix transposition is to be avoided, then $J_{\mu \nu, P}$ as F-contiguous matrix is better to be passed as argument. Then our problem is to solve $\mathbf{Y}^\dagger$ from $\mathbf{Y}^\dagger \mathbf{L}^\dagger = \mathbf{J}^\dagger$ F-contiguously; then transpose $\mathbf{Y}^\dagger$ to $\mathbf{Y}$ as a C-contiguous matrix.

What's tricky is that, for function `scipy.linalg.solve_triangular`, it calls `dtrtrs`. This BLAS function could not handle $\mathbf{L}^\dagger$ lying on right-side. So the underlying BLAS function `dtrsm` is required to solve $\mathbf{Y}^\dagger \mathbf{L}^\dagger = \mathbf{J}^\dagger$. However, seems there's no function in scipy wraping `?trsm` as high-level API. So to avoid too much data copy and transposition, we may need to explicitly call `scipy.linalg.blas.dtrsm`:

```python
if decompose_j2c == 'cd':
    if not ints.flags.c_contiguous:
        log.warn("`ints` is not c_contiguous here. Additional transpose is involved.")
        ints = np.array(ints, order='C')
    cderi[:, p0:p1] = scipy.linalg.blas.dtrsm(
        1, low.T, ints.T, side=1, lower=False, overwrite_b=True).T
```

This code also has some potential problems:
1. This code almost asserts `ints` as result from transposed `gto.moleintor.getints3c` is C-contiguous; but I don't know if there could be any exceptions.
2. This code assumes integrals to be double-type.
3. This code avoids transpose, but still requires some data copy. Assignment to `cderi[:, p0:p1]` also requires data copy, which seems to be unavoidable if `ints` and `cderi` uses different buffers in memory. I think this data copy process is possible to be avoided, but that may involve some code logic changes to buffer assignment.
4. Above mentioned code is only for incore.py; I haven't validated case of outcore.py.

## Simple benchmark efficiency improvement

C<sub>25</sub>H<sub>52</sub>, RI-JK/def2-TZVP (202 electrons, 1087 basis, 2811 auxbasis), Intel 6150 with 32 physical cores, fully incore
PySCF compiled with MKL, haswell

| use `np.einsum(optimize=True)`* | use `dtrsm` | RI-JK time |
|--|--|--|
| x | x | 80.66 sec |
| √ | x | 48.25 sec |
| √ | √ | 35.64 sec |

\* This option is applied globally, meaning that I manually modified signature in numpy/core/einsumfunc.py directly.

[benchmark_code.py.txt](https://github.com/pyscf/pyscf/files/13063667/benchmark_code.py.txt)


---

native support dispersion correction

- support d3 and d4 via dftd3 and dftd4 respectively
- support scf, gradient, hessian

---

Lattice-sum cutoff

* Fix a bug in lattice sum cutoff for non-orthogonal cell reported in issue #1911 .

---

4th, and 5th order XC derivatives

* Add a patch to xcfun to compute up to 5th order XC derivatives
* Update xcfun_itrf for up to 5th order derviatives
* Update libxc_itrf to support 4th order XC derivatives
* Add the transform_xc function to support arbitrary order XC derivatives
* Update conda build script


---

Problem with k_points = cell.get_abs_kpts(kpts)

I am getting the message
>Exception has occurred: LinAlgError
0-dimensional array given. Array must be at least two-dimensional
  File "/Users/patrykkozlowski/caltech/classes/caltech/f23/ch121b/si/trotting.py", line 44, in <module>
    k_points = cell.get_abs_kpts(kpts)
numpy.linalg.LinAlgError: 0-dimensional array given. Array must be at least two-dimensional

even though my  kpts has ndim 2. 

I have pasted my script below in case someone wants to look
```
import os
import numpy as np
import matplotlib.pyplot as plt
from pyscf.lib import chkfile
from pyscf.pbc.lib.chkfile import load_cell
from ase.dft.kpoints import sc_special_points as special_points
from ase.dft.kpoints import bandpath
from ase.lattice import bulk
import pyscf.pbc.dft as pbcdft


# Set the file path for the checkpoint file
file_path = os.path.join(os.getcwd(), 'chunky.chk')

# Load the cell object
cell = load_cell(file_path)
cell.pbc = [True, True, True]

# Load the checkpoint file
scf_data = chkfile.load(file_path, 'scf')


# Create and populate the KRKS object
kmf = pbcdft.KRKS(cell)
kmf.__dict__.update(scf_data)

ase_cell = bulk('C', 'diamond', a=3.5668)

# Define the special k-points and paths for an FCC structure
points = special_points['fcc']
G = points['G']
X = points['X']
W = points['W']
K = points['K']
L = points['L']
path = bandpath([L, G, X, W, K, G], ase_cell.cell, npoints=50) # note change to bandpath
kpts = path.kpts
kpath, sp_points, labels = path.get_linear_kpoint_axis()



print(kpts.shape)
**# Calculate bands
k_points = cell.get_abs_kpts(kpts)**
e_kn_2 = kmf.get_bands(k_points)[0]

# Adjust for the Fermi level
vbmax = max(e_kn_2[:, cell.nelectron//2-1])
e_kn_2 -= vbmax

au2ev = 27.21139
emin = -1*au2ev
emax = 1*au2ev

# Plotting
plt.figure(figsize=(5, 6))
nbands = cell.nao_nr()
for n in range(nbands):
    plt.plot(kpath, e_kn_2[:, n]*au2ev, color='#4169E1')
for p in sp_points:
    plt.plot([p, p], [emin, emax], 'k-')
plt.plot([0, sp_points[-1]], [0, 0], 'k-')
plt.xticks(sp_points, ['$%s$' % n for n in ['L', r'\Gamma', 'X', 'W', 'K', r'\Gamma']])
plt.axis(xmin=0, xmax=sp_points[-1], ymin=emin, ymax=emax)
plt.xlabel('k-vector')

plt.show()

```

---

Fix decontract_basis function when basis are missed on certain atoms. (Fix #1711)

---

DFT running slow in SLURM system

I am running a demo DFT calculation on a small molecule on a SLURM cluster. Here is the python script `dft.py`:
```
from pyscf import gto, dft
import numpy as np
from time import perf_counter

def run():
    xyz = """
    C     0.0324075417    1.5597651675    0.0173503882
    C     0.0165327393    0.0274410148    0.0305054658
    C     0.7401306193   -0.5295158287    1.2618054783
    C    -1.4291837338   -0.5260272859   -0.0298377316
    C    -2.1505122569   -0.1629995548   -1.2436891238
    C    -2.7262202740    0.1392620880   -2.2551761211
    H     1.0589579093    1.9399387642    0.0096348267
    H    -0.4845464252    1.9534338078   -0.8620306386
    H    -0.4643663260    1.9623774373    0.9087359643
    H     0.5364722319   -0.3291892511   -0.8679611487
    H     0.2428191250   -0.2118700025    2.1862800077
    H     0.7634809319   -1.6244926985    1.2541585815
    H     1.7738173614   -0.1720416972    1.3033542233
    H    -1.3996184762   -1.6199713974    0.0562607039
    H    -1.9858455552   -0.1676037942    0.8474974509
    H    -3.2444660827    0.4018884507   -3.1437253070
    """
    begin = perf_counter()
    mol = gto.Mole()
    mol.atom = xyz
    mol.basis = 'ccpvtz'
    mol.symmetry = False
    mol.max_memory = 12000
    mol.verbose = 4
    mf = dft.RKS(mol).density_fit()
    mf.grids.level = 4
    mf.xc = 'PBE'
    mf.kernel()
    end = perf_counter()
    print(f"Time: {end-begin:.2f} s")
```

When I am simply running the script with `python dft.py`, the code should be running on the management node, and finished in ~53s. But when I tried to submit it to the computation node with `srun python dft.py`, the exact same code took ~105s. The CPU on the computation node is similar to the management node, if not better. Why will this happen? And may I have a reference on how much time this calculation should take on single CPU core?

---

A missing file is placed into the PLIST

```
===> Checking for items in pkg-plist which are not in STAGEDIR
Error: Missing: %%PYTHON_SITELIBDIR%%/pyscf_lib_placeholder.so
===> Error: Plist issues found.
```

```pyrthon setup.py install --record plist``` produces the plist file with ```pyscf_lib_placeholder.so``` that is not installed.

---

Fix PBC DFT Becke grid rounding error

fixes issue #1959 

---

Re-ordering basis functions introduces mismatch

#1620 introduced ordering basis functions if they are not ordered correctly. When using `molden.load` to load molecules from molden files, the MO coefficients are not ordered accordingly, which leads to a mismatch and therefore wrong results. 
One example would be the minimally augmented basis sets (like ma-def2-SVP) from ORCA, which have some s-type AOs appended after the p-type AOs from the standard def2-SVP.

The code has changed significantly since #1620, which makes fixing the problem a bit harder.

---

Update periodic GW init and add example

This should improve the PBC GW interface in response to, e.g., issue #1966. But I think the KUGW is broken and might need to be looked at by @zhutianyu1991 or someone else. I get the below error if I try KUKS + KUGW,
```
Traceback (most recent call last):
  File "/Users/tberkelbach/bin/pyscf/examples/pbc/22-k_points_gw.py", line 36, in <module>
    mygw.kernel()
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/gw/kugw_ac.py", line 705, in kernel
    kernel(self, mo_energy, mo_coeff, orbs=orbs,
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/gw/kugw_ac.py", line 89, in kernel
    vk = uhf.get_veff(gw.mol,dm_kpts=dm)
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/scf/kuhf.py", line 442, in get_veff
    vj, vk = self.get_jk(cell, dm_kpts, hermi, kpts, kpts_band)
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/scf/khf.py", line 529, in get_jk
    vj, vk = self.with_df.get_jk(dm_kpts, hermi, kpts, kpts_band,
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/df/df.py", line 443, in get_jk
    vk = df_jk.get_k_kpts(self, dm, hermi, kpts, kpts_band, exxdiv)
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/df/df_jk.py", line 611, in get_k_kpts
    make_kpt(ki, kj, True)
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/df/df_jk.py", line 444, in make_kpt
    for LpqR, LpqI, sign in mydf.sr_loop((kpti,kptj), max_memory, False):
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/df/df.py", line 355, in sr_loop
    with _load3c(self._cderi, self._dataname, kpti_kptj) as j3c:
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/df/df.py", line 692, in __enter__
    return self.getitem(*self.kpti_kptj)
  File "/Users/tberkelbach/bin/pyscf/pyscf/pbc/df/df.py", line 746, in getitem
    raise KeyError(f'Key {key} not found')
KeyError: 'Key j3c/2 not found'
```

---

The complex example in 02-ghf.py  fails to converge

Dear developers,
When I test the complex GHF in pyscf using the example in 02-ghf.py, I find that it doesn't  converge. The code in 02-ghf.py is
```python
#
# 2. complex GHF
#
mf = scf.GHF(mol)
dm = mf.get_init_guess() + 0j
dm[0,:] += .1j
dm[:,0] -= .1j
mf.kernel(dm0=dm)
``` 
I change .1j to .01j and fix this problem.

---

Fci str2addr

* Fix FCI string to address conversion function to support large address (issue #1886)
* Slightly optimize FCI performance

---

MP2 Geometry Optimization with Forced Cartesian Functions

Pyscf 2.4.0

I'm attempting to perform a geometry optimization with forced Cartesian GTOs. (EDIT: add script)
```
import sys,os
import pyscf
from pyscf import mp

geom_fname = sys.argv[1]
basis_name = sys.argv[2]

mol = pyscf.M(atom = geom_fname, output = 'coro_mp2_opt.log', basis = basis_name, cart = True)
mol.max_memory = 20*1024
mf = mol.RHF()
mf.chkfile = 'coro_mp2_opt.chk'
mf.verbose = 4
mf.run()

mp2 = mp.MP2(mf)
mp2.verbose = 4
mp2.run()
opt = mp2.Gradients().optimizer(solver='berny')
opt.verbose = 4

mol_eq = opt.kernel()
print(mol_eq.atom_coords())

```

HF/MP2 run fine with forced Cartesians, but the MP2 gradients error out with the following:
```
Traceback (most recent call last):
  File "../coro.py", line 21, in <module>
    mol_eq = opt.kernel()
  File "/home/dbwy/Documents/Projects/TransitionMetalDimers/venv/lib/python3.8/site-packages/pyscf/geomopt/berny_solver.py", line 203, in kernel
    kernel(self.method, callback=self.callback, **params)
  File "/home/dbwy/Documents/Projects/TransitionMetalDimers/venv/lib/python3.8/site-packages/pyscf/geomopt/berny_solver.py", line 143, in kernel
    energy, gradients = g_scanner(mol)
  File "/home/dbwy/Documents/Projects/TransitionMetalDimers/venv/lib/python3.8/site-packages/pyscf/grad/mp2.py", line 236, in __call__
    de = self.kernel(mp_scanner.t2)
  File "/home/dbwy/Documents/Projects/TransitionMetalDimers/venv/lib/python3.8/site-packages/pyscf/grad/mp2.py", line 293, in kernel
    de = self.grad_elec(t2, atmlst, verbose=log)
  File "/home/dbwy/Documents/Projects/TransitionMetalDimers/venv/lib/python3.8/site-packages/pyscf/grad/mp2.py", line 97, in grad_elec
    Imat += lib.einsum('ipx,iqx->pq', eri0.reshape(nf,nao,-1), dm2buf)
  File "/home/dbwy/Documents/Projects/TransitionMetalDimers/venv/lib/python3.8/site-packages/pyscf/lib/numpy_helper.py", line 239, in einsum
    out = _contract(subscripts, *tensors, **kwargs)
  File "/home/dbwy/Documents/Projects/TransitionMetalDimers/venv/lib/python3.8/site-packages/pyscf/lib/numpy_helper.py", line 166, in _contract
    raise ValueError(err)
ValueError: ERROR: In index string ipx,iqx->pq, the range of index x is different in A (88704) and B (73920)
```

This error goes away if I allow for auto-deduction of the basis (6-31G*) to spherical GTOs.  Am I missing something obvious here?

---

geometry optimization with dispersion correction

Hi,
I tried to optimize a molecule with B3LYP-D3/D4 ([Simple DFT-D3](https://dftd3.readthedocs.io/en/latest/index.html)). But there are some errors. 

```
from pyscf import gto, dft, scf
import dftd3.pyscf as disp
from pyscf.geomopt.geometric_solver import optimize

#no spin RHF
try:
    mol = gto.M(atom='O 0 0 0; O 0 0 1.8', unit='ANG', basis='631g*')
    mf = scf.RHF(mol)
    #mf.xc='b3lyp'
    grad=disp.energy(mf).nuc_grad_method().as_scanner()
    grad.optimizer().kernel()
    print("no spin RHF: OK")
except Exception as e:
    print(e)


#spin=1 hydroxides RHF
try:
    mol = gto.M(atom='H 0 0 0; O 0 0 1.8', unit='ANG', basis='631g*', spin=1)
    mf = scf.RHF(mol)
    #mf.xc='b3lyp'
    grad=disp.energy(mf).nuc_grad_method().as_scanner()
    grad.optimizer().kernel()
    print("spin=1 RHF: OK")
except Exception as e:
    print(e)

#spin=0 RKS
try:
    mol = gto.M(atom='O 0 0 0; O 0 0 1.8', unit='ANG', basis='631g*')
    mf = dft.RKS(mol)
    mf.xc='b3lyp'
    grad=disp.energy(mf).nuc_grad_method().as_scanner()
    grad.optimizer().kernel()
    print("spin=0 RKS: OK")
except Exception as e:
    print(e)

```
The above optimization works.

```
#spin=1 hydroxides RKS
try:
    mol = gto.M(atom='H 0 0 0; O 0 0 1.8', unit='ANG', basis='631g*', spin=1)
    mf = dft.RKS(mol)
    mf.xc='b3lyp'
    grad=disp.energy(mf).nuc_grad_method().as_scanner()
    grad.optimizer().kernel()
    print("spin=1 RKS: OK")
except Exception as e:
    print(e)

#spin=2  RKS
try:
    mol = gto.M(atom='O 0 0 0; O 0 0 1.8', unit='ANG', basis='631g*', spin=2)
    mf = dft.RKS(mol)
    mf.xc='b3lyp'
    grad=disp.energy(mf).nuc_grad_method().as_scanner()
    grad.optimizer().kernel()
    print("spin=2 RKS: OK")
except Exception as e:
    print(e)
```
When introducing spin to RKS, an error was raised: ''
mo_occ_a = (dm.mo_occ > 0).astype(numpy.double)
                ^^^^^^^^^^^^^
TypeError: '>' not supported between instances of 'list' and 'int'


When implementing UKS, it raised 'scf_grad must be an instance of Gradients'.
```
#spin=1 hydroxides UKS
try:
    mol = gto.M(atom='H 0 0 0; O 0 0 1.8', unit='ANG', basis='631g*', spin=1)
    mf = dft.UKS(mol)
    mf.xc='b3lyp'
    grad=disp.energy(mf).nuc_grad_method().as_scanner()
    grad.optimizer().kernel()
    print("spin UKS: OK")
except Exception as e:
    print(e)
```
So, it seems that 'spin' does not work for dft-d3 correction? And UKS is not supported?
I am not sure if these errors are rooted in pyscf or dftd3/d4 package.  But they all work well without dftd3. 


---

Interface to libmsym (https://github.com/mcodev31/libmsym) for handeling non-abelian symmetry

The interface allows to generate symmetry adapted AOs using [libmsym](https://github.com/mcodev31/libmsym), which works for arbitrary point groups.
It seems working fine with `scf` if geometry is given in proper axes. Some more work has to be done to make it fully compatible.
I also work for the orbitals in `mcscf` if defined as "extra symmetry" that forbids symmetry-breaking orbital mixing.
WFs are of course not symmetry adapted, so one has to be careful, especially with multidimensional irreps.

This should solve #1377.

---

Bug fix for Pipek Mezey + Stability check using Jacobi sweep

## Bug fix for Pipek Mezey

This PR fixes issue #1984. In particular, the missing factor of 2 in both gradient and Hessian is restored. The erroneous `h_diag` for exponent = 4 is fixed (as a result, some calculations with exponent = 4 require fewer cycles to converge with the new code). The new implementation supports arbitrary exponent (not limited to 2 and 4). Tests are added that examine if the new code generates gradient and Hessian that agree with finite difference.

A bug in the atomic initial guess (in `boys.py`) is also fixed: the molecular `s1e` was used for the pbc case, which is fixed now.

## Stability check of PM orbitals using Jacobi sweep

The second-order CIAH algorithm along with the atomic initial guess used by the PM code can sometimes result in convergence to a local minimum with orbitals that have high symmetry. This occurs for systems as simple as the occupied orbitals of an isolated water molecule. This PR also implements a Jacobi sweep algorithm that can break the said high symmetry in the localized orbitals and help escape from local minima. The cost is roughly two calls of `atomic_pops()`, which is very modest. The orbitals it generates serve as a better initial guess for PM optimization. A typical use case is
```Python
mlo = lo.PipekMezey(mol, occ_coeff)
lo_coeff = mlo.kernel()
while True:
    isstable, lo_coeff = mlo.stability_jacobi()
    if isstable:
        break
    else:
        mlo.init_guess = None
        lo_coeff = mlo.kernel(lo_coeff)
```
Usually one Jacobi check is enough for the subsequent PM optimization to converge to a "stable" minimum (stable w.r.t. Jacobi rotations). Two localized orbitals from water/cc-pVDZ are shown below.



<img width="425" alt="Screenshot 2023-12-04 at 22 53 27" src="https://github.com/pyscf/pyscf/assets/12220457/00956a50-1ee9-44eb-8d3c-3e4820237eb1">


---

Bug fix in interactive solver for non-canonical UMP2

 This PR fixes a bug in the iterative non-canonical UMP2 calculation (described in  #1988), causing discrepancy in UMP2 and RMP2 for a close-shell carbon atom.

---

pyscf_lib_placeholder.so is written into plist but isn't installed

```setup.py install --record {plist}``` writes ```lib/python3.8/site-packages/pyscf_lib_placeholder.so``` into plist but doesn't install it.

FreeBSD ports framework complains:
```
====> Checking for pkg-plist issues (check-plist)
===> Parsing plist
===> Checking for items in STAGEDIR missing from pkg-plist
===> Checking for items in pkg-plist which are not in STAGEDIR
Error: Missing: %%PYTHON_SITELIBDIR%%/pyscf_lib_placeholder.so
===> Error: Plist issues found.
```

---

libxcfun "patch" issue in CMake

One should normally be able to "make" more than once in the build directory, yes? It should just immediately detect that the source code hasn't changed since the project was built and exit successfully, right?

I can compile PySCF from source using CMake without issue and it works, but then if for whatever reason I decide to try to `make` a second time, this happens:

```
(pyscf) herme068@herme068:build$ make
[  1%] Performing update step for 'libcint'
[  2%] No patch step for 'libcint'
[  3%] Performing configure step for 'libcint'
loading initial cache file /home/herme068/gits/pyscf/pyscf/lib/build/deps/tmp/libcint-cache-RELWITHDEBINFO.cmake
Build type RELEASE
Enabled WITH_F12
P orbitals convention (px, py, pz)
Minimal cutoff in exponent for integral screening 20
Do not trigger hard exit for numerical issues in Rys quadrature
Exclude Fortran interface
Exclude old cint (version 2) interface
-- Configuring done
-- Generating done
-- Build files have been written to: /home/herme068/gits/pyscf/pyscf/lib/build/deps/src/libcint-build
[  3%] Performing build step for 'libcint'
[100%] Built target cint
[  4%] Performing install step for 'libcint'
[100%] Built target cint
Install the project...
-- Install configuration: "RELEASE"
-- Up-to-date: /home/herme068/gits/pyscf/pyscf/lib/deps/lib/libcint.so.6.0.0
-- Up-to-date: /home/herme068/gits/pyscf/pyscf/lib/deps/lib/libcint.so.6
-- Up-to-date: /home/herme068/gits/pyscf/pyscf/lib/deps/lib/libcint.so
-- Up-to-date: /home/herme068/gits/pyscf/pyscf/lib/deps/include/cint_funcs.h
-- Up-to-date: /home/herme068/gits/pyscf/pyscf/lib/deps/include/cint.h
[  5%] Completed 'libcint'
[  7%] Built target libcint
[ 14%] Built target libxc
[ 15%] Performing update step for 'libxcfun'
[ 16%] Performing patch step for 'libxcfun'
error: patch failed: CMakeLists.txt:2
error: CMakeLists.txt: patch does not apply
error: patch failed: src/XCFunctional.cpp:432
error: src/XCFunctional.cpp: patch does not apply
make[2]: *** [CMakeFiles/libxcfun.dir/build.make:113: deps/src/libxcfun-stamp/libxcfun-patch] Error 1
make[1]: *** [CMakeFiles/Makefile2:324: CMakeFiles/libxcfun.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
```

---

gccsd error when using an ERI with size (nmo, nmo, nmo, nmo)

Hi all,

I found a possible bug in the gccsd.ao2mo:

https://github.com/pyscf/pyscf/blob/e3ea7d1a095c6b7329bb64ddf9feb4cc567f87df/pyscf/cc/gccsd.py#L364

which missed a reshape:
` 
    if eri.size == nmo**4:  # if mycc._scf._eri is a complex array

        eri = eri.reshape(nmo**2, nmo**2)
    
        sym_forbid = (orbspin[:,None] != orbspin).ravel()`

Otherwise, the following `sym_forbid` mask would not work.

Best,
Zhihao

---

Warning messages, and other improvements

* More warning messages for inappropriate Hessian grids for mgga functionals
* Remove hdf5 temporary files automatically
* cache dynamic class

---

Chkfile initial guess problem in ROHF and ROKS (issue #1986)

---

Supercell GDF memory problem

Hi, I had a memory problem when generating supercell GDF for 4*4*4 Diamond with cc-pVDZ basis set using 30G memory.
The pyscf script is
```
from pyscf.pbc import gto, df
from pyscf.pbc.tools import k2gamma

cell = gto.Cell()
cell.build(unit='angstrom',
           a='''
            0.000000     1.783500     1.783500
            1.783500     0.000000     1.783500
            1.783500     1.783500     0.000000
           ''',
           atom='C 1.337625 1.337625 1.337625; C 2.229375 2.229375 2.229375',
           dimension=3,
           max_memory=30000,
           verbose=5,
           basis='ccpvdz')
kmesh = [4, 4, 4]
kpts = cell.make_kpts(kmesh)
scell, phase = k2gamma.get_phase(cell, kpts)

gdf = df.GDF(scell)
gdf.auxbasis = "cc-pvdz-ri"
gdf._cderi_to_save = 'gdf_ints.h5'
gdf.build()
```
The error message is 
> Traceback (most recent call last):
>   File "/home/jl710/job/debug/gamma-pseudo/diamond/input.py", line 25, in <module>
>     gdf.build()
>   File "/home/jl710/program/pyscf/pyscf/pbc/df/df.py", line 262, in build
>     self._make_j3c(self.cell, self.auxcell, None, cderi)
>   File "/home/jl710/program/pyscf/pyscf/pbc/df/df.py", line 289, in _make_j3c
>     dfbuilder.make_j3c(cderi_file, j_only=j_only, dataname=self._dataname,
>   File "/home/jl710/program/pyscf/pyscf/pbc/df/rsdf_builder.py", line 926, in make_j3c
>     fswap = self.outcore_auxe2(cderi_file, intor, aosym, comp, j_only,
>   File "/home/jl710/program/pyscf/pyscf/pbc/df/rsdf_builder.py", line 468, in outcore_auxe2
>     self._outcore_dd_block(fswap, intor, aosym, comp, j_only,
>   File "/home/jl710/program/pyscf/pyscf/pbc/df/rsdf_builder.py", line 637, in _outcore_dd_block
>     aopair = np.empty((nao**2, ngrids))
> numpy.core._exceptions._ArrayMemoryError: Unable to allocate 98.9 GiB for an array with shape (262144, 50653) and data type float64

However, when I used older version pyscf, for example commit 5bfe7d1f96f9705c3b69a6da1ff148924e15ae4c , I can generate the GDF  file with 30G memory.

---

CASSCF with symmetry for B-H throws an error

Hi,

Calculating the CAS(2,2) energy of B-H with `symmetry=True` throws an error. For Li-H or for `symmetry=False` or for CAS(3,2) there is no error. Issue #1548 seemed to be related. Also, I am running PySCF 2.4.0.

Could someone help figure this out? Thanks!

```
from pyscf import gto, scf, mcscf

### CAS(3,2) runs fine
mol1 = gto.M(atom="B 0 0 0; H 1.5 0 0", basis="sto3g", symmetry=True)
mc1 = mcscf.CASSCF(scf.RHF(mol1).run(), 3, 2)
mc1.kernel()

### Li-H runs fine
mol2 = gto.M(atom="Li 0 0 0; H 1.5 0 0", basis="sto3g", symmetry=True)
mc2 = mcscf.CASSCF(scf.RHF(mol2).run(), 2, 2)
mc2.kernel()

### symmetry=False runs fine
mol3 = gto.M(atom="B 0 0 0; H 1.5 0 0", basis="sto3g", symmetry=False)
mc3 = mcscf.CASSCF(scf.RHF(mol3).run(), 2, 2)
mc3.kernel()

### throws error
mol4 = gto.M(atom="B 0 0 0; H 1.5 0 0", basis="sto3g", symmetry=True)
mc4 = mcscf.CASSCF(scf.RHF(mol4).run(), 2, 2)
mc4.kernel()
```

the output is

```
converged SCF energy = -24.7216853309577
/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/numpy/linalg/linalg.py:2180: RuntimeWarning: divide by zero encountered in det
  r = _umath_linalg.det(a, signature=signature)
/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/numpy/linalg/linalg.py:2180: RuntimeWarning: invalid value encountered in det
  r = _umath_linalg.det(a, signature=signature)
CASSCF energy = -24.7615485480989
CASCI E = -24.7615485480989  E(CI) = -1.32807642898465  S^2 = 0.0000000
converged SCF energy = -7.86335762153512
CASSCF energy = -7.88099257585260
CASCI E = -7.88099257585260  E(CI) = -1.09902483008292  S^2 = 0.0000000
converged SCF energy = -24.7216853309577
CASSCF energy = -24.7435717749394
CASCI E = -24.7435717749394  E(CI) = -1.29911474076125  S^2 = 0.0000000
converged SCF energy = -24.7216853309577
Traceback (most recent call last):
  File "/Users/vrn738/PycharmProjects/mrpt2/molecules/BH/casscf_symmetry_issue.py", line 20, in <module>
    mc4.kernel()
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/mcscf/mc1step_symm.py", line 73, in kernel
    _kern(self, mo_coeff,
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/mcscf/mc1step.py", line 351, in kernel
    e_tot, e_cas, fcivec = casscf.casci(mo, ci0, eris, log, locals())
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/mcscf/mc1step.py", line 878, in casci
    e_tot, e_cas, fcivec = casci.kernel(fcasci, mo_coeff, ci0, log,
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/mcscf/casci.py", line 608, in kernel
    e_tot, fcivec = casci.fcisolver.kernel(h1eff, eri_cas, ncas, nelecas,
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/fci/direct_spin1_symm.py", line 781, in kernel
    ci0 = self.get_init_guess(norb, nelec, nroots, hdiag, orbsym, wfnsym_ir)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/fci/direct_spin1_symm.py", line 724, in get_init_guess
    ci0 = get_init_guess_cyl_sym(
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/fci/direct_spin1_symm.py", line 291, in get_init_guess_cyl_sym
    ca = _cyl_sym_csf2civec(strsa, addra, orbsym, degen_mapping)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/fci/direct_spin1_symm.py", line 348, in _cyl_sym_csf2civec
    u = _cyl_sym_orbital_rotation(orbsym, degen_mapping)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/vrn738/PycharmProjects/mrpt2/venv/lib/python3.11/site-packages/pyscf/fci/direct_spin1_symm.py", line 369, in _cyl_sym_orbital_rotation
    u[j,j] = sqrthi
    ~^^^^^
IndexError: index 2 is out of bounds for axis 0 with size 2
```

---

"UserWarning: Function mol.dumps drops attribute magmom because it is not JSON-serializable warnings.warn(msg)" in pbc/31-low_dimensional_pbc.py

When running pbc/31-low_dimensional_pbc.py example, I'm getting that UserWarning.

---

UserWarning: Since PySCF-2.3, B3LYP (and B3P86) are changed to the VWN-RPA variant, corresponding to the original definition by Stephens et al. (issue 1480) and the same as the B3LYP functional in Gaussian. To restore the VWN5 definition, you can put the setting "B3LYP_WITH_VWN5 = True" in pyscf_conf.py

Every time I run pyscf I am getting this warning, even when not using B3LYP. Am I supposed to be setting a parameter differently to avoid generating this warning message?

---

Unintuitive mean-field object tranformation in k2gamma

Hi,

I was hoping to get some clarification regarding the `k2gamma` function in `pyscf/pbc/tools/k2gamma.py`

Based on the documentation I read along with my intuition associated with the function, I assumed that whatever mean-field object I passed to `k2gamma`, I would receive back the same object at the gamma-point as a supercell. However, when a `pyscf.pbc.dft.krks.KRKS` object is inputted, a `pyscf.pbc.scf.hf.RHF` object is returned. I have attached an example of this based on `examples/pbc/42-k2gamma.py`. In that example, an independently constructed mean-field object used to check the result has the `pyscf.pbc.dft.rks.RKS` class, which is the class I would have expected from `k2gamma`.

I was hoping to get some clarification if this was the intended behaviour of this function? If not, then I wanted to bring it to your attention.

Many thanks,
Marcus

Example code:
[k2gamma_behaviour.py.txt](https://github.com/pyscf/pyscf/files/13982411/k2gamma_behaviour.py.txt)

---

Print b3lyp warning when needed (issue #2029)

Also update the xcfun module for issue #2016

---

Fix the class of supercell scf object for the k2gamma conversion (#2030)

---

pyscf.pbc.gto.parse bug

Dear,
I encounter a small bug of `pyscf.pbc.gto.parse` when I am using pyscf2.4. In pyscf2.3, the code runs correctly.

My code
```python
import numpy as np
from pyscf.pbc import gto
cell = gto.Cell()
cell.unit = 'B'
cell.atom = '''H     4.1965594  4.227266   4.30915   
               H     1.2282612  2.5588777  4.30915   
               H     0.51177555 1.2794389  0.51177555
               H     2.5588777  0.         0.        '''
cell.spin = 0
cell.basis = {'H':gto.parse('''#BASIS SET
                               H SZV-GTH
                               1
                               1  0  0  4  1
                                       8.3744350009  -0.0283380461
                                       1.8058681460  -0.1333810052
                                       0.4852528328  -0.3995676063
                                       0.1658236932  -0.5531027541
                               #''')}
cell.a = np.eye(3) * 5.117755447140034
cell.build()
print(cell)
```

Run in pyscf 2.4
```bash
Traceback (most recent call last):
  File "/home/lizh/hydrogen/hydrogen/main/src/temp/pyscf24bug.py", line 10, in <module>
    cell.basis = {'H':gto.parse('''#BASIS SET
  File "/home/lizh/.local/lib/python3.9/site-packages/pyscf/gto/basis/__init__.py", line 496, in parse
    return parse_cp2k.parse(string, symb, optimize)
TypeError: parse() takes from 1 to 2 positional arguments but 3 were given
```

Run in pyscf 2.3
```bash
<pyscf.pbc.gto.cell.Cell object at 0x2aaab1fefe50>
```

---

fix cp2k basis parse (issue #2043)

TODO: allow choosing symbols when parsing GTH PPs.

---

SA-CASSCF Nonadiabatic Coupling Vectors

Migration of the implementation of SA-CASSCF NACs from [mrh](https://github.com/MatthewRHermes/mrh). This code was written by @MatthewRHermes with some help from Paul Calio. I had added the tests which compare this implementation to that of OpenMolcas (v23.02). 

Briefly,
```python
from pyscf import gto, scf, mcscf
mol = gto.M(atom="H 0 0 0; H 1.3 0 0", basis="sto-3g", verbose=0, output="/dev/null")
mc = mcscf.CASSCF(scf.RHF(mol).run(), 2, 2).state_average([0.5, 0.5])
mc.fix_spin_(ss=0, shift=1)
mc.kernel()

# Similar to gradient method but requires a tuple of states
mc_nac = mc.nac_method()
de = mc_nac.kernel(state=(0,1))
print(de)

de_with_etf = mc_nac.kernel(state=(0,1), use_etfs=True)
print(de_with_etf)
```
Output:
```
[[-0.22461197  0.          0.        ]
 [-0.22461197  0.          0.        ]]
[[-1.76512088e-16  0.00000000e+00  0.00000000e+00]
 [ 1.49547359e-16  0.00000000e+00  0.00000000e+00]]
```

This code returns the NAC between state 0 and 1 (hence the `state=(0,1)`) of the calculation as 

$$
d_{01} = \langle\Psi_0 |\nabla_{R}\Psi_1 \rangle
$$

Additionally, the `use_etfs` kwarg is to control whether one adds in the so-called CSF contribution. Like in [OpenMolcas](https://molcas.gitlab.io/OpenMolcas/sphinx/users.guide/programs/alaska.html) once can decide to neglect this contribution since it is thought to break translational and rotational invariance [[1](https://doi.org/10.1021/jz3006173)].


1. Shervin Fatehi, Joseph E. Subotnik. Derivative couplings with built-in electron-translation factors: Application to benzene. J. Phys. Chem. Lett., 3[15] (2012) 2039–2043. [doi:10.1021/jz3006173](https://doi.org/10.1021/jz3006173)

---

Optimize the memory usage of GDF builder

Related to issue #2017 

Fix patch:
diff --git a/examples/adc/07-closed_shell_1RDMS.py b/examples/adc/07-closed_shell_1RDMS.py
new file mode 100644
index 0000000000..ed17ae3ce6
--- /dev/null
+++ b/examples/adc/07-closed_shell_1RDMS.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+
+'''
+IP/EA-RADC 1RDM dipole moment calculations for water
+'''
+
+from pyscf import gto, scf, adc
+import numpy as np
+from pyscf import lib
+import math
+
+#WATER
+mol = gto.Mole()
+r = 0.957492
+x = r * math.sin(104.468205 * math.pi/(2 * 180.0))
+y = r * math.cos(104.468205* math.pi/(2 * 180.0))
+mol.atom = [
+    ['O', (0., 0.    , 0)],
+    ['H', (0., -x, y)],
+    ['H', (0., x , y)],]
+mol.basis = {'H': 'cc-pVDZ',
+             'O': 'cc-pVDZ',}
+mol.verbose = 0
+mol.build()
+
+mf = scf.RHF(mol)
+mf.verbose = 0
+mf.conv_tol = 1e-12
+mf.kernel()
+
+#DIPOLE MOMENT INTEGRALS
+def get_dip_moments(adc_var):
+    m_name = adc_var.method
+    m_type = adc_var.method_type
+
+    print()
+    header = "*   1RDM Dipole Moment Contracted Integrals for " + m_type + '/' + m_name + "   *"
+    print("*" * len(header))
+    print(header)
+    print("*" * len(header))
+
+    hline = "-" * len(header)
+    print(hline)
+    print('Calculating dipole moment components...')
+    dip_ints = -adc_var.mol.intor('int1e_r', comp = 3)
+    
+    for i in range(dip_ints.shape[0]):
+        dip_ints[i] = np.dot(mf.mo_coeff.T, np.dot(dip_ints[i], mf.mo_coeff))
+
+    #NUCLEAR
+    print('Attaining nuclear charges and coordinates...')
+    charges = myadc.mol.atom_charges()
+    coords  = myadc.mol.atom_coords()
+    nucl_dip = lib.einsum('i,ix->x', charges, coords)
+
+    #Calculate GS/REF 1RDM
+    print('Calculating Reference 1RDM...')
+    rdm1_ref = myadc.make_ref_rdm1()
+
+    #Calculate EXCITED STATE 1RDM
+    print('Calculating Excited State 1RDM...')
+    rdm1_exc = myadc.make_rdm1()
+
+    #REF 1RDM CONT
+    ref_dip = lib.einsum("xqr,qr->x", dip_ints, rdm1_ref) + nucl_dip
+
+    #EXS 1RDM CONT
+    exc_dip = lib.einsum("xqr,eqr->ex", dip_ints, rdm1_exc) + nucl_dip
+    
+    print(hline)
+    print("Reference dipole moment (a.u.):")
+    print(f"    X: {ref_dip[0]:10.3e}")
+    print(f"    Y: {ref_dip[1]:10.3e}")
+    print(f"    Z: {ref_dip[2]:10.3e}")
+    print(hline)
+    print(hline)
+
+    for r in range(exc_dip.shape[0]):  
+        print(f"Excited state root {r} dipole moment (a.u.):")
+        print(f"    X: {exc_dip[r][0]:10.3e}")
+        print(f"    Y: {exc_dip[r][1]:10.3e}")
+        print(f"    Z: {exc_dip[r][2]:10.3e}")
+    print(hline)
+    print('*'*len(header))
+    print()
+    print()
+    print()
+
+#ADC CALCS
+myadc = adc.ADC(mf)
+
+###IP CALCS
+#IP-RADC(2) for 3 roots
+myadc.verbose = 0
+myadc.kernel(nroots = 3)
+get_dip_moments(myadc)
+
+#IP-RADC(2)-x for 1 root
+myadc.method = "adc(2)-x"
+myadc.kernel(nroots = 1)
+get_dip_moments(myadc)
+
+#IP-RADC(3) for 1 root
+myadc.method = "adc(3)"
+myadc.kernel(nroots = 1)
+get_dip_moments(myadc)
+
+###EA CALCS
+#EA-RADC(2) for 3 roots
+myadc.method = "adc(2)"
+myadc.method_type = "ea"
+myadc.kernel(nroots = 3)
+get_dip_moments(myadc)
+
+#EA-RADC(2)-x for 1 root
+myadc.method = "adc(2)-x"
+myadc.method_type = "ea"
+myadc.kernel(nroots = 1)
+get_dip_moments(myadc)
+
+#EA-RADC(3) for 1 root
+myadc.method = "adc(3)"
+myadc.method_type = "ea"
+myadc.kernel(nroots = 1)
+get_dip_moments(myadc)
\ No newline at end of file
diff --git a/pyscf/adc/__init__.py b/pyscf/adc/__init__.py
index fdfa047839..791df7c3d4 100644
--- a/pyscf/adc/__init__.py
+++ b/pyscf/adc/__init__.py
@@ -42,12 +42,8 @@ def ADC(mf, frozen=None, mo_coeff=None, mo_occ=None):
 
     if mf.istype('UHF'):
         return UADC(mf, frozen, mo_coeff, mo_occ)
-    #elif isinstance(mf, scf.rohf.ROHF):
-    #    lib.logger.warn(mf, 'RADC method does not support ROHF reference. ROHF object '
-    #                    'is converted to UHF object and UADC method is called.')
-    #    mf = mf.to_uhf(mf)
-    #    return UADC(mf, frozen, mo_coeff, mo_occ)
-    # TODO add ROHF functionality
+    elif mf.istype('ROHF'):
+        return UADC(mf, frozen, mo_coeff, mo_occ)
     elif mf.istype('RHF'):
         return RADC(mf, frozen, mo_coeff, mo_occ)
     else :
@@ -61,8 +57,7 @@ def UADC(mf, frozen=None, mo_coeff=None, mo_occ=None):
     if not (frozen is None or frozen == 0):
         raise NotImplementedError
 
-    mf = mf.remove_soscf()
-    if not mf.istype('UHF'):
+    if not (mf.istype('UHF') or mf.istype('ROHF')):
         mf = mf.to_uhf()
 
     return uadc.UADC(mf, frozen, mo_coeff, mo_occ)
diff --git a/pyscf/adc/dfadc.py b/pyscf/adc/dfadc.py
index 8784b164f3..5f86d6415a 100644
--- a/pyscf/adc/dfadc.py
+++ b/pyscf/adc/dfadc.py
@@ -12,6 +12,13 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+#
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
+#         Alexander Sokolov <alexander.y.sokolov@gmail.com>
+#
 
 import numpy as np
 
@@ -58,6 +65,7 @@ def get_ovvv_spin_df(myadc, Lov, Lvv, p, chnk_size):
     #vvvv = np.ascontiguousarray(vvvv.transpose(0,2,1,3)).reshape(-1, nvir, nvir * nvir)
     return ovvv
 
+
 def get_vvvv_df(myadc, Lvv, p, chnk_size):
 
     ''' Returns approximate vvvv integrals used in restricted implementation'''
@@ -75,11 +83,13 @@ def get_vvvv_df(myadc, Lvv, p, chnk_size):
     Lvv = Lvv.reshape(naux,nvir*nvir)
     vvvv = np.dot(Lvv_temp, Lvv)
     vvvv = vvvv.reshape(-1, nvir, nvir, nvir)
-    vvvv = np.ascontiguousarray(vvvv.transpose(0,2,1,3)).reshape(-1, nvir, nvir * nvir)
+    vvvv = vvvv.transpose(0,2,1,3).reshape(-1, nvir, nvir, nvir)
+    vvvv = np.ascontiguousarray(vvvv)
+
     return vvvv
 
 
-def get_vvvv_antisym_df(myadc, Lvv, p, chnk_size):
+def get_vvvv_antisym_df(myadc, Lvv, p, chnk_size, pack = True):
 
     ''' Returns approximate antisymmetrized vvvv integrals (alpha/beta spin) used in unrestricted implementation'''
 
@@ -95,9 +105,13 @@ def get_vvvv_antisym_df(myadc, Lvv, p, chnk_size):
     Lvv = Lvv.reshape(naux,nvir*nvir)
     vvvv = np.dot(Lvv_temp, Lvv)
     vvvv = vvvv.reshape(-1, nvir, nvir, nvir)
-    vvvv = vvvv.transpose(0,2,1,3).reshape(-1, nvir, nvir, nvir)
+    vvvv = vvvv.transpose(0,2,1,3)
     vvvv -= vvvv.transpose(0,1,3,2)
-    vvvv = np.ascontiguousarray(vvvv[:, :, ind_vv_g[0], ind_vv_g[1]])
+
+    if pack:
+        vvvv = np.ascontiguousarray(vvvv[:, :, ind_vv_g[0], ind_vv_g[1]])
+    else:
+        vvvv = np.ascontiguousarray(vvvv)
 
     return vvvv
 
@@ -116,7 +130,9 @@ def get_vVvV_df(myadc, Lvv, LVV, p, chnk_size):
         Lvv_temp = np.ascontiguousarray(Lvv.T.reshape(-1,naux))
 
     LVV = LVV.reshape(naux,nvir_2*nvir_2)
-    vvvv = np.dot(Lvv_temp, LVV).reshape(-1,nvir_1,nvir_2,nvir_2)
-    vvvv = np.ascontiguousarray(vvvv.transpose(0,2,1,3)).reshape(-1, nvir_2, nvir_1, nvir_2)
+    vvvv = np.dot(Lvv_temp, LVV)
+    vvvv = vvvv.reshape(-1,nvir_1,nvir_2,nvir_2)
+    vvvv = vvvv.transpose(0,2,1,3)
+    vvvv = np.ascontiguousarray(vvvv)
 
     return vvvv
diff --git a/pyscf/adc/radc.py b/pyscf/adc/radc.py
index 3137c30498..ce6c8d8e6b 100644
--- a/pyscf/adc/radc.py
+++ b/pyscf/adc/radc.py
@@ -12,7 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
 #
 
@@ -50,7 +53,7 @@ def kernel(adc, nroots=1, guess=None, eris=None, verbose=None):
     imds = adc.get_imds(eris)
     matvec, diag = adc.gen_matvec(imds, eris)
 
-    guess = adc.get_init_guess(nroots, diag, ascending=True)
+    guess = adc.get_init_guess(nroots, diag, ascending = True)
 
     conv, adc.E, U = lib.linalg_helper.davidson_nosym1(
         lambda xs : [matvec(x) for x in xs],
@@ -61,6 +64,7 @@ def kernel(adc, nroots=1, guess=None, eris=None, verbose=None):
 
     if adc.compute_properties:
         adc.P,adc.X = adc.get_properties(nroots)
+    nfalse = np.shape(conv)[0] - np.sum(conv)
 
     header = ("\n*************************************************************"
               "\n            ADC calculation summary"
@@ -71,15 +75,88 @@ def kernel(adc, nroots=1, guess=None, eris=None, verbose=None):
         print_string = ('%s root %d  |  Energy (Eh) = %14.10f  |  Energy (eV) = %12.8f  ' %
                         (adc.method, n, adc.E[n], adc.E[n]*27.2114))
         if adc.compute_properties:
-            print_string += ("|  Spec factors = %10.8f  " % adc.P[n])
+            print_string += ("|  Spec. factor = %10.8f  " % adc.P[n])
         print_string += ("|  conv = %s" % conv[n])
         logger.info(adc, print_string)
 
+    if nfalse >= 1:
+        logger.warn(adc, "Davidson iterations for " + str(nfalse) + " root(s) did not converge!!!")
+
     log.timer('ADC', *cput0)
 
     return adc.E, adc.U, adc.P, adc.X
 
 
+def make_ref_rdm1(adc):
+
+    if adc.method not in ("adc(2)", "adc(2)-x", "adc(3)"):
+        raise NotImplementedError(adc.method)
+
+    t1 = adc.t1
+    t2 = adc.t2
+    t2_ce = t1[0][:]
+    t1_ccee = t2[0][:]
+
+    ######################
+    einsum_type = True
+    nocc = adc._nocc
+    nvir = adc._nvir
+
+    nmo = nocc + nvir
+
+    OPDM = np.zeros((nmo,nmo))
+
+    ####### ADC(2) SPIN ADAPTED REF OPDM with SQA ################
+    ### OCC-OCC ###
+    OPDM[:nocc, :nocc] += lib.einsum('IJ->IJ', np.identity(nocc), optimize = einsum_type).copy()
+    OPDM[:nocc, :nocc] -= 2 * lib.einsum('Iiab,Jiab->IJ', t1_ccee, t1_ccee, optimize = einsum_type)
+    OPDM[:nocc, :nocc] += lib.einsum('Iiab,Jiba->IJ', t1_ccee, t1_ccee, optimize = einsum_type)
+
+    ### OCC-VIR ###
+    OPDM[:nocc, nocc:] += lib.einsum('IA->IA', t2_ce, optimize = einsum_type).copy()
+
+    ### VIR-OCC ###
+    OPDM[nocc:, :nocc] += lib.einsum('IA->AI', t2_ce, optimize = einsum_type).copy()
+
+    ### VIR-VIR ###
+    OPDM[nocc:, nocc:] += 2 * lib.einsum('ijAa,ijBa->AB', t1_ccee, t1_ccee, optimize = einsum_type)
+    OPDM[nocc:, nocc:] -= lib.einsum('ijAa,jiBa->AB', t1_ccee, t1_ccee, optimize = einsum_type)
+
+    ####### ADC(3) SPIN ADAPTED REF OPDM WITH SQA ################
+    if adc.method == "adc(3)":
+        t3_ce = adc.t1[1][:]
+        t2_ccee = t2[1][:]
+
+        #### OCC-OCC ###
+        OPDM[:nocc, :nocc] -= 2 * lib.einsum('Iiab,Jiab->IJ',
+                                             t1_ccee, t2_ccee, optimize = einsum_type)
+        OPDM[:nocc, :nocc] += lib.einsum('Iiab,Jiba->IJ', t1_ccee, t2_ccee, optimize = einsum_type)
+        OPDM[:nocc, :nocc] -= 2 * lib.einsum('Jiab,Iiab->IJ',
+                                             t1_ccee, t2_ccee, optimize = einsum_type)
+        OPDM[:nocc, :nocc] += lib.einsum('Jiab,Iiba->IJ', t1_ccee, t2_ccee, optimize = einsum_type)
+
+        ##### OCC-VIR ### ####
+        OPDM[:nocc, nocc:]  += lib.einsum('IA->IA', t3_ce, optimize = einsum_type).copy()
+        OPDM[:nocc, nocc:] +=  lib.einsum('IiAa,ia->IA', t1_ccee, t2_ce, optimize = einsum_type)
+        OPDM[:nocc, nocc:] -= 1/2 * \
+            lib.einsum('iIAa,ia->IA', t1_ccee, t2_ce, optimize = einsum_type)
+        ###### VIR-OCC ###
+        OPDM[nocc:, :nocc]  += lib.einsum('IA->AI', t3_ce, optimize = einsum_type).copy()
+        OPDM[nocc:, :nocc]  += lib.einsum('IiAa,ia->AI', t1_ccee, t2_ce, optimize = einsum_type)
+        OPDM[nocc:, :nocc]  -= 1/2 * \
+            lib.einsum('iIAa,ia->AI', t1_ccee, t2_ce, optimize = einsum_type)
+
+        ##### VIR=VIR ###
+        OPDM[nocc:, nocc:] += 2 * lib.einsum('ijAa,ijBa->AB',
+                                             t1_ccee, t2_ccee, optimize = einsum_type)
+        OPDM[nocc:, nocc:] -= lib.einsum('ijAa,jiBa->AB', t1_ccee, t2_ccee, optimize = einsum_type)
+        OPDM[nocc:, nocc:] += 2 * lib.einsum('ijBa,ijAa->AB',
+                                             t1_ccee, t2_ccee, optimize = einsum_type)
+        OPDM[nocc:, nocc:] -= lib.einsum('ijBa,jiAa->AB', t1_ccee, t2_ccee, optimize = einsum_type)
+
+    return 2 * OPDM
+
+
 class RADC(lib.StreamObject):
     '''Ground state calculations
 
@@ -112,13 +189,12 @@ class RADC(lib.StreamObject):
     memorymin = getattr(__config__, 'adc_radc_RADC_memorymin', 2000)
 
     _keys = {
-        'tol_residual','conv_tol', 'e_corr', 'method', 'mo_coeff',
+        'tol_residual','conv_tol', 'e_corr', 'method', 'method_type', 'mo_coeff',
         'mol', 'mo_energy', 'incore_complete',
-        'scf_energy', 'e_tot', 't1', 'frozen', 'chkfile',
-        'max_space', 't2', 'mo_occ', 'max_cycle',
-        'imds', 'method', 'method_type', 'with_df', 'compute_properties',
+        'scf_energy', 'e_tot', 't1', 't2', 'frozen', 'chkfile',
+        'max_space', 'mo_occ', 'max_cycle', 'imds', 'with_df', 'compute_properties',
         'approx_trans_moments', 'evec_print_tol', 'spec_factor_print_tol',
-        'ncvs', 'E', 'U', 'P', 'X',
+        'E', 'U', 'P', 'X', 'ncvs', 'dip_mom', 'dip_mom_nuc'
     }
 
     def __init__(self, mf, frozen=0, mo_coeff=None, mo_occ=None):
@@ -141,7 +217,7 @@ def __init__(self, mf, frozen=0, mo_coeff=None, mo_occ=None):
         self.max_space = getattr(__config__, 'adc_radc_RADC_max_space', 12)
         self.max_cycle = getattr(__config__, 'adc_radc_RADC_max_cycle', 50)
         self.conv_tol = getattr(__config__, 'adc_radc_RADC_conv_tol', 1e-12)
-        self.tol_residual = getattr(__config__, 'adc_radc_RADC_tol_res', 1e-6)
+        self.tol_residual = getattr(__config__, 'adc_radc_RADC_tol_residual', 1e-6)
         self.scf_energy = mf.e_tot
 
         self.frozen = frozen
@@ -172,9 +248,23 @@ def __init__(self, mf, frozen=0, mo_coeff=None, mo_occ=None):
         self.P = None
         self.X = None
 
+        dip_ints = -self.mol.intor('int1e_r',comp=3)
+        dip_mom = np.zeros((dip_ints.shape[0], self._nmo, self._nmo))
+
+        for i in range(dip_ints.shape[0]):
+            dip = dip_ints[i,:,:]
+            dip_mom[i,:,:] = np.dot(mo_coeff.T, np.dot(dip, mo_coeff))
+
+        self.dip_mom = dip_mom
+
+        charges = self.mol.atom_charges()
+        coords  = self.mol.atom_coords()
+        self.dip_mom_nuc = lib.einsum('i,ix->x', charges, coords)
+
     compute_amplitudes = radc_amplitudes.compute_amplitudes
     compute_energy = radc_amplitudes.compute_energy
     transform_integrals = radc_ao2mo.transform_integrals_incore
+    make_ref_rdm1 = make_ref_rdm1
 
     def dump_flags(self, verbose=None):
         logger.info(self, '')
@@ -194,8 +284,8 @@ def dump_flags_gs(self, verbose=None):
         return self
 
     def kernel_gs(self):
-        assert (self.mo_coeff is not None)
-        assert (self.mo_occ is not None)
+        assert(self.mo_coeff is not None)
+        assert(self.mo_occ is not None)
 
         self.method = self.method.lower()
         if self.method not in ("adc(2)", "adc(2)-x", "adc(3)"):
@@ -236,8 +326,8 @@ def outcore_transform():
         return self.e_corr, self.t1, self.t2
 
     def kernel(self, nroots=1, guess=None, eris=None):
-        assert (self.mo_coeff is not None)
-        assert (self.mo_occ is not None)
+        assert(self.mo_coeff is not None)
+        assert(self.mo_occ is not None)
 
         self.method = self.method.lower()
         if self.method not in ("adc(2)", "adc(2)-x", "adc(3)"):
@@ -293,8 +383,8 @@ def outcore_transform():
 
     def _finalize(self):
         '''Hook for dumping results and clearing up the object.'''
-        logger.note(self, 'E_corr = %.8f',
-                    self.e_corr)
+        logger.note(self, 'MP%s correlation energy of reference state (a.u.) = %.8f',
+                    self.method[4], self.e_corr)
         return self
 
     def ea_adc(self, nroots=1, guess=None, eris=None):
@@ -338,6 +428,7 @@ def compute_dyson_mo(self):
     def make_rdm1(self):
         return self._adc_es.make_rdm1()
 
+
 if __name__ == '__main__':
     from pyscf import scf
     from pyscf import gto
diff --git a/pyscf/adc/radc_amplitudes.py b/pyscf/adc/radc_amplitudes.py
index cf72630844..01c22df166 100644
--- a/pyscf/adc/radc_amplitudes.py
+++ b/pyscf/adc/radc_amplitudes.py
@@ -12,7 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
 #
 
@@ -526,7 +529,10 @@ def compute_energy(myadc, t2, eris):
     e_mp = 2 * lib.einsum('ijab,iabj', t2_new, eris_ovvo,optimize=True)
     e_mp -= lib.einsum('ijab,ibaj', t2_new, eris_ovvo,optimize=True)
 
+    logger.info(myadc, "Reference correlation energy (doubles): %.8f", e_mp)
+
     del t2_new
+
     return e_mp
 
 
diff --git a/pyscf/adc/radc_ao2mo.py b/pyscf/adc/radc_ao2mo.py
index ee381d87ce..bcf79df750 100644
--- a/pyscf/adc/radc_ao2mo.py
+++ b/pyscf/adc/radc_ao2mo.py
@@ -12,9 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
-#
 
 import numpy as np
 import pyscf.ao2mo as ao2mo
diff --git a/pyscf/adc/radc_ea.py b/pyscf/adc/radc_ea.py
index 7627074f95..45040f9584 100644
--- a/pyscf/adc/radc_ea.py
+++ b/pyscf/adc/radc_ea.py
@@ -12,9 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
-#
 
 '''
 Restricted algebraic diagrammatic construction
@@ -912,6 +914,516 @@ def analyze(myadc):
 
         myadc.analyze_spec_factor()
 
+def make_rdm1(adc):
+
+    cput0 = (logger.process_clock(), logger.perf_counter())
+    log = logger.Logger(adc.stdout, adc.verbose)
+
+    nroots = adc.U.shape[1]
+    U = adc.renormalize_eigenvectors(nroots)
+
+    list_rdm1 = []
+
+    for i in range(U.shape[1]):
+        rdm1 = make_rdm1_eigenvectors(adc, U[:,i], U[:,i])
+        list_rdm1.append(rdm1)
+
+    cput0 = log.timer_debug1("completed OPDM calculation", *cput0)
+    return list_rdm1
+
+def make_rdm1_eigenvectors(adc, L, R):
+    # Using SQA EA
+    L = np.array(L).ravel()
+    R = np.array(R).ravel()
+
+    t1_ccee = adc.t2[0][:]
+    t2_ce = adc.t1[0][:]
+
+    nocc = adc._nocc
+    nvir = adc._nvir
+    nmo = nocc + nvir
+    n_singles = nvir
+    n_doubles = nvir * nvir * nocc
+
+    s1 = 0
+    f1 = n_singles
+    s2 = f1
+    f2 = s2 + n_doubles
+
+    rdm1  = np.zeros((nmo,nmo))
+    kd_oc = np.identity(nocc)
+
+    L1 = L[s1:f1]
+    L2 = L[s2:f2]
+    R1 = R[s1:f1]
+    R2 = R[s2:f2]
+
+    L2 = L2.reshape(nocc,nvir,nvir)
+    R2 = R2.reshape(nocc,nvir,nvir)
+
+    einsum = lib.einsum
+    einsum_type = True
+
+############# block- ij
+    ### 000 ###
+    rdm1[:nocc, :nocc] += 2 * einsum('a,a,IJ->IJ', L1, R1, kd_oc, optimize = einsum_type)
+
+    ### 101 ###
+    rdm1[:nocc, :nocc] -= 2 * einsum('Jab,Iab->IJ', L2, R2, optimize = einsum_type)
+    rdm1[:nocc, :nocc] += 1 * einsum('Jab,Iba->IJ', L2, R2, optimize = einsum_type)
+    rdm1[:nocc, :nocc] += 4 * einsum('iab,iab,IJ->IJ', L2, R2, kd_oc, optimize = einsum_type)
+    rdm1[:nocc, :nocc] -= 2 * einsum('iab,iba,IJ->IJ', L2, R2, kd_oc, optimize = einsum_type)
+
+    ### 020 ###
+    rdm1[:nocc, :nocc] -= 2 * einsum('a,a,Iibc,Jibc->IJ', L1, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+    rdm1[:nocc, :nocc] += einsum('a,a,Iibc,Jicb->IJ', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[:nocc, :nocc] += 2 * einsum('a,b,Iiac,Jibc->IJ', L1, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+    rdm1[:nocc, :nocc] -= einsum('a,b,Iiac,Jicb->IJ', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[:nocc, :nocc] -= einsum('a,b,Iica,Jibc->IJ', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[:nocc, :nocc] += einsum('a,b,Iica,Jicb->IJ', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[:nocc, :nocc] -= 2 * einsum('a,a,Iibc,Jibc->IJ', L1, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+    rdm1[:nocc, :nocc] += einsum('a,a,Iibc,Jicb->IJ', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[:nocc, :nocc] += einsum('a,b,Iica,Jicb->IJ', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+
+############# block- ab
+    ### 000 ###
+    rdm1[nocc:, nocc:] += einsum('B,A->AB', L1, R1, optimize = einsum_type)
+
+    ### 020 ###
+    rdm1[nocc:, nocc:] -= einsum('A,a,ijab,ijBb->AB', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] += 1/2 * einsum('A,a,ijab,jiBb->AB', L1,
+                                       R1, t1_ccee, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] -= einsum('a,B,ijab,ijAb->AB', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] += 1/2 * einsum('a,B,ijab,jiAb->AB', L1,
+                                       R1, t1_ccee, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] += 2 * einsum('a,a,ijAb,ijBb->AB', L1, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] -= einsum('a,a,ijAb,jiBb->AB', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] -= einsum('a,b,ijBa,ijAb->AB', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] += einsum('a,b,ijBa,jiAb->AB', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] += 2 * einsum('a,a,ijAb,ijBb->AB', L1, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] -= einsum('a,a,ijAb,jiBb->AB', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, nocc:] -= einsum('a,b,ijBa,ijAb->AB', L1, R1, t1_ccee,
+                                 t1_ccee, optimize = einsum_type)
+
+    ### 101 ###
+    rdm1[nocc:, nocc:] += 2 * einsum('iAa,iBa->AB', R2, R2, optimize = einsum_type)
+    rdm1[nocc:, nocc:] -= einsum('iAa,iaB->AB', R2, R2, optimize = einsum_type)
+    rdm1[nocc:, nocc:] -= einsum('iaA,iBa->AB', L2, R2, optimize = einsum_type)
+    rdm1[nocc:, nocc:] += 2 * einsum('iaA,iaB->AB', L2, R2, optimize = einsum_type)
+
+############# block- ai
+    # 020 #
+    rdm1[nocc:, :nocc] -= einsum('a,A,Ia->AI', L1, R1, t2_ce, optimize = einsum_type)
+    rdm1[nocc:, :nocc] += 2 * einsum('a,a,IA->AI', L1, R1, t2_ce, optimize = einsum_type)
+
+    # 011 #
+    rdm1[nocc:, :nocc] -= 2 * einsum('A,iab,Iiab->AI', L1, R2, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, :nocc] += einsum('A,iab,Iiba->AI', L1, R2, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, :nocc] += 2 * einsum('a,iab,IiAb->AI', L1, R2, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, :nocc] -= einsum('a,iab,iIAb->AI', L1, R2, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, :nocc] -= 2 * einsum('a,iba,IiAb->AI', L1, R2, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, :nocc] += einsum('a,iba,iIAb->AI', L1, R2, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, :nocc] += 2 * einsum('a,iab,IiAb->AI', L1, R2, t1_ccee, optimize = einsum_type)
+    rdm1[nocc:, :nocc] -= einsum('a,iab,iIAb->AI', L1, R2, t1_ccee, optimize = einsum_type)
+
+    # 110 #
+    rdm1[nocc:, :nocc] -= einsum('IAa,a->AI',L2, R1, optimize = einsum_type)
+    rdm1[nocc:, :nocc] += 2 * einsum('IaA,a->AI',L2, R1, optimize = einsum_type)
+
+############# block- ia
+    rdm1[:nocc, nocc:] = rdm1[nocc:, :nocc].T
+
+    ####### ADC(3) SPIN ADAPTED EXCITED STATE OPDM WITH SQA ################
+    if adc.method == "adc(3)":
+        ### Redudant Variables used for names from SQA
+        einsum_type = True
+        t3_ce = adc.t1[1][:]
+        t2_ccee = adc.t2[1][:]
+
+############# block- ij
+        # 120 #
+        rdm1[:nocc, :nocc] -= 2 * einsum('Jab,a,Ib->IJ', L2, R1, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('Jab,b,Ia->IJ', L2, R1, t2_ce, optimize = einsum_type)
+
+        # 021 #
+        rdm1[:nocc, :nocc] -= 2 * einsum('a,Iab,Jb->IJ', L1, R2, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('a,Iba,Jb->IJ', L1, R2, t2_ce, optimize = einsum_type)
+
+        # 030 #
+        rdm1[:nocc, :nocc] -= 4 * einsum('a,a,Iibc,Jibc->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += 2 * einsum('a,a,Iibc,Jicb->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= 4 * einsum('a,a,Jibc,Iibc->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += 2 * einsum('a,a,Jibc,Iicb->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += 2 * einsum('a,b,Iibc,Jiac->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= einsum('a,b,Iibc,Jica->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= einsum('a,b,Iicb,Jiac->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += 2 * einsum('a,b,Iicb,Jica->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += 2 * einsum('a,b,Jiac,Iibc->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= einsum('a,b,Jiac,Iicb->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= einsum('a,b,Jica,Iibc->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += 2 * einsum('a,b,Jica,Iicb->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+
+############# block- ab
+        # 120 #
+        rdm1[nocc:, nocc:] -= einsum('iAa,a,iB->AB', L2, R1, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 2 * einsum('iaA,a,iB->AB', L2, R1, t2_ce, optimize = einsum_type)
+
+        # 021 #
+        rdm1[nocc:, nocc:] += 2 * einsum('a,iaB,iA->AB', L1, R2, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('a,iBa,iA->AB', L1, R2, t2_ce, optimize = einsum_type)
+
+        # 030 #
+        rdm1[nocc:, nocc:] -= einsum('B,a,ijAb,ijab->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 1/2 * einsum('B,a,ijAb,jiab->AB',
+                                           L1, R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('B,a,ijab,ijAb->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 1/2 * einsum('B,a,ijab,jiAb->AB',
+                                           L1, R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('a,A,ijBb,ijab->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 1/2 * einsum('a,A,ijBb,jiab->AB',
+                                           L1, R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('a,A,ijab,ijBb->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 1/2 * einsum('a,A,ijab,jiBb->AB',
+                                           L1, R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 4 * einsum('a,a,ijAb,ijBb->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= 2 * einsum('a,a,ijAb,jiBb->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 4 * einsum('a,a,ijBb,ijAb->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= 2 * einsum('a,a,ijBb,jiAb->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= 2 * einsum('a,b,ijAa,ijBb->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += einsum('a,b,ijAa,jiBb->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= 2 * einsum('a,b,ijBb,ijAa->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += einsum('a,b,ijBb,jiAa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+
+############# block- ia
+        # 120 #
+        rdm1[:nocc, nocc:] -= 2 * einsum('iab,A,Iiab->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('iab,A,Iiba->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 4 * einsum('iab,a,IiAb->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 2 * einsum('iab,a,iIAb->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 2 * einsum('iab,b,IiAa->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('iab,b,iIAa->IA', L2, R1, t2_ccee, optimize = einsum_type)
+
+        # 021 #
+        rdm1[:nocc, nocc:] -= einsum('a,Iab,ijbc,ijAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,Iab,ijbc,jiAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,Ibc,ijAa,jibc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('a,iaA,ijbc,Ijbc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iaA,ijbc,Ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('a,iab,ijbc,IjAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iab,ijbc,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iab,ijcb,IjAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iab,ijcb,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,ibA,Ijca,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,ibc,IjAa,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[:nocc, nocc:] -= einsum('a,Iab,ijbc,ijAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,Iab,ijbc,jiAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('a,Iba,ijbc,ijAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,Iba,ijbc,jiAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,Ibc,ijAa,ijbc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,Ibc,ijAa,jibc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('a,iAa,ijbc,Ijbc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iAa,ijbc,Ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('a,iAb,Ijac,ijbc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iAb,Ijac,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iAb,Ijca,ijbc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iAb,Ijca,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('a,iaA,ijbc,Ijbc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iaA,ijbc,Ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('a,iab,ijbc,IjAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iab,ijbc,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iab,ijcb,IjAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iab,ijcb,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('a,ibA,Ijac,ijbc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,ibA,Ijac,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,ibA,Ijca,ijbc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,ibA,Ijca,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('a,iba,ijbc,IjAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iba,ijbc,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iba,ijcb,IjAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iba,ijcb,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,ibc,IjAa,ijbc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,ibc,IjAa,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,ibc,jIAa,ijbc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,ibc,jIAa,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[:nocc, nocc:] += einsum('a,iab,ijbc,IjAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iab,ijbc,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iab,ijcb,IjAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('a,iba,ijbc,IjAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iba,ijbc,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iba,ijcb,IjAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,ibc,IjAa,ijbc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,ibc,IjAa,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[:nocc, nocc:] -= einsum('a,iAb,Ijac,ijbc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iAb,Ijac,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,iAb,Ijca,ijbc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('a,iab,ijbc,IjAc->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iab,ijbc,jIAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,iab,ijcb,IjAc->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('a,ibc,IjAa,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,ibc,jIAa,ijcb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        # 030 #
+        rdm1[:nocc, nocc:] -= einsum('A,a,Ia->IA', L1, R1, t3_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 2 * einsum('a,a,IA->IA', L1, R1, t3_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('A,a,Iiab,ib->IA', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('A,a,Iiba,ib->IA', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 2 * einsum('a,a,IiAb,ib->IA', L1, R1,
+                                         t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('a,a,iIAb,ib->IA', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('a,b,IiAb,ia->IA', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('a,b,iIAb,ia->IA', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+
+############# block- ai
+        # 120 #
+        rdm1[nocc:, :nocc] -= einsum('Iab,a,ijbc,ijAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('Iab,a,ijbc,jiAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('Iab,c,ijab,jiAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('iaA,a,ijbc,Ijbc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iaA,a,ijbc,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iaA,b,ijca,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('iab,a,ijbc,IjAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,a,ijbc,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,a,ijcb,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,a,ijcb,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,c,ijba,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[nocc:, :nocc] -= einsum('Iab,a,ijbc,ijAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('Iab,a,ijbc,jiAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('Iab,b,ijac,ijAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('Iab,b,ijac,jiAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('Iab,c,ijab,ijAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('Iab,c,ijab,jiAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('iAa,a,ijbc,Ijbc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iAa,a,ijbc,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('iAa,b,ijac,Ijbc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iAa,b,ijac,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iAa,b,ijca,Ijbc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iAa,b,ijca,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('iaA,a,ijbc,Ijbc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iaA,a,ijbc,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('iaA,b,ijac,Ijbc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iaA,b,ijac,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iaA,b,ijca,Ijbc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iaA,b,ijca,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('iab,a,ijbc,IjAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,a,ijbc,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,a,ijcb,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,a,ijcb,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('iab,b,ijac,IjAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,b,ijac,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,b,ijca,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,b,ijca,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,c,ijab,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,c,ijab,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,c,ijba,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,c,ijba,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[nocc:, :nocc] += einsum('iab,a,ijbc,IjAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,a,ijbc,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,a,ijcb,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('iab,b,ijac,IjAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,b,ijac,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,b,ijca,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,c,ijab,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,c,ijba,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[nocc:, :nocc] -= einsum('iAa,b,ijac,Ijbc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iAa,b,ijac,Ijcb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iAa,b,ijca,Ijbc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('iab,a,ijbc,IjAc->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,a,ijbc,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,a,ijcb,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('iab,c,ijba,IjAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('iab,c,ijba,jIAc->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        # 021 #
+        rdm1[nocc:, :nocc] -= 2 * einsum('A,iab,Iiab->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('A,iab,Iiba->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 4 * einsum('a,iab,IiAb->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 2 * einsum('a,iab,iIAb->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 2 * einsum('a,iba,IiAb->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('a,iba,iIAb->AI', L1, R2, t2_ccee, optimize = einsum_type)
+
+        # 030 #
+        rdm1[nocc:, :nocc] -= einsum('a,A,Ia->AI', L1, R1, t3_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 2 * einsum('a,a,IA->AI', L1, R1, t3_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('a,A,Iiab,ib->AI', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('a,A,Iiba,ib->AI', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 2 * einsum('a,a,IiAb,ib->AI', L1, R1,
+                                         t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('a,a,iIAb,ib->AI', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('a,b,IiAa,ib->AI', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('a,b,iIAa,ib->AI', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+    return rdm1
+
 
 def compute_dyson_mo(myadc):
 
@@ -1000,24 +1512,28 @@ def __init__(self, adc):
         self.with_df = adc.with_df
         self.compute_properties = adc.compute_properties
         self.approx_trans_moments = adc.approx_trans_moments
-        self.E = None
-        self.U = None
-        self.P = None
-        self.X = None
+
         self.evec_print_tol = adc.evec_print_tol
         self.spec_factor_print_tol = adc.spec_factor_print_tol
 
+        self.E = adc.E
+        self.U = adc.U
+        self.P = adc.P
+        self.X = adc.X
+
     kernel = radc.kernel
     get_imds = get_imds
     matvec = matvec
     get_diag = get_diag
     get_trans_moments = get_trans_moments
-    renormalize_eigenvectors = renormalize_eigenvectors
     get_properties = get_properties
+
+    renormalize_eigenvectors = renormalize_eigenvectors
+    analyze = analyze
     analyze_spec_factor = analyze_spec_factor
     analyze_eigenvector = analyze_eigenvector
-    analyze = analyze
     compute_dyson_mo = compute_dyson_mo
+    make_rdm1 = make_rdm1
 
     def get_init_guess(self, nroots=1, diag=None, ascending=True):
         if diag is None :
diff --git a/pyscf/adc/radc_ip.py b/pyscf/adc/radc_ip.py
index 3b25c541c2..b425194400 100644
--- a/pyscf/adc/radc_ip.py
+++ b/pyscf/adc/radc_ip.py
@@ -12,9 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
-#
 
 '''
 Restricted algebraic diagrammatic construction
@@ -280,7 +282,6 @@ def get_diag(adc,M_ij=None,eris=None):
 
     return diag
 
-
 def matvec(adc, M_ij=None, eris=None):
 
     if adc.method not in ("adc(2)", "adc(2)-x", "adc(3)"):
@@ -779,8 +780,8 @@ def compute_dyson_mo(myadc):
 
     return dyson_mo
 
-def make_rdm1(adc):
 
+def make_rdm1(adc):
     cput0 = (logger.process_clock(), logger.perf_counter())
     log = logger.Logger(adc.stdout, adc.verbose)
 
@@ -796,13 +797,16 @@ def make_rdm1(adc):
     cput0 = log.timer_debug1("completed OPDM calculation", *cput0)
     return list_rdm1
 
+
 def make_rdm1_eigenvectors(adc, L, R):
 
     L = np.array(L).ravel()
     R = np.array(R).ravel()
 
-    t2_1 = adc.t2[0][:]
-    t1_2 = adc.t1[0][:]
+    t2_ce = adc.t1[0][:]
+    t1_ccee = adc.t2[0][:]
+
+    einsum = lib.einsum
 
     nocc = adc._nocc
     nvir = adc._nvir
@@ -828,61 +832,486 @@ def make_rdm1_eigenvectors(adc, L, R):
     R2 = R2.reshape(nvir,nocc,nocc)
 
 #####G^000#### block- ij
-    rdm1[:nocc,:nocc] =  2*np.einsum('ij,m,m->ij',kd_oc,L1,R1,optimize=True)
-    rdm1[:nocc,:nocc] -= np.einsum('i,j->ij',L1,R1,optimize=True)
-
-    rdm1[:nocc,:nocc] += 4*np.einsum('ij,etu,etu->ij',kd_oc,L2,R2,optimize=True)
-    rdm1[:nocc,:nocc] -= np.einsum('ij,etu,eut->ij',kd_oc,L2,R2,optimize=True)
-    rdm1[:nocc,:nocc] -= np.einsum('ij,eut,etu->ij',kd_oc,L2,R2,optimize=True)
-    rdm1[:nocc,:nocc] -= 4*np.einsum('eti,etj->ij',L2,R2,optimize=True)
-    rdm1[:nocc,:nocc] += np.einsum('eti,ejt->ij',L2,R2,optimize=True)
-    rdm1[:nocc,:nocc] += np.einsum('eit,etj->ij',L2,R2,optimize=True)
-
-    rdm1[:nocc,:nocc] -= 2*np.einsum('g,g,hjcd,hicd->ij', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[:nocc,:nocc] += 2*np.einsum('g,g,jhcd,hicd->ij', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[:nocc,:nocc] -= 2*np.einsum('g,g,jhcd,ihcd->ij', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[:nocc,:nocc] += 2*np.einsum('g,h,jgcd,ihcd->ij', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[:nocc,:nocc] -= np.einsum('g,h,gjcd,ihcd->ij', L1,R1,t2_1,t2_1,optimize=True)
-    temp_ij = np.einsum('g,j,ghcd,ihcd->ij',L1,R1,t2_1,t2_1,optimize=True)
-    temp_ij -= 0.25*np.einsum('g,j,hgcd,ihcd->ij',L1,R1,t2_1,t2_1,optimize=True)
-    temp_ij -= 0.25*np.einsum('g,j,ghcd,hicd->ij',L1,R1,t2_1,t2_1,optimize=True)
+    rdm1[:nocc,:nocc] =  2*einsum('ij,m,m->ij',kd_oc,L1,R1,optimize=True)
+    rdm1[:nocc,:nocc] -= einsum('i,j->ij',L1,R1,optimize=True)
+
+    rdm1[:nocc,:nocc] += 4*einsum('ij,etu,etu->ij',kd_oc,L2,R2,optimize=True)
+    rdm1[:nocc,:nocc] -= einsum('ij,etu,eut->ij',kd_oc,L2,R2,optimize=True)
+    rdm1[:nocc,:nocc] -= einsum('ij,eut,etu->ij',kd_oc,L2,R2,optimize=True)
+
+    rdm1[:nocc,:nocc] -= 2*einsum('eti,etj->ij',L2,R2,optimize=True)
+    rdm1[:nocc,:nocc] += einsum('eit,etj->ij',L2,R2,optimize=True)
+    rdm1[:nocc,:nocc] += einsum('eti,ejt->ij',L2,R2,optimize=True)
+    rdm1[:nocc,:nocc] -= 2*einsum('eit,ejt->ij',L2,R2,optimize=True)
+
+    rdm1[:nocc,:nocc] -= 2*einsum('g,g,hjcd,hicd->ij', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    rdm1[:nocc,:nocc] += 2*einsum('g,g,jhcd,hicd->ij', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    rdm1[:nocc,:nocc] -= 2*einsum('g,g,jhcd,ihcd->ij', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    rdm1[:nocc,:nocc] += 2*einsum('g,h,jgcd,ihcd->ij', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    rdm1[:nocc,:nocc] -= einsum('g,h,gjcd,ihcd->ij', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    temp_ij = einsum('g,j,ghcd,ihcd->ij',L1,R1,t1_ccee,t1_ccee,optimize=True)
+    temp_ij -= 0.25*einsum('g,j,hgcd,ihcd->ij',L1,R1,t1_ccee,t1_ccee,optimize=True)
+    temp_ij -= 0.25*einsum('g,j,ghcd,hicd->ij',L1,R1,t1_ccee,t1_ccee,optimize=True)
     rdm1[:nocc,:nocc] += temp_ij
     rdm1[:nocc,:nocc] += temp_ij.T
 
-########## block- ab
-    rdm1[nocc:,nocc:] = np.einsum('atu,btu->ab', L2,R2,optimize=True)
-    rdm1[nocc:,nocc:] -= 0.5*np.einsum('aut,btu->ab', L2,R2,optimize=True)
-    rdm1[nocc:,nocc:] -= 0.5*np.einsum('atu,but->ab', L2,R2,optimize=True)
-    rdm1[nocc:,nocc:] += np.einsum('atu,btu->ab', L2,R2,optimize=True)
-
-    rdm1[nocc:,nocc:] += 4*np.einsum('g,g,hmbc,hmac->ab', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[nocc:,nocc:] -= np.einsum('g,g,mhbc,hmac->ab', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[nocc:,nocc:] -= np.einsum('g,g,hmbc,mhac->ab', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[nocc:,nocc:] -= 4*np.einsum('g,h,hmbc,gmac->ab', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[nocc:,nocc:] += np.einsum('g,h,mhbc,gmac->ab', L1,R1,t2_1,t2_1,optimize=True)
-    rdm1[nocc:,nocc:] += np.einsum('g,h,hmbc,mgac->ab', L1,R1,t2_1,t2_1,optimize=True)
-
-########### block- ia
-    rdm1[:nocc,nocc:] = -np.einsum('n,ani->ia', R1,L2,optimize=True)
-    rdm1[:nocc,nocc:] += 2*np.einsum('n,ain->ia', R1,L2,optimize=True)
-
-    rdm1[:nocc,nocc:] -= 2*np.einsum('g,cgh,ihac->ia', L1,R2,t2_1,optimize=True)
-    rdm1[:nocc,nocc:] += np.einsum('g,cgh,hiac->ia', L1,R2,t2_1,optimize=True)
-    rdm1[:nocc,nocc:] += 4*np.einsum('g,chg,ihac->ia', L1,R2,t2_1,optimize=True)
-    rdm1[:nocc,nocc:] -= np.einsum('g,chg,hiac->ia', L1,R2,t2_1,optimize=True)
-    rdm1[:nocc,nocc:] -= np.einsum('g,cgh,ihac->ia', L1,R2,t2_1,optimize=True)
-    rdm1[:nocc,nocc:] += np.einsum('i,cgh,ghac->ia', L1,R2,t2_1,optimize=True)
-    rdm1[:nocc,nocc:] -= 2*np.einsum('i,chg,ghac->ia', L1,R2,t2_1,optimize=True)
-
-    rdm1[:nocc,nocc:] += np.einsum('g,g,ia->ia', L1,R1,t1_2,optimize=True)
-    rdm1[:nocc,nocc:] += np.einsum('g,g,ia->ia', L1,R1,t1_2,optimize=True)
-    rdm1[:nocc,nocc:] -= np.einsum('g,i,ga->ia', R1,L1,t1_2,optimize=True)
-
-############ block- ai
+########### block- ab
+    rdm1[nocc:,nocc:] = einsum('atu,btu->ab', L2,R2,optimize=True)
+    rdm1[nocc:,nocc:] -= 0.5*einsum('aut,btu->ab', L2,R2,optimize=True)
+    rdm1[nocc:,nocc:] -= 0.5*einsum('atu,but->ab', L2,R2,optimize=True)
+    rdm1[nocc:,nocc:] += einsum('atu,btu->ab', L2,R2,optimize=True)
+
+    rdm1[nocc:,nocc:] += 4*einsum('g,g,hmbc,hmac->ab', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    rdm1[nocc:,nocc:] -= einsum('g,g,mhbc,hmac->ab', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    rdm1[nocc:,nocc:] -= einsum('g,g,hmbc,mhac->ab', L1,R1,t1_ccee,t1_ccee,optimize=True)
+
+    rdm1[nocc:,nocc:] -= 2 * einsum('g,h,hmbc,gmac->ab', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    rdm1[nocc:,nocc:] -= 2 * einsum('g,h,mhbc,mgac->ab', L1,R1,t1_ccee,t1_ccee,optimize=True)
+
+    rdm1[nocc:,nocc:] += einsum('g,h,mhbc,gmac->ab', L1,R1,t1_ccee,t1_ccee,optimize=True)
+    rdm1[nocc:,nocc:] += einsum('g,h,hmbc,mgac->ab', L1,R1,t1_ccee,t1_ccee,optimize=True)
+
+
+############ block- ia
+    rdm1[:nocc,nocc:] = -einsum('n,ani->ia', R1,L2,optimize=True)
+    rdm1[:nocc,nocc:] += 2*einsum('n,ain->ia', R1,L2,optimize=True)
+    rdm1[:nocc,nocc:] -= 2*einsum('g,cgh,ihac->ia', L1,R2,t1_ccee,optimize=True)
+    rdm1[:nocc,nocc:] += 4*einsum('g,chg,ihac->ia', L1,R2,t1_ccee,optimize=True)
+    rdm1[:nocc,nocc:] += einsum('g,cgh,hiac->ia', L1,R2,t1_ccee,optimize=True)
+    rdm1[:nocc,nocc:] -= 2*einsum('g,chg,hiac->ia', L1,R2,t1_ccee,optimize=True)
+
+    rdm1[:nocc,nocc:] += einsum('i,cgh,ghac->ia', L1,R2,t1_ccee,optimize=True)
+    rdm1[:nocc,nocc:] -= 2*einsum('i,chg,ghac->ia', L1,R2,t1_ccee,optimize=True)
+
+    rdm1[:nocc,nocc:] += einsum('g,g,ia->ia', L1,R1,t2_ce,optimize=True)
+    rdm1[:nocc,nocc:] += einsum('g,g,ia->ia', L1,R1,t2_ce,optimize=True)
+    rdm1[:nocc,nocc:] -= einsum('g,i,ga->ia', R1,L1,t2_ce,optimize=True)
+
+############# block- ai
     rdm1[nocc:,:nocc] = rdm1[:nocc,nocc:].T
 
+    ####### ADC(3) SPIN ADAPTED EXCITED STATE OPDM WITH SQA ################
+    if adc.method == "adc(3)":
+        ### Redudant Variables used for names from SQA
+        einsum_type = True
+        t3 = adc.t1[1][:]
+        t2_ccee = adc.t2[1][:]
+        ###################################################
+
+############# block- ij
+        ### 030 ###
+        rdm1[:nocc, :nocc] += einsum('J,i,Ijab,ijab->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= 1/2 * einsum('J,i,Ijab,ijba->IJ',
+                                           L1, R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('J,i,ijab,Ijab->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= 1/2 * einsum('J,i,ijab,Ijba->IJ',
+                                           L1, R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,I,Jjab,ijab->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= 1/2 * einsum('i,I,Jjab,ijba->IJ',
+                                           L1, R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,I,ijab,Jjab->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= 1/2 * einsum('i,I,ijab,Jjba->IJ',
+                                           L1, R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= 2 * einsum('i,i,Ijab,Jjab->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,i,Ijab,Jjba->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= 2 * einsum('i,i,Jjab,Ijab->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,i,Jjab,Ijba->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,j,Iiab,Jjab->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= einsum('i,j,Iiab,Jjba->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,j,Jjab,Iiab->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= einsum('i,j,Jjab,Iiba->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+
+        rdm1[:nocc, :nocc] -= 2 * einsum('i,i,Ijab,Jjab->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,i,Ijab,Jjba->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] -= 2 * einsum('i,i,Jjab,Ijab->IJ', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,i,Jjab,Ijba->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,j,Iiab,Jjab->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,j,Jjab,Iiab->IJ', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+
+        ### 021 ###
+        rdm1[:nocc, :nocc] -= 2 * einsum('i,aIi,Ja->IJ', L1, R2, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('i,aiI,Ja->IJ', L1, R2, t2_ce, optimize = einsum_type)
+
+        ### 120 ###
+        rdm1[:nocc, :nocc] -= 2 * einsum('aJi,i,Ia->IJ', L2, R1, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, :nocc] += einsum('aiJ,i,Ia->IJ', L2, R1, t2_ce, optimize = einsum_type)
+
+        #----------------------------------------------------------------------------------------------------------#
+
+############# block- ab
+        ### 030 ###
+        rdm1[nocc:, nocc:] += 2 * einsum('i,i,jkAa,jkBa->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('i,i,jkAa,kjBa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 2 * einsum('i,i,jkBa,jkAa->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('i,i,jkBa,kjAa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= 2 * einsum('i,j,ikBa,jkAa->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += einsum('i,j,ikBa,kjAa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= 2 * einsum('i,j,jkAa,ikBa->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += einsum('i,j,jkAa,kiBa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += einsum('i,j,kiBa,jkAa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('i,j,kiBa,kjAa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += einsum('i,j,kjAa,ikBa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('i,j,kjAa,kiBa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+
+        rdm1[nocc:, nocc:] += 2 * einsum('i,i,jkAa,jkBa->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('i,i,jkAa,kjBa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 2 * einsum('i,i,jkBa,jkAa->AB', L1,
+                                         R1, t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('i,i,jkBa,kjAa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('i,j,kiBa,kjAa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, nocc:] -= einsum('i,j,kjAa,kiBa->AB', L1, R1,
+                                     t1_ccee, t2_ccee, optimize = einsum_type)
+
+        ### 021 ###
+        rdm1[nocc:, nocc:] -= einsum('i,Bij,jA->AB', L1, R2, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 2 * einsum('i,Bji,jA->AB', L1, R2, t2_ce, optimize = einsum_type)
+
+        ### 120 ###
+        rdm1[nocc:, nocc:] -= einsum('Aij,i,jB->AB', L2, R1, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, nocc:] += 2 * einsum('Aij,j,iB->AB', L2, R1, t2_ce, optimize = einsum_type)
+
+        #----------------------------------------------------------------------------------------------------------#
+############# block- ia
+        ### 030 ###
+        rdm1[:nocc, nocc:] -= einsum('i,I,iA->IA', L1, R1, t3, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,i,IA->IA', L1, R1, t3, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('i,I,ijAa,ja->IA', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,I,jiAa,ja->IA', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,i,IjAa,ja->IA', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,i,jIAa,ja->IA', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,j,IiAa,ja->IA', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,j,iIAa,ja->IA', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+
+        rdm1[:nocc, nocc:] += einsum('i,i,IA->IA', L1, R1, t3, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,i,IjAa,ja->IA', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,i,jIAa,ja->IA', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,j,IiAa,ja->IA', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+
+        ### 021 ###
+        rdm1[:nocc, nocc:] -= einsum('i,ajI,ikAb,jkab->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,ajI,ikAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,ajI,kiAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,aji,jkab,IkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aji,jkab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aji,kjab,IkAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,ajk,IiAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,ajk,iIAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[:nocc, nocc:] += einsum('i,Aij,jkab,Ikab->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,Aij,jkab,Ikba->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('i,Aji,jkab,Ikab->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,Aji,jkab,Ikba->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,Ajk,Iiab,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,Ajk,Iiab,jkba->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('i,aIi,jkab,jkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aIi,jkab,kjAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,aIj,ikAb,jkab->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aIj,ikAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aIj,kiAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aIj,kiAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,aiI,jkab,jkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aiI,jkab,kjAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('i,aij,jkab,IkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aij,jkab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aij,kjab,IkAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aij,kjab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('i,ajI,ikAb,jkab->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,ajI,ikAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,ajI,kiAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,ajI,kiAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,aji,jkab,IkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aji,jkab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aji,kjab,IkAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aji,kjab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,ajk,IiAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,ajk,IiAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,ajk,iIAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,ajk,iIAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[:nocc, nocc:] -= einsum('i,Aji,jkab,Ikab->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,Aji,jkab,Ikba->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,Ajk,Iiab,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= einsum('i,aIi,jkab,jkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aIi,jkab,kjAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aIj,kiAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,aji,jkab,IkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aji,jkab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aji,kjab,IkAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aji,kjab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,ajk,IiAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[:nocc, nocc:] -= einsum('i,aij,jkab,IkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aij,jkab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,aij,kjab,IkAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('i,aji,jkab,IkAb->IA', L1, R2,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aji,jkab,kIAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,aji,kjab,IkAb->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 1/2 * einsum('i,ajk,IiAb,jkab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 1/2 * einsum('i,ajk,IiAb,kjab->IA',
+                                           L1, R2, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        ### 120 ###
+        rdm1[:nocc, nocc:] += einsum('aij,I,ijAa->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 2 * einsum('aij,I,jiAa->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 2 * einsum('aij,i,IjAa->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += einsum('aij,i,jIAa->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] += 4 * einsum('aij,j,IiAa->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        rdm1[:nocc, nocc:] -= 2 * einsum('aij,j,iIAa->IA', L2, R1, t2_ccee, optimize = einsum_type)
+        #----------------------------------------------------------------------------------------------------------#
+############# block- ai
+        ### 030 ###
+        rdm1[nocc:, :nocc] -= einsum('I,i,iA->AI', L1, R1, t3, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('i,i,IA->AI', L1, R1, t3, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('I,i,ijAa,ja->AI', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('I,i,jiAa,ja->AI', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('i,i,IjAa,ja->AI', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('i,i,jIAa,ja->AI', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('i,j,IjAa,ia->AI', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('i,j,jIAa,ia->AI', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+
+        rdm1[nocc:, :nocc] += einsum('i,i,IA->AI', L1, R1, t3, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('i,i,IjAa,ja->AI', L1, R1, t1_ccee,
+                                     t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('i,i,jIAa,ja->AI', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('i,j,IjAa,ia->AI', L1,
+                                           R1, t1_ccee, t2_ce, optimize = einsum_type)
+
+        ### 021 ###
+        rdm1[nocc:, :nocc] += einsum('I,aij,ijAa->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 2 * einsum('I,aij,jiAa->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 2 * einsum('i,aij,IjAa->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('i,aij,jIAa->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 4 * einsum('i,aji,IjAa->AI', L1, R2, t2_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 2 * einsum('i,aji,jIAa->AI', L1, R2, t2_ccee, optimize = einsum_type)
+
+        ### 120 ###
+        rdm1[nocc:, :nocc] -= einsum('aiI,j,ikab,jkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aiI,j,ikab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aiI,j,kiab,jkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('aij,j,ikab,IkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,j,ikab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,j,kiab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,k,ijab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,k,ijab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[nocc:, :nocc] += einsum('Aij,i,jkab,Ikab->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('Aij,i,jkab,Ikba->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('Aij,j,ikab,Ikab->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('Aij,j,ikab,Ikba->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('Aij,k,ijab,Ikab->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('Aij,k,ijab,Ikba->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('aIi,i,jkab,jkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aIi,i,jkab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('aIi,j,ikab,jkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aIi,j,ikab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aIi,j,kiab,jkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aIi,j,kiab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('aiI,i,jkab,jkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aiI,i,jkab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('aiI,j,ikab,jkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aiI,j,ikab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aiI,j,kiab,jkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aiI,j,kiab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('aij,i,jkab,IkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,i,jkab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,i,kjab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,i,kjab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('aij,j,ikab,IkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,j,ikab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,j,kiab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,j,kiab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,k,ijab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,k,ijab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,k,jiab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,k,jiab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[nocc:, :nocc] -= einsum('Aij,j,ikab,Ikab->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('Aij,j,ikab,Ikba->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('Aij,k,ijab,Ikab->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= einsum('aIi,i,jkab,jkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aIi,i,jkab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aIi,j,kiab,kjAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('aij,j,ikab,IkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,j,ikab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,j,kiab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,j,kiab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,k,ijab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+
+        rdm1[nocc:, :nocc] -= einsum('aij,i,jkab,IkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,i,jkab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,i,kjab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += einsum('aij,j,ikab,IkAb->AI', L2, R1,
+                                     t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,j,ikab,kIAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,j,kiab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] -= 1/2 * einsum('aij,k,ijab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+        rdm1[nocc:, :nocc] += 1/2 * einsum('aij,k,jiab,IkAb->AI',
+                                           L2, R1, t1_ccee, t1_ccee, optimize = einsum_type)
+
     return rdm1
 
+
 class RADCIP(radc.RADC):
     '''restricted ADC for IP energies and spectroscopic amplitudes
 
@@ -956,23 +1385,26 @@ def __init__(self, adc):
         self.with_df = adc.with_df
         self.compute_properties = adc.compute_properties
         self.approx_trans_moments = adc.approx_trans_moments
-        self.E = None
-        self.U = None
-        self.P = None
-        self.X = None
+
         self.evec_print_tol = adc.evec_print_tol
         self.spec_factor_print_tol = adc.spec_factor_print_tol
 
+        self.E = adc.E
+        self.U = adc.U
+        self.P = adc.P
+        self.X = adc.X
+
     kernel = radc.kernel
     get_imds = get_imds
     get_diag = get_diag
     matvec = matvec
     get_trans_moments = get_trans_moments
-    renormalize_eigenvectors = renormalize_eigenvectors
     get_properties = get_properties
+
+    renormalize_eigenvectors = renormalize_eigenvectors
+    analyze = analyze
     analyze_spec_factor = analyze_spec_factor
     analyze_eigenvector = analyze_eigenvector
-    analyze = analyze
     compute_dyson_mo = compute_dyson_mo
     make_rdm1 = make_rdm1
 
diff --git a/pyscf/adc/radc_ip_cvs.py b/pyscf/adc/radc_ip_cvs.py
index 9448a5a9a5..0e5ce153b2 100644
--- a/pyscf/adc/radc_ip_cvs.py
+++ b/pyscf/adc/radc_ip_cvs.py
@@ -12,9 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Abdelrahman Ahmed <abdelrahman.maa.ahmed@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
-#
 
 '''
 Restricted algebraic diagrammatic construction
diff --git a/pyscf/adc/uadc.py b/pyscf/adc/uadc.py
index be88732ef9..a62d2f66f4 100644
--- a/pyscf/adc/uadc.py
+++ b/pyscf/adc/uadc.py
@@ -12,9 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
-#
 
 '''
 Unrestricted algebraic diagrammatic construction
@@ -29,6 +31,7 @@
 from pyscf.adc import dfadc
 from pyscf import __config__
 from pyscf import df
+from pyscf import scf
 
 
 # Excited-state kernel
@@ -44,13 +47,17 @@ def kernel(adc, nroots=1, guess=None, eris=None, verbose=None):
         adc.check_sanity()
     adc.dump_flags()
 
+    if isinstance(adc._scf, scf.rohf.ROHF) and (adc.method_type == "ip" or adc.method_type == "ea"):
+        logger.warn(
+            adc, "EA/IP-ADC with the ROHF reference do not incorporate the occ-vir Fock matrix elements...")
+
     if eris is None:
         eris = adc.transform_integrals()
 
     imds = adc.get_imds(eris)
     matvec, diag = adc.gen_matvec(imds, eris)
 
-    guess = adc.get_init_guess(nroots, diag, ascending=True)
+    guess = adc.get_init_guess(nroots, diag, ascending = True)
 
     conv, adc.E, U = lib.linalg_helper.davidson1(
         lambda xs : [matvec(x) for x in xs],
@@ -61,7 +68,6 @@ def kernel(adc, nroots=1, guess=None, eris=None, verbose=None):
 
     if adc.compute_properties:
         adc.P,adc.X = adc.get_properties(nroots)
-
     nfalse = np.shape(conv)[0] - np.sum(conv)
 
     header = ("\n*************************************************************"
@@ -69,17 +75,17 @@ def kernel(adc, nroots=1, guess=None, eris=None, verbose=None):
               "\n*************************************************************")
     logger.info(adc, header)
 
-    if nfalse >= 1:
-        logger.warn(adc, "Davidson iterations for " + str(nfalse) + " root(s) not converged\n")
-
     for n in range(nroots):
         print_string = ('%s root %d  |  Energy (Eh) = %14.10f  |  Energy (eV) = %12.8f  ' %
                         (adc.method, n, adc.E[n], adc.E[n]*27.2114))
         if adc.compute_properties:
-            print_string += ("|  Spec factors = %10.8f  " % adc.P[n])
+            print_string += ("|  Spec. factor = %10.8f  " % adc.P[n])
         print_string += ("|  conv = %s" % conv[n])
         logger.info(adc, print_string)
 
+    if nfalse >= 1:
+        logger.warn(adc, "Davidson iterations for " + str(nfalse) + " root(s) did not converge!!!")
+
     log.timer('ADC', *cput0)
 
     return adc.E, adc.U, adc.P, adc.X
@@ -114,14 +120,13 @@ class UADC(lib.StreamObject):
     incore_complete = getattr(__config__, 'adc_uadc_UADC_incore_complete', False)
 
     _keys = {
-        'tol_residual','conv_tol', 'e_corr', 'method',
-        'method_type', 'mo_coeff', 'mol', 'mo_energy_b',
-        'scf_energy', 'e_tot', 't1', 'frozen',
-        'mo_energy_a', 'chkfile', 'max_space', 't2', 'mo_occ', 'max_cycle',
-        'incore_complete', 'mo_energy_a', 'mo_energy_b', 'with_df',
-        'compute_mpn_energy', 'compute_spec', 'compute_properties',
+        'tol_residual','conv_tol', 'e_corr', 'method', 'method_type', 'mo_coeff',
+        'mol', 'mo_energy_a', 'mo_energy_b', 'incore_complete',
+        'scf_energy', 'e_tot', 't1', 't2', 'frozen', 'chkfile',
+        'max_space', 'mo_occ', 'max_cycle', 'imds', 'with_df', 'compute_properties',
         'approx_trans_moments', 'evec_print_tol', 'spec_factor_print_tol',
-        'E', 'U', 'P', 'X', 'ncvs',
+        'E', 'U', 'P', 'X', 'ncvs', 'dip_mom', 'dip_mom_nuc',
+        'spin_c', 'f_ov'
     }
 
     def __init__(self, mf, frozen=None, mo_coeff=None, mo_occ=None):
@@ -144,12 +149,59 @@ def __init__(self, mf, frozen=None, mo_coeff=None, mo_occ=None):
         self.max_space = getattr(__config__, 'adc_uadc_UADC_max_space', 12)
         self.max_cycle = getattr(__config__, 'adc_uadc_UADC_max_cycle', 50)
         self.conv_tol = getattr(__config__, 'adc_uadc_UADC_conv_tol', 1e-12)
-        self.tol_residual = getattr(__config__, 'adc_uadc_UADC_tol_res', 1e-6)
-
+        self.tol_residual = getattr(__config__, 'adc_uadc_UADC_tol_residual', 1e-6)
         self.scf_energy = mf.e_tot
+
         self.frozen = frozen
         self.incore_complete = self.incore_complete or self.mol.incore_anyway
 
+        self.f_ov = None
+
+        if isinstance(mf, scf.rohf.ROHF):
+
+            logger.info(mf, "\nROHF reference detected in ADC, semicanonicalizing the orbitals...")
+
+            mo_a = mo_coeff.copy()
+            nalpha = mf.mol.nelec[0]
+            nbeta = mf.mol.nelec[1]
+
+            h1e = mf.get_hcore()
+            dm = mf.make_rdm1()
+            vhf = mf.get_veff(mf.mol, dm)
+
+            fock_a = h1e + vhf[0]
+            fock_b = h1e + vhf[1]
+
+            if nalpha > nbeta:
+                ndocc = nbeta
+                nsocc = nalpha - nbeta
+            else:
+                ndocc = nalpha
+                nsocc = nbeta - nalpha
+
+            fock_a = np.dot(mo_a.T,np.dot(fock_a, mo_a))
+            fock_b = np.dot(mo_a.T,np.dot(fock_b, mo_a))
+
+            # Semicanonicalize Ca using fock_a, nocc_a -> Ca, mo_energy_a, U_a, f_ov_a
+            mo_a, mo_energy_a, f_ov_a, f_aa = self.semi_canonicalize_orbitals(
+                fock_a, ndocc + nsocc, mo_a)
+
+            # Semicanonicalize Cb using fock_b, nocc_b -> Cb, mo_energy_b, U_b, f_ov_b
+            mo_b, mo_energy_b, f_ov_b, f_bb = self.semi_canonicalize_orbitals(fock_b, ndocc, mo_a)
+
+            mo_coeff = [mo_a, mo_b]
+
+            f_ov = [f_ov_a, f_ov_b]
+
+            self.f_ov = f_ov
+            self.spin_c = True
+            self.mo_energy_a = mo_energy_a.copy()
+            self.mo_energy_b = mo_energy_b.copy()
+
+        else:
+            self.mo_energy_a = mf.mo_energy[0]
+            self.mo_energy_b = mf.mo_energy[1]
+
         self.mo_coeff = mo_coeff
         self.mo_occ = mo_occ
         self.e_corr = None
@@ -159,28 +211,66 @@ def __init__(self, mf, frozen=None, mo_coeff=None, mo_occ=None):
         self._nocc = mf.nelec
         self._nmo = (mo_coeff[0].shape[1], mo_coeff[1].shape[1])
         self._nvir = (self._nmo[0] - self._nocc[0], self._nmo[1] - self._nocc[1])
-        self.mo_energy_a = mf.mo_energy[0]
-        self.mo_energy_b = mf.mo_energy[1]
         self.chkfile = mf.chkfile
         self.method = "adc(2)"
         self.method_type = "ip"
         self.with_df = None
-        self.compute_mpn_energy = True
-        self.compute_spec = True
         self.compute_properties = True
         self.approx_trans_moments = False
         self.evec_print_tol = 0.1
         self.spec_factor_print_tol = 0.1
+        self.ncvs = None
+
         self.E = None
         self.U = None
         self.P = None
         self.X = (None,)
-        self.ncvs = None
+
+        self.spin_c = False
+
+        dip_ints = -self.mol.intor('int1e_r',comp=3)
+        dip_mom_a = np.zeros((dip_ints.shape[0], self._nmo[0], self._nmo[0]))
+        dip_mom_b = np.zeros((dip_ints.shape[0], self._nmo[1], self._nmo[1]))
+
+        for i in range(dip_ints.shape[0]):
+            dip = dip_ints[i,:,:]
+            dip_mom_a[i,:,:] = np.dot(mo_coeff[0].T, np.dot(dip, mo_coeff[0]))
+            dip_mom_b[i,:,:] = np.dot(mo_coeff[1].T, np.dot(dip, mo_coeff[1]))
+
+        self.dip_mom = []
+        self.dip_mom.append(dip_mom_a)
+        self.dip_mom.append(dip_mom_b)
+
+        charges = self.mol.atom_charges()
+        coords  = self.mol.atom_coords()
+        self.dip_mom_nuc = lib.einsum('i,ix->x', charges, coords)
 
     compute_amplitudes = uadc_amplitudes.compute_amplitudes
     compute_energy = uadc_amplitudes.compute_energy
     transform_integrals = uadc_ao2mo.transform_integrals_incore
 
+    def semi_canonicalize_orbitals(self, f, nocc, C):
+
+        # Diagonalize occ-occ block
+        evals_oo, evecs_oo = np.linalg.eigh(f[:nocc, :nocc])
+
+        # Diagonalize virt-virt block
+        evals_vv, evecs_vv = np.linalg.eigh(f[nocc:, nocc:])
+
+        evals = np.hstack((evals_oo, evals_vv))
+
+        U = np.zeros_like(f)
+
+        U[:nocc, :nocc] = evecs_oo
+        U[nocc:, nocc:] = evecs_vv
+
+        C = np.dot(C, U)
+
+        transform_f = np.dot(U.T, np.dot(f, U))
+        f_ov = transform_f[:nocc, nocc:].copy()
+
+        return C, evals, f_ov, transform_f
+
     def dump_flags(self, verbose=None):
         logger.info(self, '')
         logger.info(self, '******** %s ********', self.__class__)
@@ -200,8 +290,8 @@ def dump_flags_gs(self, verbose=None):
         return self
 
     def kernel_gs(self):
-        assert (self.mo_coeff is not None)
-        assert (self.mo_occ is not None)
+        assert(self.mo_coeff is not None)
+        assert(self.mo_occ is not None)
 
         self.method = self.method.lower()
         if self.method not in ("adc(2)", "adc(2)-x", "adc(3)"):
@@ -301,8 +391,8 @@ def outcore_transform():
 
     def _finalize(self):
         '''Hook for dumping results and clearing up the object.'''
-        logger.note(self, 'E_corr = %.8f',
-                    self.e_corr)
+        logger.note(self, 'MP%s correlation energy of reference state (a.u.) = %.8f',
+                    self.method[4], self.e_corr)
         return self
 
     def ea_adc(self, nroots=1, guess=None, eris=None):
@@ -347,7 +437,6 @@ def make_rdm1(self):
         return self._adc_es.make_rdm1()
 
 if __name__ == '__main__':
-    from pyscf import scf
     from pyscf import gto
     from pyscf import adc
 
diff --git a/pyscf/adc/uadc_amplitudes.py b/pyscf/adc/uadc_amplitudes.py
index 225f3dcba2..d2ec13da7e 100644
--- a/pyscf/adc/uadc_amplitudes.py
+++ b/pyscf/adc/uadc_amplitudes.py
@@ -12,7 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
 #
 
@@ -29,7 +32,7 @@
 from pyscf.adc.radc_amplitudes import _create_t2_h5cache
 from pyscf import __config__
 from pyscf import df
-
+from pyscf import scf
 
 def compute_amplitudes_energy(myadc, eris, verbose=None):
 
@@ -126,12 +129,29 @@ def compute_amplitudes(myadc, eris):
 
     cput0 = log.timer_debug1("Completed t2_1 amplitude calculation", *cput0)
 
+    t1_1 = (None,)
+
+    if isinstance(myadc._scf, scf.rohf.ROHF):
+
+        f_ov_a, f_ov_b = myadc.f_ov
+
+        t1_1_a = f_ov_a/D1_a
+        t1_1_b = f_ov_b/D1_b
+        t1_1 = (t1_1_a, t1_1_b)
+    else:
+        f_ov_a = np.zeros((nocc_a, nvir_a))
+        f_ov_b = np.zeros((nocc_b, nvir_b))
+        t1_1_a = np.zeros((nocc_a, nvir_a))
+        t1_1_b = np.zeros((nocc_b, nvir_b))
+
+
     t1_2 = (None,)
     if myadc.approx_trans_moments is False or myadc.method == "adc(3)":
         # Compute second-order singles t1 (tij)
 
         t1_2_a = np.zeros((nocc_a,nvir_a))
         t1_2_b = np.zeros((nocc_b,nvir_b))
+
         if isinstance(eris.ovvv, type(None)):
             chnk_size = uadc_ao2mo.calculate_chunk_size(myadc)
             a = 0
@@ -152,6 +172,33 @@ def compute_amplitudes(myadc, eris):
         t1_2_a -= 0.5*lib.einsum('lcki,klac->ia',eris_ovoo,t2_1_a[:],optimize=True)
         t1_2_a += 0.5*lib.einsum('kcli,klac->ia',eris_ovoo,t2_1_a[:],optimize=True)
 
+        if isinstance(myadc._scf, scf.rohf.ROHF):
+            t1_2_a += lib.einsum('d,ld,ilad->ia',e_a[nocc_a:],t1_1_a,t2_1_a[:], optimize = True)
+            t1_2_a += lib.einsum('d,ld,ilad->ia',e_b[nocc_b:],t1_1_b,t2_1_ab[:], optimize = True)
+
+            t1_2_a -= lib.einsum('l,ld,ilad->ia',e_a[:nocc_a],t1_1_a,t2_1_a[:], optimize = True)
+            t1_2_a -= lib.einsum('l,ld,ilad->ia',e_b[:nocc_b],t1_1_b,t2_1_ab[:], optimize = True)
+
+
+            t1_2_a += 0.5*lib.einsum('a,ld,ilad->ia',e_a[nocc_a:],t1_1_a,t2_1_a[:], optimize = True)
+            t1_2_a += 0.5*lib.einsum('a,ld,ilad->ia',
+                                     e_a[nocc_a:],t1_1_b,t2_1_ab[:], optimize = True)
+
+            t1_2_a -= 0.5*lib.einsum('i,ld,ilad->ia',e_a[:nocc_a],t1_1_a,t2_1_a[:], optimize = True)
+            t1_2_a -= 0.5*lib.einsum('i,ld,ilad->ia',
+                                     e_a[:nocc_a],t1_1_b,t2_1_ab[:], optimize = True)
+
+            t1_2_a += lib.einsum('ld,ilad->ia',f_ov_a,t2_1_a[:], optimize = True)
+            t1_2_a += lib.einsum('ld,ilad->ia',f_ov_b,t2_1_ab[:], optimize = True)
+
+            t1_2_a += lib.einsum('ld,iadl->ia',t1_1_a, eris.ovvo, optimize = True)
+            t1_2_a -= lib.einsum('ld,idal->ia',t1_1_a, eris.ovvo, optimize = True)
+            t1_2_a += lib.einsum('ld,iadl->ia',t1_1_b, eris.ovVO, optimize = True)
+
+            t1_2_a += lib.einsum('ld,iadl->ia',t1_1_a,eris.ovvo, optimize = True)
+            t1_2_a -= lib.einsum('ld,liad->ia',t1_1_a,eris.oovv, optimize = True)
+            t1_2_a += lib.einsum('ld,iadl->ia',t1_1_b,eris.ovVO, optimize = True)
+
         if isinstance(eris.OVvv, type(None)):
             chnk_size = uadc_ao2mo.calculate_chunk_size(myadc)
             a = 0
@@ -184,7 +231,33 @@ def compute_amplitudes(myadc, eris):
             del eris_ovVV
 
         t1_2_a -= lib.einsum('lcki,klac->ia',eris_OVoo,t2_1_ab[:],optimize=True)
-        t1_2_b -= lib.einsum('lcki,lkca->ia',eris_ovOO,t2_1_ab[:])
+        t1_2_b -= lib.einsum('lcki,lkca->ia',eris_ovOO,t2_1_ab[:],optimize=True)
+
+        if isinstance(myadc._scf, scf.rohf.ROHF):
+            t1_2_b += lib.einsum('d,ld,ilad->ia',e_b[nocc_b:],t1_1_b,t2_1_b[:], optimize = True)
+            t1_2_b += lib.einsum('d,ld,lida->ia',e_a[nocc_a:],t1_1_a,t2_1_ab[:], optimize = True)
+
+            t1_2_b -= lib.einsum('l,ld,ilad->ia',e_b[:nocc_b],t1_1_b,t2_1_b[:], optimize = True)
+            t1_2_b -= lib.einsum('l,ld,lida->ia',e_a[:nocc_a],t1_1_a,t2_1_ab[:], optimize = True)
+
+            t1_2_b += 0.5*lib.einsum('a,ld,ilad->ia',e_b[nocc_b:],t1_1_b,t2_1_b[:], optimize = True)
+            t1_2_b += 0.5*lib.einsum('a,ld,lida->ia',
+                                     e_b[nocc_b:],t1_1_a,t2_1_ab[:], optimize = True)
+
+            t1_2_b -= 0.5*lib.einsum('i,ld,ilad->ia',e_b[:nocc_b],t1_1_b,t2_1_b[:], optimize = True)
+            t1_2_b -= 0.5*lib.einsum('i,ld,lida->ia',
+                                     e_b[:nocc_b],t1_1_a,t2_1_ab[:], optimize = True)
+
+            t1_2_b += lib.einsum('ld,ilad->ia',f_ov_b,t2_1_b[:], optimize = True)
+            t1_2_b += lib.einsum('ld,lida->ia',f_ov_a,t2_1_ab[:], optimize = True)
+
+            t1_2_b += lib.einsum('ld,iadl->ia',t1_1_b, eris.OVVO, optimize = True)
+            t1_2_b -= lib.einsum('ld,idal->ia',t1_1_b, eris.OVVO, optimize = True)
+            t1_2_b += lib.einsum('ld,ldai->ia',t1_1_a, eris.ovVO, optimize = True)
+
+            t1_2_b += lib.einsum('ld,iadl->ia',t1_1_b,eris.OVVO, optimize = True)
+            t1_2_b -= lib.einsum('ld,liad->ia',t1_1_b,eris.OOVV, optimize = True)
+            t1_2_b += lib.einsum('ld,ldai->ia',t1_1_a,eris.ovVO, optimize = True)
 
         if isinstance(eris.OVVV, type(None)):
             chnk_size = uadc_ao2mo.calculate_chunk_size(myadc)
@@ -234,19 +307,20 @@ def compute_amplitudes(myadc, eris):
             eris_vvvv = eris.vvvv_p
             temp = np.ascontiguousarray(
                 t2_1_a[:,:,ab_ind_a[0],ab_ind_a[1]]).reshape(nocc_a*nocc_a,-1)
-            t2_1_vvvv_a = np.dot(temp,eris_vvvv.T).reshape(nocc_a, nocc_a, -1)
+            temp = np.dot(temp,eris_vvvv.T).reshape(nocc_a, nocc_a, -1)
+            t2_1_vvvv_a = np.zeros((nocc_a,nocc_a,nvir_a,nvir_a))
+            t2_1_vvvv_a[:,:,ab_ind_a[0],ab_ind_a[1]] = temp
+            t2_1_vvvv_a[:,:,ab_ind_a[1],ab_ind_a[0]] = -temp
             del eris_vvvv
         elif isinstance(eris.vvvv_p, list):
-            t2_1_vvvv_a = contract_ladder_antisym(myadc,t2_1_a[:], eris.vvvv_p)
+            t2_1_vvvv_a = contract_ladder_antisym(myadc,t2_1_a[:], eris.vvvv_p, pack = False)
         else:
-            t2_1_vvvv_a = contract_ladder_antisym(myadc,t2_1_a[:], eris.Lvv)
+            t2_1_vvvv_a = contract_ladder(myadc, t2_1_a[:], (eris.Lvv, eris.Lvv))
 
         if not isinstance(eris.oooo, np.ndarray):
             t2_1_vvvv_a = h5cache_t2.create_dataset('t2_1_vvvv_a', data=t2_1_vvvv_a)
 
-        t2_2_a = np.zeros((nocc_a,nocc_a,nvir_a,nvir_a))
-        t2_2_a[:,:,ab_ind_a[0],ab_ind_a[1]] = t2_1_vvvv_a[:]
-        t2_2_a[:,:,ab_ind_a[1],ab_ind_a[0]] = -t2_1_vvvv_a[:]
+        t2_2_a = t2_1_vvvv_a[:].copy()
 
         t2_2_a += 0.5*lib.einsum('kilj,klab->ijab', eris_oooo, t2_1_a[:],optimize=True)
         t2_2_a -= 0.5*lib.einsum('kjli,klab->ijab', eris_oooo, t2_1_a[:],optimize=True)
@@ -262,23 +336,53 @@ def compute_amplitudes(myadc, eris):
         del temp
         del temp_1
 
+        if isinstance(myadc._scf, scf.rohf.ROHF):
+            t2_2_a += lib.einsum('la,ibjl->ijab',t1_1_a,eris.ovoo, optimize = True)
+            t2_2_a -= lib.einsum('la,jbil->ijab',t1_1_a,eris.ovoo, optimize = True)
+
+
+            t2_2_a -= lib.einsum('lb,iajl->ijab',t1_1_a,eris.ovoo, optimize = True)
+            t2_2_a += lib.einsum('lb,jail->ijab',t1_1_a,eris.ovoo, optimize = True)
+
+            if isinstance(eris.ovvv, type(None)):
+                chnk_size = uadc_ao2mo.calculate_chunk_size(myadc)
+                a = 0
+                for p in range(0,nocc_a,chnk_size):
+                    eris_ovvv = dfadc.get_ovvv_spin_df(
+                        myadc, eris.Lov, eris.Lvv, p, chnk_size).reshape(-1,nvir_a,nvir_a,nvir_a)
+                    k = eris_ovvv.shape[0]
+                    t2_2_a[:,a:a+k] += lib.einsum('id,jbad->ijab',t1_1_a,eris_ovvv, optimize = True)
+                    t2_2_a[:,a:a+k] -= lib.einsum('id,jabd->ijab',t1_1_a,eris_ovvv, optimize = True)
+                    t2_2_a[a:a+k] -= lib.einsum('jd,ibad->ijab',t1_1_a,eris_ovvv, optimize = True)
+                    t2_2_a[a:a+k] += lib.einsum('jd,iabd->ijab',t1_1_a,eris_ovvv, optimize = True)
+                    del eris_ovvv
+                    a += k
+            else:
+                eris_ovvv = uadc_ao2mo.unpack_eri_1(eris.ovvv, nvir_a)
+                t2_2_a += lib.einsum('id,jbad->ijab',t1_1_a,eris_ovvv, optimize = True)
+                t2_2_a -= lib.einsum('id,jabd->ijab',t1_1_a,eris_ovvv, optimize = True)
+                t2_2_a -= lib.einsum('jd,ibad->ijab',t1_1_a,eris_ovvv, optimize = True)
+                t2_2_a += lib.einsum('jd,iabd->ijab',t1_1_a,eris_ovvv, optimize = True)
+                del eris_ovvv
+
         if isinstance(eris.VVVV_p, np.ndarray):
             eris_VVVV = eris.VVVV_p
             temp = np.ascontiguousarray(
                 t2_1_b[:,:,ab_ind_b[0],ab_ind_b[1]]).reshape(nocc_b*nocc_b,-1)
-            t2_1_vvvv_b = np.dot(temp,eris_VVVV.T).reshape(nocc_b, nocc_b, -1)
+            temp = np.dot(temp,eris_VVVV.T).reshape(nocc_b, nocc_b, -1)
+            t2_1_vvvv_b = np.zeros((nocc_b,nocc_b,nvir_b,nvir_b))
+            t2_1_vvvv_b[:,:,ab_ind_b[0],ab_ind_b[1]] = temp
+            t2_1_vvvv_b[:,:,ab_ind_b[1],ab_ind_b[0]] = -temp
             del eris_VVVV
         elif isinstance(eris.VVVV_p, list) :
-            t2_1_vvvv_b = contract_ladder_antisym(myadc,t2_1_b[:],eris.VVVV_p)
+            t2_1_vvvv_b = contract_ladder_antisym(myadc,t2_1_b[:],eris.VVVV_p, pack = False)
         else:
-            t2_1_vvvv_b = contract_ladder_antisym(myadc,t2_1_b[:],eris.LVV)
+            t2_1_vvvv_b = contract_ladder(myadc, t2_1_b[:], (eris.LVV, eris.LVV))
 
         if not isinstance(eris.oooo, np.ndarray):
             t2_1_vvvv_b = h5cache_t2.create_dataset('t2_1_vvvv_b', data=t2_1_vvvv_b)
 
-        t2_2_b = np.zeros((nocc_b,nocc_b,nvir_b,nvir_b))
-        t2_2_b[:,:,ab_ind_b[0],ab_ind_b[1]] = t2_1_vvvv_b[:]
-        t2_2_b[:,:,ab_ind_b[1],ab_ind_b[0]] = -t2_1_vvvv_b[:]
+        t2_2_b = t2_1_vvvv_b[:].copy()
 
         t2_2_b += 0.5*lib.einsum('kilj,klab->ijab', eris_OOOO, t2_1_b[:],optimize=True)
         t2_2_b -= 0.5*lib.einsum('kjli,klab->ijab', eris_OOOO, t2_1_b[:],optimize=True)
@@ -290,9 +394,38 @@ def compute_amplitudes(myadc, eris):
         t2_2_b += temp - temp.transpose(1,0,2,3) - temp.transpose(0,1,3,2) + temp.transpose(1,0,3,2)
         t2_2_b += temp_1 - temp_1.transpose(1,0,2,3) - \
                                             temp_1.transpose(0,1,3,2) + temp_1.transpose(1,0,3,2)
+
         del temp
         del temp_1
 
+        if isinstance(myadc._scf, scf.rohf.ROHF):
+            t2_2_b += lib.einsum('la,ibjl->ijab',t1_1_b,eris.OVOO, optimize = True)
+            t2_2_b -= lib.einsum('la,jbil->ijab',t1_1_b,eris.OVOO, optimize = True)
+
+            t2_2_b -= lib.einsum('lb,iajl->ijab',t1_1_b,eris.OVOO, optimize = True)
+            t2_2_b += lib.einsum('lb,jail->ijab',t1_1_b,eris.OVOO, optimize = True)
+
+            if isinstance(eris.OVVV, type(None)):
+                chnk_size = uadc_ao2mo.calculate_chunk_size(myadc)
+                a = 0
+                for p in range(0,nocc_b,chnk_size):
+                    eris_OVVV = dfadc.get_ovvv_spin_df(
+                        myadc, eris.LOV, eris.LVV, p, chnk_size).reshape(-1,nvir_b,nvir_b,nvir_b)
+                    k = eris_OVVV.shape[0]
+                    t2_2_b[:,a:a+k] += lib.einsum('id,jbad->ijab',t1_1_b,eris_OVVV, optimize = True)
+                    t2_2_b[:,a:a+k] -= lib.einsum('id,jabd->ijab',t1_1_b,eris_OVVV, optimize = True)
+                    t2_2_b[a:a+k] -= lib.einsum('jd,ibad->ijab',t1_1_b,eris_OVVV, optimize = True)
+                    t2_2_b[a:a+k] += lib.einsum('jd,iabd->ijab',t1_1_b,eris_OVVV, optimize = True)
+                    del eris_OVVV
+                    a += k
+            else:
+                eris_OVVV = uadc_ao2mo.unpack_eri_1(eris.OVVV, nvir_b)
+                t2_2_b += lib.einsum('id,jbad->ijab',t1_1_b,eris_OVVV, optimize = True)
+                t2_2_b -= lib.einsum('id,jabd->ijab',t1_1_b,eris_OVVV, optimize = True)
+                t2_2_b -= lib.einsum('jd,ibad->ijab',t1_1_b,eris_OVVV, optimize = True)
+                t2_2_b += lib.einsum('jd,iabd->ijab',t1_1_b,eris_OVVV, optimize = True)
+                del eris_OVVV
+
         if isinstance(eris.vVvV_p, np.ndarray):
             temp = t2_1_ab.reshape(nocc_a*nocc_b,nvir_a*nvir_b)
             eris_vVvV = eris.vVvV_p
@@ -317,6 +450,43 @@ def compute_amplitudes(myadc, eris):
         t2_2_ab += lib.einsum('kcai,kjcb->ijab',eris_ovvo,t2_1_ab[:],optimize=True)
         t2_2_ab -= lib.einsum('kiac,kjcb->ijab',eris_oovv,t2_1_ab[:],optimize=True)
 
+        if isinstance(myadc._scf, scf.rohf.ROHF):
+            t2_2_ab -= lib.einsum('la,jbil->ijab',t1_1_a,eris.OVoo, optimize = True)
+            t2_2_ab -= lib.einsum('lb,iajl->ijab',t1_1_b,eris.ovOO, optimize = True)
+
+            if isinstance(eris.OVvv, type(None)):
+                chnk_size = uadc_ao2mo.calculate_chunk_size(myadc)
+                a = 0
+                for p in range(0,nocc_b,chnk_size):
+                    eris_OVvv = dfadc.get_ovvv_spin_df(
+                        myadc, eris.LOV, eris.Lvv, p, chnk_size).reshape(-1,nvir_b,nvir_a,nvir_a)
+                    k = eris_OVvv.shape[0]
+                    t2_2_ab[:, a:a+k] += lib.einsum('id,jbad->ijab',
+                                                    t1_1_a,eris_OVvv, optimize = True)
+                    del eris_OVvv
+                    a += k
+            else:
+                eris_OVvv = uadc_ao2mo.unpack_eri_1(eris.OVvv, nvir_a)
+                t2_2_ab += lib.einsum('id,jbad->ijab',t1_1_a,eris_OVvv, optimize = True)
+                del eris_OVvv
+
+            if isinstance(eris.ovVV, type(None)):
+                chnk_size = uadc_ao2mo.calculate_chunk_size(myadc)
+                a = 0
+                for p in range(0,nocc_a,chnk_size):
+                    eris_ovVV = dfadc.get_ovvv_spin_df(
+                        myadc, eris.Lov, eris.LVV, p, chnk_size).reshape(-1,nvir_a,nvir_b,nvir_b)
+                    k = eris_ovVV.shape[0]
+                    t2_2_ab[a:a+k] += lib.einsum('jd,iabd->ijab',t1_1_b,eris_ovVV, optimize = True)
+                    del eris_ovVV
+                    a += k
+            else:
+                eris_ovVV = uadc_ao2mo.unpack_eri_1(eris.ovVV, nvir_b)
+                t2_2_ab += lib.einsum('jd,iabd->ijab',t1_1_b,eris_ovVV, optimize = True)
+                del eris_ovVV
+
+
+
         D2_a = d_ij_a.reshape(-1,1) - d_ab_a.reshape(-1)
         D2_a = D2_a.reshape((nocc_a,nocc_a,nvir_a,nvir_a))
         t2_2_a = t2_2_a/D2_a
@@ -694,7 +864,7 @@ def compute_amplitudes(myadc, eris):
         t2_2 = (t2_2_a , t2_2_ab, t2_2_b)
         t2_1_vvvv = (t2_1_vvvv_a, t2_1_vvvv_ab, t2_1_vvvv_b)
 
-    t1 = (t1_2, t1_3)
+    t1 = (t1_2, t1_3, t1_1)
     t2 = (t2_1, t2_2)
 
     cput0 = log.timer_debug1("Completed amplitude calculation", *cput0)
@@ -738,17 +908,38 @@ def compute_energy(myadc, t1, t2, eris):
     e_mp -= 0.25 * lib.einsum('ijab,ibaj', t2_b, eris_OVVO)
     del t2_b
 
+    logger.info(myadc, "Reference correlation energy (doubles): %.8f", e_mp)
+
+    if isinstance(myadc._scf, scf.rohf.ROHF):
+        f_ov_a = myadc.f_ov[0]
+        f_ov_b = myadc.f_ov[1]
+        t1_1_a = t1[2][0].copy()
+        t1_1_b = t1[2][1].copy()
+
+        if (myadc.method == "adc(3)"):
+            t1_1_a += t1[0][0]
+            t1_1_b += t1[0][1]
+
+        singles = lib.einsum('ia,ia', f_ov_a, t1_1_a)
+        singles += lib.einsum('ia,ia', f_ov_b, t1_1_b)
+
+        e_mp += singles
+
+        logger.info(myadc, "Reference correlation energy (singles): %.8f", singles)
+
     cput0 = log.timer_debug1("Completed energy calculation", *cput0)
 
     return e_mp
 
-def contract_ladder(myadc,t_amp,vvvv_p):
+
+def contract_ladder(myadc,t_amp,vvvv_p, prefactor = 1.0, pack = False):
 
     nocc_a = t_amp.shape[0]
     nocc_b = t_amp.shape[1]
     nvir_a = t_amp.shape[2]
     nvir_b = t_amp.shape[3]
 
+    tril_idx = np.tril_indices(nvir_a, k=-1)
     t_amp_t = np.ascontiguousarray(t_amp.reshape(nocc_a*nocc_b,-1).T)
     t = np.zeros((nvir_a,nvir_b, nocc_a*nocc_b))
     chnk_size = uadc_ao2mo.calculate_chunk_size(myadc)
@@ -773,12 +964,14 @@ def contract_ladder(myadc,t_amp,vvvv_p):
     else:
         raise Exception("Unknown vvvv type")
 
-    t = np.ascontiguousarray(t.transpose(2,0,1)).reshape(nocc_a, nocc_b, nvir_a, nvir_b)
+    t = prefactor * np.ascontiguousarray(t.transpose(2,0,1)).reshape(nocc_a, nocc_b, nvir_a, nvir_b)
+    if pack:
+        t = t[:, :, tril_idx[0], tril_idx[1]]
 
     return t
 
 
-def contract_ladder_antisym(myadc,t_amp,vvvv_d):
+def contract_ladder_antisym(myadc,t_amp,vvvv_d, pack = True):
 
     nocc = t_amp.shape[0]
     nvir = t_amp.shape[2]
@@ -811,6 +1004,8 @@ def contract_ladder_antisym(myadc,t_amp,vvvv_d):
         raise Exception("Unknown vvvv type")
 
     t = np.ascontiguousarray(t.transpose(2,0,1)).reshape(nocc, nocc, nvir, nvir)
-    t = t[:, :, tril_idx[0], tril_idx[1]]
+
+    if pack:
+        t = t[:, :, tril_idx[0], tril_idx[1]]
 
     return t
diff --git a/pyscf/adc/uadc_ao2mo.py b/pyscf/adc/uadc_ao2mo.py
index 96f2cabf6b..80c509256a 100644
--- a/pyscf/adc/uadc_ao2mo.py
+++ b/pyscf/adc/uadc_ao2mo.py
@@ -12,7 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
 #
 
@@ -199,7 +202,7 @@ def transform_integrals_outcore(myadc):
             eris.OOvv[i] = buf[:nocc_b,nocc_a:,nocc_a:]
             eris.OVvo[i] = buf[nocc_b:,nocc_a:,:nocc_a]
             eris.OVvv[i] = lib.pack_tril(buf[nocc_b:,nocc_a:,nocc_a:])
-        del (tmpf['ba'])
+        del(tmpf['ba'])
 
     buf = None
     cput1 = logger.timer_debug1(myadc, 'transforming oopq, ovpq', *cput1)
@@ -465,17 +468,35 @@ def transform_integrals_df(myadc):
     eris.Lvv = eris.Lvv.reshape(naux,nvir_a,nvir_a)
     eris.LVV = eris.LVV.reshape(naux,nvir_b,nvir_b)
 
-    if not isinstance(myadc.ncvs, type(None)) and myadc.ncvs > 0:
-        ncvs = myadc.ncvs
-        eris.Lce = eris.Lce.reshape(naux,ncvs,nvir_a)
-        eris.Lee = eris.Lvv
-        eris.LCE = eris.LCE.reshape(naux,ncvs,nvir_b)
-        eris.LEE = eris.LVV
-
     log.timer('DF-ADC integral transformation', *cput0)
 
     return eris
 
+def unpack_eri_1(eri, norb):
+
+    n_oo = norb * (norb + 1) // 2
+    ind_oo = np.tril_indices(norb)
+
+    eri_ = None
+
+    if len(eri.shape) == 3:
+        if (eri.shape[0] == n_oo):
+            eri_ = np.zeros((norb, norb, eri.shape[1], eri.shape[2]))
+            eri_[ind_oo[0], ind_oo[1]] = eri
+            eri_[ind_oo[1], ind_oo[0]] = eri
+
+        elif (eri.shape[2] == n_oo):
+            eri_ = np.zeros((eri.shape[0], eri.shape[1], norb, norb))
+            eri_[:, :, ind_oo[0], ind_oo[1]] = eri
+            eri_[:, :, ind_oo[1], ind_oo[0]] = eri
+        else:
+            raise TypeError("ERI dimensions don't match")
+
+    else:
+        raise RuntimeError("ERI does not have a correct dimension")
+
+    return eri_
+
 def calculate_chunk_size(myadc):
 
     avail_mem = (myadc.max_memory - lib.current_memory()[0]) * 0.25
diff --git a/pyscf/adc/uadc_ea.py b/pyscf/adc/uadc_ea.py
index 53e373704d..059118b117 100644
--- a/pyscf/adc/uadc_ea.py
+++ b/pyscf/adc/uadc_ea.py
@@ -12,7 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
 #
 
@@ -287,22 +290,13 @@ def get_imds(adc, eris=None):
             M_ab_a += lib.einsum('mlfd,mled,aebf->ab',t2_1_ab, t2_1_ab, eris_vvvv, optimize=True)
             del eris_vvvv
 
-            temp = np.zeros((nocc_a,nocc_a,nvir_a,nvir_a))
-            temp[:,:,ab_ind_a[0],ab_ind_a[1]] =  adc.imds.t2_1_vvvv[0]
-            temp[:,:,ab_ind_a[1],ab_ind_a[0]] = -adc.imds.t2_1_vvvv[0]
-
-            M_ab_a -= 2 * 0.5 * 0.25*lib.einsum('mlaf,mlbf->ab',t2_1_a, temp, optimize=True)
-            del temp
-
+            M_ab_a -= 2 * 0.5 * 0.25*lib.einsum('mlaf,mlbf->ab',
+                                                t2_1_a, adc.imds.t2_1_vvvv[0], optimize=True)
         else:
-
-            temp_t2a_vvvv = np.zeros((nocc_a,nocc_a,nvir_a,nvir_a))
-            temp_t2a_vvvv[:,:,ab_ind_a[0],ab_ind_a[1]] = adc.imds.t2_1_vvvv[0][:]
-            temp_t2a_vvvv[:,:,ab_ind_a[1],ab_ind_a[0]] = -adc.imds.t2_1_vvvv[0][:]
-
-            M_ab_a -= 2*0.5*0.25*lib.einsum('mlad,mlbd->ab',  temp_t2a_vvvv, t2_1_a, optimize=True)
-            M_ab_a -= 2*0.5*0.25*lib.einsum('mlaf,mlbf->ab', t2_1_a, temp_t2a_vvvv, optimize=True)
-            del temp_t2a_vvvv
+            M_ab_a -= 2*0.5*0.25*lib.einsum('mlad,mlbd->ab',
+                                            adc.imds.t2_1_vvvv[0], t2_1_a, optimize=True)
+            M_ab_a -= 2*0.5*0.25*lib.einsum('mlaf,mlbf->ab', t2_1_a,
+                                            adc.imds.t2_1_vvvv[0], optimize=True)
 
         if isinstance(eris.vvvv_p, list):
 
@@ -387,18 +381,20 @@ def get_imds(adc, eris=None):
             M_ab_b += lib.einsum('mlfd,mled,eafb->ab',t2_1_ab, t2_1_ab,   eris_vVvV, optimize=True)
 
             eris_vVvV = eris_vVvV.reshape(nvir_a*nvir_b,nvir_a*nvir_b)
-            temp = adc.imds.t2_1_vvvv[1]
-            M_ab_a -= 0.5*lib.einsum('mlaf,mlbf->ab',t2_1_ab, temp, optimize=True)
-            M_ab_b -= 0.5*lib.einsum('mlfa,mlfb->ab',t2_1_ab, temp, optimize=True)
-            del temp
+
+            M_ab_a -= 0.5*lib.einsum('mlaf,mlbf->ab',t2_1_ab, adc.imds.t2_1_vvvv[1], optimize=True)
+            M_ab_b -= 0.5*lib.einsum('mlfa,mlfb->ab',t2_1_ab, adc.imds.t2_1_vvvv[1], optimize=True)
+
         else:
-            t2_vVvV = adc.imds.t2_1_vvvv[1][:]
+            M_ab_a -= 0.5 * lib.einsum('mlad,mlbd->ab',
+                                       adc.imds.t2_1_vvvv[1], t2_1_ab, optimize=True)
+            M_ab_b -= 0.5 * lib.einsum('mlda,mldb->ab',
+                                       adc.imds.t2_1_vvvv[1], t2_1_ab, optimize=True)
+            M_ab_a -= 0.5 * lib.einsum('mlaf,mlbf->ab', t2_1_ab,
+                                       adc.imds.t2_1_vvvv[1], optimize=True)
+            M_ab_b -= 0.5 * lib.einsum('mlfa,mlfb->ab', t2_1_ab,
+                                       adc.imds.t2_1_vvvv[1], optimize=True)
 
-            M_ab_a -= 0.5 * lib.einsum('mlad,mlbd->ab', t2_vVvV, t2_1_ab, optimize=True)
-            M_ab_b -= 0.5 * lib.einsum('mlda,mldb->ab', t2_vVvV, t2_1_ab, optimize=True)
-            M_ab_a -= 0.5 * lib.einsum('mlaf,mlbf->ab',t2_1_ab, t2_vVvV, optimize=True)
-            M_ab_b -= 0.5 * lib.einsum('mlfa,mlfb->ab',t2_1_ab, t2_vVvV, optimize=True)
-            del t2_vVvV
         del t2_1_a
 
         if isinstance(eris.VVVV_p,np.ndarray):
@@ -409,22 +405,13 @@ def get_imds(adc, eris=None):
             M_ab_b += lib.einsum('mldf,mlde,aebf->ab',t2_1_ab, t2_1_ab, eris_VVVV, optimize=True)
             del eris_VVVV
 
-            temp = np.zeros((nocc_b,nocc_b,nvir_b,nvir_b))
-            temp[:,:,ab_ind_b[0],ab_ind_b[1]] =  adc.imds.t2_1_vvvv[2]
-            temp[:,:,ab_ind_b[1],ab_ind_b[0]] = -adc.imds.t2_1_vvvv[2]
-            M_ab_b -= 2 * 0.5 * 0.25*lib.einsum('mlaf,mlbf->ab',t2_1_b, temp, optimize=True)
-            del temp
+            M_ab_b -= 2 * 0.5 * 0.25*lib.einsum('mlaf,mlbf->ab',
+                                                t2_1_b, adc.imds.t2_1_vvvv[2], optimize=True)
         else:
-
-            temp_t2b_VVVV = np.zeros((nocc_b,nocc_b,nvir_b,nvir_b))
-            temp_t2b_VVVV[:,:,ab_ind_b[0],ab_ind_b[1]] = adc.imds.t2_1_vvvv[2][:]
-            temp_t2b_VVVV[:,:,ab_ind_b[1],ab_ind_b[0]] = -adc.imds.t2_1_vvvv[2][:]
-
             M_ab_b -= 2 * 0.5 * 0.25*lib.einsum('mlad,mlbd->ab',
-                                                temp_t2b_VVVV, t2_1_b, optimize=True)
+                                                adc.imds.t2_1_vvvv[2], t2_1_b, optimize=True)
             M_ab_b -= 2 * 0.5 * 0.25*lib.einsum('mlaf,mlbf->ab',
-                                                t2_1_b, temp_t2b_VVVV, optimize=True)
-            del temp_t2b_VVVV
+                                                t2_1_b, adc.imds.t2_1_vvvv[2], optimize=True)
 
         if isinstance(eris.vvvv_p, list):
 
@@ -1971,6 +1958,7 @@ class UADCEA(uadc.UADC):
     }
 
     def __init__(self, adc):
+        self.mol = adc.mol
         self.verbose = adc.verbose
         self.stdout = adc.stdout
         self.max_memory = adc.max_memory
@@ -1987,6 +1975,7 @@ def __init__(self, adc):
         self._scf = adc._scf
         self._nocc = adc._nocc
         self._nvir = adc._nvir
+        self._nmo = adc._nmo
         self.nocc_a = adc._nocc[0]
         self.nocc_b = adc._nocc[1]
         self.nvir_a = adc._nvir[0]
@@ -1996,14 +1985,14 @@ def __init__(self, adc):
         self.mo_energy_b = adc.mo_energy_b
         self.nmo_a = adc._nmo[0]
         self.nmo_b = adc._nmo[1]
-        self.mol = adc.mol
         self.transform_integrals = adc.transform_integrals
         self.with_df = adc.with_df
+        self.compute_properties = adc.compute_properties
+        self.approx_trans_moments = adc.approx_trans_moments
+
         self.spec_factor_print_tol = adc.spec_factor_print_tol
         self.evec_print_tol = adc.evec_print_tol
 
-        self.compute_properties = adc.compute_properties
-        self.approx_trans_moments = adc.approx_trans_moments
         self.E = adc.E
         self.U = adc.U
         self.P = adc.P
@@ -2014,11 +2003,12 @@ def __init__(self, adc):
     matvec = matvec
     get_diag = get_diag
     get_trans_moments = get_trans_moments
-    analyze_spec_factor = analyze_spec_factor
     get_properties = get_properties
+
     analyze = analyze
-    compute_dyson_mo = compute_dyson_mo
+    analyze_spec_factor = analyze_spec_factor
     analyze_eigenvector = analyze_eigenvector
+    compute_dyson_mo = compute_dyson_mo
 
     def get_init_guess(self, nroots=1, diag=None, ascending=True):
         if diag is None :
diff --git a/pyscf/adc/uadc_ip.py b/pyscf/adc/uadc_ip.py
index b1ad5d4d42..1c0041c818 100644
--- a/pyscf/adc/uadc_ip.py
+++ b/pyscf/adc/uadc_ip.py
@@ -12,7 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Samragni Banerjee <samragnibanerjee4@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
 #
 
@@ -1849,6 +1852,7 @@ class UADCIP(uadc.UADC):
     }
 
     def __init__(self, adc):
+        self.mol = adc.mol
         self.verbose = adc.verbose
         self.stdout = adc.stdout
         self.max_memory = adc.max_memory
@@ -1865,6 +1869,7 @@ def __init__(self, adc):
         self._scf = adc._scf
         self._nocc = adc._nocc
         self._nvir = adc._nvir
+        self._nmo = adc._nmo
         self.nocc_a = adc._nocc[0]
         self.nocc_b = adc._nocc[1]
         self.nvir_a = adc._nvir[0]
@@ -1874,14 +1879,14 @@ def __init__(self, adc):
         self.mo_energy_b = adc.mo_energy_b
         self.nmo_a = adc._nmo[0]
         self.nmo_b = adc._nmo[1]
-        self.mol = adc.mol
         self.transform_integrals = adc.transform_integrals
         self.with_df = adc.with_df
+        self.compute_properties = adc.compute_properties
+        self.approx_trans_moments = adc.approx_trans_moments
+
         self.spec_factor_print_tol = adc.spec_factor_print_tol
         self.evec_print_tol = adc.evec_print_tol
 
-        self.compute_properties = adc.compute_properties
-        self.approx_trans_moments = adc.approx_trans_moments
         self.E = adc.E
         self.U = adc.U
         self.P = adc.P
diff --git a/pyscf/adc/uadc_ip_cvs.py b/pyscf/adc/uadc_ip_cvs.py
index 5a1a39c115..c4337d710d 100644
--- a/pyscf/adc/uadc_ip_cvs.py
+++ b/pyscf/adc/uadc_ip_cvs.py
@@ -12,7 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# Author: Abdelrahman Ahmed <abdelrahman.maa.ahmed@gmail.com>
+# Author: Abdelrahman Ahmed <>
+#         Samragni Banerjee <samragnibanerjee4@gmail.com>
+#         James Serna <jamcar456@gmail.com>
+#         Terrence Stahl <>
 #         Alexander Sokolov <alexander.y.sokolov@gmail.com>
 #
 


Test patch:
diff --git a/pyscf/adc/test/test_radc/test_H2O_radc_ea.py b/pyscf/adc/test/test_radc/test_H2O_radc_ea.py
index fde82996c4..c237fc225f 100644
--- a/pyscf/adc/test/test_radc/test_H2O_radc_ea.py
+++ b/pyscf/adc/test/test_radc/test_H2O_radc_ea.py
@@ -17,7 +17,7 @@
 #
 
 import unittest
-import numpy
+import numpy as np
 import math
 from pyscf import gto
 from pyscf import scf
@@ -47,12 +47,22 @@ def tearDownModule():
     global mol, mf, myadc
     del mol, mf, myadc
 
+def rdms_test(dm):
+    r2_int = mol.intor('int1e_r2')
+    dm_ao = np.einsum('pi,ij,qj->pq', mf.mo_coeff, dm, mf.mo_coeff.conj())
+    r2 = np.einsum('pq,pq->',r2_int,dm_ao)
+    return r2
+
 class KnownValues(unittest.TestCase):
 
     def test_ea_adc2(self):
         e, t_amp1, t_amp2 = myadc.kernel_gs()
         self.assertAlmostEqual(e, -0.2218560609876961, 6)
 
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 20.3557963972156, 6)
+
         myadcea = adc.radc_ea.RADCEA(myadc)
         e,v,p,x = myadcea.kernel(nroots=3)
 
@@ -64,11 +74,20 @@ def test_ea_adc2(self):
         self.assertAlmostEqual(p[1], 1.9941128865405613, 6)
         self.assertAlmostEqual(p[2], 1.9760420333383126, 6)
 
+        dm1_exc = np.array(myadcea.make_rdm1())
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 60.74982115808177, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 77.50057807557833, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 51.451460124678604, 6)
+
     def test_ea_adc2x(self):
         myadc.method = "adc(2)-x"
         e, t_amp1, t_amp2 = myadc.kernel_gs()
         self.assertAlmostEqual(e, -0.2218560609876961, 6)
 
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 20.3557963972156, 6)
+
         myadcea = adc.radc_ea.RADCEA(myadc)
         e,v,p,x = myadcea.kernel(nroots=3)
 
@@ -80,12 +99,21 @@ def test_ea_adc2x(self):
         self.assertAlmostEqual(p[1], 1.9905409664546319, 6)
         self.assertAlmostEqual(p[2], 1.9593142553574816, 6)
 
+        dm1_exc = myadcea.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 60.32114764303384, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 77.23400300967357, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 52.055954747398014, 6)
+
 
     def test_ea_adc3(self):
         myadc.method = "adc(3)"
         e, t_amp1, t_amp2 = myadc.kernel_gs()
         self.assertAlmostEqual(e, -0.2263968409281272, 6)
 
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 20.070653779918267, 6)
+
         myadcea = adc.radc_ea.RADCEA(myadc)
         e,v,p,x = myadcea.kernel(nroots=4)
         myadcea.analyze()
@@ -100,6 +128,11 @@ def test_ea_adc3(self):
         self.assertAlmostEqual(p[2], 1.9676462978544356, 6)
         self.assertAlmostEqual(p[3], 1.9743650630026532, 6)
 
+        dm1_exc = myadcea.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 60.22057800411394, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 77.03749070234556, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 51.28103237617329, 6)
+
 if __name__ == "__main__":
     print("EA calculations for different RADC methods for water molecule")
     unittest.main()
diff --git a/pyscf/adc/test/test_radc/test_H2O_radc_ip.py b/pyscf/adc/test/test_radc/test_H2O_radc_ip.py
index d0eec675e4..a08461c5f8 100644
--- a/pyscf/adc/test/test_radc/test_H2O_radc_ip.py
+++ b/pyscf/adc/test/test_radc/test_H2O_radc_ip.py
@@ -47,12 +47,22 @@ def tearDownModule():
     global mol, mf, myadc
     del mol, mf, myadc
 
+def rdms_test(dm):
+    r2_int = mol.intor('int1e_r2')
+    dm_ao = np.einsum('pi,ij,qj->pq', mf.mo_coeff, dm, mf.mo_coeff.conj())
+    r2 = np.einsum('pq,pq->',r2_int,dm_ao)
+    return r2
+
 class KnownValues(unittest.TestCase):
 
     def test_ip_adc2(self):
         e, t_amp1, t_amp2 = myadc.kernel_gs()
         self.assertAlmostEqual(e, -0.2039852016968376, 6)
 
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 19.073700043115412, 6)
+
         myadcip = adc.radc_ip.RADCIP(myadc)
         e,v,p,x = myadcip.kernel(nroots=3)
 
@@ -64,11 +74,20 @@ def test_ip_adc2(self):
         self.assertAlmostEqual(p[1], 1.8274312312239454, 6)
         self.assertAlmostEqual(p[2], 1.8582314560275948, 6)
 
+        dm1_exc = myadcip.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 14.495740213945693, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 14.420886528704559, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 14.222914438696922, 6)
+
     def test_ip_adc2x(self):
         myadc.method = "adc(2)-x"
         e, t_amp1, t_amp2 = myadc.kernel_gs()
         self.assertAlmostEqual(e, -0.2039852016968376, 6)
 
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 19.073700043115412, 6)
+
         myadcip = adc.radc_ip.RADCIP(myadc)
         e,v,p,x = myadcip.kernel(nroots=3)
 
@@ -80,12 +99,21 @@ def test_ip_adc2x(self):
         self.assertAlmostEqual(p[1], 1.8381884804163264, 6)
         self.assertAlmostEqual(p[2], 1.8669268953278064, 6)
 
+        dm1_exc = myadcip.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 14.63435450911693, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 14.55055095791920, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 14.34027603791598, 6)
+
 
     def test_ip_adc3(self):
         myadc.method = "adc(3)"
         e, t_amp1, t_amp2 = myadc.kernel_gs()
         self.assertAlmostEqual(e, -0.2107769014592799, 6)
 
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 19.043496230938608, 6)
+
         myadcip = adc.radc_ip.RADCIP(myadc)
         e,v,p,x = myadcip.kernel(nroots=4)
         myadcip.analyze()
@@ -100,6 +128,11 @@ def test_ip_adc3(self):
         self.assertAlmostEqual(p[2], 1.8881842403480831, 6)
         self.assertAlmostEqual(p[3], 0.1651131053450, 6)
 
+        dm1_exc = myadcip.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 14.865794062106032, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 14.750656672998344, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 14.508101917384584, 6)
+
 if __name__ == "__main__":
     print("IP calculations for different ADC methods for water molecule")
     unittest.main()
diff --git a/pyscf/adc/test/test_radc/test_N2_radc_ea.py b/pyscf/adc/test/test_radc/test_N2_radc_ea.py
index a35185e1ed..518c339f57 100644
--- a/pyscf/adc/test/test_radc/test_N2_radc_ea.py
+++ b/pyscf/adc/test/test_radc/test_N2_radc_ea.py
@@ -17,7 +17,7 @@
 #
 
 import unittest
-import numpy
+import numpy as np
 from pyscf import gto
 from pyscf import scf
 from pyscf import adc
@@ -41,6 +41,12 @@ def tearDownModule():
     global mol, mf, myadc
     del mol, mf, myadc
 
+def rdms_test(dm):
+    r2_int = mol.intor('int1e_r2')
+    dm_ao = np.einsum('pi,ij,qj->pq', mf.mo_coeff, dm, mf.mo_coeff.conj())
+    r2 = np.einsum('pq,pq->',r2_int,dm_ao)
+    return r2
+
 class KnownValues(unittest.TestCase):
 
     def test_ea_adc2(self):
@@ -48,8 +54,12 @@ def test_ea_adc2(self):
         e, t_amp1, t_amp2 = myadc.kernel_gs()
         self.assertAlmostEqual(e, -0.32201692499346535, 6)
 
-        e,v,p,x,es = myadc.ea_adc(nroots=3)
-        es.analyze()
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 39.23226380360857, 6)
+
+        myadcea = adc.radc_ea.RADCEA(myadc)
+        e,v,p,x = myadcea.kernel(nroots=3)
 
         self.assertAlmostEqual(e[0], 0.0961781923822576, 6)
         self.assertAlmostEqual(e[1], 0.1258326916409743, 6)
@@ -59,6 +69,11 @@ def test_ea_adc2(self):
         self.assertAlmostEqual(p[1], 1.9634368668786559, 6)
         self.assertAlmostEqual(p[2], 1.9783719593912672, 6)
 
+        dm1_exc = myadcea.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 83.57588095829082, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 66.92768038358671, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 66.15440155740416, 6)
+
     def test_ea_adc2_oneroot(self):
 
         myadc.method_type = "ea"
@@ -73,7 +88,13 @@ def test_ea_adc2x(self):
         myadc.method = "adc(2)-x"
         myadc.method_type = "ea"
 
-        e,v,p,x = myadc.kernel(nroots=4)
+        myadc.kernel_gs()
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 39.23226380360857, 6)
+
+        myadcea = adc.radc_ea.RADCEA(myadc)
+        e,v,p,x = myadcea.kernel(nroots=4)
         e_corr = myadc.e_corr
 
         self.assertAlmostEqual(e_corr, -0.32201692499346535, 6)
@@ -88,12 +109,24 @@ def test_ea_adc2x(self):
         self.assertAlmostEqual(p[2],1.9689940350592570, 6)
         self.assertAlmostEqual(p[3],1.9689940350592559, 6)
 
+        dm1_exc = myadcea.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 83.53454941982915, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 66.8646378314392, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 66.29435797091572, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[3]), 66.29435797091572, 6)
+
     def test_ea_adc3(self):
 
         myadc.method = "adc(3)"
         myadc.method_type = "ea"
 
-        e,v,p,x = myadc.kernel(nroots=3)
+        myadc.kernel_gs()
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 39.4764479057645, 6)
+
+        myadcea = adc.radc_ea.RADCEA(myadc)
+        e,v,p,x = myadcea.kernel(nroots=3)
         e_corr = myadc.e_corr
 
         self.assertAlmostEqual(e_corr, -0.31694173142858517 , 6)
@@ -106,6 +139,11 @@ def test_ea_adc3(self):
         self.assertAlmostEqual(p[1], 1.9840991060607487, 6)
         self.assertAlmostEqual(p[2], 1.9638550014980212, 6)
 
+        dm1_exc = myadcea.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 55.12466915835939, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 84.21966457078218, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 67.34876130600885, 6)
+
 if __name__ == "__main__":
     print("EA calculations for different RADC methods for nitrogen molecule")
     unittest.main()
diff --git a/pyscf/adc/test/test_radc/test_N2_radc_ip.py b/pyscf/adc/test/test_radc/test_N2_radc_ip.py
index 2ec50c922b..534366d836 100644
--- a/pyscf/adc/test/test_radc/test_N2_radc_ip.py
+++ b/pyscf/adc/test/test_radc/test_N2_radc_ip.py
@@ -17,7 +17,7 @@
 #
 
 import unittest
-import numpy
+import numpy as np
 from pyscf import gto
 from pyscf import scf
 from pyscf import adc
@@ -35,12 +35,19 @@ def setUpModule():
     mf = scf.RHF(mol)
     mf.conv_tol = 1e-12
     mf.kernel()
+
     myadc = adc.ADC(mf)
 
 def tearDownModule():
     global mol, mf, myadc
     del mol, mf, myadc
 
+def rdms_test(dm):
+    r2_int = mol.intor('int1e_r2')
+    dm_ao = np.einsum('pi,ij,qj->pq', mf.mo_coeff, dm, mf.mo_coeff.conj())
+    r2 = np.einsum('pq,pq->',r2_int,dm_ao)
+    return r2
+
 class KnownValues(unittest.TestCase):
 
     def test_ip_adc2(self):
@@ -48,8 +55,12 @@ def test_ip_adc2(self):
         e, t_amp1, t_amp2 = myadc.kernel_gs()
         self.assertAlmostEqual(e, -0.32201692499346535, 6)
 
-        e,v,p,x,es = myadc.ip_adc(nroots=3)
-        es.analyze()
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 39.23226380360857, 6)
+
+        myadcip = adc.radc_ip.RADCIP(myadc)
+        e,v,p,x = myadcip.kernel(nroots=3)
 
         self.assertAlmostEqual(e[0], 0.5434389910483670, 6)
         self.assertAlmostEqual(e[1], 0.6240296243595950, 6)
@@ -59,6 +70,11 @@ def test_ip_adc2(self):
         self.assertAlmostEqual(p[1], 1.8192921131700284, 6)
         self.assertAlmostEqual(p[2], 1.8192921131700293, 6)
 
+        dm1_exc = myadcip.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 32.182304246973395, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 33.184809640044106, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 33.184809640044106, 6)
+
     def test_ip_adc2_oneroot(self):
 
         e,v,p,x = myadc.kernel()
@@ -70,8 +86,10 @@ def test_ip_adc2_oneroot(self):
     def test_ip_adc2x(self):
 
         myadc.method = "adc(2)-x"
+        e, t_amp1, t_amp2 = myadc.kernel_gs()
 
-        e,v,p,x = myadc.kernel(nroots=3)
+        myadcip = adc.radc_ip.RADCIP(myadc)
+        e,v,p,x = myadcip.kernel(nroots=3)
         e_corr = myadc.e_corr
 
         self.assertAlmostEqual(e_corr, -0.32201692499346535, 6)
@@ -84,12 +102,23 @@ def test_ip_adc2x(self):
         self.assertAlmostEqual(p[1], 1.8152869633769022, 6)
         self.assertAlmostEqual(p[2], 1.8152869633769015, 6)
 
+        dm1_exc = myadcip.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 32.1274922515584, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 33.1669386304224, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 33.1669386304224, 6)
+
     def test_ip_adc3(self):
 
         myadc.method = "adc(3)"
         myadc.method_type = "ip"
 
-        e,v,p,x = myadc.kernel(nroots=3)
+        myadc.kernel_gs()
+        dm1_gs = myadc.make_ref_rdm1()
+        r2_gs = rdms_test(dm1_gs)
+        self.assertAlmostEqual(r2_gs, 39.4764479057645, 6)
+
+        myadcip = adc.radc_ip.RADCIP(myadc)
+        e,v,p,x = myadcip.kernel(nroots=3)
         e_corr = myadc.e_corr
 
         self.assertAlmostEqual(e_corr, -0.31694173142858517 , 6)
@@ -102,6 +131,11 @@ def test_ip_adc3(self):
         self.assertAlmostEqual(p[1], 1.8429224413853840, 6)
         self.assertAlmostEqual(p[2], 1.8429224413853851, 6)
 
+        dm1_exc = myadcip.make_rdm1()
+        self.assertAlmostEqual(rdms_test(dm1_exc[0]), 32.49588382444393, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[1]), 33.65709826882843, 6)
+        self.assertAlmostEqual(rdms_test(dm1_exc[2]), 33.65709826882843, 6)
+
 if __name__ == "__main__":
     print("IP calculations for different RADC methods for nitrogen molecule")
     unittest.main()