pyscf 2.6.2__py3-none-macosx_11_0_arm64.whl → 2.7.0__py3-none-macosx_11_0_arm64.whl

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 (244) hide show
  1. pyscf/__init__.py +2 -2
  2. pyscf/adc/__init__.py +3 -8
  3. pyscf/adc/dfadc.py +22 -6
  4. pyscf/adc/radc.py +106 -15
  5. pyscf/adc/radc_amplitudes.py +7 -1
  6. pyscf/adc/radc_ao2mo.py +4 -2
  7. pyscf/adc/radc_ea.py +524 -8
  8. pyscf/adc/radc_ip.py +492 -60
  9. pyscf/adc/radc_ip_cvs.py +4 -2
  10. pyscf/adc/uadc.py +116 -27
  11. pyscf/adc/uadc_amplitudes.py +215 -20
  12. pyscf/adc/uadc_ao2mo.py +30 -9
  13. pyscf/adc/uadc_ea.py +34 -44
  14. pyscf/adc/uadc_ip.py +9 -4
  15. pyscf/adc/uadc_ip_cvs.py +4 -1
  16. pyscf/agf2/__init__.py +2 -2
  17. pyscf/agf2/aux_space.py +1 -1
  18. pyscf/agf2/chkfile.py +1 -1
  19. pyscf/ao2mo/outcore.py +6 -4
  20. pyscf/cc/__init__.py +21 -3
  21. pyscf/cc/bccd.py +0 -46
  22. pyscf/cc/ccsd.py +16 -8
  23. pyscf/cc/uccsd.py +1 -1
  24. pyscf/data/elements.py +1 -1
  25. pyscf/df/__init__.py +2 -1
  26. pyscf/df/addons.py +79 -51
  27. pyscf/df/autoaux.py +191 -0
  28. pyscf/df/df.py +5 -1
  29. pyscf/df/grad/casscf.py +0 -41
  30. pyscf/df/hessian/rhf.py +2 -10
  31. pyscf/df/hessian/rks.py +1 -7
  32. pyscf/df/hessian/uhf.py +3 -13
  33. pyscf/df/hessian/uks.py +1 -8
  34. pyscf/df/incore.py +17 -5
  35. pyscf/dft/dks.py +1 -1
  36. pyscf/dft/libxc.py +65 -639
  37. pyscf/dft/numint.py +7 -3
  38. pyscf/dft/radi.py +39 -5
  39. pyscf/dft/rks.py +1 -1
  40. pyscf/dft/xc_deriv.py +1 -1
  41. pyscf/dft/xcfun.py +53 -2
  42. pyscf/eph/eph_fd.py +1 -1
  43. pyscf/eph/rhf.py +6 -36
  44. pyscf/eph/rks.py +0 -4
  45. pyscf/eph/uhf.py +1 -7
  46. pyscf/eph/uks.py +1 -7
  47. pyscf/fci/addons.py +117 -2
  48. pyscf/fci/cistring.py +1 -1
  49. pyscf/fci/direct_nosym.py +3 -3
  50. pyscf/fci/direct_spin0_symm.py +22 -43
  51. pyscf/fci/direct_spin1.py +65 -9
  52. pyscf/fci/direct_spin1_symm.py +49 -14
  53. pyscf/fci/direct_uhf.py +4 -4
  54. pyscf/fci/selected_ci_symm.py +1 -1
  55. pyscf/grad/lagrange.py +11 -3
  56. pyscf/grad/mp2.py +1 -1
  57. pyscf/grad/sacasscf.py +1 -1
  58. pyscf/grad/tdrks.py +1 -1
  59. pyscf/gto/basis/__init__.py +7 -0
  60. pyscf/gto/basis/bse.py +68 -15
  61. pyscf/gto/basis/parse_cp2k_pp.py +1 -1
  62. pyscf/gto/basis/parse_nwchem.py +1 -1
  63. pyscf/gto/basis/parse_nwchem_ecp.py +2 -1
  64. pyscf/gto/basis/sap_grasp_large.dat +2438 -0
  65. pyscf/gto/basis/sap_grasp_small.dat +1434 -0
  66. pyscf/gto/mole.py +99 -44
  67. pyscf/gw/gw_ac.py +2 -2
  68. pyscf/gw/gw_cd.py +2 -2
  69. pyscf/gw/rpa.py +2 -2
  70. pyscf/gw/ugw_ac.py +2 -2
  71. pyscf/gw/urpa.py +1 -1
  72. pyscf/hessian/rhf.py +30 -128
  73. pyscf/hessian/rks.py +1 -6
  74. pyscf/hessian/uhf.py +28 -138
  75. pyscf/hessian/uks.py +1 -8
  76. pyscf/lib/ao2mo/nr_ao2mo.c +1 -1
  77. pyscf/lib/ao2mo/nrr_ao2mo.c +1 -1
  78. pyscf/lib/ao2mo/r_ao2mo.c +1 -1
  79. pyscf/lib/cc/ccsd_pack.c +1 -1
  80. pyscf/lib/cc/ccsd_t.c +6 -6
  81. pyscf/lib/cc/uccsd_t.c +4 -4
  82. pyscf/lib/deps/include/XCFun/XCFunExport.h +1 -0
  83. pyscf/lib/dft/grid_common.c +1 -1
  84. pyscf/lib/dft/libxc_itrf.c +4 -1
  85. pyscf/lib/dft/xcfun_itrf.c +1 -1
  86. pyscf/lib/diis.py +1 -1
  87. pyscf/lib/exceptions.py +3 -0
  88. pyscf/lib/gto/fill_grids_int2c.c +11 -9
  89. pyscf/lib/gto/fill_int2e.c +7 -5
  90. pyscf/lib/gto/fill_r_4c.c +1 -1
  91. pyscf/lib/gto/ft_ao.c +1 -1
  92. pyscf/lib/gto/ft_ao.h +1 -1
  93. pyscf/lib/gto/gto.h +2 -2
  94. pyscf/lib/gto/nr_ecp.c +3 -2
  95. pyscf/lib/libagf2.dylib +0 -0
  96. pyscf/lib/libao2mo.dylib +0 -0
  97. pyscf/lib/libcc.dylib +0 -0
  98. pyscf/lib/libcgto.dylib +0 -0
  99. pyscf/lib/libcvhf.dylib +0 -0
  100. pyscf/lib/libdft.dylib +0 -0
  101. pyscf/lib/libfci.dylib +0 -0
  102. pyscf/lib/libmcscf.dylib +0 -0
  103. pyscf/lib/libnp_helper.dylib +0 -0
  104. pyscf/lib/libpbc.dylib +0 -0
  105. pyscf/lib/libri.dylib +0 -0
  106. pyscf/lib/libxc_itrf.dylib +0 -0
  107. pyscf/lib/libxcfun_itrf.dylib +0 -0
  108. pyscf/lib/linalg_helper.py +112 -192
  109. pyscf/lib/mcscf/fci_contract.c +2 -2
  110. pyscf/lib/misc.py +47 -14
  111. pyscf/lib/numpy_helper.py +1 -1
  112. pyscf/lib/pbc/nr_ecp.c +10 -3
  113. pyscf/lib/pbc/pbc.h +1 -1
  114. pyscf/lib/vhf/nr_sgx_direct.c +8 -6
  115. pyscf/lib/vhf/optimizer.c +2 -2
  116. pyscf/lo/iao.py +1 -1
  117. pyscf/lo/ibo.py +3 -3
  118. pyscf/lo/pipek_jacobi.py +1 -1
  119. pyscf/mcscf/__init__.py +2 -2
  120. pyscf/mcscf/addons.py +3 -3
  121. pyscf/mcscf/apc.py +2 -2
  122. pyscf/mcscf/casci.py +8 -6
  123. pyscf/mcscf/chkfile.py +70 -41
  124. pyscf/mcscf/dmet_cas.py +2 -2
  125. pyscf/mcscf/mc1step.py +62 -38
  126. pyscf/mcscf/newton_casscf.py +5 -5
  127. pyscf/mcscf/ucasci.py +1 -1
  128. pyscf/mcscf/umc1step.py +44 -25
  129. pyscf/md/integrators.py +3 -3
  130. pyscf/mp/mp2.py +6 -5
  131. pyscf/mp/ump2.py +7 -6
  132. pyscf/pbc/adc/kadc_rhf.py +1 -1
  133. pyscf/pbc/adc/kadc_rhf_amplitudes.py +2 -2
  134. pyscf/pbc/ao2mo/eris.py +1 -1
  135. pyscf/pbc/cc/kccsd_rhf.py +3 -3
  136. pyscf/pbc/cc/kccsd_t_rhf.py +2 -2
  137. pyscf/pbc/ci/kcis_rhf.py +2 -2
  138. pyscf/pbc/df/aft.py +2 -2
  139. pyscf/pbc/df/aft_ao2mo.py +1 -1
  140. pyscf/pbc/df/df.py +84 -11
  141. pyscf/pbc/df/df_jk.py +2 -1
  142. pyscf/pbc/df/fft.py +6 -2
  143. pyscf/pbc/df/fft_ao2mo.py +4 -0
  144. pyscf/pbc/df/fft_jk.py +11 -3
  145. pyscf/pbc/df/ft_ao.py +4 -3
  146. pyscf/pbc/df/gdf_builder.py +5 -4
  147. pyscf/pbc/df/incore.py +1 -1
  148. pyscf/pbc/df/mdf.py +6 -3
  149. pyscf/pbc/df/rsdf.py +2 -2
  150. pyscf/pbc/df/rsdf_builder.py +11 -6
  151. pyscf/pbc/df/rsdf_helper.py +1 -1
  152. pyscf/pbc/dft/cdft.py +5 -5
  153. pyscf/pbc/dft/multigrid/multigrid.py +19 -26
  154. pyscf/pbc/dft/multigrid/multigrid_pair.py +1 -1
  155. pyscf/pbc/dft/multigrid/pp.py +1 -1
  156. pyscf/pbc/dft/numint.py +30 -21
  157. pyscf/pbc/eph/eph_fd.py +1 -1
  158. pyscf/pbc/geomopt/geometric_solver.py +1 -1
  159. pyscf/pbc/gto/cell.py +37 -19
  160. pyscf/pbc/gto/ecp.py +12 -12
  161. pyscf/pbc/gto/eval_gto.py +2 -2
  162. pyscf/pbc/gto/pseudo/pp.py +1 -1
  163. pyscf/pbc/gw/krgw_ac.py +4 -4
  164. pyscf/pbc/gw/krgw_cd.py +4 -4
  165. pyscf/pbc/gw/kugw_ac.py +3 -3
  166. pyscf/pbc/lib/kpts_helper.py +4 -3
  167. pyscf/pbc/lib/linalg_helper.py +1 -1
  168. pyscf/pbc/mp/kmp2.py +1 -1
  169. pyscf/pbc/mpitools/mpi.py +1 -1
  170. pyscf/pbc/scf/addons.py +15 -11
  171. pyscf/pbc/scf/cphf.py +1 -1
  172. pyscf/pbc/scf/ghf.py +1 -1
  173. pyscf/pbc/scf/hf.py +21 -24
  174. pyscf/pbc/scf/kghf.py +33 -29
  175. pyscf/pbc/scf/khf.py +71 -26
  176. pyscf/pbc/scf/krohf.py +5 -7
  177. pyscf/pbc/scf/kuhf.py +53 -22
  178. pyscf/pbc/scf/rsjk.py +13 -9
  179. pyscf/pbc/scf/scfint.py +1 -1
  180. pyscf/pbc/scf/stability.py +1 -1
  181. pyscf/pbc/scf/uhf.py +3 -1
  182. pyscf/pbc/symm/symmetry.py +2 -2
  183. pyscf/pbc/tdscf/kproxy.py +1 -1
  184. pyscf/pbc/tdscf/kproxy_supercell.py +2 -2
  185. pyscf/pbc/tdscf/krhf.py +215 -133
  186. pyscf/pbc/tdscf/krhf_slow_supercell.py +1 -1
  187. pyscf/pbc/tdscf/krks.py +1 -45
  188. pyscf/pbc/tdscf/kuhf.py +58 -105
  189. pyscf/pbc/tdscf/kuks.py +0 -56
  190. pyscf/pbc/tdscf/proxy.py +1 -1
  191. pyscf/pbc/tdscf/rhf.py +111 -3
  192. pyscf/pbc/tdscf/rks.py +2 -1
  193. pyscf/pbc/tdscf/uhf.py +203 -1
  194. pyscf/pbc/tdscf/uks.py +2 -1
  195. pyscf/pbc/tools/k2gamma.py +7 -4
  196. pyscf/pbc/tools/pbc.py +63 -56
  197. pyscf/pbc/tools/pyscf_ase.py +0 -1
  198. pyscf/pbc/tools/pywannier90.py +1 -1
  199. pyscf/qmmm/mm_mole.py +1 -1
  200. pyscf/scf/_response_functions.py +2 -2
  201. pyscf/scf/_vhf.py +14 -10
  202. pyscf/scf/addons.py +29 -15
  203. pyscf/scf/cphf.py +14 -52
  204. pyscf/scf/dhf.py +39 -10
  205. pyscf/scf/dispersion.py +9 -8
  206. pyscf/scf/ghf.py +25 -13
  207. pyscf/scf/ghf_symm.py +2 -2
  208. pyscf/scf/hf.py +245 -29
  209. pyscf/scf/rohf.py +37 -5
  210. pyscf/scf/stability.py +142 -112
  211. pyscf/scf/ucphf.py +21 -16
  212. pyscf/scf/uhf.py +95 -58
  213. pyscf/sgx/sgx.py +1 -1
  214. pyscf/sgx/sgx_jk.py +4 -4
  215. pyscf/solvent/_ddcosmo_tdscf_grad.py +1 -1
  216. pyscf/solvent/ddcosmo.py +1 -1
  217. pyscf/solvent/pol_embed.py +1 -1
  218. pyscf/soscf/ciah.py +1 -1
  219. pyscf/soscf/newton_ah.py +1 -1
  220. pyscf/symm/__init__.py +1 -1
  221. pyscf/symm/addons.py +5 -5
  222. pyscf/tdscf/_lr_eig.py +505 -0
  223. pyscf/tdscf/common_slow.py +1 -1
  224. pyscf/tdscf/dhf.py +41 -37
  225. pyscf/tdscf/dks.py +0 -4
  226. pyscf/tdscf/ghf.py +91 -71
  227. pyscf/tdscf/gks.py +16 -16
  228. pyscf/tdscf/proxy.py +2 -2
  229. pyscf/tdscf/rhf.py +143 -96
  230. pyscf/tdscf/rks.py +15 -14
  231. pyscf/tdscf/uhf.py +117 -70
  232. pyscf/tdscf/uks.py +17 -18
  233. pyscf/tools/fcidump.py +3 -0
  234. pyscf/x2c/sfx2c1e.py +1 -1
  235. pyscf/x2c/tdscf.py +4 -4
  236. pyscf/x2c/x2c.py +15 -11
  237. {pyscf-2.6.2.dist-info → pyscf-2.7.0.dist-info}/METADATA +24 -24
  238. {pyscf-2.6.2.dist-info → pyscf-2.7.0.dist-info}/NOTICE +3 -1
  239. {pyscf-2.6.2.dist-info → pyscf-2.7.0.dist-info}/RECORD +242 -240
  240. {pyscf-2.6.2.dist-info → pyscf-2.7.0.dist-info}/WHEEL +1 -1
  241. pyscf/dft/gen_libxc_param.py +0 -35
  242. pyscf/dft/gen_xcfun_param.py +0 -209
  243. {pyscf-2.6.2.dist-info → pyscf-2.7.0.dist-info}/LICENSE +0 -0
  244. {pyscf-2.6.2.dist-info → pyscf-2.7.0.dist-info}/top_level.txt +0 -0
