Skip to content

Commit 0b1904c

Browse files
committed
revamp libcint to return c_contig view with zero copy
1 parent 036d48c commit 0b1904c

6 files changed

Lines changed: 51 additions & 31 deletions

File tree

forte2/helpers/ndarray.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,18 @@ auto make_zeros(const std::array<size_t, N>& shape) {
158158

159159
return array;
160160
}
161+
162+
template <typename Type, typename T, int N>
163+
auto fortran_to_c(nb::ndarray<Type, T, nb::ndim<N>, nb::f_contig>& arr) {
164+
std::array<std::size_t, N> C_shape;
165+
std::array<std::int64_t, N> C_strides;
166+
for (std::size_t i = 0; i < static_cast<std::size_t>(N); ++i) {
167+
C_shape[i] = arr.shape(N - 1 - i);
168+
C_strides[i] = arr.stride(N - 1 - i);
169+
}
170+
T* data = arr.data();
171+
172+
nb::object owner = arr.cast();
173+
174+
return nb::ndarray<Type, T, nb::ndim<N>, nb::c_contig>(data, static_cast<std::size_t>(N), C_shape.data(), owner, C_strides.data());
175+
}

forte2/integrals/integrals.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -715,13 +715,13 @@ def _parse_basis_args_cint_3c2e(system, basis1, basis2, basis3, origin=None):
715715
system, system.basis, common_origin=origin
716716
)
717717
nsh_bas = system.basis.nshells
718-
shell_slice = [0, nsh_bas, 0, nsh_bas, nsh_bas, nsh_bas + nsh_aux]
718+
shell_slice = [nsh_bas, nsh_bas + nsh_aux, 0, nsh_bas, 0, nsh_bas]
719719
elif basis2 is not None and basis3 is None:
720720
bas_atm, bas_bas, bas_env = basis_to_cint_envs(
721721
system, basis2, common_origin=origin
722722
)
723723
nsh_bas = basis2.nshells
724-
shell_slice = [0, nsh_bas, 0, nsh_bas, nsh_bas, nsh_bas + nsh_aux]
724+
shell_slice = [nsh_bas, nsh_bas + nsh_aux, 0, nsh_bas, 0, nsh_bas]
725725
elif basis2 is not None and basis3 is not None and basis2 != basis3:
726726
raise ValueError(
727727
"libcint doesn't support (P|QR) with Q and R being different basis sets."
@@ -734,10 +734,10 @@ def _parse_basis_args_cint_3c2e(system, basis1, basis2, basis3, origin=None):
734734

735735

736736
def _f2c(arr):
737-
if arr.shape[-1] == 1:
738-
return np.ascontiguousarray(arr[..., 0])
737+
if arr.shape[0] == 1:
738+
return arr[0]
739739
else:
740-
return np.ascontiguousarray(np.rollaxis(arr, -1, 0))
740+
return arr
741741

742742

743743
def cint_overlap(system, basis1=None, basis2=None):
@@ -783,6 +783,7 @@ def cint_overlap_spinor(system, basis1=None, basis2=None):
783783
_require_libcint()
784784
atm, bas, env, shell_slice = _parse_basis_args_cint_1e(system, basis1, basis2)
785785
res = ints.cint_int1e_ovlp_spinor(shell_slice, atm, bas, env)
786+
np.conjugate(res, out=res)
786787
return _f2c(res)
787788

788789

@@ -857,7 +858,10 @@ def cint_opVop(system, basis1=None, basis2=None):
857858
_require_libcint()
858859
atm, bas, env, shell_slice = _parse_basis_args_cint_1e(system, basis1, basis2)
859860
res = ints.cint_int1e_spnucsp_sph(shell_slice, atm, bas, env)
861+
# the x/y/z components are antisymmetric due to the cross produce (swapping the two basis functions changes the sign)
862+
# libcint returns the transposed version, hence the sign flip
860863
# C-layout, first index is the integral component (slowest changing)
864+
res[:-1] *= -1
861865
return _f2c(res)
862866

863867

@@ -885,6 +889,7 @@ def cint_opVop_spinor(system, basis1=None, basis2=None):
885889
_require_libcint()
886890
atm, bas, env, shell_slice = _parse_basis_args_cint_1e(system, basis1, basis2)
887891
res = ints.cint_int1e_spnucsp_spinor(shell_slice, atm, bas, env)
892+
np.conj(res, out=res)
888893
return _f2c(res)
889894

890895

@@ -958,4 +963,4 @@ def cint_coulomb_3c(system, basis1=None, basis2=None, basis3=None):
958963
system, basis1, basis2, basis3
959964
)
960965
res = ints.cint_int3c2e_sph(shell_slice, atm, bas, env)
961-
return res.transpose(2, 0, 1).copy() # copy makes sure it's C-contiguous
966+
return res

