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
22
23namespace votca {
24namespace xtp {
25
26template <Index cqp, Index cx, Index cd, Index cd2>
28 Index homo, Index offset) {
29 blk.homo = homo;
30 blk.vmin_rpa = opt_.vmin - opt_.rpamin;
31 blk.cmin_rpa = homo + 1 - opt_.rpamin;
32 blk.vtotal = homo - opt_.vmin + 1;
33 blk.ctotal = opt_.cmax - (homo + 1) + 1;
34 blk.size = blk.vtotal * blk.ctotal;
35 blk.offset = offset;
36}
37
38template <Index cqp, Index cx, Index cd, Index cd2>
40 opt_ = opt;
41 setup_block(alpha_, opt_.homo_alpha, 0);
42 setup_block(beta_, opt_.homo_beta, alpha_.size);
43 size_total_ = alpha_.size + beta_.size;
44 this->set_size(size_total_);
45}
46
47template <Index cqp, Index cx, Index cd, Index cd2>
49 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& blk,
50 const Eigen::MatrixXd& Hqp) const {
51 if (cqp == 0) {
52 return;
53 }
54 y += ApplyBSEQuasiparticle(Hqp, blk.vtotal, blk.ctotal, x,
55 static_cast<double>(cqp));
56}
57
58template <Index cqp, Index cx, Index cd, Index cd2>
60 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& out_blk,
61 const SpinBlockInfo& in_blk, const TCMatrix_gwbse& Mout,
62 const TCMatrix_gwbse& Min, double prefactor) const {
63 if (cx == 0 || prefactor == 0.0) {
64 return;
65 }
66 const BSEWindow out{out_blk.vmin_rpa, out_blk.cmin_rpa, out_blk.vtotal,
67 out_blk.ctotal};
68 const BSEWindow in{in_blk.vmin_rpa, in_blk.cmin_rpa, in_blk.vtotal,
69 in_blk.ctotal};
70 y += ApplyBSEExchange(Mout, out, Min, in, x, prefactor);
71}
72
73template <Index cqp, Index cx, Index cd, Index cd2>
75 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& out_blk,
76 const SpinBlockInfo& in_blk, const TCMatrix_gwbse& Mout,
77 const TCMatrix_gwbse& Min, double prefactor) const {
78 if (cd == 0 || prefactor == 0.0) {
79 return;
80 }
81
82 const Eigen::DiagonalMatrix<double, Eigen::Dynamic> eps =
83 epsilon_0_inv_.asDiagonal();
84
85 for (Index v1 = 0; v1 < out_blk.vtotal; ++v1) {
86 for (Index c1 = 0; c1 < out_blk.ctotal; ++c1) {
87
88 // rows correspond to c2, columns correspond to v2
89 const Eigen::MatrixXd left =
90 prefactor * Mout[c1 + out_blk.cmin_rpa].middleRows(in_blk.cmin_rpa,
91 in_blk.ctotal);
92
93 const Eigen::MatrixXd right =
94 Min[v1 + out_blk.vmin_rpa].middleRows(in_blk.vmin_rpa, in_blk.vtotal);
95
96 // (ctotal_in x naux) * (naux x vtotal_in) = (ctotal_in x vtotal_in)
97 const Eigen::MatrixXd block = left * eps * right.transpose();
98
99 // Flattening column-major yields index order v2*ctotal + c2
100 const Eigen::VectorXd row =
101 Eigen::Map<const Eigen::VectorXd>(block.data(), block.size());
102
103 const Index out_idx = v1 * out_blk.ctotal + c1;
104 y.row(out_idx) += row.transpose() * x;
105 }
106 }
107}
108
109template <Index cqp, Index cx, Index cd, Index cd2>
111 Eigen::MatrixXd& y, const Eigen::MatrixXd& x, const SpinBlockInfo& out_blk,
112 const SpinBlockInfo& in_blk, const TCMatrix_gwbse& Mout,
113 const TCMatrix_gwbse& Min, double prefactor) const {
114 if (cd2 == 0 || prefactor == 0.0) {
115 return;
116 }
117
118 const Eigen::DiagonalMatrix<double, Eigen::Dynamic> eps =
119 epsilon_0_inv_.asDiagonal();
120
121 for (Index c1 = 0; c1 < out_blk.ctotal; ++c1) {
122 const Eigen::MatrixXd left =
123 prefactor *
124 Mout[c1 + out_blk.cmin_rpa].middleRows(in_blk.vmin_rpa, in_blk.vtotal);
125
126 for (Index v1 = 0; v1 < out_blk.vtotal; ++v1) {
127 const Eigen::MatrixXd right =
128 Min[v1 + out_blk.vmin_rpa].middleRows(in_blk.cmin_rpa, in_blk.ctotal);
129
130 const Eigen::MatrixXd block = left * eps * right.transpose();
131
132 Eigen::VectorXd row(in_blk.vtotal * in_blk.ctotal);
133 for (Index v2 = 0; v2 < in_blk.vtotal; ++v2) {
134 for (Index c2 = 0; c2 < in_blk.ctotal; ++c2) {
135 const Index idx = v2 * in_blk.ctotal + c2;
136 row(idx) = block(v2, c2);
137 }
138 }
139
140 const Index out_idx = v1 * out_blk.ctotal + c1;
141 y.row(out_idx) += row.transpose() * x;
142 }
143 }
144}
145
146template <Index cqp, Index cx, Index cd, Index cd2>
148 const Eigen::MatrixXd& input) const {
149
150 static_assert(!(cd != 0 && cd2 != 0),
151 "Hamiltonian cannot contain Hd and Hd2 at the same time");
152
153 Eigen::MatrixXd y = Eigen::MatrixXd::Zero(size_total_, input.cols());
154
155 const Eigen::MatrixXd x_alpha = input.topRows(alpha_.size);
156 const Eigen::MatrixXd x_beta = input.bottomRows(beta_.size);
157
158 Eigen::MatrixXd y_alpha = Eigen::MatrixXd::Zero(alpha_.size, input.cols());
159 Eigen::MatrixXd y_beta = Eigen::MatrixXd::Zero(beta_.size, input.cols());
160
161 // Same-spin alpha-alpha
162 add_qp_block(y_alpha, x_alpha, alpha_, Hqp_alpha_);
163 add_exchange_block(y_alpha, x_alpha, alpha_, alpha_, Mmn_.alpha, Mmn_.alpha,
164 static_cast<double>(cx));
165 add_direct_block(y_alpha, x_alpha, alpha_, alpha_, Mmn_.alpha, Mmn_.alpha,
166 -static_cast<double>(cd));
167 add_direct2_block(y_alpha, x_alpha, alpha_, alpha_, Mmn_.alpha, Mmn_.alpha,
168 -static_cast<double>(cd2));
169
170 // Same-spin beta-beta
171 add_qp_block(y_beta, x_beta, beta_, Hqp_beta_);
172 add_exchange_block(y_beta, x_beta, beta_, beta_, Mmn_.beta, Mmn_.beta,
173 static_cast<double>(cx));
174 add_direct_block(y_beta, x_beta, beta_, beta_, Mmn_.beta, Mmn_.beta,
175 -static_cast<double>(cd));
176 add_direct2_block(y_beta, x_beta, beta_, beta_, Mmn_.beta, Mmn_.beta,
177 -static_cast<double>(cd2));
178
179 // Cross-spin coupling. In the spin-unrestricted kernel
180 // A(ia s, jb s') = delta_ss' (e_a - e_i) + (ia|jb) - delta_ss' W(ij,ab)
181 // B(ia s, jb s') = (ia|bj) - delta_ss' W(ib,aj)
182 // the bare exchange couples all spin blocks, while the screened direct
183 // terms act within one spin only. So the alpha-beta blocks of A and of B
184 // are both the bare exchange (ia|jb), with the same prefactor as the
185 // same-spin exchange. For a closed-shell reference this reproduces the
186 // singlet and triplet spectra of the restricted BSE.
187 add_exchange_block(y_alpha, x_beta, alpha_, beta_, Mmn_.alpha, Mmn_.beta,
188 static_cast<double>(cx));
189 add_exchange_block(y_beta, x_alpha, beta_, alpha_, Mmn_.beta, Mmn_.alpha,
190 static_cast<double>(cx));
191
192 y.topRows(alpha_.size) = y_alpha;
193 y.bottomRows(beta_.size) = y_beta;
194 return y;
195}
196
197template <Index cqp, Index cx, Index cd, Index cd2>
199 Eigen::MatrixXd dense = Eigen::MatrixXd::Zero(rows(), cols());
200 for (Index i = 0; i < cols(); ++i) {
201 Eigen::MatrixXd e = Eigen::MatrixXd::Zero(rows(), 1);
202 e(i, 0) = 1.0;
203 dense.col(i) = matmul(e);
204 }
205 return dense;
206}
207
208template <Index cqp, Index cx, Index cd, Index cd2>
210 static_assert(!(cd != 0 && cd2 != 0),
211 "Hamiltonian cannot contain Hd and Hd2 at the same time");
212
213 Eigen::VectorXd result = Eigen::VectorXd::Zero(size_total_);
214
215 const Eigen::DiagonalMatrix<double, Eigen::Dynamic> eps =
216 epsilon_0_inv_.asDiagonal();
217
218 // alpha block
219 for (Index v = 0; v < alpha_.vtotal; ++v) {
220 for (Index c = 0; c < alpha_.ctotal; ++c) {
221 double entry = 0.0;
222
223 if (cx != 0) {
224 entry += cx * Mmn_.alpha[v + alpha_.vmin_rpa]
225 .row(alpha_.cmin_rpa + c)
226 .squaredNorm();
227 }
228 if (cqp != 0) {
229 Index cmin_qp = alpha_.vtotal;
230 entry += Hqp_alpha_(c + cmin_qp, c + cmin_qp) - Hqp_alpha_(v, v);
231 }
232 if (cd != 0) {
233 entry -=
234 (Mmn_.alpha[c + alpha_.cmin_rpa].row(alpha_.cmin_rpa + c) * eps *
235 Mmn_.alpha[v + alpha_.vmin_rpa]
236 .row(alpha_.vmin_rpa + v)
237 .transpose())
238 .value();
239 }
240 if (cd2 != 0) {
241 entry -=
242 (Mmn_.alpha[c + alpha_.cmin_rpa].row(alpha_.vmin_rpa + v) * eps *
243 Mmn_.alpha[v + alpha_.vmin_rpa]
244 .row(alpha_.cmin_rpa + c)
245 .transpose())
246 .value();
247 }
248
249 result(alpha_.offset + v * alpha_.ctotal + c) = entry;
250 }
251 }
252
253 // beta block
254 for (Index v = 0; v < beta_.vtotal; ++v) {
255 for (Index c = 0; c < beta_.ctotal; ++c) {
256 double entry = 0.0;
257
258 if (cx != 0) {
259 entry +=
260 cx *
261 Mmn_.beta[v + beta_.vmin_rpa].row(beta_.cmin_rpa + c).squaredNorm();
262 }
263 if (cqp != 0) {
264 Index cmin_qp = beta_.vtotal;
265 entry += Hqp_beta_(c + cmin_qp, c + cmin_qp) - Hqp_beta_(v, v);
266 }
267 if (cd != 0) {
268 entry -=
269 (Mmn_.beta[c + beta_.cmin_rpa].row(beta_.cmin_rpa + c) * eps *
270 Mmn_.beta[v + beta_.vmin_rpa].row(beta_.vmin_rpa + v).transpose())
271 .value();
272 }
273 if (cd2 != 0) {
274 entry -=
275 (Mmn_.beta[c + beta_.cmin_rpa].row(beta_.vmin_rpa + v) * eps *
276 Mmn_.beta[v + beta_.vmin_rpa].row(beta_.cmin_rpa + c).transpose())
277 .value();
278 }
279
280 result(beta_.offset + v * beta_.ctotal + c) = entry;
281 }
282 }
283
284 return result;
285}
286
287template class BSE_OPERATOR_UKS<1, 1, 1, 0>;
288template class BSE_OPERATOR_UKS<0, 1, 0, 1>;
289template class BSE_OPERATOR_UKS<0, 0, 1, 0>;
290template class BSE_OPERATOR_UKS<0, 0, 0, 1>;
291
292template class BSE_OPERATOR_UKS<1, 0, 0, 0>;
293template class BSE_OPERATOR_UKS<0, 1, 0, 0>;
294
295} // namespace xtp
296} // 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
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
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
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