pyscf/tdscf/rhf.py CHANGED
@@ -32,8 +32,9 @@ from pyscf import ao2mo
32
32
  from pyscf import symm
33
33
  from pyscf.lib import logger
34
34
  from pyscf.scf import hf_symm
35
- from pyscf.scf import _response_functions
35
+ from pyscf.scf import _response_functions # noqa
36
36
  from pyscf.data import nist
37
+ from pyscf.tdscf._lr_eig import eigh as lr_eigh, eig as lr_eig
37
38
  from pyscf import __config__
38
39
 
39
40
  OUTPUT_THRESHOLD = getattr(__config__, 'tdscf_rhf_get_nto_threshold', 0.3)
@@ -65,21 +66,17 @@ def gen_tda_operation(mf, fock_ao=None, singlet=True, wfnsym=None):
65
66
  if isinstance(wfnsym, str):
66
67
  wfnsym = symm.irrep_name2id(mol.groupname, wfnsym)
67
68
  wfnsym = wfnsym % 10 # convert to D2h subgroup
68
- orbsym = hf_symm.get_orbsym(mol, mo_coeff)
69
- orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps
70
- sym_forbid = (orbsym_in_d2h[occidx,None] ^ orbsym_in_d2h[viridx]) != wfnsym
69
+ x_sym = _get_x_sym_table(mf)
70
+ sym_forbid = x_sym != wfnsym
71
71
 
