votca 2026-dev
Loading...
Searching...
No Matches
bse_operator.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 <stdexcept>
22
23// Local VOTCA includes
26#include "votca/xtp/vc2index.h"
27
28namespace votca {
29namespace xtp {
30
31template <Index cqp, Index cx, Index cd, Index cd2>
33 opt_ = opt;
34 Index bse_vmax = opt_.homo;
35 bse_cmin_ = opt_.homo + 1;
36 bse_vtotal_ = bse_vmax - opt_.vmin + 1;
37 bse_ctotal_ = opt_.cmax - bse_cmin_ + 1;
39 this->set_size(bse_size_);
40}
41
42template <Index cqp, Index cx, Index cd, Index cd2>
44 const Eigen::MatrixXd& input) const {
45
46 static_assert(!(cd2 != 0 && cd != 0),
47 "Hamiltonian cannot contain Hd and Hd2 at the same time");
48
49 Index vmin = opt_.vmin - opt_.rpamin;
50 Index cmin = bse_cmin_ - opt_.rpamin;
51
52 Eigen::MatrixXd result;
53 if ((cd != 0 || cd2 != 0) && direct_cache_ != nullptr &&
54 !direct_cache_->built()) {
56 }
57 if (direct_term_cached()) {
58 result = direct_cache_->Multiply(input, -double((cd != 0) ? cd : cd2));
59 } else if (cd != 0 || cd2 != 0) {
60 result = row_kernel_ ? ApplyDirectRows(input) : ApplyDirectBlocks(input);
61 } else {
62 result = Eigen::MatrixXd::Zero(bse_size_, input.cols());
63 }
64
65 if (cqp != 0) {
67 static_cast<double>(cqp));
68 }
69 if (cx != 0) {
70 const BSEWindow window{vmin, cmin, bse_vtotal_, bse_ctotal_};
71 result += ApplyBSEExchange(Mmn_, window, Mmn_, window, input,
72 static_cast<double>(cx));
73 }
74 return result;
75}
76
77template <Index cqp, Index cx, Index cd, Index cd2>
79 const Eigen::MatrixXd& input) const {
80 vc2index vc = vc2index(0, 0, bse_ctotal_);
81 Index vmin = opt_.vmin - opt_.rpamin;
82 Index cmin = bse_cmin_ - opt_.rpamin;
83 // screened direct terms, one Hamiltonian row per (v1,c1):
84 // cd: K(c2,v2) = sum_P S(c2,P) M_{v1}(v2,P), S = -cd M_{c1}(c,:) diag(w)
85 // cd2: K(c2,v2) = sum_P M_{v1}(c2,P) S(v2,P), S = -cd2 M_{c1}(v,:) diag(w)
86 // with K flattened column-major as the row's (v2,c2) index v2*n_c + c2.
87 Eigen::MatrixXd result(bse_size_, input.cols());
88#pragma omp parallel for schedule(dynamic)
89 for (Index c1 = 0; c1 < bse_ctotal_; c1++) {
90 const Eigen::MatrixXd S =
91 (cd != 0)
92 ? Eigen::MatrixXd(-double(cd) *
93 Mmn_[c1 + cmin].middleRows(cmin, bse_ctotal_) *
94 epsilon_0_inv_.asDiagonal())
95 : Eigen::MatrixXd(-double(cd2) *
96 Mmn_[c1 + cmin].middleRows(vmin, bse_vtotal_) *
97 epsilon_0_inv_.asDiagonal());
98 Eigen::MatrixXd K(bse_ctotal_, bse_vtotal_);
99 for (Index v1 = 0; v1 < bse_vtotal_; v1++) {
100 if (cd != 0) {
101 K.noalias() =
102 S * Mmn_[v1 + vmin].middleRows(vmin, bse_vtotal_).transpose();
103 } else {
104 K.noalias() =
105 Mmn_[v1 + vmin].middleRows(cmin, bse_ctotal_) * S.transpose();
106 }
107 const Eigen::Map<const Eigen::VectorXd> row(K.data(), K.size());
108 result.row(vc.I(v1, c1)).noalias() = row.transpose() * input;
109 }
110 }
111 return result;
112}
113
114// The screened direct term in blocks of Hamiltonian rows,
115// cd: K(v1c1, v2c2) = -cd sum_P M_{c1}(c2,P) w_P M_{v1}(v2,P)
116// cd2: K(v1c1, v2c2) = -cd2 sum_P M_{c1}(v2,P) w_P M_{v1}(c2,P)
117// cd: for each c1, the rows (v1, c1) of all v1 as one (n_v x N) matrix
118// R = stacked_vv * S^T, S = -cd M_{c1}(c,:) diag(w);
119// cd2: for each v1, the rows (v1, c1) of all c1 as one (n_c x N) matrix
120// R = stacked_cv * S^T, S = -cd2 M_{v1}(c,:) diag(w).
121// R comes out row-major in the order of the BSE vectors and multiplies all
122// input vectors at once: the same flops as the row kernel, but in large
123// products, and the input is read once per block.
124template <Index cqp, Index cx, Index cd, Index cd2>
126 const Eigen::MatrixXd& input) const {
127 using RowMajorMatrix =
128 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
129 const Index vmin = opt_.vmin - opt_.rpamin;
130 const Index cmin = bse_cmin_ - opt_.rpamin;
131 const Index nv = bse_vtotal_;
132 const Index nc = bse_ctotal_;
133 const Index aux = Mmn_.auxsize();
134 const double prefactor = -double((cd != 0) ? cd : cd2);
135
136 // cd: the vv blocks of the occupied slices, row v1*n_v + v2;
137 // cd2: the cv blocks of the virtual slices, row c1*n_v + v2
138 const Index nblocks = (cd != 0) ? nc : nv;
139 const Index blockrows = (cd != 0) ? nv : nc;
140 if (stacked_.size() == 0) {
141 const Index nslice = (cd != 0) ? nv : nc;
142 const Index first_slice = (cd != 0) ? vmin : cmin;
143 stacked_.resize(nslice * nv, aux);
144#pragma omp parallel for
145 for (Index m = 0; m < nslice; m++) {
146 stacked_.middleRows(m * nv, nv) =
147 Mmn_[m + first_slice].middleRows(vmin, nv);
148 }
149 }
150
151 Eigen::MatrixXd result(bse_size_, input.cols());
152 Eigen::MatrixXd S(stacked_.rows() / blockrows, aux);
153 RowMajorMatrix T(stacked_.rows(), S.rows());
154 Eigen::MatrixXd out(blockrows, input.cols());
155 for (Index b = 0; b < nblocks; b++) {
156 // cd: b = c1, S = M_{c1}(c,:); cd2: b = v1, S = M_{v1}(c,:)
157 const Index slice = (cd != 0) ? b + cmin : b + vmin;
158 S.noalias() = prefactor * Mmn_[slice].middleRows(cmin, nc) *
159 epsilon_0_inv_.asDiagonal();
160 T.noalias() = stacked_ * S.transpose();
161 const Eigen::Map<const RowMajorMatrix> R(T.data(), blockrows, bse_size_);
162 out.noalias() = R * input;
163 if (cd != 0) {
164 for (Index v1 = 0; v1 < nv; v1++) {
165 result.row(v1 * nc + b) = out.row(v1);
166 }
167 } else {
168 result.middleRows(b * nc, nc) = out;
169 }
170 }
171 return result;
172}
173
174// The lower triangle of the direct term with unit prefactor,
175// cd: K(v1c1, v2c2) = sum_P M_{c1}(c2,P) w_P M_{v1}(v2,P)
176// cd2: K(v1c1, v2c2) = sum_P M_{c1}(v2,P) w_P M_{v1}(c2,P),
177// both symmetric since M_a(b,P) = M_b(a,P). Row r = (v1,c1) needs the
178// columns s = (v2,c2) <= r, i.e. v2 <= v1: per (c1, v1) one product over
179// v2 = 0..v1, half the flops of the full rows.
180template <Index cqp, Index cx, Index cd, Index cd2>
182 const Index kind = DirectKind();
183 if (direct_cache_->allocated() &&
184 (direct_cache_->kind() != kind || direct_cache_->size() != bse_size_)) {
185 throw std::runtime_error(
186 "BSE_OPERATOR: the shared direct-term cache holds a different "
187 "matrix");
188 }
189 const Index vmin = opt_.vmin - opt_.rpamin;
190 const Index cmin = bse_cmin_ - opt_.rpamin;
191 const Index nv = bse_vtotal_;
192 const Index nc = bse_ctotal_;
193 vc2index vc = vc2index(0, 0, nc);
194 direct_cache_->Allocate(bse_size_, kind);
195#pragma omp parallel for schedule(dynamic)
196 for (Index c1 = 0; c1 < nc; c1++) {
197 const Eigen::MatrixXd S =
198 (cd != 0) ? Eigen::MatrixXd(Mmn_[c1 + cmin].middleRows(cmin, nc) *
199 epsilon_0_inv_.asDiagonal())
200 : Eigen::MatrixXd(Mmn_[c1 + cmin].middleRows(vmin, nv) *
201 epsilon_0_inv_.asDiagonal());
202 Eigen::MatrixXd K(nc, nv);
203 for (Index v1 = 0; v1 < nv; v1++) {
204 // K(c2, v2) for v2 <= v1, column-major: element (v2, c2) of the row
205 // at v2*n_c + c2
206 auto Kv = K.leftCols(v1 + 1);
207 if (cd != 0) {
208 Kv.noalias() = S * Mmn_[v1 + vmin].middleRows(vmin, v1 + 1).transpose();
209 } else {
210 Kv.noalias() = Mmn_[v1 + vmin].middleRows(cmin, nc) *
211 S.topRows(v1 + 1).transpose();
212 }
213 direct_cache_->SetRowLower(vc.I(v1, c1), K.data());
214 }
215 }
216 direct_cache_->FinishBuild();
217}
218
219template <Index cqp, Index cx, Index cd, Index cd2>
221
222 static_assert(!(cd2 != 0 && cd != 0),
223 "Hamiltonian cannot contain Hd and Hd2 at the same time");
224
225 vc2index vc = vc2index(0, 0, bse_ctotal_);
226 Index vmin = opt_.vmin - opt_.rpamin;
227 Index cmin = bse_cmin_ - opt_.rpamin;
228
229 Eigen::VectorXd result = Eigen::VectorXd::Zero(bse_size_);
230
231#pragma omp parallel for schedule(dynamic) reduction(+ : result)
232 for (Index v = 0; v < bse_vtotal_; v++) {
233 for (Index c = 0; c < bse_ctotal_; c++) {
234
235 double entry = 0.0;
236 if (cx != 0) {
237 entry += cx * Mmn_[v + vmin].row(cmin + c).squaredNorm();
238 }
239
240 if (cqp != 0) {
241 Index cmin_qp = bse_vtotal_;
242 entry += cqp * (Hqp_(c + cmin_qp, c + cmin_qp) - Hqp_(v, v));
243 }
244 if (cd != 0) {
245 entry -=
246 cd * (Mmn_[c + cmin].row(c + cmin) * epsilon_0_inv_.asDiagonal() *
247 Mmn_[v + vmin].row(v + vmin).transpose())
248 .value();
249 }
250 if (cd2 != 0) {
251 entry -=
252 cd2 * (Mmn_[c + cmin].row(v + vmin) * epsilon_0_inv_.asDiagonal() *
253 Mmn_[v + vmin].row(c + cmin).transpose())
254 .value();
255 }
256
257 result(vc.I(v, c)) = entry;
258 }
259 }
260 return result;
261}
262
263template class BSE_OPERATOR<1, 2, 1, 0>;
264template class BSE_OPERATOR<1, 0, 1, 0>;
265
266template class BSE_OPERATOR<1, 0, 0, 0>;
267template class BSE_OPERATOR<0, 1, 0, 0>;
268template class BSE_OPERATOR<0, 0, 1, 0>;
269template class BSE_OPERATOR<0, 0, 0, 1>;
270
271template class BSE_OPERATOR<0, 2, 0, 1>;
272
273template class BSE_OPERATOR<1, 1, 1, 0>;
274template class BSE_OPERATOR<0, 1, 0, 1>;
275
276} // namespace xtp
277
278} // namespace votca
Eigen::MatrixXd stacked_
std::shared_ptr< SymmetricTiles > direct_cache_
Eigen::MatrixXd ApplyDirectRows(const Eigen::MatrixXd &input) const
const Eigen::VectorXd & epsilon_0_inv_
const Eigen::MatrixXd & Hqp_
static constexpr Index DirectKind()
Tag of the direct term an operator caches: 1 for Hd, 2 for Hd2.
void configure(BSEOperator_Options opt)
const TCMatrix_gwbse & Mmn_
Eigen::MatrixXd matmul(const Eigen::MatrixXd &input) const
Eigen::MatrixXd ApplyDirectBlocks(const Eigen::MatrixXd &input) const
BSEOperator_Options opt_
Eigen::VectorXd diagonal() const
bool direct_term_cached() const
This class transforms a pair of indices v,c into a compound index I, via I=ctotal*v+c the fast dimens...
Definition vc2index.h:36
Index I(Index v, Index c) const
Definition vc2index.h:42
Charge transport classes.
Definition ERIs.h:28
Eigen::MatrixXd ApplyBSEExchange(const TCMatrix_gwbse &Mout, const BSEWindow &out, const TCMatrix_gwbse &Min, const BSEWindow &in, const Eigen::MatrixXd &x, double prefactor)
Eigen::MatrixXd ApplyBSEQuasiparticle(const Eigen::MatrixXd &Hqp, Index vtotal, Index ctotal, const Eigen::MatrixXd &x, double prefactor)
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26