133#define LIBINT2_CONSTEXPR_STATICS 0
134#if defined(__clang__)
135#pragma clang diagnostic push
136#pragma clang diagnostic ignored "-W#warnings"
137#elif defined(__GNUC__)
138#pragma GCC diagnostic push
139#pragma GCC diagnostic ignored "-Warray-bounds"
140#pragma GCC diagnostic ignored "-Wcpp"
142#include <libint2.hpp>
151#if defined(__clang__)
152#pragma clang diagnostic pop
153#elif defined(__GNUC__)
154#pragma GCC diagnostic pop
163std::vector<Eigen::MatrixXd>
ComputeAO3cBlock(
const libint2::Shell& auxshell,
164 const AOBasis& dftbasis,
165 libint2::Engine& engine);
189 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
212[[noreturn, maybe_unused]]
void ThrowNoDerivativeSupport(
213 const char* function_name,
const char* configure_flag) {
214 throw std::runtime_error(
215 std::string(function_name) +
216 ": this libint2 build was compiled without derivative integral "
217 "support for this specific operator category -- analytic nuclear "
218 "forces using this function are unavailable. Rebuild libint2 "
219 "with this configured (" +
221 " at libint2 configure time) to use this feature. Many "
222 "pre-packaged libint2 builds (Homebrew, Ubuntu apt, etc.) do not "
223 "enable this by default; note in particular that different "
224 "operator categories (one-body, the two-center Coulomb metric, "
225 "three-center RI) each have their own, independent flag -- "
226 "enabling one does not enable the others.");
302#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
303 (LIBINT_INCLUDE_ONEBODY >= 1)
304template <lib
int2::Operator obtype>
305std::vector<AOMatrixDerivative> computeOneBodyIntegralDerivatives(
306 const AOBasis& aobasis) {
309 libint2::operator_traits<obtype>::nopers == 1,
310 "computeOneBodyIntegralDerivatives only supports single-operator "
311 "types (overlap, kinetic) in this first pass; multipole-type "
312 "operators with multiple result matrices are not yet handled here.");
317 Index natoms =
static_cast<Index>(aobasis.getFuncPerAtom().size());
319 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
320 std::vector<std::vector<Index>> shellpair_list = aobasis.ComputeShellPairs();
321 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
325 std::vector<Index> shell2atom;
326 shell2atom.reserve(shells.size());
327 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
330 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
333 Index nbf = aobasis.AOBasisSize();
334 std::vector<AOMatrixDerivative> result(natoms);
335 for (
Index a = 0; a < natoms; ++a) {
336 for (
Index xyz = 0; xyz < 3; ++xyz) {
337 result[a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
341 std::vector<libint2::Engine> engines(nthreads);
344 engines[0] = libint2::Engine(obtype, aobasis.getMaxNprim(),
345 static_cast<int>(aobasis.getMaxL()), 1);
346 for (
Index i = 1; i < nthreads; ++i) {
347 engines[i] = engines[0];
350 std::exception_ptr eptr =
nullptr;
351 std::atomic<bool> any_nonnull_buffer{
false};
352#pragma omp parallel for schedule(dynamic)
353 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
356 libint2::Engine& engine = engines[thread_id];
357 const libint2::Engine::target_ptr_vec& buf = engine.results();
359 Index bf1 = shell2bf[s1];
360 Index n1 = shells[s1].size();
361 Index atom1 = shell2atom[s1];
363 for (
Index s2 : shellpair_list[s1]) {
365 engine.compute(shells[s1], shells[s2]);
379 if (buf[0] ==
nullptr || buf[3] ==
nullptr) {
385 any_nonnull_buffer.store(
true, std::memory_order_relaxed);
394 Index bf2 = shell2bf[s2];
395 Index n2 = shells[s2].size();
396 Index atom2 = shell2atom[s2];
404 for (
Index xyz = 0; xyz < 3; ++xyz) {
405 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
406 result[atom1][xyz].block(bf1, bf2, n1, n2) += buf_mat1;
408 result[atom1][xyz].block(bf2, bf1, n2, n1) += buf_mat1.transpose();
411 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
412 result[atom2][xyz].block(bf1, bf2, n1, n2) += buf_mat2;
414 result[atom2][xyz].block(bf2, bf1, n2, n1) += buf_mat2.transpose();
429 eptr = std::current_exception();
435 std::rethrow_exception(eptr);
437 if (!any_nonnull_buffer.load() && aobasis.getNumofShells() > 0) {
445 throw std::runtime_error(
446 "computeOneBodyIntegralDerivatives: engine.results() returned a "
447 "null buffer for EVERY shell pair -- this libint2 build does not "
448 "actually support this operator's derivative integrals at "
449 "runtime, even though it may report LIBINT2_MAX_DERIV_ORDER >= 1 "
450 "for other operators. Rebuild libint2 with this operator's "
451 "derivative support enabled (--enable-1body=1) to use this "
462 const AOBasis& aobasis) {
463 return computeOneBodyIntegralDerivatives<libint2::Operator::overlap>(aobasis);
467 const AOBasis& aobasis) {
468 return computeOneBodyIntegralDerivatives<libint2::Operator::kinetic>(aobasis);
479 ThrowNoDerivativeSupport(
"ComputeOverlapDerivatives",
"--enable-1body=1");
482 ThrowNoDerivativeSupport(
"ComputeKineticDerivatives",
"--enable-1body=1");
537#if (LIBINT_INCLUDE_ERI2 >= 1)
539 const AOBasis& aobasis) {
540 Index natoms =
static_cast<Index>(aobasis.getFuncPerAtom().size());
542 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
543 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
545 std::vector<Index> shell2atom;
546 shell2atom.reserve(aobasis.getNumofShells());
547 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
548 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
551 Index nbf = aobasis.AOBasisSize();
552 std::vector<AOMatrixDerivative> result(natoms);
553 for (
Index a = 0; a < natoms; ++a) {
554 for (
Index xyz = 0; xyz < 3; ++xyz) {
555 result[a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
559 std::vector<libint2::Engine> engines(nthreads);
561 libint2::Engine(libint2::Operator::coulomb, aobasis.getMaxNprim(),
562 static_cast<int>(aobasis.getMaxL()), 1);
563 engines[0].set(libint2::BraKet::xs_xs);
564 for (
Index i = 1; i < nthreads; ++i) {
565 engines[i] = engines[0];
568 std::exception_ptr eptr_coulmetric =
nullptr;
569 std::atomic<bool> any_nonnull_buffer_coulmetric{
false};
570#pragma omp parallel for schedule(dynamic)
571 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
574 const libint2::Engine::target_ptr_vec& buf = engine.results();
576 Index bf1 = shell2bf[s1];
577 Index n1 = shells[s1].size();
578 Index atom1 = shell2atom[s1];
583 for (
Index s2 = 0; s2 <= s1; ++s2) {
584 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xs, 1>(
585 shells[s1], libint2::Shell::unit(), shells[s2],
586 libint2::Shell::unit());
592 if (buf[0] ==
nullptr || buf[3] ==
nullptr) {
595 any_nonnull_buffer_coulmetric.store(
true, std::memory_order_relaxed);
597 Index bf2 = shell2bf[s2];
598 Index n2 = shells[s2].size();
599 Index atom2 = shell2atom[s2];
602 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
603 result[atom1][
xyz].block(bf1, bf2, n1, n2) += buf_mat1;
605 result[atom1][
xyz].block(bf2, bf1, n2, n1) += buf_mat1.transpose();
608 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
609 result[atom2][
xyz].block(bf1, bf2, n1, n2) += buf_mat2;
611 result[atom2][
xyz].block(bf2, bf1, n2, n1) += buf_mat2.transpose();
618 if (!eptr_coulmetric) {
619 eptr_coulmetric = std::current_exception();
624 if (eptr_coulmetric) {
625 std::rethrow_exception(eptr_coulmetric);
627 if (!any_nonnull_buffer_coulmetric.load() && aobasis.getNumofShells() > 0) {
630 throw std::runtime_error(
631 "ComputeCoulombMetricDerivatives: engine.results() returned a "
632 "null buffer for EVERY shell pair -- this libint2 build does not "
633 "actually support this operator's derivative integrals at "
634 "runtime, even though it may report LIBINT2_MAX_DERIV_ORDER >= 1 "
635 "for other operators. Rebuild libint2 with this operator's "
636 "derivative support enabled (--enable-eri2=1) to use this "
644 ThrowNoDerivativeSupport(
"ComputeCoulombMetricDerivatives",
705#if (LIBINT_INCLUDE_ERI3 >= 1)
707 const AOBasis& auxbasis,
const AOBasis& dftbasis) {
708 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
715 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
716 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
717 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
718 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
720 std::vector<Index> dftshell2atom;
721 dftshell2atom.reserve(dftbasis.getNumofShells());
722 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
723 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
725 std::vector<Index> auxshell2atom;
726 auxshell2atom.reserve(auxbasis.getNumofShells());
727 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
728 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
731 Index n_dft_bf = dftbasis.AOBasisSize();
732 Index n_aux_bf = auxbasis.AOBasisSize();
734 std::vector<ThreeCenterDerivative> result(natoms);
735 for (
Index a = 0; a < natoms; ++a) {
737 result[a][
xyz] = std::vector<Eigen::MatrixXd>(
738 n_aux_bf, Eigen::MatrixXd::Zero(n_dft_bf, n_dft_bf));
742 std::vector<libint2::Engine> engines(nthreads);
743 engines[0] = libint2::Engine(
744 libint2::Operator::coulomb,
745 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
746 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
747 engines[0].set(libint2::BraKet::xs_xx);
748 for (
Index i = 1; i < nthreads; ++i) {
749 engines[i] = engines[0];
752 std::exception_ptr eptr_3c =
nullptr;
753 std::atomic<bool> any_nonnull_buffer_3c{
false};
754#pragma omp parallel for schedule(dynamic)
755 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
758 const libint2::Engine::target_ptr_vec& buf = engine.results();
760 const libint2::Shell& auxshell = auxshells[aux];
761 Index aux_start = auxshell2bf[aux];
762 Index atom_aux = auxshell2atom[aux];
764 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
765 const libint2::Shell& shell_row = dftshells[row];
766 Index row_start = shell2bf[row];
767 Index atom_row = dftshell2atom[row];
779 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
780 const libint2::Shell& shell_col = dftshells[col];
781 Index col_start = shell2bf[col];
782 Index atom_col = dftshell2atom[col];
785 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
786 auxshell, libint2::Shell::unit(), shell_col, shell_row);
792 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
795 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
806 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
807 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
810 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
811 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
814 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
815 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
818 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
819 Index global_aux = aux_start +
static_cast<Index>(aux_c);
820 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
821 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
822 double val_aux = result_aux(aux_c, col_c, row_c);
823 double val_col = result_col(aux_c, col_c, row_c);
824 double val_row = result_row(aux_c, col_c, row_c);
825 Index r = row_start +
static_cast<Index>(row_c);
826 Index c = col_start +
static_cast<Index>(col_c);
827 result[atom_aux][
xyz][global_aux](r, c) += val_aux;
828 result[atom_col][
xyz][global_aux](r, c) += val_col;
829 result[atom_row][
xyz][global_aux](r, c) += val_row;
840 eptr_3c = std::current_exception();
846 std::rethrow_exception(eptr_3c);
848 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
849 dftbasis.getNumofShells() > 0) {
852 throw std::runtime_error(
853 "ComputeThreeCenterDerivatives: engine.results() returned a null "
854 "buffer for EVERY shell triple -- this libint2 build does not "
855 "actually support this operator's derivative integrals at "
856 "runtime, even though it may report LIBINT2_MAX_DERIV_ORDER >= 1 "
857 "for other operators. Rebuild libint2 with this operator's "
858 "derivative support enabled (--enable-eri3=1) to use this "
866 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivatives",
"--enable-eri3=1");
870#if (LIBINT_INCLUDE_ERI3 >= 1)
910 const AOBasis& auxbasis,
const AOBasis& dftbasis,
911 const Eigen::MatrixXd& density) {
912 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
915 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
916 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
917 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
918 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
920 std::vector<Index> dftshell2atom;
921 dftshell2atom.reserve(dftbasis.getNumofShells());
922 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
923 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
925 std::vector<Index> auxshell2atom;
926 auxshell2atom.reserve(auxbasis.getNumofShells());
927 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
928 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
931 Index n_aux_bf = auxbasis.AOBasisSize();
937 std::vector<Eigen::MatrixXd> result(natoms,
938 Eigen::MatrixXd::Zero(3, n_aux_bf));
940 std::vector<libint2::Engine> engines(nthreads);
941 engines[0] = libint2::Engine(
942 libint2::Operator::coulomb,
943 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
944 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
945 engines[0].set(libint2::BraKet::xs_xx);
946 for (
Index i = 1; i < nthreads; ++i) {
947 engines[i] = engines[0];
959 std::exception_ptr eptr_3c =
nullptr;
960 std::atomic<bool> any_nonnull_buffer_3c{
false};
961#pragma omp parallel for schedule(dynamic)
962 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
965 const libint2::Engine::target_ptr_vec& buf = engine.results();
967 const libint2::Shell& auxshell = auxshells[aux];
968 Index aux_start = auxshell2bf[aux];
969 Index atom_aux = auxshell2atom[aux];
971 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
972 const libint2::Shell& shell_row = dftshells[row];
973 Index row_start = shell2bf[row];
974 Index atom_row = dftshell2atom[row];
976 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
977 const libint2::Shell& shell_col = dftshells[col];
978 Index col_start = shell2bf[col];
979 Index atom_col = dftshell2atom[col];
982 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
983 auxshell, libint2::Shell::unit(), shell_col, shell_row);
985 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
988 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
992 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
993 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
996 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
997 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
1000 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1001 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
1004 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
1005 Index global_aux = aux_start +
static_cast<Index>(aux_c);
1006 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
1007 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
1008 double val_aux = result_aux(aux_c, col_c, row_c);
1009 double val_col = result_col(aux_c, col_c, row_c);
1010 double val_row = result_row(aux_c, col_c, row_c);
1011 Index r = row_start +
static_cast<Index>(row_c);
1012 Index c = col_start +
static_cast<Index>(col_c);
1019 double d_rc = density(r, c);
1020 result[atom_aux](
xyz, global_aux) += d_rc * val_aux;
1021 result[atom_col](
xyz, global_aux) += d_rc * val_col;
1022 result[atom_row](
xyz, global_aux) += d_rc * val_row;
1033 eptr_3c = std::current_exception();
1039 std::rethrow_exception(eptr_3c);
1041 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
1042 dftbasis.getNumofShells() > 0) {
1043 throw std::runtime_error(
1044 "ComputeThreeCenterDerivativeContraction: engine.results() "
1045 "returned a null buffer for EVERY shell triple -- this libint2 "
1046 "build does not actually support this operator's derivative "
1047 "integrals at runtime, even though it may report "
1048 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1049 "libint2 with this operator's derivative support enabled "
1050 "(--enable-eri3=1) to use this feature.");
1057 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativeContraction",
1062#if (LIBINT_INCLUDE_ERI3 >= 1)
1099 const AOBasis& auxbasis,
const AOBasis& dftbasis,
Index target_atom) {
1100 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
1101 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
1102 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
1103 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
1105 std::vector<Index> dftshell2atom;
1106 dftshell2atom.reserve(dftbasis.getNumofShells());
1107 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
1108 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
1110 std::vector<Index> auxshell2atom;
1111 auxshell2atom.reserve(auxbasis.getNumofShells());
1112 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
1113 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
1116 Index n_dft_bf = dftbasis.AOBasisSize();
1117 Index n_aux_bf = auxbasis.AOBasisSize();
1125 result[
xyz] = std::vector<Eigen::MatrixXd>(
1126 n_aux_bf, Eigen::MatrixXd::Zero(n_dft_bf, n_dft_bf));
1129 std::vector<libint2::Engine> engines(nthreads);
1130 engines[0] = libint2::Engine(
1131 libint2::Operator::coulomb,
1132 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
1133 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
1134 engines[0].set(libint2::BraKet::xs_xx);
1135 for (
Index i = 1; i < nthreads; ++i) {
1136 engines[i] = engines[0];
1139 std::exception_ptr eptr_3c =
nullptr;
1140 std::atomic<bool> any_nonnull_buffer_3c{
false};
1141#pragma omp parallel for schedule(dynamic)
1142 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
1145 const libint2::Engine::target_ptr_vec& buf = engine.results();
1147 const libint2::Shell& auxshell = auxshells[aux];
1148 Index aux_start = auxshell2bf[aux];
1149 Index atom_aux = auxshell2atom[aux];
1151 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
1152 const libint2::Shell& shell_row = dftshells[row];
1153 Index row_start = shell2bf[row];
1154 Index atom_row = dftshell2atom[row];
1156 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
1157 const libint2::Shell& shell_col = dftshells[col];
1158 Index col_start = shell2bf[col];
1159 Index atom_col = dftshell2atom[col];
1166 if (atom_aux != target_atom && atom_col != target_atom &&
1167 atom_row != target_atom) {
1172 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
1173 auxshell, libint2::Shell::unit(), shell_col, shell_row);
1175 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
1178 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
1182 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1183 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
1186 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1187 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
1190 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1191 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
1194 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
1195 Index global_aux = aux_start +
static_cast<Index>(aux_c);
1196 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
1197 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
1198 Index r = row_start +
static_cast<Index>(row_c);
1199 Index c = col_start +
static_cast<Index>(col_c);
1206 if (atom_aux == target_atom) {
1207 result[
xyz][global_aux](r, c) +=
1208 result_aux(aux_c, col_c, row_c);
1210 if (atom_col == target_atom) {
1211 result[
xyz][global_aux](r, c) +=
1212 result_col(aux_c, col_c, row_c);
1214 if (atom_row == target_atom) {
1215 result[
xyz][global_aux](r, c) +=
1216 result_row(aux_c, col_c, row_c);
1228 eptr_3c = std::current_exception();
1234 std::rethrow_exception(eptr_3c);
1236 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
1237 dftbasis.getNumofShells() > 0) {
1238 throw std::runtime_error(
1239 "ComputeThreeCenterDerivativesForAtom: engine.results() returned "
1240 "a null buffer for EVERY shell triple touching this atom -- this "
1241 "libint2 build does not actually support this operator's "
1242 "derivative integrals at runtime, even though it may report "
1243 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1244 "libint2 with this operator's derivative support enabled "
1245 "(--enable-eri3=1) to use this feature.");
1253 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativesForAtom",
1258#if (LIBINT_INCLUDE_ERI3 >= 1)
1294 const AOBasis& auxbasis,
const AOBasis& dftbasis,
1295 const Eigen::MatrixXd& occ_mo_coeffs) {
1296 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
1297 Index nocc = occ_mo_coeffs.cols();
1300 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
1301 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
1302 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
1303 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
1305 std::vector<Index> dftshell2atom;
1306 dftshell2atom.reserve(dftbasis.getNumofShells());
1307 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
1308 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
1310 std::vector<Index> auxshell2atom;
1311 auxshell2atom.reserve(auxbasis.getNumofShells());
1312 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
1313 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
1316 Index n_aux_bf = auxbasis.AOBasisSize();
1322 std::vector<ThreeCenterDerivative> result(natoms);
1323 for (
Index a = 0; a < natoms; ++a) {
1325 result[a][
xyz] = std::vector<Eigen::MatrixXd>(
1326 n_aux_bf, Eigen::MatrixXd::Zero(nocc, nocc));
1330 std::vector<libint2::Engine> engines(nthreads);
1331 engines[0] = libint2::Engine(
1332 libint2::Operator::coulomb,
1333 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
1334 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
1335 engines[0].set(libint2::BraKet::xs_xx);
1336 for (
Index i = 1; i < nthreads; ++i) {
1337 engines[i] = engines[0];
1346 std::exception_ptr eptr_3c =
nullptr;
1347 std::atomic<bool> any_nonnull_buffer_3c{
false};
1348#pragma omp parallel for schedule(dynamic)
1349 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
1352 const libint2::Engine::target_ptr_vec& buf = engine.results();
1354 const libint2::Shell& auxshell = auxshells[aux];
1355 Index aux_start = auxshell2bf[aux];
1356 Index atom_aux = auxshell2atom[aux];
1358 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
1359 const libint2::Shell& shell_row = dftshells[row];
1360 Index row_start = shell2bf[row];
1361 Index atom_row = dftshell2atom[row];
1363 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
1364 const libint2::Shell& shell_col = dftshells[col];
1365 Index col_start = shell2bf[col];
1366 Index atom_col = dftshell2atom[col];
1369 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
1370 auxshell, libint2::Shell::unit(), shell_col, shell_row);
1372 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
1375 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
1380 Index nrow =
static_cast<Index>(shell_row.size());
1381 Index ncol =
static_cast<Index>(shell_col.size());
1382 Eigen::MatrixXd mo_row_block =
1383 occ_mo_coeffs.middleRows(row_start, nrow);
1384 Eigen::MatrixXd mo_col_block =
1385 occ_mo_coeffs.middleRows(col_start, ncol);
1389 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1390 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
1393 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1394 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
1397 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
1398 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
1401 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
1402 Index global_aux = aux_start +
static_cast<Index>(aux_c);
1418 Eigen::MatrixXd block_aux(nrow, ncol);
1419 Eigen::MatrixXd block_col(nrow, ncol);
1420 Eigen::MatrixXd block_row(nrow, ncol);
1421 for (
Index col_c = 0; col_c < ncol; ++col_c) {
1422 for (
Index row_c = 0; row_c < nrow; ++row_c) {
1423 block_aux(row_c, col_c) =
1424 result_aux(aux_c,
static_cast<size_t>(col_c),
1425 static_cast<size_t>(row_c));
1426 block_col(row_c, col_c) =
1427 result_col(aux_c,
static_cast<size_t>(col_c),
1428 static_cast<size_t>(row_c));
1429 block_row(row_c, col_c) =
1430 result_row(aux_c,
static_cast<size_t>(col_c),
1431 static_cast<size_t>(row_c));
1434 result[atom_aux][
xyz][global_aux].noalias() +=
1435 mo_row_block.transpose() * block_aux * mo_col_block;
1436 result[atom_col][
xyz][global_aux].noalias() +=
1437 mo_row_block.transpose() * block_col * mo_col_block;
1438 result[atom_row][
xyz][global_aux].noalias() +=
1439 mo_row_block.transpose() * block_row * mo_col_block;
1448 eptr_3c = std::current_exception();
1454 std::rethrow_exception(eptr_3c);
1456 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
1457 dftbasis.getNumofShells() > 0) {
1458 throw std::runtime_error(
1459 "ComputeThreeCenterDerivativesMOTransformed: engine.results() "
1460 "returned a null buffer for EVERY shell triple -- this libint2 "
1461 "build does not actually support this operator's derivative "
1462 "integrals at runtime, even though it may report "
1463 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1464 "libint2 with this operator's derivative support enabled "
1465 "(--enable-eri3=1) to use this feature.");
1472 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativesMOTransformed",
1494 std::vector<Eigen::MatrixXd> tensor(
1498 libint2::Engine engine(
1499 libint2::Operator::coulomb,
1501 static_cast<int>(std::max(dftbasis.
getMaxL(), auxbasis.
getMaxL())), 0);
1502 engine.set(libint2::BraKet::xs_xx);
1505 std::vector<Eigen::MatrixXd> block =
1507 Index aux_start = auxshell2bf[aux];
1508 for (
size_t i = 0; i < block.size(); ++i) {
1509 tensor[aux_start +
static_cast<Index>(i)] = block[i];
1561#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
1562 (LIBINT_INCLUDE_ONEBODY >= 1)
1564 const AOBasis& aobasis,
const QMMolecule& mol) {
1565 Index natoms = mol.size();
1567 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
1568 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
1570 std::vector<Index> shell2atom;
1571 shell2atom.reserve(aobasis.getNumofShells());
1572 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
1573 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
1576 Index nbf = aobasis.AOBasisSize();
1577 std::vector<std::vector<AOMatrixDerivative>> result_thread(nthreads);
1578 for (
Index t = 0; t < nthreads; ++t) {
1579 result_thread[t].resize(natoms);
1580 for (
Index a = 0; a < natoms; ++a) {
1581 for (
Index xyz = 0; xyz < 3; ++xyz) {
1582 result_thread[t][a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
1587 std::vector<libint2::Engine> engines(nthreads);
1588 for (
Index i = 0; i < nthreads; ++i) {
1590 libint2::Engine(libint2::Operator::nuclear, aobasis.getMaxNprim(),
1591 static_cast<int>(aobasis.getMaxL()), 1);
1600 std::exception_ptr eptr_nucattr =
nullptr;
1601 std::atomic<bool> any_nonnull_buffer_nucattr{
false};
1602#pragma omp parallel for schedule(dynamic)
1603 for (
Index A = 0; A < natoms; ++A) {
1606 libint2::Engine& engine = engines[thread_id];
1608 std::vector<libint2::Atom> single_atom(1);
1609 single_atom[0].atomic_number =
static_cast<int>(mol[A].getNuccharge());
1610 single_atom[0].x = mol[A].getPos().x();
1611 single_atom[0].y = mol[A].getPos().y();
1612 single_atom[0].z = mol[A].getPos().z();
1613 engine.set_params(libint2::make_point_charges(single_atom));
1615 const libint2::Engine::target_ptr_vec& buf = engine.results();
1617 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
1618 Index bf1 = shell2bf[s1];
1619 Index n1 = shells[s1].size();
1620 Index atom1 = shell2atom[s1];
1622 for (
Index s2 = 0; s2 <= s1; ++s2) {
1623 engine.compute(shells[s1], shells[s2]);
1637 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
1640 any_nonnull_buffer_nucattr.store(
true, std::memory_order_relaxed);
1642 Index bf2 = shell2bf[s2];
1643 Index n2 = shells[s2].size();
1644 Index atom2 = shell2atom[s2];
1655 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
1656 result_thread[thread_id][atom1][
xyz].block(bf1, bf2, n1, n2) +=
1659 result_thread[thread_id][atom1][
xyz].block(bf2, bf1, n2, n1) +=
1660 buf_mat1.transpose();
1663 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
1664 result_thread[thread_id][atom2][
xyz].block(bf1, bf2, n1, n2) +=
1667 result_thread[thread_id][atom2][
xyz].block(bf2, bf1, n2, n1) +=
1668 buf_mat2.transpose();
1671 Eigen::Map<const MatrixLibInt> buf_mat3(buf[6 + xyz], n1, n2);
1672 result_thread[thread_id][A][
xyz].block(bf1, bf2, n1, n2) +=
1675 result_thread[thread_id][A][
xyz].block(bf2, bf1, n2, n1) +=
1676 buf_mat3.transpose();
1684 if (!eptr_nucattr) {
1685 eptr_nucattr = std::current_exception();
1691 std::rethrow_exception(eptr_nucattr);
1693 if (!any_nonnull_buffer_nucattr.load() && natoms > 0 &&
1694 aobasis.getNumofShells() > 0) {
1711 throw std::runtime_error(
1712 "ComputeNuclearAttractionDerivatives: engine.results() returned "
1713 "a null buffer for EVERY shell pair and point charge -- this "
1714 "libint2 build does not actually support nuclear-attraction "
1715 "derivative integrals at runtime, even though it may report "
1716 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1717 "libint2 with this operator's derivative support enabled "
1718 "(--enable-1body=1, which nuclear attraction is part of) to "
1719 "use this feature.");
1732 double total_norm_sq_nucattr = 0.0;
1733 for (
Index a = 0; a < natoms; ++a) {
1735 for (
Index t = 0; t < nthreads; ++t) {
1736 total_norm_sq_nucattr += result_thread[t][a][
xyz].squaredNorm();
1740 if (total_norm_sq_nucattr < 1.e-20 && natoms > 0 &&
1741 aobasis.getNumofShells() > 0) {
1742 throw std::runtime_error(
1743 "ComputeNuclearAttractionDerivatives: the assembled result is "
1744 "exactly zero everywhere, which is physically impossible for a "
1745 "real molecule -- this libint2 build likely returns valid but "
1746 "zero-filled buffers for this operator (rather than either "
1747 "computing it correctly or returning null, which the separate, "
1748 "earlier check in this function already handles). Rebuild "
1749 "libint2 with this operator's derivative support enabled "
1750 "(--enable-1body=1) to use this feature.");
1753 std::vector<AOMatrixDerivative> result(natoms);
1754 for (
Index a = 0; a < natoms; ++a) {
1756 result[a][
xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
1757 for (
Index t = 0; t < nthreads; ++t) {
1758 result[a][
xyz] += result_thread[t][a][
xyz];
1767 ThrowNoDerivativeSupport(
"ComputeNuclearAttractionDerivatives",
1768 "--enable-1body=1");
1790#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
1791 (LIBINT_INCLUDE_ONEBODY >= 1) && (LIBINT_INCLUDE_ERI2 >= 1) && \
1792 (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.