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