fcdft 1.0.2__tar.gz → 1.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {fcdft-1.0.2 → fcdft-1.1.4}/MANIFEST.in +1 -0
  2. fcdft-1.1.4/PKG-INFO +6 -0
  3. fcdft-1.1.4/fcdft/__init__.py +1 -0
  4. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/df/df_jk.py +65 -2
  5. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/df/grad/rks.py +27 -13
  6. fcdft-1.1.4/fcdft/dft/gen_grid.py +88 -0
  7. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/grad/rks.py +3 -3
  8. fcdft-1.1.4/fcdft/gto/mole.py +110 -0
  9. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/CMakeLists.txt +1 -0
  10. fcdft-1.1.4/fcdft/lib/df/CMakeLists.txt +8 -0
  11. fcdft-1.1.4/fcdft/lib/df/nr_contract_k.c +13 -0
  12. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/dft/quadrature.c +44 -4
  13. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/fcdft_helper.c +11921 -12167
  14. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/pbe/CMakeLists.txt +3 -2
  15. fcdft-1.1.4/fcdft/lib/pbe/poisson.c +152 -0
  16. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/pbe_helper.c +17872 -18275
  17. fcdft-1.1.4/fcdft/solvent/AMGX.json +32 -0
  18. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/solvent/_attach_solvent.py +5 -1
  19. fcdft-1.1.4/fcdft/solvent/boundary.py +384 -0
  20. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/solvent/calculus_helper.py +39 -0
  21. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/solvent/esp.py +8 -12
  22. fcdft-1.1.4/fcdft/solvent/grad/__init__.py +0 -0
  23. fcdft-1.1.4/fcdft/solvent/grad/pbe.py +416 -0
  24. fcdft-1.1.4/fcdft/solvent/ions.py +159 -0
  25. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/solvent/pbe.py +109 -308
  26. fcdft-1.1.4/fcdft/solvent/solver.py +281 -0
  27. fcdft-1.1.4/fcdft/tools/__init__.py +0 -0
  28. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/tools/molden.py +2 -1
  29. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/wbl/rks.py +40 -28
  30. fcdft-1.1.4/fcdft.egg-info/PKG-INFO +6 -0
  31. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft.egg-info/SOURCES.txt +12 -1
  32. fcdft-1.0.2/PKG-INFO +0 -5
  33. fcdft-1.0.2/fcdft/__init__.py +0 -1
  34. fcdft-1.0.2/fcdft/solvent/pbe_grad.py +0 -299
  35. fcdft-1.0.2/fcdft.egg-info/PKG-INFO +0 -5
  36. {fcdft-1.0.2 → fcdft-1.1.4}/AUTHORS +0 -0
  37. {fcdft-1.0.2 → fcdft-1.1.4}/LICENSE +0 -0
  38. {fcdft-1.0.2 → fcdft-1.1.4}/README.md +0 -0
  39. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/df/__init__.py +0 -0
  40. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/df/grad/__init__.py +0 -0
  41. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/df/grad/uks.py +0 -0
  42. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/dft/__init__.py +0 -0
  43. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/dft/numint.py +0 -0
  44. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/grad/__init__.py +0 -0
  45. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/grad/lifcdft.py +0 -0
  46. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/grad/uks.py +0 -0
  47. {fcdft-1.0.2/fcdft/hessian → fcdft-1.1.4/fcdft/gto}/__init__.py +0 -0
  48. {fcdft-1.0.2/fcdft/jellium → fcdft-1.1.4/fcdft/hessian}/__init__.py +0 -0
  49. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/hessian/lifcdft.py +0 -0
  50. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/hessian/numhess.py +0 -0
  51. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/hessian/thermo.py +0 -0
  52. {fcdft-1.0.2/fcdft/lifcdft → fcdft-1.1.4/fcdft/jellium}/__init__.py +0 -0
  53. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/jellium/jellium.py +0 -0
  54. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/__init__.py +0 -0
  55. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/dft/CMakeLists.txt +0 -0
  56. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/dft/nr_numint.c +0 -0
  57. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/dft/nr_numint.h +0 -0
  58. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/fcdft_helper.pyx +0 -0
  59. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/misc.py +0 -0
  60. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/pbe/boundary_condition.c +0 -0
  61. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/pbe/boundary_condition.h +0 -0
  62. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/pbe/constant.h +0 -0
  63. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lib/pbe_helper.pyx +0 -0
  64. {fcdft-1.0.2/fcdft/solvent → fcdft-1.1.4/fcdft/lifcdft}/__init__.py +0 -0
  65. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/lifcdft/lifcdft.py +0 -0
  66. {fcdft-1.0.2/fcdft/tools → fcdft-1.1.4/fcdft/solvent}/__init__.py +0 -0
  67. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/solvent/radii.py +0 -0
  68. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/tools/addons.py +0 -0
  69. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/wbl/__init__.py +0 -0
  70. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/wbl/abscissas.npy +0 -0
  71. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/wbl/uks.py +0 -0
  72. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft/wbl/weights.npy +0 -0
  73. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft.egg-info/dependency_links.txt +0 -0
  74. {fcdft-1.0.2 → fcdft-1.1.4}/fcdft.egg-info/top_level.txt +0 -0
  75. {fcdft-1.0.2 → fcdft-1.1.4}/setup.cfg +0 -0
  76. {fcdft-1.0.2 → fcdft-1.1.4}/setup.py +0 -0
