Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

k-space TDA #9

Merged
merged 69 commits into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
e11fa27
Adds DF object
obackhouse May 4, 2023
39b50c0
Start on k-space implementation
obackhouse May 9, 2023
a010511
Merge branch 'main' into pbc
obackhouse Jul 13, 2023
f578037
Merge branch 'main' into pbc
obackhouse Jul 13, 2023
5272080
Some progress
obackhouse Jul 15, 2023
0035a2a
Deprecates vhf_df
obackhouse Jul 31, 2023
69b0357
Implements kTDA
obackhouse Aug 1, 2023
db456f7
Adds KGW tests
obackhouse Aug 1, 2023
ceb7ed8
Linting
obackhouse Aug 1, 2023
c06de23
Remove some TODOs
obackhouse Aug 1, 2023
d1a16c0
Start on interpolation (broken)
obackhouse Aug 2, 2023
86b1dba
More interpolation progress
obackhouse Aug 2, 2023
1866219
Adds Fock matrix functions for PBC
obackhouse Aug 3, 2023
8537beb
PBC fock loop working
obackhouse Aug 3, 2023
5f63b8d
More fixes
obackhouse Aug 3, 2023
86128c0
Merge conflicts
obackhouse Aug 3, 2023
68ee827
Small changes
obackhouse Aug 4, 2023
8e28366
Adds Integral class for pbc
obackhouse Aug 4, 2023
81762cb
Merge conflicts
obackhouse Aug 7, 2023
ba4f2ea
Updates for new Integrals formats
obackhouse Aug 7, 2023
0091491
Linting
obackhouse Aug 7, 2023
e83da12
Merge conflicts
obackhouse Aug 7, 2023
6599b50
Testing
obackhouse Aug 7, 2023
30f9c8b
Fock changes
obackhouse Aug 7, 2023
a794ed7
Working PBC Fock loop
obackhouse Aug 10, 2023
2c88e8d
Linting
obackhouse Aug 10, 2023
d18098e
Fixes compression for pbc
obackhouse Aug 10, 2023
4ec05e2
Fix wrong file change
obackhouse Aug 11, 2023
1d9c608
Conjugation fixes
obackhouse Aug 14, 2023
60739c7
Allow _moment_error with no prev moments
obackhouse Aug 14, 2023
c8cf6e7
Allow compression=None
obackhouse Aug 14, 2023
9e946fd
Allow compression=None
obackhouse Aug 14, 2023
a7986e9
Change default compression for pbc
obackhouse Aug 14, 2023
b71fe3e
Disable compression test
obackhouse Aug 14, 2023
ac30d0d
Adds evKGW
obackhouse Aug 14, 2023
14fa4ec
Forgot a file
obackhouse Aug 14, 2023
eae4a3d
Change qsGW to return full GF, QP energies can be obtained via qsGW.q…
obackhouse Aug 14, 2023
9aa7245
Improve inheritence of kernels
obackhouse Aug 14, 2023
7bd0224
Adds missing evKGW tests
obackhouse Aug 15, 2023
3fe4fb4
Adds qsKGW - tests failing
obackhouse Aug 15, 2023
fd8bbd6
Adds scKGW
obackhouse Aug 15, 2023
d8dd7f7
Trying to fix qsKGW
obackhouse Aug 15, 2023
f038fdd
Change kpts loop signature
obackhouse Aug 16, 2023
ee38d41
Linting
obackhouse Aug 16, 2023
2b587a3
Maybe fixes qsKGW
obackhouse Aug 16, 2023
07d4fdd
Test flake
obackhouse Aug 16, 2023
c4237d2
Last try
obackhouse Aug 16, 2023
2d945c6
MPI parallelism for pbc
obackhouse Aug 17, 2023
08e1333
Try larger eta for SRG test
obackhouse Aug 17, 2023
16eb854
Actually maybe it is just flaky lol
obackhouse Aug 17, 2023
c03949b
How about now
obackhouse Aug 17, 2023
f4ef182
Revert "How about now"
obackhouse Aug 17, 2023
be3aafc
Try different moment order
obackhouse Aug 18, 2023
d40e79a
SRG symmetry
obackhouse Aug 18, 2023
67c17dd
Tests on python3.11
obackhouse Aug 18, 2023
9a45c9e
Change test value - fails on zombie
obackhouse Aug 18, 2023
df9c1e2
Adds pbc example
obackhouse Aug 18, 2023
4348faf
Remove debug print
obackhouse Aug 18, 2023
11522d8
Improves interpolation interface, adds example
obackhouse Aug 18, 2023
6e28771
Add ewald term to K
obackhouse Aug 18, 2023
a31e840
Merge conflicts
obackhouse Aug 7, 2023
85b89aa
Separate moment convolution to own function
obackhouse Aug 18, 2023
796c2ed
Working on finite size corrections
obackhouse Aug 20, 2023
b524612
Make sure _opts are properly inherited
obackhouse Aug 21, 2023
8f4ff5e
Linting
obackhouse Aug 21, 2023
eda1381
Force hermiticity? has to be wrong
obackhouse Aug 21, 2023
6d3f1a7
Enable compression test
obackhouse Aug 22, 2023
d7056e8
Remove print
obackhouse Aug 22, 2023
fc5eeaf
Clarify qsGW energy attribute difference in example
obackhouse Aug 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

