132#define LIBINT2_CONSTEXPR_STATICS 0
133#if defined(__clang__)
134#pragma clang diagnostic push
135#pragma clang diagnostic ignored "-W#warnings"
136#elif defined(__GNUC__)
137#pragma GCC diagnostic push
138#pragma GCC diagnostic ignored "-Warray-bounds"
139#pragma GCC diagnostic ignored "-Wcpp"
141#include <libint2.hpp>
150#if defined(__clang__)
151#pragma clang diagnostic pop
152#elif defined(__GNUC__)
153#pragma GCC diagnostic pop
162std::vector<Eigen::MatrixXd>
ComputeAO3cBlock(
const libint2::Shell& auxshell,
163 const AOBasis& dftbasis,
164 libint2::Engine& engine);
188 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
211[[noreturn, maybe_unused]]
void ThrowNoDerivativeSupport(
212 const char* function_name,
const char* configure_flag) {
213 throw std::runtime_error(
214 std::string(function_name) +
215 ": this libint2 build was compiled without derivative integral "
216 "support for this specific operator category -- analytic nuclear "
217 "forces using this function are unavailable. Rebuild libint2 "
218 "with this configured (" +
220 " at libint2 configure time) to use this feature. Many "
221 "pre-packaged libint2 builds (Homebrew, Ubuntu apt, etc.) do not "
222 "enable this by default; note in particular that different "
223 "operator categories (one-body, the two-center Coulomb metric, "
224 "three-center RI) each have their own, independent flag -- "
225 "enabling one does not enable the others.");
301#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
302 (LIBINT_INCLUDE_ONEBODY >= 1)
303template <lib
int2::Operator obtype>
304std::vector<AOMatrixDerivative> computeOneBodyIntegralDerivatives(
305 const AOBasis& aobasis) {
308 libint2::operator_traits<obtype>::nopers == 1,
309 "computeOneBodyIntegralDerivatives only supports single-operator "
310 "types (overlap, kinetic) in this first pass; multipole-type "
311 "operators with multiple result matrices are not yet handled here.");
316 Index natoms =
static_cast<Index>(aobasis.getFuncPerAtom().size());
318 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
319 std::vector<std::vector<Index>> shellpair_list = aobasis.ComputeShellPairs();
320 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
324 std::vector<Index> shell2atom;
325 shell2atom.reserve(shells.size());
326 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
329 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
332 Index nbf = aobasis.AOBasisSize();
333 std::vector<AOMatrixDerivative> result(natoms);
334 for (
Index a = 0; a < natoms; ++a) {
335 for (
Index xyz = 0; xyz < 3; ++xyz) {
336 result[a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
340 std::vector<libint2::Engine> engines(nthreads);
343 engines[0] = libint2::Engine(obtype, aobasis.getMaxNprim(),
344 static_cast<int>(aobasis.getMaxL()), 1);
345 for (
Index i = 1; i < nthreads; ++i) {
346 engines[i] = engines[0];
349 std::exception_ptr eptr =
nullptr;
350 std::atomic<bool> any_nonnull_buffer{
false};
351#pragma omp parallel for schedule(dynamic)
352 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
355 libint2::Engine& engine = engines[thread_id];
356 const libint2::Engine::target_ptr_vec& buf = engine.results();
358 Index bf1 = shell2bf[s1];
359 Index n1 = shells[s1].size();
360 Index atom1 = shell2atom[s1];
362 for (
Index s2 : shellpair_list[s1]) {
364 engine.compute(shells[s1], shells[s2]);
378 if (buf[0] ==
nullptr || buf[3] ==
nullptr) {
384 any_nonnull_buffer.store(
true, std::memory_order_relaxed);
393 Index bf2 = shell2bf[s2];
394 Index n2 = shells[s2].size();
395 Index atom2 = shell2atom[s2];
403 for (
Index xyz = 0; xyz < 3; ++xyz) {
404 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
405 result[atom1][xyz].block(bf1, bf2, n1, n2) += buf_mat1;
407 result[atom1][xyz].block(bf2, bf1, n2, n1) += buf_mat1.transpose();
410 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
411 result[atom2][xyz].block(bf1, bf2, n1, n2) += buf_mat2;
413 result[atom2][xyz].block(bf2, bf1, n2, n1) += buf_mat2.transpose();
428 eptr = std::current_exception();
434 std::rethrow_exception(eptr);
436 if (!any_nonnull_buffer.load() && aobasis.getNumofShells() > 0) {
444 throw std::runtime_error(
445 "computeOneBodyIntegralDerivatives: engine.results() returned a "
446 "null buffer for EVERY shell pair -- this libint2 build does not "
447 "actually support this operator's derivative integrals at "
448 "runtime, even though it may report LIBINT2_MAX_DERIV_ORDER >= 1 "
449 "for other operators. Rebuild libint2 with this operator's "
450 "derivative support enabled (--enable-1body=1) to use this "
461 const AOBasis& aobasis) {
462 return computeOneBodyIntegralDerivatives<libint2::Operator::overlap>(aobasis);
466 const AOBasis& aobasis) {
467 return computeOneBodyIntegralDerivatives<libint2::Operator::kinetic>(aobasis);
478 ThrowNoDerivativeSupport(
"ComputeOverlapDerivatives",
"--enable-1body=1");
481 ThrowNoDerivativeSupport(
"ComputeKineticDerivatives",
"--enable-1body=1");
536#if (LIBINT_INCLUDE_ERI2 >= 1)
538 const AOBasis& aobasis) {
539 Index natoms =
static_cast<Index>(aobasis.getFuncPerAtom().size());
541 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
542 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
544 std::vector<Index> shell2atom;
545 shell2atom.reserve(aobasis.getNumofShells());
546 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
547 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
550 Index nbf = aobasis.AOBasisSize();
551 std::vector<AOMatrixDerivative> result(natoms);
552 for (
Index a = 0; a < natoms; ++a) {
553 for (
Index xyz = 0; xyz < 3; ++xyz) {
554 result[a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
558 std::vector<libint2::Engine> engines(nthreads);
560 libint2::Engine(libint2::Operator::coulomb, aobasis.getMaxNprim(),
561 static_cast<int>(aobasis.getMaxL()), 1);
562 engines[0].set(libint2::BraKet::xs_xs);
563 for (
Index i = 1; i < nthreads; ++i) {
564 engines[i] = engines[0];
567 std::exception_ptr eptr_coulmetric =
nullptr;
568 std::atomic<bool> any_nonnull_buffer_coulmetric{
false};
569#pragma omp parallel for schedule(dynamic)
570 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
573 const libint2::Engine::target_ptr_vec& buf = engine.results();
575 Index bf1 = shell2bf[s1];
576 Index n1 = shells[s1].size();
577 Index atom1 = shell2atom[s1];
582 for (
Index s2 = 0; s2 <= s1; ++s2) {
583 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xs, 1>(
584 shells[s1], libint2::Shell::unit(), shells[s2],
585 libint2::Shell::unit());
591 if (buf[0] ==
nullptr || buf[3] ==
nullptr) {
594 any_nonnull_buffer_coulmetric.store(
true, std::memory_order_relaxed);
596 Index bf2 = shell2bf[s2];
597 Index n2 = shells[s2].size();
598 Index atom2 = shell2atom[s2];
601 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
602 result[atom1][
xyz].block(bf1, bf2, n1, n2) += buf_mat1;
604 result[atom1][
xyz].block(bf2, bf1, n2, n1) += buf_mat1.transpose();
607 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
608 result[atom2][
xyz].block(bf1, bf2, n1, n2) += buf_mat2;
610 result[atom2][
xyz].block(bf2, bf1, n2, n1) += buf_mat2.transpose();
617 if (!eptr_coulmetric) {
618 eptr_coulmetric = std::current_exception();
623 if (eptr_coulmetric) {
624 std::rethrow_exception(eptr_coulmetric);
626 if (!any_nonnull_buffer_coulmetric.load() && aobasis.getNumofShells() > 0) {
629 throw std::runtime_error(
630 "ComputeCoulombMetricDerivatives: engine.results() returned a "
631 "null buffer for EVERY shell pair -- this libint2 build does not "
632 "actually support this operator's derivative integrals at "
633 "runtime, even though it may report LIBINT2_MAX_DERIV_ORDER >= 1 "
634 "for other operators. Rebuild libint2 with this operator's "
635 "derivative support enabled (--enable-eri2=1) to use this "
643 ThrowNoDerivativeSupport(
"ComputeCoulombMetricDerivatives",
704#if (LIBINT_INCLUDE_ERI3 >= 1)
706 const AOBasis& auxbasis,
const AOBasis& dftbasis) {
707 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
714 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
715 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
716 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
717 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
719 std::vector<Index> dftshell2atom;
720 dftshell2atom.reserve(dftbasis.getNumofShells());
721 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
722 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
724 std::vector<Index> auxshell2atom;
725 auxshell2atom.reserve(auxbasis.getNumofShells());
726 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
727 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
730 Index n_dft_bf = dftbasis.AOBasisSize();
731 Index n_aux_bf = auxbasis.AOBasisSize();
733 std::vector<ThreeCenterDerivative> result(natoms);
734 for (
Index a = 0; a < natoms; ++a) {
736 result[a][
xyz] = std::vector<Eigen::MatrixXd>(
737 n_aux_bf, Eigen::MatrixXd::Zero(n_dft_bf, n_dft_bf));
741 std::vector<libint2::Engine> engines(nthreads);
742 engines[0] = libint2::Engine(
743 libint2::Operator::coulomb,
744 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
745 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
746 engines[0].set(libint2::BraKet::xs_xx);
747 for (
Index i = 1; i < nthreads; ++i) {
748 engines[i] = engines[0];
751 std::exception_ptr eptr_3c =
nullptr;
752 std::atomic<bool> any_nonnull_buffer_3c{
false};
753#pragma omp parallel for schedule(dynamic)
754 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
757 const libint2::Engine::target_ptr_vec& buf = engine.results();
759 const libint2::Shell& auxshell = auxshells[aux];
760 Index aux_start = auxshell2bf[aux];
761 Index atom_aux = auxshell2atom[aux];
763 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
764 const libint2::Shell& shell_row = dftshells[row];
765 Index row_start = shell2bf[row];
766 Index atom_row = dftshell2atom[row];
778 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
779 const libint2::Shell& shell_col = dftshells[col];
780 Index col_start = shell2bf[col];
781 Index atom_col = dftshell2atom[col];
784 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
785 auxshell, libint2::Shell::unit(), shell_col, shell_row);
791 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
794 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
805 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
806 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
809 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
810 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
813 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
814 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
817 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
818 Index global_aux = aux_start +
static_cast<Index>(aux_c);
819 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
820 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
821 double val_aux = result_aux(aux_c, col_c, row_c);
822 double val_col = result_col(aux_c, col_c, row_c);
823 double val_row = result_row(aux_c, col_c, row_c);
824 Index r = row_start +
static_cast<Index>(row_c);
825 Index c = col_start +
static_cast<Index>(col_c);
826 result[atom_aux][
xyz][global_aux](r, c) += val_aux;
827 result[atom_col][
xyz][global_aux](r, c) += val_col;
828 result[atom_row][
xyz][global_aux](r, c) += val_row;
839 eptr_3c = std::current_exception();
845 std::rethrow_exception(eptr_3c);
847 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
848 dftbasis.getNumofShells() > 0) {
851 throw std::runtime_error(
852 "ComputeThreeCenterDerivatives: engine.results() returned a null "
853 "buffer for EVERY shell triple -- this libint2 build does not "
854 "actually support this operator's derivative integrals at "
855 "runtime, even though it may report LIBINT2_MAX_DERIV_ORDER >= 1 "
856 "for other operators. Rebuild libint2 with this operator's "
857 "derivative support enabled (--enable-eri3=1) to use this "
865 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivatives",
"--enable-eri3=1");
869#if (LIBINT_INCLUDE_ERI3 >= 1)
909 const AOBasis& auxbasis,
const AOBasis& dftbasis,
910 const Eigen::MatrixXd& density) {
911 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
914 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
915 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
916 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
917 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
919 std::vector<Index> dftshell2atom;
920 dftshell2atom.reserve(dftbasis.getNumofShells());
921 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
922 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
924 std::vector<Index> auxshell2atom;
925 auxshell2atom.reserve(auxbasis.getNumofShells());
926 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
927 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
930 Index n_aux_bf = auxbasis.AOBasisSize();
936 std::vector<Eigen::MatrixXd> result(natoms,
937 Eigen::MatrixXd::Zero(3, n_aux_bf));
939 std::vector<libint2::Engine> engines(nthreads);
940 engines[0] = libint2::Engine(
941 libint2::Operator::coulomb,
942 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
943 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
944 engines[0].set(libint2::BraKet::xs_xx);
945 for (
Index i = 1; i < nthreads; ++i) {
946 engines[i] = engines[0];
958 std::exception_ptr eptr_3c =
nullptr;
959 std::atomic<bool> any_nonnull_buffer_3c{
false};
960#pragma omp parallel for schedule(dynamic)
961 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
964 const libint2::Engine::target_ptr_vec& buf = engine.results();
966 const libint2::Shell& auxshell = auxshells[aux];
967 Index aux_start = auxshell2bf[aux];
968 Index atom_aux = auxshell2atom[aux];
970 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
971 const libint2::Shell& shell_row = dftshells[row];
972 Index row_start = shell2bf[row];
973 Index atom_row = dftshell2atom[row];
975 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
976 const libint2::Shell& shell_col = dftshells[col];
977 Index col_start = shell2bf[col];
978 Index atom_col = dftshell2atom[col];
981 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
982 auxshell, libint2::Shell::unit(), shell_col, shell_row);
984 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
987 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
991 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
992 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
995 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
996 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
999 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1000 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
1003 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
1004 Index global_aux = aux_start +
static_cast<Index>(aux_c);
1005 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
1006 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
1007 double val_aux = result_aux(aux_c, col_c, row_c);
1008 double val_col = result_col(aux_c, col_c, row_c);
1009 double val_row = result_row(aux_c, col_c, row_c);
1010 Index r = row_start +
static_cast<Index>(row_c);
1011 Index c = col_start +
static_cast<Index>(col_c);
1018 double d_rc = density(r, c);
1019 result[atom_aux](
xyz, global_aux) += d_rc * val_aux;
1020 result[atom_col](
xyz, global_aux) += d_rc * val_col;
1021 result[atom_row](
xyz, global_aux) += d_rc * val_row;
1032 eptr_3c = std::current_exception();
1038 std::rethrow_exception(eptr_3c);
1040 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
1041 dftbasis.getNumofShells() > 0) {
1042 throw std::runtime_error(
1043 "ComputeThreeCenterDerivativeContraction: engine.results() "
1044 "returned a null buffer for EVERY shell triple -- this libint2 "
1045 "build does not actually support this operator's derivative "
1046 "integrals at runtime, even though it may report "
1047 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1048 "libint2 with this operator's derivative support enabled "
1049 "(--enable-eri3=1) to use this feature.");
1056 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativeContraction",
1061#if (LIBINT_INCLUDE_ERI3 >= 1)
1098 const AOBasis& auxbasis,
const AOBasis& dftbasis,
Index target_atom) {
1099 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
1100 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
1101 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
1102 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
1104 std::vector<Index> dftshell2atom;
1105 dftshell2atom.reserve(dftbasis.getNumofShells());
1106 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
1107 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
1109 std::vector<Index> auxshell2atom;
1110 auxshell2atom.reserve(auxbasis.getNumofShells());
1111 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
1112 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
1115 Index n_dft_bf = dftbasis.AOBasisSize();
1116 Index n_aux_bf = auxbasis.AOBasisSize();
1124 result[
xyz] = std::vector<Eigen::MatrixXd>(
1125 n_aux_bf, Eigen::MatrixXd::Zero(n_dft_bf, n_dft_bf));
1128 std::vector<libint2::Engine> engines(nthreads);
1129 engines[0] = libint2::Engine(
1130 libint2::Operator::coulomb,
1131 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
1132 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
1133 engines[0].set(libint2::BraKet::xs_xx);
1134 for (
Index i = 1; i < nthreads; ++i) {
1135 engines[i] = engines[0];
1138 std::exception_ptr eptr_3c =
nullptr;
1139 std::atomic<bool> any_nonnull_buffer_3c{
false};
1140#pragma omp parallel for schedule(dynamic)
1141 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
1144 const libint2::Engine::target_ptr_vec& buf = engine.results();
1146 const libint2::Shell& auxshell = auxshells[aux];
1147 Index aux_start = auxshell2bf[aux];
1148 Index atom_aux = auxshell2atom[aux];
1150 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
1151 const libint2::Shell& shell_row = dftshells[row];
1152 Index row_start = shell2bf[row];
1153 Index atom_row = dftshell2atom[row];
1155 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
1156 const libint2::Shell& shell_col = dftshells[col];
1157 Index col_start = shell2bf[col];
1158 Index atom_col = dftshell2atom[col];
1165 if (atom_aux != target_atom && atom_col != target_atom &&
1166 atom_row != target_atom) {
1171 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
1172 auxshell, libint2::Shell::unit(), shell_col, shell_row);
1174 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
1177 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
1181 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1182 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
1185 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1186 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
1189 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1190 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
1193 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
1194 Index global_aux = aux_start +
static_cast<Index>(aux_c);
1195 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
1196 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
1197 Index r = row_start +
static_cast<Index>(row_c);
1198 Index c = col_start +
static_cast<Index>(col_c);
1205 if (atom_aux == target_atom) {
1206 result[
xyz][global_aux](r, c) +=
1207 result_aux(aux_c, col_c, row_c);
1209 if (atom_col == target_atom) {
1210 result[
xyz][global_aux](r, c) +=
1211 result_col(aux_c, col_c, row_c);
1213 if (atom_row == target_atom) {
1214 result[
xyz][global_aux](r, c) +=
1215 result_row(aux_c, col_c, row_c);
1227 eptr_3c = std::current_exception();
1233 std::rethrow_exception(eptr_3c);
1235 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
1236 dftbasis.getNumofShells() > 0) {
1237 throw std::runtime_error(
1238 "ComputeThreeCenterDerivativesForAtom: engine.results() returned "
1239 "a null buffer for EVERY shell triple touching this atom -- this "
1240 "libint2 build does not actually support this operator's "
1241 "derivative integrals at runtime, even though it may report "
1242 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1243 "libint2 with this operator's derivative support enabled "
1244 "(--enable-eri3=1) to use this feature.");
1252 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativesForAtom",
1257#if (LIBINT_INCLUDE_ERI3 >= 1)
1293 const AOBasis& auxbasis,
const AOBasis& dftbasis,
1294 const Eigen::MatrixXd& occ_mo_coeffs) {
1295 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
1296 Index nocc = occ_mo_coeffs.cols();
1299 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
1300 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
1301 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
1302 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
1304 std::vector<Index> dftshell2atom;
1305 dftshell2atom.reserve(dftbasis.getNumofShells());
1306 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
1307 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
1309 std::vector<Index> auxshell2atom;
1310 auxshell2atom.reserve(auxbasis.getNumofShells());
1311 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
1312 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
1315 Index n_aux_bf = auxbasis.AOBasisSize();
1321 std::vector<ThreeCenterDerivative> result(natoms);
1322 for (
Index a = 0; a < natoms; ++a) {
1324 result[a][
xyz] = std::vector<Eigen::MatrixXd>(
1325 n_aux_bf, Eigen::MatrixXd::Zero(nocc, nocc));
1329 std::vector<libint2::Engine> engines(nthreads);
1330 engines[0] = libint2::Engine(
1331 libint2::Operator::coulomb,
1332 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
1333 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
1334 engines[0].set(libint2::BraKet::xs_xx);
1335 for (
Index i = 1; i < nthreads; ++i) {
1336 engines[i] = engines[0];
1345 std::exception_ptr eptr_3c =
nullptr;
1346 std::atomic<bool> any_nonnull_buffer_3c{
false};
1347#pragma omp parallel for schedule(dynamic)
1348 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
1351 const libint2::Engine::target_ptr_vec& buf = engine.results();
1353 const libint2::Shell& auxshell = auxshells[aux];
1354 Index aux_start = auxshell2bf[aux];
1355 Index atom_aux = auxshell2atom[aux];
1357 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
1358 const libint2::Shell& shell_row = dftshells[row];
1359 Index row_start = shell2bf[row];
1360 Index atom_row = dftshell2atom[row];
1362 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
1363 const libint2::Shell& shell_col = dftshells[col];
1364 Index col_start = shell2bf[col];
1365 Index atom_col = dftshell2atom[col];
1368 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
1369 auxshell, libint2::Shell::unit(), shell_col, shell_row);
1371 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
1374 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
1379 Index nrow =
static_cast<Index>(shell_row.size());
1380 Index ncol =
static_cast<Index>(shell_col.size());
1381 Eigen::MatrixXd mo_row_block =
1382 occ_mo_coeffs.middleRows(row_start, nrow);
1383 Eigen::MatrixXd mo_col_block =
1384 occ_mo_coeffs.middleRows(col_start, ncol);
1388 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1389 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
1392 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1393 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
1396 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1397 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
1400 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
1401 Index global_aux = aux_start +
static_cast<Index>(aux_c);
1417 Eigen::MatrixXd block_aux(nrow, ncol);
1418 Eigen::MatrixXd block_col(nrow, ncol);
1419 Eigen::MatrixXd block_row(nrow, ncol);
1420 for (
Index col_c = 0; col_c < ncol; ++col_c) {
1421 for (
Index row_c = 0; row_c < nrow; ++row_c) {
1422 block_aux(row_c, col_c) =
1423 result_aux(aux_c,
static_cast<size_t>(col_c),
1424 static_cast<size_t>(row_c));
1425 block_col(row_c, col_c) =
1426 result_col(aux_c,
static_cast<size_t>(col_c),
1427 static_cast<size_t>(row_c));
1428 block_row(row_c, col_c) =
1429 result_row(aux_c,
static_cast<size_t>(col_c),
1430 static_cast<size_t>(row_c));
1433 result[atom_aux][
xyz][global_aux].noalias() +=
1434 mo_row_block.transpose() * block_aux * mo_col_block;
1435 result[atom_col][
xyz][global_aux].noalias() +=
1436 mo_row_block.transpose() * block_col * mo_col_block;
1437 result[atom_row][
xyz][global_aux].noalias() +=
1438 mo_row_block.transpose() * block_row * mo_col_block;
1447 eptr_3c = std::current_exception();
1453 std::rethrow_exception(eptr_3c);
1455 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
1456 dftbasis.getNumofShells() > 0) {
1457 throw std::runtime_error(
1458 "ComputeThreeCenterDerivativesMOTransformed: engine.results() "
1459 "returned a null buffer for EVERY shell triple -- this libint2 "
1460 "build does not actually support this operator's derivative "
1461 "integrals at runtime, even though it may report "
1462 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1463 "libint2 with this operator's derivative support enabled "
1464 "(--enable-eri3=1) to use this feature.");
1471 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativesMOTransformed",
1493 std::vector<Eigen::MatrixXd> tensor(
1497 libint2::Engine engine(
1498 libint2::Operator::coulomb,
1500 static_cast<int>(std::max(dftbasis.
getMaxL(), auxbasis.
getMaxL())), 0);
1501 engine.set(libint2::BraKet::xs_xx);
1504 std::vector<Eigen::MatrixXd> block =
1506 Index aux_start = auxshell2bf[aux];
1507 for (
size_t i = 0; i < block.size(); ++i) {
1508 tensor[aux_start +
static_cast<Index>(i)] = block[i];
1560#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
1561 (LIBINT_INCLUDE_ONEBODY >= 1)
1563 const AOBasis& aobasis,
const QMMolecule& mol) {
1564 Index natoms = mol.size();
1566 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
1567 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
1569 std::vector<Index> shell2atom;
1570 shell2atom.reserve(aobasis.getNumofShells());
1571 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
1572 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
1575 Index nbf = aobasis.AOBasisSize();
1576 std::vector<std::vector<AOMatrixDerivative>> result_thread(nthreads);
1577 for (
Index t = 0; t < nthreads; ++t) {
1578 result_thread[t].resize(natoms);
1579 for (
Index a = 0; a < natoms; ++a) {
1580 for (
Index xyz = 0; xyz < 3; ++xyz) {
1581 result_thread[t][a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
1586 std::vector<libint2::Engine> engines(nthreads);
1587 for (
Index i = 0; i < nthreads; ++i) {
1589 libint2::Engine(libint2::Operator::nuclear, aobasis.getMaxNprim(),
1590 static_cast<int>(aobasis.getMaxL()), 1);
1599 std::exception_ptr eptr_nucattr =
nullptr;
1600 std::atomic<bool> any_nonnull_buffer_nucattr{
false};
1601#pragma omp parallel for schedule(dynamic)
1602 for (
Index A = 0; A < natoms; ++A) {
1605 libint2::Engine& engine = engines[thread_id];
1607 std::vector<libint2::Atom> single_atom(1);
1608 single_atom[0].atomic_number =
static_cast<int>(mol[A].getNuccharge());
1609 single_atom[0].x = mol[A].getPos().x();
1610 single_atom[0].y = mol[A].getPos().y();
1611 single_atom[0].z = mol[A].getPos().z();
1612 engine.set_params(libint2::make_point_charges(single_atom));
1614 const libint2::Engine::target_ptr_vec& buf = engine.results();
1616 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
1617 Index bf1 = shell2bf[s1];
1618 Index n1 = shells[s1].size();
1619 Index atom1 = shell2atom[s1];
1621 for (
Index s2 = 0; s2 <= s1; ++s2) {
1622 engine.compute(shells[s1], shells[s2]);
1636 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
1639 any_nonnull_buffer_nucattr.store(
true, std::memory_order_relaxed);
1641 Index bf2 = shell2bf[s2];
1642 Index n2 = shells[s2].size();
1643 Index atom2 = shell2atom[s2];
1654 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
1655 result_thread[thread_id][atom1][
xyz].block(bf1, bf2, n1, n2) +=
1658 result_thread[thread_id][atom1][
xyz].block(bf2, bf1, n2, n1) +=
1659 buf_mat1.transpose();
1662 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
1663 result_thread[thread_id][atom2][
xyz].block(bf1, bf2, n1, n2) +=
1666 result_thread[thread_id][atom2][
xyz].block(bf2, bf1, n2, n1) +=
1667 buf_mat2.transpose();
1670 Eigen::Map<const MatrixLibInt> buf_mat3(buf[6 + xyz], n1, n2);
1671 result_thread[thread_id][A][
xyz].block(bf1, bf2, n1, n2) +=
1674 result_thread[thread_id][A][
xyz].block(bf2, bf1, n2, n1) +=
1675 buf_mat3.transpose();
1683 if (!eptr_nucattr) {
1684 eptr_nucattr = std::current_exception();
1690 std::rethrow_exception(eptr_nucattr);
1692 if (!any_nonnull_buffer_nucattr.load() && natoms > 0 &&
1693 aobasis.getNumofShells() > 0) {
1710 throw std::runtime_error(
1711 "ComputeNuclearAttractionDerivatives: engine.results() returned "
1712 "a null buffer for EVERY shell pair and point charge -- this "
1713 "libint2 build does not actually support nuclear-attraction "
1714 "derivative integrals at runtime, even though it may report "
1715 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1716 "libint2 with this operator's derivative support enabled "
1717 "(--enable-1body=1, which nuclear attraction is part of) to "
1718 "use this feature.");
1731 double total_norm_sq_nucattr = 0.0;
1732 for (
Index a = 0; a < natoms; ++a) {
1734 for (
Index t = 0; t < nthreads; ++t) {
1735 total_norm_sq_nucattr += result_thread[t][a][
xyz].squaredNorm();
1739 if (total_norm_sq_nucattr < 1.e-20 && natoms > 0 &&
1740 aobasis.getNumofShells() > 0) {
1741 throw std::runtime_error(
1742 "ComputeNuclearAttractionDerivatives: the assembled result is "
1743 "exactly zero everywhere, which is physically impossible for a "
1744 "real molecule -- this libint2 build likely returns valid but "
1745 "zero-filled buffers for this operator (rather than either "
1746 "computing it correctly or returning null, which the separate, "
1747 "earlier check in this function already handles). Rebuild "
1748 "libint2 with this operator's derivative support enabled "
1749 "(--enable-1body=1) to use this feature.");
1752 std::vector<AOMatrixDerivative> result(natoms);
1753 for (
Index a = 0; a < natoms; ++a) {
1755 result[a][
xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
1756 for (
Index t = 0; t < nthreads; ++t) {
1757 result[a][
xyz] += result_thread[t][a][
xyz];
1766 ThrowNoDerivativeSupport(
"ComputeNuclearAttractionDerivatives",
1767 "--enable-1body=1");
1789#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
1790 (LIBINT_INCLUDE_ONEBODY >= 1) && (LIBINT_INCLUDE_ERI2 >= 1) && \
1791 (LIBINT_INCLUDE_ERI3 >= 1)
Container to hold Basisfunctions for all atoms.
Index AOBasisSize() const
std::vector< Index > getMapToBasisFunctions() const
Index getNumofShells() const
Index getMaxNprim() const
std::vector< libint2::Shell > GenerateLibintBasis() const
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MatrixLibInt
std::vector< AOMatrixDerivative > ComputeNuclearAttractionDerivatives(const AOBasis &aobasis, const QMMolecule &mol)
std::vector< AOMatrixDerivative > ComputeKineticDerivatives(const AOBasis &aobasis)
std::vector< AOMatrixDerivative > ComputeCoulombMetricDerivatives(const AOBasis &aobasis)
std::vector< AOMatrixDerivative > ComputeOverlapDerivatives(const AOBasis &aobasis)
std::vector< ThreeCenterDerivative > ComputeThreeCenterDerivatives(const AOBasis &auxbasis, const AOBasis &dftbasis)
std::vector< ThreeCenterDerivative > ComputeThreeCenterDerivativesMOTransformed(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &occ_mo_coeffs)
std::vector< Eigen::MatrixXd > ComputeThreeCenterIntegrals(const AOBasis &auxbasis, const AOBasis &dftbasis)
std::vector< Eigen::MatrixXd > ComputeAO3cBlock(const libint2::Shell &auxshell, const AOBasis &dftbasis, libint2::Engine &engine)
std::vector< Eigen::MatrixXd > ComputeThreeCenterDerivativeContraction(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &density)
std::array< std::vector< Eigen::MatrixXd >, 3 > ThreeCenterDerivative
std::array< Eigen::MatrixXd, 3 > AOMatrixDerivative
ThreeCenterDerivative ComputeThreeCenterDerivativesForAtom(const AOBasis &auxbasis, const AOBasis &dftbasis, Index target_atom)
bool HasLibint2DerivativeSupport()
Provides a means for comparing floating point numbers.