Skip to content

Commit 56f4378

Browse files
authored
Automatically apply SCF initial guess from existing wavefunction (#269)
* Automatically apply SCF initial guess from existing wavefunction * indention issue * Undefined variable * Bug fixes and update tests * Bug fixes --------- Co-authored-by: Qiming Sun <qiming.sun@bytedance.com>
1 parent fdaa9f4 commit 56f4378

File tree

15 files changed

+124
-101
lines changed

15 files changed

+124
-101
lines changed

gpu4pyscf/df/df.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def get_jk(self, dm, hermi=1, with_j=True, with_k=True,
123123
if key in self._rsh_df:
124124
rsh_df = self._rsh_df[key]
125125
else:
126-
rsh_df = self._rsh_df[key] = copy.copy(self).reset()
126+
rsh_df = self._rsh_df[key] = self.copy().reset()
127127
logger.info(self, 'Create RSH-DF object %s for omega=%s', rsh_df, omega)
128128

129129
return df_jk.get_jk(rsh_df, dm, hermi, with_j, with_k, direct_scf_tol, omega=omega)

gpu4pyscf/df/df_jk.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def build_df():
4747
if key in mf.with_df._rsh_df:
4848
rsh_df = mf.with_df._rsh_df[key]
4949
else:
50-
rsh_df = mf.with_df._rsh_df[key] = copy.copy(mf.with_df).reset()
50+
rsh_df = mf.with_df._rsh_df[key] = mf.with_df.copy().reset()
5151
rsh_df.build(omega=omega)
5252
return
5353

@@ -101,7 +101,7 @@ def _density_fit(mf, auxbasis=None, with_df=None, only_dfj=False):
101101
mf.with_df = with_df
102102
elif getattr(mf.with_df, 'auxbasis', None) != auxbasis:
103103
#logger.warn(mf, 'DF might have been initialized twice.')
104-
mf = copy.copy(mf)
104+
mf = mf.copy()
105105
mf.with_df = with_df
106106
mf.only_dfj = only_dfj
107107
return mf
@@ -528,7 +528,7 @@ def _get_jk(dfobj, dm, hermi=1, with_j=True, with_k=True,
528528
if key in dfobj._rsh_df:
529529
rsh_df = dfobj._rsh_df[key]
530530
else:
531-
rsh_df = dfobj._rsh_df[key] = copy.copy(dfobj).reset()
531+
rsh_df = dfobj._rsh_df[key] = dfobj.copy().reset()
532532
logger.info(dfobj, 'Create RSH-DF object %s for omega=%s', rsh_df, omega)
533533

534534
with rsh_df.mol.with_range_coulomb(omega):

gpu4pyscf/df/grad/rhf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def get_jk(mf_grad, mol=None, dm0=None, hermi=0, with_j=True, with_k=True, omega
7171
with_df = mf_grad.base.with_df._rsh_df[key]
7272
else:
7373
dfobj = mf_grad.base.with_df
74-
with_df = dfobj._rsh_df[key] = copy.copy(dfobj).reset()
74+
with_df = dfobj._rsh_df[key] = dfobj.copy().reset()
7575

7676
auxmol = with_df.auxmol
7777
if not hasattr(with_df, 'intopt') or with_df._cderi is None:
@@ -282,4 +282,4 @@ def extra_force(self, atom_id, envs):
282282
else:
283283
return 0
284284

285-
Grad = Gradients
285+
Grad = Gradients

gpu4pyscf/df/grad/uhf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def get_jk(mf_grad, mol=None, dm0=None, hermi=0, with_j=True, with_k=True,
5151
with_df = mf_grad.base.with_df._rsh_df[key]
5252
else:
5353
dfobj = mf_grad.base.with_df
54-
with_df = dfobj._rsh_df[key] = copy.copy(dfobj).reset()
54+
with_df = dfobj._rsh_df[key] = dfobj.copy().reset()
5555

5656
auxmol = with_df.auxmol
5757
if not hasattr(with_df, 'intopt') or with_df._cderi is None:

gpu4pyscf/df/tests/test_df_geomopt.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ def test_df_rhf_geomopt(self):
8282
assert np.linalg.norm(coords - coords_qchem) < 1e-4
8383

8484
def test_df_uks_geomopt(self):
85-
mf = uks.UKS(mol, xc=xc, disp=disp).density_fit()
85+
mf = uks.UKS(mol, xc=xc).density_fit()
86+
mf.disp = disp
8687
mf.grids.level = grids_level
8788
mf.kernel()
8889
mol_eq = optimize(mf, maxsteps=20)

gpu4pyscf/dft/roks.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,38 +16,42 @@
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

1818
import numpy as np
19-
from pyscf.dft import roks
20-
from gpu4pyscf.dft import numint
19+
import cupy as cp
20+
from pyscf.dft import roks as roks_cpu
2121
from gpu4pyscf.scf.rohf import ROHF
22-
from gpu4pyscf.dft import uks, gen_grid
22+
from gpu4pyscf.dft import rks, uks
2323
from gpu4pyscf.lib.cupy_helper import tag_array
24+
from gpu4pyscf.lib import utils
2425

25-
class ROKS(roks.ROKS, ROHF):
26-
from gpu4pyscf.lib.utils import to_cpu, to_gpu, device
26+
class ROKS(rks.KohnShamDFT, ROHF):
2727

2828
def __init__(self, mol, xc='LDA,VWN'):
29-
super().__init__(mol, xc)
30-
self._numint = numint.NumInt()
31-
self.disp = None
32-
self.screen_tol = 1e-14
33-
34-
grids_level = self.grids.level
35-
self.grids = gen_grid.Grids(mol)
36-
self.grids.level = grids_level
37-
38-
nlcgrids_level = self.nlcgrids.level
39-
self.nlcgrids = gen_grid.Grids(mol)
40-
self.nlcgrids.level = nlcgrids_level
29+
ROHF.__init__(self, mol)
30+
rks.KohnShamDFT.__init__(self, xc)
4131

4232
def get_veff(self, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
43-
if getattr(dm, 'mo_coeff', None) is not None:
33+
if dm is None:
34+
dm = self.make_rdm1()
35+
elif getattr(dm, 'mo_coeff', None) is not None:
4436
mo_coeff = dm.mo_coeff
4537
mo_occ_a = (dm.mo_occ > 0).astype(np.double)
4638
mo_occ_b = (dm.mo_occ ==2).astype(np.double)
47-
dm = tag_array(dm, mo_coeff=(mo_coeff,mo_coeff),
48-
mo_occ=(mo_occ_a,mo_occ_b))
39+
if dm.ndim == 2:
40+
dm = cp.repeat(dm[None]*.5, 2, axis=0)
41+
dm = tag_array(dm, mo_coeff=cp.asarray((mo_coeff,mo_coeff)),
42+
mo_occ=cp.asarray((mo_occ_a,mo_occ_b)))
43+
elif dm.ndim == 2:
44+
dm = cp.repeat(dm[None]*.5, 2, axis=0)
4945
return uks.get_veff(self, mol, dm, dm_last, vhf_last, hermi)
5046

5147
energy_elec = uks.UKS.energy_elec
5248
nuc_grad_method = NotImplemented
5349
to_hf = NotImplemented
50+
51+
to_gpu = utils.to_gpu
52+
device = utils.device
53+
54+
def to_cpu(self):
55+
mf = roks_cpu.ROKS(self.mol, xc=self.xc)
56+
utils.to_cpu(self, mf)
57+
return mf

gpu4pyscf/dft/uks.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

1818
import cupy
19-
from pyscf.dft import uks
19+
from pyscf.dft import uks as uks_cpu
2020
from pyscf import lib
2121
from gpu4pyscf.lib import logger
2222
from gpu4pyscf.dft import numint, gen_grid, rks
2323
from gpu4pyscf.scf import hf, uhf
2424
from gpu4pyscf.lib.cupy_helper import tag_array
25+
from gpu4pyscf.lib import utils
2526

2627

2728
def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
@@ -30,8 +31,9 @@ def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
3031
'''
3132
if mol is None: mol = ks.mol
3233
if dm is None: dm = ks.make_rdm1()
34+
assert dm.ndim == 3
3335
t0 = logger.init_timer(ks)
34-
rks.initialize_grids(ks, mol, dm)
36+
rks.initialize_grids(ks, mol, cupy.asarray(dm[0]+dm[1]))
3537

3638
if hasattr(ks, 'screen_tol') and ks.screen_tol is not None:
3739
ks.direct_scf_tol = ks.screen_tol
@@ -42,7 +44,7 @@ def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
4244
n, exc, vxc = (0,0), 0, 0
4345
else:
4446
max_memory = ks.max_memory - lib.current_memory()[0]
45-
n, exc, vxc = ni.nr_uks(mol, ks.grids, ks.xc, dm, max_memory=max_memory)
47+
n, exc, vxc = ni.nr_uks(mol, ks.grids, ks.xc, dm.view(cupy.ndarray), max_memory=max_memory)
4648
logger.debug(ks, 'nelec by numeric integration = %s', n)
4749
if ks.do_nlc():
4850
if ni.libxc.is_nlc(ks.xc):
@@ -61,7 +63,10 @@ def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
6163
vk = None
6264
if (ks._eri is None and ks.direct_scf and
6365
getattr(vhf_last, 'vj', None) is not None):
64-
ddm = cupy.asarray(dm) - cupy.asarray(dm_last)
66+
dm_last = cupy.asarray(dm_last)
67+
dm = cupy.asarray(dm)
68+
assert dm_last.ndim == 0 or dm_last.ndim == dm.ndim
69+
ddm = dm - dm_last
6570
vj = ks.get_j(mol, ddm[0]+ddm[1], hermi)
6671
vj += vhf_last.vj
6772
else:
@@ -71,7 +76,10 @@ def get_veff(ks, mol=None, dm=None, dm_last=0, vhf_last=0, hermi=1):
7176
omega, alpha, hyb = ni.rsh_and_hybrid_coeff(ks.xc, spin=mol.spin)
7277
if (ks._eri is None and ks.direct_scf and
7378
getattr(vhf_last, 'vk', None) is not None):
74-
ddm = cupy.asarray(dm) - cupy.asarray(dm_last)
79+
dm_last = cupy.asarray(dm_last)
80+
dm = cupy.asarray(dm)
81+
assert dm_last.ndim == 0 or dm_last.ndim == dm.ndim
82+
ddm = dm - dm_last
7583
vj, vk = ks.get_jk(mol, ddm, hermi)
7684
vk *= hyb
7785
if abs(omega) > 1e-10: # For range separated Coulomb operator
@@ -113,19 +121,15 @@ def energy_elec(ks, dm=None, h1e=None, vhf=None):
113121

114122

115123
class UKS(rks.KohnShamDFT, uhf.UHF):
116-
from gpu4pyscf.lib.utils import to_gpu, device
117-
_keys = {'disp', 'screen_tol'}
118-
119-
def __init__(self, mol, xc='LDA,VWN', disp=None):
124+
def __init__(self, mol, xc='LDA,VWN'):
120125
uhf.UHF.__init__(self, mol)
121126
rks.KohnShamDFT.__init__(self, xc)
122-
self.disp = disp
123127

124128
get_veff = get_veff
125-
get_vasp = uks.get_vsap
129+
get_vasp = uks_cpu.get_vsap
126130
energy_elec = energy_elec
127131
energy_tot = hf.RHF.energy_tot
128-
init_guess_by_vsap = uks.UKS.init_guess_by_vsap
132+
init_guess_by_vsap = uks_cpu.UKS.init_guess_by_vsap
129133

130134
to_hf = NotImplemented
131135

@@ -141,9 +145,10 @@ def nuc_grad_method(self):
141145
from gpu4pyscf.grad import uks as uks_grad
142146
return uks_grad.Gradients(self)
143147

148+
to_gpu = utils.to_gpu
149+
device = utils.device
150+
144151
def to_cpu(self):
145-
from gpu4pyscf.lib import utils
146-
mf = uks.UKS(self.mol, xc=self.xc)
147-
mf.disp = self.disp
152+
mf = uks_cpu.UKS(self.mol, xc=self.xc)
148153
utils.to_cpu(self, mf)
149154
return mf

gpu4pyscf/grad/tests/test_geomopt.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ def test_rhf_geomopt(self):
8181
assert np.linalg.norm(coords - coords_qchem) < 1e-4
8282

8383
def test_uks_geomopt(self):
84-
mf = uks.UKS(mol, xc=xc, disp=disp)
84+
mf = uks.UKS(mol, xc=xc)
85+
mf.disp = disp
8586
mf.grids.level = grids_level
8687
mf.kernel()
8788
mol_eq = optimize(mf, maxsteps=20)

gpu4pyscf/gto/mole.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def basis_seg_contraction(mol, allow_replica=False):
8282
bas_templates[key] = bas_of_ia
8383
_bas.append(bas_of_ia)
8484

85-
pmol = copy.copy(mol)
85+
pmol = mol.copy()
8686
pmol.output = mol.output
8787
pmol.verbose = mol.verbose
8888
pmol.stdout = mol.stdout

gpu4pyscf/scf/_response_functions.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import cupy
1717
from pyscf import lib
1818
from gpu4pyscf.lib import logger
19-
from gpu4pyscf.scf import hf, uhf
19+
from gpu4pyscf.scf import hf, uhf, rohf
2020

2121
def _gen_rhf_response(mf, mo_coeff=None, mo_occ=None,
2222
singlet=None, hermi=0, grids=None, max_memory=None):
@@ -133,7 +133,7 @@ def _gen_uhf_response(mf, mo_coeff=None, mo_occ=None,
133133
'''Generate a function to compute the product of UHF response function and
134134
UHF density matrices.
135135
'''
136-
assert isinstance(mf, uhf.UHF)
136+
assert isinstance(mf, (uhf.UHF, rohf.ROHF))
137137
if mo_coeff is None: mo_coeff = mf.mo_coeff
138138
if mo_occ is None: mo_occ = mf.mo_occ
139139
mol = mf.mol
@@ -194,3 +194,4 @@ def vind(dm1):
194194

195195
hf.RHF.gen_response = _gen_rhf_response
196196
uhf.UHF.gen_response = _gen_uhf_response
197+
rohf.ROHF.gen_response = _gen_uhf_response

0 commit comments

Comments
 (0)