jobs:
build:
name: python "3.10" on ubuntu-latest
name: python "3.11" on ubuntu-latest
runs-on: ubuntu-latest

strategy:
Expand All @@ -20,7 +20,7 @@ jobs:
- name: Set up python
uses: actions/setup-python@v2
with:
python-version: "3.10"
python-version: "3.11"
- name: Upgrade pip
run: |
python -m pip install --upgrade pip
Expand Down
9 changes: 9 additions & 0 deletions examples/03-qsgw.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,12 @@
gw = qsGW(mf)
gw.solver_options = dict(optimise_chempot=True, fock_loop=True)
gw.kernel(nmom_max=3)

# qsGW finds a self-consistent Green's function in the space defined
# by the moment expansion, and via quasiparticle self-consistency
# obtains a (different) set of single particle Koopmans states. Both
# of these can be accessed via the `gw` object:
print("QP energies:")
print(gw.qp_energy)
print("GF energies:")
print(gw.gf.energy)
14 changes: 7 additions & 7 deletions examples/11-srg_qsgw_s_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

# GW
gw = GW(mf)
_, gf, se = gw.kernel(nmom_max)
_, gf, se, _ = gw.kernel(nmom_max)
gf.remove_uncoupled(tol=0.8)
if which == "ip":
gw_eta = -gf.get_occupied().energy.max() * HARTREE2EV
Expand All @@ -50,12 +50,12 @@
# qsGW
gw = qsGW(mf)
gw.eta = 0.05
_, gf, se = gw.kernel(nmom_max)
_, gf, se, _ = gw.kernel(nmom_max)
gf.remove_uncoupled(tol=0.8)
if which == "ip":
qsgw_eta = -gf.get_occupied().energy.max() * HARTREE2EV
qsgw_eta = -np.max(gw.qp_energy[mf.mo_occ > 0]) * HARTREE2EV
else:
qsgw_eta = gf.get_virtual().energy.min() * HARTREE2EV
qsgw_eta = np.min(gw.qp_energy[mf.mo_occ == 0]) * HARTREE2EV

# SRG-qsGW
s_params = sorted(list(data.keys()))[::-1]
Expand All @@ -72,16 +72,16 @@
gw.diis_space = 10
gw.conv_tol = 1e-5
gw.conv_tol_moms = 1
conv, gf, se = gw.kernel(nmom_max, moments=moments)
conv, gf, se, _ = gw.kernel(nmom_max, moments=moments)
moments = (
se.get_occupied().moment(range(nmom_max+1)),
se.get_virtual().moment(range(nmom_max+1)),
)
gf.remove_uncoupled(tol=0.8)
if which == "ip":
qsgw_srg.append(-gf.get_occupied().energy.max() * HARTREE2EV)
qsgw_srg.append(-np.max(gw.qp_energy[mf.mo_occ > 0]) * HARTREE2EV)
else:
qsgw_srg.append(gf.get_virtual().energy.min() * HARTREE2EV)
qsgw_srg.append(np.min(gw.qp_energy[mf.mo_occ == 0]) * HARTREE2EV)

qsgw_srg = np.array(qsgw_srg)

