diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index a2a4b7504..000000000 --- a/.coveragerc +++ /dev/null @@ -1,23 +0,0 @@ -[run] -branch = True -source = vayesta -omit = - */libs/* - */tests/* - */tools/* - */core/DEL/* - -[report] -exclude_lines = - pragma: no cover - raise RuntimeError - raise NotImplementedError - raise AssertionError - raise ValueError - raise AbstractMethodError - pass - if __name__ == .__main__.: - except ImportError - def __repr__ - log.error - log.critical diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 78ae72174..000000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -ignore = E126, E221, E222, E226, E231, E241, E265, W503, E731, E741 -exclude = tests, .git, .github, __pycache__, __init__.py, example.py -max-line-length = 119 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4d84b4d78..a6e325920 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,7 +8,7 @@ on: - cron: '0 2 * * *' jobs: - build: + full: name: python ${{ matrix.python-version }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} @@ -19,6 +19,7 @@ jobs: - {python-version: "3.8", os: ubuntu-latest, documentation: True} - {python-version: "3.9", os: ubuntu-latest, documentation: False} - {python-version: "3.10", os: ubuntu-latest, documentation: False} + - {python-version: "3.11", os: ubuntu-latest, documentation: False} steps: - uses: actions/checkout@v2 @@ -33,8 +34,12 @@ jobs: run: | python -m pip install wheel --user python -m pip install setuptools --upgrade --user +<<<<<<< HEAD python -m pip install https://github.com/BoothGroup/dyson/archive/master.zip python -m pip install .[dmet] --user +======= + python -m pip install .[dmet,ebcc] --user +>>>>>>> master - name: Run unit tests run: | python -m pip install pytest pytest-cov --user @@ -61,3 +66,29 @@ jobs: force_orphan: true if: ${{ matrix.documentation && github.ref == 'refs/heads/master' && github.event_name != 'schedule' }} + bare: + name: python 3.8 on ubuntu-latest with no optional dependencies + runs-on: ubuntu-latest + + strategy: + fail-fast: false + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Upgrade pip + run: | + python -m pip install --upgrade pip + - name: Install Vayesta + run: | + python -m pip install wheel --user + python -m pip install setuptools --upgrade --user + python -m pip install . --user + - name: Run unit tests + run: | + python -m pip install pytest pytest-cov --user + python .github/workflows/run_tests.py + diff --git a/.github/workflows/run_tests.py b/.github/workflows/run_tests.py index b0d87ea20..d2b4594e1 100644 --- a/.github/workflows/run_tests.py +++ b/.github/workflows/run_tests.py @@ -1,6 +1,6 @@ import pytest -import sys import os +import sys src = os.path.abspath(os.path.join(__file__, "..", "..", "..", "vayesta")) diff --git a/MANIFEST.in b/MANIFEST.in index e175d5ce4..c691f34fc 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,11 +1,13 @@ include MANIFEST.in -include README.md setup.py CHANGELOG LICENSE +include README.md pyproject.toml setup.py CHANGELOG LICENSE global-exclude *.py[cod] prune vayesta/libs/build recursive-include vayesta *.dat +recursive-include vayesta/misc/gmtkn55 * include vayesta/libs/*.so +include vayesta/logo.txt # MacOS dynamic libraries include vayesta/libs/*.dylib diff --git a/examples/dmet/02-rotational-symmetry.py b/examples/dmet/02-rotational-symmetry.py index 11d8e6894..cf6388d3a 100644 --- a/examples/dmet/02-rotational-symmetry.py +++ b/examples/dmet/02-rotational-symmetry.py @@ -27,7 +27,7 @@ # One-shot DMET dmet = vayesta.dmet.DMET(mf, solver='FCI', maxiter=1) with dmet.sao_fragmentation() as f: - with f.rotational_symmetry(3, axis='z'): + with f.rotational_symmetry(3, axis=[0,0,1]): f.add_atomic_fragment([0,1]) dmet.kernel() diff --git a/examples/dmet/04-h-ring-diis.py b/examples/dmet/04-h-ring-diis.py index 8fce1ff15..e32b088a6 100644 --- a/examples/dmet/04-h-ring-diis.py +++ b/examples/dmet/04-h-ring-diis.py @@ -1,5 +1,8 @@ import numpy as np +import pyscf +import pyscf.scf + import vayesta import vayesta.dmet from vayesta.misc.molecules import ring diff --git a/examples/dmet/63-hubbard-1d.py b/examples/dmet/63-hubbard-1d.py index 42a518838..4f68d3818 100644 --- a/examples/dmet/63-hubbard-1d.py +++ b/examples/dmet/63-hubbard-1d.py @@ -20,6 +20,7 @@ f.add_atomic_fragment(list(range(site, site+nimp))) dmet.kernel() +print(dmet.fragments) # Calculate a single fragment and use translational symmetry: dmet_sym = vayesta.dmet.DMET(mf, solver='FCI') # Specify the number of translational copies in direction of the three lattice vectors by passing a list with three diff --git a/examples/edmet/01-1d-hubbard-comparison.py b/examples/edmet/01-1d-hubbard-comparison.py index 5f7da6aea..59504a99a 100644 --- a/examples/edmet/01-1d-hubbard-comparison.py +++ b/examples/edmet/01-1d-hubbard-comparison.py @@ -24,7 +24,7 @@ def gen_comparison(hubbard_u, nimp=2): mf = gen_hub(nsite, hubbard_u) dmet = vayesta.dmet.DMET(mf, solver='FCI', charge_consistent=True, maxiter=1, - bath_type=None) + bath_options=dict(bathtype='dmet')) with dmet.site_fragmentation() as f: frag = f.add_atomic_fragment(list(range(nimp))) # Add fragments which are translationally symmetric to f - the results of the fragment f @@ -33,7 +33,7 @@ def gen_comparison(hubbard_u, nimp=2): symfrags = frag.make_tsymmetric_fragments(tvecs=[nsite // nimp, 1, 1]) res_dmet += [sum(dmet.fragments[0].get_dmet_energy_contrib())/nimp] - edmet = vayesta.edmet.EDMET(mf, solver="EBFCI", charge_consistent = True,maxiter=1, bath_type=None) + edmet = vayesta.edmet.EDMET(mf, solver="FCI", charge_consistent = True,maxiter=1, bath_options=dict(bathtype='dmet')) with edmet.site_fragmentation() as f: frag = f.add_atomic_fragment(list(range(nimp))) # Add fragments which are translationally symmetric to f - the results of the fragment f diff --git a/examples/edmet/10-bosonic-Hamiltonians.py b/examples/edmet/10-bosonic-Hamiltonians.py index b9989fc25..4c5adbbf5 100644 --- a/examples/edmet/10-bosonic-Hamiltonians.py +++ b/examples/edmet/10-bosonic-Hamiltonians.py @@ -15,17 +15,17 @@ # Can generate bosons using either RPA couplings or direct projection of the Hamiltonian into the bosonic space. -rdfedmet_drpa_bos = vayesta.edmet.EDMET(mf, solver="EBCCSD", dmet_threshold=1e-12, bosonic_interaction="direct", oneshot=True, make_dd_moments=False) +rdfedmet_drpa_bos = vayesta.edmet.EDMET(mf, solver="CCSD-S-1-1", bath_options=dict(dmet_threshold=1e-12), bosonic_interaction="direct", oneshot=True, make_dd_moments=False) with rdfedmet_drpa_bos.iao_fragmentation() as f: f.add_all_atomic_fragments() rdfedmet_drpa_bos.kernel() -rdfedmet_qba_directbos = vayesta.edmet.EDMET(mf, solver="EBCCSD", dmet_threshold=1e-12, bosonic_interaction="qba", oneshot=True, make_dd_moments=False) +rdfedmet_qba_directbos = vayesta.edmet.EDMET(mf, solver="CCSD-S-1-1", bath_options=dict(dmet_threshold=1e-12), bosonic_interaction="qba", oneshot=True, make_dd_moments=False) with rdfedmet_qba_directbos.iao_fragmentation() as f: f.add_all_atomic_fragments() rdfedmet_qba_directbos.kernel() -rdfedmet_qba = vayesta.edmet.EDMET(mf, solver="EBCCSD", dmet_threshold=1e-12, bosonic_interaction="qba_bos_ex", +rdfedmet_qba = vayesta.edmet.EDMET(mf, solver="CCSD-S-1-1", bath_options=dict(dmet_threshold=1e-12), bosonic_interaction="qba_bos_ex", oneshot=True, make_dd_moments=False) with rdfedmet_qba.iao_fragmentation() as f: f.add_all_atomic_fragments() diff --git a/examples/edmet/30-start-from-dft.py b/examples/edmet/30-start-from-dft.py index 4b82896fe..1eae5ec17 100644 --- a/examples/edmet/30-start-from-dft.py +++ b/examples/edmet/30-start-from-dft.py @@ -25,7 +25,7 @@ # The KS opbject needs to be converted to a HF object: lda = lda.to_rhf() -emb_lda = vayesta.edmet.EDMET(lda, dmet_threshold=1e-12, solver="EBCCSD", oneshot=True, make_dd_moments=False) +emb_lda = vayesta.edmet.EDMET(lda, solver="CCSD-S-1-1", bath_options=dict(dmet_threshold=1e-12), oneshot=True, make_dd_moments=False) with emb_lda.iao_fragmentation() as f: f.add_all_atomic_fragments() emb_lda.kernel() @@ -38,7 +38,7 @@ # The KS opbject needs to be converted to a HF object: b3lyp = b3lyp.to_rhf() -emb_b3lyp = vayesta.edmet.EDMET(b3lyp, dmet_threshold=1e-12, solver="EBCCSD", oneshot=True, make_dd_moments=False) +emb_b3lyp = vayesta.edmet.EDMET(b3lyp, solver="CCSD-S-1-1", bath_options=dict(dmet_threshold=1e-12), oneshot=True, make_dd_moments=False) with emb_b3lyp.iao_fragmentation() as f: f.add_all_atomic_fragments() emb_b3lyp.kernel() @@ -47,7 +47,7 @@ hf = pyscf.scf.RHF(mol).density_fit() hf.kernel() -emb_hf = vayesta.edmet.EDMET(hf, dmet_threshold=1e-12, solver="EBCCSD", oneshot=True, make_dd_moments=False) +emb_hf = vayesta.edmet.EDMET(hf, solver="CCSD-S-1-1", bath_options=dict(dmet_threshold=1e-12), oneshot=True, make_dd_moments=False) with emb_hf.iao_fragmentation() as f: f.add_all_atomic_fragments() emb_hf.kernel() diff --git a/examples/edmet/70-h-ring-benchmark.py b/examples/edmet/70-h-ring-benchmark-df.py similarity index 64% rename from examples/edmet/70-h-ring-benchmark.py rename to examples/edmet/70-h-ring-benchmark-df.py index ae1d1aa3b..df018400f 100644 --- a/examples/edmet/70-h-ring-benchmark.py +++ b/examples/edmet/70-h-ring-benchmark-df.py @@ -8,12 +8,28 @@ natom = 6 -filename = "energies_scEDMET_h{:d}_compare.txt".format(natom) +filename = "energies_scEDMET_h{:d}_compare_df.txt".format(natom) with open(filename, "a") as f: f.write(("%6s" + " %16s " * 8) % ( "d", "HF", "CCSD", "FCI", "DMET (Oneshot)", "DMET", "EDMET (Oneshot)", "EDMET (old)", "EDMET (new)")) +import numpy as np +import pyscf.cc +import pyscf.fci +import pyscf.tools +import pyscf.tools.ring +import vayesta.dmet +import vayesta.edmet + + +natom = 6 +filename = "energies_h{:d}_compare_df.txt".format(natom) + +with open(filename, "a") as f: + f.write(("%6s" + " %16s " * 6 + "\n") % ( + "d", "HF", "CCSD", "FCI", "DMET (Oneshot)", "DMET", "EDMET (Oneshot)")) + for d in np.arange(0.5, 3.0001, 0.25): ring = pyscf.tools.ring.make(natom, d) @@ -27,7 +43,10 @@ mol.build() # Hartree-Fock - mf = pyscf.scf.RHF(mol) + # Replace with + # mf = pyscf.scf.RHF(mol) + # to run without density fitting. + mf = pyscf.scf.RHF(mol).density_fit() mf.kernel() # Reference full system CCSD: @@ -51,28 +70,13 @@ f.add_atomic_fragment([i, i + 1]) dmet_diis.kernel() # Single-shot EDMET - edmet_oneshot = vayesta.edmet.EDMET(mf, solver='EBFCI', max_elec_err=1e-4, maxiter=1, max_boson_occ=2) + edmet_oneshot = vayesta.edmet.EDMET(mf, solver='FCI', max_elec_err=1e-4, maxiter=1, + solver_options=dict(max_boson_occ=2), oneshot=True) with edmet_oneshot.iao_fragmentation() as f: for i in range(0, natom, 2): f.add_atomic_fragment([i, i + 1]) edmet_oneshot.kernel() - # Full DMET - edmet_orig = vayesta.edmet.EDMET(mf, solver='EBFCI', charge_consistent=True, max_elec_err=1e-4, maxiter=40, - max_boson_occ=2, old_sc_condition=True) - with edmet_orig.iao_fragmentation() as f: - for i in range(0, natom, 2): - f.add_atomic_fragment([i, i + 1]) - edmet_orig.kernel() - edmet_new = vayesta.edmet.EDMET(mf, solver='EBFCI', charge_consistent=True, max_elec_err=1e-4, maxiter=40, - max_boson_occ=2) - with edmet_new.iao_fragmentation() as f: - for i in range(0, natom, 2): - f.add_atomic_fragment([i, i + 1]) - edmet_new.kernel() - - e_sc_edmet1 = edmet_orig.e_tot if edmet_orig.converged else np.NaN - e_sc_edmet2 = edmet_new.e_tot if edmet_new.converged else np.NaN e_cc = mycc.e_tot if mycc.converged else np.NaN e_dmet = dmet_diis.e_tot if dmet_diis.converged else np.NaN print("E%-14s %+16.8f Ha" % ('(HF)=', mf.e_tot)) @@ -80,14 +84,12 @@ print("E%-14s %+16.8f Ha" % ('(FCI)=', myfci.e_tot)) print("E%-14s %+16.8f Ha" % ('(DMET-FCI)=', dmet_oneshot.e_tot)) print("E%-14s %+16.8f Ha" % ('(EDMET-FCI-Oneshot)=', edmet_oneshot.e_tot)) - print("E%-14s %+16.8f Ha" % ('(EDMET1-FCI)=', e_sc_edmet1)) - print("E%-14s %+16.8f Ha" % ('(EDMET2-FCI)=', e_sc_edmet2)) + with open(filename, "a") as f: - f.write("%.2f % 16.8f % 16.8f % 16.8f %16.8f %16.8f %16.8f %16.8f %16.8f\n" % (d, mf.e_tot, e_cc, + f.write("%.2f % 16.8f % 16.8f % 16.8f %16.8f %16.8f %16.8f\n" % (d, mf.e_tot, e_cc, myfci.e_tot, dmet_oneshot.e_tot, e_dmet, - edmet_oneshot.e_tot, - e_sc_edmet1, - e_sc_edmet2)) + edmet_oneshot.e_tot + )) diff --git a/examples/edmet/71-h-ring-benchmark-df.py b/examples/edmet/71-h-ring-benchmark-df.py deleted file mode 100644 index b4f9c7ada..000000000 --- a/examples/edmet/71-h-ring-benchmark-df.py +++ /dev/null @@ -1,94 +0,0 @@ -import numpy as np -import pyscf.cc -import pyscf.fci -import pyscf.tools -import pyscf.tools.ring -import vayesta.dmet -import vayesta.edmet - - -natom = 6 -filename = "energies_scEDMET_h{:d}_compare_df.txt".format(natom) - -with open(filename, "a") as f: - f.write(("%6s" + " %16s " * 8) % ( - "d", "HF", "CCSD", "FCI", "DMET (Oneshot)", "DMET", "EDMET (Oneshot)", "EDMET (old)", "EDMET (new)")) - -for d in np.arange(0.5, 3.0001, 0.25): - - ring = pyscf.tools.ring.make(natom, d) - atom = [('H %f %f %f' % xyz) for xyz in ring] - - mol = pyscf.gto.Mole() - mol.atom = atom - mol.basis = 'STO-6G' - # mol.verbose = 10 - # mol.output = 'pyscf_out.txt' - mol.build() - - # Hartree-Fock - mf = pyscf.scf.RHF(mol) - dfmf = mf.density_fit() - dfmf.kernel() - - # Reference full system CCSD: - mycc = pyscf.cc.CCSD(dfmf) - mycc.kernel() - - myfci = pyscf.fci.FCI(dfmf) - myfci.kernel() - - # Single-shot - dmet_oneshot = vayesta.dmet.DMET(dfmf, solver='FCI', max_elec_err=1e-4, maxiter=1) - with dmet_oneshot.iao_fragmentation() as f: - for i in range(0, natom, 2): - f.add_atomic_fragment([i, i + 1]) - dmet_oneshot.kernel() - # Full DMET - dmet_diis = vayesta.dmet.DMET(dfmf, solver='FCI', charge_consistent=True, diis=True, - max_elec_err=1e-4) - with dmet_diis.iao_fragmentation() as f: - for i in range(0, natom, 2): - f.add_atomic_fragment([i, i + 1]) - dmet_diis.kernel() - # Single-shot EDMET - edmet_oneshot = vayesta.edmet.EDMET(dfmf, solver='EBFCI', max_elec_err=1e-4, maxiter=1, max_boson_occ=2) - with edmet_oneshot.iao_fragmentation() as f: - for i in range(0, natom, 2): - f.add_atomic_fragment([i, i + 1]) - edmet_oneshot.kernel() - # Full DMET - edmet_orig = vayesta.edmet.EDMET(dfmf, solver='EBFCI', charge_consistent=True, max_elec_err=1e-4, maxiter=40, - max_boson_occ=2, old_sc_condition=True) - with edmet_orig.iao_fragmentation() as f: - for i in range(0, natom, 2): - f.add_atomic_fragment([i, i + 1]) - edmet_orig.kernel() - - edmet_new = vayesta.edmet.EDMET(dfmf, solver='EBFCI', charge_consistent=True, max_elec_err=1e-4, maxiter=40, - max_boson_occ=2) - with edmet_new.iao_fragmentation() as f: - for i in range(0, natom, 2): - f.add_atomic_fragment([i, i + 1]) - edmet_new.kernel() - - e_sc_edmet1 = edmet_orig.e_tot if edmet_orig.converged else np.NaN - e_sc_edmet2 = edmet_new.e_tot if edmet_new.converged else np.NaN - e_cc = mycc.e_tot if mycc.converged else np.NaN - e_dmet = dmet_diis.e_tot if dmet_diis.converged else np.NaN - print("E%-14s %+16.8f Ha" % ('(HF)=', dfmf.e_tot)) - print("E%-14s %+16.8f Ha" % ('(CCSD)=', e_cc)) - print("E%-14s %+16.8f Ha" % ('(FCI)=', myfci.e_tot)) - print("E%-14s %+16.8f Ha" % ('(DMET-FCI)=', dmet_oneshot.e_tot)) - print("E%-14s %+16.8f Ha" % ('(EDMET-FCI-Oneshot)=', edmet_oneshot.e_tot)) - print("E%-14s %+16.8f Ha" % ('(EDMET1-FCI)=', e_sc_edmet1)) - print("E%-14s %+16.8f Ha" % ('(EDMET2-FCI)=', e_sc_edmet2)) - - with open(filename, "a") as f: - f.write("%.2f % 16.8f % 16.8f % 16.8f %16.8f %16.8f %16.8f %16.8f %16.8f\n" % (d, dfmf.e_tot, e_cc, - myfci.e_tot, - dmet_oneshot.e_tot, - e_dmet, - edmet_oneshot.e_tot, - e_sc_edmet1, - e_sc_edmet2)) diff --git a/examples/edmet/72-h-chain-benchmark.py b/examples/edmet/72-h-chain-benchmark.py index b11ff0b10..8793fee0b 100644 --- a/examples/edmet/72-h-chain-benchmark.py +++ b/examples/edmet/72-h-chain-benchmark.py @@ -6,7 +6,7 @@ natom = 10 -for d in np.arange(1.0, 3.7, 0.2): +for d in np.arange(1.0, 3.7, 0.4): pos = [(d * x, 0, 0) for x in range(natom)] atom = [('H %f %f %f' % xyz) for xyz in pos] @@ -15,8 +15,6 @@ mol.atom = atom mol.basis = 'cc-pvdz' mol.unit = "Bohr" - #mol.verbose = 10 - #mol.output = 'pyscf_out.txt' mol.build() # Hartree-Fock @@ -27,40 +25,24 @@ mycc = pyscf.cc.CCSD(mf) mycc.kernel() - #myfci = pyscf.fci.FCI(mf) - #myfci.kernel() - # Single-shot dmet_oneshot = vayesta.dmet.DMET(mf, solver='FCI', max_elec_err=1e-6, maxiter=1) with dmet_oneshot.iao_fragmentation() as f: f.add_all_atomic_fragments() dmet_oneshot.kernel() - # Full DMET - #dmet_diis = vayesta.dmet.DMET(mf, solver='FCI', charge_consistent=True, diis=True, - # max_elec_err = 1e-6) - #dmet_diis.iao_fragmentation() - #dmet_diis.add_all_atomic_fragments() - #dmet_diis.kernel() # Single-shot EDMET - edmet_oneshot = vayesta.edmet.EDMET(mf, solver='EBFCI', max_elec_err=1e-6, maxiter=1, bos_occ_cutoff=4) + edmet_oneshot = vayesta.edmet.EDMET(mf, solver='FCI', max_elec_err=1e-6, oneshot=True, + solver_options=dict(max_boson_occ=4)) with edmet_oneshot.iao_fragmentation() as f: f.add_all_atomic_fragments() edmet_oneshot.kernel() - # Full DMET - edmet_diis = vayesta.edmet.EDMET(mf, solver='EBFCI', charge_consistent=True, max_elec_err=1e-6, maxiter=40, bos_occ_cutoff=4) - with edmet_diis.iao_fragmentation() as f: - f.add_all_atomic_fragments() - edmet_diis.kernel() - e_sc_edmet = edmet_diis.e_tot if edmet_diis.converged else np.NaN e_cc = mycc.e_tot if mycc.converged else np.NaN print("E%-14s %+16.8f Ha" % ('(HF)=', mf.e_tot)) print("E%-14s %+16.8f Ha" % ('(CCSD)=', e_cc)) - print("E%-14s %+16.8f Ha" % ('(DMET-FCI)=', dmet_oneshot.e_tot)) - #print("E%-14s %+16.8f Ha" % ('(DMET-FCI)=', dmet_diis.e_tot)) + print("E%-14s %+16.8f Ha" % ('(DMET-FCI-Oneshot)=', dmet_oneshot.e_tot)) print("E%-14s %+16.8f Ha" % ('(EDMET-FCI-Oneshot)=', edmet_oneshot.e_tot)) - print("E%-14s %+16.8f Ha" % ('(EDMET-FCI)=', e_sc_edmet)) with open("energies_h10_ccpvdz.txt", "a") as f: - f.write("%.2f % 16.8f % 16.8f %16.8f %16.8f %16.8f\n" % (d, mf.e_tot, e_cc, dmet_oneshot.e_tot, - edmet_oneshot.e_tot, e_sc_edmet)) + f.write("%.2f % 16.8f % 16.8f %16.8f %16.8f\n" % (d, mf.e_tot, e_cc, dmet_oneshot.e_tot, + edmet_oneshot.e_tot)) diff --git a/examples/ewf/molecules/20-dump-clusters.py b/examples/ewf/molecules/20-dump-clusters.py index 8cb11e556..a676849ff 100644 --- a/examples/ewf/molecules/20-dump-clusters.py +++ b/examples/ewf/molecules/20-dump-clusters.py @@ -70,11 +70,10 @@ print("c_cluster.shape= (%d, %d)" % frag['c_cluster'].shape) print("c_frag.shape= (%d, %d)" % frag['c_frag'].shape) # Integral arrays: - # hcore, fock, and eris are the 1-electron Hamiltonian, Fock, and 2-electron Hamiltonian + # fock, and eris are the Fock, and 2-electron Hamiltonian # matrix elements in the cluster space. - # heff is equal to hcore, plus an additional potential due to the Coulomb and exchange + # heff is the 1-electron Hamiltonian, plus an additional potential due to the Coulomb and exchange # interaction with the occupied environment orbitals outside the cluster. - print("hcore.shape= (%d, %d)" % frag['hcore'].shape) print("heff.shape= (%d, %d)" % frag['heff'].shape) print("fock.shape= (%d, %d)" % frag['fock'].shape) # The 2-electron integrals are in chemical ordering: eris[i,j,k,l] = (ij|kl) @@ -102,8 +101,6 @@ print("c_frag_a.shape= (%d, %d)" % frag['c_frag_a'].shape) print("c_frag_b.shape= (%d, %d)" % frag['c_frag_b'].shape) # Integral arrays: - print("hcore_a.shape= (%d, %d)" % frag['hcore_a'].shape) - print("hcore_b.shape= (%d, %d)" % frag['hcore_b'].shape) print("heff_a.shape= (%d, %d)" % frag['heff_a'].shape) print("heff_b.shape= (%d, %d)" % frag['heff_b'].shape) print("fock_a.shape= (%d, %d)" % frag['fock_a'].shape) diff --git a/examples/ewf/molecules/24-delta-tailor.py b/examples/ewf/molecules/24-delta-tailor.py index c69b955f3..03d07e9ec 100644 --- a/examples/ewf/molecules/24-delta-tailor.py +++ b/examples/ewf/molecules/24-delta-tailor.py @@ -9,7 +9,7 @@ dm1 = None -for d in np.arange(1.0, 3.1, 0.1): +for d in np.arange(1.0, 1.5, 0.2): mol = pyscf.gto.Mole() mol.atom = 'N 0 0 0 ; N 0 0 %f' % d diff --git a/examples/ewf/molecules/24-tailor-with-fragments.py b/examples/ewf/molecules/24-tailor-with-fragments.py index ed392e961..54d577034 100644 --- a/examples/ewf/molecules/24-tailor-with-fragments.py +++ b/examples/ewf/molecules/24-tailor-with-fragments.py @@ -1,55 +1,54 @@ import numpy as np import pyscf -import pyscf.gto -import pyscf.scf -import pyscf.cc -import pyscf.fci +from pyscf.scf import UHF +from pyscf.gto import Mole +from pyscf.cc import CCSD import vayesta -import vayesta.ewf - - -dm1 = None -for d in np.arange(1.0, 3.1, 0.25): - - mol = pyscf.gto.Mole() - mol.atom = 'N 0 0 0 ; N 0 0 %f' % d - mol.basis = 'STO-6G' - mol.build() - - # Hartree-Fock - mf = pyscf.scf.RHF(mol) +from vayesta.ewf import EWF + + +mol = Mole() +mol.atom = """ + Fe 0 0 0 + O 0 0 1.616 +""" +mol.spin= 4 # 3d6 Fe(II) +mol.basis = "6-31g" +mol.build() + +mf = UHF(mol) +mf.max_cycle = 300 +mf.kernel() +dm1 = mf.make_rdm1() +while True: + mo1 = mf.stability()[0] + stable = mo1 is mf.mo_coeff + dm1 = mf.make_rdm1(mo_coeff=mo1) + if stable: + break mf.kernel(dm1) - while True: - mo1 = mf.stability()[0] - stable = mo1 is mf.mo_coeff - dm1 = mf.make_rdm1(mo_coeff=mo1) - if stable: - break - mf.kernel(dm1) - - # Reference full system CCSD: - cc = pyscf.cc.CCSD(mf) - cc.kernel() - - # Reference full system FCI: - fci = pyscf.fci.FCI(mf) - fci.kernel() - - # Tailor single CCSD with two atomic FCI fragments (projected in first index onto fragment space) - tcc = vayesta.ewf.EWF(mf, solver='CCSD', bath_options=dict(bathtype='full'), solve_lambda=True) - # store_wf_type determines the type of wave function which will be stored. - # For the tailoring below, only the T1 and T2 amplitudes of the FCI fragments are needed, - # and the FCI wave function can thus be converted + truncated to a CCSD wave function. - # Setting auxilary to true, makes sure that the FCI fragments are solved first, but do not contribute - # to expectation values. - with tcc.fragmentation() as f: - fci_x1 = f.add_atomic_fragment(0, solver='FCI', bath_options=dict(bathtype='dmet'), store_wf_type='CCSD', auxiliary=True) - fci_x2 = f.add_atomic_fragment(1, solver='FCI', bath_options=dict(bathtype='dmet'), store_wf_type='CCSD', auxiliary=True) - ccsd = f.add_atomic_fragment([0, 1]) - ccsd.add_external_corrections([fci_x1, fci_x2], correction_type='tailor') - tcc.kernel() - - energies = [mf.e_tot, cc.e_tot if cc.converged else np.nan, fci.e_tot, tcc.e_tot, tcc.get_dm_energy()] - with open('energies.txt', 'a') as f: - fmt = '%.2f' + (len(energies)*' %+16.8f') + '\n' - f.write(fmt % (d, *energies)) +assert(mf.converged) +# Reference full system CCSD: +cc = CCSD(mf) +cc.kernel() + +output = [f'Hartree Fock Energy={mf.e_tot}, CCSD Energy={cc.e_tot if cc.converged else np.nan}'] +for projectors in (0, 1, 2): + # Tailor CCSD with an atomic FCI fragment (projected onto fragment space) + # T1 and T2 amplitudes of the FCI fragment are used to tailor the CCSD amplitudes. setting auxilary to true, + # makes sure that the FCI fragment is solved first, but does not contribute to expectation values. Note that + # projectors = 0 is only suitable for calculations with only a single FCI fragment. Because of overlapping bath + # spaces, for multiple constraining fragments proj=0 will double-count and therefore projectors = 1 or 2 should be used. + emb = EWF(mf) + fci_frags = [] + with emb.iao_fragmentation() as f: + fci_frags.append(f.add_atomic_fragment(['Fe'], orbital_filter=['Fe 3d'], solver='FCI', + store_wf_type='CCSDTQ', + bath_options=dict(bathtype='dmet'), auxiliary=True)) + ccsd = f.add_full_system(solver='extCCSD', bath_options=dict(bathtype='full')) + ccsd.add_external_corrections(fci_frags, correction_type='tailor', projectors=projectors) + emb.kernel() + output.append(f'Projectors={projectors}, Tailored CC Energy={emb.e_tot if emb.converged else np.nan} ') + +for line in output: + print(line) diff --git a/examples/ewf/molecules/73-fragment-symmetry.py b/examples/ewf/molecules/73-fragment-symmetry.py index 8e71b45b8..a1b38ee06 100644 --- a/examples/ewf/molecules/73-fragment-symmetry.py +++ b/examples/ewf/molecules/73-fragment-symmetry.py @@ -28,7 +28,7 @@ # Add rotational symmetry # Set order of rotation (2: 180 degrees, 3: 120 degrees, 4: 90: degrees,...), # axis along which to rotate and center of rotation (default units for axis and center are Angstroms): - with frag.rotational_symmetry(order=5, axis='z'): + with frag.rotational_symmetry(order=5, axis=[0,0,1]): frag.add_atomic_fragment('C2') frag.add_atomic_fragment('H7') diff --git a/examples/ewf/molecules/74-multiple-rotations.py b/examples/ewf/molecules/74-multiple-rotations.py index b53e5f7e7..c0dc5557c 100644 --- a/examples/ewf/molecules/74-multiple-rotations.py +++ b/examples/ewf/molecules/74-multiple-rotations.py @@ -46,8 +46,8 @@ # Important when using multiple rotations: # Only use the minimal set of rotations which generate all atomic fragments, # i.e. do not add multiple 4th-order rotations here! - with frag.rotational_symmetry(order=4, axis='z'): - with frag.rotational_symmetry(order=2, axis='y'): + with frag.rotational_symmetry(order=4, axis=[0,0,1]): + with frag.rotational_symmetry(order=2, axis=[0,1,0]): frag.add_atomic_fragment('C1') frag.add_atomic_fragment('H9') emb_sym.kernel() diff --git a/examples/ewf/other/35-self-consistency.py b/examples/ewf/other/35-self-consistency.py index c63a29b45..ee46a395e 100644 --- a/examples/ewf/other/35-self-consistency.py +++ b/examples/ewf/other/35-self-consistency.py @@ -24,7 +24,7 @@ cc.kernel() # Reference one-shot EWF-CCSD -ecc = vayesta.ewf.EWF(mf, bno_threshold=1e-4) +ecc = vayesta.ewf.EWF(mf, bath_options=dict(threshold=1e-4)) ecc.kernel() # Enable self-consistency (SC) mode by setting sc_mode: @@ -32,13 +32,10 @@ # (conservative external correction) # sc_mode = 2: Project only the first occupied index of other's fragment T2-amplitude onto it's fragment space # (more substantional external correction) -scecc = vayesta.ewf.EWF(mf, bno_threshold=1e-4, sc_mode=1) -scecc.iao_fragmentation() -f0 = scecc.add_atomic_fragment(0) -f1 = scecc.add_atomic_fragment(1) -# Additional we need to define which fragment is considered in the tailoring of each other fragment: -f0.add_tailor_fragment(f1) -f1.add_tailor_fragment(f0) +scecc = vayesta.ewf.EWF(mf, solver='TCCSD', bath_options=dict(threshold=1e-4), sc_mode=1) +with scecc.iao_fragmentation() as frag: + f0 = frag.add_atomic_fragment(0) + f1 = frag.add_atomic_fragment(1) # If each fragment should be tailored by all others (like here), you can also call ecc.tailor_all_fragments() scecc.kernel() diff --git a/examples/ewf/other/61-ext-corr-hubbard-1D.py b/examples/ewf/other/61-ext-corr-hubbard-1D.py index f48d9948a..fbcac884b 100644 --- a/examples/ewf/other/61-ext-corr-hubbard-1D.py +++ b/examples/ewf/other/61-ext-corr-hubbard-1D.py @@ -38,7 +38,7 @@ # Add single 'complete' CCSD fragment covering all sites ccsd_frag = f.add_full_system(solver='CCSD', bath_options=dict(bathtype='full'), solver_options=dict(solve_lambda=False, init_guess='CISD')) # Add symmetry-derived FCI fragments to avoid multiple calculations -fci_frags.extend(fci_frags[0].add_tsymmetric_fragments(tvecs=[5, 1, 1]) +fci_frags.extend(fci_frags[0].add_tsymmetric_fragments(tvecs=[5, 1, 1])) e_extcorr = [] extcorr_conv = [] diff --git a/examples/ewf/other/71-sc-h-ring.py b/examples/ewf/other/71-sc-h-ring.py index c9c9d1419..c7f138804 100644 --- a/examples/ewf/other/71-sc-h-ring.py +++ b/examples/ewf/other/71-sc-h-ring.py @@ -35,14 +35,17 @@ cc.kernel() # One-shot EWF-CCSD - ecc = vayesta.ewf.EWF(mf, bno_threshold=1e-4) - ecc.add_all_atomic_fragments() + ecc = vayesta.ewf.EWF(mf, bath_options=dict(threshold=1e-4)) + with ecc.iao_fragmentation() as f: + with f.rotational_symmetry(6, axis='z'): + f.add_atomic_fragment([0]) ecc.kernel() # Self-consistent EWF-CCSD - scecc = vayesta.ewf.EWF(mf, bno_threshold=1e-4, sc_mode=1) - scecc.add_all_atomic_fragments() - scecc.tailor_all_fragments() + scecc = vayesta.ewf.EWF(mf, solver='TCCSD', bath_options=dict(threshold=1e-6), sc_mode=1) + with scecc.iao_fragmentation() as f: + with f.rotational_symmetry(6, axis='z'): + f.add_atomic_fragment([0]) scecc.kernel() print("E%-14s %+16.8f Ha" % ('(HF)=', mf.e_tot)) diff --git a/examples/ewf/other/72-sc-h-plane.py b/examples/ewf/other/72-sc-h-plane.py deleted file mode 100644 index 2e0b31f36..000000000 --- a/examples/ewf/other/72-sc-h-plane.py +++ /dev/null @@ -1,58 +0,0 @@ -# Broken - -import numpy as np - -import pyscf -import pyscf.pbc -import pyscf.pbc.gto -import pyscf.pbc.scf -import pyscf.pbc.cc - -import vayesta -import vayesta.ewf - -kmesh = [4, 4, 1] - -#for d in np.arange(0.5, 3.0001, 0.25): -for d in np.arange(0.7, 3.0001, 0.25): - - cell = pyscf.pbc.gto.Cell() - cell.atom = 'He 0.0 0.0 0.0' - cell.a = d*np.eye(3) - cell.a[2,2] = 20.0 - cell.basis = '6-31g' - cell.verbose = 10 - cell.output = 'pyscf_out.txt' - cell.dimension = 2 - cell.build() - - kpts = cell.make_kpts(kmesh) - - # Hartree-Fock - kmf = pyscf.pbc.scf.KRHF(cell, kpts) - kmf = kmf.density_fit() - kmf.kernel() - - # Reference full system CCSD: - kcc = pyscf.pbc.cc.KCCSD(kmf) - kcc.kernel() - - # One-shot EWF-CCSD - ecc = vayesta.ewf.EWF(kmf, bno_threshold=1e-4) - ecc.add_all_atomic_fragments() - ecc.kernel() - - # Self-consistent EWF-CCSD - scecc = vayesta.ewf.EWF(kmf, bno_threshold=1e-4, sc_mode=1) - scecc.add_all_atomic_fragments() - scecc.tailor_all_fragments() - scecc.kernel() - - print("E%-14s %+16.8f Ha" % ('(HF)=', kmf.e_tot)) - print("E%-14s %+16.8f Ha" % ('(CCSD)=', kcc.e_tot)) - print("E%-14s %+16.8f Ha" % ('(EWF-CCSD)=', ecc.e_tot)) - print("E%-14s %+16.8f Ha" % ('(SC-EWF-CCSD)=', scecc.e_tot)) - - with open("energies.txt", "a") as f: - f.write("%.2f % 16.8f % 16.8f % 16.8f %16.8f\n" % (d, kmf.e_tot, kcc.e_tot, ecc.e_tot, scecc.e_tot)) - #f.write("%.2f % 16.8f % 16.8f % 16.8f %16.8f\n" % (d, kmf.e_tot, ecc.e_tot, scecc.e_tot)) diff --git a/examples/ewf/other/76-sc-graphene.py b/examples/ewf/other/76-sc-graphene.py deleted file mode 100644 index 7dc341212..000000000 --- a/examples/ewf/other/76-sc-graphene.py +++ /dev/null @@ -1,72 +0,0 @@ -# broken - -import numpy as np - -import pyscf -import pyscf.pbc -import pyscf.pbc.gto -import pyscf.pbc.scf - -import vayesta -import vayesta.ewf - -dists = np.arange(2.35, 2.6501, 0.05) -basis = 'def2-svp' -kmesh = [2,2,1] - -bno_threshold = [1e-4, 1e-5, 1e-6, 1e-7] - -sc_mode = 1 -#sc_mode = 2 - -def make_graphene(a, c, atoms=['C', 'C']): - cell = pyscf.pbc.gto.Cell() - cell.a = np.asarray([ - [a, 0, 0], - [a/2, a*np.sqrt(3.0)/2, 0], - [0, 0, c]]) - coords_internal = np.asarray([ - [2.0, 2.0, 3.0], - [4.0, 4.0, 3.0]])/6 - coords = np.dot(coords_internal, cell.a) - atom = [] - for i in range(len(atoms)): - if atoms[i] is not None: - atom.append([atoms[i], coords[i]]) - cell.atom = atom - cell.verbose = 10 - cell.output = 'pyscf_out.txt' - cell.basis = basis - cell.dimension = 2 - cell.build() - - return cell - -for d in dists: - - cell = make_graphene(d, c=20.0) - kpts = cell.make_kpts(kmesh) - - # Hartree-Fock - kmf = pyscf.pbc.scf.KRHF(cell, kpts) - kmf = kmf.density_fit(auxbasis='def2-svp-ri') - kmf.kernel() - - ecc = vayesta.ewf.EWF(kmf, bno_threshold=bno_threshold) - ecc.add_atomic_fragment(0, sym_factor=2) - ecc.kernel() - - with open('ewf-ccsd.txt', 'a') as f: - energies = ecc.get_energies() - fmt = ("%6.3f" + len(energies)*" %+16.8f" + "\n") - f.write(fmt % (d, *energies)) - - scecc = vayesta.ewf.EWF(kmf, bno_threshold=bno_threshold, sc_mode=sc_mode) - scecc.add_all_atomic_fragments(sym_factor=0.25) - scecc.tailor_all_fragments() - scecc.kernel() - - with open('scewf-ccsd.txt', 'a') as f: - energies = scecc.get_energies() - fmt = ("%6.3f" + len(energies)*" %+16.8f" + "\n") - f.write(fmt % (d, *energies)) diff --git a/examples/ewf/solids/02-exact-limit-uhf.py b/examples/ewf/solids/02-exact-limit-uhf.py index 356363176..dc7a36bb9 100644 --- a/examples/ewf/solids/02-exact-limit-uhf.py +++ b/examples/ewf/solids/02-exact-limit-uhf.py @@ -21,7 +21,7 @@ cell = pyscf.pbc.tools.super_cell(cell, [2,2,2]) # Hartree-Fock -mf = pyscf.pbc.scf.UHF(cell) +mf = pyscf.pbc.scf.UHF(cell).density_fit() mf.kernel() # Reference full system CCSD: @@ -29,9 +29,9 @@ cc.kernel() # Test exact limit using bath_type='full' -ecc = vayesta.ewf.EWF(mf, bath_type='full') -ecc.iao_fragmentation() -ecc.add_all_atomic_fragments() +ecc = vayesta.ewf.EWF(mf, bath_options=dict(bathtype='full')) +with ecc.iao_fragmentation() as f: + f.add_all_atomic_fragments() ecc.kernel() nocca = np.count_nonzero(mf.mo_occ[0]>0) @@ -41,7 +41,7 @@ print("E(exx-div)= %+16.8f Ha" % e_exxdiv) print("E(HF)= %+16.8f Ha" % mf.e_tot) -print("E(CCSD)= %+16.8f Ha" % (cc.e_tot + e_exxdiv)) +print("E(CCSD)= %+16.8f Ha" % cc.e_tot ) print("E(EWF-CCSD)= %+16.8f Ha" % ecc.e_tot) -assert np.allclose(cc.e_tot + e_exxdiv, ecc.e_tot) +assert np.allclose(cc.e_tot, ecc.e_tot) diff --git a/examples/ewf/solids/02-exact-limit.py b/examples/ewf/solids/02-exact-limit.py index 92e2951c1..83929d70e 100644 --- a/examples/ewf/solids/02-exact-limit.py +++ b/examples/ewf/solids/02-exact-limit.py @@ -19,7 +19,7 @@ mol.build() # Hartree-Fock -mf = pyscf.pbc.scf.RHF(mol) +mf = pyscf.pbc.scf.RHF(mol).density_fit() mf.kernel() # Reference full system CCSD: @@ -27,9 +27,9 @@ cc.kernel() # Test exact limit using bno_threshold = -1 -ecc = vayesta.ewf.EWF(mf, bno_threshold=-1) -ecc.iao_fragmentation() -ecc.add_all_atomic_fragments() +ecc = vayesta.ewf.EWF(mf, bath_options=dict(threshold=-1)) +with ecc.iao_fragmentation() as f: + f.add_all_atomic_fragments() ecc.kernel() nocc = np.count_nonzero(mf.mo_occ>0) @@ -37,7 +37,7 @@ print("E(exx-div)= %+16.8f Ha" % e_exxdiv) print("E(HF)= %+16.8f Ha" % mf.e_tot) -print("E(CCSD)= %+16.8f Ha" % (cc.e_tot + e_exxdiv)) +print("E(CCSD)= %+16.8f Ha" % cc.e_tot ) print("E(EWF-CCSD)= %+16.8f Ha" % ecc.e_tot) -assert np.allclose(cc.e_tot + e_exxdiv, ecc.e_tot) +assert np.allclose(cc.e_tot, ecc.e_tot) diff --git a/examples/ewf/solids/04-kpts-vs-supercell.py b/examples/ewf/solids/04-kpts-vs-supercell.py index 020451c79..a84000f23 100644 --- a/examples/ewf/solids/04-kpts-vs-supercell.py +++ b/examples/ewf/solids/04-kpts-vs-supercell.py @@ -33,9 +33,9 @@ kcc.kernel() # Embedded calculation will automatically fold the k-point sampled mean-field to the supercell -emb = vayesta.ewf.EWF(kmf, bno_threshold=1e-6) -emb.iao_fragmentation() -emb.add_atomic_fragment(0, sym_factor=2) # 2 C-atoms per unit cell +emb = vayesta.ewf.EWF(kmf, bath_options=dict(threshold=1e-6)) +with emb.iao_fragmentation() as f: + f.add_atomic_fragment(0, sym_factor=2) # 2 C-atoms per unit cell emb.kernel() # Hartree-Fock in supercell @@ -44,10 +44,10 @@ mf_sc = mf_sc.density_fit(auxbasis='def2-svp-ri') mf_sc.kernel() -emb_sc = vayesta.ewf.EWF(mf_sc, bno_threshold=1e-6) -emb_sc.iao_fragmentation() -ncells = np.product(kmesh) -emb_sc.add_atomic_fragment(0, sym_factor=2*ncells) +emb_sc = vayesta.ewf.EWF(mf_sc, bath_options=dict(threshold=1e-6)) +with emb_sc.iao_fragmentation() as f: + ncells = np.product(kmesh) + f.add_atomic_fragment(0, sym_factor=2*ncells) emb_sc.kernel() print("E(k-HF)= %+16.8f Ha" % kmf.e_tot) diff --git a/examples/ewf/solids/14-density-matrix.py b/examples/ewf/solids/14-density-matrix.py index c6cdb7643..ff9f6fa30 100644 --- a/examples/ewf/solids/14-density-matrix.py +++ b/examples/ewf/solids/14-density-matrix.py @@ -26,11 +26,11 @@ kmf.kernel() # Embedded calculation will automatically fold the k-point sampled mean-field to the supercell -emb = vayesta.ewf.EWF(kmf, bno_threshold=-1, store_dm1=True) +emb = vayesta.ewf.EWF(kmf, bath_options=dict(threshold=-1)) emb.kernel() dm1_demo = emb.make_rdm1_demo(ao_basis=True) -dm1_emb = emb.make_rdm1_ccsd(ao_basis=True) +dm1_emb = emb.make_rdm1(ao_basis=True) # Full system reference CCSD mf = emb.mf.density_fit(auxbasis='def2-svp-ri') diff --git a/examples/ewf/solids/55-dm-energy.py b/examples/ewf/solids/55-dm-energy.py index cd75c30d2..9463ef10a 100644 --- a/examples/ewf/solids/55-dm-energy.py +++ b/examples/ewf/solids/55-dm-energy.py @@ -25,7 +25,7 @@ kmf.kernel() # --- Embedding -emb = vayesta.ewf.EWF(kmf, bath_type='full', solve_lambda=True) +emb = vayesta.ewf.EWF(kmf, bath_options=dict(bathtype='full'), solver_options=dict(solve_lambda=True)) emb.kernel() e_dm = emb.get_dm_energy() diff --git a/examples/ewf/solids/56-dm-energy-uccsd.py b/examples/ewf/solids/56-dm-energy-uccsd.py index 3ea826009..06a190604 100644 --- a/examples/ewf/solids/56-dm-energy-uccsd.py +++ b/examples/ewf/solids/56-dm-energy-uccsd.py @@ -25,7 +25,7 @@ kmf.kernel() # --- Embedding -emb = vayesta.ewf.EWF(kmf, bath_type='full', solve_lambda=True) +emb = vayesta.ewf.EWF(kmf, bath_options=dict(bathtype='full'), solver_options=dict(solve_lambda=True)) emb.kernel() e_dm = emb.get_dm_energy() diff --git a/examples/ewf/solids/61-start-from-lda.py b/examples/ewf/solids/61-start-from-lda.py index 785ccdb71..202ab829d 100644 --- a/examples/ewf/solids/61-start-from-lda.py +++ b/examples/ewf/solids/61-start-from-lda.py @@ -26,7 +26,7 @@ lda_as_hf.__dict__.update(lda.__dict__) lda = lda_as_hf -emb_lda = vayesta.ewf.EWF(lda, bno_threshold=1e-6) +emb_lda = vayesta.ewf.EWF(lda, bath_options=dict(threshold=1e-6)) emb_lda.kernel() # HF @@ -34,7 +34,7 @@ hf = hf.density_fit(auxbasis='cc-pVDZ-ri') hf.kernel() -emb_hf = vayesta.ewf.EWF(hf, bno_threshold=1e-6) +emb_hf = vayesta.ewf.EWF(hf, bath_options=dict(threshold=1e-6)) emb_hf.kernel() # Reference full system CCSD: diff --git a/examples/ewf/solids/73-rotational-symmetry.py b/examples/ewf/solids/73-rotational-symmetry.py index 182b1f580..0eedc8c6b 100644 --- a/examples/ewf/solids/73-rotational-symmetry.py +++ b/examples/ewf/solids/73-rotational-symmetry.py @@ -6,14 +6,15 @@ import vayesta.ewf cell = pyscf.pbc.gto.Cell() -cell.atom = 'H 0 0 0; H 1 0 0; H 0 1 0; H 1 1 0' -cell.a = 4*np.eye(3) +cell.atom = 'Li 0 0 0; Li 1 0 0; Li 0 1 0; Li 1 1 0' +cell.a = 8*np.eye(3) cell.basis = 'sto-6g' +cell.exp_to_discard=0.1 cell.output = 'pyscf.out' cell.build() # Hartree-Fock with k-points -kpts = cell.make_kpts([2,2,1]) +kpts = cell.make_kpts([2,2,2]) mf = pyscf.pbc.scf.KRHF(cell, kpts) mf = mf.density_fit(auxbasis='sto-6g') mf.kernel() @@ -24,13 +25,14 @@ # Add rotational symmetry: # Set order of rotation (2: 180 degrees, 3: 120 degrees, 4: 90: degrees,...), # axis along which to rotate and center of rotation (default units for axis and center are Angstroms): -emb_sym.symmetry.add_rotation(order=4, axis=[0,0,1], center=[0.5,0.5,0]) +#emb_sym.symmetry.add_rotation(order=4, axis=[0,0,1], center=[0.5,0.5,0]) # It's also possible to use units of Bohr or lattice vectors: #emb_sym.symmetry.add_rotation(order=4, axis=[0,0,1], center=[0.5/4,0.5/4,0], unit='latvec') # Do not call add_all_atomic_fragments, as it add the symmetry related atoms as fragments! with emb_sym.iao_fragmentation() as frag: - f = frag.add_atomic_fragment(0) + with frag.rotational_symmetry(order=4, axis=[0,0,1], center=[0.5,0.5,0]): + f = frag.add_atomic_fragment(0) emb_sym.kernel() # Reference calculation without rotational symmetry: diff --git a/examples/gdf/01-simple-gdf.py b/examples/gdf/01-simple-gdf.py deleted file mode 100644 index fbc9f87c7..000000000 --- a/examples/gdf/01-simple-gdf.py +++ /dev/null @@ -1,27 +0,0 @@ -from pyscf.pbc import gto, scf -from vayesta.misc import gdf -import numpy as np - -cell = gto.Cell() -cell.atom = 'He 0 0 0' -cell.basis = '6-31g' -cell.a = np.eye(3) * 2 -cell.verbose = 0 -cell.build() - -kpts = cell.make_kpts([2, 2, 1]) - -# Initialisation is functionally identical to pyscf.pbc.df.df.GDF: -with_df = gdf.GDF(cell, kpts) -with_df.build() - -# Works seamlessly with pyscf MF methods: -mf = scf.KRHF(cell, kpts) -mf.with_df = with_df -mf.kernel() -print('E(rhf) = %16.12f' % mf.e_tot) - -mf = scf.KUHF(cell, kpts) -mf.with_df = with_df -mf.kernel() -print('E(uhf) = %16.12f' % mf.e_tot) diff --git a/examples/gdf/02-save-and-load.py b/examples/gdf/02-save-and-load.py deleted file mode 100644 index c25d58747..000000000 --- a/examples/gdf/02-save-and-load.py +++ /dev/null @@ -1,31 +0,0 @@ -from pyscf.pbc import gto, scf -from vayesta.misc import gdf -import numpy as np -import os - -cell = gto.Cell() -cell.atom = 'He 0 0 0' -cell.basis = '6-31g' -cell.a = np.eye(3) * 2 -cell.verbose = 0 -cell.build() - -kpts = cell.make_kpts([2, 2, 1]) - -# Integrals can be saved using numpy's native ndarray.save method: -with_df = gdf.GDF(cell, kpts) -with_df.build() -with_df.save('cderi.tmp') - -# GDF.build must be called, use argument with_j3c=True to prevent -# reconstruction of the integrals: -with_df = gdf.GDF(cell, kpts) -with_df.build(with_j3c=True) -with_df.load('cderi.tmp') - -mf = scf.KRHF(cell, kpts) -mf.with_df = with_df -mf.kernel() -print('E(rhf) = %16.12f' % mf.e_tot) - -os.remove('cderi.tmp') diff --git a/examples/gdf/03-jk.py b/examples/gdf/03-jk.py deleted file mode 100644 index 408cd4a98..000000000 --- a/examples/gdf/03-jk.py +++ /dev/null @@ -1,41 +0,0 @@ -from pyscf.pbc import gto -from pyscf.pbc import df as df_pyscf -from vayesta.misc import gdf -import numpy as np -import time - -cell = gto.Cell() -cell.atom = 'He 0 0 0' -cell.basis = '6-31g' -cell.a = np.eye(3) * 2 -cell.verbose = 0 -cell.build() - -kpts = cell.make_kpts([2, 2, 1]) - -with_df = gdf.GDF(cell, kpts) -with_df.build() - -with_df_pyscf = df_pyscf.GDF(cell, kpts) -with_df_pyscf.build() - -dm = ( - + np.random.random((len(kpts), cell.nao, cell.nao)) - + 1.0j * np.random.random((len(kpts), cell.nao, cell.nao)) -) -dm = dm + dm.transpose(0, 2, 1).conj() - -# Supports accelerated evaluation of J and K, but inputted density -# matrices must enumerate the same k-points as with_df.kpts: -t0 = time.time() -j0, k0 = with_df.get_jk(dm) -t1 = time.time() - -t2 = time.time() -j1, k1 = with_df_pyscf.get_jk(dm) -t3 = time.time() - -print('J equal:', np.allclose(j0, j1)) -print('K equal:', np.allclose(k0, k1)) -print('pyscf time: %.6f s' % (t3-t2)) -print('vayesta time: %.6f s' % (t1-t0)) diff --git a/examples/gdf/04-ao-tensors.py b/examples/gdf/04-ao-tensors.py deleted file mode 100644 index 50cdf94cf..000000000 --- a/examples/gdf/04-ao-tensors.py +++ /dev/null @@ -1,32 +0,0 @@ -from pyscf.pbc import gto -from vayesta.misc import gdf -import numpy as np - -cell = gto.Cell() -cell.atom = 'He 0 0 0' -cell.basis = '6-31g' -cell.a = np.eye(3) * 2 -cell.verbose = 0 -cell.build() - -kpts = cell.make_kpts([2, 2, 2]) - -with_df = gdf.GDF(cell, kpts) -with_df.build() - -ki, kj = 0, 1 -kpti = kpts[0] -kptj = kpts[1] - -# Similarly to pyscf, obtain four-center AO ERIs via get_eri or get_ao_eri: -pqrs = with_df.get_eri([kpti, kptj, kpti, kptj], compact=False) -pqrs = pqrs.reshape([cell.nao,]*4) - -# Also access three-center AO integrals via get_3c_eri or get_ao_3c_eri: -Lpq = with_df.get_3c_eri([kpti, kptj], compact=False) -Lpq = Lpq.reshape(-1, cell.nao, cell.nao) -assert np.allclose(pqrs, np.einsum('Lpq,Lrs->pqrs', Lpq, Lpq)) - -# ... or alternatively directly via the _cderi attribute: -Lpq = with_df._cderi[ki, kj] -assert np.allclose(pqrs, np.einsum('Lpq,Lrs->pqrs', Lpq, Lpq)) diff --git a/examples/gdf/05-mo-tensors.py b/examples/gdf/05-mo-tensors.py deleted file mode 100644 index 0dda4bdf3..000000000 --- a/examples/gdf/05-mo-tensors.py +++ /dev/null @@ -1,53 +0,0 @@ -from pyscf.pbc import gto -from vayesta.misc import gdf -import numpy as np - -cell = gto.Cell() -cell.atom = 'He 0 0 0' -cell.basis = '6-31g' -cell.a = np.eye(3) * 2 -cell.verbose = 0 -cell.build() - -kpts = cell.make_kpts([2, 2, 2]) - -with_df = gdf.GDF(cell, kpts) -with_df.build() - -ki, ka = 0, 1 -kpti = kpts[0] -kpta = kpts[1] - -ci = ( - + np.random.random((cell.nao, 4)) - + 1.0j * np.random.random((cell.nao, 4)) -) -ca = ( - + np.random.random((cell.nao, 8)) - + 1.0j * np.random.random((cell.nao, 8)) -) - -# Similarly to pyscf, obtain four-center MO ERIs via ao2mo or get_mo_eri: -iajb = with_df.ao2mo((ci, ca, ci, ca), [kpti, kpta, kpti, kpta], compact=False) -iajb = iajb.reshape([ci.shape[-1], ca.shape[-1],]*2) - -# Also access three-center MO integrals via ao2mo_3c or get_mo_3c_eri: -Lia = with_df.ao2mo_3c((ci, ca), [kpti, kpta], compact=False) -Lia = Lia.reshape(-1, ci.shape[-1], ca.shape[-1]) -assert np.allclose(iajb, np.einsum('Lia,Ljb->iajb', Lia, Lia)) - -# ... or alternatively directly via the _cderi attribute: -Lia = np.einsum('Lpq,pi,qa->Lia', with_df._cderi[ki, ka], ci.conj(), ca) -assert np.allclose(iajb, np.einsum('Lia,Ljb->iajb', Lia, Lia)) - -# To perform a permanent basis change to the with_df object, simply rotate -# the entire _cderi into a basis: -c = ( - + np.random.random((len(kpts), cell.nao, cell.nao)) - + 1.0j * np.random.random((len(kpts), cell.nao, cell.nao)) -) -cderi = np.zeros_like(with_df._cderi) -for i in range(len(kpts)): - for j in range(len(kpts)): - cderi[i, j] = np.einsum('Lpq,pi,qj->Lij', with_df._cderi[i, j], c[i].conj(), c[j]) -with_df._cderi = cderi diff --git a/examples/run_examples.py b/examples/run_examples.py new file mode 100644 index 000000000..58544d075 --- /dev/null +++ b/examples/run_examples.py @@ -0,0 +1,29 @@ +import os +import sys +import subprocess + +if len(sys.argv) > 1: + directory = sys.argv[1] +else: + directory = os.path.abspath(os.path.dirname(__file__)) + +examples = os.popen('find . | grep \.py$').readlines() + +assert len(examples) > 0 + +N = len(examples) +errs = [] +for eg in examples[1:]: + print("Running %s" %eg) + errno = subprocess.call('python ' + eg[:-1] + ' -q', shell=True) + if errno != 0: + print("\033[91mException in %s \033[0m" % eg) + errs.append(eg) + +if len(errs) == 0: + print("\033[92mAll examples passed \033[0m") +else: + print("\033[91m Exceptions found: %d/%d examples failed \033[0m"%(len(errs),len(examples))) + for eg in errs: + print("Execption in %s"%eg) + diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..a8f9f0f1f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,114 @@ +[project] +name = "Vayesta" +description = "A toolkit for quantum embedding methods" +keywords = [ + "embedding", + "quantum", "chemistry", + "material", "science", + "electronic", "structure", + "dmet", "rpa" +] +authors = [ + {name="M. Nusspickel", email="vayesta.embedding@gmail.com"}, + {name="O. J. Backhouse", email="vayesta.embedding@gmail.com"}, + {name="B. Ibrahim", email="vayesta.embedding@gmail.com"}, + {name="A. Santana-Bonilla", email="vayesta.embedding@gmail.com"}, + {name="C. J. C. Scott", email="vayesta.embedding@gmail.com"}, + {name="A. Khedkar", email="vayesta.embedding@gmail.com"}, + {name="G. H. Booth", email="vayesta.embedding@gmail.com"}, +] +license = {file = "LICENSE"} +readme = "README.md" +requires-python = ">=3.7" +classifiers = [ + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: Apache Software License", + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + "Topic :: Scientific/Engineering", + "Topic :: Software Development", + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: C", + "Operating System :: MacOS :: MacOS X", + "Operating System :: POSIX :: Linux", +] +dependencies = [ + "numpy>=1.19.0", + "scipy>=1.1.0,<=1.10.0", + "h5py>=2.7", + "cvxpy>=1.1", + "pyscf @ git+https://github.com/pyscf/pyscf@master", +] +dynamic = ["version"] + +[build-system] +requires = ["setuptools>=61.0.0"] +build-backend = "setuptools.build_meta" + +[tools.setuptools] +license-files = ["LICENSE"] + +[tools.setuptools.dynamic] +version = {attr = "vayesta.__version__"} + +[project.optional-dependencies] +dmet = [ + "cvxpy>=1.1", +] +mpi = [ + "mpi4py>=3.0.0", +] +dyson = [ + "dyson @ git+https://github.com/BoothGroup/dyson@master", +] +ebcc = [ + "ebcc" +] +dev = [ + "cvxpy>=1.1", + "mpi4py>=3.0.0", + "dyson @ git+https://github.com/BoothGroup/dyson@master", + "ebcc", + "pytest", + "pytest-cov", +] + +[tool.coverage.run] +branch = true +source = ["vayesta"] +omit = [ + "*/libs/*", + "*/tests/*", + "*/tools/*", + "*/core/DEL/*", +] + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "raise RuntimeError", + "raise NotImplementedError", + "raise AssertionError", + "raise ValueError", + "raise AbstractMethodError", + "except ImportError", + "pass", + "if __name__ == .__main__.:", + "def __repr__", + "def __str__", + "log.error", + "log.critical", +] + +[tool.pytest.ini_options] +addopts = "--import-mode=importlib -k 'not veryslow'" +testpaths = ["vayesta/tests"] +markers = [ + "fast", + "slow", + "veryslow", +] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 05b73527b..000000000 --- a/pytest.ini +++ /dev/null @@ -1,5 +0,0 @@ -[pytest] -markers = - fast: Run only the trivially fast tests - slow: Run the slower tests - veryslow: Run the extremely slow tests diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index cd776b9bf..000000000 --- a/setup.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[egg_info] -tag_build = -tag_date = 0 - -[tool:pytest] -addopts = --import-mode=importlib -k "not veryslow" diff --git a/setup.py b/setup.py index 838982d4f..a552fa92a 100644 --- a/setup.py +++ b/setup.py @@ -11,8 +11,6 @@ setup_src = os.path.dirname(os.path.realpath(__file__)) -# TODO: mpi4py as optional extra - class CMakeExtension(Extension): """Initialise the name of a CMake extension. @@ -124,83 +122,14 @@ def run_tests(self): [c for c in build.sub_commands if c[0] != 'build_ext']) -# Get the version from the __init__.py: -with open(os.path.join(setup_src, "vayesta", "__init__.py"), "r") as f: - for line in f.readlines(): - if line.startswith("__version__ = "): - version = line.strip("__version__ = ") - version = version.replace("\'", "") - version = version.replace("\"", "") - - setup( - name="Vayesta", - version=version, - description="A toolkit for quantum embedding methods", - url="https://vayesta.github.io", - download_url="https://github.com/BoothGroup/Vayesta", - keywords=[ - "embedding", - "quantum", "chemistry", - "material", "science", - "electronic", "structure", - "dmet", "rpa", - ], - author=", ".join([ - "M. Nusspickel", - "O. J. Backhouse", - "B. Ibrahim", - "A. Santana-Bonilla", - "C. J. C. Scott", - "A. Khedkar", - "G. H. Booth", - ]), - author_email="vayesta.embedding@gmail.com", - license="Apache License 2.0", - platforms=[ - "Linux", - "Mac OS-X", - ], - python_requires=">=3.7", - classifiers=[ - "Development Status :: 3 - Alpha", - "License :: OSI Approved :: Apache Software License", - "Intended Audience :: Science/Research", - "Intended Audience :: Developers", - "Topic :: Scientific/Engineering", - "Topic :: Software Development", - "Programming Language :: Python", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: C", - "Operating System :: MacOS :: MacOS X", - "Operating System :: POSIX :: Linux", - ], packages=find_packages(exclude=["*examples*"]), include_package_data=True, - install_requires=[ - "wheel", - "numpy>=1.19.0", - "scipy>=1.1.0", - "h5py>=2.7", - "pyscf @ git+https://github.com/pyscf/pyscf@master", - ], - extras_require={ - "dmet": ["cvxpy>=1.1"], - "mpi": ["mpi4py>=3.0.0"], - "ebcc": ["ebcc @ git+https://github.com/BoothGroup/ebcc@master"], - }, ext_modules=[CMakeExtension("vayesta/libs")], cmdclass={ "build_ext": CMakeBuild, "test": DiscoverTests, "clean": CleanCommand, }, - tests_require=[ - "pytest", - "pytest-cov", - ], zip_safe=False, ) diff --git a/vayesta/core/DEL/actspace.py b/vayesta/core/DEL/actspace.py deleted file mode 100644 index c8bea2d38..000000000 --- a/vayesta/core/DEL/actspace.py +++ /dev/null @@ -1,353 +0,0 @@ -import numpy as np - -from vayesta.core.DEL.orbitals import OrbitalSpace -from vayesta.core.DEL import helper - - -def ActiveSpace(mf, *args, **kwargs): - if mf.mo_coeff[0].ndim == 1: - return ActiveSpace_RHF(mf, *args, **kwargs) - return ActiveSpace_UHF(mf, *args, **kwargs) - -class ActiveSpace_RHF: - - def __init__(self, mf, c_active_occ, c_active_vir, c_frozen_occ=None, c_frozen_vir=None): - self.mf = mf - # Active - self._active_occ = OrbitalSpace(c_active_occ, name="active-occupied") - self._active_vir = OrbitalSpace(c_active_vir, name="active-virtual") - # Frozen - if c_frozen_occ is not None: - self._frozen_occ = OrbitalSpace(c_frozen_occ, name="frozen-occupied") - else: - self._frozen_occ = None - if c_frozen_vir is not None: - self._frozen_vir = OrbitalSpace(c_frozen_vir, name="frozen-virtual") - else: - self._frozen_vir = None - - # --- General - - def __repr__(self): - return ("ActiveSpace(nocc_active= %d, nvir_active= %d, nocc_frozen= %d, nvir_frozen= %d)" % - (self.nocc_active, self.nvir_active, self.nocc_frozen, self.nvir_frozen)) - - def pack(self): - arrays = [x.coeff for x in (self._active_occ, self._active_vir, self._frozen_occ, self._frozen_vir)] - return helper.pack_arrays(*arrays) - - @classmethod - def unpack(cls, mf, packed): - c_active_occ, c_active_vir, c_frozen_occ, c_frozen_vir = helper.unpack_arrays(packed) - return cls(mf, c_active_occ, c_active_vir, c_frozen_occ, c_frozen_vir) - - # --- Mean-field: - - @property - def is_rhf(self): - return True - - @property - def is_uhf(self): - return False - - @property - def mol(self): - """PySCF Mole or Cell object.""" - return self.mf.mol - - @property - def nao(self): - """Number of atomic orbitals.""" - return self.mol.nao_nr() - - @property - def norb(self): - """Total number of molecular orbitals in the system.""" - return self.mf.mo_coeff.shape[-1] - - @property - def nocc(self): - """Total number of occupied molecular orbitals in the system.""" - return np.count_nonzero(self.mf.mo_occ > 0) - - @property - def nvir(self): - """Total number of virtual molecular orbitals in the system.""" - return np.count_nonzero(self.mf.mo_occ == 0) - - # --- Sizes: - - @property - def norb_active(self): - """Number of active orbitals.""" - return (self.nocc_active + self.nvir_active) - - @property - def nocc_active(self): - """Number of active occupied orbitals.""" - return self._active_occ.size - - @property - def nvir_active(self): - """Number of active virtual orbitals.""" - return self._active_vir.size - - @property - def norb_frozen(self): - """Number of frozen orbitals.""" - return (self.norb - self.norb_active) - - @property - def nocc_frozen(self): - """Number of frozen occupied orbitals.""" - return (self.nocc - self.nocc_active) - - @property - def nvir_frozen(self): - """Number of frozen virtual orbitals.""" - return (self.nvir - self.nvir_active) - - # --- Indices and slices - - def get_active_slice(self): - return np.s_[self.nocc_frozen:self.nocc_frozen+self.norb_active] - - def get_active_indices(self): - return list(range(self.nocc_frozen, self.nocc_frozen+self.norb_active)) - - def get_frozen_indices(self): - return list(range(self.nocc_frozen)) + list(range(self.norb-self.nvir_frozen, self.norb)) - - # --- Orbital coefficients - - # All: - - @property - def coeff(self): - return self.all.coeff - - @property - def c_occ(self): - return self.occupied.coeff - - @property - def c_vir(self): - return self.virtual.coeff - - # Active: - - @property - def c_active(self): - return self.active.coeff - - @property - def c_active_occ(self): - return self.active.occupied.coeff - - @property - def c_active_vir(self): - return self.active.virtual.coeff - - # Frozen: - - @property - def c_frozen(self): - return self.frozen.coeff - - @property - def c_frozen_occ(self): - return self.frozen.occupied.coeff - - @property - def c_frozen_vir(self): - return self.frozen.virtual.coeff - - # --- Electron numbers: - - @property - def nelectron(self): - """Total number of electrons in the system.""" - return 2*self.nocc - - @property - def nelectron_active(self): - """Number of active electrons in the system.""" - return 2*self.nocc_active - - @property - def nelectron_frozen(self): - """Number of frozen electrons in the system.""" - return 2*self.nocc_frozen - - # --- Combined spaces: - - @property - def active(self): - active = (self._active_occ + self._active_vir) - active.occupied = self._active_occ - active.virtual = self._active_vir - return active - - @property - def frozen(self): - frozen = (self._frozen_occ + self._frozen_vir) - frozen.occupied = self._frozen_occ - frozen.virtual = self._frozen_vir - return frozen - - @property - def occupied(self): - occupied = (self._frozen_occ + self._active_occ) - occupied.active = self._active_occ - occupied.frozen = self._frozen_occ - return occupied - - @property - def virtual(self): - virtual = (self._active_vir + self._frozen_vir) - virtual.active = self._active_occ - virtual.frozen = self._frozen_occ - return virtual - - @property - def all(self): - return (self._frozen_occ + self._active_occ + self._active_vir + self._frozen_vir) - - # --- Other: - - def add_frozen_rdm1(self, dm1_active): - if dm1_active.shape != (self.norb_active, self.norb_active): - raise ValueError() - dm1 = np.zeros((self.norb, self.norb)) - dm1[np.diag_indices(self.nocc)] = 2 - act = self.get_active_slice() - dm1[act,act] = dm1_active - return dm1 - - def get_cas_size(self): - return (self.nelectron_active, self.norb_active) - - # --- Modify - - def copy(self): - copy = ActiveSpace(self.mf, self.c_active_occ, self.c_active_vir, self.c_frozen_occ, self.c_frozen_vir) - return copy - - def transform(self, trafo): - cp = self.copy() - cp._active_occ.transform(trafo, inplace=True) - cp._active_vir.transform(trafo, inplace=True) - if cp._frozen_occ is not None: - cp._frozen_occ.transform(trafo, inplace=True) - if cp._frozen_vir is not None: - cp._frozen_vir.transform(trafo, inplace=True) - return cp - - def log_sizes(self, logger, header=None): - if header: - logger(header) - logger(len(header)*'-') - logger(" Active Frozen") - logger(" ----------------------- -----------------------") - fmt = ' %-8s' + 2*' %5d / %5d (%6.1f%%)' - get_sizes = lambda a, f, n : (a, n, 100*a/n, f, n, 100*f/n) - logger(fmt, "Occupied", *get_sizes(self.nocc_active, self.nocc_frozen, self.nocc)) - logger(fmt, "Virtual", *get_sizes(self.nvir_active, self.nvir_frozen, self.nvir)) - logger(fmt, "Total", *get_sizes(self.norb_active, self.norb_frozen, self.norb)) - - #def check(self): - # assert self.norb_active == self.active.size == self.active.coeff.shape[-1] - # assert self.nocc_active == self.active.occupied.size == self.active.occupied.coeff.shape[-1] == self.c_active_occ.shape[-1] - # assert self.nvir_active == self.active.virtual.size == self.active.virtual.coeff.shape[-1] - -class ActiveSpace_UHF(ActiveSpace_RHF): - - def __repr__(self): - return ("ActiveSpace(nocc_active= (%d, %d), nvir_active= (%d, %d), nocc_frozen= (%d, %d), nvir_frozen= (%d, %d))" % - (*self.nocc_active, *self.nvir_active, *self.nocc_frozen, *self.nvir_frozen)) - - @property - def is_rhf(self): - return False - - @property - def is_uhf(self): - return True - - @property - def norb(self): - return np.asarray((self.mf.mo_coeff[0].shape[-1], - self.mf.mo_coeff[1].shape[-1])) - - @property - def nocc(self): - return np.asarray((np.count_nonzero(self.mf.mo_occ[0] > 0), - np.count_nonzero(self.mf.mo_occ[1] > 0))) - - @property - def nvir(self): - return np.asarray((np.count_nonzero(self.mf.mo_occ[0] == 0), - np.count_nonzero(self.mf.mo_occ[1] == 0))) - - # --- Indices and slices - - def get_active_slice(self): - return (np.s_[self.nocc_frozen[0]:self.nocc_frozen[0]+self.norb_active[0]], - np.s_[self.nocc_frozen[1]:self.nocc_frozen[1]+self.norb_active[1]]) - - def get_active_indices(self): - return (list(range(self.nocc_frozen[0], self.nocc_frozen[0]+self.norb_active[0])), - list(range(self.nocc_frozen[1], self.nocc_frozen[1]+self.norb_active[1]))) - - def get_frozen_indices(self): - return (list(range(self.nocc_frozen[0])) + list(range(self.norb[0]-self.nvir_frozen[0], self.norb[0])), - list(range(self.nocc_frozen[1])) + list(range(self.norb[1]-self.nvir_frozen[1], self.norb[1]))) - - # --- Electron numbers: - - @property - def nelectron(self): - """Total number of electrons in the system.""" - return self.nocc - - @property - def nelectron_active(self): - """Number of active electrons in the system.""" - return self.nocc_active - - @property - def nelectron_frozen(self): - """Number of frozen electrons in the system.""" - return self.nocc_frozen - - # --- Other: - - def add_frozen_rdm1(self, dm1_active): - if (dm1_active[0].shape != (self.norb_active[0], self.norb_active[0]) - or dm1_active[1].shape != (self.norb_active[1], self.norb_active[1])): - raise ValueError("Invalid DM shape: %r %r. N(active)= %d %d" % ( - list(dm1_active[0].shape), list(dm1_active[1].shape), *self.norb_active)) - dm1a = np.zeros((self.norb[0], self.norb[0])) - dm1b = np.zeros((self.norb[1], self.norb[1])) - dm1a[np.diag_indices(self.nocc[0])] = 1 - dm1b[np.diag_indices(self.nocc[1])] = 1 - acta, actb = self.get_active_slice() - dm1a[acta,acta] = dm1_active[0] - dm1b[actb,actb] = dm1_active[1] - return (dm1a, dm1b) - - def log_sizes(self, logger, header=None): - if header: - logger(header) - logger(len(header)*'-') - logger(" Active Frozen") - logger(" ----------------------- -----------------------") - fmt = ' %-14s' + 2*' %5d / %5d (%6.1f%%)' - get_sizes = lambda a, f, n : (a, n, 100*a/n, f, n, 100*f/n) - logger(fmt, "Alpha occupied", *get_sizes(self.nocc_active[0], self.nocc_frozen[0], self.nocc[0])) - logger(fmt, "Beta occupied", *get_sizes(self.nocc_active[1], self.nocc_frozen[1], self.nocc[1])) - logger(fmt, "Alpha virtual", *get_sizes(self.nvir_active[0], self.nvir_frozen[0], self.nvir[0])) - logger(fmt, "Beta virtual", *get_sizes(self.nvir_active[1], self.nvir_frozen[1], self.nvir[1])) - logger(fmt, "Alpha total", *get_sizes(self.norb_active[0], self.norb_frozen[0], self.norb[0])) - logger(fmt, "Beta total", *get_sizes(self.norb_active[1], self.norb_frozen[1], self.norb[1])) diff --git a/vayesta/core/DEL/orbitals.py b/vayesta/core/DEL/orbitals.py deleted file mode 100644 index f24fb2bce..000000000 --- a/vayesta/core/DEL/orbitals.py +++ /dev/null @@ -1,125 +0,0 @@ -import numpy as np - -from vayesta.core.util import hstack - -def is_rhf(coeff): - return (coeff[0].ndim == 1) - -def stack_coeffs(*coeffs): - # RHF - if np.ndim(coeffs[0][0]) == 1: - assert np.all([c.ndim == 2 for c in coeffs]) - return hstack(*coeffs) - # UHF - assert np.all([len(c) == 2 for c in coeffs]) - assert np.all([(c[0].ndim == c[1].ndim == 2) for c in coeffs]) - return (hstack(*[c[0] for c in coeffs]), - hstack(*[c[1] for c in coeffs])) - -class BaseOrbitalSpace: - pass - -def OrbitalSpace(coeff, name): - if is_rhf(coeff): - return SpatialOrbitalSpace(coeff, name=name) - return SpinOrbitalSpace(coeff, name=name) - -class SpatialOrbitalSpace(BaseOrbitalSpace): - - def __init__(self, coeff, name=''): - self.coeff = coeff - self.name = name - - def __repr__(self): - return "SpatialOrbitals(%s)" % self.name - - @property - def size(self): - return self.coeff.shape[-1] - - def __add__(self, other): - if other is None: - # Return copy to avoid unintended side-effects - return self.copy() - coeff = hstack(self.coeff, other.coeff) - name = '+'.join(filter(None, [self.name, other.name])) - return type(self)(coeff, name=name) - - def copy(self, name=''): - return type(self)(self.coeff.copy(), name=(name or self.name)) - - def transform(self, trafo, inplace=False): - copy = self.copy() if not inplace else self - copy.coeff = trafo(copy.coeff) - return copy - -class SpinOrbitalSpace(BaseOrbitalSpace): - - def __init__(self, coeff, name=''): - self.alpha = SpatialOrbitalSpace(coeff[0], 'alpha') - self.beta = SpatialOrbitalSpace(coeff[1], 'beta') - self.name = name - - def __repr__(self): - return "SpinOrbitals(%s)" % self.name - - @property - def size(self): - return np.asarray([self.alpha.size, self.beta.size]) - - @property - def coeff(self): - return (self.alpha.coeff, self.beta.coeff) - - def __add__(self, other): - if other is None: - # Return copy to avoid unintended side-effects - return self.copy() - coeff = ((self.alpha + other.alpha).coeff, - (self.beta + other.beta).coeff) - name = ','.join(filter(None, [self.name, other.name])) - return type(self)(coeff, name=name) - - def copy(self, name=''): - return type(self)((self.alpha.coeff.copy(), self.beta.coeff.copy()), name=(name or self.name)) - - def transform(self, trafo, inplace=False): - if not hasattr(trafo, '__len__'): - trafo = (trafo, trafo) - copy = self.copy() if not inplace else self - copy.alpha.transform(trafo[0], inplace=True) - copy.beta.transform(trafo[1], inplace=True) - return copy - - -if __name__ == '__main__': - - nao = 10 - nfrag = 2 - nbath = 3 - e, v = np.linalg.eigh(np.random.rand(nao, nao)) - - def test(c_frag, c_bath): - frag = Orbitals(c_frag, "Fragment") - bath = Orbitals(c_bath, "DMET-bath") - cluster = frag + bath - - print("str(frag)= %r" % frag) - print("str(bath)= %r" % cluster) - print("str(cluster)= %r" % cluster) - try: - print("cluster.size= %r" % cluster.size) - print("cluster.coeff= %r" % cluster.coeff) - except TypeError: - print("cluster.size= %r %r" % cluster.size) - print("cluster.coeff= %r %r" % cluster.coeff) - - # RHF - c_frag = v[:,:nfrag] - c_bath = v[:,nfrag:nfrag+nbath] - test(c_frag, c_bath) - - # UHF - c_frag = (c_frag, c_frag) - c_bath = (c_bath, v[:,nfrag:nfrag+nbath+2]) - test(c_frag, c_bath) diff --git a/vayesta/core/ao2mo/DEL/dfccsd.py b/vayesta/core/ao2mo/DEL/dfccsd.py deleted file mode 100644 index 7e76b91b4..000000000 --- a/vayesta/core/ao2mo/DEL/dfccsd.py +++ /dev/null @@ -1,93 +0,0 @@ -import numpy -from pyscf import lib -from pyscf.ao2mo import _ao2mo -from pyscf.mp.mp2 import _mo_without_core -from pyscf.cc import ccsd -from pyscf.cc.dfccsd import _ChemistsERIs - -def init_eris(cc, fock, mo_energy=None): - """Initialize ERIs directly, without calling _common_init_.""" - eris = _ChemistsERIs() - mo_coeff = _mo_without_core(cc, cc.mo_coeff) - eris.mo_coeff = mo_coeff - eris.fock = fock - if mo_energy is None: mo_energy = fock.diagonal() - eris.mo_energy = mo_energy - eris.nocc = cc.get_nocc() - eris.e_hf = cc._scf.e_tot - eris.mol = cc.mol - return eris - -def make_eris(cc, fock, mo_energy=None): - """Make ERIs for use in DFCCSD, without recalculating the Fock matrix.""" - - eris = init_eris(cc, fock, mo_energy) - - # The following code is from _make_df_eris in pyscf/cc/dfccsd.py: - # =============================================================== - nocc = eris.nocc - nmo = eris.fock.shape[0] - nvir = nmo - nocc - nvir_pair = nvir*(nvir+1)//2 - with_df = cc.with_df - naux = eris.naux = with_df.get_naoaux() - - eris.feri = lib.H5TmpFile() - eris.oooo = eris.feri.create_dataset('oooo', (nocc,nocc,nocc,nocc), 'f8') - eris.ovoo = eris.feri.create_dataset('ovoo', (nocc,nvir,nocc,nocc), 'f8', chunks=(nocc,1,nocc,nocc)) - eris.ovov = eris.feri.create_dataset('ovov', (nocc,nvir,nocc,nvir), 'f8', chunks=(nocc,1,nocc,nvir)) - eris.ovvo = eris.feri.create_dataset('ovvo', (nocc,nvir,nvir,nocc), 'f8', chunks=(nocc,1,nvir,nocc)) - eris.oovv = eris.feri.create_dataset('oovv', (nocc,nocc,nvir,nvir), 'f8', chunks=(nocc,nocc,1,nvir)) - # nrow ~ 4e9/8/blockdim to ensure hdf5 chunk < 4GB - chunks = (min(nvir_pair,int(4e8/with_df.blockdim)), min(naux,with_df.blockdim)) - eris.vvL = eris.feri.create_dataset('vvL', (nvir_pair,naux), 'f8', chunks=chunks) - - Loo = numpy.empty((naux,nocc,nocc)) - Lov = numpy.empty((naux,nocc,nvir)) - mo = numpy.asarray(eris.mo_coeff, order='F') - ijslice = (0, nmo, 0, nmo) - p1 = 0 - Lpq = None - for k, eri1 in enumerate(with_df.loop()): - Lpq = _ao2mo.nr_e2(eri1, mo, ijslice, aosym='s2', mosym='s1', out=Lpq) - p0, p1 = p1, p1 + Lpq.shape[0] - Lpq = Lpq.reshape(p1-p0,nmo,nmo) - Loo[p0:p1] = Lpq[:,:nocc,:nocc] - Lov[p0:p1] = Lpq[:,:nocc,nocc:] - Lvv = lib.pack_tril(Lpq[:,nocc:,nocc:]) - eris.vvL[:,p0:p1] = Lvv.T - Lpq = Lvv = None - Loo = Loo.reshape(naux,nocc**2) - #Lvo = Lov.transpose(0,2,1).reshape(naux,nvir*nocc) - Lov = Lov.reshape(naux,nocc*nvir) - eris.oooo[:] = lib.ddot(Loo.T, Loo).reshape(nocc,nocc,nocc,nocc) - eris.ovoo[:] = lib.ddot(Lov.T, Loo).reshape(nocc,nvir,nocc,nocc) - ovov = lib.ddot(Lov.T, Lov).reshape(nocc,nvir,nocc,nvir) - eris.ovov[:] = ovov - eris.ovvo[:] = ovov.transpose(0,1,3,2) - ovov = None - - mem_now = lib.current_memory()[0] - max_memory = max(0, cc.max_memory - mem_now) - blksize = max(ccsd.BLKMIN, int((max_memory*.9e6/8-nocc**2*nvir_pair)/(nocc**2+naux))) - oovv_tril = numpy.empty((nocc*nocc,nvir_pair)) - for p0, p1 in lib.prange(0, nvir_pair, blksize): - oovv_tril[:,p0:p1] = lib.ddot(Loo.T, _cp(eris.vvL[p0:p1]).T) - eris.oovv[:] = lib.unpack_tril(oovv_tril).reshape(nocc,nocc,nvir,nvir) - oovv_tril = Loo = None - - Lov = Lov.reshape(naux,nocc,nvir) - vblk = max(nocc, int((max_memory*.15e6/8)/(nocc*nvir_pair))) - vvblk = int(min(nvir_pair, 4e8/nocc, max(4, (max_memory*.8e6/8)/(vblk*nocc+naux)))) - eris.ovvv = eris.feri.create_dataset('ovvv', (nocc,nvir,nvir_pair), 'f8', - chunks=(nocc,1,vvblk)) - for q0, q1 in lib.prange(0, nvir_pair, vvblk): - vvL = _cp(eris.vvL[q0:q1]) - for p0, p1 in lib.prange(0, nvir, vblk): - tmpLov = _cp(Lov[:,:,p0:p1]).reshape(naux,-1) - eris.ovvv[:,p0:p1,q0:q1] = lib.ddot(tmpLov.T, vvL.T).reshape(nocc,p1-p0,q1-q0) - vvL = None - return eris - -def _cp(a): - return numpy.array(a, copy=False, order='C') diff --git a/vayesta/core/ao2mo/DEL/kao2gmo.py b/vayesta/core/ao2mo/DEL/kao2gmo.py deleted file mode 100644 index 8b1ae16d4..000000000 --- a/vayesta/core/ao2mo/DEL/kao2gmo.py +++ /dev/null @@ -1,590 +0,0 @@ -"""AO to MO transformation from k-space (AOs) to supercell real space (MOs) - -Author: Max Nusspickel -Email: max.nusspickel@gmail.com -""" - -# Standard -from timeit import default_timer as timer -import ctypes -import logging -# External -import numpy as np -# PySCF -import pyscf -import pyscf.lib -import pyscf.mp -import pyscf.cc -from pyscf.mp.mp2 import _mo_without_core -import pyscf.pbc -import pyscf.pbc.tools -# Package -from vayesta.core.util import dot, einsum, memory_string, time_string -import vayesta.libs -from vayesta.core.ao2mo import helper - - -log = logging.getLogger(__name__) - -def gdf_to_pyscf_eris(mf, gdf, cm, fock, mo_energy, e_hf): - """Get supercell MO eris from k-point sampled GDF. - - This folds the MO back into k-space - and contracts with the k-space three-center integrals.. - - Parameters - ---------- - mf: pyscf.scf.hf.RHF - Supercell mean-field object. - gdf: pyscf.pbc.df.GDF - Gaussian density-fit object of primitive cell (with k-points) - cm: `pyscf.mp.mp2.MP2`, `pyscf.cc.dfccdf.RCCSD`, or `pyscf.cc.ccsd.CCSD` - Correlated method, must have `mo_coeff` set. - fock: (n(AO),n(AO)) array - Fock matrix - mo_energy: (n(MO),) array - MO energies. - - Returns - ------- - eris: _ChemistsERIs - ERIs which can be used for the respective correlated method. - """ - log.debugv("Correlated method in gdf_to_pyscf_eris= %s", type(cm)) - - only_ovov = False - store_vvl = False - # MP2 ERIs - if isinstance(cm, pyscf.mp.mp2.MP2): - sym = False - only_ovov = True - # Coupled-cluster ERIs - elif isinstance(cm, pyscf.cc.rccsd.RCCSD): - sym = False - elif isinstance(cm, pyscf.cc.dfccsd.RCCSD): - store_vvl = True - sym = True - elif isinstance(cm, pyscf.cc.ccsd.CCSD): - from pyscf.cc.ccsd import _ChemistsERIs - sym = True - else: - raise NotImplementedError("Unknown correlated method= %s" % type(cm)) - - eris = _ChemistsERIs() - mo_coeff = _mo_without_core(cm, cm.mo_coeff) - eris.mo_coeff = mo_coeff - eris.nocc = cm.nocc - eris.e_hf = e_hf - fock = fock() if callable(fock) else fock - eris.fock = dot(mo_coeff.T, fock, mo_coeff) - eris.mo_energy = mo_energy - - # Remove EXXDIV correction from Fock matrix (necessary for CCSD) - #if mf.exxdiv and isinstance(cm, pyscf.cc.ccsd.CCSD): - # madelung = pyscf.pbc.tools.madelung(mf.mol, mf.kpt) - # for i in range(eris.nocc): - # eris.fock[i,i] += madelung - - # TEST: compare real_j3c = True and False - #g_r = gdf_to_eris(gdf, mo_coeff, cm.nocc, only_ovov=only_ovov, real_j3c=True) - #g_i = gdf_to_eris(gdf, mo_coeff, cm.nocc, only_ovov=only_ovov, real_j3c=False) - #for key, val in g_r.items(): - # norm = np.linalg.norm(val - g_i[key]) - # mx = abs(val - g_i[key]).max() - # log.debug("Difference in (%2s|%2s): max= %.3e norm= %.3e", key[:2], key[2:], mx, norm) - - g = gdf_to_eris(gdf, mo_coeff, cm.nocc, only_ovov=only_ovov, symmetry=sym, store_vvl=store_vvl) - for key, val in g.items(): - setattr(eris, key, val) - - return eris - - -def gdf_to_eris(gdf, mo_coeff, nocc, only_ovov=False, real_j3c=True, symmetry=False, store_vvl=False, j3c_threshold=None): - """Make supercell ERIs from k-point sampled, density-fitted three-center integrals. - - Parameters - ---------- - gdf : pyscf.pbc.df.GDF - Density fitting object of primitive cell, with k-points. - mo_coeff : (nK*nAO, nMO) array - MO coefficients in supercell. The AOs in the supercell must be ordered - in the same way as the k-points in the primitive cell! - nocc : int - Number of occupied orbitals. - only_ovov : bool, optional - Only calculate (occ,vir|occ,vir)-type ERIs (for MP2). Default=False. - real_j3c : bool, optional - Fourier transform the auxiliary basis to the real-space domain, such that the - resulting Gamma-point three center integrals become real. Default: True. - symmetry : bool, optional - If True, the 'vvvv' and 'ovvv' four-center integrals will be stored in their compact form, - otherwise the full array will be stored. Set to True for ccsd.CCSD and False for rccsd.RCCSD. - Default: False. - store_vvl : bool, optional - If True, do not perform contraction (vv|L)(L|vv)->(vv|vv) and instead store three-center - elements (vv|L). This is needed for the pyscf.cc.dfccsd.RCCSD class. Default: False. - - Returns - ------- - eris : dict - Dict of supercell ERIs. Has elements 'ovov' `if only_ovov == True` - and 'oooo', 'ovoo', 'oovv', 'ovov', 'ovvo', 'ovvv', and 'vvvv' otherwise. - """ - # DF compatiblity layer - ints3c = ThreeCenterInts.init_from_gdf(gdf) - - cell, kpts, nk, nao, naux = ints3c.cell, ints3c.kpts, ints3c.nk, ints3c.nao, ints3c.naux - - phase = pyscf.pbc.tools.k2gamma.get_phase(cell, kpts)[1] - nmo = mo_coeff.shape[-1] - nvir = nmo - nocc - o, v = np.s_[:nocc], np.s_[nocc:] - - if only_ovov: - mem_j3c = nk*naux*nocc*nvir * 16 - mem_eris = nocc**2*nvir**2 * 8 - else: - mem_j3c = nk*naux*(nocc*nvir + nocc*nocc + nvir*nvir) * 16 - if symmetry: - nvir_pair = nvir*(nvir+1)//2 - mem_eris = (nocc**4 + nocc**3*nvir + 3*nocc**2*nvir**2 + nocc*nvir*nvir_pair + nvir_pair**2) * 8 - else: - mem_eris = (nocc**4 + nocc**3*nvir + 3*nocc**2*nvir**2 + nocc*nvir**3 + nvir**4) * 8 - log.debug("Memory needed for kAO->GMO: (L|ab)= %s (ij|kl)= %s", memory_string(mem_j3c), memory_string(mem_eris)) - log.debug("Symmetry (L|ij)=(L|ji): %r", symmetry) - - # Transform: (l|ka,qb) -> (Rl|i,j) - mo_coeff = mo_coeff.reshape(nk, nao, nmo) - ck_o = einsum("Rk,Rai->kai", phase.conj(), mo_coeff[:,:,o]) / np.power(nk, 0.25) - ck_v = einsum("Rk,Rai->kai", phase.conj(), mo_coeff[:,:,v]) / np.power(nk, 0.25) - t0 = timer() - j3c = j3c_kao2gmo(ints3c, ck_o, ck_v, only_ov=only_ovov, make_real=real_j3c) - t_trafo = (timer()-t0) - - # Composite auxiliary index: R,l -> L - j3c["ov"] = j3c["ov"].reshape(nk*naux, nocc, nvir) - if not only_ovov: - j3c["oo"] = j3c["oo"].reshape(nk*naux, nocc, nocc) - j3c["vv"] = j3c["vv"].reshape(nk*naux, nvir, nvir) - - # Check symmetry errors - if False: - err_oo = np.linalg.norm(j3c['oo'] - j3c['oo'].transpose(0, 2, 1).conj()) - err_vv = np.linalg.norm(j3c['vv'] - j3c['vv'].transpose(0, 2, 1).conj()) - log.debug("Symmetry error of (L|ij) vs (L|ji)= %.2e", err_oo) - log.debug("Symmetry error of (L|ab) vs (L|ba)= %.2e", err_vv) - # Symmetrize - j3c['oo'] = 0.5*(j3c['oo'] + j3c['oo'].transpose(0,2,1).conj()) - j3c['vv'] = 0.5*(j3c['vv'] + j3c['vv'].transpose(0,2,1).conj()) - - err_oo = np.linalg.norm(j3c['oo'] - j3c['oo'].transpose(0, 2, 1).conj()) - err_vv = np.linalg.norm(j3c['vv'] - j3c['vv'].transpose(0, 2, 1).conj()) - log.debug("Symmetry error of (L|ij) vs (L|ji)= %.2e", err_oo) - log.debug("Symmetry error of (L|ab) vs (L|ba)= %.2e", err_vv) - - for key, val in j3c.items(): - log.debugv("Memory for (L|%s)= %s", key, memory_string(val.nbytes)) - - # Prune? - norm_ov = np.linalg.norm(j3c['ov'], axis=(1,2)) - log.debugv("Number of ov elements= %d - number of parts below 1E-14= %d 1E-12= %d 1E-10= %d 1E-8= %d", - len(norm_ov), np.count_nonzero(norm_ov < 1e-14), np.count_nonzero(norm_ov < 1e-12), - np.count_nonzero(norm_ov < 1e-10), np.count_nonzero(norm_ov < 1e-8)) - if not only_ovov: - norm_oo = np.linalg.norm(j3c['oo'], axis=(1,2)) - log.debugv("Number of oo elements= %d - number of parts below 1E-14= %d 1E-12= %d 1E-10= %d 1E-8= %d", - len(norm_oo), np.count_nonzero(norm_oo < 1e-14), np.count_nonzero(norm_oo < 1e-12), - np.count_nonzero(norm_oo < 1e-10), np.count_nonzero(norm_oo < 1e-8)) - norm_vv = np.linalg.norm(j3c['vv'], axis=(1,2)) - log.debugv("Number of vv elements= %d - number of parts below 1E-14= %d 1E-12= %d 1E-10= %d 1E-8= %d", - len(norm_vv), np.count_nonzero(norm_vv < 1e-14), np.count_nonzero(norm_vv < 1e-12), - np.count_nonzero(norm_vv < 1e-10), np.count_nonzero(norm_vv < 1e-8)) - - def prune_aux_basis(key): - norm = np.linalg.norm(j3c[key], axis=(1,2)) - assert (len(norm) == nk*naux) - keep = (norm > j3c_threshold) - log.debug("(L|%s): Keeping %3d out of %3d auxiliary basis funcions (threshold= %.1e)", key, np.count_nonzero(keep), len(norm), j3c_threshold) - j3c[key] = j3c[key][keep] - - if j3c_threshold: - prune_aux_basis('ov') - if not only_ovov: - prune_aux_basis('oo') - prune_aux_basis('vv') - - # Contract (L|ij)(L|kl)->(ij|kl) - eris = {} - t0 = timer() - if not only_ovov: - # (L|vv) dependend - # These symmetries are used in ccsd.CCSD but not rccsd.RCCSD! - if symmetry: - if not store_vvl: - eris["vvvv"] = contract_j3c(j3c, "vvvv", symmetry=4) - else: - eris['vvL'] = pyscf.lib.pack_tril(j3c['vv']).T - eris["ovvv"] = contract_j3c(j3c, "ovvv", symmetry=2) - else: - if not store_vvl: - eris["vvvv"] = contract_j3c(j3c, "vvvv") - else: - # Bugged? - eris['vvL'] = j3c['vv'] - eris["ovvv"] = contract_j3c(j3c, "ovvv") - - eris["oovv"] = contract_j3c(j3c, "oovv") - del j3c["vv"] - # (L|ov) dependend - eris["ovov"] = contract_j3c(j3c, "ovov") - if not only_ovov: - eris["ovvo"] = contract_j3c(j3c, "ovvo") - eris["ovoo"] = contract_j3c(j3c, "ovoo") - del j3c["ov"] - # (L|oo) dependend - eris["oooo"] = contract_j3c(j3c, "oooo") - del j3c["oo"] - t_contract = (timer()-t0) - - # Check that final 4c-integrals are real - if np.iscomplexobj(eris["ovov"]): - for key in list(eris.keys()): - val = eris[key] - inorm = np.linalg.norm(val.imag) - imax = abs(val.imag).max() - if max(inorm, imax) > 1e-5: - log.warning("Norm of Im(%2s|%2s): L(2)= %.2e L(inf)= %.2e", key[:2], key[2:], inorm, imax) - else: - log.debugv("Norm of Im(%2s|%2s): L(2)= %.2e L(inf)= %.2e", key[:2], key[2:], inorm, imax) - eris[key] = val.real - - for key, val in eris.items(): - log.debugv("Memory for (%s|%s)= %s", key[:2], key[2:], memory_string(val.nbytes)) - - log.timing("Timings for kAO->GMO: transform= %s contract= %s", time_string(t_trafo), time_string(t_contract)) - - return eris - - -def contract_j3c(j3c, kind, symmetry=None): - """Contract (L|ij)(L|kl) -> (ij|kl)""" - t0 = timer() - left, right = kind[:2], kind[2:] - # We do not store "vo" only "ov": - right_t = 'ov' if right == 'vo' else right - l, r = j3c[left], j3c[right_t] - if right == 'vo': - r = r.transpose(0, 2, 1) - # Four-fold permutation symmetry - if symmetry == 4: - l = pyscf.lib.pack_tril(l) # Lij->LI - r = pyscf.lib.pack_tril(r) # Lkl->LK - c = np.dot(l.T.conj(), r) # LI,LK->IK - # Permutation symmetry only on right side - elif symmetry == 2: - r = pyscf.lib.pack_tril(r) - c = einsum('Lij,LK->ijK', l.conj(), r) - # No permutation symmetry - else: - c = np.tensordot(l.conj(), r, axes=(0, 0)) - log.timingv("Time to contract (%2s|%2s): %s", left, right, time_string(timer()-t0)) - del l, r - - # For 2D systems we have negative parts, otherwise we can return here - if not (left + '-' in j3c): - return c - - t0 = timer() - l, r = j3c[left + "-"], j3c[right_t + "-"] - if right == 'vo': - r = r.T - - # We loop over blocks here, to avoid allocating another 4c-sized array - # Allow ~1GB working memory - mem = 1e9 - if symmetry == 4: - l = pyscf.lib.pack_tril(l) - r = pyscf.lib.pack_tril(r) - size = l.shape[0] - blksize = max(1, min(int(mem/(size*8*(1+np.iscomplexobj(l)))), size)) - log.debugv("blksize= %d out of %d (%d blocks)", blksize, size, int(np.ceil(size/blksize))) - for p0, p1 in pyscf.lib.prange(0, size, blksize): - blk = np.s_[p0:p1] - c[blk] -= np.outer(l[blk].conj(), r) - elif symmetry == 2: - r = pyscf.lib.pack_tril(r) - size = l.shape[0] - blksize = max(1, min(int(mem/(size*8*(1+np.iscomplexobj(l)))), size)) - log.debugv("blksize= %d out of %d (%d blocks)", blksize, size, int(np.ceil(size/blksize))) - for p0, p1 in pyscf.lib.prange(0, size, blksize): - blk = np.s_[p0:p1] - c[blk] -= einsum('ij,k->ijk', l[blk].conj(), r) - else: - size = l.shape[0] - blksize = max(1, min(int(mem/(size*8*(1+np.iscomplexobj(l)))), size)) - log.debugv("blksize= %d out of %d (%d blocks)", blksize, size, int(np.ceil(size/blksize))) - for p0, p1 in pyscf.lib.prange(0, size, blksize): - blk = np.s_[p0:p1] - c[blk] -= einsum("ij,kl->ijkl", l[blk].conj(), r) - - log.timingv("Time to contract (%2s|%2s)(-): %s", left, right, time_string(timer()-t0)) - return c - - -class ThreeCenterInts: - """Temporary interface class for DF classes. - - This should be implemented better at some point, as a larger effort to unify integral classes - and offer a common interface. - """ - - def __init__(self, cell, kpts, naux): - self.cell = cell - self.kpts = kpts - self.naux = naux - self.values = None - self.df = None - - @property - def nk(self): - return len(self.kpts) - - @property - def nao(self): - return self.cell.nao_nr() - - @classmethod - def init_from_gdf(cls, gdf): - if gdf.auxcell is None: - gdf.build(with_j3c=False) - ints3c = cls(gdf.cell, gdf.kpts, gdf.auxcell.nao_nr()) - ints3c.df = gdf - return ints3c - - def sr_loop(self, *args, **kwargs): - return self.df.sr_loop(*args, **kwargs) - - def get_array(self, kptsym=True): - - if self.values is not None: - return self.values, None, None - - elif isinstance(self.df._cderi, (str, type(None))): - if kptsym: - nkij = self.nk*(self.nk+1)//2 - j3c = np.zeros((nkij, self.naux, self.nao, self.nao), dtype=complex) - kuniq_map = np.zeros((self.nk, self.nk), dtype=int) - else: - j3c = np.zeros((self.nk, self.nk, self.naux, self.nao, self.nao), dtype=complex) - kuniq_map = None - - if self.cell.dimension < 3: - j3c_neg = np.zeros((self.nk, self.nao, self.nao), dtype=complex) - else: - j3c_neg = None - - kij = 0 - for ki in range(self.nk): - kjmax = (ki+1) if kptsym else self.nk - for kj in range(kjmax): - if kptsym: - kuniq_map[ki,kj] = kij - kpts_ij = (self.kpts[ki], self.kpts[kj]) - if kptsym: - j3c_kij = j3c[kij] - else: - j3c_kij = j3c[ki,kj] - blk0 = 0 - for lr, li, sign in self.df.sr_loop(kpts_ij, compact=False, blksize=int(1e9)): - blksize = lr.shape[0] - blk = np.s_[blk0:blk0+blksize] - blk0 += blksize - if (sign == 1): - j3c_kij[blk] = (lr+1j*li).reshape(blksize, self.nao, self.nao) - # For 2D systems: - else: - assert (sign == -1) and (blksize == 1) and (ki == kj), ("sign= %r, blksize= %r, ki= %r, kj=%r" % (sign, blksize, ki, kj)) - j3c_neg[ki] += (lr+1j*li)[0].reshape(self.nao, self.nao) - kij += 1 - - if kptsym: - # At this point, all kj <= ki are set - # Here we loop over kj > ki - for ki in range(self.nk): - for kj in range(ki+1, self.nk): - kuniq_map[ki,kj] = -kuniq_map[kj,ki] - assert np.all(kuniq_map < nkij) - assert np.all(kuniq_map > -nkij) - - # Old, deprecated code - keeping for now in case I reimplement ki/kj symmetry - # In IncoreGDF, we can access the array directly - #elif hasattr(self.df._cderi, '__getitem__') and 'j3c' in self.df._cderi: - # j3c = self.df._cderi["j3c"].reshape(-1, self.naux, self.nao, self.nao) - # nkuniq = j3c.shape[0] - # log.info("Nkuniq= %3d", nkuniq) - # # Check map - # #_get_kpt_hash = pyscf.pbc.df.df_incore._get_kpt_hash - # _get_kpt_hash = vayesta.misc.gdf._get_kpt_hash - # kuniq_map = np.zeros((self.nk, self.nk), dtype=int) - # # 2D systems not supported in incore version: - # j3c_neg = None - # for ki in range(self.nk): - # for kj in range(self.nk): - # kij = np.asarray((self.kpts[ki], self.kpts[kj])) - # kij_id = self.df._cderi['j3c-kptij-hash'].get(_get_kpt_hash(kij), [None]) - # assert len(kij_id) == 1 - # kij_id = kij_id[0] - # if kij_id is None: - # kij_id = self.df._cderi['j3c-kptij-hash'][_get_kpt_hash(kij[[1,0]])] - # assert len(kij_id) == 1 - # # negative to indicate transpose needed - # kij_id = -kij_id[0] - # assert (abs(kij_id) < nkuniq) - # kuniq_map[ki,kj] = kij_id - - elif isinstance(self.df._cderi, np.ndarray): - j3c = self.df._cderi - j3c_neg = None - kuniq_map = None - - else: - raise ValueError("Unknown DF type: %r" % type(self.df)) - - return j3c, j3c_neg, kuniq_map - - -def j3c_kao2gmo(ints3c, cocc, cvir, only_ov=False, make_real=True, driver='c'): - """Transform three-center integrals from k-space AO to supercell MO basis. - - Returns - ------- - j3c_ov : (Nk, Naux, Nocc, Nvir) array - Supercell occupied-virtual three-center integrals. - j3c_oo : (Nk, Naux, Nocc, Nocc) array or None - Supercell occupied-occupied three-center integrals. - j3c_vv : (Nk, Naux, Nvir, Nvir) array or None - Supercell virtual-virtual three-center integrals. - j3cn_ov : (Nocc, Nvir) array - Negative supercell occupied-virtual three-center integrals. - j3cn_oo : (Nocc, Nocc) array or None - Negative supercell occupied-occupied three-center integrals. - j3cn_vv : (Nvir, Nvir) array or None - Negative supercell virtual-virtual three-center integrals. - """ - nocc = cocc.shape[-1] - nvir = cvir.shape[-1] - cell, kpts, nk, naux = ints3c.cell, ints3c.kpts, ints3c.nk, ints3c.naux - nao = cell.nao_nr() - kconserv = helper.get_kconserv(cell, kpts, nk=2) - - j3c = {} - j3c["ov"] = np.zeros((nk, naux, nocc, nvir), dtype=complex) - #j3c_oo = j3c_vv = j3cn_ov = j3cn_oo = j3cn_vv = None - if not only_ov: - j3c["oo"] = np.zeros((nk, naux, nocc, nocc), dtype=complex) - j3c["vv"] = np.zeros((nk, naux, nvir, nvir), dtype=complex) - - if driver.lower() == 'python': # pragma: no cover - - if cell.dimension < 3: - j3c["ov-"] = np.zeros((nocc, nvir), dtype=complex) - if not only_ov: - j3c["oo-"] = np.zeros((nocc, nocc), dtype=complex) - j3c["vv-"] = np.zeros((nvir, nvir), dtype=complex) - - for ki in range(nk): - for kj in range(nk): - kij = (kpts[ki], kpts[kj]) - kk = kconserv[ki,kj] - blk0 = 0 - for lr, li, sign in ints3c.sr_loop(kij, compact=False): - blksize = lr.shape[0] - blk = np.s_[blk0:blk0+blksize] - blk0 += blksize - j3c_kij = (lr+1j*li).reshape(blksize, nao, nao) - if sign == 1: - j3c["ov"][kk,blk] += einsum("Lab,ai,bj->Lij", j3c_kij, cocc[ki].conj(), cvir[kj]) # O(Nk^2 * Nocc * Nvir) - if only_ov: continue - j3c["oo"][kk,blk] += einsum("Lab,ai,bj->Lij", j3c_kij, cocc[ki].conj(), cocc[kj]) # O(Nk^2 * Nocc * Nocc) - j3c["vv"][kk,blk] += einsum("Lab,ai,bj->Lij", j3c_kij, cvir[ki].conj(), cvir[kj]) # O(Nk^2 * Nvir * Nvir) - # For 2D systems - else: - assert (sign == -1) and (ki == kj) and (kk == 0) and (blksize == 1) - j3c["ov-"] += einsum("ab,ai,bj->ij", j3c_kij[0], cocc[ki].conj(), cvir[kj]) - if only_ov: continue - j3c["oo-"] += einsum("ab,ai,bj->ij", j3c_kij[0], cocc[ki].conj(), cocc[kj]) - j3c["vv-"] += einsum("ab,ai,bj->ij", j3c_kij[0], cvir[ki].conj(), cvir[kj]) - - elif driver.lower() == 'c': - # Load j3c into memory - t0 = timer() - j3c_kpts, j3c_neg, kunique = ints3c.get_array() - log.timingv("Time to load k-point sampled 3c-integrals: %s", time_string(timer()-t0)) - - cocc = cocc.copy() - cvir = cvir.copy() - libcore = vayesta.libs.load_library('core') - t0 = timer() - ierr = libcore.j3c_kao2gmo( - ctypes.c_int64(nk), - ctypes.c_int64(nao), - ctypes.c_int64(nocc), - ctypes.c_int64(nvir), - ctypes.c_int64(naux), - kconserv.ctypes.data_as(ctypes.c_void_p), - #kunique_pt, - kunique.ctypes.data_as(ctypes.c_void_p) if kunique is not None else ctypes.POINTER(ctypes.c_void_p)(), - cocc.ctypes.data_as(ctypes.c_void_p), - cvir.ctypes.data_as(ctypes.c_void_p), - j3c_kpts.ctypes.data_as(ctypes.c_void_p), - # In-out - j3c["ov"].ctypes.data_as(ctypes.c_void_p), - j3c["oo"].ctypes.data_as(ctypes.c_void_p) if "oo" in j3c else ctypes.POINTER(ctypes.c_void_p)(), - j3c["vv"].ctypes.data_as(ctypes.c_void_p) if "vv" in j3c else ctypes.POINTER(ctypes.c_void_p)()) - log.timingv("Time in j3c_kao2gamo in C: %s", time_string(timer()-t0)) - assert (ierr == 0) - - # Do the negative part for 2D systems in python (only one auxiliary function and ki==kj) - if j3c_neg is not None: - j3c["ov-"] = einsum("kab,kai,kbj->ij", j3c_neg, cocc.conj(), cvir) # O(Nk * Nocc * Nvir) - if not only_ov: - j3c["oo-"] = einsum("kab,kai,kbj->ij", j3c_neg, cocc.conj(), cocc) # O(Nk * Nocc * Nocc) - j3c["vv-"] = einsum("kab,kai,kbj->ij", j3c_neg, cvir.conj(), cvir) # O(Nk * Nvir * Nvir) - - if make_real: - t0 = timer() - phase = pyscf.pbc.tools.k2gamma.get_phase(cell, kpts)[1] - - def ft_auxiliary_basis(j, key): - pj = np.tensordot(phase, j, axes=1) - if pj.size > 0: - inorm = np.linalg.norm(pj.imag) - imax = abs(pj.imag).max() - if max(inorm, imax) > 1e-5: - log.warning("Norm of Im(L|%2s): L(2)= %.2e L(inf)= %.2e", key, inorm, imax) - else: - log.debug("Norm of Im(L|%2s): L(2)= %.2e L(inf)= %.2e", key, inorm, imax) - return pj.real - - def check_real(j, key): - pj = j - if pj.size > 0: - inorm = np.linalg.norm(pj.imag) - imax = abs(pj.imag).max() - if max(inorm, imax) > 1e-5: - log.warning("Norm of Im(L|%2s)(-): L(2)= %.2e L(inf)= %.2e", key[:2], inorm, imax) - else: - log.debug("Norm of Im(L|%2s)(-): L(2)= %.2e L(inf)= %.2e", key[:2], inorm, imax) - return pj.real - - for key in list(j3c.keys()): - if key[-1] == "-": - # Should already be real - j3c[key] = check_real(j3c[key], key) - else: - j3c[key] = ft_auxiliary_basis(j3c[key], key) - - log.timingv("Time to rotate to real: %s", time_string(timer()-t0)) - - return j3c diff --git a/vayesta/core/bath/bno.py b/vayesta/core/bath/bno.py index a3be547e3..7175bb2ad 100644 --- a/vayesta/core/bath/bno.py +++ b/vayesta/core/bath/bno.py @@ -289,10 +289,12 @@ def __init__(self, *args, project_dmet_order=0, project_dmet_mode='full', projec if project_dmet: project_dmet_order = 1 project_dmet_mode = project_dmet - # TODO: deprecate self.project_dmet_order = project_dmet_order self.project_dmet_mode = project_dmet_mode super().__init__(*args, **kwargs) + if project_dmet: + # Log isn't set at the top of the function + self.log.warning("project_dmet is deprecated; use project_dmet_order and project_dmet_mode.") def _make_t2(self, actspace, fock, eris=None, max_memory=None, blksize=None, energy_only=False): """Make T2 amplitudes and pair correlation energies.""" diff --git a/vayesta/core/foldscf.py b/vayesta/core/foldscf.py index a871f88dc..4f1acbaac 100644 --- a/vayesta/core/foldscf.py +++ b/vayesta/core/foldscf.py @@ -48,7 +48,7 @@ class FoldedSCF: # Propagate the following attributes to the k-point mean-field: _from_kmf = ['converged', 'exxdiv', 'verbose', 'max_memory', 'conv_tol', 'conv_tol_grad', - 'stdout'] + 'stdout', '_eri'] def __init__(self, kmf, kpt=np.zeros(3), **kwargs): # Create a copy, so that the original mean-field object does not get modified @@ -134,32 +134,6 @@ def __init__(self, kmf, *args, **kwargs): self.mo_energy, self.mo_coeff, self.mo_occ = fold_mos(self.kmf.mo_energy, self.kmf.mo_coeff, self.kmf.mo_occ, self.kphase, ovlp) - # Test MO folding - #nk = self.ncells - #hk = [dot(kmf.mo_coeff[k].T, kmf.get_ovlp()[k], kmf.mo_coeff[k]) for k in range(nk)] - - #c = self.mo_coeff - #smf = pyscf.pbc.scf.hf.RHF(self.mol) - #h = dot(c.T.conj(), smf.get_ovlp(), c) - - #nao = self.kcell.nao - #h2 = np.zeros_like(h) - #for k in range(nk): - # s = np.s_[k*nao:(k+1)*nao] - # h2[s,s] = hk[k] - - #for k in range(nk): - # for k2 in range(nk): - # s1 = np.s_[k*nao:(k+1)*nao] - # s2 = np.s_[k2*nao:(k2+1)*nao] - # print(k, k2, np.linalg.norm(h[s1,s2]-h2[s1,s2])) - # if (k == k2): - # print(h[s1,s2][0,:]) - # print(h2[s1,s2][0,:]) - - ##print((h - h2)[1,:]) - #1/0 - assert np.all(self.mo_coeff.imag == 0) class FoldedUHF(FoldedSCF, pyscf.pbc.scf.uhf.UHF): @@ -175,8 +149,6 @@ def __init__(self, kmf, *args, **kwargs): assert np.all(self.mo_coeff[0].imag == 0) assert np.all(self.mo_coeff[1].imag == 0) -#def fold_mos(kmf, kmo_energy, kmo_coeff, kmo_occ, kphase, ovlp, make_real=True): -#def fold_mos(kmo_energy, kmo_coeff, kmo_occ, kphase, ovlp, make_real=False, sort=False): def fold_mos(kmo_energy, kmo_coeff, kmo_occ, kphase, ovlp, make_real=True, sort=True): # --- MO energy and occupations mo_energy = np.hstack(kmo_energy) @@ -197,7 +169,6 @@ def fold_mos(kmo_energy, kmo_coeff, kmo_occ, kphase, ovlp, make_real=True, sort= # --- Make MOs real if make_real: mo_energy, mo_coeff = make_mo_coeff_real(mo_energy, mo_coeff, ovlp) - #mo_energy, mo_coeff = make_mo_coeff_real_2(mo_energy, mo_coeff, mo_occ, ovlp, hcore) # Check orthonormality of folded MOs err = abs(dot(mo_coeff.T.conj(), ovlp, mo_coeff) - np.eye(mo_coeff.shape[-1])).max() if err > 1e-4: @@ -232,9 +203,7 @@ def make_mo_coeff_real(mo_energy, mo_coeff, ovlp, imag_tol=1e-10): log.debugv("Orthonormality error before make_mo_coeff_real: %.2e", ortherr) # Testing - sc = np.dot(ovlp, mo_coeff) im = (np.linalg.norm(mo_coeff.imag, axis=0) > imag_tol) - #im = (np.linalg.norm(mo_coeff.imag, axis=0) > -1.0) log.debugv("%d complex MOs found. L(2)= %.2e", np.count_nonzero(im), np.linalg.norm(mo_coeff.imag)) if not np.any(im): return mo_energy, mo_coeff.real @@ -357,207 +326,9 @@ def bvk2k_2d(ag, phase): ak = einsum('kR,...RiSj,kS->...kij', phase.conj(), ag, phase) return ak - -#def rotate_mo_to_real(cell, mo_energy, mo_coeff, degen_tol=1e-3, rotate_degen=True): -# """Applies a phase factor to each MO, minimizing the maximum imaginary element. -# -# Typically, this should reduce the imaginary part of a non-degenerate, Gamma point orbital to zero. -# However, for degenerate subspaces, addition treatment is required. -# """ -# -# # Output orbitals -# mo_coeff_out = mo_coeff.copy() -# -# for mo_idx, mo_e in enumerate(mo_energy): -# # Check if MO is degnerate -# if mo_idx == 0: -# degen = (abs(mo_e - mo_energy[mo_idx+1]) < degen_tol) -# elif mo_idx == (len(mo_energy)-1): -# degen = (abs(mo_e - mo_energy[mo_idx-1]) < degen_tol) -# else: -# degen = (abs(mo_e - mo_energy[mo_idx-1]) < degen_tol) or (abs(mo_e - mo_energy[mo_idx+1]) < degen_tol) -# if degen and not rotate_degen: -# continue -# -# mo_c = mo_coeff[:,mo_idx] -# norm_in = np.linalg.norm(mo_c.imag) -# # Find phase which makes the largest element of |C| real -# maxidx = np.argmax(abs(mo_c.imag)) -# maxval = mo_c[maxidx] -# # Determine -phase of maxval and rotate to real axis -# phase = -np.angle(maxval) -# mo_c2 = mo_c*np.exp(1j*phase) -# -# # Only perform rotation if imaginary norm is decreased -# norm_out = np.linalg.norm(mo_c2.imag) -# if (norm_out < norm_in): -# mo_coeff_out[:,mo_idx] = mo_c2 -# else: -# norm_out = norm_in -# if norm_out > 1e-8 and not degen: -# logger.warn(cell, "Non-degenerate MO %4d at E= %+12.8f Ha: ||Im(C)||= %6.2e !", mo_idx, mo_e, norm_out) -# -# return mo_coeff_out -# -#def mo_k2gamma(cell, mo_energy, mo_coeff, kpts, kmesh=None, degen_tol=1e-3, imag_tol=1e-9): -# logger.debug(cell, "Starting mo_k2gamma") -# scell, phase = get_phase(cell, kpts, kmesh) -# -# # Supercell Gamma-point MO energies -# e_gamma = np.hstack(mo_energy) -# # The number of MOs may be k-point dependent (eg. due to linear dependency) -# nmo_k = np.asarray([ck.shape[-1] for ck in mo_coeff]) -# nk = len(mo_coeff) -# nao = mo_coeff[0].shape[0] -# nr = phase.shape[0] -# # Transform mo_coeff from k-points to supercell Gamma-point: -# c_gamma = [] -# for k in range(nk): -# c_k = np.einsum('R,um->Rum', phase[:,k], mo_coeff[k]) -# c_k = c_k.reshape(nr*nao, nmo_k[k]) -# c_gamma.append(c_k) -# c_gamma = np.hstack(c_gamma) -# assert c_gamma.shape == (nr*nao, sum(nmo_k)) -# # Sort according to MO energy -# sort = np.argsort(e_gamma) -# e_gamma, c_gamma = e_gamma[sort], c_gamma[:,sort] -# # Determine overlap by unfolding for better accuracy -# s_k = cell.pbc_intor('int1e_ovlp', hermi=1, kpts=kpts, pbcopt=lib.c_null_ptr()) -# s_gamma = to_supercell_ao_integrals(cell, kpts, s_k) -# # Orthogonality error of unfolded MOs -# err_orth = abs(np.linalg.multi_dot((c_gamma.conj().T, s_gamma, c_gamma)) - np.eye(c_gamma.shape[-1])).max() -# if err_orth > 1e-4: -# logger.error(cell, "Orthogonality error of MOs= %.2e !!!", err_orth) -# else: -# logger.debug(cell, "Orthogonality error of MOs= %.2e", err_orth) -# -# # Make Gamma point MOs real: -# -# # Try to remove imaginary parts by multiplication of simple phase factors -# c_gamma = rotate_mo_to_real(cell, e_gamma, c_gamma, degen_tol=degen_tol) -# -# # For degenerated MOs, the transformed orbitals in super cell may not be -# # real. Construct a sub Fock matrix in super-cell to find a proper -# # transformation that makes the transformed MOs real. -# #e_k_degen = abs(e_gamma[1:] - e_gamma[:-1]) < degen_tol -# #degen_mask = np.append(False, e_k_degen) | np.append(e_k_degen, False) -# -# # Get eigenvalue solver with linear-dependency treatment -# eigh = cell.eigh_factory(lindep_threshold=1e-13, fallback_mode=True) -# -# c_gamma_out = c_gamma.copy() -# mo_mask = (np.linalg.norm(c_gamma.imag, axis=0) > imag_tol) -# logger.debug(cell, "Number of MOs with imaginary coefficients: %d out of %d", np.count_nonzero(mo_mask), len(mo_mask)) -# if np.any(mo_mask): -# #mo_mask = np.s_[:] -# #if np.any(~degen_mask): -# # err_imag = abs(c_gamma[:,~degen_mask].imag).max() -# # logger.debug(cell, "Imaginary part in non-degenerate MO coefficients= %.2e", err_imag) -# # # Diagonalize Fock matrix spanned by degenerate MOs only -# # if err_imag < 1e-8: -# # mo_mask = degen_mask -# -# # F -# #mo_mask = (np.linalg.norm(c_gamma.imag, axis=0) > imag_tol) -# -# # Shift all MOs above the eig=0 subspace, so they can be extracted below -# shift = 1.0 - min(e_gamma[mo_mask]) -# cs = np.dot(c_gamma[:,mo_mask].conj().T, s_gamma) -# f_gamma = np.dot(cs.T.conj() * (e_gamma[mo_mask] + shift), cs) -# logger.debug(cell, "Imaginary parts of Fock matrix: ||Im(F)||= %.2e max|Im(F)|= %.2e", np.linalg.norm(f_gamma.imag), abs(f_gamma.imag).max()) -# -# e, v = eigh(f_gamma.real, s_gamma) -# -# # Extract MOs from rank-deficient Fock matrix -# mask = (e > 0.5) -# assert np.count_nonzero(mask) == len(e_gamma[mo_mask]) -# e, v = e[mask], v[:,mask] -# e_delta = e_gamma[mo_mask] - (e-shift) -# if abs(e_delta).max() > 1e-4: -# logger.error(cell, "Error of MO energies: ||dE||= %.2e max|dE|= %.2e !!!", np.linalg.norm(e_delta), abs(e_delta).max()) -# else: -# logger.debug(cell, "Error of MO energies: ||dE||= %.2e max|dE|= %.2e", np.linalg.norm(e_delta), abs(e_delta).max()) -# c_gamma_out[:,mo_mask] = v -# -# err_imag = abs(c_gamma_out.imag).max() -# if err_imag > 1e-4: -# logger.error(cell, "Imaginary part in gamma-point MOs: max|Im(C)|= %7.2e !!!", err_imag) -# else: -# logger.debug(cell, "Imaginary part in gamma-point MOs: max|Im(C)|= %7.2e", err_imag) -# c_gamma_out = c_gamma_out.real -# -# # Determine mo_phase, i.e. the unitary transformation from k-adapted orbitals to gamma-point orbitals -# s_k_g = np.einsum('kuv,Rk->kuRv', s_k, phase.conj()).reshape(nk,nao,nr*nao) -# mo_phase = [] -# for k in range(nk): -# mo_phase_k = lib.einsum('um,uv,vi->mi', mo_coeff[k].conj(), s_k_g[k], c_gamma_out) -# mo_phase.append(mo_phase_k) -# -# return scell, e_gamma, c_gamma_out, mo_phase -# -#def k2gamma(kmf, kmesh=None): -# r''' -# convert the k-sampled mean-field object to the corresponding supercell -# gamma-point mean-field object. -# -# math: -# C_{\nu ' n'} = C_{\vecR\mu, \veck m} = \frac{1}{\sqrt{N_{\UC}}} -# \e^{\ii \veck\cdot\vecR} C^{\veck}_{\mu m} -# ''' -# def transform(mo_energy, mo_coeff, mo_occ): -# scell, E_g, C_gamma = mo_k2gamma(kmf.cell, mo_energy, mo_coeff, -# kmf.kpts, kmesh)[:3] -# E_sort_idx = np.argsort(np.hstack(mo_energy)) -# mo_occ = np.hstack(mo_occ)[E_sort_idx] -# return scell, E_g, C_gamma, mo_occ -# -# if isinstance(kmf, scf.khf.KRHF): -# scell, E_g, C_gamma, mo_occ = transform(kmf.mo_energy, kmf.mo_coeff, kmf.mo_occ) -# mf = scf.RHF(scell) -# elif isinstance(kmf, scf.kuhf.KUHF): -# scell, Ea, Ca, occ_a = transform(kmf.mo_energy[0], kmf.mo_coeff[0], kmf.mo_occ[0]) -# scell, Eb, Cb, occ_b = transform(kmf.mo_energy[1], kmf.mo_coeff[1], kmf.mo_occ[1]) -# mf = scf.UHF(scell) -# E_g = [Ea, Eb] -# C_gamma = [Ca, Cb] -# mo_occ = [occ_a, occ_b] -# else: -# raise NotImplementedError('SCF object %s not supported' % kmf) -# -# mf.mo_coeff = C_gamma -# mf.mo_energy = E_g -# mf.mo_occ = mo_occ -# mf.converged = kmf.converged -# # Scale energy by number of primitive cells within supercell -# mf.e_tot = len(kmf.kpts)*kmf.e_tot -# -# # Use unfolded overlap matrix for better error cancellation -# #s_k = kmf.cell.pbc_intor('int1e_ovlp', hermi=1, kpts=kmf.kpts, pbcopt=lib.c_null_ptr()) -# s_k = kmf.get_ovlp() -# ovlp = to_supercell_ao_integrals(kmf.cell, kmf.kpts, s_k) -# assert np.allclose(ovlp, ovlp.T) -# ovlp = (ovlp + ovlp.T) / 2 -# mf.get_ovlp = lambda *args : ovlp -# -# return mf - - - -#def to_supercell_mo_integrals(kmf, mo_ints): -# '''Transform from the unitcell k-point MO integrals to the supercell -# gamma-point MO integrals. -# ''' -# cell = kmf.cell -# kpts = kmf.kpts -# -# mo_k = np.array(kmf.mo_coeff) -# Nk, nao, nmo = mo_k.shape -# e_k = np.array(kmf.mo_energy) -# scell, E_g, C_gamma, mo_phase = mo_k2gamma(cell, e_k, mo_k, kpts) -# -# scell_ints = lib.einsum('xui,xuv,xvj->ij', mo_phase.conj(), mo_ints, mo_phase) -# assert(abs(scell_ints.imag).max() < 1e-7) -# return scell_ints.real +# Depreciated functionality removed; rotation of mos to minimise imaginary part and conversion between kpoint and +# supercell calculations. +# Check out v1.0.0 or v1.0.1 if needed. if __name__ == '__main__': diff --git a/vayesta/core/qemb/OBSOLETE/fragmentation.py b/vayesta/core/qemb/OBSOLETE/fragmentation.py deleted file mode 100644 index af0533159..000000000 --- a/vayesta/core/qemb/OBSOLETE/fragmentation.py +++ /dev/null @@ -1,764 +0,0 @@ -import logging - -import numpy as np -import scipy -import scipy.linalg - -import pyscf -import pyscf.gto -import pyscf.lo -import pyscf.pbc - -from vayesta.core.util import dot, einsum - -def get_lowdin_orth_x(coeff, ovlp, tol=1e-15): - """Use as mo_coeff = np.dot(mo_coeff, x) to get orthonormal orbitals.""" - m = dot(coeff.T, ovlp, coeff) - e, v = scipy.linalg.eigh(m) - e_min = e.min() - keep = (e >= tol) - e, v = e[keep], v[:,keep] - x = dot(v/np.sqrt(e), v.T) - return x, e_min - -# --- Initialization of fragmentations -# ------------------------------------ -# These need to be called before any fragments of the respective type can be added. -# Only one fragmentation type may be initialized! - -def init_fragmentation(self, fragment_type, **kwargs): - """Initialize 'IAO', 'Lowdin-AO', or 'AO', fragmentation. - - Currently supports - 'IAO' : Intrinsic atomic orbitals - 'Lowdin-AO' : Symmetrically orthogonalized atomic orbitals - 'AO' : Non-orthogonal atomic orbitals - - Check `init_iao_fragmentation`, `init_lowdin_fragmentation`, and `init_ao_fragmentation` - for further information. - - Parameters - ---------- - fragment_type : ['IAO', 'Lowdin-AO', 'AO', 'Sites'] - Fragmentation type. - **kwargs : - Additional keyword arguments will be passed to the corresponding fragmentation - initialization method. - """ - fragment_type = fragment_type.upper() - if fragment_type == 'IAO': - return self.init_iao_fragmentation(**kwargs) - if fragment_type == 'LOWDIN-AO': - return self.init_lowdin_fragmentation(**kwargs) - if fragment_type == 'AO': - return self.init_ao_fragmentation(**kwargs) - if fragment_type == 'SITE': - return self.init_site_fragmentation(**kwargs) - raise ValueError("Unknown fragment_type: %s", fragment_type) - -def init_iao_fragmentation(self, minao='minao', make_pao=True): - """This needs to be called before any IAO fragments can be added. - - The following attributes will be defined: - default_fragment_type - iao_minao - iao_labels - iao_coeff - iao_rest_coeff - iao_occup - - Parameters - ---------- - minao : str - Minimal basis set of IAOs. - """ - self.log.info("Making IAOs for minimal basis set %s.", minao) - iao_coeff, iao_rest_coeff = self.make_iao_coeffs(minao) - iao_labels = self.get_iao_labels(minao) - iao_occup = self.get_fragment_occupancy(iao_coeff, labels=iao_labels) - # Define fragmentation specific attributes - self.default_fragment_type = 'IAO' - self.iao_minao = minao - self.iao_labels = iao_labels - self.iao_coeff = iao_coeff - self.iao_rest_coeff = iao_rest_coeff - self.iao_occup = iao_occup - # NEW: GET LOCAL VIRTUALS! - core, valence, rydberg = pyscf.lo.nao._core_val_ryd_list(self.mol) - if make_pao and rydberg: - # List of Rydberg-AOs: - # "Representation of Rydberg-AOs in terms of AOs" - c_ryd = np.eye(self.nao)[:,rydberg] - # Project AOs onto non-IAO space: - # (S^-1 - C.CT) . S = (1 - C.CT.S) - ovlp = self.get_ovlp() - p_vir = np.eye(self.nao) - dot(self.iao_coeff, self.iao_coeff.T, ovlp) - c_ryd = np.dot(p_vir, c_ryd) - #p_vir = np.dot(self.mo_coeff, self.mo_coeff.T) - np.dot(self.iao_coeff, self.iao_coeff.T) - #c_ryd = dot(p_vir, ovlp, c_ryd) - # Orthonormalize - #c_ryd = pyscf.lo.vec_lowdin(c_ryd, ovlp) - x, e_min = get_lowdin_orth_x(c_ryd, ovlp) - self.log.debug("Lowdin orthogonalization of Rydberg states: n(in)= %3d -> n(out)= %3d , e(min)= %.3e", - x.shape[0], x.shape[1], e_min) - c_ryd = np.dot(c_ryd, x) - # Check orthogonality - c_all = np.hstack((self.iao_coeff, c_ryd)) - assert (c_all.shape[-1] == self.mf.mo_coeff.shape[-1]) - err = abs(dot(c_all.T, ovlp, c_all) - np.eye(c_all.shape[-1])).max() - if err > 1e-10: - self.log.error("IAOs+PAOs non orthogonal: %.3e !", err) - self.iao_ryd_coeff = c_ryd - # Rydberg labels - self.iao_ryd_labels = (np.asarray(self.mol.ao_labels(None), dtype=object)[rydberg]).tolist() - -def init_lowdin_fragmentation(self): - """This needs to be called before any Lowdin-AO fragments can be added. - - TODO: Linear-dependency treatment - - The following attributes will be defined: - default_fragment_type - lao_labels - lao_coeff - lao_occup - """ - self.log.info("Making Lowdin-AOs") - lao_coeff = pyscf.lo.vec_lowdin(np.eye(self.nao), self.get_ovlp()) - lao_labels = self.mol.ao_labels(None) - lao_occup = self.get_fragment_occupancy(lao_coeff, labels=lao_labels) - # Define fragmentation specific attributes - self.default_fragment_type = 'Lowdin-AO' - self.lao_labels = lao_labels - self.lao_coeff = lao_coeff - self.lao_occup = lao_occup - -def init_ao_fragmentation(self): - """This needs to be called before any AO fragments can be added. - - TODO: Linear-dependency treatment not needed here (unless fragments get very large...)? - - The following attributes will be defined: - default_fragment_type - ao_labels - """ - self.log.info("Initializing AO fragmentation") - ao_labels = self.mol.ao_labels(None) - # Define fragmentation specific attributes - self.default_fragment_type = 'AO' - self.ao_labels = ao_labels - -def init_site_fragmentation(self): - """This needs to be called before any site fragments can be added. - - The following attributes will be defined: - default_fragment_type - site_labels - """ - self.log.info("Initializing site fragmentation") - site_labels = self.mol.ao_labels(None) - # Define fragmentation specific attributes - self.default_fragment_type = 'Site' - self.site_labels = site_labels - -# Fragmentation methods -# --------------------- - -def make_atom_fragment(self, atoms, aos=None, name=None, fragment_type=None, **kwargs): - """Create a fragment for one atom or a set of atoms. - - Parameters - ---------- - atoms : list - List of atom IDs or labels. - aos : list, optional - Additionally restrict fragment orbitals to a specific AO type (e.g. '2p'). Default: None. - name : str, optional - Name for fragment. - fragment_type : [None, 'IAO', 'Lowdin-AO', 'AO', 'Site'] - Fragment orbital type. If `None`, the value of `self.default_fragment_type` is used. - Default: `None`. - **kwargs : - Additional keyword arguments will be passed through to `add_fragment`. - - Returns - ------- - frag : self.Fragment - Fragment object of type self.Fragment. - """ - fragment_type = (fragment_type or self.default_fragment_type).upper() - - if np.ndim(atoms) == 0: - atoms = [atoms] - - # `atoms` can either store atoms indices or labels. - # Determine the other list and store in `atom_indices` and `atom_labels` - if isinstance(atoms[0], (int, np.integer)): - atom_indices = atoms - atom_labels = [self.mol.atom_symbol(i) for i in atoms] - else: - atom_labels = atoms - all_atom_labels = [self.mol.atom_symbol(atm) for atm in range(self.mol.natm)] - for atom_label in atom_labels: - if atom_label not in all_atom_labels: - raise ValueError("Atom with label %s not in molecule." % atom_label) - atom_indices = np.nonzero(np.isin(all_atom_labels, atom_labels))[0] - #assert len(atom_indices) == len(atom_labels) - self.log.debugv("atom_indices= %r", atom_indices) - - # Generate cluster name if not given - if name is None: - name = "-".join(atom_labels) - - # Fragment type specific implementation - if fragment_type == 'IAO': - # Base atom for each IAO - iao_atoms = [iao[0] for iao in self.iao_labels] - # Indices of IAOs based at atoms - frag_iaos = np.nonzero(np.isin(iao_atoms, atom_indices))[0] - self.log.debugv("Fragment IAOs:\n%r", frag_iaos) - refmol = pyscf.lo.iao.reference_mol(self.mol, minao=self.iao_minao) - if aos is not None: - for ao in aos: - if len(refmol.search_ao_label(ao)) == 0: - raise ValueError("No orbitals matching the label %s in molecule", ao) - ao_indices = refmol.search_ao_label(aos) - frag_iaos = [i for i in frag_iaos if (i in ao_indices)] - self.log.debug("Adding fragment orbitals %r", np.asarray(refmol.ao_labels())[frag_iaos].tolist()) - c_frag = self.iao_coeff[:,frag_iaos].copy() - # Combine remaining IAOs and rest virtual space (`iao_rest_coeff`) - #rest_iaos = np.asarray([i for i in np.arange(self.iao_coeff.shape[-1]) if i not in frag_iaos]) - rest_iaos = np.setdiff1d(range(self.iao_coeff.shape[-1]), frag_iaos) - c_env = np.hstack((self.iao_coeff[:,rest_iaos], self.iao_rest_coeff)) - # NEW: add fragment local virtuals! - if hasattr(self, 'iao_ryd_coeff'): - ryd_atoms = [ryd[0] for ryd in self.iao_ryd_labels] - self.log.debugv("Rydberg atoms:\n%r", ryd_atoms) - ryd_mask = np.isin(ryd_atoms, atom_indices) - # L-FILTER - #if True: - if False: - ryd_l = [ryd[2] for ryd in self.iao_ryd_labels] - filt = np.isin(ryd_l, ['3s', '3p']) - #filt = np.isin(ryd_l, ['3s']) - ryd_mask = np.logical_and(ryd_mask, filt) - - locvir = np.nonzero(ryd_mask)[0] - self.log.debugv("Local virtuals:\n%r", locvir) - locvir_labels = (np.array(self.iao_ryd_labels)[locvir]).tolist() - self.log.debugv("Local virtuals:\n%r", locvir_labels) - c_locvir = self.iao_ryd_coeff[:,locvir] - # c_nlenv - nlocvir = np.nonzero(~ryd_mask)[0] - c_nloc = np.hstack((self.iao_coeff[:,rest_iaos], self.iao_ryd_coeff[:,nlocvir])) - #if False: - if True: - kwargs['c_locvir'] = c_locvir - kwargs['c_nloc'] = c_nloc - else: - c_frag = np.hstack((c_frag, c_locvir)) - c_env = c_nloc - - elif fragment_type == 'LOWDIN-AO': - # Base atom for each LowdinAO - lao_atoms = [lao[0] for lao in self.lao_labels] - # Indices of LowdinAOs based at atoms - frag_laos = np.nonzero(np.isin(lao_atoms, atom_indices))[0] - c_frag = self.lao_coeff[:,frag_laos].copy() - #rest_laos = np.asarray([i for i in np.arange(self.lao_coeff.shape[-1]) if i not in frag_laos]) - rest_laos = np.setdiff1d(range(self.lao_coeff.shape[-1]), frag_laos) - c_env = self.lao_coeff[:,rest_laos].copy() - elif fragment_type == 'AO': - # TODO: linear-dependency treatment - ao_atoms = [ao[0] for ao in self.ao_labels] - frag_aos = np.nonzero(np.isin(ao_atoms, atom_indices))[0] - p_frag = self.get_subset_ao_projector(frag_aos) - e, c = scipy.linalg.eigh(p_frag, b=self.get_ovlp()) - e, c = e[::-1], c[:,::-1] - size = len(e[e>1e-5]) - if size != len(frag_aos): - raise RuntimeError("Error finding fragment atomic orbitals. Eigenvalues: %s" % e) - assert np.allclose(np.linalg.multi_dot((c.T, self.get_ovlp(), c)) - np.eye(nao), 0) - c_frag, c_env = np.hsplit(c, [size]) - # In the case of AOs, we can also store them in the fragment - kwargs['aos'] = frag_aos - elif fragment_type == 'SITE': - sites = atom_indices - c_frag = np.eye(self.mol.nao_nr())[:,sites] - rest = [i for i in range(self.mol.nao_nr()) if i not in sites] - c_env = np.eye(self.mol.nao_nr())[:,rest] - else: - raise ValueError("Unknown fragment_type: %s" % fragment_type) - - frag = self.add_fragment(name, c_frag, c_env, fragment_type=fragment_type, atoms=atom_indices, **kwargs) - return frag - -def get_ao_labels(self, ao_indices, fragment_type=None): - fragment_type = (fragment_type or self.default_fragment_type).upper() - if fragment_type in ('LOWDIN-AO', 'AO'): - mol = self.mol - elif fragment_type == 'IAO': - mol = pyscf.lo.iao.reference_mol(self.mol, minao=self.iao_minao) - ao_labels = np.asarray(mol.ao_labels())[ao_indices] - return ao_labels - -def get_ao_indices(self, ao_labels, fragment_type=None): - fragment_type = (fragment_type or self.default_fragment_type).upper() - if fragment_type in ('LOWDIN-AO', 'AO'): - mol = self.mol - elif fragment_type == 'IAO': - mol = pyscf.lo.iao.reference_mol(self.mol, minao=self.iao_minao) - for ao_label in ao_labels: - if len(mol.search_ao_label(ao_label)) == 0: - raise ValueError("No orbitals matching the label %s in molecule", ao_label) - ao_indices = mol.search_ao_label(ao_labels) - return ao_indices - - -def make_ao_fragment(self, aos, name=None, fragment_type=None, **kwargs): - """Create a fragment for one atomic orbitals or a set of atomic orbitals. - - 'Atomic orbital' refers here either to intrinsic atomic orbitals, - Lowdin-orthogonalized atomic orbitals, or non-orthogonal atomic orbitals. - - Parameters - ---------- - aos : list - List of AO IDs or labels. - name : str, optional - Name for fragment. - fragment_type : [None, 'IAO', "Lowdin-AO', 'AO'] - Fragment orbital type. If `None`, the value of `self.default_fragment_type` is used. - Default: `None`. - **kwargs : - Additional keyword arguments will be passed through to `add_fragment`. - - Returns - ------- - frag : self.Fragment - Fragment object of type self.Fragment. - """ - fragment_type = (fragment_type or self.default_fragment_type).upper() - - if np.ndim(aos) == 0: - aos = [aos] - - # `aos` can either store AO indices or labels. - # Determine the other list and store in `ao_indices` and `ao_labels` - if isinstance(aos[0], (int, np.integer)): - ao_indices = aos - #if fragment_type in ('LOWDIN-AO', 'AO'): - # ao_labels = np.asarray(self.mol.ao_labels())[ao_indices] - #elif fragment_type == 'IAO': - # refmol = pyscf.lo.iao.reference_mol(self.mol, minao=self.iao_minao) - # ao_labels = np.asarray(refmol.ao_labels())[ao_indices] - ao_labels = self.get_ao_labels(ao_indices, fragment_type) - else: - ao_labels = aos - #if fragment_type in ('LOWDIN-AO', 'AO'): - # for ao_label in ao_labels: - # if len(mol.search_ao_label(ao_label)) == 0: - # raise ValueError("No orbitals matching the label %s in molecule", ao_label) - # ao_indices = self.mol.search_ao_label(ao_labels) - #elif fragment_type == 'IAO': - # refmol = pyscf.lo.iao.reference_mol(self.mol, minao=self.iao_minao) - # for ao_label in ao_labels: - # if len(refmol.search_ao_label(ao_label)) == 0: - # raise ValueError("No orbitals matching the label %s in molecule", ao_label) - # ao_indices = refmol.search_ao_label(ao_labels) - ao_indices = self.get_ao_indices(ao_labels, fragment_type) - - if name is None: - #name = ",".join(["-".join(ao) for ao in aos]) - #name = ";".join([",".join(ao.split()) for ao in ao_labels]) - name = "-".join([ao.rstrip() for ao in ao_labels]) - - # Fragment type specific implementation - if fragment_type == 'IAO': - c_frag = self.iao_coeff[:,ao_indices].copy() - rest_iaos = np.setdiff1d(range(self.iao_coeff.shape[-1]), ao_indices) - # Combine remaining IAOs and rest virtual space (`iao_rest_coeff`) - c_env = np.hstack((self.iao_coeff[:,rest_iaos], self.iao_rest_coeff)) - elif fragment_type == 'LOWDIN-AO': - c_frag = self.lao_coeff[:,ao_indices].copy() - rest_laos = np.setdiff1d(range(self.lao_coeff.shape[-1]), ao_indices) - c_env = self.lao_coeff[:,rest_laos].copy() - kwargs['aos'] = ao_indices - elif fragment_type == 'AO': - # TODO: linear-dependency treatment - p_frag = self.get_subset_ao_projector(ao_indices) - e, c = scipy.linalg.eigh(p_frag, b=self.get_ovlp()) - e, c = e[::-1], c[:,::-1] - size = len(e[e>1e-5]) - if size != len(ao_indices): - raise RuntimeError("Error finding fragment atomic orbitals. Eigenvalues: %s" % e) - assert np.allclose(np.linalg.multi_dot((c.T, self.get_ovlp(), c)) - np.eye(c.shape[-1]), 0) - c_frag, c_env = np.hsplit(c, [size]) - kwargs['aos'] = ao_indices - else: - raise ValueError("Unknown fragment_type: %s" % fragment_type) - - frag = self.add_fragment(name, c_frag, c_env, fragment_type=fragment_type, **kwargs) - return frag - - -def add_fragment(self, name, c_frag, c_env, fragment_type, sym_factor=1.0, **kwargs): - """Create Fragment object and add to fragment list. - - This may have to be shadowed by an embedding method specific version! - - Parameters - ---------- - name : str - Name for fragment. - c_frag : ndarray - Local (fragment) orbital coefficients. - c_env : ndarray - All environment (non-fragment) orbital coefficients. - fragment_type : ['IAO', "Lowdin-AO', 'AO'] - Fragment orbital type. - sym_factor : float, optional - Symmetry factor. Default: 1.0. - - Returns - ------- - frag : self.Fragment - Fragment object of type self.Fragment. - """ - fid = self._nfrag_tot + 1 # Get new fragment ID - # TODO: Temporary fix for UHF - will not generally work for IAOs! - if self.is_uhf: - c_frag = (c_frag, c_frag) - c_env = (c_env, c_env) - frag = self.Fragment(self, fid=fid, name=name, c_frag=c_frag, c_env=c_env, - fragment_type=fragment_type, sym_factor=sym_factor, **kwargs) - self.fragments.append(frag) - self._nfrag_tot += 1 - return frag - -def make_all_atom_fragments(self, **kwargs): - """Create a fragment for each atom in the molecule.""" - fragments = [] - for atom in range(self.mol.natm): - frag = self.make_atom_fragment(atom, **kwargs) - fragments.append(frag) - return fragments - -# IAO fragmentation specific -# -------------------------- - -def make_iao_coeffs(self, minao='minao', return_rest=True): - """Make intrinsic atomic orbitals (IAOs) and remaining virtual orbitals via projection. - - Parameters - ---------- - minao : str, optional - Minimal basis set for IAOs. Default: 'minao'. - return_rest : bool, optional - Return coefficients of remaining virtual orbitals. Default: `True`. - - Returns - ------- - c_iao : (nAO, nIAO) array - IAO coefficients. - c_rest : (nAO, nRest) array - Remaining virtual orbital coefficients. `None`, if `make_rest == False`. - """ - mo_coeff = self.mo_coeff - ovlp = self.get_ovlp() - - c_occ = self.mo_coeff[:,self.mo_occ>0] - c_iao = pyscf.lo.iao.iao(self.mol, c_occ, minao=minao) - niao = c_iao.shape[-1] - self.log.info("Total number of IAOs= %4d", niao) - - # Orthogonalize IAO using symmetric orthogonalization - c_iao = pyscf.lo.vec_lowdin(c_iao, ovlp) - - # Check that all electrons are in IAO space - sc = np.dot(ovlp, c_iao) - dm_iao = np.linalg.multi_dot((sc.T, self.mf.make_rdm1(), sc)) - nelec_iao = np.trace(dm_iao) - self.log.debugv('nelec_iao= %.8f', nelec_iao) - if abs(nelec_iao - self.mol.nelectron) > 1e-5: - self.log.error("IAOs do not contain the correct number of electrons: %.8f", nelec_iao) - - # Test orthogonality of IAO - idterr = c_iao.T.dot(ovlp).dot(c_iao) - np.eye(niao) - self.log.log(logging.ERROR if np.linalg.norm(idterr) > 1e-5 else logging.DEBUG, - "Orthogonality error of IAO: L(2)= %.2e L(inf)= %.2e", np.linalg.norm(idterr), abs(idterr).max()) - - if not return_rest: - return c_iao, None - - # Add remaining virtual space, work in MO space, so that we automatically get the - # correct linear dependency treatment, if nMO < nAO - c_iao_mo = np.linalg.multi_dot((self.mo_coeff.T, ovlp, c_iao)) - # Get eigenvectors of projector into complement - p_iao = np.dot(c_iao_mo, c_iao_mo.T) - p_rest = np.eye(self.nmo) - p_iao - e, c = np.linalg.eigh(p_rest) - - # Corresponding expression in AO basis (but no linear-dependency treatment): - # p_rest = ovlp - ovlp.dot(c_iao).dot(c_iao.T).dot(ovlp) - # e, c = scipy.linalg.eigh(p_rest, ovlp) - # c_rest = c[:,e>0.5] - - # Ideally, all eigenvalues of P_env should be 0 (IAOs) or 1 (non-IAO) - # Error if > 1e-3 - mask_iao, mask_rest = (e <= 0.5), (e > 0.5) - e_iao, e_rest = e[mask_iao], e[mask_rest] - if np.any(abs(e_iao) > 1e-3): - self.log.error("CRITICAL: Some IAO eigenvalues of 1-P_IAO are not close to 0:\n%r", e_iao) - elif np.any(abs(e_iao) > 1e-6): - self.log.warning("Some IAO eigenvalues e of 1-P_IAO are not close to 0: n= %d max|e|= %.2e", - np.count_nonzero(abs(e_iao) > 1e-6), abs(e_iao).max()) - if np.any(abs(1-e_rest) > 1e-3): - self.log.error("CRITICAL: Some non-IAO eigenvalues of 1-P_IAO are not close to 1:\n%r", e_rest) - elif np.any(abs(1-e_rest) > 1e-6): - self.log.warning("Some non-IAO eigenvalues e of 1-P_IAO are not close to 1: n= %d max|1-e|= %.2e", - np.count_nonzero(abs(1-e_rest) > 1e-6), abs(1-e_rest).max()) - - if not (np.sum(mask_rest) + niao == self.nmo): - self.log.critical("Error in construction of remaining virtual orbitals! Eigenvalues of projector 1-P_IAO:\n%r", e) - self.log.critical("Number of eigenvalues above 0.5 = %d", np.sum(mask_rest)) - self.log.critical("Total number of orbitals = %d", self.nmo) - raise RuntimeError("Incorrect number of remaining virtual orbitals") - c_rest = np.dot(self.mo_coeff, c[:,mask_rest]) # Transform back to AO basis - - # --- Some checks below: - - # Test orthogonality of IAO + rest - c_all = np.hstack((c_iao, c_rest)) - idterr = c_all.T.dot(ovlp).dot(c_all) - np.eye(self.nmo) - self.log.log(logging.ERROR if np.linalg.norm(idterr) > 1e-5 else logging.DEBUG, - "Orthogonality error of IAO+vir. orbitals: L(2)= %.2e L(inf)= %.2e", np.linalg.norm(idterr), abs(idterr).max()) - - return c_iao, c_rest - - -def get_fragment_occupancy(self, coeff, dm=None, labels=None, verbose=True): - """Get electron occupancy of all fragment orbitals. - - This can be used for any orthogonal fragment basis (IAO, LowdinAO) - - Parameters - ---------- - coeff : (nAO, nFO) array - Fragment orbital coefficients. - labels : (nFO), array - Fragment orbital labels. Only needed if verbose==True. - verbose : bool, optional - Check lattice symmetry of fragment orbitals and print occupations per atom. - Default: True. - - Returns - ------- - occup : (nFO,) array - Occupation of fragment orbitals. - """ - if dm is None: - dm = self.mf.make_rdm1() - if np.ndim(dm) == 3: - occup = (self.get_fragment_occupancy(coeff, dm[0], labels=labels, verbose=verbose), - self.get_fragment_occupancy(coeff, dm[1], labels=labels, verbose=verbose)) - return occup - - sc = np.dot(self.get_ovlp(), coeff) - occup = einsum('ai,ab,bi->i', sc, dm, sc) - if not verbose: - return occup - - if len(labels) != coeff.shape[-1]: - raise RuntimeError("Inconsistent number of fragment orbitals and labels.") - # Occupancy per atom - occup_atom = [] - atoms = np.asarray([i[0] for i in labels]) - self.log.debugv('atoms= %r', atoms) - for a in range(self.mol.natm): - mask = np.where(atoms == a)[0] - occup_atom.append(occup[mask]) - self.log.debugv("occup_atom: %r", occup_atom) - - # Check lattice symmetry if k-point mf object was used - tsym = False - if self.ncells > 1: - # Fragment orbital occupations per cell - occup_cell = np.split(np.hstack(occup_atom), self.ncells) - self.log.debugv("occup_cell: %r", occup_cell) - # Compare all cells to the primitive cell - tsym = np.all([np.allclose(occup_cell[i], occup_cell[0]) for i in range(self.ncells)]) - self.log.debugv("Translation symmetry in fragment orbitals: %r", tsym) - - # Print occupations of IAOs - self.log.info("Fragment Orbital Occupancy per Atom") - self.log.info("-----------------------------------") - for a in range(self.mol.natm if not tsym else self.kcell.natm): - mask = np.where(atoms == a)[0] - fmt = " > %3d: %-8s total= %12.8f" + len(occup_atom[a])*" %s= %10.8f" - sublabels = [("_".join((x[2], x[3])) if x[3] else x[2]) for x in np.asarray(labels)[mask]] - vals = [val for pair in zip(sublabels, occup_atom[a]) for val in pair] - self.log.info(fmt, a, self.mol.atom_symbol(a), np.sum(occup_atom[a]), *vals) - - return occup - -def get_iao_labels(self, minao): - """Get labels of IAOs - - Parameters - ---------- - minao : str, optional - Minimal basis set for IAOs. Default: 'minao'. - - Returns - ------- - iao_labels : list of length nIAO - Orbital label (atom-id, atom symbol, nl string, m string) for each IAO. - """ - refmol = pyscf.lo.iao.reference_mol(self.mol, minao=minao) - iao_labels_refmol = refmol.ao_labels(None) - self.log.debugv('iao_labels_refmol: %r', iao_labels_refmol) - if refmol.natm == self.mol.natm: - iao_labels = iao_labels_refmol - # If there are ghost atoms in the system, they will be removed in refmol. - # For this reason, the atom IDs of mol and refmol will not agree anymore. - # Here we will correct the atom IDs of refmol to agree with mol - # (they will no longer be contiguous integers). - else: - ref2mol = [] - for refatm in range(refmol.natm): - ref_coords = refmol.atom_coord(refatm) - for atm in range(self.mol.natm): - coords = self.mol.atom_coord(atm) - if np.allclose(coords, ref_coords): - self.log.debugv('reference cell atom %r maps to atom %r', refatm, atm) - ref2mol.append(atm) - break - else: - raise RuntimeError("No atom found with coordinates %r" % ref_coords) - iao_labels = [] - for iao in iao_labels_refmol: - iao_labels.append((ref2mol[iao[0]], iao[1], iao[2], iao[3])) - self.log.debugv('iao_labels: %r', iao_labels) - assert (len(iao_labels_refmol) == len(iao_labels)) - return iao_labels - - -# AO fragmentation specific -# ------------------------- -# Not tested - -def get_subset_ao_projector(self, aos): - """Get projector onto AO subspace in the non-orthogonal AO basis. - - Projector from large (1) to small (2) AO basis according to https://doi.org/10.1021/ct400687b - This is a special case of the more general `get_ao_projector`, which can also - handle a different AO basis set. - - Parameters - ---------- - aos : list of AO indices or AO labels or mask - List of indices/labels or mask of subspace AOs. If a list of labels is given, - it is converted to AO indices using the PySCF `search_ao_label` function. - - Returns - ------- - p : (nAO, nAO) array - Projector onto AO subspace. - """ - s1 = self.get_ovlp() - if aos is None: - aos = np.s_[:] - - if isinstance(aos, slice): - s2 = s1[aos,aos] - elif isinstance(aos[0], str): - self.log.debugv("Searching for AO indices of AOs %r", aos) - aos_idx = self.mol.search_ao_label(aos) - self.log.debugv("Found AO indices: %r", aos_idx) - self.log.debugv("Corresponding to AO labels: %r", np.asarray(self.mol.ao_labels())[aos_idx]) - if len(aos_idx) == 0: - raise RuntimeError("No AOs with labels %r found" % aos) - aos = aos_idx - s2 = s1[np.ix_(aos, aos)] - else: - s2 = s1[np.ix_(aos, aos)] - s21 = s1[aos] - p21 = scipy.linalg.solve(s2, s21, assume_a="pos") - p = np.dot(s21.T, p21) - assert np.allclose(p, p.T) - return p - - -def get_ao_projector(self, aos, basis=None): - """Get projector onto AO subspace in the non-orthogonal AO basis. - - Projector from large (1) to small (2) AO basis according to https://doi.org/10.1021/ct400687b - - TODO: This is probably not correct (check Ref. above) if basis is not fully contained - in the span of self.mol.basis. In this case a <1|2> is missing. - - Parameters - ---------- - aos : list of AO indices or AO labels or mask - List of indices/labels or mask of subspace AOs. If a list of labels is given, - it is converted to AO indices using the PySCF `search_ao_label` function. - basis : str, optional - Basis set for AO subspace. If `None`, the same basis set as that of `self.mol` - is used. Default: `None`. - - Returns - ------- - p : (nAO, nAO) array - Projector onto AO subspace. - """ - - mol1 = self.mol - s1 = self.get_ovlp() - - # AOs are given in same basis as mol1 - if basis is None: - mol2 = mol1 - s2 = s21 = s1 - # AOs of a different basis - else: - mol2 = mol1.copy() - # What was this for? - commented for now - #if getattr(mol2, 'rcut', None) is not None: - # mol2.rcut = None - mol2.build(False, False, basis=basis2) - - if self.boundary_cond == 'open': - s2 = mol2.intor_symmetric('int1e_ovlp') - s12 = pyscf.gto.mole.intor_cross('int1e_ovlp', mol1, mol2) - else: - s2 = np.asarray(mol2.pbc_intor('int1e_ovlp', hermi=1, kpts=None)) - s21 = np.asarray(pyscf.pbc.gto.cell.intor_cross('int1e_ovlp', mol1, mol2, kpts=None)) - assert s1.ndim == 2 - assert s2.ndim == 2 - assert s21.ndim == 2 - - # All AOs - if aos is None: - aos = np.s_[:] - - if isinstance(aos, slice): - s2 = s1[aos,aos] - elif isinstance(aos[0], str): - self.log.debugv("Searching for AO indices of AOs %r", aos) - aos_idx = mol2.search_ao_label(aos) - self.log.debugv("Found AO indices: %r", aos_idx) - self.log.debugv("Corresponding to AO labels: %r", np.asarray(mol2.ao_labels())[aos_idx]) - if len(aos_idx) == 0: - raise RuntimeError("No AOs with labels %r found" % aos) - aos = aos_idx - s2 = s1[np.ix_(aos, aos)] - else: - s2 = s1[np.ix_(aos, aos)] - - s21 = s21[aos] - - p21 = scipy.linalg.solve(s2, s21, assume_a="pos") - p = np.dot(s21.T, p21) - assert np.allclose(p, p.T) - return p diff --git a/vayesta/core/qemb/fragment.py b/vayesta/core/qemb/fragment.py index 554d15974..a6a152de5 100644 --- a/vayesta/core/qemb/fragment.py +++ b/vayesta/core/qemb/fragment.py @@ -574,7 +574,6 @@ def copy(self, fid=None, name=None, **kwargs): frag = type(self)(self.base, fid, name, **kwargs_copy) return frag - @deprecated() def add_tsymmetric_fragments(self, tvecs, symtol=1e-6): """ @@ -641,10 +640,6 @@ def add_tsymmetric_fragments(self, tvecs, symtol=1e-6): fragments.append(frag) return fragments - @deprecated(replacement='add_tsymmetric_fragment') - def make_tsymmetric_fragments(self, *args, **kwargs): # pragma: no cover - return self.add_tsymmetric_fragments(*args, **kwargs) - def get_symmetry_parent(self): if self.sym_parent is None: return self @@ -797,15 +792,6 @@ def get_bath(occtype): otype = occtype[:3] assert otype in ('occ', 'vir') btype = self._get_bath_option('bathtype', occtype) - if btype is None: - self.log.warning("bathtype=None is deprecated; use bathtype='dmet'.") - btype = 'dmet' - if btype == 'all': - self.log.warning("bathtype='all' is deprecated; use bathtype='full'.") - btype = 'full' - if btype == 'mp2-bno': - self.log.warning("bathtype='mp2-bno' is deprecated; use bathtype='mp2'.") - btype = 'mp2' # DMET bath only if btype == 'dmet': return None diff --git a/vayesta/core/qemb/qemb.py b/vayesta/core/qemb/qemb.py index 43df505e7..d28b89d13 100644 --- a/vayesta/core/qemb/qemb.py +++ b/vayesta/core/qemb/qemb.py @@ -782,6 +782,12 @@ def create_symmetric_fragments(self, symmetry, fragments=None, symbol=None, mf_t List of T-symmetry related fragments. These will have the attributes `sym_parent` and `sym_op` set. """ default_axes = {'x': (1,0,0), 'y': (0,1,0), 'z': (0,0,1)} + + def catch_default_axes(axis): + if isinstance(axis, str): + return default_axes[axis.lower()] + return axis + symtype = symmetry['type'] def to_bohr(point, unit): @@ -818,14 +824,14 @@ def shift_point_to_supercell(point): center = to_bohr(symmetry['center'], symmetry['unit']) center = shift_point_to_supercell(center) axis = symmetry['axis'] - axis = np.asarray(default_axes.get(axis, axis), dtype=float) + axis = np.asarray(catch_default_axes(axis), dtype=float) axis = to_bohr(axis, symmetry['unit']) symbol = symbol or 'M' symlist = [1] elif symtype == 'rotation': order = symmetry['order'] axis = symmetry['axis'] - axis = np.asarray(default_axes.get(axis, axis), dtype=float) + axis = np.asarray(catch_default_axes(axis), dtype=float) axis = to_bohr(axis, symmetry['unit']) center = to_bohr(symmetry['center'], symmetry['unit']) center = shift_point_to_supercell(center) diff --git a/vayesta/core/types/wf/fci.py b/vayesta/core/types/wf/fci.py index 4f8b73ec4..976158af9 100644 --- a/vayesta/core/types/wf/fci.py +++ b/vayesta/core/types/wf/fci.py @@ -1,7 +1,7 @@ import numpy as np import pyscf import pyscf.fci -from vayesta.core.util import decompress_axes, dot, einsum, tril_indices_ndim +from vayesta.core.util import decompress_axes, dot, einsum, tril_indices_ndim, replace_attr from vayesta.core.types import wf as wf_types def FCI_WaveFunction(mo, ci, **kwargs): diff --git a/vayesta/core/util.py b/vayesta/core/util.py index e87a76f34..13655b49d 100644 --- a/vayesta/core/util.py +++ b/vayesta/core/util.py @@ -35,7 +35,7 @@ # Time & memory 'timer', 'log_time', 'get_used_memory', 'log_method', # Other - 'getattr_recursive', 'setattr_recursive', + 'getattr_recursive', 'setattr_recursive', 'replace_attr', 'break_into_lines', 'fix_orbital_sign', 'split_into_blocks', 'getif', 'callif', 'permutations_with_signs', ] diff --git a/vayesta/ewf/OBSOLETE/__ao2mo_j3c.py b/vayesta/ewf/OBSOLETE/__ao2mo_j3c.py deleted file mode 100644 index 957ef6521..000000000 --- a/vayesta/ewf/OBSOLETE/__ao2mo_j3c.py +++ /dev/null @@ -1,164 +0,0 @@ -"""UNMAINTAINED MODULE""" -raise NotImplementedError() - - -"""AO to MO transformation routines for density-fitted three-center integrals -""" -import logging - -import numpy as np - -import pyscf.lib -from pyscf.mp.mp2 import _mo_without_core -from pyscf.mp.mp2 import _ChemistsERIs as _ChemistsERIs_mp2 -from pyscf.cc.rccsd import _ChemistsERIs as _ChemistsERIs_cc -from pyscf.pbc import tools - -from vayesta.ewf.OBSOLETE.util import einsum - -log = logging.getLogger(__name__) - -__all__ = ["ao2mo_mp2", "ao2mo_ccsd"] - -def j3c_to_eris(j3c, mo_coeff, nocc, compact=False, ovov_only=False): - """Convert three-center integrals (L|ab) to (ij|kl) for some set of MO coefficients. - - Parameters - ---------- - j3c : ndarray - Three-center integrals in AO basis. - mo_coeff : ndarray - MO coefficients. - nocc : int - Number of occupied orbitals. - compact : bool, optional - ovov_only : bool, optional - Only tranform the occupied-virtual-occupied-virtual part of (ij|kl), - as needed by MP2. - - Returns - ------- - mo_eris : dict - """ - if compact: - raise NotImplementedError() - j3c_compact = (j3c.ndim == 2) - assert (j3c.ndim in (2, 3)) - norb = mo_coeff.shape[-1] - nvir = norb - nocc - naux = j3c.shape[0] - o, v = np.s_[:nocc], np.s_[nocc:] - co, cv = mo_coeff[:,o], mo_coeff[:,v] - assert not np.iscomplexobj(mo_coeff) - - # AO->MO - if not j3c_compact: - j3c_ov = einsum("Lab,ai,bj->Lij", j3c, co, cv) - if not ovov_only: - j3c_oo = einsum("Lab,ai,bj->Lij", j3c, co, co) - j3c_vv = einsum("Lab,ai,bj->Lij", j3c, cv, cv) - # TEST: - #j3c_vo = einsum("Lab,ai,bj->Lij", j3c, cv, co) - else: - j3c_ov = np.zeros((naux, nocc, nvir), dtype=j3c.dtype) - if not ovov_only: - j3c_oo = np.zeros((naux, nocc, nocc), dtype=j3c.dtype) - j3c_vv = np.zeros((naux, nvir, nvir), dtype=j3c.dtype) - # TEST: - #j3c_vo = np.zeros((naux, nvir, nocc), dtype=j3c.dtype) - # Avoid unpacking entire j3c at once - #zfac = 2 if np.iscomplexobj(j3c) else 1 - #stepsize = int(500 / (max(nocc, nvir)**2 * zfac * 8/1e6)) - #log.debug("Stepsize= %d", stepsize) - stepsize = 1 - for lmin, lmax in pyscf.lib.prange(0, naux, stepsize): - l = np.s_[lmin:lmax] - j3c_l = pyscf.lib.unpack_tril(j3c[l]) - j3c_ov[l] = einsum("Lab,ai,bj->Lij", j3c_l, co, cv) - if not ovov_only: - j3c_oo[l] = einsum("Lab,ai,bj->Lij", j3c_l, co, co) - j3c_vv[l] = einsum("Lab,ai,bj->Lij", j3c_l, cv, cv) - # TEST: - #j3c_vo[l] = einsum("Lab,ai,bj->Lij", j3c_l, cv, co) - # TEST - #assert (ovov_only or np.allclose(j3c_ov, j3c_vo.transpose((0,2,1)))) - - # 3c -> 4c - mo_eris = {"ovov" : einsum("Lij,Lkl->ijkl", j3c_ov, j3c_ov)} - if not ovov_only: - mo_eris["oooo"] = einsum("Lij,Lkl->ijkl", j3c_oo, j3c_oo) - mo_eris["ovoo"] = einsum("Lij,Lkl->ijkl", j3c_ov, j3c_oo) - mo_eris["oovv"] = einsum("Lij,Lkl->ijkl", j3c_oo, j3c_vv) - #mo_eris["ovvo"] = einsum("Lij,Lkl->ijkl", j3c_ov, j3c_vo) - mo_eris["ovvo"] = einsum("Lij,Llk->ijkl", j3c_ov, j3c_ov) - mo_eris["ovvv"] = einsum("Lij,Lkl->ijkl", j3c_ov, j3c_vv) - mo_eris["vvvv"] = einsum("Lij,Lkl->ijkl", j3c_vv, j3c_vv) - - return mo_eris - - -def ao2mo_mp2(mp, fock): - """Creates pyscf.mp compatible _ChemistsERIs object. - - Parameters - ---------- - mp : pyscf.mp.mp2.MP2 - PySCF MP2 object. - mo_energy : ndarray - MO energies. - - Returns - ------- - eris : pyscf.mp.mp2._ChemistERIs - ERIs for MP2. - """ - eris = _ChemistsERIs_mp2() - mo_coeff = _mo_without_core(mp, mp.mo_coeff) - eris.mo_coeff = mo_coeff - eris.nocc = mp.nocc - eris.e_hf = mp._scf.e_tot - eris.mo_energy = fock.diagonal().copy() - eris.fock = fock.copy() - - j3c = mp._scf.with_df._cderi - g = j3c_to_eris(j3c, mo_coeff, eris.nocc, ovov_only=True) - eris.ovov = g["ovov"] - - return eris - - -def ao2mo_ccsd(cc, fock): - """Creates pyscf.cc compatible _ChemistsERIs object. - - Parameters - ---------- - cc : pyscf.cc.ccsd.CCSD - PySCF CCSD object. - fock : ndarray - Must include exxdiv correction (will be removed). - - Returns - ------- - eris : pyscf.cc.rccsd._ChemistERIs - ERIs for CCSD. - """ - scf = cc._scf - eris = _ChemistsERIs_cc() - mo_coeff = _mo_without_core(cc, cc.mo_coeff) - eris.mo_coeff = mo_coeff - eris.nocc = cc.nocc - eris.e_hf = scf.e_tot - eris.mo_energy = fock.diagonal().copy() - eris.fock = fock.copy() - # Remove EXXDIV correction from Fock matrix - if scf.exxdiv is not None: - madelung = tools.madelung(scf.cell, scf.kpt) - for i in range(eris.nocc): - eris.fock[i,i] += madelung - - j3c = scf.with_df._cderi - g = j3c_to_eris(j3c, mo_coeff, eris.nocc) - for key, val in g.items(): - setattr(eris, key, val) - - return eris diff --git a/vayesta/ewf/OBSOLETE/__bath.py b/vayesta/ewf/OBSOLETE/__bath.py deleted file mode 100644 index dc16f88d1..000000000 --- a/vayesta/ewf/OBSOLETE/__bath.py +++ /dev/null @@ -1,977 +0,0 @@ -"""UNMAINTAINED MODULE""" -raise NotImplementedError() - - -"""These functions take a cluster instance as first argument ("self").""" - -import logging -import numpy as np -from timeit import default_timer as timer - -import pyscf -import pyscf.mp -import pyscf.pbc -import pyscf.pbc.mp -import pyscf.ao2mo - -from vayesta.ewf.OBSOLETE.util import * -from vayesta.ewf.OBSOLETE import ao2mo_j3c - -__all__ = [ - #"project_ref_orbitals", - "make_bath", - "make_local_bath", - "make_mf_bath", - "transform_mp2_eris", - "run_mp2", - "run_mp2_general", - "get_mp2_correction", - "make_mp2_bath", - ] - -log = logging.getLogger(__name__) - -def project_ref_orbitals(self, C_ref, C): - """Project reference orbitals into available space in new geometry. - - The projected orbitals will be ordered according to their eigenvalues within the space. - - Parameters - ---------- - C : ndarray - Orbital coefficients. - C_ref : ndarray - Orbital coefficients of reference orbitals. - """ - nref = C_ref.shape[-1] - assert (nref > 0) - assert (C.shape[-1] > 0) - log.debug("Projecting %d reference orbitals into space of %d orbitals", nref, C.shape[-1]) - S = self.base.ovlp - # Diagonalize reference orbitals among themselves (due to change in overlap matrix) - C_ref_orth = pyscf.lo.vec_lowdin(C_ref, S) - assert (C_ref_orth.shape == C_ref.shape) - # Diagonalize projector in space - CSC = np.linalg.multi_dot((C_ref_orth.T, S, C)) - P = np.dot(CSC.T, CSC) - e, R = np.linalg.eigh(P) - e, R = e[::-1], R[:,::-1] - C = np.dot(C, R) - #log.debug("All eigenvalues:\n%r", e) - - return C, e - -# ================================================================================================ # - -def make_bath(self, C_env, bathtype, kind, C_ref=None, eigref=None, - nbath=None, tol=None, energy_tol=None, - # For new MP2 bath: - C_occenv=None, C_virenv=None, - **kwargs): - """Make additional bath (beyond DMET bath) orbitals. - - Parameters - ---------- - C_env : ndarray - Environment orbitals. - bathtype : str - Type of bath orbitals. - kind : str - Occupied or virtual. - C_ref : ndarray, optional - Reference bath orbitals from previous calculation. - eigref : tuple, optional - Eigenpair reference data. If given, the bath orbitals are sorted correspondingly. - - Returns - ------- - C_bath : ndarray - Bath orbitals. - C_env : ndarray - Environment orbitals. - """ - - # The bath tolerance is understood per electron in DMET cluster - if self.opts.bath_tol_per_elec and tol is not None: - tol *= (2*self.C_occclst.shape[-1]) - - log.debug("type=%r, nbath=%r, tol=%r, energy_tol=%r, C_ref given=%r", - bathtype, nbath, tol, energy_tol, C_ref is not None) - - eigref_out = None - e_delta_mp2 = None - # No bath (None or False) - if not bathtype: - C_bath, C_env = np.hsplit(C_env, [0]) - assert C_bath.shape[-1] == 0 - # Full environment as bath - elif bathtype == "full": - C_bath, C_env = np.hsplit(C_env, [C_env.shape[-1]]) - assert C_env.shape[-1] == 0 - # Project reference orbitals - elif C_ref is not None: - nref = C_ref.shape[-1] - if nref > 0: - C_env, eig = self.project_ref_orbitals(C_ref, C_env) - log.debug("Eigenvalues of projected bath orbitals:\n%s", eig[:nref]) - log.debug("Largest remaining: %s", eig[nref:nref+3]) - C_bath, C_env = np.hsplit(C_env, [nref]) - # Make new bath orbitals - else: - #if bathtype.startswith("mp2"): - if bathtype == "local": - C_bath, C_env = self.make_local_bath(C_env, nbath=nbath, tol=tol) - - elif bathtype == "mp2-natorb": - C_bath, C_env, e_delta_mp2, eigref_out = self.make_mp2_bath( - self.C_occclst, self.C_virclst, - kind, - c_occenv=C_occenv, c_virenv=C_virenv, - eigref=eigref, - nbath=nbath, tol=tol, energy_tol=energy_tol, - **kwargs) - # MF type bath - else: - C_bath, C_env, eigref_out = self.make_mf_bath(C_env, kind, bathtype=bathtype, eigref=eigref, nbath=nbath, tol=tol, - **kwargs) - - # MP2 correction [only if there are environment (non bath) states, else = 0.0] - #if self.mp2_correction and C_env.shape[-1] > 0: - kind2n = {"occ" : 0, "vir" : 1} - if self.mp2_correction[kind2n[kind]] and C_env.shape[-1] > 0: - if e_delta_mp2 is None: - if kind == "occ": - log.debug("Calculating occupied MP2 correction.") - Co_act = np.hstack((self.C_occclst, C_bath)) - Co_all = np.hstack((Co_act, C_env)) - Cv = self.C_virclst - e_delta_mp2 = self.get_mp2_correction(Co_all, Cv, Co_act, Cv) - elif kind == "vir": - log.debug("Calculating virtual MP2 correction.") - Cv_act = np.hstack((self.C_virclst, C_bath)) - Cv_all = np.hstack((Cv_act, C_env)) - Co = self.C_occclst - e_delta_mp2 = self.get_mp2_correction(Co, Cv_all, Co, Cv_act) - - else: - log.debug("No MP2 correction.") - e_delta_mp2 = 0.0 - - return C_bath, C_env, e_delta_mp2, eigref_out - -# ================================================================================================ # - -def make_mf_bath(self, C_env, kind, bathtype, eigref=None, nbath=None, tol=None, **kwargs): - """Make mean-field bath orbitals. - - Parameters - ---------- - C_env : ndarray - Environment orbital for bath orbital construction. - kind : str - Occcupied or virtual bath orbitals. - - Returns - ------- - C_bath : ndarray - Matsubara bath orbitals. - C_env : ndarray - Remaining environment orbitals. - """ - - if kind == "occ": - mask = self.base.mo_occ > 0 - elif kind == "vir": - mask = self.base.mo_occ == 0 - - S = self.base.ovlp - CSC_loc = np.linalg.multi_dot((self.C_local.T, S, self.base.mo_coeff[:,mask])) - CSC_env = np.linalg.multi_dot((C_env.T, S, self.base.mo_coeff[:,mask])) - e = self.base.mo_energy[mask] - - # Matsubara points - if bathtype == "power": - power = kwargs.get("power", 1) - kernel = e**power - B = einsum("xi,i,ai->xa", CSC_env, kernel, CSC_loc) - elif bathtype == "matsubara": - npoints = kwargs.get("npoints", 1000) - beta = kwargs.get("beta", 100.0) - wn = (2*np.arange(npoints)+1)*np.pi/beta - kernel = wn[np.newaxis,:] / np.add.outer(e**2, wn**2) - B = einsum("xi,iw,ai->xaw", CSC_env, kernel, CSC_loc) - B = B.reshape(B.shape[0], B.shape[1]*B.shape[2]) - # For testing - elif bathtype == "random": - B = 2*np.random.rand(CSC_env.shape[0], 500)-1 - else: - raise ValueError("Unknown bathtype: %s" % bathtype) - - P = np.dot(B, B.T) - e, R = np.linalg.eigh(P) - assert np.all(e > -1e-13) - e, R = e[::-1], R[:,::-1] - C_env = np.dot(C_env, R) - - # Reorder here - if False: - with open("bath-%s-%s.txt" % (self.name, kind), "ab") as f: - np.savetxt(f, e[np.newaxis]) - - # Here we reorder the eigenvalues - if True: - if eigref is not None: - log.debug("eigref given: performing reordering of eigenpairs.") - # Get reordering array - reorder, cost = eigassign(eigref[0], eigref[1], e, C_env, b=S, cost_matrix="er/v") - log.debug("Optimized linear assignment cost=%.3e", cost) - - e = e[reorder] - C_env = C_env[:,reorder] - - if False: - with open("bath-%s-%s-ordered.txt" % (self.name, kind), "ab") as f: - np.savetxt(f, e[np.newaxis]) - - # Reference for future calculation - eigref_out = (e.copy(), C_env.copy()) - - # nbath takes preference - if nbath is not None: - - if isinstance(nbath, (float, np.floating)): - assert nbath >= 0.0 - assert nbath <= 1.0 - nbath_int = int(nbath*len(e) + 0.5) - log.info("nbath = %.1f %% -> nbath = %d", nbath*100, nbath_int) - nbath = nbath_int - - if tol is not None: - log.warning("Warning: tolerance is %.g, but nbath=%r is used.", tol, nbath) - nbath = min(nbath, len(e)) - elif tol is not None: - nbath = sum(e >= tol) - else: - raise ValueError("Neither nbath nor tol specified.") - log.debug("Eigenvalues of projector into %s bath space", kind) - log.debug("%d included eigenvalues:\n%r", nbath, e[:nbath]) - log.debug("%d excluded eigenvalues (first 3):\n%r", (len(e)-nbath), e[nbath:nbath+3]) - log.debug("%d excluded eigenvalues (all):\n%r", (len(e)-nbath), e[nbath:]) - - C_bath, C_env = np.hsplit(C_env, [nbath]) - - return C_bath, C_env, eigref_out - -# ================================================================================================ # - -def run_mp2(self, c_occ, c_vir, c_occenv=None, c_virenv=None, canonicalize=True, eris=None, local_dm=False): - """Select virtual space from MP2 natural orbitals (NOs) according to occupation number. - - Parameters - ---------- - c_occ : ndarray - Active occupied orbitals. - c_vir : ndarray - Active virtual orbitals. - c_occenv : ndarray, optional - Frozen occupied orbitals. - c_virenv : ndarray, optional - Frozen virtual orbitals. - canonicalize : bool, tuple(2), optional - Canonicalize occupied/virtual active orbitals. - eris: TODO - - Returns - ------- - TODO - """ - - # Canonicalization [optional] - if canonicalize in (True, False): - canonicalize = 2*[canonicalize] - f = self.base.get_fock() - fo = np.linalg.multi_dot((c_occ.T, f, c_occ)) - fv = np.linalg.multi_dot((c_vir.T, f, c_vir)) - if canonicalize[0]: - eo, ro = np.linalg.eigh(fo) - c_occ = np.dot(c_occ, ro) - else: - eo = np.diag(fo) - if canonicalize[1]: - ev, rv = np.linalg.eigh(fv) - c_vir = np.dot(c_vir, rv) - else: - ev = np.diag(fv) - - # Setup MP2 object - nao = c_occ.shape[0] - if c_occenv is None: - c_occenv = np.zeros((nao, 0)) - if c_virenv is None: - c_virenv = np.zeros((nao, 0)) - c_act = np.hstack((c_occ, c_vir)) - c_all = np.hstack((c_occenv, c_act, c_virenv)) - norb = c_all.shape[-1] - noccenv = c_occenv.shape[-1] - nvirenv = c_virenv.shape[-1] - frozen = list(range(noccenv)) + list(range(norb-nvirenv, norb)) - if self.use_pbc: - cls = pyscf.pbc.mp.MP2 - else: - cls = pyscf.mp.MP2 - mp2 = cls(self.mf, mo_coeff=c_all, frozen=frozen) - - # Integral transformation - t0 = timer() - if eris is None: - - # New unfolding - if self.base.kcell is not None: - log.debug("ao2mo using base.get_eris") - eris = self.base.get_eris(mp2) - - # For PBC [direct_init to avoid expensive Fock rebuild] - elif self.use_pbc: - fock = np.linalg.multi_dot((c_act.T, f, c_act)) - # TRY NEW - if hasattr(self.mf.with_df, "_cderi") and isinstance(self.mf.with_df._cderi, np.ndarray): - log.debug("ao2mo using ao2mo_j3c.ao2mo_mp2") - #eris = pbc_gdf_ao2mo.ao2mo(mp2, fock=fock, mp2=True) - # TEST NEW - #mo_energy = np.hstack((eo, ev)) - #eris = ao2mo_j3c.ao2mo_mp2(mp2, mo_energy=mo_energy) - eris = ao2mo_j3c.ao2mo_mp2(mp2, fock=fock) - #assert np.allclose(eris.mo_energy, eris2.mo_energy) - #assert np.allclose(eris.ovov, eris2.ovov) - - else: - log.debug("ao2mo using mp2.ao2mo(direct_init=True)") - mo_energy = np.hstack((eo, ev)) - eris = mp2.ao2mo(direct_init=True, mo_energy=mo_energy, fock=fock) - # For molecular calculations with DF - elif hasattr(mp2, "with_df"): - log.debug("ao2mo using mp2.ao2mo(store_eris=True)") - eris = mp2.ao2mo(store_eris=True) - else: - log.debug("ao2mo using mp2.ao2mo") - eris = mp2.ao2mo() - # PySCF forgets to set this... - if eris.nocc is None: eris.nocc = c_occ.shape[-1] - - # Reuse perviously obtained integral transformation into N^2 sized quantity (rather than N^4) - else: - log.debug("Transforming previous eris.") - #raise NotImplementedError() - eris = self.transform_mp2_eris(eris, c_occ, c_vir) - #eris2 = mp2.ao2mo() - #eris2 = mp2.ao2mo(direct_init=True, mo_energy=np.hstack((eo, ev))) - #log.debug("Eris difference=%.3e", np.linalg.norm(eris.ovov - eris2.ovov)) - #assert np.allclose(eris.ovov, eris2.ovov) - t = (timer() - t0) - log.debug("Time for integral transformation [s]: %.3f (%s)", t, get_time_string(t)) - assert (eris.ovov is not None) - - t0 = timer() - e_mp2_full, t2 = mp2.kernel(eris=eris, hf_reference=True) - t = (timer() - t0) - log.debug("Time for MP2 kernel [s]: %.3f (%s)", t, get_time_string(t)) - e_mp2_full *= self.symmetry_factor - log.debug("Full MP2 energy= %12.8g htr", e_mp2_full) - - # Exact MP2 amplitudes - #if True and hasattr(self.base, "_t2_exact"): - if False: - c_mf_occ = self.base.mo_coeff[:,self.base.mo_occ>0] - c_mf_vir = self.base.mo_coeff[:,self.base.mo_occ==0] - s = self.base.ovlp - csco = np.linalg.multi_dot((c_mf_occ.T, s, c_occ)) - cscv = np.linalg.multi_dot((c_mf_vir.T, s, c_vir)) - t2_exact = einsum("ijab,ik,jl,ac,bd->klcd", self.base._t2_exact, csco, csco, cscv, cscv) - assert t2_exact.shape == t2.shape - log.info("Difference T2: %g", np.linalg.norm(t2 - t2_exact)) - t2 = t2_exact - - no, nv = t2.shape[0], t2.shape[2] - - # Bild T2 manually [testing] - #t2_man = np.zeros_like(t2) - #eris_ovov = np.asarray(eris.ovov).reshape(no,nv,no,nv) - #for i in range(no): - # gi = eris_ovov[i].transpose(1, 0, 2) - # ei = fo[i] + np.subtract.outer(fo, np.add.outer(fv, fv)) - # assert (gi.shape == ei.shape) - # t2i = - gi**2 / ei - # t2_man[i] = t2i - ##assert np.allclose(t2, t2_man) - ##1/0 - - # Calculate local energy - # Project first occupied index onto local space - _, t2loc = self.get_local_amplitudes(mp2, None, t2, symmetrize=True) - - e_mp2 = self.symmetry_factor * mp2.energy(t2loc, eris) - log.debug("Local MP2 energy= %12.8g htr", e_mp2) - - # MP2 density matrix - if local_dm is True: - log.debug("Constructing DM from local T2 amplitudes.") - t2l, t2r = t2loc, t2loc - elif local_dm == "semi": - log.debug("Constructing DM from semi-local T2 amplitudes.") - t2l, t2r = t2loc, t2 - elif local_dm is False: - log.debug("Constructing DM from full T2 amplitudes.") - t2l, t2r = t2, t2 - # This is equivalent to: - # do, dv = pyscf.mp.mp2._gamma1_intermediates(mp2, eris=eris) - # do, dv = -2*do, 2*dv - else: - raise ValueError("Unknown value for local_dm: %r" % local_dm) - # Playing with fire! - #dmo = 2*(2*einsum("ik...,jk...->ij", t2l, t2r) - # - einsum("ik...,kj...->ij", t2l, t2r)) - #dmv = 2*(2*einsum("...ac,...bc->ab", t2l, t2r) - # - einsum("...ac,...cb->ab", t2l, t2r)) - dmo = 2*(2*einsum("ikab,jkab->ij", t2l, t2r) - - einsum("ikab,kjab->ij", t2l, t2r)) - dmv = 2*(2*einsum("ijac,ijbc->ab", t2l, t2r) - - einsum("ijac,ijcb->ab", t2l, t2r)) - if local_dm == "semi": - dmo = (dmo + dmo.T)/2 - dmv = (dmv + dmv.T)/2 - - # Rotate back to input coeffients (undo canonicalization) - if canonicalize[0]: - t2 = einsum("ij...,xi,yj->xy...", t2, ro, ro) - dmo = np.linalg.multi_dot((ro, dmo, ro.T)) - #g = eris.ovov[:].reshape((no, nv, no, nv)) - #g = einsum("iajb,xi,yj->xayb", g, ro, ro) - #eris.ovov = g.reshape((no*nv, no*nv)) - #eris.mo_coeff = None - if canonicalize[1]: - t2 = einsum("...ab,xa,yb->...xy", t2, rv, rv) - dmv = np.linalg.multi_dot((rv, dmv, rv.T)) - #g = eris.ovov[:].reshape((no, nv, no, nv)) - #g = einsum("iajb,xa,yb->ixjy", g, rv, rv) - #eris.ovov = g.reshape((no*nv, no*nv)) - #eris.mo_coeff = None - - assert np.allclose(dmo, dmo.T) - assert np.allclose(dmv, dmv.T) - - return t2, eris, dmo, dmv, e_mp2 - -def run_mp2_general(self, c_occ, c_vir, c_occ2=None, c_vir2=None, eris=None, canonicalize=True): - """Run MP2 calculations for general orbitals.. - - if c_occ1 == c_occ2 and c_vir1 == c_vir2, the PySCF kernel can be used - """ - - if canonicalize in (True, False): - canonicalize = 4*[canonicalize] - - if c_occ2 is None: - c_occ2 = c_occ - if c_vir2 is None: - c_vir2 = c_vir - - equal_c_occ = (c_occ is c_occ2) - equal_c_vir = (c_vir is c_vir2) - normal_mp2 = (equal_c_occ and equal_c_vir) - - # Different fock matrix for PBC with exxdiv? - coeffs_in = [c_occ, c_occ2, c_vir, c_vir2] - fock = self.base.get_fock() - - eigs = [] - rots = [] - coeffs = [] - for i in range(4): - f = np.linalg.multi_dot((coeffs_in[i].T, fock, coeffs_in[i])) - if canonicalize[i]: - if (i == 1 and equal_c_occ) or (i == 3 and equal_c_vir): - e, r = eigs[-1], rots[-1] - else: - e, r = np.linalg.eigh(f) - eigs.append(e) - rots.append(r) - coeffs.append(np.dot(coeffs_in[i], r)) - else: - eigs.append(np.diag(f)) - rots.append(None) - coeffs.append(coeffs_in[i]) - - sizes = [c.shape[-1] for c in coeffs] - - # Reordering [this function is its own inverse] - reorder = lambda x: (x[0], x[2], x[1], x[3]) - - # Integral transformation - if eris is None: - # Does not work for DF at the moment... - #assert (eris.ovov is not None) - # TEST - t0 = timer() - if getattr(self.mf, "with_df", False): - g_ovov = self.mf.with_df.ao2mo(reorder(coeffs)) - elif self.mf._eri is not None: - g_ovov = pyscf.ao2mo.general(self.mf._eri, reorder(coeffs)) - else: - # Out core... - # Temporary: - g_ovov = pyscf.ao2mo.general(self.mol, reorder(coeffs)) - - g_ovov = g_ovov.reshape(reorder(sizes)) - time_ao2mo = timer() - t0 - log.debug("Time for AO->MO transformation of ERIs: %s", get_time_string(time_ao2mo)) - # Reuse perviously obtained integral transformation into N^2 sized quantity (rather than N^4) - else: - raise NotImplementedError() - #eris = self.transform_mp2_eris(eris, Co, Cv) - ##eris2 = mp2.ao2mo() - ##log.debug("Eris difference=%.3e", np.linalg.norm(eris.ovov - eris2.ovov)) - ##assert np.allclose(eris.ovov, eris2.ovov) - #time_mo2mo = MPI.Wtime() - t0 - #log.debug("Time for MO->MO: %s", get_time_string(time_mo2mo)) - - # Make T2 amplitudes and energy - e2_full = 0.0 - t2 = np.zeros(sizes) - for i in range(sizes[0]): - g_iovv = g_ovov[i].transpose(1, 0, 2) - e_iovv = eigs[0][i] + np.subtract.outer(eigs[1], np.add.outer(eigs[2], eigs[3])) - assert (g_iovv.shape == e_iovv.shape) - t2[i] = g_iovv / e_iovv - #e2_full += (2*einsum("jab,jab", t2[i], g_iovv) - # - einsum("jab,jba", t2[i], g_iovv)) - - - e2_full *= self.symmetry_factor - log.debug("Full MP2 energy = %12.8g htr", e2_full) - - # Calculate local energy - # Project first occupied index onto local space - #_, pT2 = self.get_local_amplitudes(mp2, None, T2, symmetrize=False) - #_, pT2 = self.get_local_amplitudes(mp2, None, T2, variant="democratic") - #e_mp2 = self.symmetry_factor * mp2.energy(pT2, eris) - - ploc = self.get_local_projector(coeffs[0]) - t2loc = einsum("ix,i...->x...", ploc, t2) - - # MP2 density matrix - # In order to get a symmetric DM in the end we calculate it twice ASSUMING the normal symmetry of T2 - # (In reality it does not have this symmetry) - # This is different to symmetrizing the DM at the end (i.e. dm2 is not dm.T). - # Idealy, we would symmetrize T2 itself, but this is not possible here, since the dimensions to not match... - # Is what is done here still equivalent? - #if kind == "occupied": - # dm = 2*(2*einsum("ikab,jkab->ij", t2, t2) - # - einsum("ikab,kjab->ij", t2, t2)) - # dm2 = 2*(2*einsum("kiab,kjab->ij", t2, t2) - # - einsum("kiab,jkab->ij", t2, t2)) - # dm = (dm + dm2)/2 - - # r = rotations[0] - #elif kind == "virtual": - # dm = 2*(2*einsum("ijac,ijbc->ab", t2, t2) - # - einsum("ijac,ijcb->ab", t2, t2)) - # dm2 = 2*(2*einsum("ijca,ijcb->ab", t2, t2) - # - einsum("ijca,ijbc->ab", t2, t2)) - # dm = (dm + dm2)/2 - - # r = rotations[3] - #assert dm.shape[0] == dm.shape[1] - - # Here we ignore the exchange like contributions... - #dm_occ = 4*einsum("ikab,jkab->ij", t2, t2) - #dm_vir = 4*einsum("ijac,ijbc->ab", t2, t2) - dm_occ = 4*einsum("ikab,jkab->ij", t2loc, t2loc) - dm_vir = 4*einsum("ijac,ijbc->ab", t2loc, t2loc) - assert np.allclose(dm_occ, dm_occ.T) - assert np.allclose(dm_vir, dm_vir.T) - - # Undo canonicalization - if rots[0] is not None: - dm_occ = np.linalg.multi_dot((rots[0], dm_occ, rots[0].T)) - if rots[2] is not None: - dm_vir = np.linalg.multi_dot((rots[2], dm_vir, rots[2].T)) - - ## Determine symmetry - #dm_sym = (dm + dm.T) - #dm_anti = (dm - dm.T) - #norm_sym = np.linalg.norm(dm_sym) - #norm_anti = np.linalg.norm(dm_anti) - #sym = (norm_sym - norm_anti) / (norm_sym + norm_anti) - #log.info("Symmetry of DM = %.4g", sym) - ## Ignore antisymmetric part: - #dm = dm_sym - #assert np.allclose(dm, dm.T) - - #return e_mp2, eris, Doo, Dvv - return t2, dm_occ, dm_vir - -# ================================================================================================ # - -def transform_mp2_eris(self, eris, Co, Cv): - """Transform eris of kind (ov|ov) (occupied-virtual-occupied-virtual)""" - assert (eris is not None) - assert (eris.ovov is not None) - - S = self.base.ovlp - Co0, Cv0 = np.hsplit(eris.mo_coeff, [eris.nocc]) - #log.debug("eris.nocc = %d", eris.nocc) - no0 = Co0.shape[-1] - nv0 = Cv0.shape[-1] - no = Co.shape[-1] - nv = Cv.shape[-1] - - transform_occ = (no != no0 or not np.allclose(Co, Co0)) - if transform_occ: - Ro = np.linalg.multi_dot((Co.T, S, Co0)) - else: - Ro = np.eye(no) - transform_vir = (nv != nv0 or not np.allclose(Cv, Cv0)) - if transform_vir: - Rv = np.linalg.multi_dot((Cv.T, S, Cv0)) - else: - Rv = np.eye(nv) - R = np.block([ - [Ro, np.zeros((no, nv0))], - [np.zeros((nv, no0)), Rv]]) - - #govov = eris.ovov.reshape((no0, nv0, no0, nv0)) - # eris.ovov may be hfd5 dataset on disk -> allocate in memory with [:] - govov = eris.ovov[:].reshape((no0, nv0, no0, nv0)) - if transform_occ and transform_vir: - govov = einsum("xi,ya,zj,wb,iajb->xyzw", Ro, Rv, Ro, Rv, govov) - elif transform_occ: - govov = einsum("xi,zj,iajb->xazb", Ro, Ro, govov) - elif transform_vir: - govov = einsum("ya,wb,iajb->iyjw", Rv, Rv, govov) - eris.ovov = govov.reshape((no*nv, no*nv)) - eris.mo_coeff = np.hstack((Co, Cv)) - eris.fock = np.linalg.multi_dot((R, eris.fock, R.T)) - eris.mo_energy = np.diag(eris.fock) - return eris - -# ================================================================================================ # - -def get_mp2_correction(self, Co1, Cv1, Co2, Cv2): - """Calculate delta MP2 correction.""" - e_mp2_all, eris = self.run_mp2(Co1, Cv1)[:2] - e_mp2_act = self.run_mp2(Co2, Cv2, eris=eris)[0] - e_delta_mp2 = e_mp2_all - e_mp2_act - log.debug("MP2 correction: all=%.4g, active=%.4g, correction=%+.4g", - e_mp2_all, e_mp2_act, e_delta_mp2) - return e_delta_mp2 - -# ================================================================================================ # - -def make_mp2_bath(self, - c_occclst, c_virclst, - #C_env, - kind, - # For new MP2 bath: - #c_occenv=None, c_virenv=None, - c_occenv, c_virenv, - eigref=None, - nbath=None, tol=None, energy_tol=None, mp2_correction=None): - """Select occupied or virtual bath space from MP2 natural orbitals. - - The natural orbitals are calculated only including the local virtual (occupied) - cluster orbitals when calculating occupied (virtual) bath orbitals, i.e. they do not correspond - to the full system MP2 natural orbitals and are different for every cluster. - - Set nbath to a very high number or tol to -1 to get all bath orbitals. - - Parameters - ---------- - C_occclst : ndarray - Occupied cluster (fragment + DMET bath) orbitals. - C_virclst : ndarray - Virtual cluster (fragment + DMET bath) orbitals. - C_env : ndarray - Environment orbitals. These need to be off purely occupied character if kind=="occ" - and of purely virtual character if kind=="vir". - kind : str ["occ", "vir"] - Calculate occupied or virtual bath orbitals. - eigref : tuple(eigenvalues, eigenvectors), optional - Reference eigenvalues and eigenvectors from previous calculation for consistent sorting - (see also: eigref_out). - nbath : int, optional - Target number of bath orbitals. If given, tol is ignored. - The actual number of bath orbitals might be lower, if not enough - environment orbitals are available. - tol : float, optional - Occupation change tolerance for bath orbitals. Ignored if nbath is not None. - Should be chosen between 0 and 1. - - Returns - ------- - C_bath : ndarray - MP2 natural orbitals with the largest occupation change. - C_env : ndarray - Remaining MP2 natural orbitals. - e_delta_mp2 : float - MP2 correction energy (0 if self.mp2_correction == False) - eigref_out : tuple(eigenvalues, eigenvectors) - Reference eigenvalues and eigenvectors for future calculation for consistent sorting - (see also: eigref). - """ - if nbath is None and tol is None and energy_tol is None: - raise ValueError("nbath, tol, and energy_tol are None.") - if kind not in ("occ", "vir"): - raise ValueError("Unknown kind: %s", kind) - if mp2_correction is None: mp2_correction = self.mp2_correction[0 if kind == "occ" else 1] - kindname = {"occ": "occupied", "vir" : "virtual"}[kind] - - # All occupied and virtual orbitals - c_occall = np.hstack((c_occclst, c_occenv)) - c_virall = np.hstack((c_virclst, c_virenv)) - - # All occupied orbitals, only cluster virtual orbitals - if kind == "occ": - c_occ = c_occall - c_vir = c_virclst - c_env = c_occenv - t2, eris, dm, _, e_mp2_all = run_mp2( - self, c_occ, c_vir, c_occenv=None, c_virenv=c_virenv, - local_dm=False) - ncluster = c_occclst.shape[-1] - nenv = c_occ.shape[-1] - ncluster - - # All virtual orbitals, only cluster occupied orbitals - elif kind == "vir": - c_occ = c_occclst - c_vir = c_virall - c_env = c_virenv - t2, eris, _, dm, e_mp2_all = run_mp2( - self, c_occ, c_vir, c_occenv=c_occenv, c_virenv=None) - ncluster = c_virclst.shape[-1] - nenv = c_vir.shape[-1] - ncluster - - # Diagonalize environment-environment block of MP2 DM correction - # and rotate into natural orbital basis, with the orbitals sorted - # with decreasing (absolute) occupation change - # [Note that dm_occ is minus the change of the occupied DM] - - env = np.s_[ncluster:] - dm = dm[env,env] - dm_occ, dm_rot = np.linalg.eigh(dm) - assert (len(dm_occ) == nenv) - if np.any(dm_occ < -1e-12): - raise RuntimeError("Negative occupation values detected: %r" % dm_occ[dm_occ < -1e-12]) - dm_occ, dm_rot = dm_occ[::-1], dm_rot[:,::-1] - c_rot = np.dot(c_env, dm_rot) - - with open("mp2-bath-occupation.txt", "ab") as f: - #np.savetxt(f, dm_occ[np.newaxis], header="MP2 bath orbital occupation of cluster %s" % self.name) - np.savetxt(f, dm_occ, fmt="%.10e", header="%s MP2 bath orbital occupation of cluster %s" % (kindname.title(), self.name)) - - if self.opts.plot_orbitals: - #bins = np.hstack((-np.inf, np.logspace(-9, -3, 9-3+1), np.inf)) - bins = np.hstack((1, np.logspace(-3, -9, 9-3+1), -1)) - for idx, upper in enumerate(bins[:-1]): - lower = bins[idx+1] - mask = np.logical_and((dm_occ > lower), (dm_occ <= upper)) - if np.any(mask): - coeff = c_rot[:,mask] - log.info("Plotting MP2 bath density between %.0e and %.0e containing %d orbitals." % (upper, lower, coeff.shape[-1])) - dm = np.dot(coeff, coeff.T) - dset_idx = (4001 if kind == "occ" else 5001) + idx - self.cubefile.add_density(dm, dset_idx=dset_idx) - - # Reorder the eigenvalues and vectors according to the reference ordering, specified in eigref - if False: - if eigref is not None: - log.debug("eigref given: performing reordering of eigenpairs.") - # Get reordering array - S = self.base.ovlp - reorder, cost = eigassign(eigref[0], eigref[1], N, C_no, b=S, cost_matrix="er/v") - log.debug("Optimized linear assignment cost=%.3e", cost) - N = N[reorder] - C_no = C_no[:,reorder] - if False: - with open("MP2-natorb-%s-%s-ordered.txt" % (self.name, kind), "ab") as f: - np.savetxt(f, N[np.newaxis]) - - # Return ordered eigenpairs as a reference for future calculations - eigref_out = (dm_occ.copy(), c_rot.copy()) - - # --- Determine number of bath orbitals - # The number of bath orbitals can be determined in 3 ways, in decreasing priority: - # - # 1) Via nbath. If nbath is an integer, this number will be used directly. - # If nbath is a float between 0 and 1, it denotes the relative number of bath orbitals - # 2) Via an occupation tolerance: tol - # 3) Via an energy tolerance: energy_tol - # - e_delta_mp2 = None - if nbath is not None: - #if isinstance(nbath, (float, np.floating)): - # assert nbath >= 0.0 - # assert nbath <= 1.0 - # nbath_int = int(nbath*len(dm_occ) + 0.5) - # log.info("nbath = %.1f %% -> nbath = %d", nbath*100, nbath_int) - # nbath = nbath_int - - # Changed behavior!!! - #if isinstance(nbath, (float, np.floating)): - # assert ((nbath >= 0.0) and (nbath <= 1.0)) - # dm_occ_tot = np.sum(dm_occ) - # # Add bath orbitals - # for n in range(len(dm_occ)+1): - # dm_occ_n = np.sum(dm_occ[:n]) - # if (dm_occ_n / dm_occ_tot) >= nbath: - # break - # nbath = n - # log.info("(De)occupation of environment space: all %d orbitals= %.5f %d bath orbitals= %.5f ( %.3f%% )", - # len(dm_occ), dm_occ_tot, nbath, dm_occ_n, 100.0*dm_occ_n/dm_occ_tot) - - nbath = min(nbath, len(dm_occ)) - # Determine number of bath orbitals based on occupation tolerance - elif tol is not None: - nbath = sum(dm_occ >= tol) - #if tol >= 0.0: - # nbath = sum(dm_occ >= tol) - ## Changed behavior!!! - #else: - # tol = 1+tol - # assert ((tol >= 0.0) and (tol <= 1.0)) - # dm_occ_tot = np.sum(dm_occ) - # # Add bath orbitals - # for n in range(len(dm_occ)+1): - # dm_occ_n = np.sum(dm_occ[:n]) - # if (dm_occ_n / dm_occ_tot) >= tol: - # break - # nbath = n - # log.info("(De)occupation of environment space: all %d orbitals= %.5f %d bath orbitals= %.5f ( %.3f%% )", - # len(dm_occ), dm_occ_tot, nbath, dm_occ_n, 100.0*dm_occ_n/dm_occ_tot) - # assert (nbath <= len(dm_occ)) - - # Determine number of bath orbitals based on energy tolerance - elif energy_tol is not None: - _, t2_loc = self.get_local_amplitudes_general(None, t2, c_occ, c_vir) - # Rotate T2 and ERI into NO basis - no, nv = t2_loc.shape[1:3] - g = np.asarray(eris.ovov).reshape(no,nv,no,nv) - rot = np.block( - [[np.eye(ncluster), np.zeros((ncluster, nenv))], - [np.zeros((nenv, ncluster)), dm_rot]]) - if kind == "occ": - t2_loc = einsum("ij...,ix,jy->xy...", t2_loc, rot, rot) - g = einsum("iajb,ix,jy->xayb", g, rot, rot) - em = (2*einsum("ijab,iajb->ij", t2_loc, g) - - einsum("ijab,ibja->ij", t2_loc, g)) - elif kind == "vir": - t2_loc = einsum("...ab,ax,by->...xy", t2_loc, rot, rot) - g = einsum("iajb,ax,by->ixjy", g, rot, rot) - em = (2*einsum("ijab,iajb->ab", t2_loc, g) - - einsum("ijab,ibja->ab", t2_loc, g)) - - e_full = np.sum(em) - log.debug("Full energy=%g", e_full) - nbath, err = 0, e_full # in case nenv == 0 - for nbath in range(nenv+1): - act = np.s_[:ncluster+nbath] - e_act = np.sum(em[act,act]) - err = (e_full - e_act) - #log.debug("%3d bath orbitals: %8.6g , error: %8.6g", nbath, e_act, err) - - if abs(err) < energy_tol: - log.debug("%3d bath orbitals: %8.6g , error: %8.6g", nbath, e_act, err) - log.debug("Energy tolerance %.1e achieved with %d bath orbitals.", energy_tol, nbath) - break - - e_delta_mp2 = err - - # Check for degenerate subspaces, split by nbath - while (nbath > 0) and (nbath < nenv) and np.isclose(dm_occ[nbath-1], dm_occ[nbath], rtol=1e-5, atol=1e-11): - log.warning("Bath space is splitting a degenerate subspace of occupation numbers: %.8e and %.8e", - dm_occ[nbath-1], dm_occ[nbath]) - nbath += 1 - log.warning("Adding one additional bath orbital.") - - ###protect_degeneracies = False - ####protect_degeneracies = True - #### Avoid splitting within degenerate subspace - ###if protect_degeneracies and nno > 0: - ### #dgen_tol = 1e-10 - ### N0 = N[nno-1] - ### while nno < len(N): - ### #if abs(N[nno] - N0) <= dgen_tol: - ### if np.isclose(N[nno], N0, atol=1e-9, rtol=1e-6): - ### log.debug("Degenerate MP2 NO found: %.6e vs %.6e - adding to bath space.", N[nno], N0) - ### nno += 1 - ### else: - ### break - - # Split MP2 natural orbitals into bath and environment - c_bath, c_env = np.hsplit(c_rot, [nbath]) - - # Output some information - log.info("%s MP2 natural orbitals:" % kindname.title()) - db = dm_occ[:nbath] - de = dm_occ[nbath:] - fmt = " %4s: N= %4d max= %8.3g min= %8.3g avg= %8.3g sum= %8.3g ( %6.2f %%)" - if nbath > 0: - log.info(fmt, "Bath", nbath, max(db), min(db), np.mean(db), np.sum(db), 100*np.sum(db)/np.sum(dm_occ)) - else: - log.info(" No bath orbitals") - if nbath < nenv: - log.info(fmt, "Rest", nenv-nbath, max(de), min(de), np.mean(de), np.sum(de), 100*np.sum(de)/np.sum(dm_occ)) - else: - log.info(" No remaining orbitals") - - # Delta MP2 correction - no correction if all natural orbitals are already included (0 environment orbitals) - if mp2_correction and c_env.shape[-1] > 0: - if e_delta_mp2 is None: - if kind == "occ": - co_act = np.hstack((c_occclst, c_bath)) - #*_, e_mp2_act = self.run_mp2(co_act, c_vir, c_occenv=c_env, c_virenv=c_virenv) - *_, e_mp2_act = self.run_mp2(co_act, c_vir, c_occenv=c_env, c_virenv=c_virenv, eris=eris) - elif kind == "vir": - cv_act = np.hstack((c_virclst, c_bath)) - #*_, e_mp2_act = self.run_mp2(c_occ, cv_act, c_occenv=c_occenv, c_virenv=c_env) - *_, e_mp2_act = self.run_mp2(c_occ, cv_act, c_occenv=c_occenv, c_virenv=c_env, eris=eris) - - e_delta_mp2 = e_mp2_all - e_mp2_act - log.debug("MP2 correction (%s): all=%.4g, active=%.4g, correction=%+.4g", kindname, e_mp2_all, e_mp2_act, e_delta_mp2) - else: - e_delta_mp2 = 0.0 - - return c_bath, c_env, e_delta_mp2, eigref_out - -# ==== - -def make_local_bath(self, c_env, ao_indices=None, nbath=None, tol=1e-9): - - if ao_indices is None: - ao_indices = self.ao_indices - assert ao_indices is not None - p = self.base.make_ao_projector(ao_indices) - s = np.linalg.multi_dot((c_env.T, p, c_env)) - e, v = np.linalg.eigh(s) - e, v = e[::-1], v[:,::-1] - log.debug("Eigenvalues of local orbitals:\n%r", e) - assert np.all(e > -1e-8), ("Negative eigenvalues found: %r" % e[e <= -1e-8]) - if nbath is not None: - nbath = min(nbath, len(e)) - elif tol is not None: - nbath = sum(e >= tol) - - c_env = np.dot(c_env, v) - c_bath, c_env = np.hsplit(c_env, [nbath]) - - if nbath > 0: - log.debug("%3d bath orbitals: largest=%6.3g, smallest=%6.3g.", - nbath, max(e[:nbath]), min(e[:nbath])) - else: - log.debug("No bath orbitals.") - if nbath < len(e): - log.debug("%3d environment orbitals: largest=%6.3g, smallest=%6.3g.", - (len(e)-nbath), max(e[nbath:]), min(e[nbath:])) - else: - log.debug("No environment orbitals.") - - return c_bath, c_env diff --git a/vayesta/ewf/OBSOLETE/ccsd_t.py b/vayesta/ewf/OBSOLETE/ccsd_t.py deleted file mode 100644 index 7d1e4b7b7..000000000 --- a/vayesta/ewf/OBSOLETE/ccsd_t.py +++ /dev/null @@ -1,338 +0,0 @@ -import logging -import numpy as np -from pyscf import lib - - -from quanterm.core.util import einsum - -__all__ = [ - "ccsd_t", - "kernel", - "kernel_new", - ] - -log = logging.getLogger(__name__) - -def ccsd_t(t1, t2, t1loc, t2loc, eris, variant=1): - """JCP 94, 442 (1991); DOI:10.1063/1.460359. Error in Eq (1), should be [ia] >= [jb] >= [kc] - t3 as ijkabc - """ - - t1T = t1.T - t1locT = t1loc.T - t2T = t2.transpose(2,3,0,1) - t2locT = t2loc.transpose(2,3,0,1) - #t2locT = t2T.copy() - - nocc, nvir = t1.shape - #mo_e = eris.fock.diagonal() - # Correct for PBC with exxdiv?? - mo_e = eris.mo_energy - e_occ, e_vir = mo_e[:nocc], mo_e[nocc:] - eijk = lib.direct_sum('i,j,k->ijk', e_occ, e_occ, e_occ) - eijk2 = np.add.outer(e_occ, np.add.outer(e_occ, e_occ)) - assert np.allclose(eijk, eijk2) - - eris_vvov = eris.get_ovvv().conj().transpose(1,3,0,2) - eris_vooo = np.asarray(eris.ovoo).conj().transpose(1,0,3,2) - eris_vvoo = np.asarray(eris.ovov).conj().transpose(1,3,0,2) - fvo = eris.fock[nocc:,:nocc] - - def get_w_full(a, b, c): - w = einsum('if,fkj->ijk', eris_vvov[a,b], t2T[c,:]) - w-= einsum('ijm,mk->ijk', eris_vooo[a,:], t2T[b,c]) - return w - - def get_w_loc(a, b, c): - w = einsum('if,fkj->ijk', eris_vvov[a,b], t2locT[c,:]) - w-= einsum('ijm,mk->ijk', eris_vooo[a,:], t2locT[b,c]) - return w - - def get_v_full(a, b, c): - v = einsum('ij,k->ijk', eris_vvoo[a,b], t1T[c]) - v+= einsum('ij,k->ijk', t2T[a,b], fvo[c]) - return v - - def get_v_loc(a, b, c): - v = einsum('ij,k->ijk', eris_vvoo[a,b], t1locT[c]) - v+= einsum('ij,k->ijk', t2locT[a,b], fvo[c]) - return v - - if variant == 1: - - get_w = get_w_loc - - def get_z(a, b, c): - w = get_w_full(a, b, c) - v = get_v_full(a, b, c) - z = r3(w + v/2) - return z - else: - - get_w = get_w_full - - def get_z(a, b, c): - w = get_w_loc(a, b, c) - v = get_v_loc(a, b, c) - z = r3(w + v/2) - return z - - et = 0 - for a in range(nvir): - for b in range(a+1): - for c in range(b+1): - d3 = eijk - e_vir[a] - e_vir[b] - e_vir[c] - if a == c: # a == b == c - d3 *= 6 - elif a == b or b == c: - d3 *= 2 - - # local W - wabc = get_w(a, b, c) - wacb = get_w(a, c, b) - wbac = get_w(b, a, c) - wbca = get_w(b, c, a) - wcab = get_w(c, a, b) - wcba = get_w(c, b, a) - # Z - zabc = get_z(a, b, c) / d3 - zacb = get_z(a, c, b) / d3 - zbac = get_z(b, a, c) / d3 - zbca = get_z(b, c, a) / d3 - zcab = get_z(c, a, b) / d3 - zcba = get_z(c, b, a) / d3 - - et += einsum('ijk,ijk', wabc, zabc.conj()) - et += einsum('ikj,ijk', wacb, zabc.conj()) - et += einsum('jik,ijk', wbac, zabc.conj()) - et += einsum('jki,ijk', wbca, zabc.conj()) - et += einsum('kij,ijk', wcab, zabc.conj()) - et += einsum('kji,ijk', wcba, zabc.conj()) - - if True: - et += einsum('ijk,ijk', wacb, zacb.conj()) - et += einsum('ikj,ijk', wabc, zacb.conj()) - et += einsum('jik,ijk', wcab, zacb.conj()) - et += einsum('jki,ijk', wcba, zacb.conj()) - et += einsum('kij,ijk', wbac, zacb.conj()) - et += einsum('kji,ijk', wbca, zacb.conj()) - - if True: - et += einsum('ijk,ijk', wbac, zbac.conj()) - et += einsum('ikj,ijk', wbca, zbac.conj()) - et += einsum('jik,ijk', wabc, zbac.conj()) - et += einsum('jki,ijk', wacb, zbac.conj()) - et += einsum('kij,ijk', wcba, zbac.conj()) - et += einsum('kji,ijk', wcab, zbac.conj()) - - if True: - et += einsum('ijk,ijk', wbca, zbca.conj()) - et += einsum('ikj,ijk', wbac, zbca.conj()) - et += einsum('jik,ijk', wcba, zbca.conj()) - et += einsum('jki,ijk', wcab, zbca.conj()) - et += einsum('kij,ijk', wabc, zbca.conj()) - et += einsum('kji,ijk', wacb, zbca.conj()) - - if True: - et += einsum('ijk,ijk', wcab, zcab.conj()) - et += einsum('ikj,ijk', wcba, zcab.conj()) - et += einsum('jik,ijk', wacb, zcab.conj()) - et += einsum('jki,ijk', wabc, zcab.conj()) - et += einsum('kij,ijk', wbca, zcab.conj()) - et += einsum('kji,ijk', wbac, zcab.conj()) - - et += einsum('ijk,ijk', wcba, zcba.conj()) - et += einsum('ikj,ijk', wcab, zcba.conj()) - et += einsum('jik,ijk', wbca, zcba.conj()) - et += einsum('jki,ijk', wbac, zcba.conj()) - et += einsum('kij,ijk', wacb, zcba.conj()) - et += einsum('kji,ijk', wabc, zcba.conj()) - et *= 2 - #log.debug('CCSD(T) correction = %.12g', et) - - return et - -def r3(w): - return (4 * w + w.transpose(1,2,0) + w.transpose(2,0,1) - - 2 * w.transpose(2,1,0) - 2 * w.transpose(0,2,1) - - 2 * w.transpose(1,0,2)) - - -import ctypes -from pyscf.cc import _ccsd - -def kernel_new(t1, t2, t2loc, eris): - - nocc, nvir = t1.shape - nmo = nocc + nvir - - mo_e = eris.mo_energy.copy() - - gvvov = eris.get_ovvv().conj().transpose(1,3,0,2).copy() - gvooo = np.asarray(eris.ovoo).conj().transpose(1,0,3,2).copy() - gvvoo = np.asarray(eris.ovov).conj().transpose(1,3,0,2).copy() - - t1T = t1.T.copy() - t2T = t2.transpose(2,3,0,1).copy() - #t2T = t2.transpose(2,3,0,1).copy() - t2locT = t2loc.transpose(2,3,0,1).copy() - - fvo = eris.fock[nocc:,:nocc].copy() - - et = np.zeros(1) - - drv = _ccsd.libcc.ccsd_t_simple_emb - drv( - ctypes.c_int(nocc), ctypes.c_int(nvir), - mo_e.ctypes.data_as(ctypes.c_void_p), - # - t1T.ctypes.data_as(ctypes.c_void_p), - t2T.ctypes.data_as(ctypes.c_void_p), - t2locT.ctypes.data_as(ctypes.c_void_p), - # - fvo.ctypes.data_as(ctypes.c_void_p), - gvvov.ctypes.data_as(ctypes.c_void_p), - gvooo.ctypes.data_as(ctypes.c_void_p), - gvvoo.ctypes.data_as(ctypes.c_void_p), - # OUT - et.ctypes.data_as(ctypes.c_void_p), - ) - - return et[0] - - - -if True: - # FAST ADAPTION - import time - #import ctypes - import numpy - from pyscf import lib - from pyscf.lib import logger - #from pyscf.cc import _ccsd - - from pyscf.cc.ccsd_t import _sort_eri - - # JCP 94, 442 (1991); DOI:10.1063/1.460359. Error in Eq (1), should be [ia] >= [jb] >= [kc] - def kernel(mycc, t1, t2, t2loc, eris, verbose=logger.NOTE): - cpu1 = cpu0 = (time.clock(), time.time()) - log = logger.new_logger(mycc, verbose) - - t1 = t1.copy() - t2 = t2.copy() - t2loc = t2loc.copy() - - nocc, nvir = t1.shape - nmo = nocc + nvir - - dtype = numpy.result_type(t1, t2, eris.ovoo.dtype) - if mycc.incore_complete: - ftmp = None - eris_vvop = numpy.zeros((nvir,nvir,nocc,nmo), dtype) - else: - ftmp = lib.H5TmpFile() - eris_vvop = ftmp.create_dataset('vvop', (nvir,nvir,nocc,nmo), dtype) - - orbsym = _sort_eri(mycc, eris, nocc, nvir, eris_vvop, log) - - mo_energy, t1T, t2T, t2locT, vooo, fvo = \ - _sort_t2_vooo_(t1, t2, t2loc, eris) - cpu1 = log.timer_debug1('CCSD(T) sort_eri', *cpu1) - - cpu2 = list(cpu1) - orbsym = numpy.hstack((numpy.sort(orbsym[:nocc]),numpy.sort(orbsym[nocc:]))) - o_ir_loc = numpy.append(0, numpy.cumsum(numpy.bincount(orbsym[:nocc], minlength=8))) - v_ir_loc = numpy.append(0, numpy.cumsum(numpy.bincount(orbsym[nocc:], minlength=8))) - o_sym = orbsym[:nocc] - oo_sym = (o_sym[:,None] ^ o_sym).ravel() - oo_ir_loc = numpy.append(0, numpy.cumsum(numpy.bincount(oo_sym, minlength=8))) - nirrep = max(oo_sym) + 1 - - orbsym = orbsym.astype(numpy.int32) - o_ir_loc = o_ir_loc.astype(numpy.int32) - v_ir_loc = v_ir_loc.astype(numpy.int32) - oo_ir_loc = oo_ir_loc.astype(numpy.int32) - if dtype == numpy.complex: - raise RuntimeError() - else: - drv = _ccsd.libcc.CCsd_t_contract_emb - et_sum = numpy.zeros(1, dtype=dtype) - def contract(a0, a1, b0, b1, cache): - cache_row_a, cache_col_a, cache_row_b, cache_col_b = cache - drv(et_sum.ctypes.data_as(ctypes.c_void_p), - mo_energy.ctypes.data_as(ctypes.c_void_p), - t1T.ctypes.data_as(ctypes.c_void_p), - t2T.ctypes.data_as(ctypes.c_void_p), - # NEW: - t2locT.ctypes.data_as(ctypes.c_void_p), - vooo.ctypes.data_as(ctypes.c_void_p), - fvo.ctypes.data_as(ctypes.c_void_p), - ctypes.c_int(nocc), ctypes.c_int(nvir), - ctypes.c_int(a0), ctypes.c_int(a1), - ctypes.c_int(b0), ctypes.c_int(b1), - ctypes.c_int(nirrep), - o_ir_loc.ctypes.data_as(ctypes.c_void_p), - v_ir_loc.ctypes.data_as(ctypes.c_void_p), - oo_ir_loc.ctypes.data_as(ctypes.c_void_p), - orbsym.ctypes.data_as(ctypes.c_void_p), - cache_row_a.ctypes.data_as(ctypes.c_void_p), - cache_col_a.ctypes.data_as(ctypes.c_void_p), - cache_row_b.ctypes.data_as(ctypes.c_void_p), - cache_col_b.ctypes.data_as(ctypes.c_void_p)) - cpu2[:] = log.timer_debug1('contract %d:%d,%d:%d'%(a0,a1,b0,b1), *cpu2) - - # The rest 20% memory for cache b - mem_now = lib.current_memory()[0] - max_memory = max(0, mycc.max_memory - mem_now) - bufsize = (max_memory*.5e6/8-nocc**3*3*lib.num_threads())/(nocc*nmo) #*.5 for async_io - bufsize *= .5 #*.5 upper triangular part is loaded - bufsize *= .8 #*.8 for [a0:a1]/[b0:b1] partition - bufsize = max(8, bufsize) - log.debug('max_memory %d MB (%d MB in use)', max_memory, mem_now) - with lib.call_in_background(contract, sync=not mycc.async_io) as async_contract: - for a0, a1 in reversed(list(lib.prange_tril(0, nvir, bufsize))): - cache_row_a = numpy.asarray(eris_vvop[a0:a1,:a1], order='C') - if a0 == 0: - cache_col_a = cache_row_a - else: - cache_col_a = numpy.asarray(eris_vvop[:a0,a0:a1], order='C') - async_contract(a0, a1, a0, a1, (cache_row_a,cache_col_a, - cache_row_a,cache_col_a)) - - for b0, b1 in lib.prange_tril(0, a0, bufsize/8): - cache_row_b = numpy.asarray(eris_vvop[b0:b1,:b1], order='C') - if b0 == 0: - cache_col_b = cache_row_b - else: - cache_col_b = numpy.asarray(eris_vvop[:b0,b0:b1], order='C') - async_contract(a0, a1, b0, b1, (cache_row_a,cache_col_a, - cache_row_b,cache_col_b)) - - et_sum *= 2 - if abs(et_sum[0].imag) > 1e-4: - logger.warn(mycc, 'Non-zero imaginary part of CCSD(T) energy was found %s', - et_sum[0]) - et = et_sum[0].real - log.timer('CCSD(T)', *cpu0) - log.note('CCSD(T) correction = %.15g', et) - return et - - def _sort_t2_vooo_(t1, t2, t2loc, eris): - assert(t2.flags.c_contiguous) - assert(t2loc.flags.c_contiguous) - vooo = numpy.asarray(eris.ovoo).transpose(1,0,3,2).conj().copy() - nocc, nvir = t1.shape - - fvo = eris.fock[nocc:,:nocc].copy() - t1T = t1.T.copy() - t2T = lib.transpose(t2.reshape(nocc**2,nvir**2)) - t2T = lib.transpose(t2T.reshape(nvir**2,nocc,nocc), axes=(0,2,1), out=t2) - - t2locT = lib.transpose(t2loc.reshape(nocc**2,nvir**2)) - t2locT = lib.transpose(t2locT.reshape(nvir**2,nocc,nocc), axes=(0,2,1), out=t2loc) - - mo_energy = numpy.asarray(eris.mo_energy, order='C') - t2T = t2T.reshape(nvir,nvir,nocc,nocc) - t2locT = t2locT.reshape(nvir,nvir,nocc,nocc) - - return mo_energy, t1T, t2T, t2locT, vooo, fvo diff --git a/vayesta/ewf/OBSOLETE/eigtrace.py b/vayesta/ewf/OBSOLETE/eigtrace.py deleted file mode 100644 index 62c8b1ff1..000000000 --- a/vayesta/ewf/OBSOLETE/eigtrace.py +++ /dev/null @@ -1,80 +0,0 @@ -def eigassign(e1, v1, e2, v2, b=None, cost_matrix="e^2/v"): - """ - Parameters - ---------- - b : ndarray - If set, eigenvalues and eigenvectors belong to a generalized eigenvalue problem of the form Av=Bve. - cost_matrix : str - Defines the way to calculate the cost matrix. - """ - - if e1.shape != e2.shape: - raise ValueError("e1=%r with shape=%r and e2=%r with shape=%r are not compatible." % (e1, e1.shape, e2, e2.shape)) - if v1.shape != v2.shape: - raise ValueError("v1=%r with shape=%r and v2=%r with shape=%r are not compatible." % (v1, v1.shape, v2, v2.shape)) - if e1.shape[0] != v1.shape[-1]: - raise ValueError("e1=%r with shape=%r and v1=%r with shape=%r are not compatible." % (e1, e1.shape, v1, v1.shape)) - if e2.shape[0] != v2.shape[-1]: - raise ValueError("e2=%r with shape=%r and v2=%r with shape=%r are not compatible." % (e2, e2.shape, v2, v2.shape)) - - assert np.allclose(e1.imag, 0) - assert np.allclose(e2.imag, 0) - assert np.allclose(v1.imag, 0) - assert np.allclose(v2.imag, 0) - - # Define a cost matrix ("dist") which measures the difference of two eigenpairs (ei,vi), (e'j, v'j) - # of different eigenvalue problems - if b is None: - vmat = np.abs(np.dot(v1.T, v2)) - else: - vmat = np.abs(np.linalg.multi_dot((v1.T, b, v2))) - emat = np.abs(np.subtract.outer(e1, e2)) - - # relative energy difference - ematrel = emat / np.fmax(abs(e1), 1e-14)[:,np.newaxis] - - # Original formulation - if cost_matrix == "(1-v)*e": - dist = (1-vmat) * emat - elif cost_matrix == "(1-v)": - dist = (1-vmat) - elif cost_matrix == "1/v": - dist = 1/np.fmax(vmat, 1e-14) - elif cost_matrix == "v/e": - dist = -vmat / (emat + 1e-14) - elif cost_matrix == "e/v": - dist = emat / np.fmax(vmat, 1e-14) - elif cost_matrix == "er/v": - dist = ematrel / np.fmax(vmat, 1e-14) - elif cost_matrix == "e/v^2": - dist = emat / np.fmax(vmat, 1e-14)**2 - # This performed best in tests - elif cost_matrix == "e^2/v": - dist = emat**2 / np.fmax(vmat, 1e-14) - elif cost_matrix == "e^2/v**2": - dist = emat**2 / (vmat + 1e-14)**2 - elif cost_matrix == "e/sqrt(v)": - dist = emat / np.sqrt(vmat + 1e-14) - else: - raise ValueError("Unknown cost_matrix: %s" % cost_matrix) - - row, col = scipy.optimize.linear_sum_assignment(dist) - # The col indices are the new sorting - cost = dist[row,col].sum() - sort = col - return sort, cost - -def eigreorder_logging(e, reorder, log): - for i, j in enumerate(reorder): - # No reordering - if i == j: - continue - # Swap between two eigenvalues - elif reorder[j] == i: - if i < j: - log("Reordering eigenvalues %3d <-> %3d : %+6.3g <-> %+6.3g", j, i, e[j], e[i]) - # General reordering - else: - log("Reordering eigenvalues %3d --> %3d : %+6.3g --> %+6.3g", j, i, e[j], e[i]) - - diff --git a/vayesta/ewf/OBSOLETE/energy.py b/vayesta/ewf/OBSOLETE/energy.py deleted file mode 100644 index f6df8bf70..000000000 --- a/vayesta/ewf/OBSOLETE/energy.py +++ /dev/null @@ -1,518 +0,0 @@ -"""Local energy for EmbWF calculations. - -These require a projection of the some indices of the C1 and C2 -amplitudes. -""" - -import numpy as np - -from quanterm.core.util import * - -__all__ = [ - "get_local_amplitudes", - "get_local_amplitudes_general", - "get_local_energy", - ] - - -def project_amplitudes_to_fragment(self, cm, c1, c2, **kwargs): - """Wrapper for project_amplitude_to_fragment, where the mo coefficients are extracted from a MP2 or CC object.""" - - act = cm.get_frozen_mask() - occ = cm.mo_occ[act] > 0 - vir = cm.mo_occ[act] == 0 - c = cm.mo_coeff[:,act] - c_occ = c[:,occ] - c_vir = c[:,vir] - - p1 = p2 = None - if c1 is not None: - p1 = self.project_amplitude_to_fragment(c1, c_occ, c_vir, **kwargs) - if c2 is not None: - p2 = self.project_amplitude_to_fragment(c2, c_occ, c_vir, **kwargs) - return p1, p2 - - -def project_amplitude_to_fragment(self, c, c_occ=None, c_vir=None, partitioning=None, symmetrize=False): - """Get local contribution of amplitudes.""" - - if np.ndim(c) not in (2, 4): - raise NotImplementedError() - if partitioning not in ('first-occ', 'first-vir', 'democratic'): - raise ValueError("Unknown partitioning of amplitudes: %s", partitioning) - - # Projectors into fragment occupied and virtual space - if part in ("first-occ", "democratic"): - assert c_occ is not None - fo = self.get_fragment_projector(c_occ) - if part in ("first-vir", "democratic"): - assert c_vir is not None - fv = self.get_fragment_projector(c_vir) - # Inverse projectors needed - if part == "democratic": - ro = np.eye(fo.shape[-1]) - fo - rv = np.eye(fv.shape[-1]) - fv - - if np.ndim(c) == 2: - if part == "first-occ": - p = einsum("xi,ia->xa", fo, c) - elif part == "first-vir": - p = einsum("ia,xa->ix", c, fv) - elif part == "democratic": - p = einsum("xi,ia,ya->xy", fo, c, fv) - p += einsum("xi,ia,ya->xy", fo, c, rv) / 2.0 - p += einsum("xi,ia,ya->xy", ro, c, fv) / 2.0 - return p - - # ndim == 4: - - if partitioning == "first-occ": - p = einsum("xi,ijab->xjab", fo, c) - elif part == "first-vir": - p = einsum("ijab,xa->ijxb", c, fv) - elif part == "democratic": - - def project(p1, p2, p3, p4): - p = einsum("xi,yj,ijab,za,wb->xyzw", p1, p2, c, p3, p4) - return p - - # Factors of 2 due to ij,ab <-> ji,ba symmetry - # Denominators 1/N due to element being shared between N clusters - - # Quadruple F - # =========== - # This is fully included - p = project(fo, fo, fv, fv) - # Triple F - # ======== - # This is fully included - p += 2*project(fo, fo, fv, rv) - p += 2*project(fo, ro, fv, fv) - # Double F - # ======== - # P(FFrr) [This wrongly includes: 1x P(FFaa), instead of 0.5x - correction below] - p += project(fo, fo, rv, rv) - p += 2*project(fo, ro, fv, rv) - p += 2*project(fo, ro, rv, fv) - p += project(ro, ro, fv, fv) - # Single F - # ======== - # P(Frrr) [This wrongly includes: P(Faar) (where r could be a) - correction below] - p += 2*project(fo, ro, rv, rv) / 4.0 - p += 2*project(ro, ro, fv, rv) / 4.0 - - # Corrections - # =========== - # Loop over all other clusters x - for x in self.loop_fragments(exclude_self=True): - - xo = x.get_fragment_projector(c_occ) - xv = x.get_fragment_projector(c_vir) - - # Double correction - # ----------------- - # Correct for wrong inclusion of P(FFaa) - # The case P(FFaa) was included with prefactor of 1 instead of 1/2 - # We thus need to only correct by "-1/2" - p -= project(fo, fo, xv, xv) / 2.0 - p -= 2*project(fo, xo, fv, xv) / 2.0 - p -= 2*project(fo, xo, xv, fv) / 2.0 - p -= project(xo, xo, fv, fv) / 2.0 - - # Single correction - # ----------------- - # Correct for wrong inclusion of P(Faar) - # This corrects the case P(Faab) but overcorrects P(Faaa)! - p -= 2*project(fo, xo, xv, rv) / 4.0 - p -= 2*project(fo, xo, rv, xv) / 4.0 # If r == x this is the same as above -> overcorrection - p -= 2*project(fo, ro, xv, xv) / 4.0 # overcorrection - p -= 2*project(xo, xo, fv, rv) / 4.0 - p -= 2*project(xo, ro, fv, xv) / 4.0 # overcorrection - p -= 2*project(ro, xo, fv, xv) / 4.0 # overcorrection - - # Correct overcorrection - # The additional factor of 2 comes from how often the term was wrongly included above - p += 2*2*project(fo, xo, xv, xv) / 4.0 - p += 2*2*project(xo, xo, fv, xv) / 4.0 - - # Note that the energy should be invariant to symmetrization - if symmetrize: - p = (p + p.transpose(1,0,3,2)) / 2 - - return p - - -def get_local_energy(self, cm, p1, p2, eris): - """ - Parameters - ---------- - cm : pyscf[.pbc].cc.CCSD or pyscf[.pbc].mp.MP2 - PySCF coupled cluster or MP2 object. This function accesses: - cc.get_frozen_mask() - cc.mo_occ - p1 : ndarray - Locally projected C1 amplitudes. - p2 : ndarray - Locally projected C2 amplitudes. - eris : - PySCF eris object as returned by cc.ao2mo() - - Returns - ------- - e_loc : float - Local energy contribution. - """ - - # MP2 - if p1 is None: - e1 = 0 - # CC - else: - act = cc.get_frozen_mask() - occ = cc.mo_occ[act] > 0 - vir = cc.mo_occ[act] == 0 - f = eris.fock[occ][:,vir] - e1 = 2*np.sum(f * p1) - - if hasattr(eris, "ovvo"): - eris_ovvo = eris.ovvo - # MP2 only has eris.ovov - are these the same integrals? - else: - no, nv = p2.shape[1:3] - eris_ovvo = eris.ovov[:].reshape(no,nv,no,nv).transpose(0, 1, 3, 2).conj() - e2 = 2*einsum('ijab,iabj', p2, eris_ovvo) - e2 -= einsum('ijab,jabi', p2, eris_ovvo) - - self.log.info("Energy components: E1= % 16.8f Ha, E2=% 16.8f Ha", e1, e2) - if e1 > 1e-4 and 10*e1 > e2: - self.log.warning("WARNING: Large E1 component!") - - # Symmetry factor if fragment is repeated in molecule, (e.g. in hydrogen rings: only calculate one fragment) - e_frag = self.sym_factor * (e1 + e2) - - return e_frag - - -#def get_local_energy_parts(self, cc, C1, C2): - -# a = cc.get_frozen_mask() -# # Projector to local, occupied region -# S = self.mf.get_ovlp() -# C = cc.mo_coeff[:,a] -# CTS = np.dot(C.T, S) - -# # Project one index of T amplitudes -# l= self.indices -# r = self.not_indices -# o = cc.mo_occ[a] > 0 -# v = cc.mo_occ[a] == 0 - -# eris = cc.ao2mo() - -# def get_projectors(aos): -# Po = np.dot(CTS[o][:,aos], C[aos][:,o]) -# Pv = np.dot(CTS[v][:,aos], C[aos][:,v]) -# return Po, Pv - -# Lo, Lv = get_projectors(l) -# Ro, Rv = get_projectors(r) - -# # Nomenclature: -# # old occupied: i,j -# # old virtual: a,b -# # new occupied: p,q -# # new virtual: s,t -# T1_ll = einsum("pi,ia,sa->ps", Lo, C1, Lv) -# T1_lr = einsum("pi,ia,sa->ps", Lo, C1, Rv) -# T1_rl = einsum("pi,ia,sa->ps", Ro, C1, Lv) -# T1 = T1_ll + (T1_lr + T1_rl)/2 - -# F = eris.fock[o][:,v] -# e1 = 2*np.sum(F * T1) -# if not np.isclose(e1, 0): -# self.log.warning("Warning: large E1 component: %.8e" % e1) - -# #tau = cc.t2 + einsum('ia,jb->ijab', cc.t1, cc.t1) -# def project_T2(P1, P2, P3, P4): -# T2p = einsum("pi,qj,ijab,sa,tb->pqst", P1, P2, C2, P3, P4) -# return T2p - - -# def epart(P1, P2, P3, P4): -# T2_part = project_T2(P1, P2, P3, P4) -# e_part = (2*einsum('ijab,iabj', T2_part, eris.ovvo) -# - einsum('ijab,jabi', T2_part, eris.ovvo)) -# return e_part - -# energies = [] -# # 4 -# energies.append(epart(Lo, Lo, Lv, Lv)) -# # 3 -# energies.append(2*epart(Lo, Lo, Lv, Rv)) -# energies.append(2*epart(Lo, Ro, Lv, Lv)) -# assert np.isclose(epart(Lo, Lo, Rv, Lv), epart(Lo, Lo, Lv, Rv)) -# assert np.isclose(epart(Ro, Lo, Lv, Lv), epart(Lo, Ro, Lv, Lv)) - -# energies.append( epart(Lo, Lo, Rv, Rv)) -# energies.append(2*epart(Lo, Ro, Lv, Rv)) -# energies.append(2*epart(Lo, Ro, Rv, Lv)) -# energies.append( epart(Ro, Ro, Lv, Lv)) - -# energies.append(2*epart(Lo, Ro, Rv, Rv)) -# energies.append(2*epart(Ro, Ro, Lv, Rv)) -# assert np.isclose(epart(Ro, Lo, Rv, Rv), epart(Lo, Ro, Rv, Rv)) -# assert np.isclose(epart(Ro, Ro, Rv, Lv), epart(Ro, Ro, Lv, Rv)) - -# energies.append( epart(Ro, Ro, Rv, Rv)) - -# #e4 = e_aaaa -# #e3 = e_aaab + e_aaba + e_abaa + e_baaa -# #e2 = 0.5*(e_aabb + e_abab + e_abba + e_bbaa) - -# with open("energy-parts.txt", "a") as f: -# f.write((10*" %16.8e" + "\n") % tuple(energies)) - -##def get_local_energy_most_indices_2C(self, cc, C1, C2, eris=None, symmetry_factor=None): -## -## if symmetry_factor is None: -## symmetry_factor = self.symmetry_factor -## -## a = cc.get_frozen_mask() -## # Projector to local, occupied region -## S = self.mf.get_ovlp() -## C = cc.mo_coeff[:,a] -## CTS = np.dot(C.T, S) -## -## # Project one index of T amplitudes -## l= self.indices -## r = self.not_indices -## o = cc.mo_occ[a] > 0 -## v = cc.mo_occ[a] == 0 -## -## if eris is None: -## self.log.warning("Warning: recomputing AO->MO integral transformation") -## eris = cc.ao2mo() -## -## def get_projectors(aos): -## Po = np.dot(CTS[o][:,aos], C[aos][:,o]) -## Pv = np.dot(CTS[v][:,aos], C[aos][:,v]) -## return Po, Pv -## -## Lo, Lv = get_projectors(l) -## Ro, Rv = get_projectors(r) -## -## # Nomenclature: -## # old occupied: i,j -## # old virtual: a,b -## # new occupied: p,q -## # new virtual: s,t -## T1_ll = einsum("pi,ia,sa->ps", Lo, C1, Lv) -## T1_lr = einsum("pi,ia,sa->ps", Lo, C1, Rv) -## T1_rl = einsum("pi,ia,sa->ps", Ro, C1, Lv) -## T1 = T1_ll + (T1_lr + T1_rl)/2 -## -## F = eris.fock[o][:,v] -## e1 = 2*np.sum(F * T1) -## if not np.isclose(e1, 0): -## self.log.warning("Warning: large E1 component: %.8e" % e1) -## -## #tau = cc.t2 + einsum('ia,jb->ijab', cc.t1, cc.t1) -## def project_T2(P1, P2, P3, P4): -## T2p = einsum("pi,qj,ijab,sa,tb->pqst", P1, P2, C2, P3, P4) -## return T2p -## -## f3 = 1.0 -## f2 = 0.5 -## # 4 -## T2 = 1*project_T2(Lo, Lo, Lv, Lv) -## # 3 -## T2 += f3*(2*project_T2(Lo, Lo, Lv, Rv) # factor 2 for LLRL -## + 2*project_T2(Ro, Lo, Lv, Lv)) # factor 2 for RLLL -## ## 2 -## #T2 += f2*( project_T2(Lo, Lo, Rv, Rv) -## # + 2*project_T2(Lo, Ro, Lv, Rv) # factor 2 for RLRL -## # + 2*project_T2(Lo, Ro, Rv, Lv) # factor 2 for RLLR -## # + project_T2(Ro, Ro, Lv, Lv)) -## -## # 2 -## T2 += project_T2(Lo, Lo, Rv, Rv) -## T2 += 2*project_T2(Lo, Ro, Lv, Rv) # factor 2 for RLRL -## #T2 += 1*project_T2(Lo, Ro, Rv, Lv) # factor 2 for RLLR -## #T2 += project_T2(Ro, Ro, Lv, Lv) -## -## e2 = (2*einsum('ijab,iabj', T2, eris.ovvo) -## -einsum('ijab,jabi', T2, eris.ovvo)) -## -## e_loc = symmetry_factor * (e1 + e2) -## -## return e_loc -## -##def get_local_energy_most_indices(self, cc, C1, C2, variant=1): -## -## a = cc.get_frozen_mask() -## # Projector to local, occupied region -## S = self.mf.get_ovlp() -## C = cc.mo_coeff[:,a] -## CTS = np.dot(C.T, S) -## -## # Project one index of T amplitudes -## l= self.indices -## r = self.not_indices -## o = cc.mo_occ[a] > 0 -## v = cc.mo_occ[a] == 0 -## -## eris = cc.ao2mo() -## -## def get_projectors(aos): -## Po = np.dot(CTS[o][:,aos], C[aos][:,o]) -## Pv = np.dot(CTS[v][:,aos], C[aos][:,v]) -## return Po, Pv -## -## Lo, Lv = get_projectors(l) -## Ro, Rv = get_projectors(r) -## -## # ONE-ELECTRON -## # ============ -## pC1 = einsum("pi,ia,sa->ps", Lo, C1, Lv) -## pC1 += 0.5*einsum("pi,ia,sa->ps", Lo, C1, Rv) -## pC1 += 0.5*einsum("pi,ia,sa->ps", Ro, C1, Lv) -## -## F = eris.fock[o][:,v] -## e1 = 2*np.sum(F * pC1) -## if not np.isclose(e1, 0): -## self.log.warning("Warning: large E1 component: %.8e" % e1) -## -## # TWO-ELECTRON -## # ============ -## -## def project_C2_P1(P1): -## pC2 = einsum("pi,ijab->pjab", P1, C2) -## return pC2 -## -## def project_C2(P1, P2, P3, P4): -## pC2 = einsum("pi,qj,ijab,sa,tb->pqst", P1, P2, C2, P3, P4) -## return pC2 -## -## if variant == 1: -## -## # QUADRUPLE L -## # =========== -## pC2 = project_C2(Lo, Lo, Lv, Lv) -## -## # TRIPEL L -## # ======== -## pC2 += 2*project_C2(Lo, Lo, Lv, Rv) -## pC2 += 2*project_C2(Lo, Ro, Lv, Lv) -## -## # DOUBLE L -## # ======== -## # P(LLRR) [This wrongly includes: P(LLAA) - correction below] -## pC2 += project_C2(Lo, Lo, Rv, Rv) -## pC2 += 2*project_C2(Lo, Ro, Lv, Rv) -## pC2 += 2*project_C2(Lo, Ro, Rv, Lv) -## pC2 += project_C2(Ro, Ro, Lv, Lv) -## -## # SINGLE L -## # ======== -## # P(LRRR) [This wrongly includes: P(LAAR) - correction below] -## four_idx_from_occ = False -## -## if not four_idx_from_occ: -## pC2 += 0.25*2*project_C2(Lo, Ro, Rv, Rv) -## pC2 += 0.25*2*project_C2(Ro, Ro, Lv, Rv) -## else: -## pC2 += 0.5*2*project_C2(Lo, Ro, Rv, Rv) -## -## # CORRECTIONS -## # =========== -## for x in self.loop_clusters(exclude_self=True): -## Xo, Xv = get_projectors(x.indices) -## -## # DOUBLE CORRECTION -## # ----------------- -## # Correct for wrong inclusion of P(LLAA) -## # The case P(LLAA) was included with prefactor of 1 instead of 1/2 -## # We thus need to only correct by "-1/2" -## pC2 -= 0.5* project_C2(Lo, Lo, Xv, Xv) -## pC2 -= 0.5*2*project_C2(Lo, Xo, Lv, Xv) -## pC2 -= 0.5*2*project_C2(Lo, Xo, Xv, Lv) -## pC2 -= 0.5* project_C2(Xo, Xo, Lv, Lv) -## -## # SINGLE CORRECTION -## # ----------------- -## # Correct for wrong inclusion of P(LAAR) -## # This corrects the case P(LAAB) but overcorrects P(LAAA)! -## if not four_idx_from_occ: -## pC2 -= 0.25*2*project_C2(Lo, Xo, Xv, Rv) -## pC2 -= 0.25*2*project_C2(Lo, Xo, Rv, Xv) # If R == X this is the same as above -> overcorrection -## pC2 -= 0.25*2*project_C2(Lo, Ro, Xv, Xv) # overcorrection -## pC2 -= 0.25*2*project_C2(Xo, Xo, Lv, Rv) -## pC2 -= 0.25*2*project_C2(Xo, Ro, Lv, Xv) # overcorrection -## pC2 -= 0.25*2*project_C2(Ro, Xo, Lv, Xv) # overcorrection -## -## # Correct overcorrection -## pC2 += 0.25*2*2*project_C2(Lo, Xo, Xv, Xv) -## pC2 += 0.25*2*2*project_C2(Xo, Xo, Lv, Xv) -## -## else: -## pC2 -= 0.5*2*project_C2(Lo, Xo, Xv, Rv) -## pC2 -= 0.5*2*project_C2(Lo, Xo, Rv, Xv) # If R == X this is the same as above -> overcorrection -## pC2 -= 0.5*2*project_C2(Lo, Ro, Xv, Xv) # overcorrection -## -## # Correct overcorrection -## pC2 += 0.5*2*2*project_C2(Lo, Xo, Xv, Xv) -## -## e2 = (2*einsum('ijab,iabj', pC2, eris.ovvo) -## -einsum('ijab,jabi', pC2, eris.ovvo)) -## -## elif variant == 2: -## # QUADRUPLE L -## # =========== -## pC2 = project_C2(Lo, Lo, Lv, Lv) -## -## # TRIPEL L -## # ======== -## pC2 += 2*project_C2(Lo, Lo, Lv, Rv) -## pC2 += 2*project_C2(Lo, Ro, Lv, Lv) -## -## # DOUBLE L -## # ======== -## pC2 += project_C2(Lo, Lo, Rv, Rv) -## pC2 += 2*project_C2(Lo, Ro, Lv, Rv) -## pC2 += 2*project_C2(Lo, Ro, Rv, Lv) -## for x in self.loop_clusters(exclude_self=True): -## Xo, Xv = get_projectors(x.indices) -## pC2 -= project_C2(Lo, Xo, Lv, Xv) -## pC2 -= project_C2(Lo, Xo, Xv, Lv) -## -## # SINGLE L -## # ======== -## -## # This wrongly includes LXXX -## pC2 += 0.5*2*project_C2(Lo, Ro, Rv, Rv) -## for x in self.loop_clusters(exclude_self=True): -## Xo, Xv = get_projectors(x.indices) -## -## pC2 -= 0.5*2*project_C2(Lo, Xo, Rv, Xv) -## pC2 -= 0.5*2*project_C2(Lo, Xo, Xv, Rv) -## -## pC2 += 0.5*2*project_C2(Lo, Xo, Xv, Xv) -## -## e2 = (2*einsum('ijab,iabj', pC2, eris.ovvo) -## -einsum('ijab,jabi', pC2, eris.ovvo)) -## -## elif variant == 3: -## # QUADRUPLE + TRIPLE L -## # ==================== -## pC2 = project_C2_P1(Lo) -## pC2 += project_C2(Ro, Lo, Lv, Lv) -## for x in self.loop_clusters(exclude_self=True): -## Xo, Xv = get_projectors(x.indices) -## pC2 -= project_C2(Lo, Xo, Xv, Xv) -## -## e2 = (2*einsum('ijab,iabj', pC2, eris.ovvo) -## -einsum('ijab,jabi', pC2, eris.ovvo)) -## -## e_loc = e1 + e2 -## -## return e_loc diff --git a/vayesta/ewf/OBSOLETE/k2gamma_gdf.py b/vayesta/ewf/OBSOLETE/k2gamma_gdf.py deleted file mode 100644 index e496a52a1..000000000 --- a/vayesta/ewf/OBSOLETE/k2gamma_gdf.py +++ /dev/null @@ -1,364 +0,0 @@ -import logging -import ctypes -from timeit import default_timer as timer - -import numpy as np -import h5py - -import pyscf.pbc -import pyscf.lib -from pyscf.pbc.lib import kpts_helper -from pyscf.pbc.tools import k2gamma as k2gamma - -try: - from vayesta.ewf.OBSOLETE.util import * -except (SystemError, ImportError): - import functools - einsum = functools.partial(np.einsum, optimize=True) - -__all__ = ["k2gamma_gdf", "k2gamma_4c2e", "k2gamma_3c2e"] - -log = logging.getLogger(__name__) - -#DEFAULT_3C2E_VERSION = "python" -DEFAULT_3C2E_VERSION = "C" - -def k2gamma_gdf(mf, kpts, unfold_j3c=True, cderi_file=None): - """kpts is the mesh!""" - mf_sc = k2gamma.k2gamma(mf, kpts) - ncells = np.product(kpts) - assert ncells == (mf_sc.cell.natm // mf.cell.natm) - # Scale total energy to supercell size - # k2gamma GDF - if isinstance(mf.with_df, pyscf.pbc.df.GDF): - mf_sc = mf_sc.density_fit() - df = mf_sc.with_df - # Store integrals in memory - if unfold_j3c: - - j3c, j3c_neg = k2gamma_3c2e(mf.cell, mf.with_df, mf.kpts) - - if cderi_file: - df._cderi = cderi_file - with h5py.File(cderi_file, 'w') as f: - G = np.zeros((3,)) - kptij_lst = np.asarray([(G, G)]) - f["j3c-kptij"] = kptij_lst - f["j3c/0/0"] = j3c - f["j3c-/0/0"] = j3c_neg - else: - df._cderi = j3c - assert (j3c_neg is None) - - return mf_sc - -def k2gamma_4c2e(cell, gdf, kpts): - """Unfold 4c2e integrals from a k-point sampled GDF to the supercell.""" - nao = cell.nao_nr() - nk = len(kpts) - scell, phase = k2gamma.get_phase(cell, kpts) - phase = phase.T.copy() # (R,k) -> (k,R) - kconserv = kpts_helper.get_kconserv(cell, kpts) - eri_sc = np.zeros(4*[nk,nao], dtype=np.complex) - for i in range(nk): - for j in range(nk): - for k in range(nk): - l = kconserv[i,j,k] - kijkl = (kpts[i], kpts[j], kpts[k], kpts[l]) - eri_kijkl = gdf.get_eri(kpts=kijkl, compact=False).reshape(4*[nao]) - # Which conjugation order? - #eri_sc += einsum("ijkl,a,b,c,d->aibjckdl", eri_kijkl, phase[i].conj(), phase[j], phase[k].conj(), phase[l]) - eri_sc += einsum("ijkl,a,b,c,d->aibjckdl", eri_kijkl, phase[i], phase[j].conj(), phase[k], phase[l].conj()) - - eri_sc = eri_sc.reshape(4*[nk*nao]) / nk - - maximag = abs(eri_sc.imag).max() - if maximag > 1e-4: - log.error("ERROR: Large imaginary part in unfolded 4c2e integrals= %.2e !!!", maximag) - elif maximag > 1e-8: - log.warning("WARNING: Large imaginary part in unfolded 4c2e integrals= %.2e !", maximag) - return eri_sc.real - -def k2gamma_3c2e(cell, gdf, kpts, compact=True, use_ksymm=True, version=DEFAULT_3C2E_VERSION): - """Unfold 3c2e integrals from a k-point sampled GDF to the supercell.""" - nao = cell.nao_nr() - nk = len(kpts) - if gdf.auxcell is None: - gdf.build(with_j3c=False) - naux = gdf.auxcell.nao_nr() - scell, phase = k2gamma.get_phase(cell, kpts) - phase = phase.T.copy() # (R,k) -> (k,R) - kconserv = kpts_helper.get_kconserv(cell, kpts)[:,:,0].copy() - - if version == "python": - - if compact: - ncomp = nk*nao*(nk*nao+1)//2 - j3c = np.zeros((nk, naux, ncomp), dtype=np.complex) - else: - j3c = np.zeros((nk, naux, nk*nao, nk*nao), dtype=np.complex) - log.info("Memory for supercell 3c-integrals with shape %r= %s", list(j3c.shape), memory_string(j3c)) - - t0 = timer() - for ki in range(nk): - jmax = (ki+1) if use_ksymm else nk - for kj in range(jmax): - j3c_kpts, npos, nneg = load_j3c(cell, gdf, (kpts[ki], kpts[kj]), compact=False) - assert (nneg == 0) - #log.debug("naux=%d npos=%d nneg=%d at ki=%d kj=%d", naux, npos, nneg, ki, kj) - j3c_ij = einsum("Lab,i,j->Liajb", j3c_kpts, phase[ki], phase[kj].conj()).reshape(naux, nk*nao, nk*nao) - kl = kconserv[ki,kj] - if compact: - j3c[kl] += pyscf.lib.pack_tril(j3c_ij) - else: - j3c[kl] += j3c_ij - - if use_ksymm and kj < ki: - j3c_ij = j3c_ij.transpose(0, 2, 1).conj() - kl = kconserv[kj,ki] - if compact: - j3c[kl] += pyscf.lib.pack_tril(j3c_ij) - else: - j3c[kl] += j3c_ij - log.info("Time for unfolding AO basis= %.2g s", (timer()-t0)) - - # Rotate auxiliary dimension to yield real integrals - t0 = timer() - j3c = einsum("k...,kR->R...", j3c, phase) - log.info("Time for unfolding auxiliary basis= %.2g s", (timer()-t0)) - - - maximag = abs(j3c.imag).max() - if maximag > 1e-4: - log.error("ERROR: Large imaginary part in unfolded 3c2e integrals= %.2e !!!", maximag) - elif maximag > 1e-8: - log.warning("WARNING: Large imaginary part in unfolded 3c2e integrals= %.2e !", maximag) - else: - log.info("Max imaginary part in unfolded 3c2e integrals= %.2e", maximag) - j3c = j3c.real - - elif version == "C": - # Precompute all j3c_kpts - t0 = timer() - log.info("Loading k-point sampled 3c-integrals into memory...") - j3c_kpts = np.zeros((naux, nao, nao, nk, nk), dtype=np.complex) - log.info("Size of primitive cell 3c-integrals= %s", memory_string(j3c_kpts)) - if cell.dimension == 2: - j3c_kpts_neg = np.zeros((naux, nao, nao, nk, nk), dtype=np.complex) - - naux_pos = naux_neg = 0 - for ki in range(nk): - kjmax = (ki+1) if use_ksymm else nk - for kj in range(kjmax): - j3c_kpts[...,ki,kj], npos, nneg = load_j3c(cell, gdf, (kpts[ki], kpts[kj]), compact=False) - #log.debug("naux=%d npos=%d nneg=%d at ki=%d kj=%d", naux, npos, nneg, ki, kj) - naux_pos = max(npos, naux_pos) - naux_neg = max(nneg, naux_neg) - assert (cell.dimension == 2) or (nneg == 0) - # Transfer negative parts from j3c_kpts to j3c_kpts_neg - if cell.dimension == 2: - j3c_kpts_neg[...,ki,kj][:nneg] = j3c_kpts[...,ki,kj][npos:npos+nneg].copy() - j3c_kpts[...,ki,kj][npos:npos+nneg] = 0.0 - #assert abs(j3c_kpts_neg[...,ki,kj]).max() > 0 - #log.debug("before: %.2e", abs(j3c_kpts - #assert npos is None - if use_ksymm and kj < ki: - # Transpose AO indices - j3c_kpts[...,kj,ki] = j3c_kpts[...,ki,kj].transpose(0,2,1).conj() - if cell.dimension == 2: - j3c_kpts_neg[...,kj,ki] = j3c_kpts_neg[...,ki,kj].transpose(0,2,1).conj() - log.info("Time to load k-sampled j3c= %.2g s", (timer()-t0)) - - if compact: - ncomp = nk*nao*(nk*nao+1)//2 - j3c = np.zeros((nk, naux, ncomp)) - else: - j3c = np.zeros((nk, naux, nk*nao, nk*nao)) - log.info("Memory for supercell 3c-integrals with shape %r= %s", list(j3c.shape), memory_string(j3c)) - - t0 = timer() - max_imag = np.zeros(1) - libpbc = pyscf.lib.load_library("libpbc") - ierr = libpbc.j3c_k2gamma( - ctypes.c_int64(nk), ctypes.c_int64(nao), ctypes.c_int64(naux), - kconserv.ctypes.data_as(ctypes.c_void_p), - phase.ctypes.data_as(ctypes.c_void_p), - j3c_kpts.ctypes.data_as(ctypes.c_void_p), - ctypes.c_bool(compact), - # Out - j3c.ctypes.data_as(ctypes.c_void_p), - max_imag.ctypes.data_as(ctypes.c_void_p), - ) - assert (ierr == 0) - log.debug("Max imaginary element in j3c= %.2e", max_imag) - if max_imag > 1e-3: log.warning("WARNING: Large imaginary element in j3c= %.2e !", max_imag) - log.info("Time for unfolding in C= %.2g s", (timer()-t0)) - - if cell.dimension == 2: - if compact: - ncomp = nk*nao*(nk*nao+1)//2 - j3c_neg = np.zeros((nk, naux_neg, ncomp)) - else: - j3c_neg = np.zeros((nk, naux_neg, nk*nao, nk*nao)) - log.info("Memory for negative supercell 3c-integrals with shape %r= %s", list(j3c_neg.shape), memory_string(j3c_neg)) - - t0 = timer() - max_imag[0] = 0.0 - ierr = libpbc.j3c_k2gamma( - ctypes.c_int64(nk), ctypes.c_int64(nao), ctypes.c_int64(naux_neg), - kconserv.ctypes.data_as(ctypes.c_void_p), - phase.ctypes.data_as(ctypes.c_void_p), - j3c_kpts_neg.ctypes.data_as(ctypes.c_void_p), - ctypes.c_bool(compact), - # Out - j3c_neg.ctypes.data_as(ctypes.c_void_p), - max_imag.ctypes.data_as(ctypes.c_void_p), - ) - assert (ierr == 0) - log.debug("Max imaginary element in j3c= %.2e", max_imag) - if max_imag > 1e-3: log.warning("WARNING: Large imaginary element in j3c= %.2e !", max_imag) - log.info("Time for unfolding in C= %.2g s", (timer()-t0)) - else: - j3c_neg = None - - # Normalize - j3c /= np.sqrt(nk) - if j3c_neg is not None: j3c_neg /= np.sqrt(nk) - - if compact: - j3c = j3c.reshape(nk*naux, ncomp) - if j3c_neg is not None: - j3c_neg = j3c_neg.reshape(nk*naux_neg, ncomp) - else: - j3c = j3c.reshape(nk*naux, nk*nao, nk*nao) - assert (np.allclose(j3c, j3c.transpose(0,2,1))) - if j3c_neg is not None: - j3c_neg = j3c_neg.reshape(nk*naux_neg, nk*nao, nk*nao) - assert (np.allclose(j3c_neg, j3c_neg.transpose(0,2,1))) - - return j3c, j3c_neg - -def load_j3c(cell, gdf, kij, compact=False, include_sign=False): - """Load 3c-integrals into memory""" - nao = cell.nao_nr() - if gdf.auxcell is None: - gdf.build(with_j3c=False) - naux = gdf.auxcell.nao_nr() - if compact: - # Untested code, raise error to be on safe side - raise NotImplementedError - ncomp = nao*(nao+1)//2 - j3c_kij = np.zeros((naux, ncomp), dtype=np.complex) - else: - j3c_kij = np.zeros((naux, nao, nao), dtype=np.complex) - # Number of positive definite elements (in 3D simulations = all) - npos = nneg = 0 - blkstart = 0 - for lr, li, sign in gdf.sr_loop(kij, compact=compact): - blksize = lr.shape[0] - assert sign in (1, -1) - #log.debug("blksize=%d, sign=%d", blksize, sign) - if sign == 1: - npos += blksize - elif sign == -1: - nneg += blksize - # multiply by i (sqrt(-1)) - if include_sign: - lr, li = -li, lr - - blk = np.s_[blkstart:blkstart+blksize] - if compact: - j3c_kij[blk] += (lr+1j*li)#.reshape(blksize, ncomp) - else: - j3c_kij[blk] += (lr+1j*li).reshape(blksize, nao, nao) - blkstart += blksize - - assert (blkstart <= naux) - - return j3c_kij, npos, nneg - - -if __name__ == "__main__": - - from pyscf.pbc import gto, scf - - logging.basicConfig(filename="k2gamma.log", level=logging.DEBUG) - log = logging.getLogger("k2gamma.log") - - cell = gto.Cell() - cell.atom = ''' - O 0. 0. 0. - Ti 1. 0. 1. - ''' - #cell.basis = '6-31g' - cell.basis = "gth-dzvp-molopt-sr" - cell.pseudo = "gth-pade" - cell.a = 2.0*np.eye(3) - cell.verbose = 4 - cell.precision = 1e-6 - cell.build() - - nd = 2 - compact = True - #compact = False - - for i, k in enumerate(range(2, 20)): - #for i, k in enumerate(range(4, 20)): - if nd == 1: - kmesh = [1, 1, k] - elif nd == 2: - kmesh = [1, k, k] - elif nd == 3: - kmesh = [k, k, k] - kpts = cell.make_kpts(kmesh) - print("K-points: %r" % kpts) - nk = len(kpts) - norb = cell.nao_nr() - - # Primitive cell - nao = cell.nao_nr() - mf = scf.KRHF(cell, kpts) - mf = mf.density_fit() - t0 = timer() - mf.with_df.build() - t_pc_build = timer() - t0 - print("Time for primitive cell build: %.6f" % (t_pc_build)) - - # Supercell unfolding - t0 = timer() - scell, phase = k2gamma.get_phase(cell, kpts) - j3c, j3c_neg = k2gamma_3c2e(cell, mf.with_df, kpts, compact=compact) - t_pc_eri = timer() - t0 - print("Time for primitive cell ERI: %.6f" % (t_pc_eri)) - - # Supercell direct - nao_sc = scell.nao_nr() - mf_sc = scf.RHF(scell) - mf_sc = mf_sc.density_fit() - t0 = timer() - mf_sc.with_df.build() - t_sc_build = timer() - t0 - print("Time for supercell build: %.6f" % (t_sc_build)) - - # Test correctness - if True: - #if False: - if compact: - eri_3c = np.dot(j3c.T.conj(), j3c) - else: - eri_3c = np.einsum('Lpq,Lrs->pqrs', j3c.conj(), j3c) - eri_sc = mf_sc.with_df.get_eri(compact=compact) - if not compact: - eri_sc = eri_sc.reshape([nao_sc]*4) - assert (eri_3c.shape == eri_sc.shape) - err = abs(eri_3c - eri_sc).max() - print("MAX. ERROR: %.8e" % err) - assert err < 1e-8 - - # Write timings to file - if i == 0: - with open("k2gamma-timings.txt", "w") as f: - f.write("Nkpts GDF(prim) j3c-unfolding build+unfolding GDF(SC)\n") - - with open("k2gamma-timings.txt", "a") as f: - f.write("%3d %.5f %.5f %.5f %.5f\n" % (len(kpts), t_pc_build, t_pc_eri, t_pc_build+t_pc_eri, t_sc_build)) diff --git a/vayesta/ewf/OBSOLETE/tailored_cc.py b/vayesta/ewf/OBSOLETE/tailored_cc.py deleted file mode 100644 index 152d23976..000000000 --- a/vayesta/ewf/OBSOLETE/tailored_cc.py +++ /dev/null @@ -1,185 +0,0 @@ -# Taylored CC in iterations > 1 -#if True: -if self.base.tccT1 is not None: - log.debug("Adding tailorfunc for tailored CC.") - - tcc_mix_factor = 1 - - # Transform to cluster basis - act = cc.get_frozen_mask() - Co = mo_coeff[:,act][:,mo_occ[act]>0] - Cv = mo_coeff[:,act][:,mo_occ[act]==0] - Cmfo = self.base.mo_coeff[:,self.base.mo_occ>0] - Cmfv = self.base.mo_coeff[:,self.base.mo_occ==0] - S = self.mf.get_ovlp() - Ro = np.linalg.multi_dot((Co.T, S, Cmfo)) - Rv = np.linalg.multi_dot((Cv.T, S, Cmfv)) - - ttcT1, ttcT2 = self.transform_amplitudes(Ro, Rv, self.base.tccT1, self.base.tccT2) - #ttcT1 = 0 - #ttcT2 = 0 - - # Get occupied bath projector - #Pbath = self.get_local_projector(Co, inverse=True) - ##Pbath2 = self.get_local_projector(Co) - ##log.debug("%r", Pbath) - ##log.debug("%r", Pbath2) - ##1/0 - ##CSC = np.linalg.multi_dot((Co.T, S, self.C_env)) - ##Pbath2 = np.dot(CSC, CSC.T) - ##assert np.allclose(Pbath, Pbath2) - - ##CSC = np.linalg.multi_dot((Co.T, S, np.hstack((self.C_occclst, self.C_occbath)))) - #CSC = np.linalg.multi_dot((Co.T, S, np.hstack((self.C_bath, self.C_occbath)))) - #Pbath2 = np.dot(CSC, CSC.T) - #assert np.allclose(Pbath, Pbath2) - - #log.debug("DIFF %g", np.linalg.norm(Pbath - Pbath2)) - #log.debug("DIFF %g", np.linalg.norm(Pbath + Pbath2 - np.eye(Pbath.shape[-1]))) - - def tailorfunc(T1, T2): - # Difference of bath to local amplitudes - dT1 = ttcT1 - T1 - dT2 = ttcT2 - T2 - - # Project difference amplitudes to bath-bath block in occupied indices - #pT1, pT2 = self.project_amplitudes(Co, dT1, dT2, indices_T2=[0, 1]) - ###pT1, pT2 = self.project_amplitudes(Pbath, dT1, dT2, indices_T2=[0, 1]) - ###_, pT2_0 = self.project_amplitudes(Pbath, None, dT2, indices_T2=[0]) - ###_, pT2_1 = self.project_amplitudes(Pbath, None, dT2, indices_T2=[1]) - ###pT2 += (pT2_0 + pT2_1)/2 - - # Inverse=True gives the non-local (bath) part - pT1, pT2 = self.get_local_amplitudes(cc, dT1, dT2, inverse=True) - - #pT12, pT22 = self.get_local_amplitudes(cc, pT1, pT2, inverse=True, symmetrize=False) - #assert np.allclose(pT12, pT1) - #assert np.allclose(pT22, pT2) - #pT1, pT2 = self.get_local_amplitudes(cc, dT1, dT2, variant="democratic", inverse=True) - # Subtract to get non-local amplitudes - #pT1 = dT1 - pT1 - #pT2 = dT2 - pT2 - - log.debug("Norm of pT1=%6.2g, dT1=%6.2g, pT2=%6.2g, dT2=%6.2g", np.linalg.norm(dT1), np.linalg.norm(pT1), np.linalg.norm(dT2), np.linalg.norm(pT2)) - # Add projected difference amplitudes - T1 += tcc_mix_factor*pT1 - T2 += tcc_mix_factor*pT2 - return T1, T2 - - cc.tailorfunc = tailorfunc - -# Use FCI amplitudes -#if True: -#if False: -if self.coupled_bath: - log.debug("Coupling bath") - for x in self.loop_clusters(exclude_self=True): - if not x.amplitudes: - continue - log.debug("Coupling bath with fragment %s with solver %s", x.name, x.solver) - - #act = cc.get_frozen_mask() - #Co = mo_coeff[:,act][:,mo_occ[act]>0] - #Cv = mo_coeff[:,act][:,mo_occ[act]==0] - #no = Co.shape[-1] - #nv = Cv.shape[-1] - - #T1_ext = np.zeros((no, nv)) - #T2_ext = np.zeros((no, no, nv, nv)) - #Pl = [] - #Po = [] - #Pv = [] - - #for x in self.loop_clusters(exclude_self=True): - # if not x.amplitudes: - # continue - # log.debug("Amplitudes found in cluster %s with solver %s", x.name, x.solver) - # #C_x_occ = x.amplitudes["C_occ"] - # #C_x_vir = x.amplitudes["C_vir"] - # Cx_occ = x.C_occact - # Cx_vir = x.C_viract - # C1x = x.amplitudes["C1"] - # C2x = x.amplitudes["C2"] - - # actx = x.cc.get_frozen_mask() - # assert np.allclose(Cx_occ, x.cc.mo_coeff[:,actx][x.cc.mo_occ[actx]>0]) - # assert np.allclose(Cx_vir, x.cc.mo_coeff[:,actx][x.cc.mo_occ[actx]==0]) - - # assert Cx_occ.shape[-1] == C1x.shape[0] - # assert Cx_vir.shape[-1] == C1x.shape[1] - - # T1x, T2x = amplitudes_C2T(C1x, C2x) - - # # Project to local first index - # Plx = x.get_local_projector(Cx_occ) - # T1x = einsum("xi,ia->xa", Plx, T1x) - # T2x = einsum("xi,ijab->xjab", Plx, T2x) - - # # Transform to current basis - # S = self.mf.get_ovlp() - # Rox = np.linalg.multi_dot((Co.T, S, Cx_occ)) - # Rvx = np.linalg.multi_dot((Cv.T, S, Cx_vir)) - # T1x, T2x = self.transform_amplitudes(Rox, Rvx, T1x, T2x) - - # T1_ext += T1x - # T2_ext += T2x - - # Plx = np.linalg.multi_dot((x.C_local.T, S, Co)) - # Pox = np.linalg.multi_dot((x.C_occclst.T, S, Co)) - # Pvx = np.linalg.multi_dot((x.C_virclst.T, S, Cv)) - # Pl.append(Plx) - # Po.append(Pox) - # Pv.append(Pvx) - - #Pl = np.vstack(Pl) - #Pl = np.dot(Pl.T, Pl) - #Po = np.vstack(Po) - #Po = np.dot(Po.T, Po) - #Pv = np.vstack(Pv) - #Pv = np.dot(Pv.T, Pv) - - #def tailorfunc(T1, T2): - # # Difference amplitudes - # dT1 = (T1_ext - T1) - # dT2 = (T2_ext - T2) - # # Project to Px - # #pT1 = einsum("xi,ia->xa", Pext, dT1) - # #pT2 = einsum("xi,ijab->xjab", Pext, dT2) - # pT1 = einsum("xi,ya,ia->xy", Pl, Pv, dT1) - # pT2 = einsum("xi,yj,za,wb,ijab->xyzw", Pl, Po, Pv, Pv, dT2) - # # Symmetrize pT2 - # pT2 = (pT2 + pT2.transpose(1,0,3,2))/2 - # T1 += pT1 - # T2 += pT2 - # return T1, T2 - S = self.mf.get_ovlp() - - def tailorfunc(T1, T2): - T1out = T1.copy() - T2out = T2.copy() - for x in self.loop_clusters(exclude_self=True): - if not x.amplitudes: - continue - C1x, C2x = x.amplitudes["C1"], x.amplitudes["C2"] - T1x, T2x = amplitudes_C2T(C1x, C2x) - - # Remove double counting - # Transform to x basis [note that the sizes of the active orbitals will be changed] - Ro = np.linalg.multi_dot((x.C_occact.T, S, self.C_occact)) - Rv = np.linalg.multi_dot((x.C_viract.T, S, self.C_viract)) - T1x_dc, T2x_dc = self.transform_amplitudes(Ro, Rv, T1, T2) - dT1x = (T1x - T1x_dc) - dT2x = (T2x - T2x_dc) - - Px = x.get_local_projector(x.C_occact) - pT1x = einsum("xi,ia->xa", Px, dT1x) - pT2x = einsum("xi,ijab->xjab", Px, dT2x) - - # Transform back and add - pT1x, pT2x = self.transform_amplitudes(Ro.T, Rv.T, pT1x, pT2x) - T1out += pT1x - T2out += pT2x - - return T1out, T2out - - cc.tailorfunc = tailorfunc diff --git a/vayesta/ewf/WIP/basisopt.py b/vayesta/ewf/WIP/basisopt.py deleted file mode 100644 index c9c3d1dd8..000000000 --- a/vayesta/ewf/WIP/basisopt.py +++ /dev/null @@ -1,105 +0,0 @@ -import copy - -import numpy as np -import scipy -import scipy.optimize - -from matplotlib import pyplot as plt - - - -class BasisSet: - - def __init__(self, exp, coeff): - self.exp = exp - self.coeff = coeff - - def discard_diffuse(self, ndiscard=1): - self.exp = self.exp[:-ndiscard] - self.coeff = self.coeff[:-ndiscard] - - def radial_func(self, r): - f = np.sum(self.coeff[:,np.newaxis] * np.exp(np.outer(-self.exp, r**2)), axis=0) - return f - - def fit_to_basis(self, basis, fixed_exp=1): - exp = self.exp - exp_fixed = self.exp[:fixed_exp] - coeff = self.coeff - - maxr = 10.0 - grid = np.linspace(0, maxr, num=200) - - rad0 = basis.radial_func(grid) - rad1 = self.radial_func(grid) - - fig, axes = plt.subplots(ncols=2) - - axes[0].plot(grid, rad0, label="original") - axes[1].plot(grid, grid*rad0, label="original") - axes[0].plot(grid, rad1, label="truncated") - axes[1].plot(grid, grid*rad1, label="truncated") - - def objective_func(norm): - diff = (rad0 - norm*rad1) - return np.linalg.norm(diff) - - res = scipy.optimize.minimize(objective_func, x0=1) - norm = res.x - self.coeff *= norm - rad2 = self.radial_func(grid) - axes[0].plot(grid, rad2, label="normalized") - axes[1].plot(grid, grid*rad2, label="normalized") - - nexpopt = len(exp)-fixed_exp - - #maxrfit = 1/exp[-1] - maxrfit = np.sqrt(np.log(2) / exp[-1]) - - print(maxrfit) - weight = (grid < maxrfit) - - def objective_func(params): - e, c = np.split(params, [nexpopt]) - e = np.hstack((exp_fixed, e)) - rad = BasisSet(e, c).radial_func(grid) - diff = (rad - rad0) * weight - return np.linalg.norm(diff) - - x0=np.hstack((exp[fixed_exp:], coeff)) - res = scipy.optimize.minimize(objective_func, x0=x0) - e_opt, c_opt = np.split(res.x, [nexpopt]) - print(exp) - e_opt = np.hstack((exp_fixed, e_opt)) - print(e_opt) - basis_opt = BasisSet(e_opt, c_opt) - rad_opt = basis_opt.radial_func(grid) - - axes[0].plot(grid, rad_opt, label="optimized") - axes[1].plot(grid, grid*rad_opt, label="optimized") - axes[0].legend() - plt.show() - - - - -if __name__ == "__main__": - - #e = np.asarray([8.3744350009, 1.8058681460, 0.4852528328, 0.1658236932]) - #c = np.asarray([-0.0283380461, -0.1333810052, -0.3995676063, -0.5531027541]) - data = np.asarray([ - 5.3685662937, 0.0974901974, #0.0000000000 0.0000000000 -0.0510969367 0.0000000000 0.0000000000 - 1.9830691554, 0.1041996677, #0.0000000000 0.0000000000 -0.1693035193 0.0000000000 0.0000000000 - 0.6978346167, -0.3645093878, #0.0000000000 0.0000000000 -0.3579933930 0.0000000000 0.0000000000 - 0.2430968816, -0.6336931464, #1.0000000000 0.0000000000 -0.4327616531 1.0000000000 0.0000000000 - 0.0812865018, -0.1676727564, #0.0000000000 1.0000000000 -0.2457672757 0.0000000000 1.0000000000 - ]) - e = data[::2].copy() - c = data[1::2].copy() - - basis = BasisSet(e, c) - basis2 = copy.copy(basis) - basis2.discard_diffuse() - basis2.fit_to_basis(basis) - - diff --git a/vayesta/ewf/WIP/localao.py b/vayesta/ewf/WIP/localao.py deleted file mode 100644 index 53e49c9df..000000000 --- a/vayesta/ewf/WIP/localao.py +++ /dev/null @@ -1,219 +0,0 @@ -import numpy as np -import scipy -import scipy.linalg - -__all__ = ["localize_ao"] - -def localize_ao(mol, coeff, centers, power=1): - """coeff : initial coefficients""" - nao = coeff.shape[-1] - s = mol.intor_symmetric('int1e_ovlp') - assert np.allclose(np.linalg.multi_dot((coeff.T, s, coeff))-np.eye(nao), 0) - - atom_coords = mol.atom_coords() # In Bohr - atom_centers = np.asarray([atom_coords[i] for i in centers]) - #print("Atom centers:") - #print(atom_centers) - - # TODO: PBC - rmat_ao = mol.intor_symmetric("int1e_r") # In Bohr! - r2mat_ao = mol.intor_symmetric('int1e_r2') - #rmat = np.einsum("xab,ai,bj->xij", rmat_ao, coeff, coeff) - rmat = np.einsum("xpq,pa,qb->abx", rmat_ao, coeff, coeff) - assert np.allclose(rmat, rmat.transpose(1,0,2)) - #r2mat = np.einsum("xab,ai,bj->xij", r2mat_ao, coeff, coeff) - r2mat = np.einsum("pq,pa,qb->ab", r2mat_ao, coeff, coeff) - R2 = np.einsum("ix,ix->i", atom_centers, atom_centers) - - def _unpack_values(values): - """Unpack into skew-symmetric matrix""" - size = int(np.sqrt(2*values.size)) + 1 - idx = np.tril_indices(size, -1) - unpacked = np.zeros((size, size), dtype=values.dtype) - unpacked[idx] = values - unpacked = (unpacked - unpacked.T) - return unpacked - - def _pack_values(values, assert_symmetry=True): - assert (np.allclose(values, -values.T) or not assert_symmetry) - size = values.shape[-1] - idx = np.tril_indices(size, -1) - packed = values[idx] - return packed - - iteration = 0 - fval = None - - def objective_function(values, full=True): - nonlocal iteration, fval - iteration += 1 - s = _unpack_values(values) - u = scipy.linalg.expm(s) - #c = np.dot(coeff, u) - #d = np.einsum("ai,bi,xab->xi", c, c, dipole) - d = np.einsum("ai,bi,abx->ix", u, u, rmat) - fi = -2*np.einsum("ix,ix->i", atom_centers, d) - if power > 1: - assert full - if full: - # These contributions are invarient under unitary transformations and can be ignored - #fi += (R2 + np.einsum("ai,bi,ab->i", c, c, r2mat)) - d2 = np.einsum("ai,bi,ab->i", u, u, r2mat) - fi += (R2 + d2) - - fval = np.sum(fi**power) - if iteration % 1000 == 0: - print("Iteration %4d: value = %.5e" % (iteration, fval)) - return fval - - def gradient(values): - raise NotImplementedError() - # TODO - s = _unpack_values(values) - u = scipy.linalg.expm(s) - #u2 = np.eye(s.shape[-1]) - #rmat2 = np.einsum("ai,bj,abx->ijx", u, u, rmat) - #assert np.allclose(u, u2) - #c = np.dot(coeff, u) - #grad = (np.einsum("abx,bi,ix->ai", rmat, u, atom_centers) - # + np.einsum("bax,bi,ix->ai", rmat, u, atom_centers)) - #grad = 2*(np.einsum("ai,abx,bj,jx->ij", u, rmat, u, atom_centers) - # + np.einsum("ai,bax,bj,jx->ij", u, rmat, u, atom_centers)) - grad = 4 * np.einsum("xbz,by,yz->xy", rmat, u, atom_centers).T - #grad = 4 * np.einsum("xbz,by,yz->xy", rmat2, u, atom_centers).T - #grad = 4 * np.einsum("xbz,by,yz->xy", rmat2, u2, atom_centers).T - #print(grad) - #grad += np.einsum("iy,xbz,bi,iz->xy", s, rmat, u, atom_centers) - #grad += np.einsum("ax,abz,by,yz->xy", s, rmat, u, atom_centers) - grad[np.diag_indices(nao)] = 0 - np.set_printoptions(linewidth=300) - print(grad) - print(np.linalg.norm(grad - grad.T)) - - #grad = (grad - grad.T) - grad = _pack_values(grad, assert_symmetry=True) - #grad = _pack_values(grad, assert_symmetry=False) - return grad - - #np.random.seed(0) - s0 = _pack_values(np.zeros((nao, nao))) - #s0 += 1e-6*(np.random.rand(*s0.shape)-0.5) - #s0 += 1e-2*(np.random.rand(*s0.shape)-0.5) - #s0 += 2*(np.random.rand(*s0.shape)-0.5) - - #import numdifftools as nd - #m = 2 - #a = np.random.rand(m, m) - ##a = np.eye(m) - #s = np.random.rand(m, m) - #u = scipy.linalg.expm(s) - ##fval = lambda x : np.trace(np.dot(a, scipy.linalg.expm(x))) - #def fval(x): - # x = x.reshape(m, m) - # return np.trace(np.dot(a, scipy.linalg.expm(x))) - #grad = nd.Gradient(fval) - ##grad = nd.Jacobian(fval) - #s0 = np.random.rand(m, m) - #drv = grad(s0).reshape(m, m) - #print(drv) - - #def grad(x): - # x = x.reshape(m, m) - # u = scipy.linalg.expm(x) - # #return np.dot(u.T, a) - # g = np.dot(a, u.T) - # g = (g + g.T)/2 - # return g - # #return u.T - - #drv = grad(s0) - #print(drv) - - - #g2 = gradient(s0) - #print(g2.shape) - #print(g2) - - #grad = nd.Gradient(objective_function) - #drv = grad(s0) - #print("Gradient") - #print(drv.shape) - #print(drv) - #print(np.linalg.norm(g2-drv)) - - #1/0 - - fval = objective_function(s0) - print("Initial value = %.5e" % (fval)) - res = scipy.optimize.minimize(objective_function, x0=s0, args=(True,)) - s = _unpack_values(res.x) - u = scipy.linalg.expm(s) - coeff_loc = np.dot(coeff, u) - print("Final value = %.5e" % (fval)) - - def get_localization(coeff): - dip = np.einsum("ai,bi,xab->xi", coeff, coeff, rmat_ao) - omega = -2*np.einsum("ix,xi->i", atom_centers, dip) - omega += np.einsum("ai,bi,ab->i", coeff, coeff, r2mat_ao) - omega += np.einsum("ix,ix->i", atom_centers, atom_centers) - omega = np.sqrt(omega) - return omega - - print("Initial localizations:\n%r" % get_localization(coeff)) - print("Final localizations:\n%r" % get_localization(coeff_loc)) - - return coeff_loc - - - -if __name__ == "__main__": - import pyscf - import pyscf.gto - import pyscf.scf - import pyscf.lo - - #distance = 0.74 - #distance = 1.0 - distance = 0.5 - - #for d in [1.0, 2.0]: - for d in [0.0]: - - atom = "H 0 0 %f ; H 0 0 %f" % (d, d+distance) - basis = "cc-pVDZ" - mol = pyscf.gto.M(atom=atom, basis=basis) - - s = mol.intor_symmetric('int1e_ovlp') - coeff_lowdin = pyscf.lo.vec_lowdin(np.eye(s.shape[-1]), s) - - #centers = [mol.bas_coord(i) for i in range(100)] - centers = [l[0] for l in mol.ao_labels(None)] - coeff_loc = localize_ao(mol, coeff_lowdin, centers) - #coeff_loc = localize_ao(mol, coeff_lowdin, centers, power=2) - - 1/0 - - from util import create_orbital_file - #create_orbital_file(mol, "orbitals-in", coeffs) - #create_orbital_file(mol, "orbitals-out", coeffs_u) - create_orbital_file(mol, "orbitals-in", coeff_lowdin, filetype="cube") - create_orbital_file(mol, "orbitals-out", coeff_loc, filetype="cube") - - coeff_loc = localize_ao(mol, coeff_lowdin, centers, power=2) - create_orbital_file(mol, "orbitals-2-out", coeff_loc, filetype="cube") - - - 1/0 - - - dipol = mol.intor_symmetric("int1e_r", comp=3) - print(dipol * 0.52) - print(dipol.shape) - - hf = pyscf.scf.RHF(mol) - hf.kernel() - - dipol_mo = np.einsum("xab,ai,bj->xij", dipol, hf.mo_coeff, hf.mo_coeff) - print(dipol_mo) - print(dipol_mo * 0.52) - diff --git a/vayesta/ewf/ewf.py b/vayesta/ewf/ewf.py index 158b722d3..cf81c3c05 100644 --- a/vayesta/ewf/ewf.py +++ b/vayesta/ewf/ewf.py @@ -54,21 +54,10 @@ class EWF(Embedding): Fragment = Fragment Options = Options - def __init__(self, mf, solver='CCSD', bno_threshold=None, bath_type=None, solve_lambda=None, log=None, **kwargs): + def __init__(self, mf, solver='CCSD', log=None, **kwargs): t0 = timer() super().__init__(mf, solver=solver, log=log, **kwargs) - # Backwards support - if bno_threshold is not None: - self.log.deprecated("keyword argument bno_threshold is deprecated!") - self.opts.bath_options = {**self.opts.bath_options, **dict(threshold=bno_threshold)} - if bath_type is not None: - self.log.deprecated("keyword argument bath_type is deprecated!") - self.opts.bath_options = {**self.opts.bath_options, **dict(bathtype=bath_type)} - if solve_lambda is not None: - self.log.deprecated("keyword argument solve_lambda is deprecated!") - self.opts.solver_options = {**self.opts.solver_options, **dict(solve_lambda=solve_lambda)} - # Logging with self.log.indent(): # Options @@ -237,20 +226,6 @@ def t1_diagnostic(self, warntol=0.02): else: self.log.info("Global T1 diagnostic: %.5f", t1diag) - # --- Bardwards compatibility: - @deprecated("get_t1 is deprecated - use get_global_t1 instead.") - def get_t1(self, *args, **kwargs): - return self.get_global_t1(*args, **kwargs) - @deprecated("get_t2 is deprecated - use get_global_t2 instead.") - def get_t2(self, *args, **kwargs): - return self.get_global_t2(*args, **kwargs) - @deprecated("get_l1 is deprecated - use get_global_l1 instead.") - def get_l1(self, *args, **kwargs): - return self.get_global_l1(*args, **kwargs) - @deprecated("get_l2 is deprecated - use get_global_l2 instead.") - def get_l2(self, *args, **kwargs): - return self.get_global_l2(*args, **kwargs) - # --- Density-matrices # -------------------- @@ -320,7 +295,7 @@ def _make_rdm2_ccsd_proj_lambda(self, *args, **kwargs): def get_e_corr(self, functional=None, **kwargs): functional = (functional or self.opts.energy_functional) if functional == 'projected': - # TODO: print deprecation message + self.log.warning("functional='projected' is deprecated; use functional='wf' instead.") functional = 'wf' if functional == 'wf': return self.get_wf_corr_energy(**kwargs) @@ -346,10 +321,6 @@ def get_wf_corr_energy(self): e_corr += x.symmetry_factor * ex return e_corr/self.ncells - def get_proj_corr_energy(self): - """TODO: deprecate in favor of get_wf_corr_energy.""" - return self.get_wf_corr_energy() - def get_dm_corr_energy(self, dm1='global-wf', dm2='projected-lambda', t_as_lambda=None, with_exxdiv=None): e1 = self.get_dm_corr_energy_e1(dm1=dm1, t_as_lambda=None, with_exxdiv=None) e2 = self.get_dm_corr_energy_e2(dm2=dm2, t_as_lambda=t_as_lambda) @@ -470,10 +441,6 @@ def get_wf_energy(self, *args, **kwargs): e_corr = self.get_wf_corr_energy(*args, **kwargs) return self.e_mf + e_corr - def get_proj_energy(self, *args, **kwargs): - """TODO: deprecate in favor of get_wf_energy.""" - return self.get_wf_energy(*args, **kwargs) - def get_dm_energy(self, *args, **kwargs): e_corr = self.get_dm_corr_energy(*args, **kwargs) return self.e_mf + e_corr @@ -537,35 +504,6 @@ def get_fbc_energy(self, occupied=True, virtual=True): def get_intercluster_mp2_energy(self, *args, **kwargs): return get_intercluster_mp2_energy_rhf(self, *args, **kwargs) - # --- Deprecated - - @deprecated(replacement='_get_atom_projectors') - def _get_atomic_coeffs(self, atoms=None, projection='sao'): - if atoms is None: - atoms = list(range(self.mol.natm)) - natom = len(atoms) - projection = projection.lower() - if projection == 'sao': - frag = SAO_Fragmentation(self) - elif projection.replace('+', '').replace('/', '') == 'iaopao': - frag = IAOPAO_Fragmentation(self) - else: - raise ValueError("Invalid projection: %s" % projection) - frag.kernel() - c_atom = [] - for atom in atoms: - name, indices = frag.get_atomic_fragment_indices(atom) - c_atom.append(frag.get_frag_coeff(indices)) - return c_atom - - @deprecated(replacement='get_corrfunc_mf') - def get_atomic_ssz_mf(self, dm1=None, atoms=None, projection='sao'): - return self.get_corrfunc_mf('Sz,Sz', dm1=dm1, atoms=atoms, projection=projection) - - @deprecated(replacement='get_corrfunc') - def get_atomic_ssz(self, dm1=None, dm2=None, atoms=None, projection='sao', dm2_with_dm1=None): - return self.get_corrfunc('Sz,Sz', dm1=dm1, dm2=dm2, atoms=atoms, projection=projection, dm2_with_dm1=dm2_with_dm1) - def _get_dm_energy_old(self, global_dm1=True, global_dm2=False): """Calculate total energy from reduced density-matrices. @@ -643,136 +581,5 @@ def _debug_get_wf(self, kind): wf = self.opts._debug_wf self._debug_wf = wf - # -------------------------------------------------------------------------------------------- # - - - # TODO: Reimplement PMO - #def make_atom_fragment(self, atoms, name=None, check_atoms=True, **kwargs): - # """ - # Parameters - # --------- - # atoms : list of int/str or int/str - # Atom labels of atoms in fragment. - # name : str - # Name of fragment. - # """ - # # Atoms may be a single atom index/label - # #if not isinstance(atoms, (tuple, list, np.ndarray)): - # if np.isscalar(atoms): - # atoms = [atoms] - - # # Check if atoms are valid labels of molecule - # atom_labels_mol = [self.mol.atom_symbol(atomid) for atomid in range(self.mol.natm)] - # if isinstance(atoms[0], str) and check_atoms: - # for atom in atoms: - # if atom not in atom_labels_mol: - # raise ValueError("Atom with label %s not in molecule." % atom) - - # # Get atom indices/labels - # if isinstance(atoms[0], (int, np.integer)): - # atom_indices = atoms - # atom_labels = [self.mol.atom_symbol(i) for i in atoms] - # else: - # atom_indices = np.nonzero(np.isin(atom_labels_mol, atoms))[0] - # atom_labels = atoms - # assert len(atom_indices) == len(atom_labels) - - # # Generate cluster name if not given - # if name is None: - # name = ",".join(atom_labels) - - # # Indices refers to AOs or IAOs, respectively - - # # Non-orthogonal AOs - # if self.opts.fragment_type == "AO": - # # Base atom for each AO - # ao_atoms = np.asarray([ao[1] for ao in self.mol.ao_labels(None)]) - # indices = np.nonzero(np.isin(ao_atoms, atoms))[0] - # C_local, C_env = self.make_local_ao_orbitals(indices) - - # # Lowdin orthonalized AOs - # elif self.opts.fragment_type == "LAO": - # lao_atoms = [lao[1] for lao in self.lao_labels] - # indices = np.nonzero(np.isin(lao_atoms, atom_labels))[0] - # C_local, C_env = self.make_local_lao_orbitals(indices) - - # # Orthogonal intrinsic AOs - # elif self.opts.fragment_type == "IAO": - # iao_atoms = [iao[0] for iao in self.iao_labels] - # iao_indices = np.nonzero(np.isin(iao_atoms, atom_indices))[0] - # C_local, C_env = self.make_local_iao_orbitals(iao_indices) - - # # Non-orthogonal intrinsic AOs - # elif self.opts.fragment_type == "NonOrth-IAO": - # ao_atoms = np.asarray([ao[1] for ao in self.mol.ao_labels(None)]) - # indices = np.nonzero(np.isin(ao_atoms, atom_labels))[0] - # C_local, C_env = self.make_local_nonorth_iao_orbitals(indices, minao=self.opts.iao_minao) - - # # Projected molecular orbitals - # # (AVAS paper) - # elif self.opts.fragment_type == "PMO": - # #ao_atoms = np.asarray([ao[1] for ao in self.mol.ao_labels(None)]) - # #indices = np.nonzero(np.isin(ao_atoms, atoms))[0] - - # # Use atom labels as AO labels - # self.log.debug("Making occupied projector.") - # Po = self.get_ao_projector(atom_labels, basis=kwargs.pop("basis_proj_occ", None)) - # self.log.debug("Making virtual projector.") - # Pv = self.get_ao_projector(atom_labels, basis=kwargs.pop("basis_proj_vir", None)) - # self.log.debug("Done.") - - # o = (self.mo_occ > 0) - # v = (self.mo_occ == 0) - # C = self.mo_coeff - # So = np.linalg.multi_dot((C[:,o].T, Po, C[:,o])) - # Sv = np.linalg.multi_dot((C[:,v].T, Pv, C[:,v])) - # eo, Vo = np.linalg.eigh(So) - # ev, Vv = np.linalg.eigh(Sv) - # rev = np.s_[::-1] - # eo, Vo = eo[rev], Vo[:,rev] - # ev, Vv = ev[rev], Vv[:,rev] - # self.log.debug("Non-zero occupied eigenvalues:\n%r", eo[eo>1e-10]) - # self.log.debug("Non-zero virtual eigenvalues:\n%r", ev[ev>1e-10]) - # #tol = 1e-8 - # tol = 0.1 - # lo = eo > tol - # lv = ev > tol - # Co = np.dot(C[:,o], Vo) - # Cv = np.dot(C[:,v], Vv) - # C_local = np.hstack((Co[:,lo], Cv[:,lv])) - # C_env = np.hstack((Co[:,~lo], Cv[:,~lv])) - # self.log.debug("Number of local orbitals: %d", C_local.shape[-1]) - # self.log.debug("Number of environment orbitals: %d", C_env.shape[-1]) - - # frag = self.make_fragment(name, C_local, C_env, atoms=atom_indices, **kwargs) - - # # TEMP - # #ao_indices = get_ao_indices_at_atoms(self.mol, atomids) - # ao_indices = helper.atom_labels_to_ao_indices(self.mol, atom_labels) - # frag.ao_indices = ao_indices - - # return frag - - #def collect_results(self, *attributes): - # """Use MPI to collect results from all fragments.""" - - # #self.log.debug("Collecting attributes %r from all clusters", (attributes,)) - # fragments = self.fragments - - # if mpi: - # def reduce_fragment(attr, op=mpi.MPI.SUM, root=0): - # res = mpi.world.reduce(np.asarray([getattr(f, attr) for f in fragments]), op=op, root=root) - # return res - # else: - # def reduce_fragment(attr): - # res = np.asarray([getattr(f, attr) for f in fragments]) - # return res - - # results = {} - # for attr in attributes: - # results[attr] = reduce_fragment(attr) - - # return results - REWF = EWF diff --git a/vayesta/ewf/fragment.py b/vayesta/ewf/fragment.py index 14a739948..e9aacfffc 100644 --- a/vayesta/ewf/fragment.py +++ b/vayesta/ewf/fragment.py @@ -124,10 +124,6 @@ def set_cas(self, iaos=None, c_occ=None, c_vir=None, minao='auto', dmet_threshol self.opts.c_cas_vir = c_cas_vir return c_cas_occ, c_cas_vir - @deprecated(replacement='add_external_corrections') - def tailor_with_fragments(self, fragments, projectors=1): - return self.add_external_corrections(fragments, projectors=projectors) - def add_external_corrections(self, fragments, correction_type='tailor', projectors=1, test_extcorr=False, low_level_coul=True): """Add tailoring or external correction from other fragment solutions to CCSD solver. @@ -178,63 +174,6 @@ def clear_external_corrections(self): def get_init_guess(self, init_guess, solver, cluster): # FIXME return {} - # --- Project initial guess and integrals from previous cluster calculation with smaller eta: - # Use initial guess from previous calculations - # For self-consistent calculations, we can restart calculation: - #if init_guess is None and 'ccsd' in solver.lower(): - # if self.base.opts.sc_mode and self.base.iteration > 1: - # self.log.debugv("Restarting using T1,T2 from previous iteration") - # init_guess = {'t1' : self.results.t1, 't2' : self.results.t2} - # elif self.base.opts.project_init_guess and self.results.t2 is not None: - # self.log.debugv("Restarting using projected previous T1,T2") - # # Projectors for occupied and virtual orbitals - # p_occ = dot(self.c_active_occ.T, self.base.get_ovlp(), cluster.c_active_occ) - # p_vir = dot(self.c_active_vir.T, self.base.get_ovlp(), cluster.c_active_vir) - # #t1, t2 = init_guess.pop('t1'), init_guess.pop('t2') - # t1, t2 = helper.transform_amplitudes(self.results.t1, self.results.t2, p_occ, p_vir) - # init_guess = {'t1' : t1, 't2' : t2} - #if init_guess is None: init_guess = {} - #return init_guess - - #def kernel(self, bno_threshold=None, bno_threshold_occ=None, bno_threshold_vir=None, solver=None, init_guess=None, eris=None): - #"""Run solver for a single BNO threshold. - - #Parameters - #---------- - #bno_threshold : float, optional - # Bath natural orbital (BNO) threshold. - #solver : {'MP2', 'CISD', 'CCSD', 'FCI'}, optional - # Correlated solver. - - #Returns - #------- - #results : self.Results - #""" - #if bno_threshold is None: - # bno_threshold = self.opts.bno_threshold - #if bno_threshold_occ is None: - # bno_threshold_occ = self.opts.bno_threshold_occ - #if bno_threshold_vir is None: - # bno_threshold_vir = self.opts.bno_threshold_vir - - #bno_threshold = BNO_Threshold(self.opts.bno_truncation, bno_threshold) - - #if bno_threshold_occ is not None: - # bno_threshold_occ = BNO_Threshold(self.opts.bno_truncation, bno_threshold_occ) - #if bno_threshold_vir is not None: - # bno_threshold_vir = BNO_Threshold(self.opts.bno_truncation, bno_threshold_vir) - - #if solver is None: - # solver = self.solver - #if self.bath is None: - # self.make_bath() - - #cluster = self.make_cluster(self.bath, bno_threshold=bno_threshold, - # bno_threshold_occ=bno_threshold_occ, bno_threshold_vir=bno_threshold_vir) - #cluster.log_sizes(self.log.info, header="Orbitals for %s with %s" % (self, bno_threshold)) - - #if mpi: - # self.base.communicate_clusters() def kernel(self, solver=None, init_guess=None): diff --git a/vayesta/ewf/uewf.py b/vayesta/ewf/uewf.py index cc53c184d..696bac58e 100644 --- a/vayesta/ewf/uewf.py +++ b/vayesta/ewf/uewf.py @@ -112,141 +112,6 @@ def _make_rdm2_ccsd_proj_lambda(self, *args, **kwargs): def get_intercluster_mp2_energy(self, *args, **kwargs): return get_intercluster_mp2_energy_uhf(self, *args, **kwargs) - # --- Other expectation values - - @deprecated(replacement='get_corrfunc_mf') - def get_atomic_ssz_mf(self, dm1=None, atoms=None, projection='sao'): - """TODO: update similar to restricted code - dm1 in MO basis""" - if dm1 is None: - dm1a = np.zeros((self.nmo[0], self.nmo[0])) - dm1b = np.zeros((self.nmo[1], self.nmo[1])) - dm1a[np.diag_indices(self.nocc[0])] = 1 - dm1b[np.diag_indices(self.nocc[1])] = 1 - dm1 = (dm1a, dm1b) - c_atom = self._get_atomic_coeffs(atoms=atoms, projection=projection) - natom = len(c_atom) - ovlp = self.get_ovlp() - # Get projectors - proj = [] - for a in range(natom): - ra = dot(self.mo_coeff[0].T, ovlp, c_atom[a][0]) - rb = dot(self.mo_coeff[1].T, ovlp, c_atom[a][1]) - pa = np.dot(ra, ra.T) - pb = np.dot(rb, rb.T) - proj.append((pa, pb)) - ssz = np.zeros((natom, natom)) - for a in range(natom): - for b in range(natom): - ssz[a,b] = corrfunc.spinspin_z_unrestricted(dm1, None, proj1=proj[a], proj2=proj[b]) - return ssz - - @log_method() - @deprecated(replacement='get_corrfunc') - def get_atomic_ssz(self, dm1=None, dm2=None, atoms=None, projection='sao', dm2_with_dm1=None): - """Get expectation values , where P(X) are projectors onto atoms. - - TODO: MPI""" - # --- Setup - if dm2_with_dm1 is None: - dm2_with_dm1 = False - if dm2 is not None: - # Determine if DM2 contains DM1 by calculating norm - norm_aa = einsum('iikk->', dm2[0]) - norm_ab = einsum('iikk->', dm2[1]) - norm_bb = einsum('iikk->', dm2[2]) - norm = norm_aa + norm_bb + 2*norm_ab - ne2 = self.mol.nelectron*(self.mol.nelectron-1) - dm2_with_dm1 = (norm > ne2/2) - if atoms is None: - atoms = list(range(self.mol.natm)) - natom = len(atoms) - c_atom = self._get_atomic_coeffs(atoms=atoms, projection=projection) - ovlp = self.get_ovlp() - - proj = [] - for a in range(natom): - rxa = dot(self.mo_coeff[0].T, ovlp, c_atom[a][0]) - rxb = dot(self.mo_coeff[1].T, ovlp, c_atom[a][1]) - pxa = np.dot(rxa, rxa.T) - pxb = np.dot(rxb, rxb.T) - proj.append((pxa, pxb)) - # Fragment dependent projection operator: - if dm2 is None: - proj_x = [] - for x in self.get_fragments(contributes=True): - tmpa = np.dot(x.cluster.c_active[0].T, ovlp) - tmpb = np.dot(x.cluster.c_active[1].T, ovlp) - proj_x.append([]) - for a in range(natom): - rxa = np.dot(tmpa, c_atom[a][0]) - rxb = np.dot(tmpb, c_atom[a][1]) - pxa = np.dot(rxa, rxa.T) - pxb = np.dot(rxb, rxb.T) - proj_x[-1].append((pxa, pxb)) - - ssz = np.zeros((natom, natom)) - # 1-DM contribution: - if dm1 is None: - dm1 = self.make_rdm1() - dm1a, dm1b = dm1 - for a in range(natom): - tmpa = np.dot(proj[a][0], dm1a) - tmpb = np.dot(proj[a][1], dm1b) - for b in range(natom): - ssz[a,b] = (np.sum(tmpa*proj[b][0]) - + np.sum(tmpb*proj[b][1]))/4 - - occa = np.s_[:self.nocc[0]] - occb = np.s_[:self.nocc[1]] - occdiaga = np.diag_indices(self.nocc[0]) - occdiagb = np.diag_indices(self.nocc[1]) - # Non-cumulant DM2 contribution: - if not dm2_with_dm1: - ddm1a, ddm1b = dm1a.copy(), dm1b.copy() - ddm1a[occdiaga] -= 0.5 - ddm1b[occdiagb] -= 0.5 - # Traces of projector*DM(HF) - trpa = [np.trace(p[0][occa,occa]) for p in proj] - trpb = [np.trace(p[1][occb,occb]) for p in proj] - # Traces of projector*[DM(CC) + DM(HF)/2] - trda = [np.sum(p[0] * ddm1a) for p in proj] - trdb = [np.sum(p[1] * ddm1b) for p in proj] - for a in range(natom): - tmpa = np.dot(proj[a][0], ddm1a) - tmpb = np.dot(proj[a][1], ddm1b) - for b in range(natom): - ssz[a,b] -= (np.sum(tmpa[occa] * proj[b][0][occa]) - + np.sum(tmpb[occb] * proj[b][1][occb]))/2 - # Note that this contribution cancel to 0 in RHF, - # since trpa == trpb and trda == trdb: - ssz[a,b] += ((trpa[a]*trda[b] + trpa[b]*trda[a]) # alpha-alpha - - (trpa[a]*trdb[b] + trpb[b]*trda[a]) # alpha-beta - - (trpb[a]*trda[b] + trpa[b]*trdb[a]) # beta-alpha - + (trpb[a]*trdb[b] + trpb[b]*trdb[a]))/4 # beta-beta - - if dm2 is not None: - dm2aa, dm2ab, dm2bb = dm2 - for a in range(natom): - pa = proj[a] - tmpa = (np.tensordot(pa[0], dm2aa) - np.tensordot(dm2ab, pa[1])) - tmpb = (np.tensordot(pa[1], dm2bb) - np.tensordot(pa[0], dm2ab)) - for b in range(natom): - pb = proj[b] - ssz[a,b] += (np.sum(tmpa*pb[0]) + np.sum(tmpb*pb[1]))/4 - else: - # Cumulant DM2 contribution: - for ix, x in enumerate(self.get_fragments(contributes=True)): - dm2aa, dm2ab, dm2bb = x.make_fragment_dm2cumulant() - for a in range(natom): - pa = proj_x[ix][a] - tmpa = (np.tensordot(pa[0], dm2aa) - np.tensordot(dm2ab, pa[1])) - tmpb = (np.tensordot(pa[1], dm2bb) - np.tensordot(pa[0], dm2ab)) - for b in range(natom): - pb = proj_x[ix][b] - ssz[a,b] += (np.sum(tmpa*pb[0]) + np.sum(tmpb*pb[1]))/4 - return ssz - def _get_dm_corr_energy_old(self, global_dm1=True, global_dm2=False, t_as_lambda=None): """Calculate correlation energy from reduced density-matrices. diff --git a/vayesta/tests/core/scmf/test_scmf.py b/vayesta/tests/core/scmf/test_scmf.py index 3145f2596..9b67e1974 100644 --- a/vayesta/tests/core/scmf/test_scmf.py +++ b/vayesta/tests/core/scmf/test_scmf.py @@ -19,7 +19,7 @@ def tearDownClass(cls): @classmethod @cache def emb(cls, scmf=None): - emb = ewf.EWF(cls.mf, solve_lambda=True, bath_type='dmet') + emb = ewf.EWF(cls.mf, solver_options=dict(solve_lambda=True), bath_options=dict(bathtype='dmet')) with emb.sao_fragmentation() as f: f.add_all_atomic_fragments() if scmf == 'pdmet': diff --git a/vayesta/tests/core/wf/test_wf.py b/vayesta/tests/core/wf/test_wf.py index fab102cad..513fcaf52 100644 --- a/vayesta/tests/core/wf/test_wf.py +++ b/vayesta/tests/core/wf/test_wf.py @@ -79,8 +79,8 @@ def tearDownClass(cls): @classmethod @cache def frag(cls): - emb = vayesta.ewf.EWF(cls.mf, bath_type='full', solve_lambda=True, solver=cls.solver, - solver_options=cls.solver_opts) + emb = vayesta.ewf.EWF(cls.mf, bath_options=dict(bathtype='full'), solver=cls.solver, + solver_options=dict(**cls.solver_opts, solve_lambda=True)) with emb.iao_fragmentation() as f: frag = f.add_atomic_fragment(list(range(emb.mol.natm))) emb.kernel() diff --git a/vayesta/tests/dmet/test_hubbard.py b/vayesta/tests/dmet/test_hubbard.py index 07513e772..3d2eaa2e8 100644 --- a/vayesta/tests/dmet/test_hubbard.py +++ b/vayesta/tests/dmet/test_hubbard.py @@ -1,3 +1,5 @@ +import sys +import pytest import unittest from vayesta import dmet from vayesta.tests.common import TestCase @@ -8,6 +10,13 @@ class HubbardDMETTests(TestCase): PLACES_ENERGY = 6 CONV_TOL = 1e-8 + @classmethod + def setUpClass(cls): + try: + import cvxpy + except ImportError: + pytest.skip("Requires cvxpy") + def _test_converged(self, emb, known_values=None): """Test that the DMET has converged. """ diff --git a/vayesta/tests/dmet/test_molecule.py b/vayesta/tests/dmet/test_molecule.py index 539e76f29..39db42bac 100644 --- a/vayesta/tests/dmet/test_molecule.py +++ b/vayesta/tests/dmet/test_molecule.py @@ -1,3 +1,5 @@ +import sys +import pytest import unittest from vayesta import dmet from vayesta.tests.common import TestCase @@ -12,6 +14,10 @@ class MoleculeTest(TestCase): @classmethod def setUpClass(cls): + try: + import cvxpy + except ImportError: + pytest.skip("Requires cvxpy") cls.mf = testsystems.h6_sto6g.rhf() @classmethod diff --git a/vayesta/tests/edmet/test_dfedmet_hubbard.py b/vayesta/tests/edmet/test_dfedmet_hubbard.py index 68a5c0216..b0ff9fb94 100644 --- a/vayesta/tests/edmet/test_dfedmet_hubbard.py +++ b/vayesta/tests/edmet/test_dfedmet_hubbard.py @@ -1,3 +1,5 @@ +import sys +import pytest import unittest from vayesta import edmet @@ -8,6 +10,13 @@ class HubbardDFEDMETTests(TestCase): PLACES_ENERGY = 9 + @classmethod + def setUpClass(cls): + try: + import cvxpy + except ImportError: + pytest.skip("Requires cvxpy") + def _test_energy(self, emb, dfedmet, known_values): """Test that the energy contributions match a known value and the non-density fitted value. """ diff --git a/vayesta/tests/edmet/test_dfedmet_molecule.py b/vayesta/tests/edmet/test_dfedmet_molecule.py index a1aceacd8..87b7472e1 100644 --- a/vayesta/tests/edmet/test_dfedmet_molecule.py +++ b/vayesta/tests/edmet/test_dfedmet_molecule.py @@ -1,3 +1,5 @@ +import sys +import pytest import unittest import vayesta @@ -9,6 +11,13 @@ class MolecularDFEDMETTest(TestCase): ENERGY_PLACES = 8 CONV_TOL = 1e-9 + @classmethod + def setUpClass(cls): + try: + import cvxpy + except ImportError: + pytest.skip("Requires cvxpy") + def _test_energy(self, emb, known_values): """Tests that the energy matfhes a known values. """ diff --git a/vayesta/tests/edmet/test_edmet_hubbard.py b/vayesta/tests/edmet/test_edmet_hubbard.py index f6394d564..eb9321d3a 100644 --- a/vayesta/tests/edmet/test_edmet_hubbard.py +++ b/vayesta/tests/edmet/test_edmet_hubbard.py @@ -1,3 +1,5 @@ +import sys +import pytest import unittest from vayesta import edmet @@ -8,6 +10,13 @@ class EDMET_Hubbard_Tests(TestCase): PLACES_ENERGY = 6 + @classmethod + def setUpClass(cls): + try: + import cvxpy + except ImportError: + pytest.skip("Requires cvxpy") + def _test_energy(self, emb, known_values): """Test that the energy matches a known value. """ diff --git a/vayesta/tests/edmet/test_edmet_molecule.py b/vayesta/tests/edmet/test_edmet_molecule.py index 6bab28507..215c71ddf 100644 --- a/vayesta/tests/edmet/test_edmet_molecule.py +++ b/vayesta/tests/edmet/test_edmet_molecule.py @@ -1,3 +1,5 @@ +import sys +import pytest import unittest import vayesta @@ -10,6 +12,13 @@ class MolecularEDMETTest(TestCase): ENERGY_PLACES = 7 CONV_TOL = 1e-9 + @classmethod + def setUpClass(cls): + try: + import cvxpy + except ImportError: + pytest.skip("Requires cvxpy.") + def _test_energy(self, emb, known_values): """Tests that the energy matfhes a known values. """ diff --git a/vayesta/tests/ewf/test_corrfunc.py b/vayesta/tests/ewf/test_corrfunc.py index c2fdc2b42..f72989a1d 100644 --- a/vayesta/tests/ewf/test_corrfunc.py +++ b/vayesta/tests/ewf/test_corrfunc.py @@ -29,7 +29,9 @@ def tearDownClass(cls): @classmethod @cache def remb(cls, bno_threshold, run_kernel=True): - remb = vayesta.ewf.EWF(cls.rhf, solver=cls.solver, bno_threshold=bno_threshold, solve_lambda=True) + remb = vayesta.ewf.EWF(cls.rhf, solver=cls.solver, + bath_options=dict(threshold=bno_threshold), + solver_options=dict(solve_lambda=True)) if run_kernel: remb.kernel() return remb @@ -37,7 +39,9 @@ def remb(cls, bno_threshold, run_kernel=True): @classmethod @cache def uemb(cls, bno_threshold, run_kernel=True): - uemb = vayesta.ewf.EWF(cls.uhf, solver=cls.solver, bno_threshold=bno_threshold, solve_lambda=True) + uemb = vayesta.ewf.EWF(cls.uhf, solver=cls.solver, + bath_options=dict(threshold=bno_threshold), + solver_options=dict(solve_lambda=True)) if run_kernel: uemb.kernel() return uemb @@ -49,7 +53,7 @@ def test_mf(self): ssz_u = uemb.get_corrfunc_mf('Sz,Sz') self.assertAllclose(ssz_r, ssz_u, atol=1e-6) # OLD - ssz_old_u = uemb.get_atomic_ssz_mf() + ssz_old_u = uemb.get_corrfunc_mf('Sz,Sz') self.assertAllclose(ssz_old_u, ssz_u, atol=1e-6) def test_full_bath(self): @@ -59,10 +63,10 @@ def test_full_bath(self): dm1 = self.rcc.make_rdm1() dm2 = self.rcc.make_rdm2() - ssz = remb.get_atomic_ssz(dm1=dm1, dm2=dm2) + ssz = remb.get_corrfunc('Sz,Sz', dm1=dm1, dm2=dm2) - rssz = remb.get_atomic_ssz() - ussz = uemb.get_atomic_ssz() + rssz = remb.get_corrfunc('Sz,Sz') + ussz = uemb.get_corrfunc('Sz,Sz') self.assertAllclose(rssz, ssz, atol=1e-6) self.assertAllclose(ussz, ssz, atol=1e-6) @@ -75,8 +79,8 @@ def test_full_bath(self): # Full 2DMs rdm2 = remb.make_rdm2() udm2 = uemb.make_rdm2() - rssz = remb.get_atomic_ssz(dm2=rdm2) - ussz = uemb.get_atomic_ssz(dm2=udm2) + rssz = remb.get_corrfunc('Sz,Sz', dm2=rdm2) + ussz = uemb.get_corrfunc('Sz,Sz', dm2=udm2) self.assertAllclose(rssz, ssz, atol=1e-6) self.assertAllclose(ussz, ssz, atol=1e-6) @@ -91,8 +95,8 @@ def test_finite_bath(self): remb = self.remb(eta) uemb = self.uemb(eta) - ssz = rssz = remb.get_atomic_ssz() - ussz = uemb.get_atomic_ssz() + ssz = rssz = remb.get_corrfunc('Sz,Sz') + ussz = uemb.get_corrfunc('Sz,Sz') self.assertAllclose(rssz, ssz, atol=1e-6) self.assertAllclose(ussz, ssz, atol=1e-6) @@ -105,8 +109,8 @@ def test_finite_bath(self): # Full 2DMs rdm2 = remb.make_rdm2() udm2 = uemb.make_rdm2() - rssz = remb.get_atomic_ssz(dm2=rdm2) - ussz = uemb.get_atomic_ssz(dm2=udm2) + rssz = remb.get_corrfunc('Sz,Sz', dm2=rdm2) + ussz = uemb.get_corrfunc('Sz,Sz', dm2=udm2) self.assertAllclose(rssz, ssz, atol=1e-6) self.assertAllclose(ussz, ssz, atol=1e-6) @@ -147,7 +151,9 @@ def tearDownClass(cls): @classmethod @cache def uemb(cls, bno_threshold): - uemb = vayesta.ewf.EWF(cls.uhf, solver=cls.solver, bno_threshold=bno_threshold, solve_lambda=True) + uemb = vayesta.ewf.EWF(cls.uhf, solver=cls.solver, + bath_options=dict(threshold=bno_threshold), + solver_options=dict(solve_lambda=True)) uemb.kernel() return uemb @@ -157,10 +163,10 @@ def _test_full_bath(self, projection): dm1 = self.ucc.make_rdm1() dm2 = self.ucc.make_rdm2() - # Deprecated: get_atomic_ssz: - ssz = uemb.get_atomic_ssz(dm1=dm1, dm2=dm2, projection=projection) + # Deprecated: get_corrfunc: + ssz = uemb.get_corrfunc('Sz,Sz', dm1=dm1, dm2=dm2, projection=projection) udm2 = uemb.make_rdm2() - ssz_2 = uemb.get_atomic_ssz(dm2=udm2, dm2_with_dm1=True, projection=projection) + ssz_2 = uemb.get_corrfunc('Sz,Sz', dm2=udm2, dm2_with_dm1=True, projection=projection) self.assertAllclose(ssz_2, ssz, atol=1e-6) # Replacement: get_corrfunc('Sz,Sz', ...) diff --git a/vayesta/tests/ewf/test_h2.py b/vayesta/tests/ewf/test_h2.py index 431d2c919..d13cd09f7 100644 --- a/vayesta/tests/ewf/test_h2.py +++ b/vayesta/tests/ewf/test_h2.py @@ -63,9 +63,9 @@ def setUpClass(cls): @classmethod @cache def emb(cls, bno_threshold): - solver_opts = dict(conv_tol= 1e-10, conv_tol_normt=1e-8) - emb = vayesta.ewf.EWF(cls.mf, bath_options=dict(threshold=bno_threshold), solve_lambda=True, - solver_options=solver_opts) + solver_opts = dict(conv_tol= 1e-10, conv_tol_normt=1e-8, solve_lambda=True) + emb = vayesta.ewf.EWF(cls.mf, bath_options=dict(threshold=bno_threshold), + solver_options=solver_opts) emb.kernel() return emb diff --git a/vayesta/tests/ewf/test_h2_pbc.py b/vayesta/tests/ewf/test_h2_pbc.py index f7023fd5d..f1517fdde 100644 --- a/vayesta/tests/ewf/test_h2_pbc.py +++ b/vayesta/tests/ewf/test_h2_pbc.py @@ -51,7 +51,7 @@ def get_e_exxdiv(cls): @classmethod @cache def emb(cls, bno_threshold): - emb = vayesta.ewf.EWF(cls.mf, bno_threshold=bno_threshold, solver='MP2') + emb = vayesta.ewf.EWF(cls.mf, bath_options=dict(threshold=bno_threshold), solver='MP2') with emb.iao_fragmentation(minao='minao') as f: f.add_all_atomic_fragments() emb.kernel() @@ -135,7 +135,8 @@ def setUpClass(cls): @classmethod @cache def emb(cls, bno_threshold): - emb = vayesta.ewf.EWF(cls.mf, bno_threshold=bno_threshold, solve_lambda=True, solver_options=TIGHT_SOLVER) + emb = vayesta.ewf.EWF(cls.mf, bath_options=dict(threshold=bno_threshold), + solver_options={**TIGHT_SOLVER, 'solve_lambda': True}) with emb.iao_fragmentation(minao='minao') as f: f.add_all_atomic_fragments() emb.kernel() diff --git a/vayesta/tests/ewf/test_hubbard.py b/vayesta/tests/ewf/test_hubbard.py index 9587bfd42..4a61004b5 100644 --- a/vayesta/tests/ewf/test_hubbard.py +++ b/vayesta/tests/ewf/test_hubbard.py @@ -21,7 +21,7 @@ def test_6_u0_1imp(self): emb = ewf.EWF( testsystems.hubb_6_u0.rhf(), - bno_threshold=1e-8, + bath_options=dict(threshold=1e-8), solver_options={ 'conv_tol': self.CONV_TOL, }, @@ -41,7 +41,7 @@ def test_10_u2_2imp(self): emb = ewf.EWF( testsystems.hubb_10_u2.rhf(), - bno_threshold=1e-8, + bath_options=dict(threshold=1e-8), solver_options={ 'conv_tol': self.CONV_TOL, }, @@ -61,7 +61,7 @@ def test_10_u2_2imp_uhf(self): emb = ewf.EWF( testsystems.hubb_10_u2.rhf(), - bno_threshold=1e-2, + bath_options=dict(threshold=1e-2), solver_options={ 'conv_tol': self.CONV_TOL, }, @@ -75,7 +75,7 @@ def test_10_u2_2imp_uhf(self): uemb = ewf.EWF( testsystems.hubb_10_u2.uhf(), - bno_threshold=1e-2, + bath_options=dict(threshold=1e-2), solver_options={ 'conv_tol': self.CONV_TOL, }, @@ -96,7 +96,7 @@ def test_6x6_u0_1x1imp(self): emb = ewf.EWF( testsystems.hubb_6x6_u0_1x1imp.rhf(), - bno_threshold=1e-8, + bath_options=dict(threshold=1e-8), solver_options={ 'conv_tol': self.CONV_TOL, }, @@ -116,7 +116,7 @@ def test_6x6_u6_1x1imp(self): emb = ewf.EWF( testsystems.hubb_6x6_u6_1x1imp.rhf(), - bno_threshold=1e-8, + bath_options=dict(threshold=1e-8), solver_options={ 'conv_tol': self.CONV_TOL, }, @@ -136,7 +136,7 @@ def test_8x8_u2_2x2imp(self): emb = ewf.EWF( testsystems.hubb_8x8_u2_2x2imp.rhf(), - bno_threshold=1e-8, + bath_options=dict(threshold=1e-8), solver_options={ 'conv_tol': self.CONV_TOL, }, diff --git a/vayesta/tests/ewf/test_molecules.py b/vayesta/tests/ewf/test_molecules.py index 878737ebb..e7ea57cd7 100644 --- a/vayesta/tests/ewf/test_molecules.py +++ b/vayesta/tests/ewf/test_molecules.py @@ -257,8 +257,8 @@ def test_tccsd_via_fragment(self): frag_o = f.add_atomic_fragment(0, solver='extCCSD', active=False) frag_h = f.add_atomic_fragment(1, solver='extCCSD', sym_factor=2, active=False) emb.kernel() - frag_o.tailor_with_fragments([cas_o], projectors=0) - frag_h.tailor_with_fragments([cas_h], projectors=0) + frag_o.add_external_corrections([cas_o], projectors=0) + frag_h.add_external_corrections([cas_h], projectors=0) cas_o.active = cas_h.active = False frag_o.active = frag_h.active = True emb.kernel() @@ -292,7 +292,7 @@ def test_h2_cisd(self): ecisd = ewf.EWF( testsystems.h2_ccpvdz.rhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver='CISD', solver_options={ 'conv_tol': self.CONV_TOL, @@ -303,7 +303,7 @@ def test_h2_cisd(self): eccsd = ewf.EWF( testsystems.h2_ccpvdz.rhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver='CCSD', solver_options={ 'conv_tol': self.CONV_TOL, @@ -320,7 +320,7 @@ def test_h2o_mp2_compression(self): """ rewf = ewf.EWF( testsystems.water_ccpvdz.rhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver="MP2" ) @@ -330,7 +330,7 @@ def test_h2o_mp2_compression(self): df_rewf = ewf.EWF( testsystems.water_ccpvdz_df.rhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver="MP2", solver_options={ "compress_cderi":False @@ -344,7 +344,7 @@ def test_h2o_mp2_compression(self): cdf_rewf = ewf.EWF( testsystems.water_ccpvdz_df.rhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver="MP2", solver_options={ "compress_cderi":True @@ -367,7 +367,7 @@ def test_lih_rhf_vs_uhf(self): rewf = ewf.EWF( testsystems.lih_ccpvdz.rhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver_options={ 'conv_tol': self.CONV_TOL, 'conv_tol_normt': self.CONV_TOL_NORMT, @@ -379,7 +379,7 @@ def test_lih_rhf_vs_uhf(self): uewf = ewf.UEWF( testsystems.lih_ccpvdz.uhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver_options={ 'conv_tol': self.CONV_TOL, 'conv_tol_normt': self.CONV_TOL_NORMT, @@ -399,7 +399,7 @@ def test_lih_rhf_vs_uhf_cisd(self): rewf = ewf.EWF( testsystems.lih_ccpvdz.rhf(), solver='CISD', - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver_options={ 'conv_tol': self.CONV_TOL, 'conv_tol_normt': self.CONV_TOL_NORMT, @@ -412,7 +412,7 @@ def test_lih_rhf_vs_uhf_cisd(self): uewf = ewf.UEWF( testsystems.lih_ccpvdz.uhf(), solver='CISD', - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver_options={ 'conv_tol': self.CONV_TOL, 'conv_tol_normt': self.CONV_TOL_NORMT, @@ -432,7 +432,7 @@ def test_h2_rhf_vs_uhf_fci(self): rewf = ewf.EWF( testsystems.h2_ccpvdz.rhf(), solver='FCI', - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver_options={ 'conv_tol': 1e-12, }, @@ -444,7 +444,7 @@ def test_h2_rhf_vs_uhf_fci(self): uewf = ewf.UEWF( testsystems.h2_ccpvdz.uhf(), solver='FCI', - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver_options={ 'conv_tol': 1e-12, }, @@ -462,7 +462,7 @@ def test_lih_rhf_vs_uhf_CAS(self): rewf = ewf.EWF( testsystems.lih_ccpvdz.rhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver_options={ 'conv_tol': self.CONV_TOL, 'conv_tol_normt': self.CONV_TOL_NORMT, @@ -474,7 +474,7 @@ def test_lih_rhf_vs_uhf_CAS(self): uewf = ewf.UEWF( testsystems.lih_ccpvdz.uhf(), - bath_type='dmet', + bath_options=dict(bathtype='dmet'), solver_options={ 'conv_tol': self.CONV_TOL, 'conv_tol_normt': self.CONV_TOL_NORMT, diff --git a/vayesta/tests/ewf/test_nelectron_target.py b/vayesta/tests/ewf/test_nelectron_target.py index 3371aade1..027b0c256 100644 --- a/vayesta/tests/ewf/test_nelectron_target.py +++ b/vayesta/tests/ewf/test_nelectron_target.py @@ -19,7 +19,7 @@ def setUpClass(cls): @classmethod @cache def emb(cls, bno_threshold): - emb = vayesta.ewf.EWF(cls.mf, solver=cls.solver, bno_threshold=bno_threshold) + emb = vayesta.ewf.EWF(cls.mf, solver=cls.solver, bath_options=dict(threshold=bno_threshold)) with emb.sao_fragmentation() as f: f.add_atomic_fragment(0, nelectron_target=cls.targets[0], nelectron_target_atol=1e-7, nelectron_target_rtol=0) f.add_atomic_fragment(1, nelectron_target=cls.targets[1], nelectron_target_atol=1e-7, nelectron_target_rtol=0) diff --git a/vayesta/tests/ewf/test_rdm_energy.py b/vayesta/tests/ewf/test_rdm_energy.py index 2322fdb98..effceafbb 100644 --- a/vayesta/tests/ewf/test_rdm_energy.py +++ b/vayesta/tests/ewf/test_rdm_energy.py @@ -19,7 +19,7 @@ def test(self): cc.kernel() #Full bath EWF - ewf = vayesta.ewf.EWF(mf, bath_type='full', solve_lambda=True) + ewf = vayesta.ewf.EWF(mf, bath_options=dict(bathtype='full'), solver_options=dict(solve_lambda=True)) ewf.kernel() ll = ewf._get_dm_corr_energy_old(global_dm1=False, global_dm2=False) @@ -46,7 +46,7 @@ def test(self): cc.kernel() #Full bath EWF - ewf = vayesta.ewf.EWF(mf, bath_type='full', solve_lambda=True) + ewf = vayesta.ewf.EWF(mf, bath_options=dict(bathtype='full'), solver_options=dict(solve_lambda=True)) ewf.kernel() ll = ewf._get_dm_corr_energy_old(global_dm1=False, global_dm2=False) @@ -59,6 +59,7 @@ def test(self): self.assertAlmostEqual(lg, cc.e_corr) self.assertAlmostEqual(gg, cc.e_corr) +<<<<<<< HEAD self.assertAlmostEqual(ewf.get_dm_energy(), cc.e_tot) # def test_h2_solid(self): @@ -83,6 +84,8 @@ def test(self): # self.assertAlmostEqual(gl, cc.e_corr) # self.assertAlmostEqual(lg, cc.e_corr) # self.assertAlmostEqual(gg, cc.e_corr) +======= +>>>>>>> master if __name__ == '__main__': print("Running %s" % __file__) diff --git a/vayesta/tests/ewf/test_water_sao.py b/vayesta/tests/ewf/test_water_sao.py index b27239ca3..49a3437d8 100644 --- a/vayesta/tests/ewf/test_water_sao.py +++ b/vayesta/tests/ewf/test_water_sao.py @@ -17,7 +17,7 @@ def setUpClass(cls): @classmethod @cache def emb(cls, bno_threshold): - emb = vayesta.ewf.EWF(cls.mf, solver='MP2', bno_threshold=bno_threshold) + emb = vayesta.ewf.EWF(cls.mf, solver='MP2', bath_options=dict(threshold=bno_threshold)) with emb.sao_fragmentation() as f: f.add_all_atomic_fragments() emb.kernel() @@ -63,9 +63,9 @@ def setUpClass(cls): @classmethod @cache def emb(cls, bno_threshold): - solver_opts = dict(conv_tol= 1e-10, conv_tol_normt=1e-8) - emb = vayesta.ewf.EWF(cls.mf, bno_threshold=bno_threshold, solve_lambda=True, - solver_options=solver_opts) + solver_opts = dict(conv_tol= 1e-10, conv_tol_normt=1e-8, solve_lambda=True) + emb = vayesta.ewf.EWF(cls.mf, bath_options=dict(threshold=bno_threshold), + solver_options=solver_opts) with emb.sao_fragmentation() as f: f.add_all_atomic_fragments() emb.kernel() @@ -109,7 +109,7 @@ def setUpClass(cls): @classmethod @cache def emb(cls, bno_threshold): - emb = vayesta.ewf.EWF(cls.mf, solver='MP2', bno_threshold=bno_threshold) + emb = vayesta.ewf.EWF(cls.mf, solver='MP2', bath_options=dict(threshold=bno_threshold)) with emb.sao_fragmentation() as f: f.add_all_atomic_fragments() emb.kernel() @@ -152,9 +152,9 @@ def tearDownClass(cls): @classmethod @cache def remb(cls, bno_threshold): - solver_opts = dict(conv_tol= 1e-10, conv_tol_normt=1e-8) - emb = vayesta.ewf.EWF(cls.rhf, bno_threshold=bno_threshold, solve_lambda=True, - solver_options=solver_opts) + solver_opts = dict(conv_tol= 1e-10, conv_tol_normt=1e-8, solve_lambda=True) + emb = vayesta.ewf.EWF(cls.rhf, bath_options=dict(threshold=bno_threshold), + solver_options=solver_opts) with emb.sao_fragmentation() as f: f.add_all_atomic_fragments() emb.kernel() @@ -163,9 +163,9 @@ def remb(cls, bno_threshold): @classmethod @cache def uemb(cls, bno_threshold): - solver_opts = dict(conv_tol= 1e-10, conv_tol_normt=1e-8) - emb = vayesta.ewf.EWF(cls.uhf, bno_threshold=bno_threshold, solve_lambda=True, - solver_options=solver_opts) + solver_opts = dict(conv_tol= 1e-10, conv_tol_normt=1e-8, solve_lambda=True) + emb = vayesta.ewf.EWF(cls.uhf, bath_options=dict(threshold=bno_threshold), + solver_options=solver_opts) with emb.sao_fragmentation() as f: f.add_all_atomic_fragments() emb.kernel() diff --git a/vayesta/tests/solver/test_ccsd.py b/vayesta/tests/solver/test_ccsd.py index f1680b455..ee606832a 100644 --- a/vayesta/tests/solver/test_ccsd.py +++ b/vayesta/tests/solver/test_ccsd.py @@ -17,7 +17,7 @@ class TestSolvers(TestCase): def _test(self, key): mf = getattr(getattr(testsystems, key[0]), key[1])() - emb = vayesta.ewf.EWF(mf, solver='CCSD', bath_type='full') + emb = vayesta.ewf.EWF(mf, solver='CCSD', bath_options=dict(bathtype='full')) emb.kernel() cc = pyscf.cc.CCSD(mf) diff --git a/vayesta/tests/solver/test_cisd.py b/vayesta/tests/solver/test_cisd.py index 7090314af..fc4c6f95e 100644 --- a/vayesta/tests/solver/test_cisd.py +++ b/vayesta/tests/solver/test_cisd.py @@ -18,7 +18,7 @@ def _test(self, key): mf = getattr(getattr(testsystems, key[0]), key[1])() solver_opts = dict(conv_tol=1e-10) - emb = vayesta.ewf.EWF(mf, solver='CISD', bath_type='full', solver_options=solver_opts) + emb = vayesta.ewf.EWF(mf, solver='CISD', bath_options=dict(bathtype='full'), solver_options=solver_opts) emb.kernel() ci = pyscf.ci.CISD(mf) diff --git a/vayesta/tests/solver/test_fci.py b/vayesta/tests/solver/test_fci.py index 04efaf340..341253719 100644 --- a/vayesta/tests/solver/test_fci.py +++ b/vayesta/tests/solver/test_fci.py @@ -15,7 +15,7 @@ class TestSolvers(unittest.TestCase): def _test(self, key, ss=None, places=8): mf = getattr(getattr(testsystems, key[0]), key[1])() - emb = vayesta.ewf.EWF(mf, solver='FCI', bath_type='full', solver_options={'conv_tol' : 1e-12}) + emb = vayesta.ewf.EWF(mf, solver='FCI', bath_options=dict(bathtype='full'), solver_options={'conv_tol' : 1e-12}) emb.kernel() fci = pyscf.fci.FCI(mf) diff --git a/vayesta/tests/solver/test_mp2.py b/vayesta/tests/solver/test_mp2.py index 0e9e0e275..4566994ef 100644 --- a/vayesta/tests/solver/test_mp2.py +++ b/vayesta/tests/solver/test_mp2.py @@ -15,7 +15,7 @@ class TestSolvers(unittest.TestCase): def _test(self, key): mf = getattr(getattr(testsystems, key[0]), key[1])() - emb = vayesta.ewf.EWF(mf, solver='MP2', bath_type='full') + emb = vayesta.ewf.EWF(mf, solver='MP2', bath_options=dict(bathtype='full')) emb.kernel() mp2 = pyscf.mp.MP2(mf)