votca 2026-dev
Loading...
Searching...
No Matches
gw.h
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#pragma once
21#ifndef VOTCA_XTP_GW_H
22#define VOTCA_XTP_GW_H
23
24#include <unordered_map>
25#include <unordered_set>
26
27// Local VOTCA includes
28#include "dfttimings.h"
29#include "logger.h"
30#include "orbitals.h"
31#include "qp_solver_utils.h"
32#include "rpa.h"
33#include "sigma_base.h"
34#include "threecenter.h"
35
36namespace votca {
37namespace xtp {
38
39class GW {
40
45
46 public:
47 GW(Logger& log, TCMatrix_gwbse& Mmn, const Eigen::MatrixXd& vxc,
48 const Eigen::VectorXd& dft_energies)
49 : log_(log),
50 Mmn_(Mmn),
51 vxc_(vxc),
52 dft_energies_(dft_energies),
53 rpa_(log, Mmn) {};
54
55 struct options {
61 double eta;
62 double g_sc_limit;
66 double shift = 0;
67 double ScaHFX = 0.0;
68 std::string sigma_integration;
69 Index reset_3c; // how often the 3c integrals in iterate should be
70 // rebuilt
71 std::string qp_solver;
72 double qp_solver_alpha = 0.75;
73 // Legacy aliases from the original grid-search implementation.
74 // They used to define both the total QP window and the scan resolution at
75 // the same time. The new implementation keeps them only so that old XML
76 // files and existing tests still work; configuration code maps them onto
77 // the decoupled controls below.
79 double qp_grid_spacing = 0.0;
80
81 // Decoupled QP search controls:
82 // - qp_full_window_half_width defines the outer full search interval
83 // - qp_dense_spacing defines the dense scan used for robust sign changes
84 // - qp_adaptive_shell_width / count define the outward shell search
85 // All values are normalized in configure(); negative values mean "unset"
86 // and trigger either legacy mapping or robust defaults.
87 double qp_full_window_half_width = -1.0; // Ha; <=0 means "unset"
88 double qp_dense_spacing = -1.0; // Ha; <=0 means "unset"
89 double qp_adaptive_shell_width = -1.0; // Ha; <=0 means "unset"
90 Index qp_adaptive_shell_count = 0; // 0 means "use shell width"
91
92 Index gw_mixing_order; // mixing order
93 double gw_mixing_alpha; // mixing alpha, also linear mixing
94 std::string quadrature_scheme; // Kind of Gaussian-quadrature scheme to use
95 Index order; // only needed for complex integration sigma CDA
96 double alpha; // smooth tail in complex integration sigma CDA
97 bool qp_restrict_search = true;
98 // evGW: after the first iteration keep each level on the root branch of
99 // the previous iteration (closest accepted root) instead of re-choosing
100 // by weight
102 // evGW: when W is rebuilt (see ScreeningUpdate): "every" or "adaptive"
103 std::string screening_update = "adaptive";
104 // evGW: after the first iteration search each level's root only near
105 // its previous one (falling back to the full search), verified by one
106 // full search after convergence
107 bool qp_root_tracking = false;
110 double qp_zero_margin = 1e-6;
112 std::string qp_root_finder = "brent";
113 std::string qp_grid_search_mode = "adaptive_with_dense_fallback";
114
115 // QSGW options
116 // When true, run quasiparticle self-consistent GW instead of evGW.
117 // The three-centre integrals are rotated at each iteration so that W and
118 // Sigma are evaluated in the basis of the current QP wavefunctions.
119 bool do_qsgw = false;
121 double qsgw_sc_limit = 1e-5; // Ha; convergence threshold on QP energies
122
123 // Maximum allowed perturbative QP correction for virtual states to be
124 // included in the QSGW self-consistency loop. Virtual states with
125 // |e_QP - e_DFT| > qsgw_max_virt_correction are excluded from the QSGW
126 // window and kept at their perturbative QP energies (DFT-MO wavefunctions).
127 // This prevents pathological high-energy basis-set artefact states from
128 // destabilising the QSGW rotation. Occupied states are never excluded.
129 // Default: 0.5 Ha (13.6 eV, 1 Rydberg) -- corrections above this are
130 // unlikely to be physically meaningful for typical molecular systems.
131 // Set to a large value (e.g. 1e10) to disable the threshold entirely.
132 double qsgw_max_virt_correction = 0.5; // Ha
133 // RPA energies of levels outside the GW window (OutOfWindowShift)
135 };
136
137 void configure(const options& opt);
138
144 Eigen::VectorXd getGWAResults() const;
145
172 void setReactionField(const Eigen::MatrixXd& R);
177 void setCoreExchange(const Eigen::MatrixXd& X) { core_exchange_ = X; }
178 const Eigen::MatrixXd& getSigmaReac() const { return Sigma_reac_; }
179
180 // Calculates the diagonal elements up to self consistency
182
183 // Calculated offdiagonal elements as well
184 void CalculateHQP();
185
202 void CalculateQSGW();
203
206 const Eigen::MatrixXd& getQSGWRotation() const { return qsgw_rotation_; }
207
209 const Eigen::VectorXd& getQSGWSeedEnergies() const {
210 return qsgw_seed_energies_;
211 }
212
221 void PrintQSGW_Energies(const std::string& seed_label,
222 const Eigen::VectorXd& seed_energies,
223 const Eigen::VectorXd& qsgw_energies) const;
224
234 void PrintQSGW_Composition(double threshold = 0.01) const;
235
236 Eigen::MatrixXd getHQP() const;
237
238 // Diagonalize QP particle Hamiltonian
239 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> DiagonalizeQPHamiltonian()
240 const;
241
242 void PlotSigma(std::string filename, Index steps, double spacing,
243 std::string states) const;
244
245 Eigen::VectorXd RPAInputEnergies() const {
246 return rpa_.getRPAInputEnergies();
247 }
248
249 private:
251 // wall-clock accounting of the GW steps, reported at the end
253
254 Eigen::MatrixXd Sigma_x_; // Fock exchange with the bare v, only
255 Eigen::MatrixXd Sigma_c_; // dynamic correlation
256 Eigen::MatrixXd reaction_field_; // R, fill-time aux frame; empty: off
257 Eigen::MatrixXd dressing_; // (1 + R)^(1/2), fill-time aux frame
258 void DressForEnvironment();
259 Eigen::MatrixXd Sigma_reac_; // static correlation from v_reac (COH+SEX)
260 void PrintReactionFieldShifts() const;
261 Eigen::MatrixXd qsgw_rotation_; // accumulated U: DFT MOs -> QSGW QP
262 // wavefunctions
263 Eigen::VectorXd qsgw_seed_energies_; // evGW/G0W0 energies used as QSGW seed
264 // Merged QSGW+seed energies for the full QP window. Set by CalculateQSGW()
265 // when the virtual window is trimmed. getGWAResults() returns this when
266 // non-empty, bypassing the sigma-matrix recomputation which would be wrong
267 // for the excluded levels.
268 Eigen::VectorXd qsgw_final_energies_;
269
271
272 std::unique_ptr<Sigma_base> sigma_ = nullptr;
275 const Eigen::MatrixXd& vxc_;
276 const Eigen::VectorXd& dft_energies_;
277
278 Eigen::MatrixXd core_exchange_; // see setCoreExchange
282
284 // small class which calculates f(w) with and df/dw(w)
285 // f=Sigma_c(w)+offset-w
286 // offset= e_dft+Sigma_x-Vxc
287 class QPFunc {
288 public:
289 QPFunc(Index gw_level, const Sigma_base& sigma, double offset)
290 : gw_level_(gw_level), offset_(offset), sigma_c_func_(sigma) {}
291
292 std::pair<double, double> operator()(double frequency) const {
293 std::pair<double, double> result;
294 result.first = value(frequency, EvalStage::Other);
295 result.second = deriv(frequency);
296 return result;
297 }
298
299 double sigma(double frequency, EvalStage stage = EvalStage::Other) const {
300 const std::uint64_t key = FrequencyKey(frequency);
301
302 auto insert_result = seen_frequencies_.insert(key);
303 if (!insert_result.second) {
304 ++stats_.sigma_repeat_calls;
305 } else {
306 ++stats_.sigma_unique_frequencies;
307 }
308
309 CountSigmaStage(stage);
310 auto cached = cache_.find(key);
311 if (cached != cache_.end()) {
312 return cached->second;
313 }
314 return sigma_c_func_.CalcCorrelationDiagElement(gw_level_, frequency);
315 }
316
319 void Prefetch(const std::vector<double>& frequencies) const {
320 std::vector<double> todo;
321 for (double f : frequencies) {
322 if (cache_.find(FrequencyKey(f)) == cache_.end()) {
323 todo.push_back(f);
324 }
325 }
326 if (todo.empty()) {
327 return;
328 }
329 const Eigen::VectorXd values = sigma_c_func_.CalcCorrelationDiagElements(
330 gw_level_,
331 Eigen::Map<const Eigen::VectorXd>(todo.data(), Index(todo.size())));
332 for (std::size_t i = 0; i < todo.size(); ++i) {
333 cache_[FrequencyKey(todo[i])] = values(Index(i));
334 }
335 }
336
337 double value(double frequency, EvalStage stage = EvalStage::Other) const {
338 return sigma(frequency, stage) + offset_ - frequency;
339 }
340
341 double deriv(double frequency) const {
342 ++stats_.deriv_calls;
343 return sigma_c_func_.CalcCorrelationDiagElementDerivative(gw_level_,
344 frequency) -
345 1.0;
346 }
347
348 const QPStats& GetStats() const { return stats_; }
349
350 private:
351 static std::uint64_t FrequencyKey(double x) {
352 std::uint64_t key = 0;
353 static_assert(sizeof(double) == sizeof(std::uint64_t),
354 "Unexpected double size");
355 std::memcpy(&key, &x, sizeof(double));
356 return key;
357 }
358
359 void CountSigmaStage(EvalStage stage) const {
360 switch (stage) {
361 case EvalStage::Scan:
362 ++stats_.sigma_scan_calls;
363 break;
364 case EvalStage::Refine:
365 ++stats_.sigma_refine_calls;
366 break;
367 case EvalStage::Derivative:
368 ++stats_.sigma_derivative_calls;
369 break;
370 case EvalStage::Other:
371 default:
372 ++stats_.sigma_other_calls;
373 break;
374 }
375 }
376
378 double offset_;
380
381 mutable std::unordered_set<std::uint64_t> seen_frequencies_;
382 mutable std::unordered_map<std::uint64_t, double> cache_;
384 };
385
386 double CalcHomoLumoShift(Eigen::VectorXd frequencies) const;
387 Eigen::VectorXd ScissorShift_DFTlevel(
388 const Eigen::VectorXd& dft_energies) const;
389 void PrintQP_Energies(const Eigen::VectorXd& qp_diag_energies) const;
390 void PrintGWA_Energies() const;
391
392 Eigen::VectorXd SolveQP(const Eigen::VectorXd& frequencies) const;
393 // HOMO-LUMO midpoint of the current QP guesses, set by SolveQP before
394 // its parallel loop and only read inside it (SolveQP_Grid).
395 mutable double qp_midgap_ = 0.0;
396 // per level of the last SolveQP: whether two accepted roots carry
397 // comparable weight (see qp_solver::CheckCompetingRoots)
398 mutable std::vector<qp_solver::CompetingRoots> competing_roots_;
399 // root tracking (opt_.qp_root_tracking): the roots of the last QP solve,
400 // their weights and their last change; active from the second iteration
401 // on until the verifying full search
402 mutable Eigen::VectorXd tracked_root_;
403 mutable Eigen::VectorXd tracked_Z_;
404 mutable Eigen::VectorXd tracked_change_;
405 mutable bool tracking_active_ = false;
406 mutable Index tracked_local_ = 0; // levels solved locally in the last solve
408 boost::optional<qp_solver::RootCandidate> SolveQP_Tracked(
409 double intercept0, double frequency0, Index gw_level,
410 QPStats* stats) const;
412 const std::vector<QPRootCandidate>& roots,
413 double chosen) const {
414 if (gw_level < Index(competing_roots_.size())) {
415 competing_roots_[std::size_t(gw_level)] =
416 qp_solver::CheckCompetingRoots(roots, chosen);
417 }
418 }
419 // logs the levels with competing roots of the last SolveQP
420 void PrintCompetingRoots(Log::Level level) const;
421 boost::optional<double> SolveQP_Grid(double intercept0, double frequency0,
422 Index gw_level,
423 QPStats* stats = nullptr) const;
424
425 boost::optional<double> SolveQP_Grid_Windowed(
426 double intercept0, double frequency0, Index gw_level, double left_limit,
427 double right_limit, bool allow_rejected_return = true,
428 QPStats* stats = nullptr) const;
429
430 boost::optional<double> SolveQP_Grid_Windowed_Adaptive(
431 double intercept0, double frequency0, Index gw_level, double left_limit,
432 double right_limit, bool allow_rejected_return = true,
433 QPStats* stats = nullptr) const;
434
435 boost::optional<double> SolveQP_Grid_Windowed_Dense(
436 double intercept0, double frequency0, Index gw_level, double left_limit,
437 double right_limit, bool allow_rejected_return = true,
438 QPStats* stats = nullptr) const;
439
440 boost::optional<double> SolveQP_FixedPoint(double intercept0,
441 double frequency0, Index gw_level,
442 QPStats* stats = nullptr) const;
443 boost::optional<double> SolveQP_Linearisation(double intercept0,
444 double frequency0,
445 Index gw_level,
446 QPStats* stats = nullptr) const;
447 bool Converged(const Eigen::VectorXd& e1, const Eigen::VectorXd& e2,
448 double epsilon) const;
449
450 boost::optional<QPRootCandidate> RefineQPInterval(
451 double lowerbound, double f_lowerbound, double upperbound,
452 double f_upperbound, const QPFunc& f, double reference) const;
453};
454} // namespace xtp
455} // namespace votca
456
457#endif // VOTCA_XTP_GW_H
Wall-clock accounting for the parts of a DFT run.
Definition dfttimings.h:45
void CountSigmaStage(EvalStage stage) const
Definition gw.h:359
std::unordered_map< std::uint64_t, double > cache_
Definition gw.h:382
double value(double frequency, EvalStage stage=EvalStage::Other) const
Definition gw.h:337
double sigma(double frequency, EvalStage stage=EvalStage::Other) const
Definition gw.h:299
const Sigma_base & sigma_c_func_
Definition gw.h:379
const QPStats & GetStats() const
Definition gw.h:348
std::unordered_set< std::uint64_t > seen_frequencies_
Definition gw.h:381
static std::uint64_t FrequencyKey(double x)
Definition gw.h:351
QPFunc(Index gw_level, const Sigma_base &sigma, double offset)
Definition gw.h:289
double deriv(double frequency) const
Definition gw.h:341
void Prefetch(const std::vector< double > &frequencies) const
Definition gw.h:319
std::pair< double, double > operator()(double frequency) const
Definition gw.h:292
boost::optional< double > SolveQP_Grid_Windowed(double intercept0, double frequency0, Index gw_level, double left_limit, double right_limit, bool allow_rejected_return=true, QPStats *stats=nullptr) const
Definition gw.cc:977
void PlotSigma(std::string filename, Index steps, double spacing, std::string states) const
Definition gw.cc:1482
Index qptotal_
Definition gw.h:250
Index QPIterations() const
Definition gw.h:141
const Eigen::VectorXd & getQSGWSeedEnergies() const
Return the seed (G0W0/evGW) energies that QSGW started from.
Definition gw.h:209
DFTTimings timings_
Definition gw.h:252
Eigen::MatrixXd reaction_field_
Definition gw.h:256
void setReactionField(const Eigen::MatrixXd &R)
Screen by a static polarizable environment (embedded GW).
Definition gw.cc:68
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonian() const
Definition gw.cc:131
void PrintGWA_Energies() const
Definition gw.cc:138
Eigen::VectorXd tracked_change_
Definition gw.h:404
double qp_midgap_
Definition gw.h:395
void setCoreExchange(const Eigen::MatrixXd &X)
Definition gw.h:177
RPA rpa_
Definition gw.h:283
boost::optional< qp_solver::RootCandidate > SolveQP_Tracked(double intercept0, double frequency0, Index gw_level, QPStats *stats) const
Definition gw.cc:730
boost::optional< QPRootCandidate > RefineQPInterval(double lowerbound, double f_lowerbound, double upperbound, double f_upperbound, const QPFunc &f, double reference) const
Index ScreeningBuilds() const
Screening builds and QP iterations of the last evGW run.
Definition gw.h:140
void PrintQSGW_Energies(const std::string &seed_label, const Eigen::VectorXd &seed_energies, const Eigen::VectorXd &qsgw_energies) const
Print a two-column comparison of seed (G0W0 or evGW) vs converged QSGW quasiparticle energies.
Definition gw.cc:221
Index TrackedLocalSolves() const
Level solves of the last evGW run done by root tracking (locally).
Definition gw.h:143
void PrintCompetingRoots(Log::Level level) const
Definition gw.cc:556
void CalculateQSGW()
Run quasiparticle self-consistent GW (QSGW).
Definition gw.cc:1178
bool Converged(const Eigen::VectorXd &e1, const Eigen::VectorXd &e2, double epsilon) const
Definition gw.cc:1125
Index qp_iterations_
Definition gw.h:280
bool tracking_active_
Definition gw.h:405
void configure(const options &opt)
Definition gw.cc:39
boost::optional< double > SolveQP_Grid_Windowed_Adaptive(double intercept0, double frequency0, Index gw_level, double left_limit, double right_limit, bool allow_rejected_return=true, QPStats *stats=nullptr) const
Definition gw.cc:771
options opt_
Definition gw.h:270
Eigen::MatrixXd getHQP() const
Definition gw.cc:125
Index tracked_local_total_
Definition gw.h:407
Eigen::VectorXd SolveQP(const Eigen::VectorXd &frequencies) const
Definition gw.cc:581
TCMatrix_gwbse & Mmn_
Definition gw.h:274
Index screening_builds_
Definition gw.h:279
Index gw_sc_iteration_
Definition gw.h:281
qp_solver::EvalStage EvalStage
Definition gw.h:41
void PrintReactionFieldShifts() const
Definition gw.cc:84
qp_solver::Stats QPStats
Definition gw.h:42
boost::optional< double > SolveQP_Grid_Windowed_Dense(double intercept0, double frequency0, Index gw_level, double left_limit, double right_limit, bool allow_rejected_return=true, QPStats *stats=nullptr) const
Definition gw.cc:846
Eigen::MatrixXd Sigma_c_
Definition gw.h:255
qp_solver::RootCandidate QPRootCandidate
Definition gw.h:43
void PrintQSGW_Composition(double threshold=0.01) const
Print the dominant DFT-KS orbital contributions to each converged QSGW quasiparticle state.
Definition gw.cc:178
Eigen::MatrixXd Sigma_reac_
Definition gw.h:259
Eigen::VectorXd qsgw_seed_energies_
Definition gw.h:263
const Eigen::VectorXd & dft_energies_
Definition gw.h:276
std::unique_ptr< Sigma_base > sigma_
Definition gw.h:272
void CalculateHQP()
Definition gw.cc:1138
std::vector< qp_solver::CompetingRoots > competing_roots_
Definition gw.h:398
Eigen::VectorXd qsgw_final_energies_
Definition gw.h:268
Logger & log_
Definition gw.h:273
Eigen::VectorXd getGWAResults() const
Definition gw.cc:545
Eigen::VectorXd RPAInputEnergies() const
Definition gw.h:245
const Eigen::MatrixXd & getSigmaReac() const
Definition gw.h:178
Eigen::VectorXd tracked_Z_
Definition gw.h:403
void DressForEnvironment()
Definition gw.cc:74
qp_solver::WindowDiagnostics QPWindowDiagnostics
Definition gw.h:44
double CalcHomoLumoShift(Eigen::VectorXd frequencies) const
Definition gw.cc:118
boost::optional< double > SolveQP_Grid(double intercept0, double frequency0, Index gw_level, QPStats *stats=nullptr) const
Definition gw.cc:1031
const Eigen::MatrixXd & vxc_
Definition gw.h:275
void RecordCompetingRoots(Index gw_level, const std::vector< QPRootCandidate > &roots, double chosen) const
Definition gw.h:411
void PrintQP_Energies(const Eigen::VectorXd &qp_diag_energies) const
Definition gw.cc:248
Index tracked_local_
Definition gw.h:406
const Eigen::MatrixXd & getQSGWRotation() const
Definition gw.h:206
boost::optional< double > SolveQP_FixedPoint(double intercept0, double frequency0, Index gw_level, QPStats *stats=nullptr) const
Definition gw.cc:1107
Eigen::VectorXd ScissorShift_DFTlevel(const Eigen::VectorXd &dft_energies) const
Definition gw.cc:275
GW(Logger &log, TCMatrix_gwbse &Mmn, const Eigen::MatrixXd &vxc, const Eigen::VectorXd &dft_energies)
Definition gw.h:47
Eigen::MatrixXd Sigma_x_
Definition gw.h:254
boost::optional< double > SolveQP_Linearisation(double intercept0, double frequency0, Index gw_level, QPStats *stats=nullptr) const
Definition gw.cc:752
void CalculateGWPerturbation()
Definition gw.cc:283
Eigen::MatrixXd qsgw_rotation_
Definition gw.h:261
Eigen::MatrixXd dressing_
Definition gw.h:257
Eigen::MatrixXd core_exchange_
Definition gw.h:278
Eigen::VectorXd tracked_root_
Definition gw.h:402
Logger is used for thread-safe output of messages.
Definition logger.h:164
CompetingRoots CheckCompetingRoots(const std::vector< RootCandidate > &roots, double chosen)
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
Level
be loud and noisy
Definition globals.h:28
OutOfWindowShift out_of_window_shift
Definition gw.h:134
double qp_full_window_half_width
Definition gw.h:87
double qsgw_sc_limit
Definition gw.h:121
double qsgw_max_virt_correction
Definition gw.h:132
Index qp_adaptive_shell_count
Definition gw.h:90
double qp_adaptive_shell_width
Definition gw.h:89
std::string screening_update
Definition gw.h:103
double qp_solver_alpha
Definition gw.h:72
double screening_update_ratio
Definition gw.h:108
double qp_zero_margin
Definition gw.h:110
double gw_sc_limit
Definition gw.h:64
std::string qp_grid_search_mode
Definition gw.h:113
double qp_virtual_min_energy
Definition gw.h:111
Index screening_update_max_inner
Definition gw.h:109
Index gw_mixing_order
Definition gw.h:92
Index gw_sc_max_iterations
Definition gw.h:65
Index qp_grid_steps
Definition gw.h:78
std::string quadrature_scheme
Definition gw.h:94
std::string qp_solver
Definition gw.h:71
Index g_sc_max_iterations
Definition gw.h:63
double qp_grid_spacing
Definition gw.h:79
double g_sc_limit
Definition gw.h:62
std::string qp_root_finder
Definition gw.h:112
double gw_mixing_alpha
Definition gw.h:93
std::string sigma_integration
Definition gw.h:68
bool qp_root_continuity
Definition gw.h:101
double qp_dense_spacing
Definition gw.h:88
Index qsgw_max_iterations
Definition gw.h:120
bool qp_restrict_search
Definition gw.h:97
How the RPA energies of levels outside the GW window are shifted.