Expand Down
44 changes: 44 additions & 0 deletions examples/30-ktda.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Example of running k-space GW calculations with dTDA screening.
"""

import numpy as np
from pyscf.pbc import gto, dft
from momentGW.pbc.gw import KGW
from momentGW.pbc.qsgw import qsKGW
from momentGW.pbc.evgw import evKGW
from momentGW.pbc.scgw import scKGW

cell = gto.Cell()
cell.atom = "He 0 0 0; He 1 1 1"
cell.a = np.eye(3) * 3
cell.basis = "6-31g"
cell.verbose = 5
cell.build()

kpts = cell.make_kpts([2, 2, 2])

mf = dft.KRKS(cell, kpts)
mf = mf.density_fit()
mf.xc = "hf"
mf.kernel()

# KGW
gw = KGW(mf)
gw.polarizability = "dtda"
gw.kernel(nmom_max=5)

# qsKGW
gw = qsKGW(mf)
gw.polarizability = "dtda"
gw.srg = 100
gw.kernel(nmom_max=1)

# evKGW
gw = evKGW(mf)
gw.polarizability = "dtda"
gw.kernel(nmom_max=1)

# scKGW
gw = scKGW(mf)
gw.polarizability = "dtda"
gw.kernel(nmom_max=1)
55 changes: 55 additions & 0 deletions examples/31-kpt_interpolation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Example of interpolation of a GW calculation onto a new k-point mesh.
"""

import numpy as np
import matplotlib.pyplot as plt
from pyscf.pbc import gto, dft
from momentGW.pbc.gw import KGW

cell = gto.Cell()
cell.atom = "H 0 0 0; H 0 0 1"
cell.a = np.array([[25, 0, 0], [0, 25, 0], [0, 0, 2]])
cell.basis = "sto6g"
cell.max_memory = 1e10
cell.verbose = 5
cell.build()

kmesh1 = [1, 1, 3]
kmesh2 = [1, 1, 9]
kpts1 = cell.make_kpts(kmesh1)
kpts2 = cell.make_kpts(kmesh2)

mf1 = dft.KRKS(cell, kpts1, xc="hf")
mf1 = mf1.density_fit(auxbasis="weigend")
mf1.exxdiv = None
mf1.conv_tol = 1e-10
mf1.kernel()

mf2 = dft.KRKS(cell, kpts2, xc="hf")
mf2 = mf2.density_fit(mf1.with_df.auxbasis)
mf2.exxdiv = mf1.exxdiv
mf2.conv_tol = mf1.conv_tol
mf2.kernel()

gw1 = KGW(mf1)
gw1.polarizability = "dtda"
gw1.kernel(5)

gw2 = gw1.interpolate(mf2, 5)

e1 = gw1.qp_energy
e2 = gw2.qp_energy


def get_xy(kpts, e):
kpts = kpts.wrap_around(kpts._kpts)[:, 2]
arg = np.argsort(kpts)
return kpts[arg], np.array(e)[arg]