72
72
  if fock_ao is None:
73
- #dm0 = mf.make_rdm1(mo_coeff, mo_occ)
74
- #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0)
75
- foo = numpy.diag(mo_energy[occidx])
76
- fvv = numpy.diag(mo_energy[viridx])
73
+ e_ia = hdiag = mo_energy[viridx] - mo_energy[occidx,None]
77
74
  else:
78
75
  fock = reduce(numpy.dot, (mo_coeff.conj().T, fock_ao, mo_coeff))
79
76
  foo = fock[occidx[:,None],occidx]
80
77
  fvv = fock[viridx[:,None],viridx]
78
+ hdiag = fvv.diagonal() - foo.diagonal()[:,None]
81
79
 
82
- hdiag = fvv.diagonal() - foo.diagonal()[:,None]
83
80
  if wfnsym is not None and mol.symmetry:
84
81
  hdiag[sym_forbid] = 0
85
82
  hdiag = hdiag.ravel()
@@ -97,8 +94,11 @@ def gen_tda_operation(mf, fock_ao=None, singlet=True, wfnsym=None):
97
94
  dmov = lib.einsum('xov,qv,po->xpq', zs*2, orbv.conj(), orbo)
98
95
  v1ao = vresp(dmov)
99
96
  v1ov = lib.einsum('xpq,po,qv->xov', v1ao, orbo.conj(), orbv)
