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

Head and wings corrections for k-dTDA #58

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d05d6b0
Cleaning up branches
mkakcl Jan 29, 2024
83e7741
Aligning with dRPA and ewald correction added.
mkakcl Feb 8, 2024
c4dcf82
Updates to Head term
mkakcl Feb 21, 2024
2b0bb39
kpt changes for rounding
mkakcl Feb 29, 2024
779a964
Changes hopefully fixing the naux issues and subsequent Hermiticity i…
mkakcl Mar 11, 2024
12929dc
Initial wings implementation.
mkakcl Mar 19, 2024
0683748
Small fix
mkakcl Mar 19, 2024
f7a844e
Head and wings cleanup
mkakcl Mar 21, 2024
3431d18
Potential MPI fix
mkakcl Apr 3, 2024
fdd0b30
More cleanup
mkakcl Apr 3, 2024
aff4dc5
A few merge issues resolved
mkakcl Apr 4, 2024
ac1ad7e
Linting
mkakcl Apr 4, 2024
c7beb4f
More linting
mkakcl Apr 4, 2024
26e873b
Even more linting
mkakcl Apr 4, 2024
ad9cdee
Fix kwargs
mkakcl Apr 4, 2024
43370f5
Linting
mkakcl Apr 4, 2024
d0acdee
einsum _contraction order correction
mkakcl Apr 5, 2024
fe62183
Additional MPI changes
mkakcl Apr 8, 2024
62fd849
Change to util einsums
mkakcl Apr 10, 2024
cdc2756
HW test for kTDA
mkakcl Apr 17, 2024
32ad7ea
Merge branch 'master' into HW_TDA_from_master
mkakcl Apr 17, 2024
f16b1d9
Update test
mkakcl Apr 17, 2024
1fe4a2c
Frozen static field fix
mkakcl Apr 18, 2024
79d8696
Changes pre discussion in PR
mkakcl May 1, 2024
f00bbfc
Linting
mkakcl May 1, 2024
cbe49f8
Further linting
mkakcl May 2, 2024
5d845b4
More linting
mkakcl May 2, 2024
e5e2b1a
Support inheritance for static SE with finite size corrections
obackhouse May 28, 2024
1e6a5bd
Fix madelung attribute
obackhouse May 28, 2024
7534d99
HWB implementation
mkakcl Sep 27, 2024
5b14ad8
Merge remote-tracking branch 'origin/HW_TDA_from_master' into HW_TDA_…
mkakcl Sep 27, 2024
e2941f7
Corrections to HWB implementation
mkakcl Sep 30, 2024
d7ebf2d
Example and tests for HWB corrections
mkakcl Sep 30, 2024
7f361ee
Small fix and updated test values
mkakcl Sep 30, 2024
b2c0fe7
Some changes related to the old PR and linting.
mkakcl Sep 30, 2024
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
46 changes: 46 additions & 0 deletions examples/20-finite_size_corrections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""
Examples of finite size corrections for `momentGW` calculations for periodic solids.
"""

import numpy as np
from pyscf.pbc import dft, gto

from momentGW import KGW, KUGW

# Define a unit cell
cell = gto.Cell()
cell.atom = "He 0 0 0; He 1 1 1"
cell.basis = "6-31g"
cell.a = np.eye(3) * 3
cell.verbose = 5
cell.build()
kpts = cell.make_kpts([3, 1, 1])

# Run a DFT calculation
mf = dft.KRKS(cell, kpts)
mf = mf.density_fit()
mf.xc = "b3lyp"
mf.kernel()

# For any `pbc` calculation a finite size correction can be added for
# the divergence associated with G = 0, q=0 for GDF Coulomb integrals.
# This is done by setting the `fsc` attribute to any combination of
# "H", "W", and/or "B" for the Head, Wings and Body portion of the
# correction. The Ewald correction is added in all cases. The default
# is `None` which disables the correction.

# RHF reference
gw = KGW(mf)
gw.polarizability = "dRPA"
gw.fsc = "HWB"
gw.kernel(nmom_max=3)

gw = KGW(mf)
gw.polarizability = "dTDA"
gw.fsc = "HW"
gw.kernel(nmom_max=3)

gw = KGW(mf)
gw.polarizability = "dRPA"
gw.fsc = "H"
gw.kernel(nmom_max=3)
38 changes: 35 additions & 3 deletions momentGW/gw.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,37 @@ def name(self):
polarizability = self.polarizability.upper().replace("DTDA", "dTDA").replace("DRPA", "dRPA")
return f"{polarizability}-G0W0"

def get_veff(self, integrals, dm=None, **kwargs):
"""Get the effective potential.

