votca 2026-dev
Loading...
Searching...
No Matches
threecenter.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// Local VOTCA includes
21// Standard includes
22#include <algorithm>
23#include <cassert>
24#include <stdexcept>
25#include <string>
26
27#include "votca/xtp/aomatrix.h"
30
31namespace votca {
32namespace xtp {
33
34Eigen::MatrixXd TCMatrix_gwbse::CoreExchange(const AOBasis& auxbasis,
35 const AOBasis& dftbasis,
36 const Eigen::MatrixXd& mos,
37 Index ncore, Index qpmin,
38 Index qpmax) {
39 const Index qptotal = qpmax - qpmin + 1;
40 Eigen::MatrixXd X = Eigen::MatrixXd::Zero(qptotal, qptotal);
41 if (ncore <= 0 || qptotal <= 0) {
42 return X;
43 }
44 // (m c | P) for m in the GW window, c in the core: freshly filled, so in
45 // the orthogonal auxiliary frame where the bare v is M M^T
47 Mc.Initialize(auxbasis.AOBasisSize(), qpmin, qpmax, 0, ncore - 1);
48 Mc.Fill(auxbasis, dftbasis, mos);
49 Eigen::MatrixXd Z(qptotal, Mc.auxsize());
50 for (Index c = 0; c < ncore; ++c) {
51 for (Index m = 0; m < qptotal; ++m) {
52 Z.row(m) = Mc[m].row(c);
53 }
54 X.selfadjointView<Eigen::Upper>().rankUpdate(Z, -1.0);
55 }
56 return X.selfadjointView<Eigen::Upper>();
57}
58
59void TCMatrix_gwbse::Initialize(Index basissize, Index mmin, Index mmax,
60 Index nmin, Index nmax) {
61
62 // here as storage indices starting from zero
63 nmin_ = nmin;
64 nmax_ = nmax;
65 ntotal_ = nmax - nmin + 1;
66 mmin_ = mmin;
67 mmax_ = mmax;
68 mtotal_ = mmax - mmin + 1;
69 auxbasissize_ = basissize;
70
71 // vector has mtotal elements
72 // largest object should be allocated in multithread fashion
73 matrix_ = std::vector<Eigen::MatrixXd>(mtotal_);
74#pragma omp parallel for schedule(dynamic, 4)
75 for (Index i = 0; i < mtotal_; i++) {
76 matrix_[i] = Eigen::MatrixXd::Zero(ntotal_, auxbasissize_);
77 }
78}
79
80/*
81 * Modify 3-center matrix elements consistent with use of symmetrized
82 * Coulomb interaction.
83 */
84void TCMatrix_gwbse::MultiplyRightWithAuxMatrix(const Eigen::MatrixXd& matrix) {
85#pragma omp parallel for schedule(dynamic)
86 for (Index i = 0; i < msize(); i++) {
87 matrix_[i] *= matrix;
88 }
89 if (matrix.rows() != matrix.cols()) {
90 aux_frame_known_ = false; // a projection, not a change of frame
91 aux_frame_.resize(0, 0);
92 } else if (aux_frame_known_) {
93 aux_frame_ = (aux_frame_.size() == 0) ? matrix : aux_frame_ * matrix;
94 }
95}
96
98 Index full_slices,
99 Index lead) {
100 if (U.rows() != U.cols()) {
102 return;
103 }
104 const Index lead_rows = std::clamp<Index>(lead, 0, nsize());
105 const Index lead_slices = std::clamp<Index>(lead, 0, msize());
106 full_slices = std::clamp<Index>(full_slices, 0, lead_slices);
107#pragma omp parallel for schedule(dynamic)
108 for (Index i = 0; i < lead_slices; i++) {
109 const Index rows = (i < full_slices) ? nsize() : lead_rows;
110 Eigen::MatrixXd rotated = matrix_[i].topRows(rows) * U;
111 matrix_[i].topRows(rows) = rotated;
112 }
113 if (aux_frame_known_) {
114 aux_frame_ = (aux_frame_.size() == 0) ? U : aux_frame_ * U;
115 }
116 if (full_slices < msize() && (lead_slices < msize() || lead_rows < nsize())) {
117 partially_rotated_ = true;
118 }
119}
120
122 if (!aux_frame_known_) {
123 return false;
124 }
125 if (aux_frame_.size() == 0) {
126 return true;
127 }
128 const Index n = aux_frame_.rows();
129 return (aux_frame_.transpose() * aux_frame_ - Eigen::MatrixXd::Identity(n, n))
130 .cwiseAbs()
131 .maxCoeff() < 1e-10;
132}
133
134void TCMatrix_gwbse::MultiplyInFillFrame(const Eigen::MatrixXd& A) {
135 if (partially_rotated_) {
136 throw std::runtime_error(
137 "TCMatrix_gwbse: cannot dress the auxiliary index after only part of "
138 "the tensor was rotated (MultiplyRightWithAuxMatrixLeading). Rebuild "
139 "first.");
140 }
141 if (!aux_frame_known_) {
142 throw std::runtime_error(
143 "TCMatrix_gwbse: cannot dress the auxiliary index after a non-square "
144 "MultiplyRightWithAuxMatrix. Rebuild first.");
145 }
146 if (aux_frame_.size() == 0) {
148 return;
149 }
150 // M_fill F X = M_fill A F => X = F^-1 A F. The frame becomes A F.
151 const Eigen::PartialPivLU<Eigen::MatrixXd> lu(aux_frame_);
153}
154
155void TCMatrix_gwbse::DressAuxIndex(const Eigen::MatrixXd& S) {
156 if (Dressed()) {
157 throw std::runtime_error(
158 "TCMatrix_gwbse::DressAuxIndex: already dressed. Undress first.");
159 }
160 if (S.rows() != auxbasissize_ || S.cols() != auxbasissize_) {
161 throw std::runtime_error(
162 "TCMatrix_gwbse::DressAuxIndex: S is " + std::to_string(S.rows()) +
163 "x" + std::to_string(S.cols()) + ", auxiliary basis has " +
164 std::to_string(auxbasissize_) + " functions.");
165 }
167 dressing_ = S;
168}
169
171 if (!Dressed()) {
172 return;
173 }
175 dressing_.resize(0, 0);
176}
177
179 const Eigen::MatrixXd& K) const {
180 if (!aux_frame_known_) {
181 throw std::runtime_error(
182 "TCMatrix_gwbse::ToCurrentAuxFrame: the auxiliary index of the "
183 "three-centre integrals was multiplied by a non-square matrix, so "
184 "there is no frame to bring the kernel into. Apply it before that, "
185 "or Rebuild.");
186 }
187 if (aux_frame_.size() == 0) {
188 return K;
189 }
190 if (K.rows() != aux_frame_.rows() || K.cols() != aux_frame_.rows()) {
191 throw std::runtime_error(
192 "TCMatrix_gwbse::ToCurrentAuxFrame: kernel is " +
193 std::to_string(K.rows()) + "x" + std::to_string(K.cols()) +
194 ", auxiliary frame is " + std::to_string(aux_frame_.rows()) + "x" +
195 std::to_string(aux_frame_.cols()) + ".");
196 }
197 const Index n = aux_frame_.rows();
198 const double off_orthogonal =
199 (aux_frame_.transpose() * aux_frame_ - Eigen::MatrixXd::Identity(n, n))
200 .cwiseAbs()
201 .maxCoeff();
202 Eigen::MatrixXd result;
203 if (off_orthogonal < 1e-10) {
204 result = aux_frame_.transpose() * K * aux_frame_;
205 } else {
206 const Eigen::PartialPivLU<Eigen::MatrixXd> lu(aux_frame_);
207 const Eigen::MatrixXd X = lu.solve(K); // F^-1 K
208 result = lu.solve(Eigen::MatrixXd(X.transpose())).transpose();
209 }
210 return result;
211}
212/*
213 * Fill the 3-center object by looping over shells of GW basis set and
214 * calling FillBlock, which calculates all 3-center overlap integrals
215 * associated to a particular shell, convoluted with the DFT orbital
216 * coefficients
217 */
218void TCMatrix_gwbse::Fill(const AOBasis& auxbasis, const AOBasis& dftbasis,
219 const Eigen::MatrixXd& dft_orbitals) {
220 // needed for Rebuild())
221 auxbasis_ = &auxbasis;
222 dftbasis_ = &dftbasis;
223 dft_orbitals_ = &dft_orbitals;
224
225 Fill3cMO(auxbasis, dftbasis, dft_orbitals);
226
227 AOOverlap auxoverlap;
228 auxoverlap.Fill(auxbasis);
229 AOCoulomb auxcoulomb;
230 auxcoulomb.Fill(auxbasis);
231 inv_sqrt_ = auxcoulomb.Pseudo_InvSqrt_GWBSE(auxoverlap, metric_tolerance);
232 removedfunctions_ = auxcoulomb.Removedfunctions();
234 // What Fill leaves behind is the reference frame by definition.
235 aux_frame_.resize(0, 0);
236 aux_frame_known_ = true;
237 partially_rotated_ = false;
238 dressing_.resize(0, 0);
239
240 return;
241}
242
243void TCMatrix_gwbse::RotateOrbitals(const Eigen::MatrixXd& U, Index first,
244 Index last) {
245 const Index window = last - first + 1;
246 assert(first >= nmin_ && last <= nmax_);
247 assert(first >= mmin_ && last <= mmax_);
248 assert(U.rows() == window && U.cols() == window);
249 const Index row0 = first - nmin_;
250 const Index slice0 = first - mmin_;
251 const Index rows = matrix_.empty() ? 0 : Index(matrix_[0].rows());
252 const Index aux = matrix_.empty() ? 0 : Index(matrix_[0].cols());
253
254 // second index, every slice
255 const Eigen::MatrixXd Ut = U.transpose();
256#pragma omp parallel for schedule(dynamic)
257 for (Index m = 0; m < Index(matrix_.size()); m++) {
258 auto block = matrix_[m].middleRows(row0, window);
259 block = Ut * block;
260 }
261
262 // first index: the slices of the window as columns of one matrix, in
263 // chunks of auxiliary columns (contiguous in each slice) of about 64 MB
264 const Index chunk = std::max<Index>(
265 1, std::min<Index>(aux, Index(8e6 / double(rows * window + 1))));
266 Eigen::MatrixXd X;
267 Eigen::MatrixXd Y;
268 for (Index c0 = 0; c0 < aux; c0 += chunk) {
269 const Index nc = std::min(chunk, aux - c0);
270 const Index len = rows * nc;
271 X.resize(len, window);
272#pragma omp parallel for
273 for (Index k = 0; k < window; k++) {
274 X.col(k) = Eigen::Map<const Eigen::VectorXd>(
275 matrix_[slice0 + k].col(c0).data(), len);
276 }
277 Y.noalias() = X * U;
278#pragma omp parallel for
279 for (Index i = 0; i < window; i++) {
280 Eigen::Map<Eigen::VectorXd>(matrix_[slice0 + i].col(c0).data(), len) =
281 Y.col(i);
282 }
283 }
284}
285
287 const std::vector<std::vector<Index>>& kept) {
288 basissize_ = dftbasis.AOBasisSize();
289 const std::vector<Index> shell2bf = dftbasis.getMapToBasisFunctions();
290 runs_.clear();
291 col_offset_.assign(basissize_, 0);
292 Index offset = 0;
293 for (Index a = 0; a < Index(kept.size()); ++a) {
294 const Index start = shell2bf[a];
295 const Index size = dftbasis.getShell(a).getNumFunc();
296 for (Index i = 0; i < size; ++i) {
297 const Index mu = start + i;
298 col_offset_[mu] = offset;
299 // merge neighbouring kept shells into one run of rows
300 Index k = 0;
301 while (k < Index(kept[a].size())) {
302 Index b_first = kept[a][k];
303 Index b_last = b_first;
304 while (k + 1 < Index(kept[a].size()) && kept[a][k + 1] == b_last + 1) {
305 ++k;
306 b_last = kept[a][k];
307 }
308 ++k;
309 const Index row = shell2bf[b_first];
310 const Index end = std::min(
311 shell2bf[b_last] + dftbasis.getShell(b_last).getNumFunc(), mu + 1);
312 runs_.push_back({mu, row, end - row, offset});
313 offset += end - row;
314 }
315 }
316 }
317}
318
319void TCMatrix_dft::FillFullMatrix(Index P, Eigen::MatrixXd& full) const {
320 assert(full.rows() == basissize_ && full.cols() == basissize_);
321 const double* src = data_.col(P).data();
322 for (const Run& r : runs_) {
323 std::copy(src + r.offset, src + r.offset + r.length,
324 full.data() + r.col * basissize_ + r.row);
325 }
326 full.triangularView<Eigen::StrictlyLower>() = full.transpose();
327}
328
329Eigen::MatrixXd TCMatrix_dft::FullMatrix(Index P) const {
330 Eigen::MatrixXd full = Eigen::MatrixXd::Zero(basissize_, basissize_);
331 FillFullMatrix(P, full);
332 return full;
333}
334
335Eigen::VectorXd TCMatrix_dft::PackWeighted(const Eigen::MatrixXd& full) const {
336 assert(full.rows() == basissize_ && full.cols() == basissize_);
337 Eigen::VectorXd packed(data_.rows());
338 for (const Run& r : runs_) {
339 for (Index k = 0; k < r.length; ++k) {
340 const Index row = r.row + k;
341 packed(r.offset + k) =
342 (row == r.col) ? full(r.col, row) : 2.0 * full(r.col, row);
343 }
344 }
345 return packed;
346}
347
348Eigen::MatrixXd TCMatrix_dft::Unpack(const Eigen::VectorXd& packed) const {
349 assert(packed.size() == data_.rows());
350 Eigen::MatrixXd full = Eigen::MatrixXd::Zero(basissize_, basissize_);
351 for (const Run& r : runs_) {
352 full.block(r.row, r.col, r.length, 1) = packed.segment(r.offset, r.length);
353 }
354 full.triangularView<Eigen::StrictlyLower>() = full.transpose();
355 return full;
356}
357
358} // namespace xtp
359} // namespace votca
Container to hold Basisfunctions for all atoms.
Definition aobasis.h:42
Index AOBasisSize() const
Definition aobasis.h:46
std::vector< Index > getMapToBasisFunctions() const
Definition aobasis.cc:45
const AOShell & getShell(Index idx) const
Definition aobasis.h:52
void Fill(const AOBasis &aobasis) final
Index Removedfunctions() const
Definition aomatrix.h:77
Eigen::MatrixXd Pseudo_InvSqrt_GWBSE(const AOOverlap &auxoverlap, double etol)
Definition aomatrix.cc:54
void Fill(const AOBasis &aobasis) final
Index getNumFunc() const
Definition aoshell.h:103
std::vector< Index > col_offset_
std::vector< Run > runs_
Index size() const
Number of aux functions.
Definition threecenter.h:82
Eigen::VectorXd PackWeighted(const Eigen::MatrixXd &full) const
Eigen::MatrixXd FullMatrix(Index P) const
B_P as a full symmetric matrix, zero for the dropped pairs.
void SetupLayout(const AOBasis &dftbasis, const std::vector< std::vector< Index > > &kept)
void FillFullMatrix(Index P, Eigen::MatrixXd &full) const
Eigen::MatrixXd Unpack(const Eigen::VectorXd &packed) const
Eigen::MatrixXd data_
void Fill(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &dft_orbitals)
const AOBasis * auxbasis_
static constexpr double metric_tolerance
void DressAuxIndex(const Eigen::MatrixXd &S)
Dress the auxiliary index with S: M_fill -> M_fill S.
void MultiplyRightWithAuxMatrixLeading(const Eigen::MatrixXd &U, Index full_slices, Index lead)
Rotate the auxiliary index of only the part of the tensor a consumer reads: all rows of slices [0,...
Eigen::MatrixXd aux_frame_
Eigen::MatrixXd dressing_
const Eigen::MatrixXd * dft_orbitals_
bool AuxFrameIsOrthogonal() const
void Fill3cMO(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &dft_orbitals)
void Initialize(Index basissize, Index mmin, Index mmax, Index nmin, Index nmax)
void MultiplyRightWithAuxMatrix(const Eigen::MatrixXd &matrix)
std::vector< Eigen::MatrixXd > matrix_
static Eigen::MatrixXd CoreExchange(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &mos, Index ncore, Index qpmin, Index qpmax)
void RotateOrbitals(const Eigen::MatrixXd &U, Index first, Index last)
Change the orbital basis of levels [first, last] for QSGW: phi_i = sum_k U_ki psi_k,...
const AOBasis * dftbasis_
void MultiplyInFillFrame(const Eigen::MatrixXd &A)
Eigen::MatrixXd ToCurrentAuxFrame(const Eigen::MatrixXd &K) const
Eigen::MatrixXd inv_sqrt_
Definition threecenter.h:57
Charge transport classes.
Definition ERIs.h:28
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26