votca 2026-dev
Loading...
Searching...
No Matches
libint2_calls.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2024 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20// Standard includes
21#include <algorithm>
22#include <chrono>
23#include <numeric>
24
25// Local VOTCA includes
26#include "votca/xtp/ERIs.h"
27#include "votca/xtp/aobasis.h"
29#include "votca/xtp/aomatrix.h"
32
33// include libint last otherwise it overrides eigen
35#define LIBINT2_CONSTEXPR_STATICS 0
36#if defined(__clang__)
37#pragma clang diagnostic push
38#pragma clang diagnostic ignored "-W#warnings"
39#elif defined(__GNUC__)
40#pragma GCC diagnostic push
41#pragma GCC diagnostic ignored "-Warray-bounds"
42#pragma GCC diagnostic ignored "-Wcpp"
43#endif
44#include <libint2.hpp>
45#include <libint2/statics_definition.h>
46#if defined(__clang__)
47#pragma clang diagnostic pop
48#elif defined(__GNUC__)
49#pragma GCC diagnostic pop
50#endif
51
52namespace votca {
53namespace xtp {
54
55std::vector<std::vector<Index>> AOBasis::ComputeShellPairs(
56 double threshold) const {
57
58 Index nthreads = OPENMP::getMaxThreads();
59
60 std::vector<libint2::Shell> shells = GenerateLibintBasis();
61
62 // construct the 2-electron repulsion integrals engine
63 std::vector<libint2::Engine> engines;
64 engines.reserve(nthreads);
65 engines.emplace_back(libint2::Operator::overlap, getMaxNprim(), getMaxL(), 0);
66 for (Index i = 1; i != nthreads; ++i) {
67 engines.push_back(engines[0]);
68 }
69
70 std::vector<std::vector<Index>> pairs(shells.size());
71
72#pragma omp parallel for schedule(dynamic)
73 for (Index s1 = 0; s1 < Index(shells.size()); ++s1) {
74 Index thread_id = OPENMP::getThreadId();
75
76 libint2::Engine& engine = engines[thread_id];
77 const libint2::Engine::target_ptr_vec& buf = engine.results();
78 Index n1 = shells[s1].size();
79
80 for (Index s2 = 0; s2 <= s1; ++s2) {
81 bool on_same_center = (shells[s1].O == shells[s2].O);
82 bool significant = on_same_center;
83 if (!on_same_center) {
84 Index n2 = shells[s2].size();
85 engine.compute(shells[s1], shells[s2]);
86 Eigen::Map<const Eigen::MatrixXd> buf_mat(buf[0], n1, n2);
87 significant = (buf_mat.norm() >= threshold);
88 }
89 if (significant) {
90 pairs[s1].push_back(s2);
91 }
92 }
93 std::sort(pairs[s1].begin(), pairs[s1].end());
94 }
95 return pairs;
96}
97
98using MatrixLibInt =
99 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
100
101template <libint2::Operator obtype,
102 typename OperatorParams =
103 typename libint2::operator_traits<obtype>::oper_params_type>
104std::array<MatrixLibInt, libint2::operator_traits<obtype>::nopers>
106 OperatorParams oparams = OperatorParams()) {
107
108 Index nthreads = OPENMP::getMaxThreads();
109 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
110
111 std::vector<std::vector<Index>> shellpair_list = aobasis.ComputeShellPairs();
112
113 Index nopers = static_cast<Index>(libint2::operator_traits<obtype>::nopers);
114 std::array<MatrixLibInt, libint2::operator_traits<obtype>::nopers> result;
115 for (MatrixLibInt& r : result) {
116 r = MatrixLibInt::Zero(aobasis.AOBasisSize(), aobasis.AOBasisSize());
117 }
118
119 std::vector<libint2::Engine> engines(nthreads);
120 engines[0] = libint2::Engine(obtype, aobasis.getMaxNprim(),
121 static_cast<int>(aobasis.getMaxL()), 0);
122 engines[0].set_params(oparams);
123 for (Index i = 1; i < nthreads; ++i) {
124 engines[i] = engines[0];
125 }
126
127 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
128
129#pragma omp parallel for schedule(dynamic)
130 for (Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
131 Index thread_id = OPENMP::getThreadId();
132 libint2::Engine& engine = engines[thread_id];
133 const libint2::Engine::target_ptr_vec& buf = engine.results();
134
135 Index bf1 = shell2bf[s1];
136 Index n1 = shells[s1].size();
137
138 for (Index s2 : shellpair_list[s1]) {
139
140 engine.compute(shells[s1], shells[s2]);
141 if (buf[0] == nullptr) {
142 continue; // if all integrals screened out, skip to next shell set
143 }
144 Index bf2 = shell2bf[s2];
145 Index n2 = shells[s2].size();
146 for (unsigned int op = 0; op != nopers; ++op) {
147 Eigen::Map<const MatrixLibInt> buf_mat(buf[op], n1, n2);
148 result[op].block(bf1, bf2, n1, n2) = buf_mat;
149 if (s1 != s2) { // if s1 >= s2, copy {s1,s2} to the corresponding
150 // {s2,s1} block, note the transpose!
151 result[op].block(bf2, bf1, n2, n1) = buf_mat.transpose();
152 }
153 }
154 }
155 }
156 return result;
157}
158
159/***********************************
160 * KINETIC
161 ***********************************/
165
166/***********************************
167 * OVERLAP
168 ***********************************/
172
173Eigen::MatrixXd AOOverlap::singleShellOverlap(const AOShell& shell) const {
174 libint2::Shell::do_enforce_unit_normalization(false);
175 libint2::Operator obtype = libint2::Operator::overlap;
176 try {
177 libint2::Engine engine(obtype, shell.getSize(),
178 static_cast<int>(shell.getL()), 0);
179
180 const libint2::Engine::target_ptr_vec& buf = engine.results();
181
182 libint2::Shell s = shell.LibintShell();
183 engine.compute(s, s);
184
185 Eigen::Map<const MatrixLibInt> buf_mat(buf[0], shell.getNumFunc(),
186 shell.getNumFunc());
187 return buf_mat;
188 } catch (const libint2::Engine::lmax_exceeded& error) {
189 std::ostringstream oss;
190 oss << "\nA libint error occured:\n"
191 << error.what() << "\n"
192 << "\nYou requested a computation for a shell with angular momentum "
193 << error.lmax_requested()
194 << ",\nbut your libint package only supports angular momenta upto "
195 << error.lmax_limit() - 1 << ".\n"
196 << "\nTo fix this error you will need to reinstall libint with "
197 "support\n"
198 "for higher angular momenta. If you installed your own libint it\n"
199 "should be reconfigured and installed with the option "
200 "--with-max-am=<maxAngularMomentum>.\n"
201 "If you installed libint with your OS package manager, you will\n"
202 "need to setup you own libint installation with the \n"
203 "--with-max-am=<maxAngularMomentum> option set."
204 << std::endl;
205 throw std::runtime_error(oss.str());
206 }
207}
208
209/***********************************
210 * DIPOLE
211 ***********************************/
212void AODipole::Fill(const AOBasis& aobasis) {
213 auto results = computeOneBodyIntegrals<libint2::Operator::emultipole1,
214 std::array<libint2::Shell::real_t, 3>>(
215 aobasis, r_);
216
217 for (Index i = 0; i < 3; i++) {
218 aomatrix_[i] = results[1 + i]; // emultipole1 returns: overlap, x-dipole,
219 // y-dipole, z-dipole
220 }
221}
222
223/***********************************
224 * COULOMB
225 ***********************************/
226void AOCoulomb::Fill(const AOBasis& aobasis) {
228}
229
231 Index nthreads = OPENMP::getMaxThreads();
232 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
233 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
234
235 aomatrix_ =
236 Eigen::MatrixXd::Zero(aobasis.AOBasisSize(), aobasis.AOBasisSize());
237
238 // build engines for each thread
239 std::vector<libint2::Engine> engines(nthreads);
240 engines[0] =
241 libint2::Engine(libint2::Operator::coulomb, aobasis.getMaxNprim(),
242 static_cast<int>(aobasis.getMaxL()), 0);
243 engines[0].set(libint2::BraKet::xs_xs);
244 for (Index i = 1; i != nthreads; ++i) {
245 engines[i] = engines[0];
246 }
247
248#pragma omp parallel for schedule(dynamic)
249 for (Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
250 libint2::Engine& engine = engines[OPENMP::getThreadId()];
251 const libint2::Engine::target_ptr_vec& buf = engine.results();
252
253 Index bf1 = shell2bf[s1];
254 Index n1 = shells[s1].size();
255 // cannot use shellpairs because this is still a two-center integral and
256 // overlap screening would give wrong result
257 for (Index s2 = 0; s2 <= s1; ++s2) {
258
259 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xs, 0>(
260 shells[s1], libint2::Shell::unit(), shells[s2],
261 libint2::Shell::unit());
262
263 if (buf[0] == nullptr) {
264 continue; // if all integrals screened out, skip to next shell set
265 }
266 Index bf2 = shell2bf[s2];
267 Index n2 = shells[s2].size();
268
269 Eigen::Map<const MatrixLibInt> buf_mat(buf[0], n1, n2);
270 aomatrix_.block(bf1, bf2, n1, n2) = buf_mat;
271 if (s1 != s2) { // if s1 >= s2, copy {s1,s2} to the corresponding
272 // {s2,s1} block, note the transpose!
273 aomatrix_.block(bf2, bf1, n2, n1) = buf_mat.transpose();
274 }
275 }
276 }
277}
278
279Eigen::MatrixXd ERIs::ComputeSchwarzShells(const AOBasis& basis) const {
280
281 Index noshells = basis.getNumofShells();
282
283 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(noshells, noshells);
284 Index nthreads = OPENMP::getMaxThreads();
285 std::vector<libint2::Engine> engines(nthreads);
286 double epsilon = 0.0;
287 engines[0] = libint2::Engine(libint2::Operator::coulomb, basis.getMaxNprim(),
288 static_cast<int>(basis.getMaxL()), 0, epsilon);
289
290 for (Index i = 1; i < nthreads; ++i) {
291 engines[i] = engines[0];
292 }
293
294 std::vector<libint2::Shell> shells = basis.GenerateLibintBasis();
295
296#pragma omp parallel for schedule(dynamic)
297 for (Index s1 = 0l; s1 < basis.getNumofShells(); ++s1) {
298 Index thread_id = OPENMP::getThreadId();
299 libint2::Engine& engine = engines[thread_id];
300 const libint2::Engine::target_ptr_vec& buf = engine.results();
301 Index n1 = shells[s1].size();
302
303 for (Index s2 = 0l; s2 <= s1; ++s2) {
304 Index n2 = shells[s2].size();
305 Index n12 = n1 * n2;
306
307 engines[thread_id]
308 .compute2<libint2::Operator::coulomb, libint2::BraKet::xx_xx, 0>(
309 shells[s1], shells[s2], shells[s1], shells[s2]);
310
311 Eigen::Map<const MatrixLibInt> buf_mat(buf[0], n12, n12);
312
313 result(s2, s1) = std::sqrt(buf_mat.cwiseAbs().maxCoeff());
314 }
315 }
316 return result.selfadjointView<Eigen::Upper>();
317}
318
319template <bool with_exchange>
320std::array<Eigen::MatrixXd, 2> ERIs::Compute4c(const Eigen::MatrixXd& dmat,
321 double error) const {
322 assert(schwarzscreen_.rows() > 0 && schwarzscreen_.cols() > 0 &&
323 "Please call Initialize_4c before running this");
324 Index nthreads = OPENMP::getMaxThreads();
325
326 Eigen::MatrixXd hartree = Eigen::MatrixXd::Zero(dmat.rows(), dmat.cols());
327 Eigen::MatrixXd exchange;
328 if (with_exchange) {
329 exchange = Eigen::MatrixXd::Zero(dmat.rows(), dmat.cols());
330 }
331 Eigen::MatrixXd dnorm_block = ComputeShellBlockNorm(dmat);
332 double fock_precision = error;
333 // engine precision controls primitive truncation, assume worst-case scenario
334 // (all primitive combinations add up constructively)
335 Index max_nprim4 = maxnprim_ * maxnprim_ * maxnprim_ * maxnprim_;
336 double engine_precision = std::min(fock_precision / dnorm_block.maxCoeff(),
337 std::numeric_limits<double>::epsilon()) /
338 double(max_nprim4);
339 std::vector<libint2::Engine> engines(nthreads);
340 engines[0] = libint2::Engine(libint2::Operator::coulomb, int(maxnprim_),
341 int(maxL_), 0);
342 engines[0].set_precision(engine_precision); // shellset-dependent precision
343 // control will likely break
344 // positive definiteness
345 // stick with this simple recipe
346 for (Index i = 1; i < nthreads; ++i) {
347 engines[i] = engines[0];
348 }
349 Index nshells = basis_.size();
350
351#pragma omp parallel for schedule(dynamic) reduction(+ : hartree) \
352 reduction(+ : exchange)
353 for (Index s1 = 0; s1 < nshells; ++s1) {
354 Index thread_id = OPENMP::getThreadId();
355 libint2::Engine& engine = engines[thread_id];
356 const auto& buf = engine.results();
357 Index start_1 = starts_[s1];
358 const libint2::Shell& shell1 = basis_[s1];
359 Index n1 = shell1.size();
360
361 auto sp12_iter = shellpairdata_[s1].begin();
362 for (Index s2 : shellpairs_[s1]) {
363 Index start_2 = starts_[s2];
364 const libint2::Shell& shell2 = basis_[s2];
365 Index n2 = shell2.size();
366 double dnorm_12 = dnorm_block(s1, s2);
367 const libint2::ShellPair* sp12 = &(*sp12_iter);
368 ++sp12_iter;
369
370 for (Index s3 = 0; s3 <= s1; ++s3) {
371
372 Index start_3 = starts_[s3];
373 const libint2::Shell& shell3 = basis_[s3];
374 Index n3 = shell3.size();
375 auto sp34_iter = shellpairdata_[s3].begin();
376 double dnorm_123 = std::max(dnorm_block(s1, s3),
377 std::max(dnorm_block(s2, s3), dnorm_12));
378 Index s4max = (s1 == s3) ? s2 : s3;
379 for (Index s4 : shellpairs_[s3]) {
380 if (s4 > s4max) {
381 break;
382 } // for each s3, s4 are stored in monotonically increasing
383 // order
384
385 const libint2::ShellPair* sp34 = &(*sp34_iter);
386 // must update the iter even if going to skip s4
387 ++sp34_iter;
388 double dnorm_1234 =
389 std::max(dnorm_block(s1, s4),
390 std::max(dnorm_block(s2, s4),
391 std::max(dnorm_block(s3, s4), dnorm_123)));
392
393 if (dnorm_1234 * schwarzscreen_(s1, s2) * schwarzscreen_(s3, s4) <
394 fock_precision) {
395 continue;
396 }
397
398 const libint2::Shell& shell4 = basis_[s4];
399 engine
400 .compute2<libint2::Operator::coulomb, libint2::BraKet::xx_xx, 0>(
401 shell1, shell2, shell3, shell4, sp12, sp34);
402 const auto* buf_1234 = buf[0];
403 if (buf_1234 == nullptr) {
404 continue; // if all integrals screened out, skip to next quartet
405 }
406 Index start_4 = starts_[s4];
407 Index n4 = shell4.size();
408 Index s12_deg = (s1 == s2) ? 1 : 2;
409 Index s34_deg = (s3 == s4) ? 1 : 2;
410 Index s12_34_deg = (s1 == s3) ? (s2 == s4 ? 1 : 2) : 2;
411 Index s1234_deg = s12_deg * s34_deg * s12_34_deg;
412
413 for (Index f1 = 0, f1234 = 0; f1 != n1; ++f1) {
414 const Index bf1 = f1 + start_1;
415 for (Index f2 = 0; f2 != n2; ++f2) {
416 const Index bf2 = f2 + start_2;
417 for (Index f3 = 0; f3 != n3; ++f3) {
418 const Index bf3 = f3 + start_3;
419 for (Index f4 = 0; f4 != n4; ++f4, ++f1234) {
420 const Index bf4 = f4 + start_4;
421
422 const double value = buf_1234[f1234];
423
424 const double value_scal_by_deg = value * double(s1234_deg);
425
426 hartree(bf1, bf2) += dmat(bf3, bf4) * value_scal_by_deg;
427 hartree(bf3, bf4) += dmat(bf1, bf2) * value_scal_by_deg;
428 if (with_exchange) {
429 exchange(bf1, bf3) -= dmat(bf2, bf4) * value_scal_by_deg;
430 exchange(bf2, bf3) -= dmat(bf1, bf4) * value_scal_by_deg;
431 exchange(bf2, bf4) -= dmat(bf1, bf3) * value_scal_by_deg;
432 exchange(bf1, bf4) -= dmat(bf2, bf3) * value_scal_by_deg;
433 }
434 }
435 }
436 }
437 }
438 }
439 }
440 }
441 }
442 std::array<Eigen::MatrixXd, 2> result2;
443 // 0.25=0.5(symmetrisation)*0.5(our dmat has a factor 2)
444 result2[0] = 0.25 * (hartree + hartree.transpose());
445 if (with_exchange) {
446 // prefactor
447 result2[1] = 0.125 * (exchange + exchange.transpose());
448 }
449 return result2;
450}
451
452template std::array<Eigen::MatrixXd, 2> ERIs::Compute4c<true>(
453 const Eigen::MatrixXd& dmat, double error) const;
454template std::array<Eigen::MatrixXd, 2> ERIs::Compute4c<false>(
455 const Eigen::MatrixXd& dmat, double error) const;
456
457std::vector<std::vector<Index>> TCMatrix_dft::SignificantPairs(
458 const AOBasis& dftbasis, const Eigen::MatrixXd& metric,
459 double pair_threshold) const {
460 const Index nshells = dftbasis.getNumofShells();
461 std::vector<std::vector<Index>> kept(nshells);
462 if (pair_threshold <= 0.0) {
463 for (Index a = 0; a < nshells; ++a) {
464 kept[a].resize(a + 1);
465 std::iota(kept[a].begin(), kept[a].end(), Index(0));
466 }
467 return kept;
468 }
469 // |(P|ab)| <= sqrt((P|P)) sqrt((ab|ab))
470 const double max_aux = std::sqrt(metric.diagonal().cwiseAbs().maxCoeff());
471 const Index nthreads = OPENMP::getMaxThreads();
472 std::vector<libint2::Engine> engines(nthreads);
473 engines[0] =
474 libint2::Engine(libint2::Operator::coulomb, dftbasis.getMaxNprim(),
475 static_cast<int>(dftbasis.getMaxL()), 0, 0.0);
476 for (Index i = 1; i < nthreads; ++i) {
477 engines[i] = engines[0];
478 }
479 const std::vector<libint2::Shell> shells = dftbasis.GenerateLibintBasis();
480#pragma omp parallel for schedule(dynamic)
481 for (Index a = nshells - 1; a >= 0; --a) {
482 libint2::Engine& engine = engines[OPENMP::getThreadId()];
483 const libint2::Engine::target_ptr_vec& buf = engine.results();
484 for (Index b = 0; b < a; ++b) {
485 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xx_xx, 0>(
486 shells[a], shells[b], shells[a], shells[b]);
487 if (buf[0] == nullptr) {
488 continue;
489 }
490 const Index n = Index(shells[a].size() * shells[b].size());
491 const double schwarz =
492 std::sqrt(Eigen::Map<const Eigen::MatrixXd>(buf[0], n, n)
493 .cwiseAbs()
494 .maxCoeff());
495 if (max_aux * schwarz >= pair_threshold) {
496 kept[a].push_back(b);
497 }
498 }
499 kept[a].push_back(a); // diagonal shell pairs are always kept
500 }
501 return kept;
502}
503
504void TCMatrix_dft::Fill(const AOBasis& auxbasis, const AOBasis& dftbasis,
505 double pair_threshold, Index build_columns) {
506 std::vector<std::vector<Index>> kept;
507 {
508 auto metric_start = std::chrono::steady_clock::now();
509 AOCoulomb auxAOcoulomb;
510 auxAOcoulomb.Fill(auxbasis);
511 inv_sqrt_ = auxAOcoulomb.Pseudo_InvSqrt(1e-8);
512 removedfunctions_ = auxAOcoulomb.Removedfunctions();
513 metric_seconds_ = std::chrono::duration<double>(
514 std::chrono::steady_clock::now() - metric_start)
515 .count();
516 kept = SignificantPairs(dftbasis, auxAOcoulomb.Matrix(), pair_threshold);
517 }
518 SetupLayout(dftbasis, kept);
519 const Index naux = auxbasis.AOBasisSize();
520 // every stored entry is written below
521 data_.resize(
522 Index(runs_.empty() ? 0 : runs_.back().offset + runs_.back().length),
523 naux);
524
525 const std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
526 const std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
527 const std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
528 const std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
529
530 // Work unit: shell a with the kept shells kept[a][first, last). Its pair
531 // columns are built for all aux functions at once, at most about
532 // build_columns of them, which bounds the scratch memory per thread.
533 struct Unit {
534 Index a;
535 Index first;
536 Index last;
537 };
538 std::vector<Unit> units;
539 Index max_rows = 0;
540 for (Index a = dftbasis.getNumofShells() - 1; a >= 0; --a) {
541 const Index na = Index(dftshells[a].size());
542 Index first = 0;
543 while (first < Index(kept[a].size())) {
544 Index last = first;
545 Index rows = 0;
546 while (last < Index(kept[a].size()) &&
547 (last == first ||
548 rows + na * Index(dftshells[kept[a][last]].size()) <=
549 build_columns)) {
550 rows += na * Index(dftshells[kept[a][last]].size());
551 ++last;
552 }
553 max_rows = std::max(max_rows, rows);
554 units.push_back({a, first, last});
555 first = last;
556 }
557 }
558
559 const Index nthreads = OPENMP::getMaxThreads();
560 std::vector<libint2::Engine> engines(nthreads);
561 engines[0] = libint2::Engine(
562 libint2::Operator::coulomb,
563 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
564 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 0);
565 engines[0].set(libint2::BraKet::xs_xx);
566 for (Index i = 1; i < nthreads; ++i) {
567 engines[i] = engines[0];
568 }
569
570#pragma omp parallel
571 {
572 libint2::Engine& engine = engines[OPENMP::getThreadId()];
573 const libint2::Engine::target_ptr_vec& buf = engine.results();
574 // rows: pair columns (nu, mu) of the unit, columns: aux functions
575 Eigen::MatrixXd raw(max_rows, naux);
576 Eigen::MatrixXd transformed(max_rows, naux);
577 std::vector<Index> row_start;
578 std::vector<Index> chunk_pos;
579
580#pragma omp for schedule(dynamic)
581 for (Index u = 0; u < Index(units.size()); ++u) {
582 const Unit& unit = units[u];
583 const libint2::Shell& shell_a = dftshells[unit.a];
584 const Index na = Index(shell_a.size());
585 const Index start_a = shell2bf[unit.a];
586 const bool has_diagonal = kept[unit.a][unit.last - 1] == unit.a;
587
588 // position of each kept shell in the unit's part of a column
589 chunk_pos.assign(1, 0);
590 for (Index k = unit.first; k < unit.last; ++k) {
591 chunk_pos.push_back(chunk_pos.back() +
592 Index(dftshells[kept[unit.a][k]].size()));
593 }
594 const Index width = chunk_pos.back();
595 // column mu = start_a + i holds width rows, fewer on the diagonal
596 row_start.assign(1, 0);
597 for (Index i = 0; i < na; ++i) {
598 const Index len = has_diagonal ? width - (na - i - 1) : width;
599 row_start.push_back(row_start.back() + len);
600 }
601 const Index rows = row_start.back();
602 raw.topRows(rows).setZero();
603
604 for (Index aux = 0; aux < Index(auxshells.size()); ++aux) {
605 const libint2::Shell& auxshell = auxshells[aux];
606 const Index aux_start = auxshell2bf[aux];
607 for (Index k = unit.first; k < unit.last; ++k) {
608 const Index b = kept[unit.a][k];
609 const libint2::Shell& shell_b = dftshells[b];
610 engine
611 .compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 0>(
612 auxshell, libint2::Shell::unit(), shell_a, shell_b);
613 if (buf[0] == nullptr) {
614 continue;
615 }
616 Eigen::TensorMap<
617 Eigen::Tensor<const double, 3, Eigen::RowMajor> const>
618 result(buf[0], auxshell.size(), shell_a.size(), shell_b.size());
619 const Index nb = Index(shell_b.size());
620 const Index pos = chunk_pos[k - unit.first];
621 for (Index i = 0; i < na; ++i) {
622 // nu <= mu
623 const Index ncol = (b == unit.a) ? std::min(nb, i + 1) : nb;
624 for (Index c = 0; c < ncol; ++c) {
625 for (Index f = 0; f < Index(auxshell.size()); ++f) {
626 raw(row_start[i] + pos + c, aux_start + f) = result(f, i, c);
627 }
628 }
629 }
630 }
631 }
632
633 // B_P = sum_Q V^-1/2_PQ (Q|..)
634 transformed.topRows(rows).noalias() =
635 raw.topRows(rows) * inv_sqrt_.transpose();
636 // unit rows of column mu continue the column after the shells before
637 Index before = 0;
638 for (Index k = 0; k < unit.first; ++k) {
639 before += Index(dftshells[kept[unit.a][k]].size());
640 }
641 for (Index i = 0; i < na; ++i) {
642 const Index len = row_start[i + 1] - row_start[i];
643 data_.block(col_offset_[start_a + i] + before, 0, len, naux) =
644 transformed.middleRows(row_start[i], len);
645 }
646 }
647 }
648}
649
650/*
651 * Determines the 3-center integrals for a given shell in the aux basis
652 * by calculating the 3-center repulsion integral of the functions in the
653 * aux shell with ALL functions in the DFT basis set
654 */
655std::vector<Eigen::MatrixXd> ComputeAO3cBlock(const libint2::Shell& auxshell,
656 const AOBasis& dftbasis,
657 libint2::Engine& engine) {
658 std::vector<Eigen::MatrixXd> ao3c = std::vector<Eigen::MatrixXd>(
659 auxshell.size(),
660 Eigen::MatrixXd::Zero(dftbasis.AOBasisSize(), dftbasis.AOBasisSize()));
661
662 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
663 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
664
665 const libint2::Engine::target_ptr_vec& buf = engine.results();
666 // alpha-loop over the "left" DFT basis function
667 for (Index row = 0; row < Index(dftshells.size()); row++) {
668
669 const libint2::Shell& shell_row = dftshells[row];
670 const Index row_start = shell2bf[row];
671 // ThreecMatrix is symmetric, restrict explicit calculation to triangular
672 // matrix
673 for (Index col = 0; col <= row; col++) {
674 const libint2::Shell& shell_col = dftshells[col];
675 const Index col_start = shell2bf[col];
676
677 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 0>(
678 auxshell, libint2::Shell::unit(), shell_col, shell_row);
679
680 if (buf[0] == nullptr) {
681 continue;
682 }
683 Eigen::TensorMap<Eigen::Tensor<const double, 3, Eigen::RowMajor> const>
684 result(buf[0], auxshell.size(), shell_col.size(), shell_row.size());
685
686 for (size_t aux_c = 0; aux_c < auxshell.size(); aux_c++) {
687 for (size_t col_c = 0; col_c < shell_col.size(); col_c++) {
688 for (size_t row_c = 0; row_c < shell_row.size(); row_c++) {
689 // ao3c is col major result is row-major so this is ideal
690 ao3c[aux_c](row_start + row_c, col_start + col_c) =
691 result(aux_c, col_c, row_c);
692 } // ROW copy
693 } // COL copy
694 } // AUX copy
695
696 } // gamma-loop
697 } // alpha-loop
698
699 for (Eigen::MatrixXd& mat : ao3c) {
700 mat.triangularView<Eigen::Upper>() =
701 mat.triangularView<Eigen::Lower>().transpose();
702 }
703 return ao3c;
704}
705
706namespace {
707// libint2 shells of a Gaussian charge (s) and a Gaussian dipole (cartesian
708// p) of exponent beta at pos, and the factors that turn the L2-normalized
709// primitives libint2 makes of them into the unit charge g (beta/pi)^3/2
710// exp(-beta r^2) and the unit dipole density 2 beta (r - R) g:
711// s: N_s = (2 beta/pi)^3/4, charge N_s (pi/beta)^3/2;
712// p: N_p = (2 beta/pi)^3/4 2 sqrt(beta).
713struct GaussianSiteShells {
714 libint2::Shell s;
715 libint2::Shell p;
716 double s_factor;
717 double p_factor;
718 GaussianSiteShells(const Eigen::Vector3d& pos, double width) {
719 const double beta = 1.0 / (width * width);
720 const std::array<double, 3> O = {pos.x(), pos.y(), pos.z()};
721 s = libint2::Shell{{beta}, {{0, false, {1.0}}}, O};
722 p = libint2::Shell{{beta}, {{1, false, {1.0}}}, O};
723 const double n_s = std::pow(2.0 * beta / M_PI, 0.75);
724 s_factor = 1.0 / (n_s * std::pow(M_PI / beta, 1.5));
725 const double n_p = n_s * 2.0 * std::sqrt(beta);
726 p_factor = 2.0 * beta * std::pow(beta / M_PI, 1.5) / n_p;
727 }
728};
729
730std::vector<libint2::Engine> GaussianSiteEngines(const AOBasis& basis) {
731 std::vector<libint2::Engine> engines(OPENMP::getMaxThreads());
732 engines[0] = libint2::Engine(libint2::Operator::coulomb,
733 int(std::max<Index>(basis.getMaxNprim(), 1)),
734 int(std::max<Index>(basis.getMaxL(), 1)), 0);
735 engines[0].set(libint2::BraKet::xs_xx);
736 for (std::size_t i = 1; i < engines.size(); ++i) {
737 engines[i] = engines[0];
738 }
739 return engines;
740}
741} // namespace
742
743Eigen::MatrixXd AOGaussianSites::Potential(const AOBasis& basis,
744 const std::vector<Source>& sources) {
745 const Index nao = basis.AOBasisSize();
746 Eigen::MatrixXd V = Eigen::MatrixXd::Zero(nao, nao);
747 for (const Source& src : sources) {
748 if (!(src.width > 0.0)) {
749 throw std::runtime_error(
750 "AOGaussianSites: Gaussian sites need a positive width");
751 }
752 }
753 std::vector<libint2::Engine> engines = GaussianSiteEngines(basis);
754#pragma omp parallel for schedule(dynamic) reduction(+ : V)
755 for (Index k = 0; k < Index(sources.size()); ++k) {
756 const Source& src = sources[std::size_t(k)];
757 const GaussianSiteShells sh(src.pos, src.width);
758 libint2::Engine& engine = engines[OPENMP::getThreadId()];
759 if (src.charge != 0.0) {
760 V +=
761 (src.charge * sh.s_factor) * ComputeAO3cBlock(sh.s, basis, engine)[0];
762 }
763 if (src.dipole.squaredNorm() > 0.0) {
764 std::vector<Eigen::MatrixXd> p = ComputeAO3cBlock(sh.p, basis, engine);
765 for (Index c = 0; c < 3; ++c) {
766 V += (src.dipole(c) * sh.p_factor) * p[std::size_t(c)];
767 }
768 }
769 }
770 return V;
771}
772
774 const AOBasis& basis, const Eigen::MatrixXd& D,
775 const std::vector<Eigen::Vector3d>& points,
776 const std::vector<double>& widths) {
777 if (widths.size() != points.size()) {
778 throw std::runtime_error(
779 "AOGaussianSites: " + std::to_string(widths.size()) + " widths for " +
780 std::to_string(points.size()) + " points");
781 }
782 const Index n = Index(points.size());
783 for (double w : widths) {
784 if (!(w > 0.0)) {
785 throw std::runtime_error(
786 "AOGaussianSites: Gaussian sites need a positive width");
787 }
788 }
789 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(n, 4);
790 std::vector<libint2::Engine> engines = GaussianSiteEngines(basis);
791#pragma omp parallel for schedule(dynamic)
792 for (Index k = 0; k < n; ++k) {
793 const GaussianSiteShells sh(points[std::size_t(k)], widths[std::size_t(k)]);
794 libint2::Engine& engine = engines[OPENMP::getThreadId()];
795 result(k, 0) =
796 sh.s_factor *
797 ComputeAO3cBlock(sh.s, basis, engine)[0].cwiseProduct(D).sum();
798 // d/dR (mn|g_R) = (mn| 2 beta (r - R) g_R): the dipole density
799 std::vector<Eigen::MatrixXd> p = ComputeAO3cBlock(sh.p, basis, engine);
800 for (Index c = 0; c < 3; ++c) {
801 result(k, 1 + c) = sh.p_factor * p[std::size_t(c)].cwiseProduct(D).sum();
802 }
803 }
804 return result;
805}
806
807namespace {
808// L * A * R evaluated in the cheaper order. For the AO->MO transformation of
809// the three-centre integrals L = C_n^T (n x N), A = (mu nu|P) (N x N) and
810// R = C_m (N x m) with m < n, so A * R first saves a factor of about n/m on
811// the dominant product.
812Eigen::MatrixXd MultiplyLeftRight(const Eigen::MatrixXd& L,
813 const Eigen::MatrixXd& A,
814 const Eigen::MatrixXd& R) {
815 const double left_first =
816 double(L.rows()) * double(A.rows()) * double(A.cols()) +
817 double(L.rows()) * double(A.cols()) * double(R.cols());
818 const double right_first =
819 double(A.rows()) * double(A.cols()) * double(R.cols()) +
820 double(L.rows()) * double(A.rows()) * double(R.cols());
821 if (right_first < left_first) {
822 return L * (A * R);
823 }
824 return (L * A) * R;
825}
826} // namespace
827
828void TCMatrix_gwbse::Fill3cMO(const AOBasis& auxbasis, const AOBasis& dftbasis,
829 const Eigen::MatrixXd& dft_orbitals) {
830
831 const Eigen::MatrixXd dftm = dft_orbitals.middleCols(mmin_, mtotal_);
832 const Eigen::MatrixXd dftn =
833 dft_orbitals.middleCols(nmin_, ntotal_).transpose();
834
835 Index nthreads = OPENMP::getMaxThreads();
836
837 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
838 std::vector<libint2::Engine> engines(nthreads);
839 engines[0] = libint2::Engine(
840 libint2::Operator::coulomb,
841 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
842 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 0);
843 engines[0].set(libint2::BraKet::xs_xx);
844 for (Index i = 1; i < nthreads; ++i) {
845 engines[i] = engines[0];
846 }
847 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
848
849#pragma omp parallel
850 {
851 Index threadid = OPENMP::getThreadId();
852#pragma omp for schedule(dynamic)
853 for (Index aux = 0; aux < Index(auxshells.size()); aux++) {
854 const libint2::Shell& auxshell = auxshells[aux];
855
856 std::vector<Eigen::MatrixXd> ao3c =
857 ComputeAO3cBlock(auxshell, dftbasis, engines[threadid]);
858
859 // AO->MO transformation of each function of the aux shell, written
860 // straight into its column of every m-slice. Each aux function is a
861 // different column, so the threads write to disjoint memory.
862 const Index dim = static_cast<Index>(ao3c.size());
863 const Index aux0 = auxshell2bf[aux];
864 for (Index k = 0; k < dim; ++k) {
865 ao3c[k] = MultiplyLeftRight(dftn, ao3c[k], dftm);
866 for (Index m_level = 0; m_level < mtotal_; m_level++) {
867 matrix_[m_level].col(aux0 + k) = ao3c[k].col(m_level);
868 }
869 ao3c[k].resize(0, 0);
870 }
871 } // shells of GW basis set
872 }
873}
874
875// EnvironmentScreening: the two functions that need libint2 engines live
876// here, so that environmentscreening.cc does not include libint2.hpp (a
877// single include of it takes 2-5 GB to compile, depending on the libint2
878// version).
879
881 const AOBasis& auxbasis, const std::vector<Eigen::Vector3d>& points,
882 const std::vector<double>& widths) {
883 if (!widths.empty() && widths.size() != points.size()) {
884 throw std::runtime_error("EnvironmentScreening::AuxFieldAtPoints: " +
885 std::to_string(widths.size()) + " widths for " +
886 std::to_string(points.size()) + " points.");
887 }
888
889 // Same shells, same function offsets, same normalization as
890 // TCMatrix_gwbse::Fill3cMO -- which is what makes the rows of F line up
891 // with the auxiliary index of the stored three-centre integrals.
892 const std::vector<libint2::Shell> shells = auxbasis.GenerateLibintBasis();
893 const std::vector<Index> shell2bf = auxbasis.getMapToBasisFunctions();
894 const Index n_points = Index(points.size());
895
896 Eigen::MatrixXd F =
897 Eigen::MatrixXd::Zero(auxbasis.AOBasisSize(), 3 * n_points);
898 if (n_points == 0 || shells.empty()) {
899 return F;
900 }
901
902 const Index nthreads = OPENMP::getMaxThreads();
903 std::vector<libint2::Engine> engines(nthreads);
904 engines[0] =
905 libint2::Engine(libint2::Operator::nuclear, int(auxbasis.getMaxNprim()),
906 int(auxbasis.getMaxL()), 0);
907 for (Index i = 1; i < nthreads; ++i) {
908 engines[i] = engines[0];
909 }
910 // Smeared sites: (chi_Q | g) with g a single s primitive, as the
911 // auxiliary metric is computed (xs_xs, unit shells on the other side).
912 std::vector<libint2::Engine> coulomb(nthreads);
913 coulomb[0] =
914 libint2::Engine(libint2::Operator::coulomb, int(auxbasis.getMaxNprim()),
915 int(auxbasis.getMaxL()), 0);
916 coulomb[0].set(libint2::BraKet::xs_xs);
917 for (Index i = 1; i < nthreads; ++i) {
918 coulomb[i] = coulomb[0];
919 }
920
921 // Four-point central difference for d/dC, error O(h^4):
922 // f'(C) = [-f(C+2h) + 8 f(C+h) - 8 f(C-h) + f(C-2h)] / (12 h)
923 const double h = 1e-3;
924 const std::array<double, 4> offset = {2.0 * h, h, -h, -2.0 * h};
925 const std::array<double, 4> weight = {-1.0 / (12.0 * h), 8.0 / (12.0 * h),
926 -8.0 / (12.0 * h), 1.0 / (12.0 * h)};
927
928 // Sign. libint2's nuclear operator with a unit charge at C is
929 // -1/|r - C|, so the integral against Shell::unit() is -phi_P(C), minus
930 // the potential of the density chi_P at C (verified against the closed
931 // form for an s-Gaussian). The field is E = -grad_C phi = +grad_C of
932 // that integral, so the stencil is applied to the raw integral as is.
933#pragma omp parallel for schedule(dynamic)
934 for (Index p = 0; p < n_points; ++p) {
935 const double width = widths.empty() ? 0.0 : widths[std::size_t(p)];
936 if (width > 0.0) {
937 // Field of chi_Q averaged over g: E = -grad_C (chi_Q | g_C), with
938 // (chi_Q | g_C) the potential of chi_Q averaged over g (positive
939 // for a positive chi_Q), so the stencil is applied with a minus.
940 // libint2 normalizes the primitive to unit L2 norm, N = (2b/pi)^3/4;
941 // dividing by its charge N (pi/b)^3/2 makes it a unit charge.
942 libint2::Engine& engine = coulomb[OPENMP::getThreadId()];
943 const libint2::Engine::target_ptr_vec& buf = engine.results();
944 const double beta = 1.0 / (width * width);
945 const double charge =
946 std::pow(2.0 * beta / M_PI, 0.75) * std::pow(M_PI / beta, 1.5);
947 for (Index k = 0; k < 3; ++k) {
948 for (std::size_t s = 0; s < offset.size(); ++s) {
949 Eigen::Vector3d C = points[std::size_t(p)];
950 C(k) += offset[s];
951 const libint2::Shell g{
952 {beta}, {{0, false, {1.0}}}, {{C.x(), C.y(), C.z()}}};
953 for (std::size_t sh = 0; sh < shells.size(); ++sh) {
954 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xs,
955 0>(shells[sh], libint2::Shell::unit(), g,
956 libint2::Shell::unit());
957 if (buf[0] == nullptr) {
958 continue;
959 }
960 const Index start = shell2bf[sh];
961 for (std::size_t f = 0; f < shells[sh].size(); ++f) {
962 F(start + Index(f), 3 * p + k) -= weight[s] * buf[0][f] / charge;
963 }
964 }
965 }
966 }
967 continue;
968 }
969 libint2::Engine& engine = engines[OPENMP::getThreadId()];
970 const libint2::Engine::target_ptr_vec& buf = engine.results();
971 for (Index k = 0; k < 3; ++k) {
972 for (std::size_t s = 0; s < offset.size(); ++s) {
973 Eigen::Vector3d C = points[std::size_t(p)];
974 C(k) += offset[s];
975 std::vector<std::pair<double, std::array<double, 3>>> charge{
976 {1.0, {C.x(), C.y(), C.z()}}};
977 engine.set_params(charge);
978 for (std::size_t sh = 0; sh < shells.size(); ++sh) {
979 engine.compute(shells[sh], libint2::Shell::unit());
980 if (buf[0] == nullptr) {
981 continue; // screened out by libint2: exactly zero
982 }
983 const Index start = shell2bf[sh];
984 for (std::size_t f = 0; f < shells[sh].size(); ++f) {
985 F(start + Index(f), 3 * p + k) += weight[s] * buf[0][f];
986 }
987 }
988 }
989 }
990 }
991 return F;
992}
993
994// Net charge of every auxiliary function, integral chi_Q d^3r: an overlap
995// integral against the unit shell, in the order and normalization of the
996// three-centre integrals (same shells, same offsets).
998 const AOBasis& auxbasis, const std::vector<Eigen::Vector3d>& points,
999 const std::vector<double>& widths) {
1000 if (widths.size() != points.size()) {
1001 throw std::runtime_error("EnvironmentScreening::AuxPotentialAtPoints: " +
1002 std::to_string(widths.size()) + " widths for " +
1003 std::to_string(points.size()) + " points.");
1004 }
1005 const std::vector<libint2::Shell> shells = auxbasis.GenerateLibintBasis();
1006 const std::vector<Index> shell2bf = auxbasis.getMapToBasisFunctions();
1007 const Index n_points = Index(points.size());
1008 Eigen::MatrixXd P = Eigen::MatrixXd::Zero(auxbasis.AOBasisSize(), n_points);
1009 if (n_points == 0 || shells.empty()) {
1010 return P;
1011 }
1012 const Index nthreads = OPENMP::getMaxThreads();
1013 std::vector<libint2::Engine> engines(nthreads);
1014 engines[0] =
1015 libint2::Engine(libint2::Operator::nuclear, int(auxbasis.getMaxNprim()),
1016 int(auxbasis.getMaxL()), 0);
1017 std::vector<libint2::Engine> coulomb(nthreads);
1018 coulomb[0] =
1019 libint2::Engine(libint2::Operator::coulomb, int(auxbasis.getMaxNprim()),
1020 int(auxbasis.getMaxL()), 0);
1021 coulomb[0].set(libint2::BraKet::xs_xs);
1022 for (Index i = 1; i < nthreads; ++i) {
1023 engines[i] = engines[0];
1024 coulomb[i] = coulomb[0];
1025 }
1026 // Signs and normalization as in AuxFieldAtPoints: the nuclear integral
1027 // against Shell::unit() with a unit charge at C is -phi_Q(C); (chi_Q|g_C)
1028 // divided by the charge of libint2's L2-normalized primitive is +phi_Q
1029 // averaged over the unit Gaussian g_C.
1030#pragma omp parallel for schedule(dynamic)
1031 for (Index p = 0; p < n_points; ++p) {
1032 const Eigen::Vector3d& C = points[std::size_t(p)];
1033 const double width = widths[std::size_t(p)];
1034 if (width > 0.0) {
1035 libint2::Engine& engine = coulomb[OPENMP::getThreadId()];
1036 const libint2::Engine::target_ptr_vec& buf = engine.results();
1037 const double beta = 1.0 / (width * width);
1038 const double charge =
1039 std::pow(2.0 * beta / M_PI, 0.75) * std::pow(M_PI / beta, 1.5);
1040 const libint2::Shell g{
1041 {beta}, {{0, false, {1.0}}}, {{C.x(), C.y(), C.z()}}};
1042 for (std::size_t sh = 0; sh < shells.size(); ++sh) {
1043 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xs, 0>(
1044 shells[sh], libint2::Shell::unit(), g, libint2::Shell::unit());
1045 if (buf[0] == nullptr) {
1046 continue;
1047 }
1048 for (std::size_t f = 0; f < shells[sh].size(); ++f) {
1049 P(shell2bf[sh] + Index(f), p) = buf[0][f] / charge;
1050 }
1051 }
1052 continue;
1053 }
1054 libint2::Engine& engine = engines[OPENMP::getThreadId()];
1055 const libint2::Engine::target_ptr_vec& buf = engine.results();
1056 std::vector<std::pair<double, std::array<double, 3>>> charge{
1057 {1.0, {C.x(), C.y(), C.z()}}};
1058 engine.set_params(charge);
1059 for (std::size_t sh = 0; sh < shells.size(); ++sh) {
1060 engine.compute(shells[sh], libint2::Shell::unit());
1061 if (buf[0] == nullptr) {
1062 continue;
1063 }
1064 for (std::size_t f = 0; f < shells[sh].size(); ++f) {
1065 P(shell2bf[sh] + Index(f), p) = -buf[0][f];
1066 }
1067 }
1068 }
1069 return P;
1070}
1071
1072Eigen::VectorXd EnvironmentScreening::AuxCharges(const AOBasis& auxbasis) {
1073 const std::vector<libint2::Shell> shells = auxbasis.GenerateLibintBasis();
1074 const std::vector<Index> shell2bf = auxbasis.getMapToBasisFunctions();
1075 Eigen::VectorXd q = Eigen::VectorXd::Zero(auxbasis.AOBasisSize());
1076 libint2::Engine engine(libint2::Operator::overlap,
1077 int(auxbasis.getMaxNprim()), int(auxbasis.getMaxL()),
1078 0);
1079 const libint2::Engine::target_ptr_vec& buf = engine.results();
1080 for (std::size_t sh = 0; sh < shells.size(); ++sh) {
1081 engine.compute(shells[sh], libint2::Shell::unit());
1082 if (buf[0] == nullptr) {
1083 continue;
1084 }
1085 for (std::size_t f = 0; f < shells[sh].size(); ++f) {
1086 q(shell2bf[sh] + Index(f)) = buf[0][f];
1087 }
1088 }
1089 return q;
1090}
1091
1092} // namespace xtp
1093} // namespace votca
Container to hold Basisfunctions for all atoms.
Definition aobasis.h:42
Index getMaxL() const
Definition aobasis.cc:29
AOShellIterator begin() const
Definition aobasis.h:49
Index AOBasisSize() const
Definition aobasis.h:46
AOShellIterator end() const
Definition aobasis.h:50
std::vector< Index > getMapToBasisFunctions() const
Definition aobasis.cc:45
Index getNumofShells() const
Definition aobasis.h:56
Index getMaxNprim() const
Definition aobasis.cc:37
std::vector< std::vector< Index > > ComputeShellPairs(double threshold=1e-20) const
std::vector< libint2::Shell > GenerateLibintBasis() const
Definition aobasis.cc:119
void Fill(const AOBasis &aobasis) final
Eigen::MatrixXd aomatrix_
Definition aomatrix.h:82
const Eigen::MatrixXd & Matrix() const
Definition aomatrix.h:72
void computeCoulombIntegrals(const AOBasis &aobasis)
Eigen::MatrixXd Pseudo_InvSqrt(double etol)
Definition aomatrix.cc:88
Index Removedfunctions() const
Definition aomatrix.h:77
std::array< Eigen::MatrixXd, 3 > aomatrix_
Definition aomatrix.h:101
std::array< libint2::Shell::real_t, 3 > r_
Definition aomatrix.h:102
void Fill(const AOBasis &aobasis) final
static Eigen::MatrixXd Potential(const AOBasis &basis, const std::vector< Source > &sources)
static Eigen::MatrixXd PotentialAndGradientAt(const AOBasis &basis, const Eigen::MatrixXd &D, const std::vector< Eigen::Vector3d > &points, const std::vector< double > &widths)
void Fill(const AOBasis &aobasis) final
Eigen::MatrixXd aomatrix_
Definition aomatrix.h:44
void Fill(const AOBasis &aobasis) final
Eigen::MatrixXd singleShellOverlap(const AOShell &shell) const
Eigen::MatrixXd aomatrix_
Definition aomatrix.h:64
libint2::Shell LibintShell() const
Definition aoshell.cc:65
Index getSize() const
Definition aoshell.h:109
Index getNumFunc() const
Definition aoshell.h:103
std::vector< std::vector< libint2::ShellPair > > shellpairdata_
Definition ERIs.h:107
std::vector< libint2::Shell > basis_
Definition ERIs.h:103
Eigen::MatrixXd ComputeSchwarzShells(const AOBasis &dftbasis) const
std::vector< std::vector< Index > > shellpairs_
Definition ERIs.h:106
std::array< Eigen::MatrixXd, 2 > Compute4c(const Eigen::MatrixXd &dmat, double error) const
Index maxL_
Definition ERIs.h:109
Eigen::MatrixXd schwarzscreen_
Definition ERIs.h:136
Eigen::MatrixXd ComputeShellBlockNorm(const Eigen::MatrixXd &dmat) const
Definition ERIs.cc:70
std::vector< Index > starts_
Definition ERIs.h:104
Index maxnprim_
Definition ERIs.h:108
static Eigen::VectorXd AuxCharges(const AOBasis &auxbasis)
static Eigen::MatrixXd AuxPotentialAtPoints(const AOBasis &auxbasis, const std::vector< Eigen::Vector3d > &points, const std::vector< double > &widths)
The electrostatic potential of each auxiliary function (as a charge density) at each point,...
static Eigen::MatrixXd AuxFieldAtPoints(const AOBasis &auxbasis, const std::vector< Eigen::Vector3d > &points, const std::vector< double > &widths={})
F: the electric field at each point produced by each auxiliary basis function, taken as a charge dens...
std::vector< Index > col_offset_
std::vector< Run > runs_
std::vector< std::vector< Index > > SignificantPairs(const AOBasis &dftbasis, const Eigen::MatrixXd &metric, double pair_threshold) const
Index size() const
Number of aux functions.
Definition threecenter.h:82
void Fill(const AOBasis &auxbasis, const AOBasis &dftbasis, double pair_threshold=0.0, Index build_columns=kBuildColumns)
void SetupLayout(const AOBasis &dftbasis, const std::vector< std::vector< Index > > &kept)
Eigen::MatrixXd data_
void Fill3cMO(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &dft_orbitals)
std::vector< Eigen::MatrixXd > matrix_
Eigen::MatrixXd inv_sqrt_
Definition threecenter.h:57
Index getMaxThreads()
Definition eigen.h:145
Index getThreadId()
Definition eigen.h:160
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MatrixLibInt
Definition aoecp.cc:56
std::vector< Eigen::MatrixXd > ComputeAO3cBlock(const libint2::Shell &auxshell, const AOBasis &dftbasis, libint2::Engine &engine)
std::array< MatrixLibInt, libint2::operator_traits< obtype >::nopers > computeOneBodyIntegrals(const AOBasis &aobasis, OperatorParams oparams=OperatorParams())
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26