@@ -2,3 +2,4 @@ include MANIFEST.in
2
2
 
3
3
  recursive-include fcdft/lib *.so *.c *.pyx *.h CMakeLists.txt dft
4
4
  recursive-include fcdft/wbl *.npy
5
+ recursive-include fcdft/solvent *.json
fcdft-1.1.4/PKG-INFO ADDED
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: fcdft
3
+ Version: 1.1.4
4
+ License-File: LICENSE
5
+ License-File: AUTHORS
6
+ Dynamic: license-file
@@ -0,0 +1 @@
1
+ __version__ = '1.1.4'
@@ -4,6 +4,12 @@ from pyscf.df import df_jk
4
4
  from pyscf import lib
5
5
  from pyscf.lib import logger
6
6
  from fcdft import wbl
7
+ import ctypes
8
+ import os
9
+ import fcdft
10
+ from pyscf.lib.numpy_helper import _dgemm
11
+
12
+ libdf = lib.load_library(os.path.join(fcdft.__path__[0], 'lib', 'libdf'))
7
13
 
8
14
  def density_fit(mf, auxbasis=None, with_df=None, only_dfj=False):
9
15
  from pyscf import df
@@ -128,13 +134,71 @@ def get_j(dfobj, dm, hermi=0, direct_scf_tol=1e-13):
128
134
  logger.timer(dfobj, 'df-vj', *t0)
129
135
  return numpy.asarray(vj).reshape(dm_shape)
130
136
 
137
+ # numpy.einsum replaced by custom dgemm for computational efficiency.
138
+ def get_jk(dfobj, dm, hermi=0, with_j=True, with_k=True, direct_scf_tol=1e-13):
139
+ assert (with_j or with_k)
140
+ if (not with_k and not dfobj.mol.incore_anyway and
141
+ # 3-center integral tensor is not initialized
142
+ dfobj._cderi is None):
143
+ return get_j(dfobj, dm, hermi, direct_scf_tol), None
144
+
145
+ t0 = t1 = (logger.process_clock(), logger.perf_counter())
146
+ log = logger.Logger(dfobj.stdout, dfobj.verbose)
147
+
148
+ dms = numpy.asarray(dm)
149
+ dm_shape = dms.shape
150
+ nao = dm_shape[-1]
151
+ dms = dms.reshape(-1,nao,nao)
152
+ nset = dms.shape[0]
153
+ vj = 0
154
+ vk = numpy.zeros_like(dms)
155
+
156
+ fdrv = libdf.nr_mapdm1
157
+
158
+ if numpy.iscomplexobj(dms):
159
+ if with_j:
160
+ vj = numpy.zeros_like(dms)
161
+ max_memory = dfobj.max_memory - lib.current_memory()[0]
162
+ blksize = max(4, int(min(dfobj.blockdim, max_memory*.22e6/8/nao**2)))
163
+ buf = numpy.empty((blksize,nao,nao))
164
+ for eri1 in dfobj.loop(blksize):
165
+ naux, nao_pair = eri1.shape
166
+ eri1 = lib.unpack_tril(eri1, out=buf)
167
+ if with_j:
168
+ tmp = numpy.tensordot(eri1, dms.real, axes=([1,2],[2,1]))
169
+ vj.real += numpy.tensordot(tmp.T, eri1, axes=([1],[0]))
170
+ tmp = numpy.tensordot(eri1, dms.imag, axes=([1,2],[2,1]))
171
+ vj.imag += numpy.tensordot(tmp.T, eri1, axes=([1],[0]))
172
+ buf2 = numpy.empty((naux,nao,nao), dtype=numpy.float64, order='C')
173
+ for k in range(nset):
174
+ dmsRe = numpy.asarray(dms[k].real, dtype=numpy.float64, order='C')
175
+ dmsIm = numpy.asarray(dms[k].imag, dtype=numpy.float64, order='C')
176
+ fdrv(buf2.ctypes.data_as(ctypes.c_void_p),
177
+ eri1.ctypes.data_as(ctypes.c_void_p),
178
+ dmsRe.ctypes.data_as(ctypes.c_void_p),
179
+ ctypes.c_int(nao), ctypes.c_int(naux))
180
+ vk[k].real += numpy.tensordot(buf2, eri1, axes=([0,2],[0,1]))
181
+ fdrv(buf2.ctypes.data_as(ctypes.c_void_p),
182
+ eri1.ctypes.data_as(ctypes.c_void_p),
183
+ dmsIm.ctypes.data_as(ctypes.c_void_p),
184
+ ctypes.c_int(nao), ctypes.c_int(naux))
185
+ vk[k].imag += numpy.tensordot(buf2, eri1, axes=([0,2],[0,1]))
186
+ t1 = log.timer_debug1('jk', *t1)
187
+ if with_j: vj = vj.reshape(dm_shape)
188
+ if with_k: vk = vk.reshape(dm_shape)
189
+ logger.timer(dfobj, 'df vj and vk', *t0)
190
+ return vj, vk
191
+
192
+ else:
193
+ return df_jk.get_jk(dfobj, dm, hermi, with_j, with_k, direct_scf_tol)
194
+
131
195
  class _DFHF(df_jk._DFHF):