100
- v1ov += lib.einsum('xqs,sp->xqp', zs, fvv)
101
- v1ov -= lib.einsum('xpr,sp->xsr', zs, foo)
97
+ if fock_ao is None:
98
+ v1ov += numpy.einsum('xia,ia->xia', zs, e_ia)
99
+ else:
100
+ v1ov += lib.einsum('xqs,sp->xqp', zs, fvv)
101
+ v1ov -= lib.einsum('xpr,sp->xsr', zs, foo)
102
102
  if wfnsym is not None and mol.symmetry:
103
103
  v1ov[:,sym_forbid] = 0
104
104
  return v1ov.reshape(v1ov.shape[0],-1)
@@ -106,11 +106,21 @@ def gen_tda_operation(mf, fock_ao=None, singlet=True, wfnsym=None):
106
106
  return vind, hdiag
107
107
  gen_tda_hop = gen_tda_operation
108
108
 
109
+ def _get_x_sym_table(mf):
110
+ '''Irrep (up to D2h symmetry) of each coefficient in X[nocc,nvir]'''
111
+ mol = mf.mol
112
+ mo_occ = mf.mo_occ
113
+ orbsym = hf_symm.get_orbsym(mol, mf.mo_coeff)
114
+ orbsym = orbsym % 10 # convert to D2h irreps
115
+ return orbsym[mo_occ==2,None] ^ orbsym[mo_occ==0]
116
+
109
117
  def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None):
110
118
  r'''A and B matrices for TDDFT response function.
111
119
 
112
120
  A[i,a,j,b] = \delta_{ab}\delta_{ij}(E_a - E_i) + (ia||bj)
113
121
  B[i,a,j,b] = (ia||jb)
122
+
123
+ Ref: Chem Phys Lett, 256, 454
114
124
  '''
115
125
  if mo_energy is None: mo_energy = mf.mo_energy
116
126
  if mo_coeff is None: mo_coeff = mf.mo_coeff
@@ -126,7 +136,6 @@ def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None):
126
136
  nvir = orbv.shape[1]
127
137
  nocc = orbo.shape[1]
128
138
  mo = numpy.hstack((orbo,orbv))
129
- nmo = nocc + nvir
130
139
 
131
140
  e_ia = lib.direct_sum('a-i->ia', mo_energy[viridx], mo_energy[occidx])
132
141
  a = numpy.diag(e_ia.ravel()).reshape(nocc,nvir,nocc,nvir)
@@ -142,16 +151,22 @@ def get_ab(mf, mo_energy=None, mo_coeff=None, mo_occ=None):
142
151
  b -= numpy.einsum('jaib->iajb', eri_mo[:nocc,nocc:,:nocc,nocc:]) * hyb
143
152
 
144
153
  if isinstance(mf, scf.hf.KohnShamDFT):
145
- from pyscf.dft import xc_deriv
146
154
  ni = mf._numint
147
155
  ni.libxc.test_deriv_order(mf.xc, 2, raise_error=True)
148
156
  if mf.do_nlc():
149
157
  logger.warn(mf, 'NLC functional found in DFT object. Its second '
150
- 'deriviative is not available. Its contribution is '
158
+ 'derivative is not available. Its contribution is '
151
159
  'not included in the response function.')
152
160
  omega, alpha, hyb = ni.rsh_and_hybrid_coeff(mf.xc, mol.spin)
153
161
 
154
162
  add_hf_(a, b, hyb)
163
+ if omega != 0: # For RSH
164
+ with mol.with_range_coulomb(omega):
165
+ eri_mo = ao2mo.general(mol, [orbo,mo,mo,mo], compact=False)
166
+ eri_mo = eri_mo.reshape(nocc,nmo,nmo,nmo)
167
+ k_fac = alpha - hyb
168
+ a -= numpy.einsum('ijba->iajb', eri_mo[:nocc,:nocc,nocc:,nocc:]) * k_fac
169
+ b -= numpy.einsum('jaib->iajb', eri_mo[:nocc,nocc:,:nocc,nocc:]) * k_fac
155
170
 
156
171
  xctype = ni._xc_type(mf.xc)
157
172
  dm0 = mf.make_rdm1(mo_coeff, mo_occ)
@@ -381,7 +396,7 @@ def analyze(tdobj, verbose=None):
381
396
  log.note('Excited State %3d: %12.5f eV %9.2f nm f=%.4f',
382
397
  i+1, e_ev[i], wave_length[i], f_oscillator[i])
383
398
  else:
384
- wfnsym = analyze_wfnsym(tdobj, x_sym, x)
399
+ wfnsym = _analyze_wfnsym(tdobj, x_sym, x)
385
400
  log.note('Excited State %3d: %4s %12.5f eV %9.2f nm f=%.4f',
386
401
  i+1, wfnsym, e_ev[i], wave_length[i], f_oscillator[i])
387
402
 
@@ -419,23 +434,23 @@ def analyze(tdobj, verbose=None):
419
434
  i+1, m[0], m[1], m[2])
420
435
  return tdobj
421
436
 
