votca 2026-dev
Loading...
Searching...
No Matches
rpa.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2021 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// Local VOTCA includes
21#include "votca/xtp/rpa.h"
22#include "votca/xtp/aomatrix.h"
25#include "votca/xtp/vc2index.h"
26#include <iomanip>
27#include <sstream>
28
29namespace votca {
30namespace xtp {
31
32void RPA::UpdateRPAInputEnergies(const Eigen::VectorXd& dftenergies,
33 const Eigen::VectorXd& gwaenergies,
34 Index qpmin) {
35 Index rpatotal = rpamax_ - rpamin_ + 1;
36 energies_ = dftenergies.segment(rpamin_, rpatotal);
37 Index gwsize = Index(gwaenergies.size());
38
39 energies_.segment(qpmin - rpamin_, gwsize) = gwaenergies;
40
41 ShiftUncorrectedEnergies(dftenergies, qpmin, gwsize);
42}
43
44// Shifts the energies of levels in the RPA but outside the QP window, see
45// OutOfWindowShift.
46void RPA::ShiftUncorrectedEnergies(const Eigen::VectorXd& dftenergies,
47 Index qpmin, Index gwsize) {
48 out_of_window_.Apply(energies_, dftenergies, rpamin_, rpamax_, homo_, qpmin,
49 qpmin + gwsize - 1);
50}
51
53 const WeightedGram::RowsVisitor& use) const {
54 const Index n_unocc = rpamax_ - homo_;
55 use(Mmn_[m_level].bottomRows(n_unocc));
56}
57
58Eigen::MatrixXd RPA::ResponseSum(const WeightedGram::WeightsFn& weights) const {
59 const Index size = Mmn_.auxsize();
60 const Index n_occ = homo_ + 1 - rpamin_;
61 OptionalTiming timing(timings_, "screening: epsilon (RPA)");
63 n_occ, size, weights,
64 [this](Index m, const WeightedGram::RowsVisitor& use) {
66 });
67}
68
69template <bool imag>
70Eigen::MatrixXd RPA::calculate_epsilon(double frequency) const {
71 const Index n_unocc = rpamax_ - homo_;
72 const double freq2 = frequency * frequency;
73 const double eta2 = eta_ * eta_;
74 Eigen::MatrixXd result =
75 ResponseSum([&](Index m_level, Eigen::VectorXd& denom) {
76 const Eigen::ArrayXd deltaE =
77 energies_.tail(n_unocc).array() - energies_(m_level);
78 if (imag) {
79 denom = 4 * deltaE / (deltaE.square() + freq2);
80 } else {
81 Eigen::ArrayXd deltEf = deltaE - frequency;
82 Eigen::ArrayXd sum = deltEf / (deltEf.square() + eta2);
83 deltEf = deltaE + frequency;
84 sum += deltEf / (deltEf.square() + eta2);
85 denom = 2 * sum;
86 }
87 });
88 result.diagonal().array() += 1.0;
89 return result;
90}
91
92template Eigen::MatrixXd RPA::calculate_epsilon<true>(double frequency) const;
93template Eigen::MatrixXd RPA::calculate_epsilon<false>(double frequency) const;
94
95Eigen::MatrixXd RPA::calculate_epsilon_r(std::complex<double> frequency) const {
96 const Index n_unocc = rpamax_ - homo_;
97 const double sigma_1 = std::pow(frequency.imag() + eta_, 2);
98 const double sigma_2 = std::pow(frequency.imag() - eta_, 2);
99 Eigen::MatrixXd result =
100 ResponseSum([&](Index m_level, Eigen::VectorXd& chi) {
101 const Eigen::ArrayXd deltaE =
102 energies_.tail(n_unocc).array() - energies_(m_level);
103 const Eigen::ArrayXd deltaEm = frequency.real() - deltaE;
104 const Eigen::ArrayXd deltaEp = frequency.real() + deltaE;
105 // the factor -2 of the response is folded into the weights
106 chi = -2.0 * (deltaEm * (deltaEm.abs2() + sigma_1).inverse() -
107 deltaEp * (deltaEp.abs2() + sigma_2).inverse());
108 });
109 result.diagonal().array() += 1.0;
110 return result;
111}
112
114 const Index lumo = homo_ + 1;
115 const Index n_occ = lumo - rpamin_;
116 const Index n_unocc = rpamax_ - lumo + 1;
117 const Index rpasize = n_occ * n_unocc;
118
119 Eigen::VectorXd AmB = Calculate_H2p_AmB();
120 Eigen::MatrixXd ApB = Calculate_H2p_ApB();
121
123 sol.ERPA_correlation = -0.25 * (ApB.trace() + AmB.sum());
124
125 // C = AmB^1/2 * ApB * AmB^1/2
126 Eigen::MatrixXd& C = ApB;
127 C.applyOnTheLeft(AmB.cwiseSqrt().asDiagonal());
128 C.applyOnTheRight(AmB.cwiseSqrt().asDiagonal());
129
131
132 // Do not remove this line! It has to be there for MKL to not crash
133 sol.omega = Eigen::VectorXd::Zero(es.values.size());
134 sol.omega = es.values.cwiseSqrt();
135 sol.ERPA_correlation += 0.5 * sol.omega.sum();
136
137 {
138 std::ostringstream oss;
139 oss << TimeStamp() << " RKS H2p poles (first 20, eV): ";
140 const Index nprint = std::min<Index>(20, sol.omega.size());
141 for (Index i = 0; i < nprint; ++i) {
142 oss << std::fixed << std::setprecision(6)
143 << tools::conv::hrt2ev * sol.omega(i);
144 if (i + 1 < nprint) {
145 oss << ", ";
146 }
147 }
148 XTP_LOG(Log::error, log_) << oss.str() << std::flush;
149 }
150
152 << " Lowest neutral excitation energy (eV): "
153 << tools::conv::hrt2ev * sol.omega.minCoeff()
154 << std::flush;
155
156 // RPA correlation energy calculated from Eq.9 of J. Chem. Phys. 132, 234114
157 // (2010)
159 << TimeStamp()
160 << " RPA correlation energy (Hartree): " << sol.ERPA_correlation
161 << std::flush;
162
163 sol.XpY = Eigen::MatrixXd(rpasize, rpasize);
164
165 Eigen::VectorXd AmB_sqrt = AmB.cwiseSqrt();
166 Eigen::VectorXd Omega_sqrt_inv = sol.omega.cwiseSqrt().cwiseInverse();
167 for (int s = 0; s < rpasize; s++) {
168 sol.XpY.col(s) =
169 Omega_sqrt_inv(s) * AmB_sqrt.cwiseProduct(es.vectors.col(s));
170 }
171
172 return sol;
173}
174
175Eigen::VectorXd RPA::Calculate_H2p_AmB() const {
176 const Index lumo = homo_ + 1;
177 const Index n_occ = lumo - rpamin_;
178 const Index n_unocc = rpamax_ - lumo + 1;
179 const Index rpasize = n_occ * n_unocc;
180 vc2index vc = vc2index(0, 0, n_unocc);
181 Eigen::VectorXd AmB = Eigen::VectorXd::Zero(rpasize);
182 for (Index v = 0; v < n_occ; v++) {
183 Index i = vc.I(v, 0);
184 AmB.segment(i, n_unocc) =
185 energies_.segment(n_occ, n_unocc).array() - energies_(v);
186 }
187 return AmB;
188}
189
190Eigen::MatrixXd RPA::Calculate_H2p_ApB() const {
191 const Index lumo = homo_ + 1;
192 const Index n_occ = lumo - rpamin_;
193 const Index n_unocc = rpamax_ - lumo + 1;
194 const Index rpasize = n_occ * n_unocc;
195 vc2index vc = vc2index(0, 0, n_unocc);
196 Eigen::MatrixXd ApB = Eigen::MatrixXd::Zero(rpasize, rpasize);
197#pragma omp parallel for schedule(guided)
198 for (Index v2 = 0; v2 < n_occ; v2++) {
199 Index i2 = vc.I(v2, 0);
200 const Eigen::MatrixXd Mmn_v2T =
201 Mmn_[v2].middleRows(n_occ, n_unocc).transpose();
202 for (Index v1 = v2; v1 < n_occ; v1++) {
203 Index i1 = vc.I(v1, 0);
204 // Multiply with factor 2 to sum over both (identical) spin states
205 ApB.block(i1, i2, n_unocc, n_unocc) =
206 2 * 2 * Mmn_[v1].middleRows(n_occ, n_unocc) * Mmn_v2T;
207 }
208 }
209 ApB.diagonal() += Calculate_H2p_AmB();
210 return ApB;
211}
212
213SymmetricEigenSystem RPA::Diagonalize_H2p_C(const Eigen::MatrixXd& C) const {
215 << TimeStamp() << " Diagonalizing two-particle Hamiltonian "
216 << std::flush;
219 << TimeStamp() << " Diagonalization done " << std::flush;
220 double minCoeff = es.values.minCoeff();
221 if (minCoeff <= 0.0) {
223 << TimeStamp() << " Detected non-positive eigenvalue: " << minCoeff
224 << std::flush;
225 throw std::runtime_error("Detected non-positive eigenvalue.");
226 }
227 return es;
228}
229
230} // namespace xtp
231} // namespace votca
Eigen::MatrixXd Calculate_H2p_ApB() const
Definition rpa.cc:190
void ShiftUncorrectedEnergies(const Eigen::VectorXd &dftenergies, Index qpmin, Index gwsize)
Definition rpa.cc:46
Eigen::MatrixXd ResponseSum(const WeightedGram::WeightsFn &weights) const
Definition rpa.cc:58
Index rpamax_
Definition rpa.h:90
OutOfWindowShift out_of_window_
Definition rpa.h:115
Eigen::VectorXd energies_
Definition rpa.h:93
void VisitHoleVirtualRows(Index m_level, const WeightedGram::RowsVisitor &use) const
Definition rpa.cc:52
Eigen::MatrixXd calculate_epsilon(double frequency) const
Definition rpa.cc:70
Eigen::MatrixXd calculate_epsilon_r(double frequency) const
Definition rpa.h:61
const TCMatrix_gwbse & Mmn_
Definition rpa.h:96
const double eta_
Definition rpa.h:91
Index rpamin_
Definition rpa.h:89
SymmetricEigenSystem Diagonalize_H2p_C(const Eigen::MatrixXd &C) const
Definition rpa.cc:213
Eigen::VectorXd Calculate_H2p_AmB() const
Definition rpa.cc:175
Logger & log_
Definition rpa.h:95
rpa_eigensolution Diagonalize_H2p() const
Definition rpa.cc:113
void UpdateRPAInputEnergies(const Eigen::VectorXd &dftenergies, const Eigen::VectorXd &gwaenergies, Index qpmin)
Definition rpa.cc:32
DFTTimings * timings_
Definition rpa.h:97
Index homo_
Definition rpa.h:88
Timestamp returns the current time as a string Example: cout << TimeStamp().
Definition logger.h:224
std::function< void(Index m, Eigen::VectorXd &w)> WeightsFn
Writes the weights of block m; their number is the number of rows.
std::function< void(const Eigen::Ref< const Eigen::MatrixXd > &)> RowsVisitor
Calls use(R_m); R_m may be a block of stored data or a temporary.
static Eigen::MatrixXd Compute(Index nblocks, Index ncols, const WeightsFn &weights, const RowsFn &rows)
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
#define XTP_LOG(level, log)
Definition logger.h:40
const double hrt2ev
Definition constants.h:53
Charge transport classes.
Definition ERIs.h:28
SymmetricEigenSystem SymmetricEigen(const Eigen::MatrixXd &A, bool vectors=true)
With vectors = false only the eigenvalues are computed.
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26