132
196
  def get_jk(self, mol=None, dm=None, hermi=0, with_j=True, with_k=True, omega=None):
133
197
  if dm is None: dm = self.make_rdm1()
134
198
  if not with_k:
135
199
  return get_j(self.with_df, dm, hermi, self.direct_scf_tol), None
136
200
  else:
137
- return super().get_jk(mol, dm, hermi, with_j, with_k, omega)
201
+ return get_jk(self.with_df, dm, hermi, with_j, with_k, self.direct_scf_tol)
138
202
 
139
203
  def nuc_grad_method(self):
140
204
  from fcdft.df.grad import rks, uks
@@ -152,4 +216,3 @@ class _DFHF(df_jk._DFHF):
152
216
 
153
217
  def to_gpu(self):
154
218
  raise NotImplementedError
155
-
@@ -15,7 +15,7 @@ LINEAR_DEP_THRESHOLD = LINEAR_DEP_THR
15
15
 
16
16
  def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
17
17
  decompose_j2c='CD', lindep=LINEAR_DEP_THRESHOLD):
18
- """Copied from pyscf.df.grad.rhf and modified some parts to allow complex density matrix."""
18
+ """Copied from pyscf.df.grad.rhf and some parts modified to handle complex density matrices."""
19
19
  assert (with_j or with_k)
20
20
  if not with_k:
21
21
  return get_j (mf_grad, mol=mol, dm=dm, hermi=hermi), None
@@ -57,7 +57,7 @@ def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
57
57
  vk = numpy.zeros((nset,3,nao,nao), dtype=numpy.complex128)
58
58
  get_int3c_ip1 = df_rhf_grad._int3c_wrapper(mol, auxmol, 'int3c2e_ip1', 's1')
59
59
  max_memory = mf_grad.max_memory - lib.current_memory()[0]
60
- blksize = int(min(max(max_memory * .5e6/8 / (nao**2*3), 20), naux, 240))
60
+ blksize = int(min(max(max_memory * .5e6/8 / (nao**2*3), 20), naux, 80)) # 240 -> 80 for handling complex128
61
61
  ao_ranges = df_rhf_grad.balance_partition(aux_loc, blksize)
62
62
  fmmm = _ao2mo.libao2mo.AO2MOmmm_bra_nr_s1 # MO output index slower than AO output index; input AOs are asymmetric
63
63
  fdrv = _ao2mo.libao2mo.AO2MOnr_e2_drv # comp and aux indices are slower
@@ -74,10 +74,11 @@ def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
74
74
  vj[i,1] += numpy.dot (rhoj[i,p0:p1], int3c[1].reshape (p1-p0, -1)).reshape (nao, nao).T
75
75
  vj[i,2] += numpy.dot (rhoj[i,p0:p1], int3c[2].reshape (p1-p0, -1)).reshape (nao, nao).T
76
76
  t2 = logger.timer_debug1 (mf_grad, "df grad einsum rho_P (P|mn') rho_P", *t2)
77
+ tmp = numpy.empty ((3,p1-p0,nocc[i],nao), dtype=numpy.complex128)
77
78
  tmpRe = numpy.empty ((3,p1-p0,nocc[i],nao), dtype=numpy.float64)
78
79
  tmpIm = numpy.empty ((3,p1-p0,nocc[i],nao), dtype=numpy.float64)
79
80
  orbolRe = numpy.asarray(orbol[i].real, order='F')
80
- orbolIm = numpy.asarray(orbol[i].imag, order='F')
81
+ orbolIm = numpy.asarray(orbol[i].imag, order='F')
81
82
  fdrv(ftrans, fmmm, # lib.einsum ('xpmn,mi->xpin', int3c, orbol[i])
82
83
  tmpRe.ctypes.data_as(ctypes.c_void_p),
83
84
  int3c.ctypes.data_as(ctypes.c_void_p),
@@ -85,6 +86,7 @@ def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
85
86
  ctypes.c_int (3*(p1-p0)), ctypes.c_int (nao),
86
87
  (ctypes.c_int*4)(0, nocc[i], 0, nao),
87
88
  null, ctypes.c_int(0))
89
+ orbolRe = None
88
90
  fdrv(ftrans, fmmm, # lib.einsum ('xpmn,mi->xpin', int3c, orbol[i])
89
91
  tmpIm.ctypes.data_as(ctypes.c_void_p),
90
92
  int3c.ctypes.data_as(ctypes.c_void_p),
@@ -92,10 +94,13 @@ def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
92
94
  ctypes.c_int (3*(p1-p0)), ctypes.c_int (nao),
93
95
  (ctypes.c_int*4)(0, nocc[i], 0, nao),
94
96
  null, ctypes.c_int(0))