422
- def analyze_wfnsym(tdobj, x_sym, x):
423
- '''Guess the wfn symmetry of TDDFT X amplitude'''
424
- possible_sym = x_sym[(x > 1e-7) | (x < -1e-7)]
425
- if numpy.all(possible_sym == symm.MULTI_IRREPS):
426
- if tdobj.wfnsym is None:
427
- wfnsym = '???'
428
- else:
429
- wfnsym = tdobj.wfnsym
437
+ def _analyze_wfnsym(tdobj, x_sym, x):
438
+ '''Guess the wfn symmetry of TDDFT X amplitude. Return a label'''
439
+ wfnsym = _guess_wfnsym_id(tdobj, x_sym, x)
440
+ if wfnsym == symm.MULTI_IRREPS:
441
+ wfnsym = '???'
430
442
  else:
431
- ids = possible_sym[possible_sym != symm.MULTI_IRREPS]
432
- ids = numpy.unique(ids)
433
- if ids.size == 1:
434
- wfnsym = symm.irrep_id2name(tdobj.mol.groupname, ids[0])
435
- else:
436
- wfnsym = '???'
443
+ wfnsym = symm.irrep_id2name(tdobj.mol.groupname, wfnsym)
437
444
  return wfnsym
438
445
 
446
+ def _guess_wfnsym_id(tdobj, x_sym, x):
447
+ '''Guess the wfn symmetry of TDDFT X amplitude. Return an ID'''
448
+ possible_sym = x_sym[(x > 1e-7) | (x < -1e-7)]
449
+ wfnsym = symm.MULTI_IRREPS
450
+ ids = possible_sym[possible_sym != symm.MULTI_IRREPS]
451
+ if len(ids) > 0 and all(ids == ids[0]):
452
+ wfnsym = ids[0]
453
+ return wfnsym
439
454
 
440
455
  def transition_dipole(tdobj, xy=None):
441
456
  '''Transition dipole moments in the length gauge'''
@@ -521,16 +536,20 @@ def _charge_center(mol):
521
536
  return numpy.einsum('z,zr->r', charges, coords)/charges.sum()
522
537
 
523
538
  def _contract_multipole(tdobj, ints, hermi=True, xy=None):
539
+ '''ints is the integral tensor of a spin-independent operator'''
524
540
  if xy is None: xy = tdobj.xy
541
+ nstates = len(xy)
542
+ pol_shape = ints.shape[:-2]
543
+ nao = ints.shape[-1]
544
+
545
+ if not tdobj.singlet:
546
+ return numpy.zeros((nstates,) + pol_shape)
547
+
525
548
  mo_coeff = tdobj._scf.mo_coeff
526
549
  mo_occ = tdobj._scf.mo_occ
527
550
  orbo = mo_coeff[:,mo_occ==2]
528
551
  orbv = mo_coeff[:,mo_occ==0]
529
552
 
530
- nstates = len(xy)
531
- pol_shape = ints.shape[:-2]
532
- nao = ints.shape[-1]
533
-
534
553
  #Incompatible to old numpy version
535
554
  #ints = numpy.einsum('...pq,pi,qj->...ij', ints, orbo.conj(), orbv)
536
555
  ints = lib.einsum('xpq,pi,qj->xij', ints.reshape(-1,nao,nao), orbo.conj(), orbv)
@@ -640,12 +659,11 @@ class TD_Scanner(lib.SinglePointScanner):
640
659
 
641
660
 
642
661
  class TDBase(lib.StreamObject):
643
- conv_tol = getattr(__config__, 'tdscf_rhf_TDA_conv_tol', 1e-9)
662
+ conv_tol = getattr(__config__, 'tdscf_rhf_TDA_conv_tol', 1e-5)
644
663
  nstates = getattr(__config__, 'tdscf_rhf_TDA_nstates', 3)
645
664
  singlet = getattr(__config__, 'tdscf_rhf_TDA_singlet', True)
646
665
  lindep = getattr(__config__, 'tdscf_rhf_TDA_lindep', 1e-12)
647
666
  level_shift = getattr(__config__, 'tdscf_rhf_TDA_level_shift', 0)
648
- max_space = getattr(__config__, 'tdscf_rhf_TDA_max_space', 50)
649
667
  max_cycle = getattr(__config__, 'tdscf_rhf_TDA_max_cycle', 100)
650
668
  # Low excitation filter to avoid numerical instability
651
669
  positive_eig_threshold = getattr(__config__, 'tdscf_rhf_TDDFT_positive_eig_threshold', 1e-3)
@@ -653,7 +671,7 @@ class TDBase(lib.StreamObject):
653
671
  deg_eia_thresh = getattr(__config__, 'tdscf_rhf_TDDFT_deg_eia_thresh', 1e-3)
654
672
 
655
673
  _keys = {
656
- 'conv_tol', 'nstates', 'singlet', 'lindep', 'level_shift', 'max_space',
674
+ 'conv_tol', 'nstates', 'singlet', 'lindep', 'level_shift',
657
675
  'max_cycle', 'mol', 'chkfile', 'wfnsym', 'converged', 'e', 'xy',
658
676
  }
659
677
 
@@ -701,7 +719,6 @@ class TDBase(lib.StreamObject):
701
719
  log.info('conv_tol = %g', self.conv_tol)
702
720
  log.info('eigh lindep = %g', self.lindep)
703
721
  log.info('eigh level_shift = %g', self.level_shift)
704
- log.info('eigh max_space = %d', self.max_space)
705
722
  log.info('eigh max_cycle = %d', self.max_cycle)
706
723
  log.info('chkfile = %s', self.chkfile)
