Skip to content

Commit 3231824

Browse files
authored
Support linear dependent overlap matrix for k point sampling (#572)
* Linear dependent overlap matrix roughly supported for k point sampling * Forgot to add one file * Bug fix with previous merge and previous functionality * Another round of cleanup * Tests done!
1 parent fd88464 commit 3231824

File tree

12 files changed

+389
-43
lines changed

12 files changed

+389
-43
lines changed

gpu4pyscf/df/df_jk.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ def get_jk(self, mol=None, dm=None, hermi=1, with_j=True, with_k=True,
134134
vj, vk = self.with_df.get_jk(dm, hermi, with_j, with_k,
135135
self.direct_scf_tol, omega)
136136
else:
137-
vj, vk = super().get_jk(mol, dm, hermi, with_j, with_k, omega)
137+
raise ValueError(f"with_df field not found in a df object (type = {type(self)}) during a get_jk() call.")
138+
# vj, vk = super().get_jk(mol, dm, hermi, with_j, with_k, omega)
138139
return vj, vk
139140

140141
def nuc_grad_method(self):

gpu4pyscf/lib/cupy_helper.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ def pinv(a, lindep=1e-10):
836836
j2c = cupy.dot(v1/w[mask], v1.conj().T)
837837
return j2c
838838

839-
def cond(a, sympos=False):
839+
def cond(a, sympos=False, verbose=logger.WARN):
840840
"""
841841
Calculate the condition number of a matrix.
842842
@@ -847,27 +847,33 @@ def cond(a, sympos=False):
847847
Returns:
848848
float: The condition number of the matrix.
849849
"""
850+
if isinstance(verbose, logger.Logger):
851+
log = verbose
852+
else:
853+
log = logger.Logger(sys.stdout, verbose)
854+
850855
if a.shape[0] > cusolver.MAX_EIGH_DIM:
851856
if not SCIPY_EIGH_FOR_LARGE_ARRAYS:
852857
raise RuntimeError(
853858
f'Array size exceeds the maximum size {cusolver.MAX_EIGH_DIM}.')
854859
a = a.get()
855860
if sympos:
856861
s = scipy.linalg.eigvalsh(a)
857-
if s[0] <= 0:
858-
raise RuntimeError('matrix is not positive definite')
859-
return s[-1] / s[0]
860-
else:
861-
_, s, _ = scipy.linalg.svd(a)
862-
cond_number = s[0] / s[-1]
863-
return cond_number
864-
865-
if sympos:
866-
s = cupy.linalg.eigvalsh(a)
867-
if s[0] <= 0:
868-
raise RuntimeError('matrix is not positive definite')
869-
return s[-1] / s[0]
862+
if s[0] > 0:
863+
return s[-1] / s[0]
864+
else:
865+
log.warn(f'In condition number calculation, matrix is assumed to be positive definite, but it is not (minimal eigenvalue = {s[0]:e})')
866+
_, s, _ = scipy.linalg.svd(a)
867+
cond_number = s[0] / s[-1]
868+
return cond_number
869+
870870
else:
871+
if sympos:
872+
s = cupy.linalg.eigvalsh(a)
873+
if s[0] > 0:
874+
return s[-1] / s[0]
875+
else:
876+
log.warn(f'In condition number calculation, matrix is assumed to be positive definite, but it is not (minimal eigenvalue = {s[0]:e})')
871877
_, s, _ = cupy.linalg.svd(a)
872878
cond_number = s[0] / s[-1]
873879
return cond_number

gpu4pyscf/pbc/dft/krks.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ def get_veff(ks, cell=None, dm=None, dm_last=None, vhf_last=None, hermi=1,
5959
n, exc, vxc = ni.nr_rks(cell, ks.grids, ks.xc, dm, 0, hermi, kpts, kpts_band)
6060
log.debug('nelec by numeric integration = %s', n)
6161
if ks.do_nlc():
62+
raise NotImplementedError("VV10 not implemented for periodic system")
6263
if ni.libxc.is_nlc(ks.xc):
6364
xc = ks.xc
6465
else:
@@ -73,12 +74,12 @@ def get_veff(ks, cell=None, dm=None, dm_last=None, vhf_last=None, hermi=1,
7374
vj, vk = _get_jk(ks, cell, dm, hermi, kpts, kpts_band, not j_in_xc,
7475
dm_last, vhf_last)
7576
if not j_in_xc:
76-
vxc += vj
77+
vxc = vxc + vj
7778
ecoul = None
7879
if ground_state:
7980
ecoul = float(cp.einsum('Kij,Kji->', dm, vj).real.get()) * .5 * weight
8081
if hybrid:
81-
vxc -= .5 * vk
82+
vxc = vxc - .5 * vk
8283
if ground_state:
8384
exc -= float(cp.einsum('Kij,Kji->', dm, vk).real.get()) * .25 * weight
8485
vxc = tag_array(vxc, ecoul=ecoul, exc=exc, vj=vj, vk=vk)

gpu4pyscf/pbc/dft/kuks.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def get_veff(ks, cell=None, dm=None, dm_last=None, vhf_last=None, hermi=1,
6060
ks.initialize_grids(cell, dm, kpts)
6161
n, exc, vxc = ni.nr_uks(cell, ks.grids, ks.xc, dm, 0, hermi, kpts, kpts_band)
6262
if ks.do_nlc():
63+
raise NotImplementedError("VV10 not implemented for periodic system")
6364
if ni.libxc.is_nlc(ks.xc):
6465
xc = ks.xc
6566
else:
@@ -75,12 +76,12 @@ def get_veff(ks, cell=None, dm=None, dm_last=None, vhf_last=None, hermi=1,
7576
vj, vk = krks._get_jk(ks, cell, dm, hermi, kpts, kpts_band, not j_in_xc,
7677
dm_last, vhf_last)
7778
if not j_in_xc:
78-
vxc += vj[0] + vj[1]
79+
vxc = vxc + vj[0] + vj[1]
7980
ecoul = None
8081
if ground_state:
8182
ecoul = float(cp.einsum('nKij,mKji->', dm, vj).real.get()) * .5 * weight
8283
if hybrid:
83-
vxc -= vk
84+
vxc = vxc - vk
8485
if ground_state:
8586
exc -= float(cp.einsum('nKij,nKji->', dm, vk).real.get()) * .5 * weight
8687
vxc = tag_array(vxc, ecoul=ecoul, exc=exc, vj=vj, vk=vk)

gpu4pyscf/pbc/dft/rks.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ def get_veff(ks, cell=None, dm=None, dm_last=None, vhf_last=None, hermi=1,
8181
n, exc, vxc = ni.nr_rks(cell, ks.grids, ks.xc, dm, 0, hermi, kpt, kpts_band)
8282
log.debug('nelec by numeric integration = %s', n)
8383
if ks.do_nlc():
84+
warning_message = "ATTENTION!!! VV10 is only valid for open boundary, and it is incorrect for actual periodic system! " \
85+
"Lattice summation is not performed for the double integration. " \
86+
"Please use only under open boundary, i.e. neighbor images are well separated, and " \
87+
"all atoms belonging to one image is placed in the same image in the input."
88+
log.warn(warning_message)
89+
print(warning_message) # This is an important warning, so print even if verbose == 0.
90+
8491
if ni.libxc.is_nlc(ks.xc):
8592
xc = ks.xc
8693
else:

gpu4pyscf/pbc/dft/uks.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ def get_veff(ks, cell=None, dm=None, dm_last=None, vhf_last=None, hermi=1,
6868
ks.initialize_grids(cell, dm, kpt)
6969
n, exc, vxc = ni.nr_uks(cell, ks.grids, ks.xc, dm, 0, hermi, kpt, kpts_band)
7070
if ks.do_nlc():
71+
warning_message = "ATTENTION!!! VV10 is only valid for open boundary, and it is incorrect for actual periodic system! " \
72+
"Lattice summation is not performed for the double integration. " \
73+
"Please use only under open boundary, i.e. neighbor images are well separated, and " \
74+
"all atoms belonging to one image is placed in the same image in the input."
75+
log.warn(warning_message)
76+
print(warning_message) # This is an important warning, so print even if verbose == 0.
77+
7178
if ni.libxc.is_nlc(ks.xc):
7279
xc = ks.xc
7380
else:

gpu4pyscf/pbc/scf/hf.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,7 @@ def check_sanity(self):
125125
isinstance(self.with_df, df.DF)):
126126
logger.warn(self, 'exxdiv %s is not supported in DF', self.exxdiv)
127127

128-
if self.verbose >= logger.DEBUG:
129-
mol_hf.SCF.check_sanity(self)
128+
mol_hf.SCF.check_sanity(self)
130129
return self
131130

132131
@property

gpu4pyscf/pbc/scf/khf.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from pyscf.pbc import tools
2828
from gpu4pyscf.lib import logger, utils
2929
from gpu4pyscf.lib.cupy_helper import (
30-
return_cupy_array, contract, tag_array, sandwich_dot)
30+
return_cupy_array, contract, tag_array, sandwich_dot, eigh)
3131
from gpu4pyscf.scf import hf as mol_hf
3232
from gpu4pyscf.pbc.scf import hf as pbchf
3333
from gpu4pyscf.pbc import df
@@ -168,6 +168,9 @@ def energy_elec(mf, dm_kpts=None, h1e_kpts=None, vhf_kpts=None):
168168
return (e1+e_coul).real, e_coul.real
169169

170170
def canonicalize(mf, mo_coeff_kpts, mo_occ_kpts, fock=None):
171+
if hasattr(mf, 'overlap_canonical_decomposed_x') and mf.overlap_canonical_decomposed_x is not None:
172+
raise NotImplementedError("Overlap matrix canonical decomposition (removing linear dependency for diffused orbitals) "
173+
"not supported for canonicalize() function with k-point sampling")
171174
if fock is None:
172175
dm = mf.make_rdm1(mo_coeff_kpts, mo_occ_kpts)
173176
fock = mf.get_fock(dm=dm)
@@ -389,10 +392,26 @@ def eig(self, h_kpts, s_kpts):
389392
nkpts, nao = h_kpts.shape[:2]
390393
eig_kpts = cp.empty((nkpts, nao))
391394
mo_coeff_kpts = cp.empty((nkpts, nao, nao), dtype=h_kpts.dtype)
392-
for k in range(nkpts):
393-
e, c = self._eigh(h_kpts[k], s_kpts[k])
394-
eig_kpts[k] = e
395-
mo_coeff_kpts[k] = c
395+
396+
x_kpts = None
397+
if hasattr(self, 'overlap_canonical_decomposed_x') and self.overlap_canonical_decomposed_x is not None:
398+
x_kpts = [cp.asarray(x) for x in self.overlap_canonical_decomposed_x]
399+
400+
if x_kpts is None:
401+
for k in range(nkpts):
402+
e, c = eigh(h_kpts[k], s_kpts[k])
403+
eig_kpts[k] = e
404+
mo_coeff_kpts[k] = c
405+
else:
406+
for k in range(nkpts):
407+
xk = x_kpts[k]
408+
ek, ck = cp.linalg.eigh(xk.T.conj() @ h_kpts[k] @ xk)
409+
ck = xk @ ck
410+
_, nmo_k = xk.shape
411+
eig_kpts[k, :nmo_k] = ek
412+
eig_kpts[k, nmo_k:] = float(cp.max(cp.abs(ek))) * 2 + 1e5
413+
mo_coeff_kpts[k, :, :nmo_k] = ck
414+
mo_coeff_kpts[k, :, nmo_k:] = 0
396415
return eig_kpts, mo_coeff_kpts
397416

398417
def make_rdm1(self, mo_coeff_kpts=None, mo_occ_kpts=None, **kwargs):

gpu4pyscf/pbc/scf/kuhf.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ def canonicalize(mf, mo_coeff_kpts, mo_occ_kpts, fock=None):
174174
'''Canonicalization diagonalizes the UHF Fock matrix within occupied,
175175
virtual subspaces separatedly (without change occupancy).
176176
'''
177+
if hasattr(mf, 'overlap_canonical_decomposed_x') and mf.overlap_canonical_decomposed_x is not None:
178+
raise NotImplementedError("Overlap matrix canonical decomposition (removing linear dependency for diffused orbitals) "
179+
"not supported for canonicalize() function with k-point sampling")
177180
if fock is None:
178181
dm = mf.make_rdm1(mo_coeff_kpts, mo_occ_kpts)
179182
fock = mf.get_fock(dm=dm)

0 commit comments

Comments
 (0)