95
- tmp = tmpRe + 1.0j * tmpIm
97
+ # tmp = tmpRe + 1.0j * tmpIm
98
+ orbolIm = None
99
+ tmp.real, tmp.imag = tmpRe, tmpIm
100
+ tmpRe = tmpIm = None
96
101
  t2 = logger.timer_debug1 (mf_grad, "df grad einsum (P|mn') u_mi = dg_Pin", *t2)
97
102
  rhok = get_rhok (i, p0, p1)
98
- vk[i] += lib.einsum('xpoi,pok->xik', tmp, rhok)
103
+ vk[i] += numpy.tensordot(tmp, rhok, axes=([1,2],[0,1]))
99
104
  t2 = logger.timer_debug1 (mf_grad, "df grad einsum D_Pim dg_Pin = v_ij", *t2)
100
105
  rhok = tmp = None
101
106
  int3c = None
@@ -114,10 +119,12 @@ def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
114
119
  # dPiu C_uj -> dPij. *Not* symmetric i<->j: "i" has an occupancy
115
120
  # factor and "j" must not.
116
121
  max_memory = mf_grad.max_memory - lib.current_memory()[0]
117
- blksize = int(min(max(max_memory * .5e6/8 / (nao*max (nocc)), 20), naux))
122
+ # blksize = int(min(max(max_memory * .5e6/8 / (nao*max (nocc)), 20), naux))
123
+ # In principe, all occupation numbers are non-zero for open quantum systems.
124
+ blksize = int(min(max(max_memory * .5e6/8 / (nao*nao), 20), naux) / 3) # Divided by 3 for handling complex128
118
125
  rhok_oo = []
119
126
  for i, j in product (range (nset), repeat=2):
120
- tmp = numpy.empty ((naux,nocc[i],nocc[j]), numpy.complex128)
127
+ tmp = numpy.empty ((naux,nocc[i],nocc[j]), dtype=numpy.complex128)
121
128
  for p0, p1 in lib.prange(0, naux, blksize):
122
129
  rhok = get_rhok (i, p0, p1).reshape ((p1-p0)*nocc[i], nao)
123
130
  tmp[p0:p1] = lib.dot (rhok, orbol[j]).reshape (p1-p0, nocc[i], nocc[j])
@@ -147,8 +154,9 @@ def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
147
154
  # Here, the sparse matrix int3c is transformed into the smaller MO
148
155
  # basis. The latter approach is obviously more performant.
149
156
  for i in range (nset):
150
- bufRe = numpy.empty ((3, p1-p0, nocc[i], nao), dtype=numpy.float64)
151
- bufIm = numpy.empty ((3, p1-p0, nocc[i], nao), dtype=numpy.float64)
157
+ buf = numpy.empty((3, p1-p0, nocc[i], nao), dtype=numpy.complex128)
158
+ bufRe = numpy.empty((3, p1-p0, nocc[i], nao), dtype=numpy.float64)
159
+ bufIm = numpy.empty((3, p1-p0, nocc[i], nao), dtype=numpy.float64)
152
160
  orbolRe = numpy.asarray(orbol[i].real, order='F')
153
161
  orbolIm = numpy.asarray(orbol[i].imag, order='F')
154
162
  fdrv(ftrans, fmmm, # lib.einsum ('pmn,ni->pim', int3c, orbol[i])
@@ -165,14 +173,18 @@ def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
165
173
  ctypes.c_int (3*(p1-p0)), ctypes.c_int (nao),
166
174
  (ctypes.c_int*4)(0, nocc[i], 0, nao),
167
175
  null, ctypes.c_int(0))
168
- buf = bufRe + 1.0j * bufIm
176
+ buf.real, buf.imag = bufRe, bufIm
169
177
  for j in range (nset): # lib.einsum ('pim,mj->pij', buf, orbor[j])
170
178
  int3c_ij = lib.dot (buf.reshape (-1, nao), orbor[j])
171
179
  int3c_ij = int3c_ij.reshape (3, p1-p0, nocc[i], nocc[j])
172
180
  rhok_oo_ij = rhok_oo[(i*nset)+j][p0:p1]
173
181
  vkaux[i,j,:,p0:p1] += lib.einsum('xpij,pij->xp', int3c_ij,
174
182
  rhok_oo_ij)
183
+ int3c = None
175
184
  t2 = logger.timer_debug1 (mf_grad, "df grad vk aux (P'|mn) eval", *t2)
185
+ orbol = orbor = None
186
+ buf = bufRe = bufIm = orbolRe = orbolIm = None
187
+ dm_tril = None
176
188
  int3c = tmp = None
177
189
  t1 = logger.timer_debug1 (mf_grad, "df grad vj and vk aux (P'|mn) eval", *t1)
178
190
 