707
724
  log.info('max_memory %d MB (current use %d MB)',
@@ -730,7 +747,7 @@ class TDBase(lib.StreamObject):
730
747
  return get_ab(mf)
731
748
 
732
749
  def get_precond(self, hdiag):
733
- def precond(x, e, x0):
750
+ def precond(x, e, *args):
734
751
  diagd = hdiag - (e-self.level_shift)
735
752
  diagd[abs(diagd)<1e-8] = 1e-8
736
753
  return x/diagd
@@ -788,13 +805,25 @@ class TDA(TDBase):
788
805
  excited state. (X,Y) are normalized to 1/2 in RHF/RKS methods and
789
806
  normalized to 1 for UHF/UKS methods. In the TDA calculation, Y = 0.
790
807
  '''
808
+
791
809
  def gen_vind(self, mf=None):
792
810
  '''Generate function to compute Ax'''
793
811
  if mf is None:
794
812
  mf = self._scf
795
813
  return gen_tda_hop(mf, singlet=self.singlet, wfnsym=self.wfnsym)
796
814
 
797
- def init_guess(self, mf, nstates=None, wfnsym=None):
815
+ def init_guess(self, mf, nstates=None, wfnsym=None, return_symmetry=False):
816
+ '''
817
+ Generate initial guess for TDA
818
+
819
+ Kwargs:
820
+ nstates : int
821
+ The number of initial guess vectors.
822
+ wfnsym : int or str
823
+ The irrep label or ID of the wavefunction.
824
+ return_symmetry : bool
825
+ Whether to return symmetry labels for initial guess vectors.
826
+ '''
798
827
  if nstates is None: nstates = self.nstates
799
828
  if wfnsym is None: wfnsym = self.wfnsym
800
829
 
@@ -802,27 +831,37 @@ class TDA(TDBase):
802
831
  mo_occ = mf.mo_occ
803
832
  occidx = numpy.where(mo_occ==2)[0]
804
833
  viridx = numpy.where(mo_occ==0)[0]
805
- e_ia = mo_energy[viridx] - mo_energy[occidx,None]
806
-
807
- if wfnsym is not None and mf.mol.symmetry:
808
- if isinstance(wfnsym, str):
809
- wfnsym = symm.irrep_name2id(mf.mol.groupname, wfnsym)
810
- wfnsym = wfnsym % 10 # convert to D2h subgroup
811
- orbsym = hf_symm.get_orbsym(mf.mol, mf.mo_coeff)
812
- orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps
813
- e_ia[(orbsym_in_d2h[occidx,None] ^ orbsym_in_d2h[viridx]) != wfnsym] = 1e99
814
-
834
+ e_ia = (mo_energy[viridx] - mo_energy[occidx,None]).ravel()
815
835
  nov = e_ia.size
816
836
  nstates = min(nstates, nov)
817
- e_ia = e_ia.ravel()
818
- e_threshold = numpy.sort(e_ia)[nstates-1]
837
+
838
+ if (wfnsym is not None or return_symmetry) and mf.mol.symmetry:
839
+ x_sym = _get_x_sym_table(mf).ravel()
840
+ if wfnsym is not None:
841
+ if isinstance(wfnsym, str):
842
+ wfnsym = symm.irrep_name2id(mf.mol.groupname, wfnsym)
843
+ wfnsym = wfnsym % 10 # convert to D2h subgroup
844
+ e_ia[x_sym != wfnsym] = 1e99
845
+ nov_allowed = numpy.count_nonzero(x_sym == wfnsym)
846
+ nstates = min(nstates, nov_allowed)
847
+
848
+ # Find the nstates-th lowest energy gap
849
+ e_threshold = numpy.partition(e_ia, nstates-1)[nstates-1]
819
850
  e_threshold += self.deg_eia_thresh
820
851
 
821
852
  idx = numpy.where(e_ia <= e_threshold)[0]
822
853
  x0 = numpy.zeros((idx.size, nov))
823
854
  for i, j in enumerate(idx):
824
855
  x0[i, j] = 1 # Koopmans' excitations
825
- return x0
856
+
857
+ if return_symmetry:
858
+ if mf.mol.symmetry:
859
+ x0sym = x_sym[idx]
860
+ else:
861
+ x0sym = None
862
+ return x0, x0sym
863
+ else:
864
+ return x0
826
865
 
827
866
  def kernel(self, x0=None, nstates=None):
828
867
  '''TDA diagonalization solver
@@ -834,6 +873,7 @@ class TDA(TDBase):
834
873
  nstates = self.nstates
835
874
  else:
836
875
  self.nstates = nstates
876
+ mol = self.mol
837
877
 
838
878
  log = logger.Logger(self.stdout, self.verbose)
839
879
 
@@ -844,21 +884,23 @@ class TDA(TDBase):
844
884
  idx = numpy.where(w > self.positive_eig_threshold)[0]
845
885
  return w[idx], v[:,idx], idx
846
886
 
887
+ x0sym = None
847
888
  if x0 is None:
848
- x0 = self.init_guess(self._scf, self.nstates)
889
+ x0, x0sym = self.init_guess(
890
+ self._scf, self.nstates, return_symmetry=True)
891
+ elif mol.symmetry:
892
+ x_sym = _get_x_sym_table(self._scf).ravel()
893
+ x0sym = [_guess_wfnsym_id(self, x_sym, x) for x in x0]
849
894
 
850
- self.converged, self.e, x1 = \
851
- lib.davidson1(vind, x0, precond,
852
- tol=self.conv_tol,
853
- nroots=nstates, lindep=self.lindep,
854
- max_cycle=self.max_cycle,
855
- max_space=self.max_space, pick=pickeig,
856
- verbose=log)
895
+ self.converged, self.e, x1 = lr_eigh(
896
+ vind, x0, precond, tol_residual=self.conv_tol, lindep=self.lindep,
897
+ nroots=nstates, x0sym=x0sym, pick=pickeig, max_cycle=self.max_cycle,
898
+ max_memory=self.max_memory, verbose=log)
857
899
 
858
900
  nocc = (self._scf.mo_occ>0).sum()
859
901
  nmo = self._scf.mo_occ.size
860
902
  nvir = nmo - nocc
861
- # 1/sqrt(2) because self.x is for alpha excitation amplitude and 2(X^+*X) = 1
903
+ # 1/sqrt(2) because self.x is for alpha excitation and 2(X^+*X) = 1
862
904
  self.xy = [(xi.reshape(nocc,nvir)*numpy.sqrt(.5),0) for xi in x1]
863
905
 
864
906
  if self.chkfile:
@@ -877,8 +919,8 @@ CIS = TDA
877
919
  def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None):