Parameters
----------
integrals : Integrals
Integrals object.
dm : numpy.ndarray, optional
Density matrix. If `None`, determine using `self.make_rdm1`.
Default value is `None`.
**kwargs : dict, optional
Additional keyword arguments passed to the integrals object.

Returns
-------
veff : numpy.ndarray
Effective potential.
"""

# Get the density matrix
if dm is None:
dm = self.make_rdm1()

# Get the effective potential
veff = integrals.get_veff(dm, **kwargs)

return veff

@logging.with_timer("Static self-energy")
@logging.with_status("Building static self-energy")
def build_se_static(self, integrals):
def build_se_static(self, integrals, force_build=False):
"""
Build the static part of the self-energy, including the Fock
matrix.
Expand All @@ -155,6 +183,10 @@ def build_se_static(self, integrals):
----------
integrals : Integrals
Integrals object.
force_build : bool, optional
If `True`, force the static self-energy to be built, even if
the underlying mean-field object is Hartree--Fock. Default
value is `False`.

Returns
-------
Expand All @@ -168,15 +200,15 @@ def build_se_static(self, integrals):
dm = self._scf.make_rdm1(mo_coeff=self._mo_coeff)

# Get the contribution from the exchange-correlation potential
if getattr(self._scf, "xc", "hf") == "hf":
if getattr(self._scf, "xc", "hf") == "hf" and not force_build:
se_static = np.zeros_like(dm)
se_static = se_static[..., mask, :][..., :, mask]
else:
with util.SilentSCF(self._scf):
veff = self._scf.get_veff(None, dm)[..., mask, :][..., :, mask]
vj = self._scf.get_j(None, dm)[..., mask, :][..., :, mask]