@@ -182,7 +194,9 @@ def get_jk(mf_grad, mol=None, dm=None, hermi=0, with_j=True, with_k=True,
182
194
  for i, j in product (range (nset), repeat=2):
183
195
  k = (i*nset) + j
184
196
  l = (j*nset) + i
185
- tmp = lib.einsum('pij,qji->pq', rhok_oo[k], rhok_oo[l])
197
+ tmp = numpy.zeros((naux,naux), dtype=numpy.complex128)
198
+ for p0, p1 in lib.prange(0, nao, blksize):
199
+ tmp += numpy.tensordot(rhok_oo[k][:,p0:p1,:], rhok_oo[l][:,:,p0:p1], axes=([1,2], [2,1]))
186
200
  vkaux[i,j] -= lib.einsum('xpq,pq->xp', int2c_e1, tmp)
187
201
  t1 = logger.timer_debug1 (mf_grad, "df grad vj and vk aux (P'|Q) eval", *t1)
188
202
 
@@ -229,7 +243,7 @@ def get_j(mf_grad, mol=None, dm=None, hermi=0):
229
243
 
230
244
  aux_loc = auxmol.ao_loc
231
245
  max_memory = mf_grad.max_memory - lib.current_memory()[0]
232
- blksize = int(min(max(max_memory * .5e6/8 / (nao**2*3), 20), naux, 240))
246
+ blksize = int(min(max(max_memory * .5e6/8 / (nao**2*3), 20), naux, 80)) # 240 -> 80 for handling complex128
233
247
  ao_ranges = df_rhf_grad.balance_partition(aux_loc, blksize)
234
248
 
235
249
  # (ij|P), (nao, nao, naux)
@@ -292,7 +306,7 @@ def _cho_solve_rhojk (mf_grad, mol, auxmol, orbol, orbor,
292
306
  f_rhok = lib.H5TmpFile()
293
307
  t1 = (logger.process_clock (), logger.perf_counter ())
294
308
  max_memory = mf_grad.max_memory - lib.current_memory()[0]
295
- blksize = max_memory * .5e6/8 / (naux*nao)
309
+ blksize = max_memory * .5e6/8 / (naux*nao) / 3 # Divided by 3 for handling complex128 safely (complex + buffer)
296
310
  mol_ao_ranges = df_rhf_grad.balance_partition(ao_loc, blksize)
297
311
  nsteps = len(mol_ao_ranges)
298
312
  t2 = t1
@@ -0,0 +1,88 @@
1
+ import numpy
2
+ from pyscf.dft import gen_grid
3
+ from pyscf.dft import radi
4
+ from pyscf.lib import logger
5
+ from fcdft.gto.mole import split_mol
6
+ import ipdb
7
+
8
+ # Grid for equilibrium DFT object.
9
+
10
+ def get_partition(mol, atom_slice, *args, **kwargs):
11
+ mol1, mol2 = split_mol(mol, atom_slice)
12
+ coords1, weights1 = gen_grid.get_partition(mol1, *args, **kwargs)
13
+ coords2, weights2 = gen_grid.get_partition(mol2, *args, **kwargs)
14
+ coords_all = [coords1, coords2]
15
+ weights_all = [weights1, weights2]
16
+ return coords_all, weights_all
17
+
18
+ class Grids(gen_grid.Grids):
19
+ _keys = {'atom_slice'}
20
+
21
+ def __init__(self, mol, atom_slice):
22
+ gen_grid.Grids.__init__(self, mol)
23
+ self.atom_slice = atom_slice
24
+
25
+ def build(self, mol=None, with_non0tab=False, sort_grids=True, **kwargs):
26
+ if mol is None: mol = self.mol
27
+ if self.verbose >= logger.WARN:
28
+ self.check_sanity()
29
+ atom_grids_tab = self.gen_atomic_grids(
30
+ mol, self.atom_grid, self.radi_method, self.level, self.prune, **kwargs)
31
+ self.coords, self.weights = self.get_partition(
32
+ mol, self.atom_slice, atom_grids_tab, self.radii_adjust, self.atomic_radii, self.becke_scheme)
33
+ mol1, mol2 = split_mol(mol, self.atom_slice)
34
+ mol = [mol1, mol2]
35
+ atm_idx1 = numpy.empty(self.coords[0].shape[0], dtype=numpy.int32)
36
+ atm_idx2 = numpy.empty(self.coords[1].shape[0], dtype=numpy.int32)
37
+ atm_idx = [atm_idx1, atm_idx2]
38
+ quad_weights1 = numpy.empty(self.coords[0].shape[0])
39
+ quad_weights2 = numpy.empty(self.coords[1].shape[0])
40
+ quadrature_weights = [quad_weights1, quad_weights2]
41
+ for i in range(2):
42
+ p0 = p1 = 0
43
+ for ia in range(mol[i].natm):
44
+ r, vol = atom_grids_tab[mol[i].atom_symbol(ia)]
45
+ p0, p1 = p1, p1 + vol.size
46
+ atm_idx[i][p0:p1] = ia
47
+ quadrature_weights[i][p0:p1] = vol
48
+ self.atm_idx = atm_idx
49
+ self.quadrature_weights = quadrature_weights
50
+ if sort_grids:
51
+ for i in range(2):
52
+ idx = gen_grid.arg_group_grids(mol[i], self.coords[i])
53
+ self.coords[i] = self.coords[i][idx]
54
+ self.weights[i] = self.weights[i][idx]
55
+ self.atm_idx[i] = self.atm_idx[i][idx]
56
+ self.quadrature_weights[i] = self.quadrature_weights[i][idx]
57
+ # ??
58
+ if self.alignment > 1:
59
+ padding = gen_grid._padding_size(self.size, self.alignment)
60
+ logger.debug(self, 'Padding %d grids', padding)
61
+ if padding > 0:
62
+ self.coords = numpy.vstack(
63
+ [self.coords, numpy.repeat([[1e-4]*3], padding, axis=0)])
64
+ self.weights = numpy.hstack([self.weights, numpy.zeros(padding)])
65
+ self.atm_idx = numpy.hstack([self.atm_idx, numpy.full(padding, -1, dtype=numpy.int32)])
66
+ self.quadrature_weights = numpy.hstack([self.quadrature_weights, numpy.zeros(padding)])
67
+ if with_non0tab:
68
+ non0tab = []
69
+ for i in range(2):
70
+ non0tab.append(self.make_mask(mol[i], self.coords[i]))
71
+ self.non0tab = non0tab
72
+ self.screen_index = self.non0tab
73
+ else:
74
+ self.screen_index = self.non0tab = None
75
+ logger.info(self, 'tot grids = %d', len(self.weights[0]) + len(self.weights[1]))
76
+ return self
77
+
78
+ def kernel(self, **kwargs):
79
+ self.dump_flags()
80
+ return self.build(**kwargs)
81
+
82
+ def get_partition(self, mol, atom_slice, atom_grids_tab=None,
83
+ radii_adjust=None, atomic_radii=radi.BRAGG_RADII,
84
+ becke_scheme=gen_grid.original_becke, concat=True):
85
+ if atom_grids_tab is None:
86
+ atom_grids_tab = self.gen_atomic_grids(mol)
87
+ return get_partition(mol, atom_slice, atom_grids_tab, radii_adjust, atomic_radii,
88
+ becke_scheme, concat=concat)
@@ -42,10 +42,10 @@ def grad_elec(mf_grad, mo_energy=None, mo_coeff=None, mo_occ=None, atmlst=None):
42
42
  for k, ia in enumerate(atmlst):
43
43
  p0, p1 = aoslices [ia,2:]
44
44
  h1ao = hcore_deriv(ia)
45
- de[k] += numpy.einsum('xij,ij->x', h1ao, dm0)
45
+ de[k] += numpy.tensordot(h1ao, dm0, axes=([1,2], [0,1]))
46
46
  # nabla was applied on bra in vhf, *2 for the contributions of nabla|ket>
47
- de[k] += numpy.einsum('xij,ij->x', vhf[:,p0:p1], dm0[p0:p1]) * 2
48
- de[k] -= numpy.einsum('xij,ij->x', s1[:,p0:p1], dme0[p0:p1]) * 2
47
+ de[k] += numpy.tensordot(vhf[:,p0:p1], dm0[p0:p1], axes=([1,2], [0,1])) * 2
48
+ de[k] -= numpy.tensordot(s1[:,p0:p1], dme0[p0:p1], axes=([1,2], [0,1])) * 2
49
49
 
50
50
  de[k] += mf_grad.extra_force(ia, locals())
51
51
 
@@ -0,0 +1,110 @@
1
+ from pyscf.gto.mole import Mole
2
+ from pyscf.lib import logger
3
+
4
+ # def split_env(mol, atm, bas, env, atom_id):
5
+ # symbols = [mol.atom_symbol(i) for i in range(mol.natm)]
6
+ # sym1 = symbols[:atom_id]
7
+ # from pyscf.gto.mole import make_bas_env
8
+ # len_env = 0
9
+ # for symb, basis_add in mol._basis.items():
10
+ # if symb in sym1:
11
+ # _, env0 = make_bas_env(basis_add, 0, 0)
12
+ # len_env += len(env0)
13
+
14
+ # env1, env2 = [numpy.zeros(PTR_ENV_START)], [numpy.zeros(PTR_ENV_START)]
15
+ # env1.append(env[PTR_ENV_START:PTR_ENV_START+4*atom_id])
16
+ # env2.append(env[PTR_ENV_START+4*atom_id:PTR_ENV_START+4*len(atm)])
17
+ # env1, env2 = env[:len_env], env[len_env:]
18
+ # idx = numpy.where(bas[:,0] == atom_id)[0][0]
19
+ # bas1, bas2 = bas[:idx].copy(), bas[idx:].copy()
20
+ # off = len(env1)
21
+ # natm_off = atom_id
22
+ # atm1, atm2 = atm[:atom_id].copy(), atm[atom_id:].copy()
23
+ # atm2[:,PTR_COORD] -= off
24
+ # atm2[:,PTR_ZETA ] -= off
25
+ # bas2[:,ATOM_OF ] -= natm_off
26
+ # bas2[:,PTR_EXP ] -= off
27
+ # bas2[:,PTR_COEFF] -= off
28
+ # return atm1, bas1, env1, atm2, bas2, env2
29
+
30
+ def conc_mol(mol1, mol2):
31
+ from pyscf.gto import mole
32
+ mol = mole.conc_mol(mol1, mol2)
33
+ if mol1.basis == mol2.basis:
34
+ mol.basis = mol1.basis
35
+ return mol
36
+
37
+ def split_mol(mol, atom_id):
38
+ '''Split the molecule into two Mole objects.
39
+ Reverse of conc_mol in pyscf.gto.mole
40
+ '''
41
+ if not mol._built:
42
+ logger.warn(mol, 'Warning: object %s not initialized. Initializing %s',
43
+ mol, mol)
44
+ mol.build()
45
+
46
+ # TODO: mol.stdout for logger
47
+ mol1, mol2 = Mole(), Mole()
48
+ mol1.basis = mol2.basis = mol.basis
49
+ mol1.verbose = mol2.verbose = mol.verbose
50
+ mol1.stdout = mol2.stdout = mol.stdout
51
+ mol1.output = mol2.output = mol.output
52
+ mol1.max_memory = mol2.max_memory = mol.max_memory
53
+ mol1.spin = mol2.spin = 0
54
+ mol1.symmetry = mol2.symmetry = False
55
+ mol1.symmetry_subgroup = mol2.symmetry_subgroup = None
56
+ mol1.cart = mol2.cart = mol.cart
57
+ mol1._atom = mol._atom[:atom_id]
58
+ mol2._atom = mol._atom[atom_id:]
59
+ mol1.unit = mol2.unit = 'Bohr'
60
+ mol1.build(), mol2.build()
61
+
62
+ return mol1, mol2
63
+
64
+ if __name__=='__main__':
65
+ from pyscf import gto
66
+ mol1 = gto.M(
67
+ atom='''
68
+ C -1.1367537947 0.1104289172 2.4844663896
69
+ C -1.1385831318 0.1723328088 3.8772156394
70
+ C 0.0819843127 0.0788096973 1.7730802291
71
+ H -2.0846565855 0.1966185690 4.4236084687
72
+ C 0.0806058727 0.2041086872 4.5921211233
73
+ C 1.2993389981 0.1104289172 2.4844663896
74
+ H 2.2526138470 0.0865980845 1.9483127672
75
+ C 1.2994126658 0.1723829840 3.8783367991
76
+ H 2.2453411518 0.1966879024 4.4251589385
77
+ H -2.0869454458 0.0863720324 1.9432143952
78
+ C 0.0810980584 0.2676328718 6.0213144069
79
+ N 0.0819851974 0.3199013851 7.1972568519
80
+ S 0.0000000000 0.0000000000 0.0000000000
81
+ H 1.3390319419 -0.0095801980 -0.2157234144''',
82
+ charge=0, basis='6-31g**', verbose=5)
83
+ mol2 = gto.M(
84
+ atom='''
85
+ C -0.8476079365 0.0026700202 -3.5281035617
86
+ C -2.0218283577 -0.2604683627 -2.8073958219
87
+ C 0.3353012600 0.2642432684 -2.8231212050
88
+ H -2.9520951875 -0.4549635668 -3.3338745954
89
+ H 1.2611570861 0.4600128780 -3.3568350109
90
+ C -2.0073245682 -0.2604462093 -1.4139657047
91
+ C 0.3383704802 0.2619859179 -1.4285927349
92
+ H -2.9349818456 -0.4420746761 -0.8791308006
93
+ H 1.2732326220 0.4430128273 -0.9060391242
94
+ C -0.8293545128 0.0002996322 -0.6916543989
95
+ C -0.8192397451 -0.0006201775 0.7937732451
96
+ C -1.5616839183 -0.9482725602 1.5218647171
97
+ C -0.0671411632 0.9462610490 1.5129186979
98
+ C -1.5541603792 -0.9481485004 2.9180008413
99
+ C -0.0558307025 0.9446630867 2.9090260355
100
+ C -0.8001707945 -0.0022152441 3.6187748549
101
+ H -2.1295491966 -1.7060626237 0.9896596517
102
+ H 0.4930453218 1.7050509252 0.9740007250
103
+ H -2.1296311282 -1.6947234290 3.4583587491
104
+ H 0.5267024257 1.6907508988 3.4424644381
105
+ H -0.7929373074 -0.0027907562 4.7049223527
106
+ S -0.9353266992 -0.0162143726 -5.3112847893
107
+ H 0.3533301599 0.3018611373 -5.5386460312''',
108
+ charge=0, basis='6-31g**', verbose=5)
109
+ mol = gto.conc_mol(mol1, mol2)
110
+ _mol1, _mol2 = split_mol(mol, 14)
@@ -102,6 +102,7 @@ endif()
102
102
  #add_subdirectory(vhf)
103
103
  add_subdirectory(dft)
104
104
  add_subdirectory(pbe)
105
+ add_subdirectory(df)
105
106
  #configure_file(
106
107
  # "${PYSCF_LIB_PATH}/config.h.in"
107
108
  # "${PYSCF_LIB_PATH}/config.h")
@@ -0,0 +1,8 @@
1
+ add_library(df SHARED nr_contract_k.c)
2
+
3
+ find_package(LAPACK REQUIRED)
4
+
5
+ set_target_properties(df PROPERTIES
6
+ LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR})
7
+
8
+ target_link_libraries(df ${OPENMP_C_PROPERTIES} ${LAPACK_LIBRARIES})
@@ -0,0 +1,13 @@
1
+ #include <stdlib.h>
2
+ #include <stdio.h>
3
+ #include <stdint.h>
4
+ #include <omp.h>
5
+ #include "cblas.h"
6
+
7
+ void nr_mapdm1(double *buf, double *eri, double *dms, int nao, int naux) {
8
+ // vk shape: (nao, nao), (155,155)
9
+ // eri shape: (naux, nao, nao) (240,155,155)
10
+ // dms shape: (nao, nao) (155,155)
11
+ // buf shape: (naux, nao, nao) (240,155,155)
12
+ cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, naux*nao, nao, nao, 1.0, eri, nao, dms, nao, 0.0, buf, nao);
13
+ }
@@ -4,6 +4,8 @@
4
4
  #include <omp.h>
