votca 2026-dev
Loading...
Searching...
No Matches
gw_uks.h
Go to the documentation of this file.
1/*
2 * Copyright 2009-2026 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 */
7#pragma once
8#ifndef VOTCA_XTP_GW_UKS_H
9#define VOTCA_XTP_GW_UKS_H
10
11#include <memory>
12#include <unordered_set>
13
14#include "logger.h"
15#include "orbitals.h"
16#include "qp_solver_utils.h"
17#include "rpa_uks.h"
18#include "sigma_base_uks.h"
19#include "threecenter.h"
20#include "votca/xtp/ppm.h"
21
22namespace votca {
23namespace xtp {
24
25class GW_UKS {
26
31
32 public:
33 struct options {
34 // RPA energies of levels outside the GW window (OutOfWindowShift)
42 double eta;
43 double g_sc_limit;
47 double shift = 0;
48 double ScaHFX = 0.0;
49 std::string sigma_integration;
51 std::string qp_solver;
52 double qp_solver_alpha = 0.75;
53 // Legacy aliases from the original grid-search implementation.
54 // They used to define both the total QP window and the scan resolution at
55 // the same time. The new implementation keeps them only so that old XML
56 // files and existing tests still work; configuration code maps them onto
57 // the decoupled controls below.
59 double qp_grid_spacing = 0.0;
60
61 // Decoupled QP search controls:
62 // - qp_full_window_half_width defines the outer full search interval
63 // - qp_dense_spacing defines the dense scan used for robust sign changes
64 // - qp_adaptive_shell_width / count define the outward shell search
65 // All values are normalized in configure(); negative values mean "unset"
66 // and trigger either legacy mapping or robust defaults.
67 double qp_full_window_half_width = -1.0; // Ha; <=0 means "unset"
68 double qp_dense_spacing = -1.0; // Ha; <=0 means "unset"
69 double qp_adaptive_shell_width = -1.0; // Ha; <=0 means "unset"
70 Index qp_adaptive_shell_count = 0; // 0 means "use shell width"
73 std::string quadrature_scheme;
75 double alpha;
76 bool qp_restrict_search = true;
77 // evGW: after the first iteration keep each level on the root branch of
78 // the previous iteration (closest accepted root) instead of re-choosing
79 // by weight
80 bool qp_root_continuity = true;
81 // evGW: when W is rebuilt (see ScreeningUpdate): "every" or "adaptive"
82 std::string screening_update = "adaptive";
83 // evGW: after the first iteration search each level's root only near
84 // its previous one (falling back to the full search), verified by one
85 // full search after convergence
86 bool qp_root_tracking = false;
89 double qp_zero_margin = 1e-6;
90 double qp_virtual_min_energy = -0.1;
91 std::string qp_root_finder = "brent";
92 std::string qp_grid_search_mode = "adaptive_with_dense_fallback";
93 };
94
96 const Eigen::MatrixXd& vxc_alpha, const Eigen::MatrixXd& vxc_beta,
97 const Eigen::VectorXd& dft_energies_alpha,
98 const Eigen::VectorXd& dft_energies_beta);
99
100 void configure(const options& opt);
103 void setCoreExchange(const Eigen::MatrixXd& alpha,
104 const Eigen::MatrixXd& beta) {
105 core_exchange_alpha_ = alpha;
106 core_exchange_beta_ = beta;
107 }
108 void CalculateHQP();
109
110 Eigen::VectorXd getGWAResultsAlpha() const;
111 Eigen::VectorXd getGWAResultsBeta() const;
112 const Eigen::VectorXd& RPAInputEnergiesAlpha() const;
113 const Eigen::VectorXd& RPAInputEnergiesBeta() const;
114 Eigen::MatrixXd getHQPAlpha() const;
115 Eigen::MatrixXd getHQPBeta() const;
116 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> DiagonalizeQPHamiltonianAlpha()
117 const;
118 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> DiagonalizeQPHamiltonianBeta()
119 const;
125
126 private:
127 enum class Spin { Alpha, Beta };
128
129 class QPFunc {
130 public:
131 QPFunc(Index gw_level, const Sigma_base_UKS& sigma, double offset)
132 : gw_level_(gw_level), offset_(offset), sigma_c_func_(sigma) {}
133
134 std::pair<double, double> operator()(double frequency) const {
135 std::pair<double, double> result;
136 result.first = value(frequency, EvalStage::Other);
137 result.second = deriv(frequency);
138 return result;
139 }
140
141 double sigma(double frequency, EvalStage stage = EvalStage::Other) const {
142 const std::uint64_t key = FrequencyKey(frequency);
143
144 auto insert_result = seen_frequencies_.insert(key);
145 if (!insert_result.second) {
146 ++stats_.sigma_repeat_calls;
147 } else {
148 ++stats_.sigma_unique_frequencies;
149 }
150
151 CountSigmaStage(stage);
152 auto cached = cache_.find(key);
153 if (cached != cache_.end()) {
154 return cached->second;
155 }
156 return sigma_c_func_.CalcCorrelationDiagElement(gw_level_, frequency);
157 }
158
162 void Prefetch(const std::vector<double>& frequencies) const {
163 std::vector<double> todo;
164 for (double f : frequencies) {
165 if (cache_.find(FrequencyKey(f)) == cache_.end()) {
166 todo.push_back(f);
167 }
168 }
169 if (todo.empty()) {
170 return;
171 }
172 const Eigen::VectorXd values = sigma_c_func_.CalcCorrelationDiagElements(
173 gw_level_,
174 Eigen::Map<const Eigen::VectorXd>(todo.data(), Index(todo.size())));
175 for (std::size_t i = 0; i < todo.size(); ++i) {
176 cache_[FrequencyKey(todo[i])] = values(Index(i));
177 }
178 }
179
180 double value(double frequency, EvalStage stage = EvalStage::Other) const {
181 return sigma(frequency, stage) + offset_ - frequency;
182 }
183
184 double deriv(double frequency) const {
185 ++stats_.deriv_calls;
186 return sigma_c_func_.CalcCorrelationDiagElementDerivative(gw_level_,
187 frequency) -
188 1.0;
189 }
190
191 const QPStats& GetStats() const { return stats_; }
192
193 private:
194 static std::uint64_t FrequencyKey(double x) {
195 std::uint64_t key = 0;
196 static_assert(sizeof(double) == sizeof(std::uint64_t),
197 "Unexpected double size");
198 std::memcpy(&key, &x, sizeof(double));
199 return key;
200 }
201
202 void CountSigmaStage(EvalStage stage) const {
203 switch (stage) {
204 case EvalStage::Scan:
205 ++stats_.sigma_scan_calls;
206 break;
207 case EvalStage::Refine:
208 ++stats_.sigma_refine_calls;
209 break;
210 case EvalStage::Derivative:
211 ++stats_.sigma_derivative_calls;
212 break;
213 case EvalStage::Other:
214 default:
215 ++stats_.sigma_other_calls;
216 break;
217 }
218 }
219
221 double offset_;
223
224 mutable std::unordered_set<std::uint64_t> seen_frequencies_;
225 mutable std::unordered_map<std::uint64_t, double> cache_;
227 };
228
230 const Eigen::VectorXd& DftEnergies(Spin spin) const;
231 const Eigen::MatrixXd& Vxc(Spin spin) const;
232 Eigen::MatrixXd& SigmaX(Spin spin);
233 Eigen::MatrixXd& SigmaC(Spin spin);
234 const Eigen::MatrixXd& SigmaX(Spin spin) const;
235 const Eigen::MatrixXd& SigmaC(Spin spin) const;
237 const Sigma_base_UKS& SigmaEvaluator(Spin spin) const;
238 Index Homo(Spin spin) const;
239 const char* SpinName(Spin spin) const;
240
241 Eigen::VectorXd ScissorShift_DFTlevel(const Eigen::VectorXd& dft_energies,
242 Index homo) const;
243 double CalcSpinHomoLumoShift(const Eigen::VectorXd& frequencies,
244 Spin spin) const;
245 void PrintGWA_Energies(Spin spin) const;
246 void PrintQP_Energies(Spin spin,
247 const Eigen::VectorXd& qp_diag_energies) const;
248 Eigen::VectorXd SolveQP(Spin spin, const Eigen::VectorXd& frequencies) const;
249 // per spin and level of the last SolveQP: whether two accepted roots carry
250 // comparable weight (see qp_solver::CheckCompetingRoots)
251 mutable std::vector<qp_solver::CompetingRoots> competing_roots_[2];
252 // root tracking per spin (see GW): roots, weights, last changes
253 mutable Eigen::VectorXd tracked_root_[2];
254 mutable Eigen::VectorXd tracked_Z_[2];
255 mutable Eigen::VectorXd tracked_change_[2];
256 mutable bool tracking_active_ = false;
258 Eigen::MatrixXd core_exchange_alpha_; // see setCoreExchange
259 Eigen::MatrixXd core_exchange_beta_;
262 void RecordCompetingRoots(Spin spin, Index gw_level,
263 const std::vector<QPRootCandidate>& roots,
264 double chosen) const {
265 auto& list = competing_roots_[spin == Spin::Alpha ? 0 : 1];
266 if (gw_level < Index(list.size())) {
267 list[std::size_t(gw_level)] =
268 qp_solver::CheckCompetingRoots(roots, chosen);
269 }
270 }
271 void PrintCompetingRoots(Spin spin, Log::Level level) const;
272
273 boost::optional<double> SolveQP_Grid(Spin spin, double intercept0,
274 double frequency0, Index gw_level,
275 QPStats* stats = nullptr) const;
276
277 boost::optional<double> SolveQP_Grid_Windowed(
278 Spin spin, double intercept0, double frequency0, Index gw_level,
279 double left_limit, double right_limit, bool allow_rejected_return = true,
280 QPStats* stats = nullptr) const;
281
282 boost::optional<double> SolveQP_Grid_Windowed_Adaptive(
283 Spin spin, double intercept0, double frequency0, Index gw_level,
284 double left_limit, double right_limit, bool allow_rejected_return = true,
285 QPStats* stats = nullptr) const;
286
287 boost::optional<double> SolveQP_Grid_Windowed_Dense(
288 Spin spin, double intercept0, double frequency0, Index gw_level,
289 double left_limit, double right_limit, bool allow_rejected_return = true,
290 QPStats* stats = nullptr) const;
291
292 boost::optional<double> SolveQP_FixedPoint(Spin spin, double intercept0,
293 double frequency0, Index gw_level,
294 QPStats* stats = nullptr) const;
295
296 boost::optional<double> SolveQP_Linearisation(Spin spin, double intercept0,
297 double frequency0,
298 Index gw_level,
299 QPStats* stats = nullptr) const;
300
301 bool Converged(const Eigen::VectorXd& e1, const Eigen::VectorXd& e2,
302 double epsilon) const;
303
304 boost::optional<QPRootCandidate> RefineQPInterval(
305 double lowerbound, double f_lowerbound, double upperbound,
306 double f_upperbound, const QPFunc& f, double reference) const;
307
308 std::string LevelLabel(Spin spin, Index level) const;
309 const char* OccupationTag(Spin spin, Index level) const;
310
316 const Eigen::MatrixXd& vxc_alpha_;
317 const Eigen::MatrixXd& vxc_beta_;
318 const Eigen::VectorXd& dft_energies_alpha_;
319 const Eigen::VectorXd& dft_energies_beta_;
321 std::unique_ptr<Sigma_base_UKS> sigma_alpha_;
322 std::unique_ptr<Sigma_base_UKS> sigma_beta_;
323 Eigen::MatrixXd Sigma_x_alpha_;
324 Eigen::MatrixXd Sigma_x_beta_;
325 Eigen::MatrixXd Sigma_c_alpha_;
326 Eigen::MatrixXd Sigma_c_beta_;
327};
328
329} // namespace xtp
330} // namespace votca
331
332#endif
void CountSigmaStage(EvalStage stage) const
Definition gw_uks.h:202
std::pair< double, double > operator()(double frequency) const
Definition gw_uks.h:134
std::unordered_set< std::uint64_t > seen_frequencies_
Definition gw_uks.h:224
double sigma(double frequency, EvalStage stage=EvalStage::Other) const
Definition gw_uks.h:141
const QPStats & GetStats() const
Definition gw_uks.h:191
double deriv(double frequency) const
Definition gw_uks.h:184
double value(double frequency, EvalStage stage=EvalStage::Other) const
Definition gw_uks.h:180
static std::uint64_t FrequencyKey(double x)
Definition gw_uks.h:194
void Prefetch(const std::vector< double > &frequencies) const
Definition gw_uks.h:162
QPFunc(Index gw_level, const Sigma_base_UKS &sigma, double offset)
Definition gw_uks.h:131
const Sigma_base_UKS & sigma_c_func_
Definition gw_uks.h:222
std::unordered_map< std::uint64_t, double > cache_
Definition gw_uks.h:225
boost::optional< double > SolveQP_Grid_Windowed(Spin spin, double intercept0, double frequency0, Index gw_level, double left_limit, double right_limit, bool allow_rejected_return=true, QPStats *stats=nullptr) const
Definition gw_uks.cc:913
Index TrackedLocalSolves() const
Definition gw_uks.h:124
void PrintCompetingRoots(Spin spin, Log::Level level) const
Definition gw_uks.cc:478
TCMatrix_gwbse_spin & Mmn_
Definition gw_uks.h:315
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonianAlpha() const
Definition gw_uks.cc:1028
Index ScreeningBuilds() const
Definition gw_uks.h:122
bool Converged(const Eigen::VectorXd &e1, const Eigen::VectorXd &e2, double epsilon) const
Definition gw_uks.cc:991
Eigen::MatrixXd core_exchange_alpha_
Definition gw_uks.h:258
void PrintQP_Energies(Spin spin, const Eigen::VectorXd &qp_diag_energies) const
Definition gw_uks.cc:1081
Eigen::MatrixXd & SigmaC(Spin spin)
Definition gw_uks.cc:138
const Eigen::VectorXd & DftEnergies(Spin spin) const
Definition gw_uks.cc:129
std::unique_ptr< Sigma_base_UKS > sigma_alpha_
Definition gw_uks.h:321
boost::optional< double > SolveQP_Linearisation(Spin spin, double intercept0, double frequency0, Index gw_level, QPStats *stats=nullptr) const
Definition gw_uks.cc:626
std::string LevelLabel(Spin spin, Index level) const
Definition gw_uks.cc:160
Eigen::VectorXd tracked_Z_[2]
Definition gw_uks.h:254
Index qp_iterations_
Definition gw_uks.h:261
Eigen::MatrixXd Sigma_x_alpha_
Definition gw_uks.h:323
std::unique_ptr< Sigma_base_UKS > sigma_beta_
Definition gw_uks.h:322
boost::optional< double > SolveQP_Grid_Windowed_Adaptive(Spin spin, double intercept0, double frequency0, Index gw_level, double left_limit, double right_limit, bool allow_rejected_return=true, QPStats *stats=nullptr) const
Definition gw_uks.cc:711
boost::optional< double > SolveQP_Grid(Spin spin, double intercept0, double frequency0, Index gw_level, QPStats *stats=nullptr) const
Definition gw_uks.cc:647
Index screening_builds_
Definition gw_uks.h:260
Eigen::MatrixXd Sigma_c_beta_
Definition gw_uks.h:326
Eigen::MatrixXd & SigmaX(Spin spin)
Definition gw_uks.cc:135
Eigen::VectorXd getGWAResultsAlpha() const
Definition gw_uks.cc:461
boost::optional< QPRootCandidate > RefineQPInterval(double lowerbound, double f_lowerbound, double upperbound, double f_upperbound, const QPFunc &f, double reference) const
const Eigen::MatrixXd & vxc_alpha_
Definition gw_uks.h:316
Eigen::VectorXd ScissorShift_DFTlevel(const Eigen::VectorXd &dft_energies, Index homo) const
Definition gw_uks.cc:174
const Eigen::VectorXd & RPAInputEnergiesAlpha() const
Definition gw_uks.cc:471
Index tracked_local_total_
Definition gw_uks.h:257
qp_solver::WindowDiagnostics QPWindowDiagnostics
Definition gw_uks.h:30
const char * OccupationTag(Spin spin, Index level) const
Definition gw_uks.cc:170
qp_solver::Stats QPStats
Definition gw_uks.h:28
Eigen::MatrixXd core_exchange_beta_
Definition gw_uks.h:259
Sigma_base_UKS & SigmaEvaluator(Spin spin)
Definition gw_uks.cc:147
Eigen::VectorXd SolveQP(Spin spin, const Eigen::VectorXd &frequencies) const
Definition gw_uks.cc:504
const Eigen::VectorXd & RPAInputEnergiesBeta() const
Definition gw_uks.cc:474
Eigen::MatrixXd getHQPBeta() const
Definition gw_uks.cc:1021
bool tracking_active_
Definition gw_uks.h:256
void PrintGWA_Energies(Spin spin) const
Definition gw_uks.cc:1041
Eigen::VectorXd tracked_change_[2]
Definition gw_uks.h:255
Eigen::VectorXd getGWAResultsBeta() const
Definition gw_uks.cc:466
Eigen::MatrixXd getHQPAlpha() const
Definition gw_uks.cc:1016
Eigen::MatrixXd Sigma_x_beta_
Definition gw_uks.h:324
Index gw_sc_iteration_
Definition gw_uks.h:314
const char * SpinName(Spin spin) const
Definition gw_uks.cc:156
GW_UKS(Logger &log, TCMatrix_gwbse_spin &Mmn, const Eigen::MatrixXd &vxc_alpha, const Eigen::MatrixXd &vxc_beta, const Eigen::VectorXd &dft_energies_alpha, const Eigen::VectorXd &dft_energies_beta)
Definition gw_uks.cc:28
const Eigen::VectorXd & dft_energies_alpha_
Definition gw_uks.h:318
double CalcSpinHomoLumoShift(const Eigen::VectorXd &frequencies, Spin spin) const
Definition gw_uks.cc:182
boost::optional< double > SolveQP_Grid_Windowed_Dense(Spin spin, double intercept0, double frequency0, Index gw_level, double left_limit, double right_limit, bool allow_rejected_return=true, QPStats *stats=nullptr) const
Definition gw_uks.cc:791
const Eigen::MatrixXd & vxc_beta_
Definition gw_uks.h:317
const Eigen::VectorXd & dft_energies_beta_
Definition gw_uks.h:319
qp_solver::EvalStage EvalStage
Definition gw_uks.h:27
Logger & log_
Definition gw_uks.h:313
void setCoreExchange(const Eigen::MatrixXd &alpha, const Eigen::MatrixXd &beta)
Frozen-core exchange per spin, see GW::setCoreExchange.
Definition gw_uks.h:103
qp_solver::RootCandidate QPRootCandidate
Definition gw_uks.h:29
Index QPIterations() const
Definition gw_uks.h:123
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonianBeta() const
Definition gw_uks.cc:1035
Eigen::MatrixXd Sigma_c_alpha_
Definition gw_uks.h:325
const Eigen::MatrixXd & Vxc(Spin spin) const
Definition gw_uks.cc:132
std::vector< qp_solver::CompetingRoots > competing_roots_[2]
Definition gw_uks.h:251
void configure(const options &opt)
Definition gw_uks.cc:41
void RecordCompetingRoots(Spin spin, Index gw_level, const std::vector< QPRootCandidate > &roots, double chosen) const
Definition gw_uks.h:262
void CalculateGWPerturbation()
Definition gw_uks.cc:192
boost::optional< double > SolveQP_FixedPoint(Spin spin, double intercept0, double frequency0, Index gw_level, QPStats *stats=nullptr) const
Definition gw_uks.cc:969
Index Homo(Spin spin) const
Definition gw_uks.cc:153
Eigen::VectorXd tracked_root_[2]
Definition gw_uks.h:253
Logger is used for thread-safe output of messages.
Definition logger.h:164
Unrestricted RPA helper for spin-resolved GW screening.
Definition rpa_uks.h:70
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
std::string screening_update
Definition gw_uks.h:82
std::string quadrature_scheme
Definition gw_uks.h:73
OutOfWindowShift out_of_window_shift
Definition gw_uks.h:35
std::string qp_grid_search_mode
Definition gw_uks.h:92
std::string sigma_integration
Definition gw_uks.h:49
std::string qp_root_finder
Definition gw_uks.h:91
How the RPA energies of levels outside the GW window are shifted.