From c48501d66d5635dd3e889e08822457ce6645cd17 Mon Sep 17 00:00:00 2001 From: Oskar Weser Date: Thu, 21 Nov 2024 14:30:23 -0500 Subject: [PATCH 1/8] added mypy configuration file --- mypy.ini | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 00000000..bd1183d5 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,17 @@ +[mypy] + no_implicit_optional = True + +# TODO: whenever the following packages have stubs available, +# stop ignoring them. + +[mypy-pyscf.*] + ignore_missing_imports = True + +[mypy-libdmet.*] + ignore_missing_imports = True + +[mypy-setuptools.*] + ignore_missing_imports = True + +[mypy-h5py.*] + ignore_missing_imports = True From bb486e872023c1cf4c7dd4ce9a9b6b8528f8a6fc Mon Sep 17 00:00:00 2001 From: Oskar Weser Date: Thu, 21 Nov 2024 14:30:57 -0500 Subject: [PATCH 2/8] updated unit test workflow clearer separation between code analysis and unit tests --- .github/workflows/quemb_unittest.yml | 70 +++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/.github/workflows/quemb_unittest.yml b/.github/workflows/quemb_unittest.yml index 97d582bd..591f245d 100644 --- a/.github/workflows/quemb_unittest.yml +++ b/.github/workflows/quemb_unittest.yml @@ -13,11 +13,12 @@ permissions: contents: read jobs: - build: + analysis: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.12"] + python-version: ["3.12"] + steps: - uses: actions/checkout@v4 @@ -31,7 +32,6 @@ jobs: run: | python -m pip install --upgrade pip - - uses: actions/cache@v4 with: path: ${{ env.pythonLocation }} @@ -40,14 +40,8 @@ jobs: - name: Install dependencies run: | - pip install --upgrade --upgrade-strategy eager pytest ruff - if [ -f requirements.txt ]; then pip install --upgrade --upgrade-strategy eager -r requirements.txt; fi - pip install git+https://github.com/pyscf/dmrgscf - PYSCFHOME=$(pip show pyscf-dmrgscf | grep 'Location' | tr ' ' '\n' | tail -n 1) - wget https://raw.githubusercontent.com/pyscf/dmrgscf/master/pyscf/dmrgscf/settings.py.example - mv settings.py.example ${PYSCFHOME}/pyscf/dmrgscf/settings.py + pip install --upgrade --upgrade-strategy eager ruff pylint mypy scipy-stubs pip install . - echo ${{ github.workspace }} > $(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")/quemb.pth - name: Check formatting @@ -55,16 +49,70 @@ jobs: ruff format --diff - - name: Static analysis + - name: Static analysis with ruff run: | ruff check . || true # for the moment we want to report always report success + - name: Static analysis with pylint + run: | + # ruff does nearly everything that we want from pylint + # except for detecting unresolved imports + # TODO: if they add it to ruff as well https://github.com/astral-sh/ruff/issues/9103 + # remove pylint. + pylint --disable=all --enable=E0401,R0401,E0611 . || true # for the moment we want to report always report success + + + - name: Static analysis with mypy + run: | + mypy tests/ example/ src/ || true # for the moment we want to report always report success + + + + build: + runs-on: ubuntu-latest + needs: analysis + strategy: + matrix: + python-version: ["3.9", "3.12"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Prepare pip + run: | + python -m pip install --upgrade pip + + + - uses: actions/cache@v4 + with: + path: ${{ env.pythonLocation }} + key: ${{ env.pythonLocation }}-${{ hashFiles('setup.py') }}-${{ hashFiles('dev-requirements.txt') }} + + + - name: Install dependencies + run: | + pip install --upgrade --upgrade-strategy eager pytest + if [ -f requirements.txt ]; then pip install --upgrade --upgrade-strategy eager -r requirements.txt; fi + pip install git+https://github.com/pyscf/dmrgscf + PYSCFHOME=$(pip show pyscf-dmrgscf | grep 'Location' | tr ' ' '\n' | tail -n 1) + wget https://raw.githubusercontent.com/pyscf/dmrgscf/master/pyscf/dmrgscf/settings.py.example + mv settings.py.example ${PYSCFHOME}/pyscf/dmrgscf/settings.py + pip install . + echo ${{ github.workspace }} > $(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")/quemb.pth + + - name: Test with pytest run: | cd tests QUEMB_SKIP_EXPENSIVE_TESTS=true pytest --doctest-modules --junitxml=junit/quemb-test-results_${{ matrix.python-version }}.xml + - name: Upload pytest junit results uses: actions/upload-artifact@v4 with: From 55f588b9e5c749e31d70b4692548105fdf4ea14b Mon Sep 17 00:00:00 2001 From: Oskar Weser Date: Thu, 21 Nov 2024 14:31:47 -0500 Subject: [PATCH 3/8] ignore vim swap files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ce697f8f..64da0307 100644 --- a/.gitignore +++ b/.gitignore @@ -165,3 +165,6 @@ cython_debug/ # pyscf files eri_file.h5 + +# vim swap files +.*.swp From 5b11557357d4af2c150ea7cc68c7ee362a887887 Mon Sep 17 00:00:00 2001 From: Oskar Weser Date: Thu, 21 Nov 2024 14:32:15 -0500 Subject: [PATCH 4/8] incorporate pylint warnings into ruff --- .ruff.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.ruff.toml b/.ruff.toml index 708d0329..c1933696 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -1,6 +1,6 @@ [lint] # see the rules [here](https://docs.astral.sh/ruff/rules/) -select = ["E", "F", "I", "NPY", "ARG"] +select = ["E", "F", "I", "NPY", "ARG", "PL"] ignore = [ "S101", # https://docs.astral.sh/ruff/rules/assert/ @@ -10,5 +10,9 @@ ignore = [ # https://docs.astral.sh/ruff/rules/ambiguous-variable-name/ # Prevents the use of the characters 'l', 'O', or 'I' as variable names. # Overly restrictive, in particular when implementing mathematical expressions. + "PLR", + # https://docs.astral.sh/ruff/rules/#refactor-r + # while these warnings are nice for a fresh codebase, + # they are too many to fix now and not important enough ] preview = true From 7de0c35748d9614fab02446be9309bd036ba30d5 Mon Sep 17 00:00:00 2001 From: Oskar Weser Date: Thu, 21 Nov 2024 14:37:45 -0500 Subject: [PATCH 5/8] updated setup.py to not point to custom libdmet --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 73170992..b3703cec 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,6 @@ "scipy>=1.7.0", "pyscf>=2.0.0", "matplotlib", - "libdmet @ git+https://github.com/mcocdawc/libdmet_preview.git@add_fixes_for_BE", + "libdmet @ git+https://github.com/gkclab/libdmet_preview.git", ], ) From 5af850f4db2247b76717091e7eb3f5caccbed607 Mon Sep 17 00:00:00 2001 From: Oskar Weser Date: Thu, 21 Nov 2024 14:39:28 -0500 Subject: [PATCH 6/8] explicit ignore of unresolved imports for optional packages --- src/molbe/be_parallel.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/molbe/be_parallel.py b/src/molbe/be_parallel.py index 3c95003d..17cf4bcc 100644 --- a/src/molbe/be_parallel.py +++ b/src/molbe/be_parallel.py @@ -132,6 +132,7 @@ def run_solver( efci, civec = mc_.kernel() rdm1_tmp = mc_.make_rdm1(civec, mc_.norb, mc_.nelec) elif solver == "HCI": + # pylint: disable-next=E0611 from pyscf import hci # noqa: PLC0415 # hci is an optional module nao, nmo = mf_.mo_coeff.shape @@ -158,6 +159,7 @@ def run_solver( rdm2s = rdm2aa + rdm2ab + rdm2ab.transpose(2, 3, 0, 1) + rdm2bb elif solver == "SHCI": + # pylint: disable-next=E0401,E0611 from pyscf.shciscf import shci # noqa: PLC0415 # shci is an optional module nao, nmo = mf_.mo_coeff.shape @@ -176,9 +178,8 @@ def run_solver( rdm1_tmp, rdm2s = mch.fcisolver.make_rdm12(0, nmo, nelec) elif solver == "SCI": - from pyscf import ( # noqa: PLC0415 # cornell_shci is an optional module - cornell_shci, - ) + # pylint: disable-next=E0611 + from pyscf import cornell_shci # noqa: PLC0415 # optional module nao, nmo = mf_.mo_coeff.shape nelec = (nocc, nocc) From ecbc7961cc0e2dbec556396f6b5e3e4ecabbd1e6 Mon Sep 17 00:00:00 2001 From: Oskar Weser Date: Thu, 21 Nov 2024 14:41:56 -0500 Subject: [PATCH 7/8] enforce single # for comments --- src/kbe/autofrag.py | 4 ++-- src/molbe/external/optqn.py | 4 ++-- src/molbe/pfrag.py | 2 +- src/molbe/solver.py | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/kbe/autofrag.py b/src/kbe/autofrag.py index 8c20a98a..0d5587bf 100644 --- a/src/kbe/autofrag.py +++ b/src/kbe/autofrag.py @@ -471,7 +471,7 @@ def autogen( sys.exit() # kmesh lkpt ends - ## starts here + # starts here normlist = [] for i in coord: normlist.append(numpy.linalg.norm(i)) @@ -572,7 +572,7 @@ def autogen( # part of l,r,d,u,m,t but are in the # unit cell that is their k is 1 # for example, klsts[i] = 1 - ## WARNING !!! + # WARNING !!! # For systems like Graphene, BN, SiC, hexagonal 2D sheets, # BE4 can give wrong fragmentations # the following code adds in redundant atoms diff --git a/src/molbe/external/optqn.py b/src/molbe/external/optqn.py index 91273c13..b25d47a6 100644 --- a/src/molbe/external/optqn.py +++ b/src/molbe/external/optqn.py @@ -333,7 +333,7 @@ def get_atbe_Jblock_frag(fobj, res_func): for k_ in range(len(edge)): if j_ > k_: continue - ## response w.r.t matching pot + # response w.r.t matching pot # edges tmpje_ = [] @@ -366,7 +366,7 @@ def get_atbe_Jblock_frag(fobj, res_func): Jc.append(tmpjc_) - ## response w.r.t. chem pot + # response w.r.t. chem pot # edge xe.append(dP_mu[edge[j_], edge[k_]]) cout += 1 diff --git a/src/molbe/pfrag.py b/src/molbe/pfrag.py index 408566ed..3bca41e0 100644 --- a/src/molbe/pfrag.py +++ b/src/molbe/pfrag.py @@ -323,7 +323,7 @@ def set_udim(self, cout): return cout def energy(self, rdm2s, eri=None, print_fragE=False): - ## This function uses old energy expression and will be removed + # This function uses old energy expression and will be removed rdm2s = numpy.einsum( "ijkl,pi,qj,rk,sl->pqrs", 0.5 * rdm2s, diff --git a/src/molbe/solver.py b/src/molbe/solver.py index e8f1a9e9..840ebcac 100644 --- a/src/molbe/solver.py +++ b/src/molbe/solver.py @@ -813,7 +813,7 @@ def solve_block2(mf: object, nocc: int, frag_scratch: str = None, **solver_kwarg mc = mcscf.CASCI(mf, norb, nelec) mc.fcisolver = dmrgscf.DMRGCI(mf.mol) - ###Sweep scheduling + # Sweep scheduling mc.fcisolver.scheduleSweeps = schedule_kwargs.pop( "scheduleSweeps", [ @@ -844,7 +844,7 @@ def solve_block2(mf: object, nocc: int, frag_scratch: str = None, **solver_kwarg "scheduleNoises", [max_noise, max_noise, max_noise / 10, max_noise / 100, max_noise / 100, 0.0], ) - ###Other DMRG parameters + # Other DMRG parameters mc.fcisolver.threads = int(os.environ.get("OMP_NUM_THREADS", 8)) mc.fcisolver.twodot_to_onedot = int(twodot_to_onedot) mc.fcisolver.maxIter = int(max_iter) @@ -857,7 +857,7 @@ def solve_block2(mf: object, nocc: int, frag_scratch: str = None, **solver_kwarg mc.kernel(orbs) rdm1, rdm2 = dmrgscf.DMRGCI.make_rdm12(mc.fcisolver, root, norb, nelec) - ###Subtract off non-cumulant contribution to correlated 2RDM. + # Subtract off non-cumulant contribution to correlated 2RDM. if use_cumulant: hf_dm = numpy.zeros_like(rdm1) hf_dm[numpy.diag_indices(nocc)] += 2.0 From 8d93ebd3b5fc951e65480ed2ffc8644ced54dd5b Mon Sep 17 00:00:00 2001 From: Oskar Weser Date: Thu, 21 Nov 2024 14:42:14 -0500 Subject: [PATCH 8/8] ignore unresolved import for optional package and reraise cc solver exception --- src/molbe/solver.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/molbe/solver.py b/src/molbe/solver.py index 840ebcac..f00877df 100644 --- a/src/molbe/solver.py +++ b/src/molbe/solver.py @@ -139,6 +139,7 @@ def be_func( rdm1_tmp = mc.make_rdm1(civec, mc.norb, mc.nelec) elif solver == "HCI": + # pylint: disable-next=E0611 from pyscf import hci # noqa: PLC0415 # optional module nao, nmo = fobj._mf.mo_coeff.shape @@ -172,6 +173,7 @@ def be_func( rdm2s = rdm2aa + rdm2ab + rdm2ab.transpose(2, 3, 0, 1) + rdm2bb elif solver == "SHCI": + # pylint: disable-next=E0611,E0401 from pyscf.shciscf import shci # noqa: PLC0415 # shci is optional if scratch_dir is None and be_var.CREATE_SCRATCH_DIR: @@ -203,6 +205,7 @@ def be_func( rdm1_tmp, rdm2s = mch.fcisolver.make_rdm12(0, nmo, nelec) elif solver == "SCI": + # pylint: disable-next=E0611 from pyscf import cornell_shci # noqa: PLC0415 # optional module nao, nmo = fobj._mf.mo_coeff.shape @@ -685,16 +688,11 @@ def solve_ccsd( try: cc__.verbose = verbose cc__.kernel(eris=eris) - except: + except Exception as e: print(flush=True) - print( - "Exception in CCSD -> applying level_shift=0.2, diis_space=25", flush=True - ) + print("Exception in CCSD, play with different CC options.", flush=True) print(flush=True) - cc__.verbose = 4 - cc__.diis_space = 25 - cc__.level_shift = 0.2 - cc__.kernel(eris=eris) + raise e # Extract the CCSD amplitudes t1 = cc__.t1 @@ -782,6 +780,7 @@ def solve_block2(mf: object, nocc: int, frag_scratch: str = None, **solver_kwarg """ + # pylint: disable-next=E0611 from pyscf import dmrgscf # noqa: PLC0415 # optional module use_cumulant = solver_kwargs.pop("use_cumulant", True)