plt.figure()
plt.plot(*get_xy(gw1.kpts, e1), "C0.-", label="original")
plt.plot(*get_xy(gw2.kpts, e2), "C2.-", label="interpolated")
handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())
plt.show()
4 changes: 4 additions & 0 deletions momentGW/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@
from momentGW.evgw import evGW
from momentGW.scgw import scGW
from momentGW.qsgw import qsGW
from momentGW.pbc.gw import KGW
from momentGW.pbc.evgw import evKGW
from momentGW.pbc.qsgw import qsKGW
from momentGW.pbc.scgw import scKGW
124 changes: 124 additions & 0 deletions momentGW/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Base class for moment-constrained GW solvers.
"""

import warnings

import numpy as np
from pyscf import lib
from pyscf.agf2 import mpi_helper
Expand Down Expand Up @@ -82,6 +84,9 @@ def __init__(self, mf, **kwargs):
self.stdout = self.mol.stdout
self.max_memory = 1e10

if kwargs.pop("vhf_df", None) is not None:
warnings.warn("Keyword argument vhf_df is deprecated.", DeprecationWarning)

for key, val in kwargs.items():
if not hasattr(self, key):
raise AttributeError("%s has no attribute %s", self.name, key)
Expand All @@ -97,6 +102,7 @@ def __init__(self, mf, **kwargs):
self.converged = None
self.se = None
self.gf = None
self._qp_energy = None

self._keys = set(self.__dict__.keys()).union(self._opts)

Expand All @@ -118,10 +124,60 @@ def build_se_moments(self, *args, **kwargs):
def solve_dyson(self, *args, **kwargs):
raise NotImplementedError

def _kernel(self, *args, **kwargs):
raise NotImplementedError

def kernel(
self,
nmom_max,
mo_energy=None,
mo_coeff=None,
moments=None,
integrals=None,
):
if mo_coeff is None:
mo_coeff = self.mo_coeff
if mo_energy is None:
mo_energy = self.mo_energy

cput0 = (logger.process_clock(), logger.perf_counter())
self.dump_flags()
logger.info(self, "nmom_max = %d", nmom_max)

self.converged, self.gf, self.se, self._qp_energy = self._kernel(
nmom_max,
mo_energy,
mo_coeff,
integrals=integrals,
)

gf_occ = self.gf.get_occupied()
gf_occ.remove_uncoupled(tol=1e-1)
for n in range(min(5, gf_occ.naux)):
en = -gf_occ.energy[-(n + 1)]
vn = gf_occ.coupling[:, -(n + 1)]
qpwt = np.linalg.norm(vn) ** 2
logger.note(self, "IP energy level %d E = %.16g QP weight = %0.6g", n, en, qpwt)

gf_vir = self.gf.get_virtual()
gf_vir.remove_uncoupled(tol=1e-1)
for n in range(min(5, gf_vir.naux)):
en = gf_vir.energy[n]
vn = gf_vir.coupling[:, n]
qpwt = np.linalg.norm(vn) ** 2
logger.note(self, "EA energy level %d E = %.16g QP weight = %0.6g", n, en, qpwt)

logger.timer(self, self.name, *cput0)

return self.converged, self.gf, self.se, self.qp_energy

@staticmethod
def _moment_error(t, t_prev):
"""Compute scaled error between moments."""

if t_prev is None:
t_prev = np.zeros_like(t)

error = 0
for a, b in zip(t, t_prev):
a = a / max(np.max(np.abs(a)), 1)
Expand All @@ -141,6 +197,63 @@ def _gf_to_occ(gf):

return occ

@staticmethod
def _gf_to_energy(gf):
"""Return the `energy` attribute of a `gf`. Allows hooking in
`pbc` methods to retain syntax.
"""
return gf.energy

@staticmethod
def _gf_to_coupling(gf):
"""Return the `coupling` attribute of a `gf`. Allows hooking in
`pbc` methods to retain syntax.
"""
return gf.coupling

def _gf_to_mo_energy(self, gf):
"""Find the poles of a GF which best overlap with the MOs.

Parameters
----------
gf : GreensFunction
Green's function object.

Returns
-------
mo_energy : ndarray
Updated MO energies.
"""

check = set()
mo_energy = np.zeros_like(self.mo_energy)

for i in range(self.nmo):
arg = np.argmax(gf.coupling[i] ** 2)
mo_energy[i] = gf.energy[arg]
check.add(arg)

if len(check) != self.nmo:
logger.warn(self, "Inconsistent quasiparticle weights!")

return mo_energy

@property
def qp_energy(self):
"""
Return the quasiparticle energies. For most GW methods, this
simply consists of the poles of the `self.gf` that best
overlap with the MOs, in order. In some methods such as qsGW,
these two quantities are not the same.
"""

if self._qp_energy is not None:
return self._qp_energy

qp_energy = self._gf_to_mo_energy(self.gf)

return qp_energy

@property
def mol(self):
return self._scf.mol
Expand All @@ -151,6 +264,17 @@ def with_df(self):
raise ValueError("GW solvers require density fitting.")
return self._scf.with_df

@property
def has_fock_loop(self):
"""
Returns a boolean indicating whether the solver requires a Fock
loop. For most GW methods, this is simply `self.fock_loop`. In
some methods such as qsGW, a Fock loop is required with or
without `self.fock_loop` for the quasiparticle self-consistency,
with this property acting as a hook to indicate this.
"""
return self.fock_loop

get_nmo = get_nmo
get_nocc = get_nocc
get_frozen_mask = get_frozen_mask
Expand Down
Loading
Loading