878
920
  '''Generate function to compute
879
921
 
880
- [ A B][X]
881
- [-B -A][Y]
922
+ [ A B ][X]
923
+ [-B* -A*][Y]
882
924
  '''
883
925
  mol = mf.mol
884
926
  mo_coeff = mf.mo_coeff
@@ -897,19 +939,11 @@ def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None):
897
939
  if isinstance(wfnsym, str):
898
940
  wfnsym = symm.irrep_name2id(mol.groupname, wfnsym)
899
941
  wfnsym = wfnsym % 10 # convert to D2h subgroup
900
- orbsym = hf_symm.get_orbsym(mol, mo_coeff)
901
- orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps
902
- sym_forbid = (orbsym_in_d2h[occidx,None] ^ orbsym_in_d2h[viridx]) != wfnsym
942
+ sym_forbid = _get_x_sym_table(mf) != wfnsym
903
943
 
904
- #dm0 = mf.make_rdm1(mo_coeff, mo_occ)
905
- #fock_ao = mf.get_hcore() + mf.get_veff(mol, dm0)
906
- #fock = reduce(numpy.dot, (mo_coeff.T, fock_ao, mo_coeff))
907
- #foo = fock[occidx[:,None],occidx]
908
- #fvv = fock[viridx[:,None],viridx]
909
- foo = numpy.diag(mo_energy[occidx])
910
- fvv = numpy.diag(mo_energy[viridx])
944
+ assert fock_ao is None
911
945
 
912
- hdiag = fvv.diagonal() - foo.diagonal()[:,None]
946
+ e_ia = hdiag = mo_energy[viridx] - mo_energy[occidx,None]
913
947
  if wfnsym is not None and mol.symmetry:
914
948
  hdiag[sym_forbid] = 0
915
949
  hdiag = numpy.hstack((hdiag.ravel(), -hdiag.ravel()))
@@ -925,18 +959,21 @@ def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None):
925
959
  xys[:,:,sym_forbid] = 0
926
960
 
927
961
  xs, ys = xys.transpose(1,0,2,3)
928
- # dms = AX + BY
929
962
  # *2 for double occupancy
930
963
  dms = lib.einsum('xov,qv,po->xpq', xs*2, orbv.conj(), orbo)
931
964
  dms += lib.einsum('xov,pv,qo->xpq', ys*2, orbv, orbo.conj())
932
-
933
- v1ao = vresp(dms)
965
+ v1ao = vresp(dms) # = <mb||nj> Xjb + <mj||nb> Yjb
966
+ # A ~= <ib||aj>, B = <ij||ab>
967
+ # AX + BY
968
+ # = <ib||aj> Xjb + <ij||ab> Yjb
969
+ # = (<mb||nj> Xjb + <mj||nb> Yjb) Cmi* Cna
934
970
  v1ov = lib.einsum('xpq,po,qv->xov', v1ao, orbo.conj(), orbv)
971
+ # (B*)X + (A*)Y
972
+ # = <ab||ij> Xjb + <aj||ib> Yjb
973
+ # = (<mb||nj> Xjb + <mj||nb> Yjb) Cma* Cni
935
974
  v1vo = lib.einsum('xpq,qo,pv->xov', v1ao, orbo, orbv.conj())
936
- v1ov += lib.einsum('xqs,sp->xqp', xs, fvv) # AX
937
- v1ov -= lib.einsum('xpr,sp->xsr', xs, foo) # AX
938
- v1vo += lib.einsum('xqs,sp->xqp', ys, fvv) # AY
939
- v1vo -= lib.einsum('xpr,sp->xsr', ys, foo) # AY
975
+ v1ov += numpy.einsum('xia,ia->xia', xs, e_ia) # AX
976
+ v1vo += numpy.einsum('xia,ia->xia', ys, e_ia.conj()) # (A*)Y
940
977
 
941
978
  if wfnsym is not None and mol.symmetry:
942
979
  v1ov[:,sym_forbid] = 0
@@ -950,12 +987,12 @@ def gen_tdhf_operation(mf, fock_ao=None, singlet=True, wfnsym=None):
950
987
  return vind, hdiag
951
988
 
952
989
 
953
- class TDHF(TDA):
990
+ class TDHF(TDBase):
954
991
  '''Time-dependent Hartree-Fock
955
992
 
956
993
  Attributes:
957
994
  conv_tol : float
958
- Diagonalization convergence tolerance. Default is 1e-9.
995
+ Diagonalization convergence tolerance. Default is 1e-4.
959
996
  nstates : int
960
997
  Number of TD states to be computed. Default is 3.
961
998
 
@@ -971,16 +1008,22 @@ class TDHF(TDA):
971
1008
  excited state. (X,Y) are normalized to 1/2 in RHF/RKS methods and
972
1009
  normalized to 1 for UHF/UKS methods. In the TDA calculation, Y = 0.
973
1010
  '''
1011
+
974
1012
  @lib.with_doc(gen_tdhf_operation.__doc__)
975
1013
  def gen_vind(self, mf=None):
976
1014
  if mf is None:
977
1015
  mf = self._scf
978
1016
  return gen_tdhf_operation(mf, singlet=self.singlet, wfnsym=self.wfnsym)
979
1017
 
980
- def init_guess(self, mf, nstates=None, wfnsym=None):
981
- x0 = TDA.init_guess(self, mf, nstates, wfnsym)
982
- y0 = numpy.zeros_like(x0)
983
- return numpy.asarray(numpy.block([[x0, y0], [y0, x0.conj()]]))
1018
+ def init_guess(self, mf, nstates=None, wfnsym=None, return_symmetry=False):
1019
+ if return_symmetry:
1020
+ x0, x0sym = TDA.init_guess(self, mf, nstates, wfnsym, return_symmetry)
1021
+ y0 = numpy.zeros_like(x0)
1022
+ return numpy.hstack([x0, y0]), x0sym
1023
+ else:
1024
+ x0 = TDA.init_guess(self, mf, nstates, wfnsym, return_symmetry)
1025
+ y0 = numpy.zeros_like(x0)
1026
+ return numpy.hstack([x0, y0])
984
1027
 
