49double DavidsonToleranceValue(
const std::string& tol) {
52 }
else if (tol ==
"normal") {
54 }
else if (tol ==
"strict") {
56 }
else if (tol ==
"lapack") {
59 throw std::runtime_error(tol +
" is not a valid Davidson tolerance");
64 const Eigen::MatrixXd& Hqp_in) {
73 if (
opt_.use_Hqp_offdiag) {
82 const options& opt,
const Eigen::VectorXd& RPAInputEnergies,
83 const Eigen::MatrixXd& Hqp_in,
const Eigen::VectorXd& epsilon_0_inv) {
92 if (
opt_.use_Hqp_offdiag) {
108 throw std::runtime_error(
109 "Unsupported QMStateType in BSE::GetBSEEigenSystem");
120 throw std::runtime_error(
121 "Unsupported QMStateType in BSE::GetBSEEigenSystem");
127 return " ====== singlet energies (eV) ====== ";
129 return " ====== triplet energies (eV) ====== ";
131 throw std::runtime_error(
132 "Unsupported QMStateType in BSE::StateEnergiesHeader");
142 throw std::runtime_error(
"Unsupported QMStateType in BSE::StateShortLabel");
152 throw std::runtime_error(
153 "Unsupported QMStateType in BSE::StateDynamicLabel");
163 throw std::runtime_error(
164 "Unsupported QMStateType in BSE::ExchangePrefactor");
169 const Eigen::VectorXd& RPAInputEnergies) {
174 Eigen::MatrixXd Hqp_BSE = Eigen::MatrixXd::Zero(hqp_size, hqp_size);
179 Hqp_BSE = Hqp.block(start, start, hqp_size, hqp_size);
181 Index virtoffset = gwsize - start;
182 Hqp_BSE.topLeftCorner(virtoffset, virtoffset) =
183 Hqp.block(start, start, virtoffset, virtoffset);
186 Hqp_BSE.diagonal().tail(virt_extra) =
187 RPAInputEnergies.segment(RPAoffset + virtoffset, virt_extra);
193 Hqp_BSE.diagonal().head(occ_extra) =
194 RPAInputEnergies.segment(RPAoffset, occ_extra);
196 Hqp_BSE.block(occ_extra, occ_extra, gwsize, gwsize) = Hqp;
199 Index virtoffset = occ_extra + gwsize;
201 Hqp_BSE.diagonal().tail(virt_extra) =
202 RPAInputEnergies.segment(RPAoffset + virtoffset, virt_extra);
222 Mmn_.MultiplyRightWithAuxMatrixLeading(U, occupied_slices, lead);
232 if (dressed_route && !
Mmn_.Dressed()) {
234 }
else if (!dressed_route &&
Mmn_.Dressed()) {
235 Mmn_.UndressAuxIndex();
243 const Eigen::VectorXd& RPAInputEnergies,
double energy,
251 auto t = timings.
Measure(
"eigensolver");
257 const Index n = screening.rows();
258 const Eigen::MatrixXd
I = Eigen::MatrixXd::Identity(n, n);
260 const Eigen::MatrixXd u_inv =
262 Eigen::MatrixXd W =
InverseSPD(u_inv + screening -
I);
263 W = 0.5 * (W + W.transpose()).eval();
275 const Eigen::VectorXd& RPAInputEnergies,
double energy) {
282 auto t = timings.
Measure(
"rotation");
287 <<
" Ha: " << timings.
Format() << flush;
290template <
typename BSE_OPERATOR>
292 std::shared_ptr<SymmetricTiles> cache)
const {
300 H.set_direct_cache(std::move(cache));
309 double pending = 0.0;
311 if (*c !=
nullptr && !(*c)->built()) {
316 std::ostringstream msg;
318 msg <<
" BSE direct terms (lower triangle, " << need * 1
e-9 <<
" GB each):";
319 auto decide = [&](std::shared_ptr<SymmetricTiles>& cache,
bool& decided,
322 msg <<
" " << name << (cache ?
" kept (reused)" :
" not kept") <<
";";
326 if (need <= available) {
327 cache = std::make_shared<SymmetricTiles>();
329 msg <<
" " << name <<
" kept;";
331 msg <<
" " << name <<
" not kept;";
345 auto unbuilt = [](
const std::shared_ptr<SymmetricTiles>& c) {
346 return c ==
nullptr || !c->built();
353 const double wanted = resident + extra;
354 msg <<
"; --memory " << std::ceil(1.1 * wanted * 1
e-9 + 1.0)
355 <<
" or more would keep all";
378 const Eigen::VectorXd kreac =
381 <<
TimeStamp() <<
" Environment K_reac (linear-response part), "
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> = "
407 Eigen::VectorXd result = Eigen::VectorXd::Zero(nstates);
408#pragma omp parallel for schedule(dynamic)
409 for (
Index s = 0; s < nstates; ++s) {
414 const Eigen::Map<const Eigen::MatrixXd> mat(coeffs.data(),
bse_ctotal_,
416 Eigen::VectorXd d = Eigen::VectorXd::Zero(
Mmn_.auxsize());
421 result(s) = 2.0 * d.dot(Rc * d);
441 <<
TimeStamp() <<
" Setup TDA singlet hamiltonian " << flush;
459template <
typename BSE_OPERATOR>
462 std::chrono::time_point<std::chrono::system_clock> start =
463 std::chrono::system_clock::now();
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;
483 << elapsed_time.count() <<
" secs" << flush;
495 <<
TimeStamp() <<
" Setup Full singlet hamiltonian " << flush;
506 <<
TimeStamp() <<
" Setup Full triplet hamiltonian " << flush;
510template <
typename BSE_OPERATOR_A,
typename BSE_OPERATOR_B>
512 BSE_OPERATOR_B& Bop)
const {
518 fopt.
tolerance = DavidsonToleranceValue(
opt_.davidson_tolerance);
522 return solver.
Solve(Aop, Bop,
opt_.nmax);
523 }
catch (
const std::runtime_error& error) {
526 <<
"; using the non-Hermitian Davidson solver" << flush;
529 std::chrono::time_point<std::chrono::system_clock> start =
530 std::chrono::system_clock::now();
544 Aop.diagonal(), Bop.diagonal(),
opt_.nmax);
551 Eigen::MatrixXd tmpX = DS.
eigenvectors().topRows(Aop.rows());
552 Eigen::MatrixXd tmpY = DS.
eigenvectors().bottomRows(Bop.rows());
558 <<
" BSE root(s) without positive X^2 - Y^2 norm (not converged?)"
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;
569 << elapsed_time.count() <<
" secs" << flush;
577 double dq = frag.value().H[state] + frag.value().E[state];
578 double qeff = dq + frag.value().Gs;
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
593 double weight = weights(i_bse);
594 if (weight >
opt_.min_print_weight) {
597 " HOMO-%1$-3d -> LUMO+%2$-3d : %3$3.1f%%") %
598 (
opt_.homo - vc.
v(i_bse)) % (vc.
c(i_bse) -
opt_.homo - 1) %
614 if (fragments.size() > 0) {
620 const Eigen::VectorXd& energies = bse.
eigenvalues();
625 Eigen::VectorXd weights = bse.
eigenvectors().col(i).cwiseAbs2();
630 double osc = oscs[i];
635 const std::string kx_label = dressed ?
"<K_x+K_reac>" :
"<K_x>";
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") %
641 (1240.0 / (hrt2ev * energies(i))) %
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
656 if (fragments.size() > 0) {
671 if (fragments.size() > 0) {
677 const Eigen::VectorXd& energies = bse.
eigenvalues();
681 Eigen::VectorXd weights = bse.
eigenvectors().col(i).cwiseAbs2();
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") %
698 if (fragments.size() > 0) {
708Eigen::VectorXd
ExpValue(
const Eigen::MatrixXd& state1, OP OPxstate2) {
709 return state1.cwiseProduct(OPxstate2.eval()).colwise().sum().transpose();
712Eigen::VectorXd
ExpValue(
const Eigen::MatrixXd& state1,
713 const Eigen::MatrixXd& OPxstate2) {
714 return state1.cwiseProduct(OPxstate2).colwise().sum().transpose();
717template <
typename BSE_OPERATOR>
734 expectation_values.
cross_term = Eigen::VectorXd::Zero(0);
736 return expectation_values;
756std::shared_ptr<SymmetricTiles> ReusableCache(
757 const std::shared_ptr<SymmetricTiles>& cache) {
758 return (cache !=
nullptr && cache->built()) ? cache :
nullptr;
810using RowMajorMatrix =
811 Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
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);
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() *
836 const std::vector<std::pair<
const Eigen::VectorXd*,
837 const Eigen::VectorXd*>>& pairs)
const {
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);
848 Eigen::MatrixXd b = Eigen::MatrixXd::Zero(nc * vt, N);
849 for (
const auto& pair : pairs) {
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();
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);
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)];
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);
875 G.noalias() += b.transpose() * a;
885 const Eigen::VectorXd& Bvec)
const {
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();
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);
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)];
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);
920 G.noalias() += b.transpose() * a;
943 const Eigen::VectorXd& BSEenergies = BSECoefs.
eigenvalues();
946 Eigen::VectorXd BSEenergies_dynamic = BSEenergies;
948 for (
Index i_exc = 0; i_exc < BSEenergies.size(); i_exc++) {
950 <<
" static " << BSEenergies(i_exc) << flush;
952 const Eigen::VectorXd X = BSECoefs.
eigenvectors().col(i_exc);
954 std::vector<std::pair<const Eigen::VectorXd*, const Eigen::VectorXd*>>
958 pairs.emplace_back(&Y, &Y);
967 double value = (W !=
nullptr) ? ContractScreened(*W, Gd)
970 value += 2 * ((W !=
nullptr) ? ContractScreened(*W, G2)
975 const double Hd_static_contribution = Hd(
nullptr);
980 double old_energy = BSEenergies_dynamic(i_exc);
986 BSEenergies_dynamic(i_exc) =
987 BSEenergies(i_exc) + Hd_static_contribution - Hd(&W);
990 <<
"Dynamical Screening BSE, excitation " << i_exc <<
" iteration "
991 << iter <<
" dynamic " << BSEenergies_dynamic(i_exc) << flush;
994 if (std::abs(BSEenergies_dynamic(i_exc) - old_energy) <
dyn_tolerance_) {
1005 "dynamical screening (eV) ====== "
1009 double osc = oscs[i];
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))
1023 "dynamical screening (eV) ====== "
1028 " T(dynamic) = %1$4d Omega = %2$+1.12f eV lamdba = %3$+3.2f "
1030 (i + 1) % (hrt2ev * BSEenergies_dynamic(i)) %
1031 (1240.0 / (hrt2ev * BSEenergies_dynamic(i)))
1036 throw std::runtime_error(
1037 "Unsupported QMStateType in BSE::Perturbative_DynamicalScreening");
void setReactionField(const Eigen::MatrixXd &R, bool include_kreac)
Screen by a static polarizable environment (embedded BSE).
void Solve_singlets(Orbitals &orb) const
static double state_matrix_bytes_
DirectCaches direct_caches_
void DecideDirectCaches(bool coupling) const
void printFragInfo(const std::vector< QMFragment< BSE_Population > > &frags, Index state) const
void PrintWeights(const Eigen::VectorXd &weights) const
std::string StateDynamicLabel(const QMStateType &type) const
void configure_with_precomputed_screening(const options &opt, const Eigen::VectorXd &RPAEnergies, const Eigen::MatrixXd &Hqp_in, const Eigen::VectorXd &epsilon_0_inv)
void Analyze_singlets(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
Eigen::MatrixXd DirectTermDensity(const std::vector< std::pair< const Eigen::VectorXd *, const Eigen::VectorXd * > > &pairs) const
tools::EigenSystem Solve_triplets_BTDA() const
Eigen::VectorXd ReactionFieldExchange(const tools::EigenSystem &es, bool tda) const
TripletOperator_TDA getTripletOperator_TDA() const
void MatchDressingToRoute()
SingletOperator_TDA getSingletOperator_TDA() const
tools::EigenSystem Solve_singlets_BTDA() const
void Perturbative_DynamicalScreening(const QMStateType &type, Orbitals &orb)
void Analyze_triplets(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
void SetupDirectInteractionOperator(const Eigen::VectorXd &DFTenergies, double energy)
void configure(const options &opt, const Eigen::VectorXd &RPAEnergies, const Eigen::MatrixXd &Hqp_in)
tools::EigenSystem & GetBSEEigenSystem(const QMStateType &type, Orbitals &orb) const
Eigen::VectorXd epsilon_0_inv_
SymmetricEigenSystem ScreenedInteraction(const Eigen::VectorXd &RPAInputEnergies, double energy, DFTTimings &timings) const
void configureBSEOperator(BSE_OPERATOR &H, std::shared_ptr< SymmetricTiles > cache=nullptr) const
ExpectationValues ExpectationValue_Operator(const QMStateType &type, const Orbitals &orb, const BSE_OPERATOR &H) const
Interaction Analyze_eh_interaction(const QMStateType &type, const Orbitals &orb) const
double ExchangePrefactor(const QMStateType &type) const
void RotateIntoScreeningFrame(const Eigen::MatrixXd &U)
tools::EigenSystem Solve_singlets_TDA() const
Eigen::MatrixXd reaction_field_
tools::EigenSystem solve_hermitian(BSE_OPERATOR &h) const
void Solve_triplets(Orbitals &orb) const
void ReleaseDirectCaches() const
tools::EigenSystem Solve_nonhermitian_Davidson(BSE_OPERATOR_A &Aop, BSE_OPERATOR_B &Bop) const
Eigen::MatrixXd AdjustHqpSize(const Eigen::MatrixXd &Hqp_in, const Eigen::VectorXd &RPAInputEnergies)
Eigen::MatrixXd CouplingTermDensity(const Eigen::VectorXd &Avec, const Eigen::VectorXd &Bvec) const
std::string StateShortLabel(const QMStateType &type) const
tools::EigenSystem Solve_triplets_TDA() const
Eigen::MatrixXd dressing_
std::string StateEnergiesHeader(const QMStateType &type) const
Wall-clock accounting for the parts of a DFT run.
Scope Measure(const std::string &name)
std::string Format() const
The entries on one line, "name 1.23 s, name 4.56 s".
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_iter_max(Index N)
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.
const tools::EigenSystem & BSETriplets() const
Return read-only access to triplet BSE eigenpairs.
void CalcCoupledTransition_Dipoles()
const tools::EigenSystem & BSESinglets() const
Return read-only access to singlet BSE eigenpairs.
bool getTDAApprox() const
Return whether the Tamm-Dancoff approximation is enabled.
Eigen::VectorXd Oscillatorstrengths() const
const std::vector< Eigen::Vector3d > & TransitionDipoles() const
Return the stored transition dipole moments.
const Eigen::VectorXd & RPAInputEnergies() const
Return read-only access to the RPA input energies.
const Eigen::VectorXd & BSETriplets_dynamic() const
Return dynamically screened triplet BSE energies.
void setTDAApprox(bool usedTDA)
Enable or disable the Tamm-Dancoff approximation flag.
const Eigen::VectorXd & BSESinglets_dynamic() const
Return dynamically screened singlet BSE energies.
void CalcChargeperFragment(std::vector< QMFragment< BSE_Population > > &frags, const Orbitals &orbitals, QMStateType type) const
void setRPAInputEnergies(const Eigen::VectorXd &rpaenergies)
void setTimings(DFTTimings *timings)
Times the dielectric-matrix builds in these timings (optional).
Eigen::MatrixXd calculate_epsilon_r(double frequency) const
void configure(Index homo, Index rpamin, Index rpamax)
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().
This class transforms a pair of indices v,c into a compound index I, via I=ctotal*v+c the fast dimens...
Index c(Index index) const
Index v(Index index) const
#define XTP_LOG(level, log)
Charge transport classes.
Index NormalizeExcitationVectors(Eigen::MatrixXd &X, Eigen::MatrixXd &Y)
Eigen::VectorXd ExpValue(const Eigen::MatrixXd &state1, OP OPxstate2)
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
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
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.
Eigen::VectorXd direct_term
Eigen::VectorXd cross_term
Eigen::VectorXd qp_contrib
Eigen::VectorXd exchange_contrib
Eigen::VectorXd direct_contrib