votca 2026-dev
Loading...
Searching...
No Matches
bse_operator_uks.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2026 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
21
22namespace votca {
23namespace xtp {
24
25template <Index cqp, Index cx, Index cd, Index cd2>
27 Index homo, Index offset) {
28 blk.homo = homo;
29 blk.vmin_rpa = opt_.vmin - opt_.rpamin;
30 blk.cmin_rpa = homo + 1 - opt_.rpamin;
31 blk.vtotal = homo - opt_.vmin + 1;
32 blk.ctotal = opt_.cmax - (homo + 1) + 1;
33 blk.size = blk.vtotal * blk.ctotal;
34 blk.offset = offset;
35}
36
37template <Index cqp, Index cx, Index cd, Index cd2>
39 opt_ = opt;
40 setup_block(alpha_, opt_.homo_alpha, 0);
41 setup_block(beta_, opt_.homo_beta, alpha_.size);
42 size_total_ = alpha_.size + beta_.size;
43 this->set_size(size_total_);
44}
45
46template <Index cqp, Index cx, Index cd, Index cd2>
48 const Eigen::MatrixXd& Hqp, const SpinBlockInfo& blk, Index v1,
49 Index c1) const {
50 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(blk.ctotal, blk.vtotal);
51 Index cmin_qp = blk.vtotal;
52 result.col(v1) += Hqp.col(c1 + cmin_qp).segment(cmin_qp, blk.ctotal);
53 result.row(c1) -= Hqp.col(v1).head(blk.vtotal).transpose();
54 return Eigen::Map<Eigen::VectorXd>(result.data(), result.size());
55}
56
57template <Index cqp, Index cx, Index cd, Index cd2>
59 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& blk,
60 const Eigen::MatrixXd& Hqp) const {
61 if (cqp == 0) {
62 return;
63 }
64
65 for (Index c1 = 0; c1 < blk.ctotal; ++c1) {
66 for (Index v1 = 0; v1 < blk.vtotal; ++v1) {
67 const Index out_idx = v1 * blk.ctotal + c1;
68 Eigen::VectorXd row = Hqp_row(Hqp, blk, v1, c1);
69 y.row(out_idx) += row.transpose() * x;
70 }
71 }
72}
73
74template <Index cqp, Index cx, Index cd, Index cd2>
76 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& out_blk,
77 const SpinBlockInfo& in_blk, const TCMatrix_gwbse& Mout,
78 const TCMatrix_gwbse& Min, double prefactor) const {
79 if (cx == 0 || prefactor == 0.0) {
80 return;
81 }
82
83 for (Index v1 = 0; v1 < out_blk.vtotal; ++v1) {
84 const Eigen::MatrixXd left =
85 prefactor * Mout[v1 + out_blk.vmin_rpa].middleRows(out_blk.cmin_rpa,
86 out_blk.ctotal);
87
88 for (Index v2 = 0; v2 < in_blk.vtotal; ++v2) {
89 const Eigen::MatrixXd right =
90 Min[v2 + in_blk.vmin_rpa].middleRows(in_blk.cmin_rpa, in_blk.ctotal);
91
92 const Eigen::MatrixXd block = left * right.transpose();
93 const Index out_row0 = v1 * out_blk.ctotal;
94 const Index in_row0 = v2 * in_blk.ctotal;
95 y.middleRows(out_row0, out_blk.ctotal) +=
96 block * x.middleRows(in_row0, in_blk.ctotal);
97 }
98 }
99}
100
101template <Index cqp, Index cx, Index cd, Index cd2>
103 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& out_blk,
104 const SpinBlockInfo& in_blk, const TCMatrix_gwbse& Mout,
105 const TCMatrix_gwbse& Min, double prefactor) const {
106 if (cd == 0 || prefactor == 0.0) {
107 return;
108 }
109
110 const Eigen::DiagonalMatrix<double, Eigen::Dynamic> eps =
111 epsilon_0_inv_.asDiagonal();
112
113 for (Index v1 = 0; v1 < out_blk.vtotal; ++v1) {
114 for (Index c1 = 0; c1 < out_blk.ctotal; ++c1) {
115
116 // rows correspond to c2, columns correspond to v2
117 const Eigen::MatrixXd left =
118 prefactor * Mout[c1 + out_blk.cmin_rpa].middleRows(in_blk.cmin_rpa,
119 in_blk.ctotal);
120
121 const Eigen::MatrixXd right =
122 Min[v1 + out_blk.vmin_rpa].middleRows(in_blk.vmin_rpa, in_blk.vtotal);
123
124 // (ctotal_in x naux) * (naux x vtotal_in) = (ctotal_in x vtotal_in)
125 const Eigen::MatrixXd block = left * eps * right.transpose();
126
127 // Flattening column-major yields index order v2*ctotal + c2
128 const Eigen::VectorXd row =
129 Eigen::Map<const Eigen::VectorXd>(block.data(), block.size());
130
131 const Index out_idx = v1 * out_blk.ctotal + c1;
132 y.row(out_idx) += row.transpose() * x;
133 }
134 }
135}
136
137template <Index cqp, Index cx, Index cd, Index cd2>
139 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& out_blk,
140 const SpinBlockInfo& in_blk, const TCMatrix_gwbse& Mout,
141 const TCMatrix_gwbse& Min, double prefactor) const {
142 if (cd2 == 0 || prefactor == 0.0) {
143 return;
144 }
145
146 const Eigen::DiagonalMatrix<double, Eigen::Dynamic> eps =
147 epsilon_0_inv_.asDiagonal();
148
149 for (Index c1 = 0; c1 < out_blk.ctotal; ++c1) {
150 const Eigen::MatrixXd left =
151 prefactor *
152 Mout[c1 + out_blk.cmin_rpa].middleRows(in_blk.vmin_rpa, in_blk.vtotal);
153
154 for (Index v1 = 0; v1 < out_blk.vtotal; ++v1) {
155 const Eigen::MatrixXd right =
156 Min[v1 + out_blk.vmin_rpa].middleRows(in_blk.cmin_rpa, in_blk.ctotal);
157
158 const Eigen::MatrixXd block = left * eps * right.transpose();
159
160 Eigen::VectorXd row(in_blk.vtotal * in_blk.ctotal);
161 for (Index v2 = 0; v2 < in_blk.vtotal; ++v2) {
162 for (Index c2 = 0; c2 < in_blk.ctotal; ++c2) {
163 const Index idx = v2 * in_blk.ctotal + c2;
164 row(idx) = block(v2, c2);
165 }
166 }
167
168 const Index out_idx = v1 * out_blk.ctotal + c1;
169 y.row(out_idx) += row.transpose() * x;
170 }
171 }
172}
173
174template <Index cqp, Index cx, Index cd, Index cd2>
176 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& out_blk,
177 const SpinBlockInfo& in_blk, const TCMatrix_gwbse& Mout,
178 const TCMatrix_gwbse& Min, double prefactor) const {
179 if (cd == 0 || prefactor == 0.0) {
180 return;
181 }
182
183 const Eigen::DiagonalMatrix<double, Eigen::Dynamic> eps =
184 epsilon_0_inv_.asDiagonal();
185
186 for (Index v1 = 0; v1 < out_blk.vtotal; ++v1) {
187 for (Index c1 = 0; c1 < out_blk.ctotal; ++c1) {
188
189 // Transition density for the output excitation (v1 -> c1)
190 const Eigen::RowVectorXd tout =
191 prefactor * Mout[c1 + out_blk.cmin_rpa].row(v1 + out_blk.vmin_rpa);
192
193 const Index out_idx = v1 * out_blk.ctotal + c1;
194
195 // Build the row blockwise in the input excitation space:
196 // input ordering is (v2 * ctotal + c2), i.e. c2 runs fastest.
197 for (Index v2 = 0; v2 < in_blk.vtotal; ++v2) {
198 const Eigen::MatrixXd Tin = Min[v2 + in_blk.vmin_rpa].middleRows(
199 in_blk.cmin_rpa, in_blk.ctotal);
200
201 // Tin rows correspond to c2, and column-major flattening over
202 // successive v2 blocks is therefore consistent with vc = v*ctotal + c.
203 const Eigen::VectorXd row_block = Tin * eps * tout.transpose();
204
205 const Index in_row0 = v2 * in_blk.ctotal;
206 y.row(out_idx) +=
207 row_block.transpose() * x.middleRows(in_row0, in_blk.ctotal);
208 }
209 }
210 }
211}
212
213template <Index cqp, Index cx, Index cd, Index cd2>
215 const Eigen::MatrixXd& input) const {
216
217 static_assert(!(cd != 0 && cd2 != 0),
218 "Hamiltonian cannot contain Hd and Hd2 at the same time");
219
220 Eigen::MatrixXd y = Eigen::MatrixXd::Zero(size_total_, input.cols());
221
222 const Eigen::MatrixXd x_alpha = input.topRows(alpha_.size);
223 const Eigen::MatrixXd x_beta = input.bottomRows(beta_.size);
224
225 Eigen::MatrixXd y_alpha = Eigen::MatrixXd::Zero(alpha_.size, input.cols());
226 Eigen::MatrixXd y_beta = Eigen::MatrixXd::Zero(beta_.size, input.cols());
227
228 // Same-spin alpha-alpha
229 add_qp_block(y_alpha, x_alpha, alpha_, Hqp_alpha_);
230 add_exchange_block(y_alpha, x_alpha, alpha_, alpha_, Mmn_.alpha, Mmn_.alpha,
231 static_cast<double>(cx));
232 add_direct_block(y_alpha, x_alpha, alpha_, alpha_, Mmn_.alpha, Mmn_.alpha,
233 -static_cast<double>(cd));
234 add_direct2_block(y_alpha, x_alpha, alpha_, alpha_, Mmn_.alpha, Mmn_.alpha,
235 -static_cast<double>(cd2));
236
237 // Same-spin beta-beta
238 add_qp_block(y_beta, x_beta, beta_, Hqp_beta_);
239 add_exchange_block(y_beta, x_beta, beta_, beta_, Mmn_.beta, Mmn_.beta,
240 static_cast<double>(cx));
241 add_direct_block(y_beta, x_beta, beta_, beta_, Mmn_.beta, Mmn_.beta,
242 -static_cast<double>(cd));
243 add_direct2_block(y_beta, x_beta, beta_, beta_, Mmn_.beta, Mmn_.beta,
244 -static_cast<double>(cd2));
245
246 // Cross-spin TDA coupling: use transition-density form.
247 add_direct_cross_tda_block(y_alpha, x_beta, alpha_, beta_, Mmn_.alpha,
248 Mmn_.beta, -static_cast<double>(cd));
249 add_direct_cross_tda_block(y_beta, x_alpha, beta_, alpha_, Mmn_.beta,
250 Mmn_.alpha, -static_cast<double>(cd));
251
252 // Cross-spin full-BSE B-block coupling is not the same object as the TDA
253 // cross block above; keep the existing Hd2-style contraction for now.
254 add_direct2_block(y_alpha, x_beta, alpha_, beta_, Mmn_.alpha, Mmn_.beta,
255 -static_cast<double>(cd2));
256
257 add_direct2_block(y_beta, x_alpha, beta_, alpha_, Mmn_.beta, Mmn_.alpha,
258 -static_cast<double>(cd2));
259
260 y.topRows(alpha_.size) = y_alpha;
261 y.bottomRows(beta_.size) = y_beta;
262 return y;
263}
264
265template <Index cqp, Index cx, Index cd, Index cd2>
267 Eigen::MatrixXd dense = Eigen::MatrixXd::Zero(rows(), cols());
268 for (Index i = 0; i < cols(); ++i) {
269 Eigen::MatrixXd e = Eigen::MatrixXd::Zero(rows(), 1);
270 e(i, 0) = 1.0;
271 dense.col(i) = matmul(e);
272 }
273 return dense;
274}
275
276template <Index cqp, Index cx, Index cd, Index cd2>
278 static_assert(!(cd != 0 && cd2 != 0),
279 "Hamiltonian cannot contain Hd and Hd2 at the same time");
280
281 Eigen::VectorXd result = Eigen::VectorXd::Zero(size_total_);
282
283 const Eigen::DiagonalMatrix<double, Eigen::Dynamic> eps =
284 epsilon_0_inv_.asDiagonal();
285
286 // alpha block
287 for (Index v = 0; v < alpha_.vtotal; ++v) {
288 for (Index c = 0; c < alpha_.ctotal; ++c) {
289 double entry = 0.0;
290
291 if (cx != 0) {
292 entry += cx * Mmn_.alpha[v + alpha_.vmin_rpa]
293 .row(alpha_.cmin_rpa + c)
294 .squaredNorm();
295 }
296 if (cqp != 0) {
297 Index cmin_qp = alpha_.vtotal;
298 entry += Hqp_alpha_(c + cmin_qp, c + cmin_qp) - Hqp_alpha_(v, v);
299 }
300 if (cd != 0) {
301 entry -=
302 (Mmn_.alpha[c + alpha_.cmin_rpa].row(alpha_.cmin_rpa + c) * eps *
303 Mmn_.alpha[v + alpha_.vmin_rpa]
304 .row(alpha_.vmin_rpa + v)
305 .transpose())
306 .value();
307 }
308 if (cd2 != 0) {
309 entry -=
310 (Mmn_.alpha[c + alpha_.cmin_rpa].row(alpha_.vmin_rpa + v) * eps *
311 Mmn_.alpha[v + alpha_.vmin_rpa]
312 .row(alpha_.cmin_rpa + c)
313 .transpose())
314 .value();
315 }
316
317 result(alpha_.offset + v * alpha_.ctotal + c) = entry;
318 }
319 }
320
321 // beta block
322 for (Index v = 0; v < beta_.vtotal; ++v) {
323 for (Index c = 0; c < beta_.ctotal; ++c) {
324 double entry = 0.0;
325
326 if (cx != 0) {
327 entry +=
328 cx *
329 Mmn_.beta[v + beta_.vmin_rpa].row(beta_.cmin_rpa + c).squaredNorm();
330 }
331 if (cqp != 0) {
332 Index cmin_qp = beta_.vtotal;
333 entry += Hqp_beta_(c + cmin_qp, c + cmin_qp) - Hqp_beta_(v, v);
334 }
335 if (cd != 0) {
336 entry -=
337 (Mmn_.beta[c + beta_.cmin_rpa].row(beta_.cmin_rpa + c) * eps *
338 Mmn_.beta[v + beta_.vmin_rpa].row(beta_.vmin_rpa + v).transpose())
339 .value();
340 }
341 if (cd2 != 0) {
342 entry -=
343 (Mmn_.beta[c + beta_.cmin_rpa].row(beta_.vmin_rpa + v) * eps *
344 Mmn_.beta[v + beta_.vmin_rpa].row(beta_.cmin_rpa + c).transpose())
345 .value();
346 }
347
348 result(beta_.offset + v * beta_.ctotal + c) = entry;
349 }
350 }
351
352 return result;
353}
354
355template class BSE_OPERATOR_UKS<1, 1, 1, 0>;
356template class BSE_OPERATOR_UKS<0, 1, 0, 1>;
357template class BSE_OPERATOR_UKS<0, 0, 1, 0>;
358template class BSE_OPERATOR_UKS<0, 0, 0, 1>;
359
360template class BSE_OPERATOR_UKS<1, 0, 0, 0>;
361template class BSE_OPERATOR_UKS<0, 1, 0, 0>;
362
363} // namespace xtp
364} // namespace votca
void add_exchange_block(Eigen::MatrixXd &y, const Eigen::MatrixXd &x, const SpinBlockInfo &out_blk, const SpinBlockInfo &in_blk, const TCMatrix_gwbse &Mout, const TCMatrix_gwbse &Min, double prefactor) const
const Eigen::MatrixXd & Hqp_beta_
Eigen::VectorXd diagonal() const override
const TCMatrix_gwbse_spin & Mmn_
const Eigen::MatrixXd & Hqp_alpha_
void configure(BSEOperatorUKS_Options opt)
void add_direct_block(Eigen::MatrixXd &y, const Eigen::MatrixXd &x, const SpinBlockInfo &out_blk, const SpinBlockInfo &in_blk, const TCMatrix_gwbse &Mout, const TCMatrix_gwbse &Min, double prefactor) const
void add_direct_cross_tda_block(Eigen::MatrixXd &y, const Eigen::MatrixXd &x, const SpinBlockInfo &out_blk, const SpinBlockInfo &in_blk, const TCMatrix_gwbse &Mout, const TCMatrix_gwbse &Min, double prefactor) const
BSEOperatorUKS_Options opt_
void add_direct2_block(Eigen::MatrixXd &y, const Eigen::MatrixXd &x, const SpinBlockInfo &out_blk, const SpinBlockInfo &in_blk, const TCMatrix_gwbse &Mout, const TCMatrix_gwbse &Min, double prefactor) const
Eigen::VectorXd Hqp_row(const Eigen::MatrixXd &Hqp, const SpinBlockInfo &blk, Index v1, Index c1) const
void setup_block(SpinBlockInfo &blk, Index homo, Index offset)
Eigen::MatrixXd matmul(const Eigen::MatrixXd &input) const override
Eigen::MatrixXd dense_matrix() const
void add_qp_block(Eigen::MatrixXd &y, const Eigen::MatrixXd &x, const SpinBlockInfo &blk, const Eigen::MatrixXd &Hqp) const
const Eigen::VectorXd & epsilon_0_inv_
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