votca 2026-dev
Loading...
Searching...
No Matches
ERIs.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 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 <cmath>
23#include <vector>
24
25// Local VOTCA includes
26#include "votca/xtp/ERIs.h"
27#include "votca/xtp/aobasis.h"
30namespace votca {
31namespace xtp {
32
33void ERIs::Initialize(const AOBasis& dftbasis, const AOBasis& auxbasis,
34 double pair_threshold) {
35 threecenter_.Fill(auxbasis, dftbasis, pair_threshold);
36 return;
37}
38
39void ERIs::Initialize_4c(const AOBasis& dftbasis) {
40
41 basis_ = dftbasis.GenerateLibintBasis();
42 shellpairs_ = dftbasis.ComputeShellPairs();
44 maxnprim_ = dftbasis.getMaxNprim();
45 maxL_ = dftbasis.getMaxL();
46
48
50 return;
51}
52
53std::vector<std::vector<libint2::ShellPair>> ERIs::ComputeShellPairData(
54 const std::vector<libint2::Shell>& basis,
55 const std::vector<std::vector<Index>>& shellpairs) const {
56 std::vector<std::vector<libint2::ShellPair>> shellpairdata(basis.size());
57 const double ln_max_engine_precision =
58 std::log(std::numeric_limits<double>::epsilon() * 1e-10);
59
60#pragma omp parallel for schedule(dynamic)
61 for (Index s1 = 0; s1 < Index(shellpairs.size()); s1++) {
62 for (Index s2 : shellpairs[s1]) {
63 shellpairdata[s1].emplace_back(
64 libint2::ShellPair(basis[s1], basis[s2], ln_max_engine_precision));
65 }
66 }
67 return shellpairdata;
68}
69
70Eigen::MatrixXd ERIs::ComputeShellBlockNorm(const Eigen::MatrixXd& dmat) const {
71 Eigen::MatrixXd result =
72 Eigen::MatrixXd::Zero(starts_.size(), starts_.size());
73#pragma omp parallel for schedule(dynamic)
74 for (Index s1 = 0l; s1 < Index(basis_.size()); ++s1) {
75 Index bf1 = starts_[s1];
76 Index n1 = basis_[s1].size();
77 for (Index s2 = 0l; s2 <= s1; ++s2) {
78 Index bf2 = starts_[s2];
79 Index n2 = basis_[s2].size();
80
81 result(s2, s1) = dmat.block(bf2, bf1, n2, n1).cwiseAbs().maxCoeff();
82 }
83 }
84 return result.selfadjointView<Eigen::Upper>();
85}
86
87// J[D]_mu nu = sum_P B_P,mu nu c_P with c_P = sum_kl B_P,kl D_kl: two
88// matrix-vector products with the stored pair x aux tensor.
89Eigen::MatrixXd ERIs::CalculateERIs_3c(const Eigen::MatrixXd& DMAT) const {
90 assert(threecenter_.size() > 0 &&
91 "Please call Initialize before running this");
92 const Eigen::MatrixXd& data = threecenter_.Data();
93 // lower triangle of DMAT, as before
94 const Eigen::VectorXd dpacked = threecenter_.PackWeighted(DMAT);
95 Eigen::VectorXd c(data.cols());
96#pragma omp parallel for schedule(static)
97 for (Index P = 0; P < data.cols(); ++P) {
98 c(P) = data.col(P).dot(dpacked);
99 }
100 Eigen::VectorXd jpacked(data.rows());
101 const Index nblocks = std::max<Index>(1, OPENMP::getMaxThreads()) * 8;
102 const Index blocksize = (data.rows() + nblocks - 1) / nblocks;
103#pragma omp parallel for schedule(static)
104 for (Index blk = 0; blk < nblocks; ++blk) {
105 const Index row = blk * blocksize;
106 const Index len = std::min(blocksize, data.rows() - row);
107 if (len > 0) {
108 jpacked.segment(row, len).noalias() = data.middleRows(row, len) * c;
109 }
110 }
111 return threecenter_.Unpack(jpacked);
112}
113
114// K[D] = -sum_P B_P D B_P is linear in D. Writing D = X X^T - Y Y^T from
115// its eigendecomposition turns every term into products with N x rank(D)
116// factors -- the work of the occupied-MO route -- instead of two N^3
117// products per aux function. Any symmetric D is handled exactly, including
118// indefinite ones (incremental differences); the gain comes from the low
119// rank of the densities the SCF produces: a density mixed from idempotent
120// ones has at most a few times as many nonzero eigenvalues as there are
121// occupied orbitals.
122Eigen::MatrixXd ERIs::CalculateEXX_dmat(const Eigen::MatrixXd& DMAT) const {
123 assert(threecenter_.size() > 0 &&
124 "Please call Initialize before running this");
125 Eigen::MatrixXd EXX = Eigen::MatrixXd::Zero(DMAT.rows(), DMAT.cols());
126
127 const SymmetricEigenSystem es =
128 SymmetricEigen(0.5 * (DMAT + DMAT.transpose()));
129 const Eigen::VectorXd& lambda = es.values;
130 if (lambda.size() == 0) {
131 return EXX;
132 }
133 // Eigenvalues below this are rounding noise of a lower-rank matrix.
134 const double cutoff = kDensityRankCutoff * lambda.cwiseAbs().maxCoeff();
135 std::vector<Index> positive;
136 std::vector<Index> negative;
137 for (Index k = 0; k < lambda.size(); ++k) {
138 if (lambda(k) > cutoff) {
139 positive.push_back(k);
140 } else if (lambda(k) < -cutoff) {
141 negative.push_back(k);
142 }
143 }
144 const Index npos = Index(positive.size());
145 const Index nneg = Index(negative.size());
146 if (npos + nneg == 0) {
147 return EXX;
148 }
149 // columns: sqrt(|lambda_k|) u_k, positive eigenvalues first
150 Eigen::MatrixXd factors(DMAT.rows(), npos + nneg);
151 for (Index c = 0; c < npos; ++c) {
152 const Index k = positive[c];
153 factors.col(c) = std::sqrt(lambda(k)) * es.vectors.col(k);
154 }
155 for (Index c = 0; c < nneg; ++c) {
156 const Index k = negative[c];
157 factors.col(npos + c) = std::sqrt(-lambda(k)) * es.vectors.col(k);
158 }
159 return ExchangeFromFactors(factors, npos);
160}
161
162Eigen::MatrixXd ERIs::CalculateEXX_mos(const Eigen::MatrixXd& occMos) const {
163 assert(threecenter_.size() > 0 &&
164 "Please call Initialize before running this");
165 // D = 2 C C^T
166 return ExchangeFromFactors(std::sqrt(2.0) * occMos, occMos.cols());
167}
168
169// Each aux function contributes (B_P X)(B_P X)^T. Per thread, B_P is unpacked
170// into one reused buffer, B_P X is formed with a plain matrix product, and
171// the rows of several aux functions are stacked so that the N x N
172// accumulator is touched by one rank update per batch instead of once per
173// aux function.
174Eigen::MatrixXd ERIs::ExchangeFromFactors(const Eigen::MatrixXd& factors,
175 Index npos) const {
176 const Index n = factors.rows();
177 const Index nneg = factors.cols() - npos;
178 Eigen::MatrixXd EXX = Eigen::MatrixXd::Zero(n, n);
179 if (factors.cols() == 0) {
180 return EXX;
181 }
182 const Index batch =
183 std::max<Index>(1, kExchangeBatchRows / std::max(npos, nneg));
184 const Eigen::MatrixXd xt = factors.leftCols(npos).transpose();
185 const Eigen::MatrixXd yt = factors.rightCols(nneg).transpose();
186
187#pragma omp parallel
188 {
189 Eigen::MatrixXd local = Eigen::MatrixXd::Zero(n, n);
190 // entries of screened pairs are never written and stay zero
191 Eigen::MatrixXd b = Eigen::MatrixXd::Zero(n, n);
192 Eigen::MatrixXd tx(batch * npos, n);
193 Eigen::MatrixXd ty(batch * nneg, n);
194 Index filled = 0;
195 auto flush = [&]() {
196 if (filled == 0) {
197 return;
198 }
199 local.selfadjointView<Eigen::Lower>().rankUpdate(
200 tx.topRows(filled * npos).transpose(), -1.0);
201 if (nneg > 0) {
202 local.selfadjointView<Eigen::Lower>().rankUpdate(
203 ty.topRows(filled * nneg).transpose(), 1.0);
204 }
205 filled = 0;
206 };
207#pragma omp for schedule(dynamic)
208 for (Index i = 0; i < threecenter_.size(); i++) {
209 threecenter_.FillFullMatrix(i, b);
210 if (npos > 0) {
211 tx.middleRows(filled * npos, npos).noalias() = xt * b;
212 }
213 if (nneg > 0) {
214 ty.middleRows(filled * nneg, nneg).noalias() = yt * b;
215 }
216 if (++filled == batch) {
217 flush();
218 }
219 }
220 flush();
221#pragma omp critical
222 {
223 EXX.triangularView<Eigen::Lower>() += local;
224 }
225 }
226 return EXX.selfadjointView<Eigen::Lower>();
227}
228
229} // namespace xtp
230} // namespace votca
Container to hold Basisfunctions for all atoms.
Definition aobasis.h:42
Index getMaxL() const
Definition aobasis.cc:29
std::vector< Index > getMapToBasisFunctions() const
Definition aobasis.cc:45
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
Eigen::MatrixXd CalculateERIs_3c(const Eigen::MatrixXd &DMAT) const
Definition ERIs.cc:89
void Initialize(const AOBasis &dftbasis, const AOBasis &auxbasis, double pair_threshold=0.0)
Definition ERIs.cc:33
std::vector< std::vector< libint2::ShellPair > > shellpairdata_
Definition ERIs.h:95
std::vector< libint2::Shell > basis_
Definition ERIs.h:91
Eigen::MatrixXd ComputeSchwarzShells(const AOBasis &dftbasis) const
static constexpr double kDensityRankCutoff
Definition ERIs.h:101
std::vector< std::vector< Index > > shellpairs_
Definition ERIs.h:94
static constexpr Index kExchangeBatchRows
Rows of B_P X collected per thread before one rank update.
Definition ERIs.h:109
void Initialize_4c(const AOBasis &dftbasis)
Definition ERIs.cc:39
Index maxL_
Definition ERIs.h:97
std::vector< std::vector< libint2::ShellPair > > ComputeShellPairData(const std::vector< libint2::Shell > &basis, const std::vector< std::vector< Index > > &shellpairs) const
Definition ERIs.cc:53
Eigen::MatrixXd ExchangeFromFactors(const Eigen::MatrixXd &factors, Index npos) const
Definition ERIs.cc:174
Eigen::MatrixXd schwarzscreen_
Definition ERIs.h:124
Eigen::MatrixXd ComputeShellBlockNorm(const Eigen::MatrixXd &dmat) const
Definition ERIs.cc:70
std::vector< Index > starts_
Definition ERIs.h:92
Eigen::MatrixXd CalculateEXX_dmat(const Eigen::MatrixXd &DMAT) const
Definition ERIs.cc:122
TCMatrix_dft threecenter_
Definition ERIs.h:122
Index maxnprim_
Definition ERIs.h:96
Eigen::MatrixXd CalculateEXX_mos(const Eigen::MatrixXd &occMos) const
Definition ERIs.cc:162
Index getMaxThreads()
Definition eigen.h:145
Charge transport classes.
Definition ERIs.h:28
SymmetricEigenSystem SymmetricEigen(const Eigen::MatrixXd &A, bool vectors=true)
With vectors = false only the eigenvalues are computed.
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26