5
5
  #include <stdio.h>
6
6
 
7
+ double const TWO_PI = 2.0 * M_PI;
8
+
7
9
  void roots_legendre(int n, double *abscissas, double *weights){
8
10
  double z, z1, pp, p1, p2, p3;
9
11
  int m = (n + 1) / 2;
@@ -34,26 +36,64 @@ void roots_legendre(int n, double *abscissas, double *weights){
34
36
 
35
37
  double occ_drv(double sampling, double moe_energy, double fermi, double broad, double smear) {
36
38
  double dist = 1 / (exp((sampling - fermi)/smear) + 1);
37
- return dist * broad / (pow(sampling - moe_energy, 2) + pow(broad / 2, 2)) / 2.0 / M_PI;
39
+ double a = sampling - moe_energy;
40
+ double b = broad / 2.0;
41
+ return dist * broad / (a*a + b*b) / TWO_PI;
38
42
  }
39
43
 
40
44
  double occ_grad_drv(double sampling, double moe_energy, double fermi, double broad, double smear) {
41
45
  double dist = 1 / (exp((sampling - fermi)/smear) + 1);
42
- return dist * (1 - dist) * broad / (pow(sampling - moe_energy, 2) + pow(broad / 2, 2)) / 2.0 / M_PI / smear;
46
+ double a = sampling - moe_energy;
47
+ double b = broad / 2.0;
48
+ return dist * (1 - dist) * broad / (a*a + b*b) / TWO_PI / smear;
43
49
  }
44
50
 
45
51
  void fermi_level_drv(double *moe_energy, double *abscissas, double *weights, double fermi, double broad, double smear, double window, int pts, int nbas, double *mo_occ, double *mo_grad) {
46
52
  int i, n;
47
53
  double sampling;
48
54
  double _mo_grad = 0.0;
55
+ double *window_weights = (double *)malloc(sizeof(double) * pts);
56
+
57
+ #pragma omp parallel for private(n)
58
+ for (n = 0; n < pts; n++) {
59
+ window_weights[n] = window * weights[n];
60
+ }
61
+
49
62
  #pragma omp parallel for private(n, sampling) reduction(+:_mo_grad)
50
63
  for (i = 0; i < nbas; i++) {
51
64
  mo_occ[i] = 0;
52
65
  for (n = 0; n < pts; n++) {
53
66
  sampling = abscissas[n] * window + moe_energy[i];
54
- mo_occ[i] += window * weights[n] * occ_drv(sampling, moe_energy[i], fermi, broad, smear);
55
- _mo_grad += window * weights[n] * occ_grad_drv(sampling, moe_energy[i], fermi, broad, smear);
67
+ mo_occ[i] += window_weights[n] * occ_drv(sampling, moe_energy[i], fermi, broad, smear);
68
+ _mo_grad += window_weights[n] * occ_grad_drv(sampling, moe_energy[i], fermi, broad, smear);
56
69
  }
57
70
  }
58
71
  *mo_grad = _mo_grad;
72
+ free(window_weights);
59
73
  }
74
+
75
+ void occupation_drv(double *moe_energy, double *abscissas, double *weights, double fermi, double broad, double smear, double window, int pts, int nbas, double *mo_occ) {
76
+ int i, n;
77
+ double sampling;
78
+ #pragma omp parallel for private(n, sampling)
79
+ for (i = 0; i < nbas; i++) {
80
+ mo_occ[i] = 0;
81
+ for (n = 0; n < pts; n++) {
82
+ sampling = abscissas[n] * window + moe_energy[i];
83
+ mo_occ[i] += window * weights[n] * occ_drv(sampling, moe_energy[i], fermi, broad, smear);
84
+ }
85
+ }
86
+ }
87
+
88
+ void occupation_grad_drv(double *moe_energy, double *abscissas, double *weights, double fermi, double broad, double smear, double window, int pts, int nbas, double *occ_grad) {
89
+ int i, n;
90
+ double sampling;
91
+ #pragma omp parallel for private(n, sampling)
92
+ for (i = 0; i < nbas; i++) {
93
+ occ_grad[i] = 0;
94
+ for (n = 0; n < pts; n++) {
95
+ sampling = abscissas[n] * window + moe_energy[i];
96
+ occ_grad[i] += window * weights[n] * occ_grad_drv(sampling, moe_energy[i], fermi, broad, smear);
97
+ }
98
+ }
99
+ }