49#define LIBINT2_CONSTEXPR_STATICS 0
51#pragma clang diagnostic push
52#pragma clang diagnostic ignored "-W#warnings"
53#elif defined(__GNUC__)
54#pragma GCC diagnostic push
55#pragma GCC diagnostic ignored "-Warray-bounds"
56#pragma GCC diagnostic ignored "-Wcpp"
62#pragma clang diagnostic pop
63#elif defined(__GNUC__)
64#pragma GCC diagnostic pop
72#if !defined(LIBINT_INCLUDE_ONEBODY) && defined(INCLUDE_ONEBODY)
73#define LIBINT_INCLUDE_ONEBODY INCLUDE_ONEBODY
75#if !defined(LIBINT_INCLUDE_ERI2) && defined(INCLUDE_ERI2)
76#define LIBINT_INCLUDE_ERI2 INCLUDE_ERI2
78#if !defined(LIBINT_INCLUDE_ERI) && defined(INCLUDE_ERI)
79#define LIBINT_INCLUDE_ERI INCLUDE_ERI
81#if !defined(LIBINT_INCLUDE_ERI3) && defined(INCLUDE_ERI3)
82#define LIBINT_INCLUDE_ERI3 INCLUDE_ERI3
90#ifdef VOTCA_LIBINT_EXPECT_MAJOR
91#ifdef LIBINT_INCLUDE_ONEBODY
92#define VOTCA_LIBINT_HAVE_ONEBODY LIBINT_INCLUDE_ONEBODY
94#define VOTCA_LIBINT_HAVE_ONEBODY -1
96#ifdef LIBINT_INCLUDE_ERI
97#define VOTCA_LIBINT_HAVE_ERI LIBINT_INCLUDE_ERI
99#define VOTCA_LIBINT_HAVE_ERI -1
101#ifdef LIBINT_INCLUDE_ERI2
102#define VOTCA_LIBINT_HAVE_ERI2 LIBINT_INCLUDE_ERI2
104#define VOTCA_LIBINT_HAVE_ERI2 -1
106#ifdef LIBINT_INCLUDE_ERI3
107#define VOTCA_LIBINT_HAVE_ERI3 LIBINT_INCLUDE_ERI3
109#define VOTCA_LIBINT_HAVE_ERI3 -1
111#if LIBINT_MAJOR_VERSION != VOTCA_LIBINT_EXPECT_MAJOR || \
112 LIBINT_MINOR_VERSION != VOTCA_LIBINT_EXPECT_MINOR || \
113 LIBINT_MICRO_VERSION != VOTCA_LIBINT_EXPECT_MICRO || \
114 VOTCA_LIBINT_HAVE_ONEBODY != VOTCA_LIBINT_EXPECT_ONEBODY || \
115 VOTCA_LIBINT_HAVE_ERI != VOTCA_LIBINT_EXPECT_ERI || \
116 VOTCA_LIBINT_HAVE_ERI2 != VOTCA_LIBINT_EXPECT_ERI2 || \
117 VOTCA_LIBINT_HAVE_ERI3 != VOTCA_LIBINT_EXPECT_ERI3
118#error "The libint2 headers found by the compiler are not those of the libint2 CMake configured (VOTCA_LIBINT_CONFIG_H in CMakeCache.txt). Another libint2 is earlier in the include path; remove it from there or uninstall it."
128std::vector<Eigen::MatrixXd>
ComputeAO3cBlock(
const libint2::Shell& auxshell,
129 const AOBasis& dftbasis,
130 libint2::Engine& engine);
143 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
150[[noreturn, maybe_unused]]
void ThrowNoDerivativeSupport(
151 const char* function_name,
const char* configure_flag) {
152 throw std::runtime_error(
153 std::string(function_name) +
154 ": this libint2 build was compiled without derivative integral "
155 "support for this operator category, so analytic nuclear forces "
156 "are unavailable. Rebuild libint2 with " +
158 " to use this feature. Many packaged libint2 builds (Homebrew, "
159 "Ubuntu apt, etc.) do not enable it; one-body, two-center Coulomb "
160 "metric and three-center RI integrals each have their own "
161 "configure option.");
181#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
182 (LIBINT_INCLUDE_ONEBODY >= 1)
183template <lib
int2::Operator obtype>
184std::vector<AOMatrixDerivative> computeOneBodyIntegralDerivatives(
185 const AOBasis& aobasis) {
188 libint2::operator_traits<obtype>::nopers == 1,
189 "computeOneBodyIntegralDerivatives only supports single-operator "
190 "types (overlap, kinetic); multipole-type operators with multiple "
191 "result matrices are not handled.");
194 Index natoms =
static_cast<Index>(aobasis.getFuncPerAtom().size());
196 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
197 std::vector<std::vector<Index>> shellpair_list = aobasis.ComputeShellPairs();
198 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
201 std::vector<Index> shell2atom;
202 shell2atom.reserve(shells.size());
203 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
204 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
207 Index nbf = aobasis.AOBasisSize();
208 std::vector<AOMatrixDerivative> result(natoms);
209 for (
Index a = 0; a < natoms; ++a) {
210 for (
Index xyz = 0; xyz < 3; ++xyz) {
211 result[a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
215 std::vector<libint2::Engine> engines(nthreads);
217 engines[0] = libint2::Engine(obtype, aobasis.getMaxNprim(),
218 static_cast<int>(aobasis.getMaxL()), 1);
219 for (
Index i = 1; i < nthreads; ++i) {
220 engines[i] = engines[0];
223 std::exception_ptr eptr =
nullptr;
224 std::atomic<bool> any_nonnull_buffer{
false};
225#pragma omp parallel for schedule(dynamic)
226 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
229 libint2::Engine& engine = engines[thread_id];
230 const libint2::Engine::target_ptr_vec& buf = engine.results();
232 Index bf1 = shell2bf[s1];
233 Index n1 = shells[s1].size();
234 Index atom1 = shell2atom[s1];
236 for (
Index s2 : shellpair_list[s1]) {
238 engine.compute(shells[s1], shells[s2]);
242 if (buf[0] ==
nullptr || buf[3] ==
nullptr) {
246 any_nonnull_buffer.store(
true, std::memory_order_relaxed);
248 Index bf2 = shell2bf[s2];
249 Index n2 = shells[s2].size();
250 Index atom2 = shell2atom[s2];
252 for (
Index xyz = 0; xyz < 3; ++xyz) {
253 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
254 result[atom1][xyz].block(bf1, bf2, n1, n2) += buf_mat1;
256 result[atom1][xyz].block(bf2, bf1, n2, n1) += buf_mat1.transpose();
259 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
260 result[atom2][xyz].block(bf1, bf2, n1, n2) += buf_mat2;
262 result[atom2][xyz].block(bf2, bf1, n2, n1) += buf_mat2.transpose();
272 eptr = std::current_exception();
278 std::rethrow_exception(eptr);
280 if (!any_nonnull_buffer.load() && aobasis.getNumofShells() > 0) {
283 throw std::runtime_error(
284 "computeOneBodyIntegralDerivatives: engine.results() returned a "
285 "null buffer for every shell pair; this libint2 build does not "
286 "support this operator's derivative integrals at runtime, even "
287 "though it may report LIBINT2_MAX_DERIV_ORDER >= 1 for other "
288 "operators. Rebuild libint2 with --enable-1body=1 to use this "
296 const AOBasis& aobasis) {
297 return computeOneBodyIntegralDerivatives<libint2::Operator::overlap>(aobasis);
301 const AOBasis& aobasis) {
302 return computeOneBodyIntegralDerivatives<libint2::Operator::kinetic>(aobasis);
308 ThrowNoDerivativeSupport(
"ComputeOverlapDerivatives",
"--enable-1body=1");
311 ThrowNoDerivativeSupport(
"ComputeKineticDerivatives",
"--enable-1body=1");
325#if (LIBINT_INCLUDE_ERI2 >= 1)
327 const AOBasis& aobasis) {
328 Index natoms =
static_cast<Index>(aobasis.getFuncPerAtom().size());
330 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
331 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
333 std::vector<Index> shell2atom;
334 shell2atom.reserve(aobasis.getNumofShells());
335 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
336 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
339 Index nbf = aobasis.AOBasisSize();
340 std::vector<AOMatrixDerivative> result(natoms);
341 for (
Index a = 0; a < natoms; ++a) {
342 for (
Index xyz = 0; xyz < 3; ++xyz) {
343 result[a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
347 std::vector<libint2::Engine> engines(nthreads);
349 libint2::Engine(libint2::Operator::coulomb, aobasis.getMaxNprim(),
350 static_cast<int>(aobasis.getMaxL()), 1);
351 engines[0].set(libint2::BraKet::xs_xs);
352 for (
Index i = 1; i < nthreads; ++i) {
353 engines[i] = engines[0];
356 std::exception_ptr eptr_coulmetric =
nullptr;
357 std::atomic<bool> any_nonnull_buffer_coulmetric{
false};
358#pragma omp parallel for schedule(dynamic)
359 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
362 const libint2::Engine::target_ptr_vec& buf = engine.results();
364 Index bf1 = shell2bf[s1];
365 Index n1 = shells[s1].size();
366 Index atom1 = shell2atom[s1];
371 for (
Index s2 = 0; s2 <= s1; ++s2) {
372 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xs, 1>(
373 shells[s1], libint2::Shell::unit(), shells[s2],
374 libint2::Shell::unit());
377 if (buf[0] ==
nullptr || buf[3] ==
nullptr) {
380 any_nonnull_buffer_coulmetric.store(
true, std::memory_order_relaxed);
382 Index bf2 = shell2bf[s2];
383 Index n2 = shells[s2].size();
384 Index atom2 = shell2atom[s2];
387 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
388 result[atom1][
xyz].block(bf1, bf2, n1, n2) += buf_mat1;
390 result[atom1][
xyz].block(bf2, bf1, n2, n1) += buf_mat1.transpose();
393 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
394 result[atom2][
xyz].block(bf1, bf2, n1, n2) += buf_mat2;
396 result[atom2][
xyz].block(bf2, bf1, n2, n1) += buf_mat2.transpose();
403 if (!eptr_coulmetric) {
404 eptr_coulmetric = std::current_exception();
409 if (eptr_coulmetric) {
410 std::rethrow_exception(eptr_coulmetric);
412 if (!any_nonnull_buffer_coulmetric.load() && aobasis.getNumofShells() > 0) {
413 throw std::runtime_error(
414 "ComputeCoulombMetricDerivatives: engine.results() returned a "
415 "null buffer for every shell pair; this libint2 build does not "
416 "support this operator's derivative integrals at runtime, even "
417 "though it may report LIBINT2_MAX_DERIV_ORDER >= 1 for other "
418 "operators. Rebuild libint2 with --enable-eri2=1 to use this "
426 ThrowNoDerivativeSupport(
"ComputeCoulombMetricDerivatives",
450#if (LIBINT_INCLUDE_ERI3 >= 1)
452 const AOBasis& auxbasis,
const AOBasis& dftbasis) {
453 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
457 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
458 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
459 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
460 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
462 std::vector<Index> dftshell2atom;
463 dftshell2atom.reserve(dftbasis.getNumofShells());
464 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
465 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
467 std::vector<Index> auxshell2atom;
468 auxshell2atom.reserve(auxbasis.getNumofShells());
469 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
470 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
473 Index n_dft_bf = dftbasis.AOBasisSize();
474 Index n_aux_bf = auxbasis.AOBasisSize();
476 std::vector<ThreeCenterDerivative> result(natoms);
477 for (
Index a = 0; a < natoms; ++a) {
479 result[a][
xyz] = std::vector<Eigen::MatrixXd>(
480 n_aux_bf, Eigen::MatrixXd::Zero(n_dft_bf, n_dft_bf));
484 std::vector<libint2::Engine> engines(nthreads);
485 engines[0] = libint2::Engine(
486 libint2::Operator::coulomb,
487 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
488 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
489 engines[0].set(libint2::BraKet::xs_xx);
490 for (
Index i = 1; i < nthreads; ++i) {
491 engines[i] = engines[0];
494 std::exception_ptr eptr_3c =
nullptr;
495 std::atomic<bool> any_nonnull_buffer_3c{
false};
496#pragma omp parallel for schedule(dynamic)
497 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
500 const libint2::Engine::target_ptr_vec& buf = engine.results();
502 const libint2::Shell& auxshell = auxshells[aux];
503 Index aux_start = auxshell2bf[aux];
504 Index atom_aux = auxshell2atom[aux];
506 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
507 const libint2::Shell& shell_row = dftshells[row];
508 Index row_start = shell2bf[row];
509 Index atom_row = dftshell2atom[row];
513 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
514 const libint2::Shell& shell_col = dftshells[col];
515 Index col_start = shell2bf[col];
516 Index atom_col = dftshell2atom[col];
519 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
520 auxshell, libint2::Shell::unit(), shell_col, shell_row);
523 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
526 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
532 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
533 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
536 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
537 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
540 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
541 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
544 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
545 Index global_aux = aux_start +
static_cast<Index>(aux_c);
546 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
547 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
548 double val_aux = result_aux(aux_c, col_c, row_c);
549 double val_col = result_col(aux_c, col_c, row_c);
550 double val_row = result_row(aux_c, col_c, row_c);
551 Index r = row_start +
static_cast<Index>(row_c);
552 Index c = col_start +
static_cast<Index>(col_c);
553 result[atom_aux][
xyz][global_aux](r, c) += val_aux;
554 result[atom_col][
xyz][global_aux](r, c) += val_col;
555 result[atom_row][
xyz][global_aux](r, c) += val_row;
566 eptr_3c = std::current_exception();
572 std::rethrow_exception(eptr_3c);
574 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
575 dftbasis.getNumofShells() > 0) {
576 throw std::runtime_error(
577 "ComputeThreeCenterDerivatives: engine.results() returned a null "
578 "buffer for every shell triple; this libint2 build does not "
579 "support this operator's derivative integrals at runtime, even "
580 "though it may report LIBINT2_MAX_DERIV_ORDER >= 1 for other "
581 "operators. Rebuild libint2 with --enable-eri3=1 to use this "
589 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivatives",
"--enable-eri3=1");
593#if (LIBINT_INCLUDE_ERI3 >= 1)
602 const AOBasis& auxbasis,
const AOBasis& dftbasis,
603 const Eigen::MatrixXd& density) {
604 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
607 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
608 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
609 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
610 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
612 std::vector<Index> dftshell2atom;
613 dftshell2atom.reserve(dftbasis.getNumofShells());
614 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
615 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
617 std::vector<Index> auxshell2atom;
618 auxshell2atom.reserve(auxbasis.getNumofShells());
619 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
620 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
623 Index n_aux_bf = auxbasis.AOBasisSize();
626 std::vector<Eigen::MatrixXd> result(natoms,
627 Eigen::MatrixXd::Zero(3, n_aux_bf));
629 std::vector<libint2::Engine> engines(nthreads);
630 engines[0] = libint2::Engine(
631 libint2::Operator::coulomb,
632 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
633 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
634 engines[0].set(libint2::BraKet::xs_xx);
635 for (
Index i = 1; i < nthreads; ++i) {
636 engines[i] = engines[0];
642 std::exception_ptr eptr_3c =
nullptr;
643 std::atomic<bool> any_nonnull_buffer_3c{
false};
644#pragma omp parallel for schedule(dynamic)
645 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
648 const libint2::Engine::target_ptr_vec& buf = engine.results();
650 const libint2::Shell& auxshell = auxshells[aux];
651 Index aux_start = auxshell2bf[aux];
652 Index atom_aux = auxshell2atom[aux];
654 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
655 const libint2::Shell& shell_row = dftshells[row];
656 Index row_start = shell2bf[row];
657 Index atom_row = dftshell2atom[row];
659 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
660 const libint2::Shell& shell_col = dftshells[col];
661 Index col_start = shell2bf[col];
662 Index atom_col = dftshell2atom[col];
665 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
666 auxshell, libint2::Shell::unit(), shell_col, shell_row);
668 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
671 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
675 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
676 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
679 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
680 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
683 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
684 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
687 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
688 Index global_aux = aux_start +
static_cast<Index>(aux_c);
689 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
690 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
691 double val_aux = result_aux(aux_c, col_c, row_c);
692 double val_col = result_col(aux_c, col_c, row_c);
693 double val_row = result_row(aux_c, col_c, row_c);
694 Index r = row_start +
static_cast<Index>(row_c);
695 Index c = col_start +
static_cast<Index>(col_c);
697 double d_rc = density(r, c);
698 result[atom_aux](
xyz, global_aux) += d_rc * val_aux;
699 result[atom_col](
xyz, global_aux) += d_rc * val_col;
700 result[atom_row](
xyz, global_aux) += d_rc * val_row;
711 eptr_3c = std::current_exception();
717 std::rethrow_exception(eptr_3c);
719 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
720 dftbasis.getNumofShells() > 0) {
721 throw std::runtime_error(
722 "ComputeThreeCenterDerivativeContraction: engine.results() "
723 "returned a null buffer for every shell triple; this libint2 "
724 "build does not support this operator's derivative integrals at "
725 "runtime, even though it may report LIBINT2_MAX_DERIV_ORDER >= 1 "
726 "for other operators. Rebuild libint2 with --enable-eri3=1 to "
727 "use this feature.");
734 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativeContraction",
739#if (LIBINT_INCLUDE_ERI3 >= 1)
746 const AOBasis& auxbasis,
const AOBasis& dftbasis,
Index target_atom) {
747 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
748 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
749 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
750 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
752 std::vector<Index> dftshell2atom;
753 dftshell2atom.reserve(dftbasis.getNumofShells());
754 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
755 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
757 std::vector<Index> auxshell2atom;
758 auxshell2atom.reserve(auxbasis.getNumofShells());
759 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
760 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
763 Index n_dft_bf = dftbasis.AOBasisSize();
764 Index n_aux_bf = auxbasis.AOBasisSize();
770 result[
xyz] = std::vector<Eigen::MatrixXd>(
771 n_aux_bf, Eigen::MatrixXd::Zero(n_dft_bf, n_dft_bf));
774 std::vector<libint2::Engine> engines(nthreads);
775 engines[0] = libint2::Engine(
776 libint2::Operator::coulomb,
777 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
778 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
779 engines[0].set(libint2::BraKet::xs_xx);
780 for (
Index i = 1; i < nthreads; ++i) {
781 engines[i] = engines[0];
784 std::exception_ptr eptr_3c =
nullptr;
785 std::atomic<bool> any_nonnull_buffer_3c{
false};
786#pragma omp parallel for schedule(dynamic)
787 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
790 const libint2::Engine::target_ptr_vec& buf = engine.results();
792 const libint2::Shell& auxshell = auxshells[aux];
793 Index aux_start = auxshell2bf[aux];
794 Index atom_aux = auxshell2atom[aux];
796 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
797 const libint2::Shell& shell_row = dftshells[row];
798 Index row_start = shell2bf[row];
799 Index atom_row = dftshell2atom[row];
801 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
802 const libint2::Shell& shell_col = dftshells[col];
803 Index col_start = shell2bf[col];
804 Index atom_col = dftshell2atom[col];
807 if (atom_aux != target_atom && atom_col != target_atom &&
808 atom_row != target_atom) {
813 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
814 auxshell, libint2::Shell::unit(), shell_col, shell_row);
816 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
819 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
823 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
824 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
827 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
828 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
831 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
832 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
835 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
836 Index global_aux = aux_start +
static_cast<Index>(aux_c);
837 for (
size_t col_c = 0; col_c < shell_col.size(); ++col_c) {
838 for (
size_t row_c = 0; row_c < shell_row.size(); ++row_c) {
839 Index r = row_start +
static_cast<Index>(row_c);
840 Index c = col_start +
static_cast<Index>(col_c);
842 if (atom_aux == target_atom) {
843 result[
xyz][global_aux](r, c) +=
844 result_aux(aux_c, col_c, row_c);
846 if (atom_col == target_atom) {
847 result[
xyz][global_aux](r, c) +=
848 result_col(aux_c, col_c, row_c);
850 if (atom_row == target_atom) {
851 result[
xyz][global_aux](r, c) +=
852 result_row(aux_c, col_c, row_c);
864 eptr_3c = std::current_exception();
870 std::rethrow_exception(eptr_3c);
872 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
873 dftbasis.getNumofShells() > 0) {
874 throw std::runtime_error(
875 "ComputeThreeCenterDerivativesForAtom: engine.results() returned "
876 "a null buffer for every shell triple touching this atom; this "
877 "libint2 build does not support this operator's derivative "
878 "integrals at runtime, even though it may report "
879 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
880 "libint2 with --enable-eri3=1 to use this feature.");
888 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativesForAtom",
893#if (LIBINT_INCLUDE_ERI3 >= 1)
903 const AOBasis& auxbasis,
const AOBasis& dftbasis,
904 const Eigen::MatrixXd& occ_mo_coeffs) {
905 Index natoms =
static_cast<Index>(dftbasis.getFuncPerAtom().size());
906 Index nocc = occ_mo_coeffs.cols();
909 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
910 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
911 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
912 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
914 std::vector<Index> dftshell2atom;
915 dftshell2atom.reserve(dftbasis.getNumofShells());
916 for (
Index s = 0; s < dftbasis.getNumofShells(); ++s) {
917 dftshell2atom.push_back(dftbasis.getShell(s).getAtomIndex());
919 std::vector<Index> auxshell2atom;
920 auxshell2atom.reserve(auxbasis.getNumofShells());
921 for (
Index s = 0; s < auxbasis.getNumofShells(); ++s) {
922 auxshell2atom.push_back(auxbasis.getShell(s).getAtomIndex());
925 Index n_aux_bf = auxbasis.AOBasisSize();
928 std::vector<ThreeCenterDerivative> result(natoms);
929 for (
Index a = 0; a < natoms; ++a) {
931 result[a][
xyz] = std::vector<Eigen::MatrixXd>(
932 n_aux_bf, Eigen::MatrixXd::Zero(nocc, nocc));
936 std::vector<libint2::Engine> engines(nthreads);
937 engines[0] = libint2::Engine(
938 libint2::Operator::coulomb,
939 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
940 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 1);
941 engines[0].set(libint2::BraKet::xs_xx);
942 for (
Index i = 1; i < nthreads; ++i) {
943 engines[i] = engines[0];
948 std::exception_ptr eptr_3c =
nullptr;
949 std::atomic<bool> any_nonnull_buffer_3c{
false};
950#pragma omp parallel for schedule(dynamic)
951 for (
Index aux = 0; aux < auxbasis.getNumofShells(); ++aux) {
954 const libint2::Engine::target_ptr_vec& buf = engine.results();
956 const libint2::Shell& auxshell = auxshells[aux];
957 Index aux_start = auxshell2bf[aux];
958 Index atom_aux = auxshell2atom[aux];
960 for (
Index row = 0; row < dftbasis.getNumofShells(); ++row) {
961 const libint2::Shell& shell_row = dftshells[row];
962 Index row_start = shell2bf[row];
963 Index atom_row = dftshell2atom[row];
965 for (
Index col = 0; col < dftbasis.getNumofShells(); ++col) {
966 const libint2::Shell& shell_col = dftshells[col];
967 Index col_start = shell2bf[col];
968 Index atom_col = dftshell2atom[col];
971 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 1>(
972 auxshell, libint2::Shell::unit(), shell_col, shell_row);
974 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
977 any_nonnull_buffer_3c.store(
true, std::memory_order_relaxed);
980 Index nrow =
static_cast<Index>(shell_row.size());
981 Index ncol =
static_cast<Index>(shell_col.size());
982 Eigen::MatrixXd mo_row_block =
983 occ_mo_coeffs.middleRows(row_start, nrow);
984 Eigen::MatrixXd mo_col_block =
985 occ_mo_coeffs.middleRows(col_start, ncol);
989 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
990 result_aux(buf[xyz], auxshell.size(), shell_col.size(),
993 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
994 result_col(buf[3 + xyz], auxshell.size(), shell_col.size(),
997 Eigen::Tensor<const double, 3, Eigen::RowMajor>
const>
998 result_row(buf[6 + xyz], auxshell.size(), shell_col.size(),
1001 for (
size_t aux_c = 0; aux_c < auxshell.size(); ++aux_c) {
1002 Index global_aux = aux_start +
static_cast<Index>(aux_c);
1007 Eigen::MatrixXd block_aux(nrow, ncol);
1008 Eigen::MatrixXd block_col(nrow, ncol);
1009 Eigen::MatrixXd block_row(nrow, ncol);
1010 for (
Index col_c = 0; col_c < ncol; ++col_c) {
1011 for (
Index row_c = 0; row_c < nrow; ++row_c) {
1012 block_aux(row_c, col_c) =
1013 result_aux(aux_c,
static_cast<size_t>(col_c),
1014 static_cast<size_t>(row_c));
1015 block_col(row_c, col_c) =
1016 result_col(aux_c,
static_cast<size_t>(col_c),
1017 static_cast<size_t>(row_c));
1018 block_row(row_c, col_c) =
1019 result_row(aux_c,
static_cast<size_t>(col_c),
1020 static_cast<size_t>(row_c));
1023 result[atom_aux][
xyz][global_aux].noalias() +=
1024 mo_row_block.transpose() * block_aux * mo_col_block;
1025 result[atom_col][
xyz][global_aux].noalias() +=
1026 mo_row_block.transpose() * block_col * mo_col_block;
1027 result[atom_row][
xyz][global_aux].noalias() +=
1028 mo_row_block.transpose() * block_row * mo_col_block;
1037 eptr_3c = std::current_exception();
1043 std::rethrow_exception(eptr_3c);
1045 if (!any_nonnull_buffer_3c.load() && auxbasis.getNumofShells() > 0 &&
1046 dftbasis.getNumofShells() > 0) {
1047 throw std::runtime_error(
1048 "ComputeThreeCenterDerivativesMOTransformed: engine.results() "
1049 "returned a null buffer for every shell triple; this libint2 "
1050 "build does not support this operator's derivative integrals at "
1051 "runtime, even though it may report LIBINT2_MAX_DERIV_ORDER >= 1 "
1052 "for other operators. Rebuild libint2 with --enable-eri3=1 to "
1053 "use this feature.");
1060 ThrowNoDerivativeSupport(
"ComputeThreeCenterDerivativesMOTransformed",
1074 std::vector<Eigen::MatrixXd> tensor(
1078 libint2::Engine engine(
1079 libint2::Operator::coulomb,
1081 static_cast<int>(std::max(dftbasis.
getMaxL(), auxbasis.
getMaxL())), 0);
1082 engine.set(libint2::BraKet::xs_xx);
1085 std::vector<Eigen::MatrixXd> block =
1087 Index aux_start = auxshell2bf[aux];
1088 for (
size_t i = 0; i < block.size(); ++i) {
1089 tensor[aux_start +
static_cast<Index>(i)] = block[i];
1108#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
1109 (LIBINT_INCLUDE_ONEBODY >= 1)
1111 const AOBasis& aobasis,
const QMMolecule& mol) {
1112 Index natoms = mol.size();
1114 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
1115 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
1117 std::vector<Index> shell2atom;
1118 shell2atom.reserve(aobasis.getNumofShells());
1119 for (
Index s = 0; s < aobasis.getNumofShells(); ++s) {
1120 shell2atom.push_back(aobasis.getShell(s).getAtomIndex());
1123 Index nbf = aobasis.AOBasisSize();
1124 std::vector<std::vector<AOMatrixDerivative>> result_thread(nthreads);
1125 for (
Index t = 0; t < nthreads; ++t) {
1126 result_thread[t].resize(natoms);
1127 for (
Index a = 0; a < natoms; ++a) {
1128 for (
Index xyz = 0; xyz < 3; ++xyz) {
1129 result_thread[t][a][xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
1134 std::vector<libint2::Engine> engines(nthreads);
1135 for (
Index i = 0; i < nthreads; ++i) {
1137 libint2::Engine(libint2::Operator::nuclear, aobasis.getMaxNprim(),
1138 static_cast<int>(aobasis.getMaxL()), 1);
1143 std::exception_ptr eptr_nucattr =
nullptr;
1144 std::atomic<bool> any_nonnull_buffer_nucattr{
false};
1145#pragma omp parallel for schedule(dynamic)
1146 for (
Index A = 0; A < natoms; ++A) {
1149 libint2::Engine& engine = engines[thread_id];
1151 std::vector<libint2::Atom> single_atom(1);
1152 single_atom[0].atomic_number =
static_cast<int>(mol[A].getNuccharge());
1153 single_atom[0].x = mol[A].getPos().x();
1154 single_atom[0].y = mol[A].getPos().y();
1155 single_atom[0].z = mol[A].getPos().z();
1156 engine.set_params(libint2::make_point_charges(single_atom));
1158 const libint2::Engine::target_ptr_vec& buf = engine.results();
1160 for (
Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
1161 Index bf1 = shell2bf[s1];
1162 Index n1 = shells[s1].size();
1163 Index atom1 = shell2atom[s1];
1165 for (
Index s2 = 0; s2 <= s1; ++s2) {
1166 engine.compute(shells[s1], shells[s2]);
1171 if (buf[0] ==
nullptr || buf[3] ==
nullptr || buf[6] ==
nullptr) {
1174 any_nonnull_buffer_nucattr.store(
true, std::memory_order_relaxed);
1176 Index bf2 = shell2bf[s2];
1177 Index n2 = shells[s2].size();
1178 Index atom2 = shell2atom[s2];
1182 Eigen::Map<const MatrixLibInt> buf_mat1(buf[xyz], n1, n2);
1183 result_thread[thread_id][atom1][
xyz].block(bf1, bf2, n1, n2) +=
1186 result_thread[thread_id][atom1][
xyz].block(bf2, bf1, n2, n1) +=
1187 buf_mat1.transpose();
1190 Eigen::Map<const MatrixLibInt> buf_mat2(buf[3 + xyz], n1, n2);
1191 result_thread[thread_id][atom2][
xyz].block(bf1, bf2, n1, n2) +=
1194 result_thread[thread_id][atom2][
xyz].block(bf2, bf1, n2, n1) +=
1195 buf_mat2.transpose();
1198 Eigen::Map<const MatrixLibInt> buf_mat3(buf[6 + xyz], n1, n2);
1199 result_thread[thread_id][A][
xyz].block(bf1, bf2, n1, n2) +=
1202 result_thread[thread_id][A][
xyz].block(bf2, bf1, n2, n1) +=
1203 buf_mat3.transpose();
1211 if (!eptr_nucattr) {
1212 eptr_nucattr = std::current_exception();
1218 std::rethrow_exception(eptr_nucattr);
1220 if (!any_nonnull_buffer_nucattr.load() && natoms > 0 &&
1221 aobasis.getNumofShells() > 0) {
1224 throw std::runtime_error(
1225 "ComputeNuclearAttractionDerivatives: engine.results() returned "
1226 "a null buffer for every shell pair and point charge; this "
1227 "libint2 build does not support nuclear-attraction derivative "
1228 "integrals at runtime, even though it may report "
1229 "LIBINT2_MAX_DERIV_ORDER >= 1 for other operators. Rebuild "
1230 "libint2 with --enable-1body=1 to use this feature.");
1236 double total_norm_sq_nucattr = 0.0;
1237 for (
Index a = 0; a < natoms; ++a) {
1239 for (
Index t = 0; t < nthreads; ++t) {
1240 total_norm_sq_nucattr += result_thread[t][a][
xyz].squaredNorm();
1244 if (total_norm_sq_nucattr < 1.e-20 && natoms > 0 &&
1245 aobasis.getNumofShells() > 0) {
1246 throw std::runtime_error(
1247 "ComputeNuclearAttractionDerivatives: the assembled result is "
1248 "exactly zero everywhere, which is impossible for a real "
1249 "molecule; this libint2 build likely returns zero-filled buffers "
1250 "for this operator. Rebuild libint2 with --enable-1body=1 to use "
1254 std::vector<AOMatrixDerivative> result(natoms);
1255 for (
Index a = 0; a < natoms; ++a) {
1257 result[a][
xyz] = Eigen::MatrixXd::Zero(nbf, nbf);
1258 for (
Index t = 0; t < nthreads; ++t) {
1259 result[a][
xyz] += result_thread[t][a][
xyz];
1268 ThrowNoDerivativeSupport(
"ComputeNuclearAttractionDerivatives",
1269 "--enable-1body=1");
1278#if defined(LIBINT2_MAX_DERIV_ORDER) && LIBINT2_MAX_DERIV_ORDER >= 1 && \
1279 (LIBINT_INCLUDE_ONEBODY >= 1) && (LIBINT_INCLUDE_ERI2 >= 1) && \
1280 (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.