vhf = integrals.get_veff(dm, j=vj, basis="ao")
vhf = self.get_veff(integrals, dm=dm, j=vj, basis="ao")
se_static = vhf - veff
se_static = util.einsum(
"...pq,...pi,...qj->...ij", se_static, np.conj(self.mo_coeff), self.mo_coeff
Expand Down
6 changes: 3 additions & 3 deletions momentGW/pbc/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ class BaseKGW(BaseGW):
thc_opts : dict, optional
Dictionary of options to be used for THC calculations. Current
implementation requires a filepath to import the THC integrals.
fc : bool, optional
fsc : bool, optional
If `True`, apply finite size corrections. Default value is
`False`.
"""

_defaults = OrderedDict(
**BaseGW._defaults,
fc=False,
fsc=None,
)
_defaults["compression"] = None

Expand All @@ -70,7 +70,7 @@ def __init__(self, mf, **kwargs):
super().__init__(mf, **kwargs)

# Options
self.fc = False
self.fsc = None

# Attributes
self._kpts = KPoints(self.cell, getattr(mf, "kpts", np.zeros((1, 3))))
Expand Down
66 changes: 59 additions & 7 deletions momentGW/pbc/gw.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class KGW(BaseKGW, GW):
thc_opts : dict, optional
Dictionary of options to be used for THC calculations. Current
implementation requires a filepath to import the THC integrals.
fc : bool, optional
fsc : bool, optional
If `True`, apply finite size corrections. Default value is
`False`.
"""
Expand All @@ -69,9 +69,44 @@ def name(self):
polarizability = self.polarizability.upper().replace("DTDA", "dTDA").replace("DRPA", "dRPA")
return f"{polarizability}-KG0W0"

def get_veff(self, integrals, dm=None, **kwargs):
"""Get the effective potential.

Parameters
----------
integrals : KIntegrals
Integrals object.
dm : numpy.ndarray, optional
Density matrix at each k-point. If `None`, determine using
`self.make_rdm1`. Default value is `None`.
**kwargs : dict, optional
Additional keyword arguments passed to the integrals object.

Returns
-------
veff : numpy.ndarray
Effective potential at each k-point.
"""

# Get the density matrix
if dm is None:
dm = self.make_rdm1()

# Set the default options
if "ewald" not in kwargs:
if self.fsc is not None:
kwargs = {**kwargs, "ewald": True}
else:
kwargs = {**kwargs, "ewald": False}

# Get the effective potential
veff = integrals.get_veff(dm, **kwargs)

return veff

@logging.with_timer("Static self-energy")
@logging.with_status("Building static self-energy")
def build_se_static(self, integrals):
def build_se_static(self, integrals, **kwargs):
"""
Build the static part of the self-energy, including the Fock
matrix.
Expand All @@ -80,14 +115,29 @@ def build_se_static(self, integrals):
----------
integrals : KIntegrals
Integrals object.
**kwargs : dict, optional
Additional keyword arguments.

Returns
-------
se_static : numpy.ndarray
Static part of the self-energy at each k-point. If
`self.diagonal_se`, non-diagonal elements are set to zero.
"""
return super().build_se_static(integrals)
if self.fsc is not None:
if len(list(self.fsc)) > 3:
raise ValueError(
"Finite size corrections require as an input a combination of H, W and B "
"for the different finite size corrections (H - Head, W - Wing, B - Body)")
for i, letter in enumerate(list(self.fsc)):
if letter not in ["H", "W", "B"]:
raise ValueError(
"Finite size corrections require as an input a combination of H, W and B "
"for the different finite size corrections (H - Head, W - Wing, B - Body)")
kwargs = {**kwargs, "force_build": True}
else:
kwargs = {**kwargs, "force_build": False}
return super().build_se_static(integrals, **kwargs)

def build_se_moments(self, nmom_max, integrals, **kwargs):
"""Build the moments of the self-energy.
Expand All @@ -112,10 +162,10 @@ def build_se_moments(self, nmom_max, integrals, **kwargs):
"""

if self.polarizability.lower() == "dtda":
tda = dTDA(self, nmom_max, integrals, **kwargs)
tda = dTDA(self, nmom_max, integrals, fsc=self.fsc, **kwargs)
return tda.kernel()
if self.polarizability.lower() == "drpa":
rpa = dRPA(self, nmom_max, integrals, **kwargs)
rpa = dRPA(self, nmom_max, integrals, fsc=self.fsc, **kwargs)
return rpa.kernel()
elif self.polarizability.lower() == "thc-dtda":
tda = thc.dTDA(self, nmom_max, integrals, **kwargs)
Expand Down Expand Up @@ -154,6 +204,8 @@ def ao2mo(self, transform=True):
compression=self.compression,
compression_tol=self.compression_tol,
store_full=self.fock_loop,
mo_energy_w=self.mo_energy,
fsc=self.fsc,
input_path=self.thc_opts["file_path"],
)

Expand Down Expand Up @@ -334,7 +386,7 @@ def make_rdm1(self, gf=None):

@logging.with_timer("Energy")
@logging.with_status("Calculating energy")
def energy_hf(self, gf=None, integrals=None):
def energy_hf(self, gf=None, integrals=None, **kwargs):
"""Calculate the one-body (Hartree--Fock) energy.

Parameters
Expand Down Expand Up @@ -367,7 +419,7 @@ def energy_hf(self, gf=None, integrals=None):
"kpq,kpi,kqj->kij", self._scf.get_hcore(), self.mo_coeff.conj(), self.mo_coeff
)
rdm1 = self.make_rdm1()
fock = integrals.get_fock(rdm1, h1e)
fock = integrals.get_fock(rdm1, h1e, **kwargs)

# Calculate the Hartree--Fock energy at each k-point
e_1b = sum(energy.hartree_fock(rdm1[k], fock[k], h1e[k]) for k in self.kpts.loop(1))
Expand Down
Loading