votca 2026-dev
Loading...
Searching...
No Matches
bse.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 <chrono>
22#include <cmath>
23#include <iostream>
24#include <sstream>
25
26// VOTCA includes
27#include <votca/tools/linalg.h>
28
29// Local VOTCA includes
30#include "votca/xtp/bse.h"
40#include "votca/xtp/rpa.h"
41#include "votca/xtp/vc2index.h"
42
43using std::flush;
44
45namespace votca {
46namespace xtp {
47
48namespace {
49double DavidsonToleranceValue(const std::string& tol) {
50 if (tol == "loose") {
51 return 1e-3;
52 } else if (tol == "normal") {
53 return 1e-4;
54 } else if (tol == "strict") {
55 return 1e-5;
56 } else if (tol == "lapack") {
57 return 1e-9;
58 }
59 throw std::runtime_error(tol + " is not a valid Davidson tolerance");
60}
61} // namespace
62
63void BSE::configure(const options& opt, const Eigen::VectorXd& RPAInputEnergies,
64 const Eigen::MatrixXd& Hqp_in) {
65 opt_ = opt;
66 bse_vmax_ = opt_.homo;
67 bse_cmin_ = opt_.homo + 1;
68 bse_vtotal_ = bse_vmax_ - opt_.vmin + 1;
69 bse_ctotal_ = opt_.cmax - bse_cmin_ + 1;
71 max_dyn_iter_ = opt_.max_dyn_iter;
72 dyn_tolerance_ = opt_.dyn_tolerance;
73 if (opt_.use_Hqp_offdiag) {
74 Hqp_ = AdjustHqpSize(Hqp_in, RPAInputEnergies);
75 } else {
76 Hqp_ = AdjustHqpSize(Hqp_in, RPAInputEnergies).diagonal().asDiagonal();
77 }
78 SetupDirectInteractionOperator(RPAInputEnergies, 0.0);
79}
80
82 const options& opt, const Eigen::VectorXd& RPAInputEnergies,
83 const Eigen::MatrixXd& Hqp_in, const Eigen::VectorXd& epsilon_0_inv) {
84 opt_ = opt;
85 bse_vmax_ = opt_.homo;
86 bse_cmin_ = opt_.homo + 1;
87 bse_vtotal_ = bse_vmax_ - opt_.vmin + 1;
88 bse_ctotal_ = opt_.cmax - bse_cmin_ + 1;
90 max_dyn_iter_ = opt_.max_dyn_iter;
91 dyn_tolerance_ = opt_.dyn_tolerance;
92 if (opt_.use_Hqp_offdiag) {
93 Hqp_ = AdjustHqpSize(Hqp_in, RPAInputEnergies);
94 } else {
95 Hqp_ = AdjustHqpSize(Hqp_in, RPAInputEnergies).diagonal().asDiagonal();
96 }
97 epsilon_0_inv_ = epsilon_0_inv;
99}
100
102 Orbitals& orb) const {
103 if (type == QMStateType::Singlet) {
104 return orb.BSESinglets();
105 } else if (type == QMStateType::Triplet) {
106 return orb.BSETriplets();
107 } else {
108 throw std::runtime_error(
109 "Unsupported QMStateType in BSE::GetBSEEigenSystem");
110 }
111}
112
114 const Orbitals& orb) const {
115 if (type == QMStateType::Singlet) {
116 return orb.BSESinglets();
117 } else if (type == QMStateType::Triplet) {
118 return orb.BSETriplets();
119 } else {
120 throw std::runtime_error(
121 "Unsupported QMStateType in BSE::GetBSEEigenSystem");
122 }
123}
124
125std::string BSE::StateEnergiesHeader(const QMStateType& type) const {
126 if (type == QMStateType::Singlet) {
127 return " ====== singlet energies (eV) ====== ";
128 } else if (type == QMStateType::Triplet) {
129 return " ====== triplet energies (eV) ====== ";
130 } else {
131 throw std::runtime_error(
132 "Unsupported QMStateType in BSE::StateEnergiesHeader");
133 }
134}
135
136std::string BSE::StateShortLabel(const QMStateType& type) const {
137 if (type == QMStateType::Singlet) {
138 return "S";
139 } else if (type == QMStateType::Triplet) {
140 return "T";
141 } else {
142 throw std::runtime_error("Unsupported QMStateType in BSE::StateShortLabel");
143 }
144}
145
146std::string BSE::StateDynamicLabel(const QMStateType& type) const {
147 if (type == QMStateType::Singlet) {
148 return "singlet";
149 } else if (type == QMStateType::Triplet) {
150 return "triplet";
151 } else {
152 throw std::runtime_error(
153 "Unsupported QMStateType in BSE::StateDynamicLabel");
154 }
155}
156
157double BSE::ExchangePrefactor(const QMStateType& type) const {
158 if (type == QMStateType::Singlet) {
159 return 2.0;
160 } else if (type == QMStateType::Triplet) {
161 return 0.0;
162 } else {
163 throw std::runtime_error(
164 "Unsupported QMStateType in BSE::ExchangePrefactor");
165 }
166}
167
168Eigen::MatrixXd BSE::AdjustHqpSize(const Eigen::MatrixXd& Hqp,
169 const Eigen::VectorXd& RPAInputEnergies) {
170
171 Index hqp_size = bse_vtotal_ + bse_ctotal_;
172 Index gwsize = opt_.qpmax - opt_.qpmin + 1;
173 Index RPAoffset = opt_.vmin - opt_.rpamin;
174 Eigen::MatrixXd Hqp_BSE = Eigen::MatrixXd::Zero(hqp_size, hqp_size);
175
176 if (opt_.vmin >= opt_.qpmin) {
177 Index start = opt_.vmin - opt_.qpmin;
178 if (opt_.cmax <= opt_.qpmax) {
179 Hqp_BSE = Hqp.block(start, start, hqp_size, hqp_size);
180 } else {
181 Index virtoffset = gwsize - start;
182 Hqp_BSE.topLeftCorner(virtoffset, virtoffset) =
183 Hqp.block(start, start, virtoffset, virtoffset);
184
185 Index virt_extra = opt_.cmax - opt_.qpmax;
186 Hqp_BSE.diagonal().tail(virt_extra) =
187 RPAInputEnergies.segment(RPAoffset + virtoffset, virt_extra);
188 }
189 }
190
191 if (opt_.vmin < opt_.qpmin) {
192 Index occ_extra = opt_.qpmin - opt_.vmin;
193 Hqp_BSE.diagonal().head(occ_extra) =
194 RPAInputEnergies.segment(RPAoffset, occ_extra);
195
196 Hqp_BSE.block(occ_extra, occ_extra, gwsize, gwsize) = Hqp;
197
198 if (opt_.cmax > opt_.qpmax) {
199 Index virtoffset = occ_extra + gwsize;
200 Index virt_extra = opt_.cmax - opt_.qpmax;
201 Hqp_BSE.diagonal().tail(virt_extra) =
202 RPAInputEnergies.segment(RPAoffset + virtoffset, virt_extra);
203 }
204 }
205
206 return Hqp_BSE;
207}
208
209void BSE::setReactionField(const Eigen::MatrixXd& R, bool include_kreac) {
210 reaction_field_ = R;
211 include_kreac_ = include_kreac;
213 : Eigen::MatrixXd();
214}
215
216// The BSE operators read slices and rows up to the highest conduction level;
217// the dielectric matrix reads all rows of the occupied slices. Only those
218// are rotated (see TCMatrix_gwbse::MultiplyRightWithAuxMatrixLeading).
219void BSE::RotateIntoScreeningFrame(const Eigen::MatrixXd& U) {
220 const Index occupied_slices = opt_.homo + 1 - opt_.rpamin;
221 const Index lead = opt_.cmax + 1 - opt_.rpamin;
222 Mmn_.MultiplyRightWithAuxMatrixLeading(U, occupied_slices, lead);
223}
224
226 const bool environment = reaction_field_.size() > 0;
227 const bool dressed_route = environment && include_kreac_;
228 // Dressed: every pairing of two M's is through u = v + v_reac, so eps
229 // below is the environment-screened one and Kx carries K_reac. Bare:
230 // Kx stays v, and W_tot is assembled explicitly below. GW may have left
231 // the integrals either way.
232 if (dressed_route && !Mmn_.Dressed()) {
233 Mmn_.DressAuxIndex(dressing_);
234 } else if (!dressed_route && Mmn_.Dressed()) {
235 Mmn_.UndressAuxIndex();
236 }
237}
238
239// W = vectors diag(values) vectors^T in the current frame of the
240// integrals, as the operators use it: the inverse of epsilon without its
241// non-positive modes, or W_tot of the bare environment route.
243 const Eigen::VectorXd& RPAInputEnergies, double energy,
244 DFTTimings& timings) const {
245 RPA rpa = RPA(log_, Mmn_);
246 rpa.configure(opt_.homo, opt_.rpamin, opt_.rpamax);
247 rpa.setRPAInputEnergies(RPAInputEnergies);
248 rpa.setTimings(&timings);
249 const Eigen::MatrixXd screening = rpa.calculate_epsilon_r(energy);
250
251 auto t = timings.Measure("eigensolver");
252 if (reaction_field_.size() > 0 && !include_kreac_) {
253 // Operators expect M U with U orthogonal and diag(epsilon_0_inv_) the
254 // screened interaction in that frame: Kd = M U d U^T M^T and
255 // Kx = M U U^T M^T = M M^T = v. So diagonalize W_tot, not eps, and
256 // hand its eigenvalues over as epsilon_0_inv_.
257 const Index n = screening.rows();
258 const Eigen::MatrixXd I = Eigen::MatrixXd::Identity(n, n);
259 // 1 + R and u^-1 + eps - 1 are positive definite (Cholesky, LU if not)
260 const Eigen::MatrixXd u_inv =
261 InverseSPD(I + Mmn_.ToCurrentAuxFrame(reaction_field_));
262 Eigen::MatrixXd W = InverseSPD(u_inv + screening - I);
263 W = 0.5 * (W + W.transpose()).eval();
264 return SymmetricEigen(W);
265 }
266
267 SymmetricEigenSystem es = SymmetricEigen(screening);
268 for (Index i = 0; i < es.values.size(); ++i) {
269 es.values(i) = (es.values(i) > 1e-8) ? 1 / es.values(i) : 0.0;
270 }
271 return es;
272}
273
275 const Eigen::VectorXd& RPAInputEnergies, double energy) {
276 ReleaseDirectCaches(); // the integrals and the screening change
278 DFTTimings timings;
280 ScreenedInteraction(RPAInputEnergies, energy, timings);
281 {
282 auto t = timings.Measure("rotation");
284 }
285 epsilon_0_inv_ = std::move(W.values);
286 XTP_LOG(Log::error, log_) << TimeStamp() << " BSE screening at " << energy
287 << " Ha: " << timings.Format() << flush;
288}
289
290template <typename BSE_OPERATOR>
292 std::shared_ptr<SymmetricTiles> cache) const {
294 opt.cmax = opt_.cmax;
295 opt.homo = opt_.homo;
296 opt.qpmin = opt_.qpmin;
297 opt.rpamin = opt_.rpamin;
298 opt.vmin = opt_.vmin;
299 H.configure(opt);
300 H.set_direct_cache(std::move(cache));
301}
302
304
305void BSE::DecideDirectCaches(bool coupling) const {
306 const Index n = bse_size_;
307 const double need = SymmetricTiles::Bytes(n);
308 // what is kept but not built yet does not show in the resident memory
309 double pending = 0.0;
310 for (const auto* c : {&direct_caches_.hd, &direct_caches_.hd2}) {
311 if (*c != nullptr && !(*c)->built()) {
312 pending += need;
313 }
314 }
315 double available = MemoryBudget::AvailableBytes() - pending;
316 std::ostringstream msg;
317 msg.precision(3);
318 msg << " BSE direct terms (lower triangle, " << need * 1e-9 << " GB each):";
319 auto decide = [&](std::shared_ptr<SymmetricTiles>& cache, bool& decided,
320 const char* name) {
321 if (decided) {
322 msg << " " << name << (cache ? " kept (reused)" : " not kept") << ";";
323 return;
324 }
325 decided = true;
326 if (need <= available) {
327 cache = std::make_shared<SymmetricTiles>();
328 available -= need;
329 msg << " " << name << " kept;";
330 } else {
331 msg << " " << name << " not kept;";
332 }
333 };
334 decide(direct_caches_.hd, direct_caches_.hd_decided, "Hd");
335 if (coupling) {
336 decide(direct_caches_.hd2, direct_caches_.hd2_decided, "Hd2");
337 }
338 msg << " " << MemoryBudget::Describe();
339 const Index missing = Index(direct_caches_.hd == nullptr) +
340 Index(coupling && direct_caches_.hd2 == nullptr);
341 if (missing > 0) {
342 // what the process holds now plus the matrices, with the margin
343 const double resident = std::max(0.0, MemoryBudget::ResidentBytes());
344 // the needed terms not built yet, and one kept but unbuilt otherwise
345 auto unbuilt = [](const std::shared_ptr<SymmetricTiles>& c) {
346 return c == nullptr || !c->built();
347 };
348 double extra = unbuilt(direct_caches_.hd) ? need : 0.0;
349 if (coupling ? unbuilt(direct_caches_.hd2)
350 : (direct_caches_.hd2 && !direct_caches_.hd2->built())) {
351 extra += need;
352 }
353 const double wanted = resident + extra;
354 msg << "; --memory " << std::ceil(1.1 * wanted * 1e-9 + 1.0)
355 << " or more would keep all";
356 }
357 XTP_LOG(Log::error, log_) << TimeStamp() << msg.str() << flush;
358}
359
367
369 orb.setTDAApprox(opt_.useTDA);
370 if (opt_.useTDA) {
372 } else {
374 }
376
377 if (reaction_field_.size() > 0) {
378 const Eigen::VectorXd kreac =
381 << TimeStamp() << " Environment K_reac (linear-response part), "
382 << (include_kreac_ ? "included" : "NOT included, estimate only")
383 << ", first order [eV]:" << flush;
384 for (Index i = 0; i < kreac.size(); ++i) {
386 << (boost::format(" S = %1$4d Omega = %2$+1.4f eV <K_reac> = "
387 "%3$+1.4f eV") %
388 (i + 1) %
390 (kreac(i) * tools::conv::hrt2ev))
391 .str()
392 << flush;
393 }
394 }
395}
396
398 bool tda) const {
399 // The transition density of each state in the auxiliary basis,
400 // d = sum_vc (X+Y)_vc M_v,c, and <K_reac> = 2 d^T R d: the singlet
401 // spin factor of Kx, which K_reac shares, times the first-order change
402 // (X+Y)^T dK (X+Y) that a perturbation entering A and B alike produces.
403 const Eigen::MatrixXd Rc = Mmn_.ToCurrentAuxFrame(reaction_field_);
404 const Index vmin = opt_.vmin - opt_.rpamin;
405 const Index cmin = bse_cmin_ - opt_.rpamin;
406 const Index nstates = es.eigenvalues().size();
407 Eigen::VectorXd result = Eigen::VectorXd::Zero(nstates);
408#pragma omp parallel for schedule(dynamic)
409 for (Index s = 0; s < nstates; ++s) {
410 Eigen::VectorXd coeffs = es.eigenvectors().col(s);
411 if (!tda) {
412 coeffs += es.eigenvectors2().col(s);
413 }
414 const Eigen::Map<const Eigen::MatrixXd> mat(coeffs.data(), bse_ctotal_,
416 Eigen::VectorXd d = Eigen::VectorXd::Zero(Mmn_.auxsize());
417 for (Index v = 0; v < bse_vtotal_; ++v) {
418 d +=
419 Mmn_[v + vmin].middleRows(cmin, bse_ctotal_).transpose() * mat.col(v);
420 }
421 result(s) = 2.0 * d.dot(Rc * d);
422 }
423 return result;
424}
425
427 orb.setTDAApprox(opt_.useTDA);
428 if (opt_.useTDA) {
430 } else {
432 }
433}
434
436
437 DecideDirectCaches(false);
441 << TimeStamp() << " Setup TDA singlet hamiltonian " << flush;
442 return solve_hermitian(Hs);
443}
444
451
458
459template <typename BSE_OPERATOR>
461
462 std::chrono::time_point<std::chrono::system_clock> start =
463 std::chrono::system_clock::now();
464
465 tools::EigenSystem result;
466
468
469 DS.set_correction(opt_.davidson_correction);
470 DS.set_tolerance(opt_.davidson_tolerance);
471 DS.set_size_update(opt_.davidson_update);
472 DS.set_iter_max(opt_.davidson_maxiter);
473 DS.set_max_search_space(10 * opt_.nmax);
474 DS.solve(h, opt_.nmax);
475 result.eigenvalues() = DS.eigenvalues();
476 result.eigenvectors() = DS.eigenvectors();
477
478 std::chrono::time_point<std::chrono::system_clock> end =
479 std::chrono::system_clock::now();
480 std::chrono::duration<double> elapsed_time = end - start;
481
482 XTP_LOG(Log::info, log_) << TimeStamp() << " Diagonalization done in "
483 << elapsed_time.count() << " secs" << flush;
484
485 return result;
486}
487
498
509
510template <typename BSE_OPERATOR_A, typename BSE_OPERATOR_B>
512 BSE_OPERATOR_B& Bop) const {
513 // Hermitian (A-B)(A+B) form: one application of A and of B per new
514 // vector. Falls back to the general non-Hermitian Davidson if A-B or A+B
515 // is not positive definite.
516 try {
518 fopt.tolerance = DavidsonToleranceValue(opt_.davidson_tolerance);
519 fopt.max_iterations = opt_.davidson_maxiter;
520 fopt.max_subspace = 10 * opt_.nmax;
521 FullBSEDavidson solver(log_, fopt);
522 return solver.Solve(Aop, Bop, opt_.nmax);
523 } catch (const std::runtime_error& error) {
525 << TimeStamp() << " " << error.what()
526 << "; using the non-Hermitian Davidson solver" << flush;
527 }
528
529 std::chrono::time_point<std::chrono::system_clock> start =
530 std::chrono::system_clock::now();
531
532 // operator
534
535 // Davidson solver
537 DS.set_correction(opt_.davidson_correction);
538 DS.set_tolerance(opt_.davidson_tolerance);
539 DS.set_size_update(opt_.davidson_update);
540 DS.set_iter_max(opt_.davidson_maxiter);
541 DS.set_max_search_space(10 * opt_.nmax);
542 DS.set_matrix_type("HAM");
543 Eigen::MatrixXd initial_guess = BuildFullBSEXRankedInitialGuess(
544 Aop.diagonal(), Bop.diagonal(), opt_.nmax);
545
546 DS.solve(Hop, opt_.nmax, initial_guess);
547
548 // results
549 tools::EigenSystem result;
550 result.eigenvalues() = DS.eigenvalues();
551 Eigen::MatrixXd tmpX = DS.eigenvectors().topRows(Aop.rows());
552 Eigen::MatrixXd tmpY = DS.eigenvectors().bottomRows(Bop.rows());
553
554 // normalization so that X^T X - Y^T Y = 1
555 if (const Index bad = NormalizeExcitationVectors(tmpX, tmpY); bad > 0) {
557 << TimeStamp() << " WARNING: " << bad
558 << " BSE root(s) without positive X^2 - Y^2 norm (not converged?)"
559 << flush;
560 }
561 result.eigenvectors() = tmpX;
562 result.eigenvectors2() = tmpY;
563
564 std::chrono::time_point<std::chrono::system_clock> end =
565 std::chrono::system_clock::now();
566 std::chrono::duration<double> elapsed_time = end - start;
567
568 XTP_LOG(Log::info, log_) << TimeStamp() << " Diagonalization done in "
569 << elapsed_time.count() << " secs" << flush;
570
571 return result;
572}
573
574void BSE::printFragInfo(const std::vector<QMFragment<BSE_Population>>& frags,
575 Index state) const {
576 for (const QMFragment<BSE_Population>& frag : frags) {
577 double dq = frag.value().H[state] + frag.value().E[state];
578 double qeff = dq + frag.value().Gs;
580 << boost::format(
581 " Fragment %1$4d -- hole: %2$5.1f%% electron: "
582 "%3$5.1f%% dQ: %4$+5.2f Qeff: %5$+5.2f") %
583 int(frag.getId()) % (100.0 * frag.value().H[state]) %
584 (-100.0 * frag.value().E[state]) % dq % qeff
585 << flush;
586 }
587 return;
588}
589
590void BSE::PrintWeights(const Eigen::VectorXd& weights) const {
592 for (Index i_bse = 0; i_bse < bse_size_; ++i_bse) {
593 double weight = weights(i_bse);
594 if (weight > opt_.min_print_weight) {
596 << boost::format(
597 " HOMO-%1$-3d -> LUMO+%2$-3d : %3$3.1f%%") %
598 (opt_.homo - vc.v(i_bse)) % (vc.c(i_bse) - opt_.homo - 1) %
599 (100.0 * weight)
600 << flush;
601 }
602 }
603 return;
604}
605
607 const Orbitals& orb) const {
608
610
611 Eigen::VectorXd oscs = orb.Oscillatorstrengths();
612 Interaction act = Analyze_eh_interaction(type, orb);
613
614 if (fragments.size() > 0) {
615 Lowdin low;
616 low.CalcChargeperFragment(fragments, orb, type);
617 }
618
619 const tools::EigenSystem& bse = GetBSEEigenSystem(type, orb);
620 const Eigen::VectorXd& energies = bse.eigenvalues();
621
622 double hrt2ev = tools::conv::hrt2ev;
623 XTP_LOG(Log::error, log_) << StateEnergiesHeader(type) << flush;
624 for (Index i = 0; i < opt_.nmax; ++i) {
625 Eigen::VectorXd weights = bse.eigenvectors().col(i).cwiseAbs2();
626 if (!orb.getTDAApprox()) {
627 weights -= bse.eigenvectors2().col(i).cwiseAbs2();
628 }
629
630 double osc = oscs[i];
631 // On the dressed route (environment with K_reac) the exchange operator
632 // acts on integrals dressed with (1+R)^1/2, so its expectation value is
633 // that of K_x + K_reac. Label it as such.
634 const bool dressed = reaction_field_.size() > 0 && include_kreac_;
635 const std::string kx_label = dressed ? "<K_x+K_reac>" : "<K_x>";
637 << boost::format(
638 " %1$2s = %2$4d Omega = %3$+1.12f eV lamdba = %4$+3.2f nm "
639 "<FT> = %5$+1.4f %8$s = %6$+1.4f <K_d> = %7$+1.4f") %
640 StateShortLabel(type) % (i + 1) % (hrt2ev * energies(i)) %
641 (1240.0 / (hrt2ev * energies(i))) %
642 (hrt2ev * act.qp_contrib(i)) %
643 (hrt2ev * act.exchange_contrib(i)) %
644 (hrt2ev * act.direct_contrib(i)) % kx_label
645 << flush;
646
647 const Eigen::Vector3d& trdip = orb.TransitionDipoles()[i];
649 << boost::format(
650 " TrDipole length gauge[e*bohr] dx = %1$+1.4f dy = "
651 "%2$+1.4f dz = %3$+1.4f |d|^2 = %4$+1.4f f = %5$+1.4f") %
652 trdip[0] % trdip[1] % trdip[2] % (trdip.squaredNorm()) % osc
653 << flush;
654
655 PrintWeights(weights);
656 if (fragments.size() > 0) {
657 printFragInfo(fragments, i);
658 }
659
660 XTP_LOG(Log::error, log_) << flush;
661 }
662 return;
663}
664
666 const Orbitals& orb) const {
667
669 Interaction act = Analyze_eh_interaction(type, orb);
670
671 if (fragments.size() > 0) {
672 Lowdin low;
673 low.CalcChargeperFragment(fragments, orb, type);
674 }
675
676 const tools::EigenSystem& bse = GetBSEEigenSystem(type, orb);
677 const Eigen::VectorXd& energies = bse.eigenvalues();
678
679 XTP_LOG(Log::error, log_) << StateEnergiesHeader(type) << flush;
680 for (Index i = 0; i < opt_.nmax; ++i) {
681 Eigen::VectorXd weights = bse.eigenvectors().col(i).cwiseAbs2();
682 if (!orb.getTDAApprox()) {
683 weights -= bse.eigenvectors2().col(i).cwiseAbs2();
684 }
685
687 << boost::format(
688 " %1$2s = %2$4d Omega = %3$+1.12f eV lamdba = %4$+3.2f nm "
689 "<FT> = %5$+1.4f <K_d> = %6$+1.4f") %
690 StateShortLabel(type) % (i + 1) %
691 (tools::conv::hrt2ev * energies(i)) %
692 (1240.0 / (tools::conv::hrt2ev * energies(i))) %
695 << flush;
696
697 PrintWeights(weights);
698 if (fragments.size() > 0) {
699 printFragInfo(fragments, i);
700 }
701 XTP_LOG(Log::error, log_) << boost::format(" ") << flush;
702 }
703
704 return;
705}
706
707template <class OP>
708Eigen::VectorXd ExpValue(const Eigen::MatrixXd& state1, OP OPxstate2) {
709 return state1.cwiseProduct(OPxstate2.eval()).colwise().sum().transpose();
710}
711
712Eigen::VectorXd ExpValue(const Eigen::MatrixXd& state1,
713 const Eigen::MatrixXd& OPxstate2) {
714 return state1.cwiseProduct(OPxstate2).colwise().sum().transpose();
715}
716
717template <typename BSE_OPERATOR>
719 const QMStateType& type, const Orbitals& orb, const BSE_OPERATOR& H) const {
720
721 const tools::EigenSystem& BSECoefs = GetBSEEigenSystem(type, orb);
722
723 ExpectationValues expectation_values;
724
725 const Eigen::MatrixXd temp = H * BSECoefs.eigenvectors();
726
727 expectation_values.direct_term = ExpValue(BSECoefs.eigenvectors(), temp);
728 if (!orb.getTDAApprox()) {
729 expectation_values.direct_term +=
730 ExpValue(BSECoefs.eigenvectors2(), H * BSECoefs.eigenvectors2());
731 expectation_values.cross_term =
732 2 * ExpValue(BSECoefs.eigenvectors2(), temp);
733 } else {
734 expectation_values.cross_term = Eigen::VectorXd::Zero(0);
735 }
736 return expectation_values;
737}
738
739// Composition of the excitation energy in terms of QP, direct (screened),
740// and exchance contributions in the BSE
741// Full BSE:
742//
743// | A* | | H K | | A |
744// | -B* | | -K -H | | B | = A*.H.A + B*.H.B + 2A*.K.B
745//
746// with: H = H_qp + H_d + eta.H_x
747// K = H_d2 + eta.H_x
748//
749// reports composition for FULL BSE as
750// <FT> = A*.H_qp.A + B*.H_qp.B
751// <Kx> = eta.(A*.H_x.A + B*.H_x.B + 2A*.H_x.B)
752// <Kd> = A*.H_d.A + B*.H_d.B + 2A*.H_d2.B
753namespace {
754// A kept direct term for the analysis only if it is built already: building
755// it for the few states of the analysis would cost more than it saves.
756std::shared_ptr<SymmetricTiles> ReusableCache(
757 const std::shared_ptr<SymmetricTiles>& cache) {
758 return (cache != nullptr && cache->built()) ? cache : nullptr;
759}
760} // namespace
761
763 const Orbitals& orb) const {
764 Interaction analysis;
765 {
768 ExpectationValues expectation_values =
769 ExpectationValue_Operator(type, orb, hqp);
770 analysis.qp_contrib = expectation_values.direct_term;
771 }
772 {
773 // the direct terms of the solve, if kept, are not rebuilt here
775 configureBSEOperator(hd, ReusableCache(direct_caches_.hd));
776 ExpectationValues expectation_values =
777 ExpectationValue_Operator(type, orb, hd);
778 analysis.direct_contrib = expectation_values.direct_term;
779 }
780 if (!orb.getTDAApprox()) {
781 // only the cross term 2 Y.Hd2.X: Hd2 on X alone
783 configureBSEOperator(hd2, ReusableCache(direct_caches_.hd2));
784 const tools::EigenSystem& coefs = GetBSEEigenSystem(type, orb);
785 analysis.direct_contrib +=
786 2 * ExpValue(coefs.eigenvectors2(), hd2 * coefs.eigenvectors());
787 }
788
789 double xpref = ExchangePrefactor(type);
790 if (xpref != 0.0) {
793 ExpectationValues expectation_values =
794 ExpectationValue_Operator(type, orb, hx);
795 analysis.exchange_contrib = xpref * expectation_values.direct_term;
796 if (!orb.getTDAApprox()) {
797 analysis.exchange_contrib += xpref * expectation_values.cross_term;
798 }
799 } else {
800 analysis.exchange_contrib =
801 Eigen::VectorXd::Zero(analysis.direct_contrib.size());
802 }
803
804 return analysis;
805}
806
807double BSE::state_matrix_bytes_ = 1e9;
808
809namespace {
810using RowMajorMatrix =
811 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
812
813// Number of hole levels per pass, so that the stacked intermediates of one
814// pass stay within the given bytes.
815Index HoleChunk(Index vtotal, Index ctotal, Index auxsize, double bytes) {
816 const double per_level =
817 8.0 * double(auxsize) * double(ctotal + 2 * std::max(vtotal, ctotal));
818 return std::clamp<Index>(Index(bytes / per_level), 1, vtotal);
819}
820
821// sum_PQ W_PQ G_PQ for W = vectors diag(values) vectors^T
822double ContractScreened(const SymmetricEigenSystem& W,
823 const Eigen::MatrixXd& G) {
824 const Eigen::MatrixXd GPhi = G * W.vectors;
825 return (W.vectors.cwiseProduct(GPhi).colwise().sum().transpose().array() *
826 W.values.array())
827 .sum();
828}
829} // namespace
830
831// G with <A|Hd|B> = -sum_PQ W_PQ G_PQ, summed over the pairs (A, B), for the
832// screened direct term Hd(v1c1, v2c2) = -M[c1](c2,:) W M[v1](v2,:)^T:
833// G = sum_{v1 v2} b_{v1v2} a_{v1v2}^T, a_{v1v2} = M[v1](v2,:),
834// b_{v1v2} = sum_{c1 c2} A(v1,c1) B(v2,c2) M[c1](c2,:).
836 const std::vector<std::pair<const Eigen::VectorXd*,
837 const Eigen::VectorXd*>>& pairs) const {
838 const Index vmin = opt_.vmin - opt_.rpamin;
839 const Index cmin = bse_cmin_ - opt_.rpamin;
840 const Index vt = bse_vtotal_;
841 const Index ct = bse_ctotal_;
842 const Index N = Mmn_.auxsize();
843 const Index chunk = HoleChunk(vt, ct, N, state_matrix_bytes_);
844 Eigen::MatrixXd G = Eigen::MatrixXd::Zero(N, N);
845 for (Index v0 = 0; v0 < vt; v0 += chunk) {
846 const Index nc = std::min(chunk, vt - v0);
847 // rows j * vt + v1: b_{v1, v0 + j}
848 Eigen::MatrixXd b = Eigen::MatrixXd::Zero(nc * vt, N);
849 for (const auto& pair : pairs) {
850 // coefficient vectors as (c, v) matrices, index v * ct + c
851 Eigen::Map<const Eigen::MatrixXd> A(pair.first->data(), ct, vt);
852 Eigen::Map<const Eigen::MatrixXd> B(pair.second->data(), ct, vt);
853 const Eigen::MatrixXd Bchunk = B.middleCols(v0, nc).transpose();
854 // T[j](c1, :) = sum_c2 B(v0 + j, c2) M[c1](c2, :)
855 std::vector<RowMajorMatrix> T(std::size_t(nc), RowMajorMatrix(ct, N));
856#pragma omp parallel for schedule(dynamic)
857 for (Index c1 = 0; c1 < ct; ++c1) {
858 const Eigen::MatrixXd t = Bchunk * Mmn_[c1 + cmin].middleRows(cmin, ct);
859 for (Index j = 0; j < nc; ++j) {
860 T[std::size_t(j)].row(c1) = t.row(j);
861 }
862 }
863#pragma omp parallel for schedule(dynamic)
864 for (Index j = 0; j < nc; ++j) {
865 b.middleRows(j * vt, vt).noalias() += A.transpose() * T[std::size_t(j)];
866 }
867 }
868 Eigen::MatrixXd a(nc * vt, N);
869#pragma omp parallel for schedule(dynamic)
870 for (Index v1 = 0; v1 < vt; ++v1) {
871 for (Index j = 0; j < nc; ++j) {
872 a.row(j * vt + v1) = Mmn_[v1 + vmin].row(vmin + v0 + j);
873 }
874 }
875 G.noalias() += b.transpose() * a;
876 }
877 return G;
878}
879
880// G with <A|Hd2|B> = -sum_PQ W_PQ G_PQ for the screened coupling term
881// Hd2(v1c1, v2c2) = -M[v1](c2,:) W M[c1](v2,:)^T:
882// G = sum_{c1 v2} b_{c1v2} a_{c1v2}^T, a_{c1v2} = M[c1](v2,:),
883// b_{c1v2} = sum_{v1 c2} A(v1,c1) B(v2,c2) M[v1](c2,:).
884Eigen::MatrixXd BSE::CouplingTermDensity(const Eigen::VectorXd& Avec,
885 const Eigen::VectorXd& Bvec) const {
886 const Index vmin = opt_.vmin - opt_.rpamin;
887 const Index cmin = bse_cmin_ - opt_.rpamin;
888 const Index vt = bse_vtotal_;
889 const Index ct = bse_ctotal_;
890 const Index N = Mmn_.auxsize();
891 const Index chunk = HoleChunk(vt, ct, N, state_matrix_bytes_);
892 Eigen::Map<const Eigen::MatrixXd> A(Avec.data(), ct, vt);
893 Eigen::Map<const Eigen::MatrixXd> B(Bvec.data(), ct, vt);
894 Eigen::MatrixXd G = Eigen::MatrixXd::Zero(N, N);
895 for (Index v0 = 0; v0 < vt; v0 += chunk) {
896 const Index nc = std::min(chunk, vt - v0);
897 const Eigen::MatrixXd Bchunk = B.middleCols(v0, nc).transpose();
898 // U[j](v1, :) = sum_c2 B(v0 + j, c2) M[v1](c2, :)
899 std::vector<RowMajorMatrix> U(std::size_t(nc), RowMajorMatrix(vt, N));
900#pragma omp parallel for schedule(dynamic)
901 for (Index v1 = 0; v1 < vt; ++v1) {
902 const Eigen::MatrixXd u = Bchunk * Mmn_[v1 + vmin].middleRows(cmin, ct);
903 for (Index j = 0; j < nc; ++j) {
904 U[std::size_t(j)].row(v1) = u.row(j);
905 }
906 }
907 // rows j * ct + c1: b_{c1, v0 + j} and a_{c1, v0 + j}
908 Eigen::MatrixXd b(nc * ct, N);
909#pragma omp parallel for schedule(dynamic)
910 for (Index j = 0; j < nc; ++j) {
911 b.middleRows(j * ct, ct).noalias() = A * U[std::size_t(j)];
912 }
913 Eigen::MatrixXd a(nc * ct, N);
914#pragma omp parallel for schedule(dynamic)
915 for (Index c1 = 0; c1 < ct; ++c1) {
916 for (Index j = 0; j < nc; ++j) {
917 a.row(j * ct + c1) = Mmn_[c1 + cmin].row(vmin + v0 + j);
918 }
919 }
920 G.noalias() += b.transpose() * a;
921 }
922 return G;
923}
924
925// Dynamical Screening in BSE as perturbation to static excitation energies
926// as in Phys. Rev. B 80, 241405 (2009) for the TDA case
927//
928// The integrals stay in the frame of the static screening set up in
929// configure, where W(0) = diag(epsilon_0_inv_). For each state, the
930// screened terms <X|Hd|X> + <Y|Hd|Y> + 2<Y|Hd2|X> are -sum_PQ W_PQ G_PQ with
931// state matrices G built once, so W(w) at the next frequency costs one
932// dielectric matrix and its eigenvectors: no pass over the BSE Hamiltonian
933// and no rotation of the integrals per state and step.
935 Orbitals& orb) {
936 // no BSE operators from here on: free the kept direct terms
938
939 const tools::EigenSystem& BSECoefs = GetBSEEigenSystem(type, orb);
940 const Eigen::VectorXd& RPAInputEnergies = orb.RPAInputEnergies();
941 const bool full = !orb.getTDAApprox();
942
943 const Eigen::VectorXd& BSEenergies = BSECoefs.eigenvalues();
944
945 // initial copy of static BSE energies to dynamic
946 Eigen::VectorXd BSEenergies_dynamic = BSEenergies;
947
948 for (Index i_exc = 0; i_exc < BSEenergies.size(); i_exc++) {
949 XTP_LOG(Log::info, log_) << "Dynamical Screening BSE, Excitation " << i_exc
950 << " static " << BSEenergies(i_exc) << flush;
951
952 const Eigen::VectorXd X = BSECoefs.eigenvectors().col(i_exc);
953 Eigen::VectorXd Y;
954 std::vector<std::pair<const Eigen::VectorXd*, const Eigen::VectorXd*>>
955 pairs{{&X, &X}};
956 if (full) {
957 Y = BSECoefs.eigenvectors2().col(i_exc);
958 pairs.emplace_back(&Y, &Y);
959 }
960 const Eigen::MatrixXd Gd = DirectTermDensity(pairs);
961 Eigen::MatrixXd G2;
962 if (full) {
963 G2 = CouplingTermDensity(Y, X);
964 }
965 // screened direct contribution for W(w), or for the static W(0)
966 auto Hd = [&](const SymmetricEigenSystem* W) {
967 double value = (W != nullptr) ? ContractScreened(*W, Gd)
968 : epsilon_0_inv_.dot(Gd.diagonal());
969 if (full) {
970 value += 2 * ((W != nullptr) ? ContractScreened(*W, G2)
971 : epsilon_0_inv_.dot(G2.diagonal()));
972 }
973 return -value;
974 };
975 const double Hd_static_contribution = Hd(nullptr);
976
977 for (Index iter = 0; iter < max_dyn_iter_; iter++) {
978
979 // screened interaction at the last energy as screening frequency
980 double old_energy = BSEenergies_dynamic(i_exc);
981 DFTTimings timings;
982 const SymmetricEigenSystem W =
983 ScreenedInteraction(RPAInputEnergies, old_energy, timings);
984
985 // new energy perturbatively
986 BSEenergies_dynamic(i_exc) =
987 BSEenergies(i_exc) + Hd_static_contribution - Hd(&W);
988
990 << "Dynamical Screening BSE, excitation " << i_exc << " iteration "
991 << iter << " dynamic " << BSEenergies_dynamic(i_exc) << flush;
992
993 // check tolerance
994 if (std::abs(BSEenergies_dynamic(i_exc) - old_energy) < dyn_tolerance_) {
995 break;
996 }
997 }
998 }
999
1000 double hrt2ev = tools::conv::hrt2ev;
1001
1002 if (type == QMStateType::Singlet) {
1003 orb.BSESinglets_dynamic() = BSEenergies_dynamic;
1004 XTP_LOG(Log::error, log_) << " ====== singlet energies with perturbative "
1005 "dynamical screening (eV) ====== "
1006 << flush;
1007 Eigen::VectorXd oscs = orb.Oscillatorstrengths();
1008 for (Index i = 0; i < opt_.nmax; ++i) {
1009 double osc = oscs[i];
1011 << boost::format(
1012 " S(dynamic) = %1$4d Omega = %2$+1.12f eV lamdba = %3$+3.2f "
1013 "nm f = %4$+1.4f") %
1014 (i + 1) % (hrt2ev * BSEenergies_dynamic(i)) %
1015 (1240.0 / (hrt2ev * BSEenergies_dynamic(i))) %
1016 (osc * BSEenergies_dynamic(i) / BSEenergies(i))
1017 << flush;
1018 }
1019
1020 } else if (type == QMStateType::Triplet) {
1021 orb.BSETriplets_dynamic() = BSEenergies_dynamic;
1022 XTP_LOG(Log::error, log_) << " ====== triplet energies with perturbative "
1023 "dynamical screening (eV) ====== "
1024 << flush;
1025 for (Index i = 0; i < opt_.nmax; ++i) {
1027 << boost::format(
1028 " T(dynamic) = %1$4d Omega = %2$+1.12f eV lamdba = %3$+3.2f "
1029 "nm ") %
1030 (i + 1) % (hrt2ev * BSEenergies_dynamic(i)) %
1031 (1240.0 / (hrt2ev * BSEenergies_dynamic(i)))
1032 << flush;
1033 }
1034
1035 } else {
1036 throw std::runtime_error(
1037 "Unsupported QMStateType in BSE::Perturbative_DynamicalScreening");
1038 }
1039}
1040
1041} // namespace xtp
1042} // namespace votca
const Eigen::MatrixXd & eigenvectors2() const
Definition eigensystem.h:36
const Eigen::VectorXd & eigenvalues() const
Definition eigensystem.h:30
const Eigen::MatrixXd & eigenvectors() const
Definition eigensystem.h:33
void setReactionField(const Eigen::MatrixXd &R, bool include_kreac)
Screen by a static polarizable environment (embedded BSE).
Definition bse.cc:209
void Solve_singlets(Orbitals &orb) const
Definition bse.cc:368
static double state_matrix_bytes_
Definition bse.h:145
DirectCaches direct_caches_
Definition bse.h:189
void DecideDirectCaches(bool coupling) const
Definition bse.cc:305
void printFragInfo(const std::vector< QMFragment< BSE_Population > > &frags, Index state) const
Definition bse.cc:574
void PrintWeights(const Eigen::VectorXd &weights) const
Definition bse.cc:590
std::string StateDynamicLabel(const QMStateType &type) const
Definition bse.cc:146
double dyn_tolerance_
Definition bse.h:155
void configure_with_precomputed_screening(const options &opt, const Eigen::VectorXd &RPAEnergies, const Eigen::MatrixXd &Hqp_in, const Eigen::VectorXd &epsilon_0_inv)
Definition bse.cc:81
void Analyze_singlets(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
Definition bse.cc:606
Eigen::MatrixXd DirectTermDensity(const std::vector< std::pair< const Eigen::VectorXd *, const Eigen::VectorXd * > > &pairs) const
Definition bse.cc:835
tools::EigenSystem Solve_triplets_BTDA() const
Definition bse.cc:499
Eigen::VectorXd ReactionFieldExchange(const tools::EigenSystem &es, bool tda) const
Definition bse.cc:397
TripletOperator_TDA getTripletOperator_TDA() const
Definition bse.cc:452
void MatchDressingToRoute()
Definition bse.cc:225
SingletOperator_TDA getSingletOperator_TDA() const
Definition bse.cc:445
options opt_
Definition bse.h:132
tools::EigenSystem Solve_singlets_BTDA() const
Definition bse.cc:488
Index bse_vmax_
Definition bse.h:148
Index bse_cmin_
Definition bse.h:149
void Perturbative_DynamicalScreening(const QMStateType &type, Orbitals &orb)
Definition bse.cc:934
void Analyze_triplets(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
Definition bse.cc:665
void SetupDirectInteractionOperator(const Eigen::VectorXd &DFTenergies, double energy)
Definition bse.cc:274
void configure(const options &opt, const Eigen::VectorXd &RPAEnergies, const Eigen::MatrixXd &Hqp_in)
Definition bse.cc:63
Eigen::MatrixXd Hqp_
Definition bse.h:160
tools::EigenSystem & GetBSEEigenSystem(const QMStateType &type, Orbitals &orb) const
Definition bse.cc:101
Eigen::VectorXd epsilon_0_inv_
Definition bse.h:157
SymmetricEigenSystem ScreenedInteraction(const Eigen::VectorXd &RPAInputEnergies, double energy, DFTTimings &timings) const
Definition bse.cc:242
void configureBSEOperator(BSE_OPERATOR &H, std::shared_ptr< SymmetricTiles > cache=nullptr) const
Definition bse.cc:291
ExpectationValues ExpectationValue_Operator(const QMStateType &type, const Orbitals &orb, const BSE_OPERATOR &H) const
Definition bse.cc:718
Interaction Analyze_eh_interaction(const QMStateType &type, const Orbitals &orb) const
Definition bse.cc:762
Index bse_ctotal_
Definition bse.h:152
double ExchangePrefactor(const QMStateType &type) const
Definition bse.cc:157
TCMatrix_gwbse & Mmn_
Definition bse.h:159
void RotateIntoScreeningFrame(const Eigen::MatrixXd &U)
Definition bse.cc:219
Index bse_size_
Definition bse.h:150
tools::EigenSystem Solve_singlets_TDA() const
Definition bse.cc:435
Eigen::MatrixXd reaction_field_
Definition bse.h:162
bool include_kreac_
Definition bse.h:164
Index max_dyn_iter_
Definition bse.h:154
tools::EigenSystem solve_hermitian(BSE_OPERATOR &h) const
Definition bse.cc:460
void Solve_triplets(Orbitals &orb) const
Definition bse.cc:426
Logger & log_
Definition bse.h:147
void ReleaseDirectCaches() const
Definition bse.cc:303
tools::EigenSystem Solve_nonhermitian_Davidson(BSE_OPERATOR_A &Aop, BSE_OPERATOR_B &Bop) const
Definition bse.cc:511
Eigen::MatrixXd AdjustHqpSize(const Eigen::MatrixXd &Hqp_in, const Eigen::VectorXd &RPAInputEnergies)
Definition bse.cc:168
Eigen::MatrixXd CouplingTermDensity(const Eigen::VectorXd &Avec, const Eigen::VectorXd &Bvec) const
Definition bse.cc:884
Index bse_vtotal_
Definition bse.h:151
std::string StateShortLabel(const QMStateType &type) const
Definition bse.cc:136
tools::EigenSystem Solve_triplets_TDA() const
Definition bse.cc:360
Eigen::MatrixXd dressing_
Definition bse.h:163
std::string StateEnergiesHeader(const QMStateType &type) const
Definition bse.cc:125
Wall-clock accounting for the parts of a DFT run.
Definition dfttimings.h:45
Scope Measure(const std::string &name)
Definition dfttimings.h:74
std::string Format() const
The entries on one line, "name 1.23 s, name 4.56 s".
Definition dfttimings.cc:58
Use Davidson algorithm to solve A*V=E*V.
void set_max_search_space(Index N)
Eigen::VectorXd eigenvalues() const
void solve(const MatrixReplacement &A, Index neigen, Index size_initial_guess=0)
void set_matrix_type(std::string mt)
void set_correction(std::string method)
void set_size_update(std::string update_size)
void set_tolerance(std::string tol)
Eigen::MatrixXd eigenvectors() const
static Eigen::MatrixXd DressingMatrix(const Eigen::MatrixXd &R)
S = (1 + R)^(1/2), the dressing of the auxiliary index that turns the bare interaction into u = v + v...
Lowest roots of the full (non-TDA) BSE.
tools::EigenSystem Solve(const OpA &A, const OpB &B, Index nroots)
static std::string Describe()
e.g. "budget 400 GB, 46.1 GB in use" or "no --memory given"
static double ResidentBytes()
Resident memory of the process (-1 if unknown on this platform).
static double AvailableBytes()
Container for molecular orbitals and derived one-particle data.
Definition orbitals.h:47
const tools::EigenSystem & BSETriplets() const
Return read-only access to triplet BSE eigenpairs.
Definition orbitals.h:483
void CalcCoupledTransition_Dipoles()
Definition orbitals.cc:774
const tools::EigenSystem & BSESinglets() const
Return read-only access to singlet BSE eigenpairs.
Definition orbitals.h:496
bool getTDAApprox() const
Return whether the Tamm-Dancoff approximation is enabled.
Definition orbitals.h:402
Eigen::VectorXd Oscillatorstrengths() const
Definition orbitals.cc:657
const std::vector< Eigen::Vector3d > & TransitionDipoles() const
Return the stored transition dipole moments.
Definition orbitals.h:540
const Eigen::VectorXd & RPAInputEnergies() const
Return read-only access to the RPA input energies.
Definition orbitals.h:443
const Eigen::VectorXd & BSETriplets_dynamic() const
Return dynamically screened triplet BSE energies.
Definition orbitals.h:523
void setTDAApprox(bool usedTDA)
Enable or disable the Tamm-Dancoff approximation flag.
Definition orbitals.h:400
const Eigen::VectorXd & BSESinglets_dynamic() const
Return dynamically screened singlet BSE energies.
Definition orbitals.h:508
void CalcChargeperFragment(std::vector< QMFragment< BSE_Population > > &frags, const Orbitals &orbitals, QMStateType type) const
void setRPAInputEnergies(const Eigen::VectorXd &rpaenergies)
Definition rpa.h:69
void setTimings(DFTTimings *timings)
Times the dielectric-matrix builds in these timings (optional).
Definition rpa.h:55
Eigen::MatrixXd calculate_epsilon_r(double frequency) const
Definition rpa.h:61
void configure(Index homo, Index rpamin, Index rpamax)
Definition rpa.h:41
static double Bytes(Index n, Index tile=DefaultTile)
Bytes the tiles of an n x n matrix need.
Timestamp returns the current time as a string Example: cout << TimeStamp().
Definition logger.h:224
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 c(Index index) const
Definition vc2index.h:48
Index v(Index index) const
Definition vc2index.h:46
#define XTP_LOG(level, log)
Definition logger.h:40
const double hrt2ev
Definition constants.h:53
Charge transport classes.
Definition ERIs.h:28
Index NormalizeExcitationVectors(Eigen::MatrixXd &X, Eigen::MatrixXd &Y)
Eigen::VectorXd ExpValue(const Eigen::MatrixXd &state1, OP OPxstate2)
Definition bse.cc:708
SymmetricEigenSystem SymmetricEigen(const Eigen::MatrixXd &A, bool vectors=true)
With vectors = false only the eigenvalues are computed.
BSE_OPERATOR< 1, 0, 0, 0 > HqpOperator
BSE_OPERATOR< 0, 0, 1, 0 > HdOperator
BSE_OPERATOR< 0, 0, 0, 1 > Hd2Operator
BSE_OPERATOR< 1, 2, 1, 0 > SingletOperator_TDA
Definition bse.h:40
Populationanalysis< true > Lowdin
Eigen::MatrixXd BuildFullBSEXRankedInitialGuess(const Eigen::VectorXd &adiag, const Eigen::VectorXd &bdiag, Index nroots)
Build an initial guess for full-BSE Davidson diagonalization.
BSE_OPERATOR< 1, 0, 1, 0 > TripletOperator_TDA
Definition bse.h:41
BSE_OPERATOR< 0, 2, 0, 1 > SingletOperator_BTDA_B
BSE_OPERATOR< 0, 1, 0, 0 > HxOperator
Eigen::MatrixXd InverseSPD(const Eigen::MatrixXd &A)
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
Eigen::VectorXd direct_term
Definition bse.h:141
Eigen::VectorXd cross_term
Definition bse.h:142
Eigen::VectorXd qp_contrib
Definition bse.h:137
Eigen::VectorXd exchange_contrib
Definition bse.h:135
Eigen::VectorXd direct_contrib
Definition bse.h:136