forte2/integrals/libcint_compute.h

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ namespace forte2 {
2929
// templated function to compute two-center integrals with M components
3030
// (i.e., 1 for scalar integrals, 3 for dipoles integrals, etc.)
3131
template <std::size_t M>
32-
np_tensor3_f cint_int2c(CIntorFunc intor, const std::vector<int>& shell_slice, np_matrix_int atm,
32+
np_tensor3_c cint_int2c(CIntorFunc intor, const std::vector<int>& shell_slice, np_matrix_int atm,
3333
np_matrix_int bas, np_vector env) {
3434

35-
const int ish_0 = static_cast<int>(shell_slice[0]);
36-
const int ish_1 = static_cast<int>(shell_slice[1]);
37-
const int jsh_0 = static_cast<int>(shell_slice[2]);
38-
const int jsh_1 = static_cast<int>(shell_slice[3]);
35+
const int jsh_0 = static_cast<int>(shell_slice[0]);
36+
const int jsh_1 = static_cast<int>(shell_slice[1]);
37+
const int ish_0 = static_cast<int>(shell_slice[2]);
38+
const int ish_1 = static_cast<int>(shell_slice[3]);
3939
const int nish = ish_1 - ish_0;
4040
const int njsh = jsh_1 - jsh_0;
4141

@@ -76,17 +76,17 @@ np_tensor3_f cint_int2c(CIntorFunc intor, const std::vector<int>& shell_slice, n
7676
}
7777
}
7878

79-
return ints;
79+
return fortran_to_c<nb::numpy, double, 3>(ints);
8080
}
8181

8282
template <std::size_t M>
83-
np_tensor3_complex_f cint_int2c_spinor(CIntorFuncSpinor intor, const std::vector<int>& shell_slice,
83+
np_tensor3_complex_c cint_int2c_spinor(CIntorFuncSpinor intor, const std::vector<int>& shell_slice,
8484
np_matrix_int atm, np_matrix_int bas, np_vector env) {
8585

86-
const int ish_0 = static_cast<int>(shell_slice[0]);
87-
const int ish_1 = static_cast<int>(shell_slice[1]);
88-
const int jsh_0 = static_cast<int>(shell_slice[2]);
89-
const int jsh_1 = static_cast<int>(shell_slice[3]);
86+
const int jsh_0 = static_cast<int>(shell_slice[0]);
87+
const int jsh_1 = static_cast<int>(shell_slice[1]);
88+
const int ish_0 = static_cast<int>(shell_slice[2]);
89+
const int ish_1 = static_cast<int>(shell_slice[3]);
9090
const int nish = ish_1 - ish_0;
9191
const int njsh = jsh_1 - jsh_0;
9292

@@ -127,7 +127,7 @@ np_tensor3_complex_f cint_int2c_spinor(CIntorFuncSpinor intor, const std::vector
127127
}
128128
}
129129

130-
return ints;
130+
return fortran_to_c<nb::numpy, std::complex<double>, 3>(ints);
131131
}
132132

133133
void fill_3c_sym(np_tensor3_f& ints) {
@@ -166,14 +166,14 @@ void fill_3c_sym(np_tensor3_f& ints) {
166166
}
167167

168168
// function to compute three-center integrals
169-
np_tensor3_f cint_int3c(CIntorFunc intor, const std::vector<int>& shell_slice, np_matrix_int atm,
169+
np_tensor3_c cint_int3c(CIntorFunc intor, const std::vector<int>& shell_slice, np_matrix_int atm,
170170
np_matrix_int bas, np_vector env) {
171-
const int ish_0 = static_cast<int>(shell_slice[0]);
172-
const int ish_1 = static_cast<int>(shell_slice[1]);
171+
const int ksh_0 = static_cast<int>(shell_slice[0]);
172+
const int ksh_1 = static_cast<int>(shell_slice[1]);
173173
const int jsh_0 = static_cast<int>(shell_slice[2]);
174174
const int jsh_1 = static_cast<int>(shell_slice[3]);
175-
const int ksh_0 = static_cast<int>(shell_slice[4]);
176-
const int ksh_1 = static_cast<int>(shell_slice[5]);
175+
const int ish_0 = static_cast<int>(shell_slice[4]);
176+
const int ish_1 = static_cast<int>(shell_slice[5]);
177177

178178
// Whether i and j shells are identical, if they are we can exploit symmetry
179179
bool ij_sym = (ish_0 == jsh_0) && (ish_1 == jsh_1);
@@ -264,7 +264,7 @@ np_tensor3_f cint_int3c(CIntorFunc intor, const std::vector<int>& shell_slice, n
264264
fill_3c_sym(ints);
265265
}
266266

267-
return ints;
267+
return fortran_to_c<nb::numpy, double, 3>(ints);
268268
}
269269

270270
} // namespace forte2

forte2/integrals/libcint_three_center.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace forte2 {
4242
// return cint_int2c<1>(int1e_ovlp_sph, shell_slice, atm, bas, env);
4343
// }
4444
#define DECL_CINT_FORTE2_FUNC_SPH(name) \
45-
np_tensor3_f cint_##name##_sph(const std::vector<int>& shell_slice, np_matrix_int atm, \
45+
np_tensor3_c cint_##name##_sph(const std::vector<int>& shell_slice, np_matrix_int atm, \
4646
np_matrix_int bas, np_vector env) { \
4747
return cint_int3c(name##_sph, shell_slice, atm, bas, env); \
4848
}

forte2/integrals/libcint_two_center.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ namespace forte2 {
5555
// return cint_int2c<1>(int1e_ovlp_sph, shell_slice, atm, bas, env);
5656
// }
5757
#define DECL_CINT_FORTE2_FUNC_SPH(name, comp) \
58-
np_tensor3_f cint_##name##_sph(const std::vector<int>& shell_slice, np_matrix_int atm, np_matrix_int bas, \
58+
np_tensor3_c cint_##name##_sph(const std::vector<int>& shell_slice, np_matrix_int atm, np_matrix_int bas, \
5959
np_vector env) { \
6060
return cint_int2c<comp>(name##_sph, shell_slice, atm, bas, env); \
6161
}
@@ -69,7 +69,7 @@ DECL_CINT_FORTE2_FUNC_SPH(int2c2e, 1)
6969
#undef DECL_CINT_FORTE2_FUNC_SPH
7070

7171
#define DECL_CINT_FORTE2_FUNC_SPINOR(name, comp) \
72-
np_tensor3_complex_f cint_##name##_spinor(const std::vector<int>& shell_slice, np_matrix_int atm, \
72+
np_tensor3_complex_c cint_##name##_spinor(const std::vector<int>& shell_slice, np_matrix_int atm, \
7373
np_matrix_int bas, np_vector env) { \
7474
return cint_int2c_spinor<comp>(name##_spinor, shell_slice, atm, bas, env); \
7575
}

tests/integrals/test_libcint.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ def test_libcint_spnucsp_sph():
7070
system = System(xyz, basis_set="sto-3g", minao_basis_set=None)
7171
s_cint = integrals.cint_opVop(system)
7272
c_int2 = integrals.opVop(system)
73-
assert np.linalg.norm(s_cint[3] - c_int2[0]) < 1e-6 # I2
74-
assert np.linalg.norm(s_cint[0] - c_int2[1]) < 1e-6 # sigma_x
75-
assert np.linalg.norm(s_cint[1] - c_int2[2]) < 1e-6 # sigma_y
76-
assert np.linalg.norm(s_cint[2] - c_int2[3]) < 1e-6 # sigma_z
73+
assert np.linalg.norm(s_cint[3] - c_int2[0]) < 1e-6 # sigma_x
74+
assert np.linalg.norm(s_cint[0] - c_int2[1]) < 1e-6 # sigma_y
75+
assert np.linalg.norm(s_cint[1] - c_int2[2]) < 1e-6 # sigma_z
76+
assert np.linalg.norm(s_cint[2] - c_int2[3]) < 1e-6 # I2
7777
assert np.linalg.norm(s_cint) == pytest.approx(5982385.234519612, rel=1e-6)
7878

7979

0 commit comments

Comments
 (0)