votca 2024.2-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// Local VOTCA includes
21#include "votca/xtp/ERIs.h"
22#include "votca/xtp/aobasis.h"
23#include "votca/xtp/aomatrix.h"
26
27// include libint last otherwise it overrides eigen
29#define LIBINT2_CONSTEXPR_STATICS 0
30#if defined(__clang__)
31#elif defined(__GNUC__)
32#pragma GCC diagnostic push
33#pragma GCC diagnostic ignored "-Warray-bounds"
34#endif
35#include <libint2.hpp>
36#include <libint2/statics_definition.h>
37#if defined(__clang__)
38#elif defined(__GNUC__)
39#pragma GCC diagnostic pop
40#endif
41
42namespace votca {
43namespace xtp {
44
45std::vector<std::vector<Index>> AOBasis::ComputeShellPairs(
46 double threshold) const {
47
48 Index nthreads = OPENMP::getMaxThreads();
49
50 std::vector<libint2::Shell> shells = GenerateLibintBasis();
51
52 // construct the 2-electron repulsion integrals engine
53 std::vector<libint2::Engine> engines;
54 engines.reserve(nthreads);
55 engines.emplace_back(libint2::Operator::overlap, getMaxNprim(), getMaxL(), 0);
56 for (Index i = 1; i != nthreads; ++i) {
57 engines.push_back(engines[0]);
58 }
59
60 std::vector<std::vector<Index>> pairs(shells.size());
61
62#pragma omp parallel for schedule(dynamic)
63 for (Index s1 = 0; s1 < Index(shells.size()); ++s1) {
64 Index thread_id = OPENMP::getThreadId();
65
66 libint2::Engine& engine = engines[thread_id];
67 const libint2::Engine::target_ptr_vec& buf = engine.results();
68 Index n1 = shells[s1].size();
69
70 for (Index s2 = 0; s2 <= s1; ++s2) {
71 bool on_same_center = (shells[s1].O == shells[s2].O);
72 bool significant = on_same_center;
73 if (!on_same_center) {
74 Index n2 = shells[s2].size();
75 engine.compute(shells[s1], shells[s2]);
76 Eigen::Map<const Eigen::MatrixXd> buf_mat(buf[0], n1, n2);
77 significant = (buf_mat.norm() >= threshold);
78 }
79 if (significant) {
80 pairs[s1].push_back(s2);
81 }
82 }
83 std::sort(pairs[s1].begin(), pairs[s1].end());
84 }
85 return pairs;
86}
87
88using MatrixLibInt =
89 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
90
91template <libint2::Operator obtype,
92 typename OperatorParams =
93 typename libint2::operator_traits<obtype>::oper_params_type>
94std::array<MatrixLibInt, libint2::operator_traits<obtype>::nopers>
96 OperatorParams oparams = OperatorParams()) {
97
98 Index nthreads = OPENMP::getMaxThreads();
99 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
100
101 std::vector<std::vector<Index>> shellpair_list = aobasis.ComputeShellPairs();
102
103 Index nopers = static_cast<Index>(libint2::operator_traits<obtype>::nopers);
104 std::array<MatrixLibInt, libint2::operator_traits<obtype>::nopers> result;
105 for (MatrixLibInt& r : result) {
106 r = MatrixLibInt::Zero(aobasis.AOBasisSize(), aobasis.AOBasisSize());
107 }
108
109 std::vector<libint2::Engine> engines(nthreads);
110 engines[0] = libint2::Engine(obtype, aobasis.getMaxNprim(),
111 static_cast<int>(aobasis.getMaxL()), 0);
112 engines[0].set_params(oparams);
113 for (Index i = 1; i < nthreads; ++i) {
114 engines[i] = engines[0];
115 }
116
117 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
118
119#pragma omp parallel for schedule(dynamic)
120 for (Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
121 Index thread_id = OPENMP::getThreadId();
122 libint2::Engine& engine = engines[thread_id];
123 const libint2::Engine::target_ptr_vec& buf = engine.results();
124
125 Index bf1 = shell2bf[s1];
126 Index n1 = shells[s1].size();
127
128 for (Index s2 : shellpair_list[s1]) {
129
130 engine.compute(shells[s1], shells[s2]);
131 if (buf[0] == nullptr) {
132 continue; // if all integrals screened out, skip to next shell set
133 }
134 Index bf2 = shell2bf[s2];
135 Index n2 = shells[s2].size();
136 for (unsigned int op = 0; op != nopers; ++op) {
137 Eigen::Map<const MatrixLibInt> buf_mat(buf[op], n1, n2);
138 result[op].block(bf1, bf2, n1, n2) = buf_mat;
139 if (s1 != s2) { // if s1 >= s2, copy {s1,s2} to the corresponding
140 // {s2,s1} block, note the transpose!
141 result[op].block(bf2, bf1, n2, n1) = buf_mat.transpose();
142 }
143 }
144 }
145 }
146 return result;
147}
148
149/***********************************
150 * KINETIC
151 ***********************************/
155
156/***********************************
157 * OVERLAP
158 ***********************************/
162
163Eigen::MatrixXd AOOverlap::singleShellOverlap(const AOShell& shell) const {
164 libint2::Shell::do_enforce_unit_normalization(false);
165 libint2::Operator obtype = libint2::Operator::overlap;
166 try {
167 libint2::Engine engine(obtype, shell.getSize(),
168 static_cast<int>(shell.getL()), 0);
169
170 const libint2::Engine::target_ptr_vec& buf = engine.results();
171
172 libint2::Shell s = shell.LibintShell();
173 engine.compute(s, s);
174
175 Eigen::Map<const MatrixLibInt> buf_mat(buf[0], shell.getNumFunc(),
176 shell.getNumFunc());
177 return buf_mat;
178 } catch (const libint2::Engine::lmax_exceeded& error) {
179 std::ostringstream oss;
180 oss << "\nA libint error occured:\n"
181 << error.what() << "\n"
182 << "\nYou requested a computation for a shell with angular momentum "
183 << error.lmax_requested()
184 << ",\nbut your libint package only supports angular momenta upto "
185 << error.lmax_limit() - 1 << ".\n"
186 << "\nTo fix this error you will need to reinstall libint with "
187 "support\n"
188 "for higher angular momenta. If you installed your own libint it\n"
189 "should be reconfigured and installed with the option "
190 "--with-max-am=<maxAngularMomentum>.\n"
191 "If you installed libint with your OS package manager, you will\n"
192 "need to setup you own libint installation with the \n"
193 "--with-max-am=<maxAngularMomentum> option set."
194 << std::endl;
195 throw std::runtime_error(oss.str());
196 }
197}
198
199/***********************************
200 * DIPOLE
201 ***********************************/
202void AODipole::Fill(const AOBasis& aobasis) {
203 auto results = computeOneBodyIntegrals<libint2::Operator::emultipole1,
204 std::array<libint2::Shell::real_t, 3>>(
205 aobasis, r_);
206
207 for (Index i = 0; i < 3; i++) {
208 aomatrix_[i] = results[1 + i]; // emultipole1 returns: overlap, x-dipole,
209 // y-dipole, z-dipole
210 }
211}
212
213/***********************************
214 * COULOMB
215 ***********************************/
216void AOCoulomb::Fill(const AOBasis& aobasis) {
218}
219
221 Index nthreads = OPENMP::getMaxThreads();
222 std::vector<libint2::Shell> shells = aobasis.GenerateLibintBasis();
223 std::vector<Index> shell2bf = aobasis.getMapToBasisFunctions();
224
225 aomatrix_ =
226 Eigen::MatrixXd::Zero(aobasis.AOBasisSize(), aobasis.AOBasisSize());
227
228 // build engines for each thread
229 std::vector<libint2::Engine> engines(nthreads);
230 engines[0] =
231 libint2::Engine(libint2::Operator::coulomb, aobasis.getMaxNprim(),
232 static_cast<int>(aobasis.getMaxL()), 0);
233 engines[0].set(libint2::BraKet::xs_xs);
234 for (Index i = 1; i != nthreads; ++i) {
235 engines[i] = engines[0];
236 }
237
238#pragma omp parallel for schedule(dynamic)
239 for (Index s1 = 0; s1 < aobasis.getNumofShells(); ++s1) {
240 libint2::Engine& engine = engines[OPENMP::getThreadId()];
241 const libint2::Engine::target_ptr_vec& buf = engine.results();
242
243 Index bf1 = shell2bf[s1];
244 Index n1 = shells[s1].size();
245 // cannot use shellpairs because this is still a two-center integral and
246 // overlap screening would give wrong result
247 for (Index s2 = 0; s2 <= s1; ++s2) {
248
249 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xs, 0>(
250 shells[s1], libint2::Shell::unit(), shells[s2],
251 libint2::Shell::unit());
252
253 if (buf[0] == nullptr) {
254 continue; // if all integrals screened out, skip to next shell set
255 }
256 Index bf2 = shell2bf[s2];
257 Index n2 = shells[s2].size();
258
259 Eigen::Map<const MatrixLibInt> buf_mat(buf[0], n1, n2);
260 aomatrix_.block(bf1, bf2, n1, n2) = buf_mat;
261 if (s1 != s2) { // if s1 >= s2, copy {s1,s2} to the corresponding
262 // {s2,s1} block, note the transpose!
263 aomatrix_.block(bf2, bf1, n2, n1) = buf_mat.transpose();
264 }
265 }
266 }
267}
268
269Eigen::MatrixXd ERIs::ComputeSchwarzShells(const AOBasis& basis) const {
270
271 Index noshells = basis.getNumofShells();
272
273 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(noshells, noshells);
274 Index nthreads = OPENMP::getMaxThreads();
275 std::vector<libint2::Engine> engines(nthreads);
276 double epsilon = 0.0;
277 engines[0] = libint2::Engine(libint2::Operator::coulomb, basis.getMaxNprim(),
278 static_cast<int>(basis.getMaxL()), 0, epsilon);
279
280 for (Index i = 1; i < nthreads; ++i) {
281 engines[i] = engines[0];
282 }
283
284 std::vector<libint2::Shell> shells = basis.GenerateLibintBasis();
285
286#pragma omp parallel for schedule(dynamic)
287 for (Index s1 = 0l; s1 < basis.getNumofShells(); ++s1) {
288 Index thread_id = OPENMP::getThreadId();
289 libint2::Engine& engine = engines[thread_id];
290 const libint2::Engine::target_ptr_vec& buf = engine.results();
291 Index n1 = shells[s1].size();
292
293 for (Index s2 = 0l; s2 <= s1; ++s2) {
294 Index n2 = shells[s2].size();
295 Index n12 = n1 * n2;
296
297 engines[thread_id]
298 .compute2<libint2::Operator::coulomb, libint2::BraKet::xx_xx, 0>(
299 shells[s1], shells[s2], shells[s1], shells[s2]);
300
301 Eigen::Map<const MatrixLibInt> buf_mat(buf[0], n12, n12);
302
303 result(s2, s1) = std::sqrt(buf_mat.cwiseAbs().maxCoeff());
304 }
305 }
306 return result.selfadjointView<Eigen::Upper>();
307}
308
309template <bool with_exchange>
310std::array<Eigen::MatrixXd, 2> ERIs::Compute4c(const Eigen::MatrixXd& dmat,
311 double error) const {
312 assert(schwarzscreen_.rows() > 0 && schwarzscreen_.cols() > 0 &&
313 "Please call Initialize_4c before running this");
314 Index nthreads = OPENMP::getMaxThreads();
315
316 Eigen::MatrixXd hartree = Eigen::MatrixXd::Zero(dmat.rows(), dmat.cols());
317 Eigen::MatrixXd exchange;
318 if (with_exchange) {
319 exchange = Eigen::MatrixXd::Zero(dmat.rows(), dmat.cols());
320 }
321 Eigen::MatrixXd dnorm_block = ComputeShellBlockNorm(dmat);
322 double fock_precision = error;
323 // engine precision controls primitive truncation, assume worst-case scenario
324 // (all primitive combinations add up constructively)
325 Index max_nprim4 = maxnprim_ * maxnprim_ * maxnprim_ * maxnprim_;
326 double engine_precision = std::min(fock_precision / dnorm_block.maxCoeff(),
327 std::numeric_limits<double>::epsilon()) /
328 double(max_nprim4);
329 std::vector<libint2::Engine> engines(nthreads);
330 engines[0] = libint2::Engine(libint2::Operator::coulomb, int(maxnprim_),
331 int(maxL_), 0);
332 engines[0].set_precision(engine_precision); // shellset-dependent precision
333 // control will likely break
334 // positive definiteness
335 // stick with this simple recipe
336 for (Index i = 1; i < nthreads; ++i) {
337 engines[i] = engines[0];
338 }
339 Index nshells = basis_.size();
340
341#pragma omp parallel for schedule(dynamic) reduction(+ : hartree) \
342 reduction(+ : exchange)
343 for (Index s1 = 0; s1 < nshells; ++s1) {
344 Index thread_id = OPENMP::getThreadId();
345 libint2::Engine& engine = engines[thread_id];
346 const auto& buf = engine.results();
347 Index start_1 = starts_[s1];
348 const libint2::Shell& shell1 = basis_[s1];
349 Index n1 = shell1.size();
350
351 auto sp12_iter = shellpairdata_[s1].begin();
352 for (Index s2 : shellpairs_[s1]) {
353 Index start_2 = starts_[s2];
354 const libint2::Shell& shell2 = basis_[s2];
355 Index n2 = shell2.size();
356 double dnorm_12 = dnorm_block(s1, s2);
357 const libint2::ShellPair* sp12 = &(*sp12_iter);
358 ++sp12_iter;
359
360 for (Index s3 = 0; s3 <= s1; ++s3) {
361
362 Index start_3 = starts_[s3];
363 const libint2::Shell& shell3 = basis_[s3];
364 Index n3 = shell3.size();
365 auto sp34_iter = shellpairdata_[s3].begin();
366 double dnorm_123 = std::max(dnorm_block(s1, s3),
367 std::max(dnorm_block(s2, s3), dnorm_12));
368 Index s4max = (s1 == s3) ? s2 : s3;
369 for (Index s4 : shellpairs_[s3]) {
370 if (s4 > s4max) {
371 break;
372 } // for each s3, s4 are stored in monotonically increasing
373 // order
374
375 const libint2::ShellPair* sp34 = &(*sp34_iter);
376 // must update the iter even if going to skip s4
377 ++sp34_iter;
378 double dnorm_1234 =
379 std::max(dnorm_block(s1, s4),
380 std::max(dnorm_block(s2, s4),
381 std::max(dnorm_block(s3, s4), dnorm_123)));
382
383 if (dnorm_1234 * schwarzscreen_(s1, s2) * schwarzscreen_(s3, s4) <
384 fock_precision) {
385 continue;
386 }
387
388 const libint2::Shell& shell4 = basis_[s4];
389 engine
390 .compute2<libint2::Operator::coulomb, libint2::BraKet::xx_xx, 0>(
391 shell1, shell2, shell3, shell4, sp12, sp34);
392 const auto* buf_1234 = buf[0];
393 if (buf_1234 == nullptr) {
394 continue; // if all integrals screened out, skip to next quartet
395 }
396 Index start_4 = starts_[s4];
397 Index n4 = shell4.size();
398 Index s12_deg = (s1 == s2) ? 1 : 2;
399 Index s34_deg = (s3 == s4) ? 1 : 2;
400 Index s12_34_deg = (s1 == s3) ? (s2 == s4 ? 1 : 2) : 2;
401 Index s1234_deg = s12_deg * s34_deg * s12_34_deg;
402
403 for (Index f1 = 0, f1234 = 0; f1 != n1; ++f1) {
404 const Index bf1 = f1 + start_1;
405 for (Index f2 = 0; f2 != n2; ++f2) {
406 const Index bf2 = f2 + start_2;
407 for (Index f3 = 0; f3 != n3; ++f3) {
408 const Index bf3 = f3 + start_3;
409 for (Index f4 = 0; f4 != n4; ++f4, ++f1234) {
410 const Index bf4 = f4 + start_4;
411
412 const double value = buf_1234[f1234];
413
414 const double value_scal_by_deg = value * double(s1234_deg);
415
416 hartree(bf1, bf2) += dmat(bf3, bf4) * value_scal_by_deg;
417 hartree(bf3, bf4) += dmat(bf1, bf2) * value_scal_by_deg;
418 if (with_exchange) {
419 exchange(bf1, bf3) -= dmat(bf2, bf4) * value_scal_by_deg;
420 exchange(bf2, bf3) -= dmat(bf1, bf4) * value_scal_by_deg;
421 exchange(bf2, bf4) -= dmat(bf1, bf3) * value_scal_by_deg;
422 exchange(bf1, bf4) -= dmat(bf2, bf3) * value_scal_by_deg;
423 }
424 }
425 }
426 }
427 }
428 }
429 }
430 }
431 }
432 std::array<Eigen::MatrixXd, 2> result2;
433 // 0.25=0.5(symmetrisation)*0.5(our dmat has a factor 2)
434 result2[0] = 0.25 * (hartree + hartree.transpose());
435 if (with_exchange) {
436 // prefactor
437 result2[1] = 0.125 * (exchange + exchange.transpose());
438 }
439 return result2;
440}
441
442template std::array<Eigen::MatrixXd, 2> ERIs::Compute4c<true>(
443 const Eigen::MatrixXd& dmat, double error) const;
444template std::array<Eigen::MatrixXd, 2> ERIs::Compute4c<false>(
445 const Eigen::MatrixXd& dmat, double error) const;
446
447void TCMatrix_dft::Fill(const AOBasis& auxbasis, const AOBasis& dftbasis) {
448 {
449 AOCoulomb auxAOcoulomb;
450 auxAOcoulomb.Fill(auxbasis);
451 inv_sqrt_ = auxAOcoulomb.Pseudo_InvSqrt(1e-8);
452 removedfunctions_ = auxAOcoulomb.Removedfunctions();
453 }
454 matrix_ = std::vector<Symmetric_Matrix>(auxbasis.AOBasisSize());
455
456#pragma omp parallel for schedule(dynamic, 4)
457 for (Index i = 0; i < auxbasis.AOBasisSize(); i++) {
458 matrix_[i] = Symmetric_Matrix(dftbasis.AOBasisSize());
459 }
460
461 Index nthreads = OPENMP::getMaxThreads();
462 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
463 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
464 std::vector<libint2::Engine> engines(nthreads);
465 engines[0] = libint2::Engine(
466 libint2::Operator::coulomb,
467 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
468 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 0);
469 engines[0].set(libint2::BraKet::xs_xx);
470 for (Index i = 1; i < nthreads; ++i) {
471 engines[i] = engines[0];
472 }
473
474 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
475 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
476
477#pragma omp parallel for schedule(dynamic)
478 for (Index is = dftbasis.getNumofShells() - 1; is >= 0; is--) {
479
480 libint2::Engine& engine = engines[OPENMP::getThreadId()];
481 const libint2::Engine::target_ptr_vec& buf = engine.results();
482 const libint2::Shell& dftshell = dftshells[is];
483 Index start = shell2bf[is];
484 std::vector<Eigen::MatrixXd> block(dftshell.size());
485 for (Index i = 0; i < Index(dftshell.size()); i++) {
486 Index size = start + i + 1;
487 block[i] = Eigen::MatrixXd::Zero(auxbasis.AOBasisSize(), size);
488 }
489
490 for (Index aux = 0; aux < auxbasis.getNumofShells(); aux++) {
491 const libint2::Shell& auxshell = auxshells[aux];
492 Index aux_start = auxshell2bf[aux];
493
494 for (Index dis = 0; dis <= is; dis++) {
495
496 const libint2::Shell& shell_col = dftshells[dis];
497 Index col_start = shell2bf[dis];
498 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 0>(
499 auxshell, libint2::Shell::unit(), dftshell, shell_col);
500
501 if (buf[0] == nullptr) {
502 continue;
503 }
504 Eigen::TensorMap<Eigen::Tensor<const double, 3, Eigen::RowMajor> const>
505 result(buf[0], auxshell.size(), dftshell.size(), shell_col.size());
506
507 for (size_t left = 0; left < dftshell.size(); left++) {
508 for (size_t auxf = 0; auxf < auxshell.size(); auxf++) {
509 for (size_t col = 0; col < shell_col.size(); col++) {
510 // symmetry
511 if ((col_start + col) > (start + left)) {
512 break;
513 }
514 block[left](aux_start + auxf, col_start + col) =
515 result(auxf, left, col);
516 }
517 }
518 }
519 }
520 }
521
522 for (Index i = 0; i < Index(block.size()); ++i) {
523 Eigen::MatrixXd temp = inv_sqrt_ * block[i];
524 for (Index mu = 0; mu < temp.rows(); ++mu) {
525 for (Index j = 0; j < temp.cols(); ++j) {
526 matrix_[mu](i + start, j) = temp(mu, j);
527 }
528 }
529 }
530 }
531
532 return;
533}
534
535/*
536 * Determines the 3-center integrals for a given shell in the aux basis
537 * by calculating the 3-center repulsion integral of the functions in the
538 * aux shell with ALL functions in the DFT basis set
539 */
540std::vector<Eigen::MatrixXd> ComputeAO3cBlock(const libint2::Shell& auxshell,
541 const AOBasis& dftbasis,
542 libint2::Engine& engine) {
543 std::vector<Eigen::MatrixXd> ao3c = std::vector<Eigen::MatrixXd>(
544 auxshell.size(),
545 Eigen::MatrixXd::Zero(dftbasis.AOBasisSize(), dftbasis.AOBasisSize()));
546
547 std::vector<libint2::Shell> dftshells = dftbasis.GenerateLibintBasis();
548 std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
549
550 const libint2::Engine::target_ptr_vec& buf = engine.results();
551 // alpha-loop over the "left" DFT basis function
552 for (Index row = 0; row < Index(dftshells.size()); row++) {
553
554 const libint2::Shell& shell_row = dftshells[row];
555 const Index row_start = shell2bf[row];
556 // ThreecMatrix is symmetric, restrict explicit calculation to triangular
557 // matrix
558 for (Index col = 0; col <= row; col++) {
559 const libint2::Shell& shell_col = dftshells[col];
560 const Index col_start = shell2bf[col];
561
562 engine.compute2<libint2::Operator::coulomb, libint2::BraKet::xs_xx, 0>(
563 auxshell, libint2::Shell::unit(), shell_col, shell_row);
564
565 if (buf[0] == nullptr) {
566 continue;
567 }
568 Eigen::TensorMap<Eigen::Tensor<const double, 3, Eigen::RowMajor> const>
569 result(buf[0], auxshell.size(), shell_col.size(), shell_row.size());
570
571 for (size_t aux_c = 0; aux_c < auxshell.size(); aux_c++) {
572 for (size_t col_c = 0; col_c < shell_col.size(); col_c++) {
573 for (size_t row_c = 0; row_c < shell_row.size(); row_c++) {
574 // ao3c is col major result is row-major so this is ideal
575 ao3c[aux_c](row_start + row_c, col_start + col_c) =
576 result(aux_c, col_c, row_c);
577 } // ROW copy
578 } // COL copy
579 } // AUX copy
580
581 } // gamma-loop
582 } // alpha-loop
583
584 for (Eigen::MatrixXd& mat : ao3c) {
585 mat.triangularView<Eigen::Upper>() =
586 mat.triangularView<Eigen::Lower>().transpose();
587 }
588 return ao3c;
589}
590
591void TCMatrix_gwbse::Fill3cMO(const AOBasis& auxbasis, const AOBasis& dftbasis,
592 const Eigen::MatrixXd& dft_orbitals) {
593
594 const Eigen::MatrixXd dftm = dft_orbitals.middleCols(mmin_, mtotal_);
595 const Eigen::MatrixXd dftn =
596 dft_orbitals.middleCols(nmin_, ntotal_).transpose();
597
598 OpenMP_CUDA transform;
599 transform.setOperators(dftn, dftm);
600 Index nthreads = OPENMP::getMaxThreads();
601
602 std::vector<libint2::Shell> auxshells = auxbasis.GenerateLibintBasis();
603 std::vector<libint2::Engine> engines(nthreads);
604 engines[0] = libint2::Engine(
605 libint2::Operator::coulomb,
606 std::max(dftbasis.getMaxNprim(), auxbasis.getMaxNprim()),
607 static_cast<int>(std::max(dftbasis.getMaxL(), auxbasis.getMaxL())), 0);
608 engines[0].set(libint2::BraKet::xs_xx);
609 for (Index i = 1; i < nthreads; ++i) {
610 engines[i] = engines[0];
611 }
612 std::vector<Index> auxshell2bf = auxbasis.getMapToBasisFunctions();
613
614#pragma omp parallel
615 {
616 Index threadid = OPENMP::getThreadId();
617#pragma omp for schedule(dynamic)
618 for (Index aux = 0; aux < Index(auxshells.size()); aux++) {
619 const libint2::Shell& auxshell = auxshells[aux];
620
621 std::vector<Eigen::MatrixXd> ao3c =
622 ComputeAO3cBlock(auxshell, dftbasis, engines[threadid]);
623
624 // this is basically a transpose of AO3c and at the same time the ao->mo
625 // transformation
626 // we do not want to put it into matrix_ straight away is because,
627 // matrix_ is shared between all threads and we want a nice clean access
628 // pattern to it
629 std::vector<Eigen::MatrixXd> block = std::vector<Eigen::MatrixXd>(
630 mtotal_, Eigen::MatrixXd::Zero(ntotal_, ao3c.size()));
631
632 Index dim = static_cast<Index>(ao3c.size());
633 for (Index k = 0; k < dim; ++k) {
634 transform.MultiplyLeftRight(ao3c[k], threadid);
635 for (Index i = 0; i < ao3c[k].cols(); ++i) {
636 block[i].col(k) = ao3c[k].col(i);
637 }
638 }
639
640 // put into correct position
641 for (Index m_level = 0; m_level < mtotal_; m_level++) {
642 matrix_[m_level].middleCols(auxshell2bf[aux], auxshell.size()) =
643 block[m_level];
644 } // m-th DFT orbital
645 } // shells of GW basis set
646 }
647}
648
649} // namespace xtp
650} // 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
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
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:78
std::vector< libint2::Shell > basis_
Definition ERIs.h:74
Eigen::MatrixXd ComputeSchwarzShells(const AOBasis &dftbasis) const
std::vector< std::vector< Index > > shellpairs_
Definition ERIs.h:77
std::array< Eigen::MatrixXd, 2 > Compute4c(const Eigen::MatrixXd &dmat, double error) const
Index maxL_
Definition ERIs.h:80
Eigen::MatrixXd schwarzscreen_
Definition ERIs.h:98
Eigen::MatrixXd ComputeShellBlockNorm(const Eigen::MatrixXd &dmat) const
Definition ERIs.cc:63
std::vector< Index > starts_
Definition ERIs.h:75
Index maxnprim_
Definition ERIs.h:79
void MultiplyLeftRight(Eigen::MatrixXd &matrix, Index OpenmpThread)
void setOperators(const std::vector< Eigen::MatrixXd > &tensor, const Eigen::MatrixXd &rightoperator)
void Fill(const AOBasis &auxbasis, const AOBasis &dftbasis)
std::vector< Symmetric_Matrix > matrix_
Definition threecenter.h:63
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:49
Index getMaxThreads()
Definition eigen.h:128
Index getThreadId()
Definition eigen.h:143
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())
base class for all analysis tools
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26