985
1028
  def kernel(self, x0=None, nstates=None):
986
1029
  '''TDHF diagonalization with non-Hermitian eigenvalue solver
@@ -992,6 +1035,7 @@ class TDHF(TDA):
992
1035
  nstates = self.nstates
993
1036
  else:
994
1037
  self.nstates = nstates
1038
+ mol = self.mol
995
1039
 
996
1040
  log = logger.Logger(self.stdout, self.verbose)
997
1041
 
@@ -1015,16 +1059,19 @@ class TDHF(TDA):
1015
1059
  # approximately be used as the "real" eigen solutions.
1016
1060
  return lib.linalg_helper._eigs_cmplx2real(w, v, realidx, real_system)
1017
1061
 
1062
+ x0sym = None
1018
1063
  if x0 is None:
1019
- x0 = self.init_guess(self._scf, self.nstates)
1020
-
1021
- self.converged, w, x1 = \
1022
- lib.davidson_nosym1(vind, x0, precond,
1023
- tol=self.conv_tol,
1024
- nroots=nstates, lindep=self.lindep,
1025
- max_cycle=self.max_cycle,
1026
- max_space=self.max_space, pick=pickeig,
1027
- verbose=log)
1064
+ x0, x0sym = self.init_guess(
1065
+ self._scf, self.nstates, return_symmetry=True)
1066
+ elif mol.symmetry:
1067
+ x_sym = y_sym = _get_x_sym_table(self._scf).ravel()
1068
+ x_sym = numpy.append(x_sym, y_sym)
1069
+ x0sym = [_guess_wfnsym_id(self, x_sym, x) for x in x0]
1070
+
1071
+ self.converged, w, x1 = lr_eig(
1072
+ vind, x0, precond, tol_residual=self.conv_tol, lindep=self.lindep,
1073
+ nroots=nstates, x0sym=x0sym, pick=pickeig, max_cycle=self.max_cycle,
1074
+ max_memory=self.max_memory, verbose=log)
1028
1075
 
1029
1076
  nocc = (self._scf.mo_occ>0).sum()
1030
1077
  nmo = self._scf.mo_occ.size
pyscf/tdscf/rks.py CHANGED
@@ -25,8 +25,7 @@ import numpy
25
25
  from pyscf import lib
26
26
  from pyscf import symm
27
27
  from pyscf.tdscf import rhf
28
- from pyscf.scf import hf_symm
29
- from pyscf.data import nist
28
+ from pyscf.tdscf._lr_eig import eigh as lr_eigh
30
29
  from pyscf.dft.rks import KohnShamDFT
31
30
  from pyscf import __config__
32
31
 
@@ -46,6 +45,7 @@ RPA = TDRKS = TDDFT
46
45
  class CasidaTDDFT(TDDFT, TDA):
47
46
  '''Solve the Casida TDDFT formula (A-B)(A+B)(X+Y) = (X+Y)w^2
48
47
  '''
48
+
49
49
  init_guess = TDA.init_guess
50
50
 
51
51
  def gen_vind(self, mf=None):
@@ -71,9 +71,7 @@ class CasidaTDDFT(TDDFT, TDA):
71
71
  if isinstance(wfnsym, str):
72
72
  wfnsym = symm.irrep_name2id(mol.groupname, wfnsym)
73
73
  wfnsym = wfnsym % 10 # convert to D2h subgroup
74
- orbsym = hf_symm.get_orbsym(mol, mo_coeff)
75
- orbsym_in_d2h = numpy.asarray(orbsym) % 10 # convert to D2h irreps
76
- sym_forbid = (orbsym_in_d2h[occidx,None] ^ orbsym_in_d2h[viridx]) != wfnsym
74
+ sym_forbid = rhf._get_x_sym_table(mf) != wfnsym
77
75
 
78
76
  e_ia = (mo_energy[viridx].reshape(-1,1) - mo_energy[occidx]).T
79
77
  if wfnsym is not None and mol.symmetry:
@@ -105,6 +103,7 @@ class CasidaTDDFT(TDDFT, TDA):
105
103
  '''TDDFT diagonalization solver
106
104
  '''
107
105
  cpu0 = (lib.logger.process_clock(), lib.logger.perf_counter())
106
+ mol = self.mol
108
107
  mf = self._scf
109
108
  if mf._numint.libxc.is_hybrid_xc(mf.xc):
110
109
  raise RuntimeError('%s cannot be used with hybrid functional'
@@ -125,16 +124,18 @@ class CasidaTDDFT(TDDFT, TDA):
125
124
  idx = numpy.where(w > self.positive_eig_threshold)[0]
126
125
  return w[idx], v[:,idx], idx
127
126
 
127
+ x0sym = None
128
128
  if x0 is None:
129
- x0 = self.init_guess(self._scf, self.nstates)
130
-
131
- self.converged, w2, x1 = \
132
- lib.davidson1(vind, x0, precond,
133
- tol=self.conv_tol,
134
- nroots=nstates, lindep=self.lindep,
135
- max_cycle=self.max_cycle,
136
- max_space=self.max_space, pick=pickeig,
137
- verbose=log)
129
+ x0, x0sym = self.init_guess(
130
+ self._scf, self.nstates, return_symmetry=True)
131
+ elif mol.symmetry:
132
+ x_sym = rhf._get_x_sym_table(mf).ravel()
133
+ x0sym = [rhf._guess_wfnsym_id(self, x_sym, x) for x in x0]
134
+
135
+ self.converged, w2, x1 = lr_eigh(
136
+ vind, x0, precond, tol_residual=self.conv_tol, lindep=self.lindep,
137
+ nroots=nstates, x0sym=x0sym, pick=pickeig, max_cycle=self.max_cycle,
138
+ max_memory=self.max_memory, verbose=log)
138
139
 
139
140
  mo_energy = self._scf.mo_energy
140
141
  mo_occ = self._scf.mo_occ