32
32
33
33
34
34
def factorial2 (n , exact = False ):
35
- """Wrap scipy.special.factorial2 to return 1.0 when the input is -1.
35
+ """Wrap scipy.special.factorial2 to return 1.0 when the input is -1 and handle float arrays .
36
36
37
37
This is a temporary workaround while we wait for Scipy's update.
38
38
To learn more, see https://github.com/scipy/scipy/issues/18409.
39
39
40
40
Parameters
41
41
----------
42
- n : int or np.ndarray
42
+ n : int, float, or np.ndarray
43
43
Values to calculate n!! for. If n={0, -1}, the return value is 1.
44
44
For n < -1, the return value is 0.
45
45
"""
46
- # Scipy 1.11.x returns an integer when n is an integer, but 1.10.x returns an array,
47
- # so np.array(n) is passed to make sure the output is always an array.
48
- out = scipy .special .factorial2 (np .array (n ), exact = exact )
49
- out [out <= 0 ] = 1.0
50
- out [out <= - 2 ] = 0.0
51
- return out
46
+ # Handle integer inputs
47
+ if isinstance (n , (int , np .integer )):
48
+ if n == - 1 or n == 0 :
49
+ return 1.0
50
+ elif n < - 1 :
51
+ return 0.0
52
+ else :
53
+ return scipy .special .factorial2 (n , exact = exact )
54
+
55
+ # Handle float inputs
56
+ elif isinstance (n , float ):
57
+ if n == - 1.0 or n == 0.0 :
58
+ return 1.0
59
+ elif n < - 1.0 :
60
+ return 0.0
61
+ else :
62
+ return scipy .special .factorial2 (int (n ), exact = exact )
63
+
64
+ # Handle array inputs
65
+ elif isinstance (n , np .ndarray ):
66
+ result = np .zeros_like (n , dtype = float )
67
+ for i , val in np .ndenumerate (n ):
68
+ if val == - 1.0 or val == 0.0 :
69
+ result [i ] = 1.0
70
+ elif val < - 1.0 :
71
+ result [i ] = 0.0
72
+ else :
73
+ result [i ] = scipy .special .factorial2 (int (val ), exact = exact )
74
+ return result
52
75
53
76
54
77
# pylint: disable=too-many-nested-blocks,too-many-statements,too-many-branches
55
- def compute_overlap (
56
- obasis0 : MolecularBasis ,
57
- atcoords0 : np .ndarray ,
58
- obasis1 : Optional [MolecularBasis ] = None ,
59
- atcoords1 : Optional [np .ndarray ] = None ,
60
- ) -> np .ndarray :
78
+ def compute_overlap (obasis0 : MolecularBasis , atcoords0 : np .ndarray ,
79
+ obasis1 : Optional [MolecularBasis ] = None ,
80
+ atcoords1 : Optional [np .ndarray ] = None ,) -> np .ndarray :
61
81
r"""Compute overlap matrix for the given molecular basis set(s).
62
82
63
83
.. math::
@@ -89,30 +109,28 @@ def compute_overlap(
89
109
The matrix with overlap integrals, ``shape=(obasis0.nbasis, obasis1.nbasis)``.
90
110
91
111
"""
92
- if obasis0 .primitive_normalization != "L2" :
93
- raise ValueError ("The overlap integrals are only implemented for L2 " "normalization." )
112
+ if obasis0 .primitive_normalization != 'L2' :
113
+ raise ValueError ('The overlap integrals are only implemented for L2 '
114
+ 'normalization.' )
94
115
95
116
# Get a segmented basis, for simplicity
96
117
obasis0 = obasis0 .get_segmented ()
97
118
98
119
# Handle optional arguments
99
120
if obasis1 is None :
100
121
if atcoords1 is not None :
101
- raise TypeError (
102
- "When no second basis is given, no second second "
103
- "array of atomic coordinates is expected."
104
- )
122
+ raise TypeError ("When no second basis is given, no second second "
123
+ "array of atomic coordinates is expected." )
105
124
obasis1 = obasis0
106
125
atcoords1 = atcoords0
107
126
identical = True
108
127
else :
109
- if obasis1 .primitive_normalization != "L2" :
110
- raise ValueError ("The overlap integrals are only implemented for L2 " "normalization." )
128
+ if obasis1 .primitive_normalization != 'L2' :
129
+ raise ValueError ('The overlap integrals are only implemented for L2 '
130
+ 'normalization.' )
111
131
if atcoords1 is None :
112
- raise TypeError (
113
- "When a second basis is given, a second second "
114
- "array of atomic coordinates is expected."
115
- )
132
+ raise TypeError ("When a second basis is given, a second second "
133
+ "array of atomic coordinates is expected." )
116
134
# Get a segmented basis, for simplicity
117
135
obasis1 = obasis1 .get_segmented ()
118
136
identical = False
@@ -122,13 +140,13 @@ def compute_overlap(
122
140
123
141
# Compute the normalization constants of the Cartesian primitives, with the
124
142
# contraction coefficients multiplied in.
125
- scales0 = [_compute_cart_shell_normalizations (shell ) * shell .coeffs for shell in obasis0 .shells ]
143
+ scales0 = [_compute_cart_shell_normalizations (shell ) * shell .coeffs
144
+ for shell in obasis0 .shells ]
126
145
if identical :
127
146
scales1 = scales0
128
147
else :
129
- scales1 = [
130
- _compute_cart_shell_normalizations (shell ) * shell .coeffs for shell in obasis1 .shells
131
- ]
148
+ scales1 = [_compute_cart_shell_normalizations (shell ) * shell .coeffs
149
+ for shell in obasis1 .shells ]
132
150
133
151
n_max = max (np .max (shell .angmoms ) for shell in obasis0 .shells )
134
152
if not identical :
@@ -203,9 +221,9 @@ def compute_overlap(
203
221
# END of Cartesian coordinate system (if going to pure coordinates)
204
222
205
223
# cart to pure
206
- if shell0 .kinds [0 ] == "p" :
224
+ if shell0 .kinds [0 ] == 'p' :
207
225
shell_overlap = np .dot (tfs [shell0 .angmoms [0 ]], shell_overlap )
208
- if shell1 .kinds [0 ] == "p" :
226
+ if shell1 .kinds [0 ] == 'p' :
209
227
shell_overlap = np .dot (shell_overlap , tfs [shell1 .angmoms [0 ]].T )
210
228
211
229
# store lower triangular result
@@ -254,12 +272,12 @@ def compute_overlap_gaussian_1d(self, x1, x2, n1, n2, two_at):
254
272
pf_i = self .binomials [n1 ][i ] * x1 ** (n1 - i )
255
273
for j in range (i % 2 , n2 + 1 , 2 ):
256
274
m = i + j
257
- integ = self .facts [m ] / two_at ** (m / 2 ) # TODO // 2
275
+ integ = self .facts [m ] / two_at ** (m / 2 ) # TODO // 2
258
276
value += pf_i * self .binomials [n2 ][j ] * x2 ** (n2 - j ) * integ
259
277
return value
260
278
261
279
262
- def _compute_cart_shell_normalizations (shell : " Shell" ) -> np .ndarray :
280
+ def _compute_cart_shell_normalizations (shell : ' Shell' ) -> np .ndarray :
263
281
"""Return normalization constants for the primitives in a given shell.
264
282
265
283
Parameters
@@ -274,7 +292,7 @@ def _compute_cart_shell_normalizations(shell: "Shell") -> np.ndarray:
274
292
shell is pure.
275
293
276
294
"""
277
- shell = attr .evolve (shell , kinds = ["c" ] * shell .ncon )
295
+ shell = attr .evolve (shell , kinds = ['c' ] * shell .ncon )
278
296
result = []
279
297
for angmom in shell .angmoms :
280
298
for exponent in shell .exponents :
@@ -301,6 +319,5 @@ def gob_cart_normalization(alpha: np.ndarray, n: np.ndarray) -> np.ndarray:
301
319
The normalization constant for the gaussian cartesian basis.
302
320
303
321
"""
304
- return np .sqrt (
305
- (4 * alpha ) ** sum (n ) * (2 * alpha / np .pi ) ** 1.5 / np .prod (factorial2 (2 * n - 1 ))
306
- )
322
+ return np .sqrt ((4 * alpha ) ** sum (n ) * (2 * alpha / np .pi ) ** 1.5
323
+ / np .prod (factorial2 (2 * n - 1 )))
0 commit comments