votca 2026-dev
Loading...
Searching...
No Matches
gwbse.cc
Go to the documentation of this file.
1
2
3/*
4 * Copyright 2009-2023 The VOTCA Development Team
5 * (http://www.votca.org)
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License")
8 *
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */
21
22// Third party includes
23#include <boost/algorithm/string.hpp>
24#include <boost/format.hpp>
25
26// VOTCA includes
27#include <stdexcept>
29#include <votca/tools/version.h>
30
31// Local VOTCA includes
33#include "votca/xtp/basisset.h"
34#include "votca/xtp/bse.h"
35#include "votca/xtp/citations.h"
37#include "votca/xtp/gwbse.h"
38#include "votca/xtp/logger.h"
40#include "votca/xtp/orbitals.h"
41#include "votca/xtp/rpa_uks.h"
44#include "votca/xtp/vxc_grid.h"
46
47using std::flush;
48namespace votca {
49namespace xtp {
50
52 Index ignored_corelevels = 0;
53 if (!orbitals_.hasECPName()) {
54 ECPBasisSet basis;
55 basis.Load("corelevels");
56 Index coreElectrons = 0;
57 for (const auto& atom : orbitals_.QMAtoms()) {
58 coreElectrons += basis.getElement(atom.getElement()).getNcore();
59 }
60 ignored_corelevels = coreElectrons / 2;
61 }
62 return ignored_corelevels;
63}
64
66
67 // getting level ranges
68 Index rpamax = 0;
69 Index rpamin = 0; // never changes
70 Index qpmin = 0;
71 Index qpmax = 0;
72 Index bse_vmin = 0;
73 Index bse_cmax = 0;
74
75 const bool is_uks = orbitals_.hasUnrestrictedOrbitals();
76 Index homo = orbitals_.getHomo(); // indexed from 0
77 if (is_uks) {
78 homo = std::max(orbitals_.getHomoAlpha(), orbitals_.getHomoBeta());
79 }
80 Index num_of_levels = orbitals_.getBasisSetSize();
81 Index num_of_occlevels = orbitals_.getNumberOfAlphaElectrons();
82 if (is_uks) {
83 num_of_occlevels = std::max(orbitals_.getNumberOfAlphaElectrons(),
84 orbitals_.getNumberOfBetaElectrons());
85 }
86
87 std::string ranges = options.get(".ranges").as<std::string>();
88
89 // now check validity, and get rpa, qp, and bse level ranges accordingly
90
91 if (ranges == "factor") {
92
93 double rpamaxfactor = options.get(".rpamax").as<double>();
94 rpamax = Index(rpamaxfactor * double(num_of_levels)) -
95 1; // total number of levels
96
97 double qpminfactor = options.get(".qpmin").as<double>();
98 qpmin =
99 num_of_occlevels - Index(qpminfactor * double(num_of_occlevels)) - 1;
100
101 double qpmaxfactor = options.get(".qpmax").as<double>();
102 qpmax =
103 num_of_occlevels + Index(qpmaxfactor * double(num_of_occlevels)) - 1;
104
105 double bseminfactor = options.get(".bsemin").as<double>();
106 bse_vmin =
107 num_of_occlevels - Index(bseminfactor * double(num_of_occlevels)) - 1;
108
109 double bsemaxfactor = options.get(".bsemax").as<double>();
110 bse_cmax =
111 num_of_occlevels + Index(bsemaxfactor * double(num_of_occlevels)) - 1;
112
113 } else if (ranges == "explicit") {
114 // get explicit numbers
115 rpamax = options.get(".rpamax").as<Index>();
116 qpmin = options.get(".qpmin").as<Index>();
117 qpmax = options.get(".qpmax").as<Index>();
118 bse_vmin = options.get(".bsemin").as<Index>();
119 bse_cmax = options.get(".bsemax").as<Index>();
120 } else if (ranges == "default") {
121 rpamax = num_of_levels - 1;
122 qpmin = 0;
123 qpmax = 3 * homo + 1;
124 bse_vmin = 0;
125 bse_cmax = 3 * homo + 1;
126 } else if (ranges == "full") {
127 rpamax = num_of_levels - 1;
128 qpmin = 0;
129 qpmax = num_of_levels - 1;
130 bse_vmin = 0;
131 bse_cmax = num_of_levels - 1;
132 }
133 std::string ignore_corelevels =
134 options.get(".ignore_corelevels").as<std::string>();
135
136 if (ignore_corelevels == "RPA" || ignore_corelevels == "GW" ||
137 ignore_corelevels == "BSE") {
138 Index ignored_corelevels = CountCoreLevels();
139 if (ignore_corelevels == "RPA") {
140 rpamin = ignored_corelevels;
141 }
142 if (ignore_corelevels == "GW" || ignore_corelevels == "RPA") {
143 if (qpmin < ignored_corelevels) {
144 qpmin = ignored_corelevels;
145 }
146 }
147 if (ignore_corelevels == "GW" || ignore_corelevels == "RPA" ||
148 ignore_corelevels == "BSE") {
149 if (bse_vmin < ignored_corelevels) {
150 bse_vmin = ignored_corelevels;
151 }
152 }
153
155 << TimeStamp() << " Ignoring " << ignored_corelevels
156 << " core levels for " << ignore_corelevels << " and beyond." << flush;
157 }
158
159 // check maximum and minimum sizes
160 if (rpamax >= num_of_levels) {
161 rpamax = num_of_levels - 1;
162 }
163 if (qpmax >= num_of_levels) {
164 qpmax = num_of_levels - 1;
165 }
166 if (bse_cmax >= num_of_levels) {
167 bse_cmax = num_of_levels - 1;
168 }
169 if (bse_vmin < 0) {
170 bse_vmin = 0;
171 }
172 if (qpmin < 0) {
173 qpmin = 0;
174 }
175
176 Index bse_vmax = homo;
177 Index bse_cmin = homo + 1;
178
179 // Energy caps on the GW and BSE windows (eV above the DFT LUMO / below the
180 // DFT HOMO; <= 0: off). They only shrink the windows set above, and never
181 // cut a (near-)degenerate set of levels.
182 {
183 const double qp_emax =
184 options.ifExistsReturnElseReturnDefault<double>(".qp_emax", 0.0);
185 const double qp_emin =
186 options.ifExistsReturnElseReturnDefault<double>(".qp_emin", 0.0);
187 const double bse_emax =
188 options.ifExistsReturnElseReturnDefault<double>(".bse_emax", 0.0);
189 const double bse_emin =
190 options.ifExistsReturnElseReturnDefault<double>(".bse_emin", 0.0);
191 std::vector<const Eigen::VectorXd*> spins{&orbitals_.MOs().eigenvalues()};
192 std::vector<Index> homos{is_uks ? orbitals_.getHomoAlpha() : homo};
193 if (is_uks) {
194 spins.push_back(&orbitals_.MOs_beta().eigenvalues());
195 homos.push_back(orbitals_.getHomoBeta());
196 }
197 // levels closer than this count as degenerate and stay together
198 constexpr double degenerate = 5e-4; // Ha
199 // highest level (over the spins) within cap_ev above the LUMO
200 auto upper = [&](double cap_ev) {
201 Index last = homo + 1;
202 for (std::size_t s = 0; s < spins.size(); ++s) {
203 const Eigen::VectorXd& e = *spins[s];
204 const double limit = e(homos[s] + 1) + cap_ev * tools::conv::ev2hrt;
205 Index i = homos[s] + 1;
206 while (i + 1 < e.size() && e(i + 1) <= limit) {
207 ++i;
208 }
209 const double edge = e(i); // keep the set degenerate with it
210 while (i + 1 < e.size() && e(i + 1) - edge < degenerate) {
211 ++i;
212 }
213 last = std::max(last, i);
214 }
215 return last;
216 };
217 // lowest level (over the spins) within cap_ev below the HOMO
218 auto lower = [&](double cap_ev) {
219 Index first = homo;
220 for (std::size_t s = 0; s < spins.size(); ++s) {
221 const Eigen::VectorXd& e = *spins[s];
222 const double limit = e(homos[s]) - cap_ev * tools::conv::ev2hrt;
223 Index i = homos[s];
224 while (i - 1 >= 0 && e(i - 1) >= limit) {
225 --i;
226 }
227 const double edge = e(i);
228 while (i - 1 >= 0 && edge - e(i - 1) < degenerate) {
229 --i;
230 }
231 first = std::min(first, i);
232 }
233 return first;
234 };
235 auto report = [&](const std::string& what, const std::string& option,
236 double cap, Index before, Index after) {
238 << TimeStamp() << " " << what << " capped by " << option << " = "
239 << cap << " eV: " << before << " -> " << after << " ("
240 << std::abs(before - after) << " levels removed)" << flush;
241 };
242 if (qp_emax > 0.0) {
243 const Index cap = std::min(qpmax, upper(qp_emax));
244 report("GW window top", "qp_emax", qp_emax, qpmax, cap);
245 qpmax = cap;
246 }
247 if (qp_emin > 0.0) {
248 const Index cap = std::max(qpmin, lower(qp_emin));
249 report("GW window bottom", "qp_emin", qp_emin, qpmin, cap);
250 qpmin = cap;
251 }
252 if (bse_emax > 0.0) {
253 const Index cap = std::min(bse_cmax, upper(bse_emax));
254 report("BSE window top", "bse_emax", bse_emax, bse_cmax, cap);
255 bse_cmax = cap;
256 }
257 if (bse_emin > 0.0) {
258 const Index cap = std::max(bse_vmin, lower(bse_emin));
259 report("BSE window bottom", "bse_emin", bse_emin, bse_vmin, cap);
260 bse_vmin = cap;
261 }
262 }
263
264 if (rpamin < 0 || rpamax < 0 || rpamin > rpamax) {
265 throw std::runtime_error("Invalid RPA level range after setup/clamping.");
266 }
267 if (qpmin < 0 || qpmax < 0 || qpmin > qpmax) {
268 throw std::runtime_error("Invalid GW level range after setup/clamping.");
269 }
270 if (bse_vmin < 0 || bse_vmax < 0 || bse_vmin > bse_vmax) {
271 throw std::runtime_error(
272 "Invalid BSE occupied level range after setup/clamping.");
273 }
274 if (bse_cmin < 0 || bse_cmax < 0 || bse_cmin > bse_cmax) {
275 throw std::runtime_error(
276 "Invalid BSE virtual level range after setup/clamping.");
277 }
278 if (bse_vmax >= num_of_levels || bse_cmax >= num_of_levels) {
279 throw std::runtime_error(
280 "BSE level range exceeds available orbital indices.");
281 }
282 if (bse_vmax >= bse_cmin) {
283 throw std::runtime_error("BSE occupied and virtual level ranges overlap.");
284 }
285
286 gwopt_.homo = homo;
287 gwopt_.qpmin = qpmin;
288 gwopt_.qpmax = qpmax;
289 gwopt_.rpamin = rpamin;
290 gwopt_.rpamax = rpamax;
291
292 bseopt_.vmin = bse_vmin;
293 bseopt_.cmax = bse_cmax;
294 bseopt_.homo = homo;
295 bseopt_.qpmin = qpmin;
296 bseopt_.qpmax = qpmax;
297 bseopt_.rpamin = rpamin;
298 bseopt_.rpamax = rpamax;
299
300 orbitals_.setRPAindices(rpamin, rpamax);
301 orbitals_.setGWindices(qpmin, qpmax);
302 orbitals_.setBSEindices(bse_vmin, bse_cmax);
303
304 // Index bse_vmax = homo;
305 // Index bse_cmin = homo + 1;
306 Index bse_vtotal = bse_vmax - bse_vmin + 1;
307 Index bse_ctotal = bse_cmax - bse_cmin + 1;
308 Index bse_size = bse_vtotal * bse_ctotal;
309
310 XTP_LOG(Log::error, *pLog_) << TimeStamp() << " RPA level range [" << rpamin
311 << ":" << rpamax << "]" << flush;
312 XTP_LOG(Log::error, *pLog_) << TimeStamp() << " GW level range [" << qpmin
313 << ":" << qpmax << "]" << flush;
315 << TimeStamp() << " BSE level range occ[" << bse_vmin << ":" << bse_vmax
316 << "] virt[" << bse_cmin << ":" << bse_cmax << "]" << flush;
317
318 gwopt_.reset_3c = options.get(".gw.rebuild_3c_freq").as<Index>();
319
320 bseopt_.nmax = options.get(".bse.exctotal").as<Index>();
321 if (bseopt_.nmax > bse_size || bseopt_.nmax < 0) {
322 bseopt_.nmax = bse_size;
323 }
324
325 bseopt_.davidson_correction =
326 options.get("bse.davidson.correction").as<std::string>();
327
328 bseopt_.davidson_tolerance =
329 options.get("bse.davidson.tolerance").as<std::string>();
330
331 bseopt_.davidson_update =
332 options.get("bse.davidson.update").as<std::string>();
333
334 bseopt_.davidson_maxiter = options.get("bse.davidson.maxiter").as<Index>();
335
336 bseopt_.useTDA = options.get("bse.useTDA").as<bool>();
337 orbitals_.setTDAApprox(bseopt_.useTDA);
338 if (!bseopt_.useTDA) {
339 XTP_LOG(Log::error, *pLog_) << " BSE type: full" << flush;
340 } else {
341 XTP_LOG(Log::error, *pLog_) << " BSE type: TDA" << flush;
342 }
343
344 Index full_bse_size = (bseopt_.useTDA) ? bse_size : 2 * bse_size;
345 XTP_LOG(Log::error, *pLog_) << TimeStamp() << " BSE Hamiltonian has size "
346 << full_bse_size << "x" << full_bse_size << flush;
347
348 bseopt_.use_Hqp_offdiag = options.get("bse.use_Hqp_offdiag").as<bool>();
349 orbitals_.SetFlagUseHqpOffdiag(bseopt_.use_Hqp_offdiag);
350
351 if (!bseopt_.use_Hqp_offdiag) {
353 << " BSE without Hqp offdiagonal elements" << flush;
354 } else {
356 << " BSE with Hqp offdiagonal elements" << flush;
357 }
358
359 bseopt_.max_dyn_iter = options.get("bse.dyn_screen_max_iter").as<Index>();
360 bseopt_.dyn_tolerance = options.get("bse.dyn_screen_tol").as<double>();
361 if (bseopt_.max_dyn_iter > 0) {
363 }
364
365 functional_ = orbitals_.getXCFunctionalName();
366 grid_ = orbitals_.getXCGrid();
367
368 dftbasis_name_ = orbitals_.getDFTbasisName();
369 if (orbitals_.hasAuxbasisName()) {
370 auxbasis_name_ = orbitals_.getAuxbasisName();
371 } else if (options.exists(".auxbasisset")) {
372 auxbasis_name_ = options.get(".auxbasisset").as<std::string>();
373 } else {
375 try {
376 BasisSet b;
378 } catch (std::runtime_error&) {
379 throw std::runtime_error(
380 "There is no auxbasis from the dftcalculation nor did you specify an "
381 "auxbasisset for the gwbse calculation. Also no auxiliary basisset "
382 "for basisset " +
383 dftbasis_name_ + " could be found!");
384 }
386 << " No auxbasisset given, using " << auxbasis_name_ << flush;
387 }
388
389 std::string mode = options.get("gw.mode").as<std::string>();
390 if (mode == "G0W0") {
391 gwopt_.gw_sc_max_iterations = 1;
392 }
393
394 XTP_LOG(Log::error, *pLog_) << " Running GW as: " << mode << flush;
395 gwopt_.ScaHFX = orbitals_.getScaHFX();
396
397 gwopt_.shift = options.get("gw.scissor_shift").as<double>();
398 gwopt_.g_sc_limit =
399 options.get("gw.qp_sc_limit").as<double>(); // convergence criteria
400 // for qp iteration
401 // [Hartree]]
402 gwopt_.g_sc_max_iterations =
403 options.get("gw.qp_sc_max_iter").as<Index>(); // convergence
404 // criteria for qp
405 // iteration
406 // [Hartree]]
407
408 if (mode == "evGW") {
409 gwopt_.gw_sc_max_iterations = options.get("gw.sc_max_iter").as<Index>();
410 }
411
412 gwopt_.gw_sc_limit =
413 options.get("gw.sc_limit").as<double>(); // convergence criteria
414 // for shift it
416 << " qp_sc_limit [Hartree]: " << gwopt_.g_sc_limit << flush;
417 if (gwopt_.gw_sc_max_iterations > 1) {
419 << " gw_sc_limit [Hartree]: " << gwopt_.gw_sc_limit << flush;
420 }
421 bseopt_.min_print_weight = options.get("bse.print_weight").as<double>();
422 // print exciton WF composition weight larger than minimum
423
424 // possible tasks
425 std::string tasks_string = options.get(".tasks").as<std::string>();
426 boost::algorithm::to_lower(tasks_string);
427
428 if (tasks_string.find("gw") != std::string::npos) {
429 do_gw_ = true;
430 }
431
432 if (is_uks) {
433 if (tasks_string.find("excitons") != std::string::npos ||
434 tasks_string.find("exciton_uks") != std::string::npos) {
435 do_gw_ = true;
436 do_bse_exciton_uks_ = true;
437 }
438
439 if (tasks_string.find("singlets") != std::string::npos ||
440 tasks_string.find("triplets") != std::string::npos) {
441 throw std::runtime_error(
442 "Invalid gwbse task for UKS reference: 'singlets' and 'triplets' "
443 "are not defined for open-shell systems.\n"
444 "Use 'exciton_uks' (or 'excitons') instead.");
445 }
446 } else {
447 if (tasks_string.find("all") != std::string::npos) {
448 if (is_uks) {
449 do_gw_ = true;
450 do_bse_exciton_uks_ = true;
451 } else {
452 do_gw_ = true;
453 do_bse_singlets_ = true;
454 do_bse_triplets_ = true;
455 }
456 }
457 if (tasks_string.find("singlets") != std::string::npos) {
458 do_bse_singlets_ = true;
459 }
460 if (tasks_string.find("triplets") != std::string::npos) {
461 do_bse_triplets_ = true;
462 }
463 }
464
465 XTP_LOG(Log::error, *pLog_) << " Tasks: " << flush;
466 if (do_gw_) {
467 XTP_LOG(Log::error, *pLog_) << " GW " << flush;
468 }
469 if (do_bse_singlets_) {
470 XTP_LOG(Log::error, *pLog_) << " singlets " << flush;
471 }
472 if (do_bse_triplets_) {
473 XTP_LOG(Log::error, *pLog_) << " triplets " << flush;
474 }
476 XTP_LOG(Log::error, *pLog_) << " exciton_uks " << flush;
477 }
478
479 if (options.exists("bse.fragments")) {
480 std::vector<tools::Property*> prop_region =
481 options.Select("bse.fragments.fragment");
482 Index index = 0;
483 for (tools::Property* prop : prop_region) {
484 std::string indices = prop->get("indices").as<std::string>();
485 fragments_.push_back(QMFragment<BSE_Population>(index, indices));
486 index++;
487 }
488 }
489
490 gwopt_.sigma_integration =
491 options.get("gw.sigma_integrator").as<std::string>();
493 << " Sigma integration: " << gwopt_.sigma_integration << flush;
494 gwopt_.eta = options.get("gw.eta").as<double>();
495 XTP_LOG(Log::error, *pLog_) << " eta: " << gwopt_.eta << flush;
496 if (gwopt_.sigma_integration == "exact") {
498 << " RPA Hamiltonian size: " << (homo + 1 - rpamin) * (rpamax - homo)
499 << flush;
500 }
501 if (gwopt_.sigma_integration == "cda") {
502 gwopt_.order = options.get("gw.quadrature_order").as<Index>();
504 << " Quadrature integration order : " << gwopt_.order << flush;
505 gwopt_.quadrature_scheme =
506 options.get("gw.quadrature_scheme").as<std::string>();
508 << " Quadrature integration scheme : " << gwopt_.quadrature_scheme
509 << flush;
510 gwopt_.alpha = options.get("gw.alpha").as<double>();
512 << " Alpha smoothing parameter : " << gwopt_.alpha << flush;
513 }
514 gwopt_.qp_solver = options.get("gw.qp_solver").as<std::string>();
515
516 XTP_LOG(Log::error, *pLog_) << " QP solver: " << gwopt_.qp_solver << flush;
517 if (gwopt_.qp_solver == "grid") {
518 // Grid-based QP solving now exposes the full search extent, dense scan,
519 // and adaptive shell scan as separate controls. This avoids the old
520 // overloading of qp_grid_steps / qp_grid_spacing, where one pair of values
521 // simultaneously determined the window width and both scan resolutions.
522 //
523 // New-style options are read first. Deprecated legacy aliases are then
524 // translated only for values that are still unset.
525 // New decoupled QP search options
526 if (options.exists("gw.qp_full_window_half_width")) {
527 gwopt_.qp_full_window_half_width =
528 options.get("gw.qp_full_window_half_width").as<double>();
529 }
530 if (options.exists("gw.qp_dense_spacing")) {
531 gwopt_.qp_dense_spacing = options.get("gw.qp_dense_spacing").as<double>();
532 }
533 if (options.exists("gw.qp_adaptive_shell_width")) {
534 gwopt_.qp_adaptive_shell_width =
535 options.get("gw.qp_adaptive_shell_width").as<double>();
536 }
537 if (options.exists("gw.qp_adaptive_shell_count")) {
538 gwopt_.qp_adaptive_shell_count =
539 options.get("gw.qp_adaptive_shell_count").as<Index>();
540 }
541
542 // Deprecated legacy aliases. They are accepted for backward
543 // compatibility and mapped onto the canonical controls below.
544 const bool has_legacy_steps = options.exists("gw.qp_grid_steps");
545 const bool has_legacy_spacing = options.exists("gw.qp_grid_spacing");
546
547 if (has_legacy_steps != has_legacy_spacing) {
548 throw std::runtime_error(
549 "Deprecated gw.qp_grid_steps and gw.qp_grid_spacing must be given "
550 "together if either is used.");
551 }
552
553 if (has_legacy_steps && has_legacy_spacing) {
554 gwopt_.qp_grid_steps = options.get("gw.qp_grid_steps").as<Index>();
555 gwopt_.qp_grid_spacing = options.get("gw.qp_grid_spacing").as<double>();
556
557 const double legacy_half_width =
559 const double legacy_shell_width =
561
562 if (gwopt_.qp_full_window_half_width <= 0.0) {
563 gwopt_.qp_full_window_half_width = legacy_half_width;
564 }
565 if (gwopt_.qp_dense_spacing <= 0.0) {
566 gwopt_.qp_dense_spacing = gwopt_.qp_grid_spacing;
567 }
568 if (gwopt_.qp_adaptive_shell_count <= 0 &&
569 gwopt_.qp_adaptive_shell_width <= 0.0) {
570 gwopt_.qp_adaptive_shell_width = legacy_shell_width;
571 }
572
574 << " Deprecated GW QP options detected: " << "qp_grid_steps="
575 << gwopt_.qp_grid_steps
576 << " qp_grid_spacing=" << gwopt_.qp_grid_spacing
577 << " -> mapped to qp_full_window_half_width="
578 << gwopt_.qp_full_window_half_width
579 << " qp_dense_spacing=" << gwopt_.qp_dense_spacing
580 << " qp_adaptive_shell_width=" << gwopt_.qp_adaptive_shell_width
581 << flush;
582 }
583
584 // Final normalization produces one canonical option set used by both
585 // GW and GW_UKS implementations.
587
589 << " QP full window half-width: " << gwopt_.qp_full_window_half_width
590 << flush;
592 << " QP dense spacing: " << gwopt_.qp_dense_spacing << flush;
594 << " QP adaptive shell width: " << gwopt_.qp_adaptive_shell_width
595 << flush;
597 << " QP adaptive shell count: " << gwopt_.qp_adaptive_shell_count
598 << flush;
599 }
600 gwopt_.qp_root_finder = options.get("gw.qp_root_finder").as<std::string>();
602 << " QP root finder: " << gwopt_.qp_root_finder << flush;
603
604 gwopt_.gw_mixing_order =
605 options.get("gw.mixing_order").as<Index>(); // max history in
606 // mixing (0: plain,
607 // 1: linear, >1
608 // Anderson)
609
610 gwopt_.gw_mixing_alpha = options.get("gw.mixing_alpha").as<double>();
611 gwopt_.qp_grid_search_mode =
612 options.get("gw.qp_grid_search_mode").as<std::string>();
613 gwopt_.qp_restrict_search = options.get("gw.qp_restrict_search").as<bool>();
614 gwopt_.qp_root_continuity = options.ifExistsReturnElseReturnDefault<bool>(
615 "gw.qp_root_continuity", true);
616 gwopt_.qp_root_tracking = options.ifExistsReturnElseReturnDefault<bool>(
617 "gw.qp_root_tracking", false);
619 options.ifExistsReturnElseReturnDefault<bool>("gw.core_exchange", true);
620 gwopt_.screening_update =
621 options.ifExistsReturnElseReturnDefault<std::string>(
622 "gw.screening_update", "adaptive");
623 ScreeningUpdate::Parse(gwopt_.screening_update); // validates
624 gwopt_.screening_update_ratio =
625 options.ifExistsReturnElseReturnDefault<double>(
626 "gw.screening_update_ratio", 0.1);
627 gwopt_.screening_update_max_inner =
629 "gw.screening_update_max_inner", 10);
630 gwopt_.qp_zero_margin = options.get("gw.qp_zero_margin").as<double>();
631 gwopt_.qp_virtual_min_energy =
632 options.get("gw.qp_virtual_min_energy").as<double>();
633
634 // QSGW options
635 gwopt_.do_qsgw =
636 options.ifExistsReturnElseReturnDefault<bool>("gw.do_qsgw", false);
637 gwopt_.qsgw_max_iterations = options.ifExistsReturnElseReturnDefault<Index>(
638 "gw.qsgw_max_iterations", 50);
639 gwopt_.qsgw_sc_limit =
640 options.ifExistsReturnElseReturnDefault<double>("gw.qsgw_sc_limit", 1e-5);
641 gwopt_.qsgw_max_virt_correction =
642 options.ifExistsReturnElseReturnDefault<double>(
643 "gw.qsgw_max_virt_correction", 0.5);
644 gwopt_.qsgw_hartree_update = options.ifExistsReturnElseReturnDefault<bool>(
645 "gw.qsgw_hartree_update", true);
646 gwopt_.qsgw_hartree_screened = options.ifExistsReturnElseReturnDefault<bool>(
647 "gw.qsgw_hartree_screened", true);
648 gwopt_.qsgw_regularization =
649 options.ifExistsReturnElseReturnDefault<std::string>(
650 "gw.qsgw_regularization", "eta");
651 if (gwopt_.qsgw_regularization != "eta" &&
652 gwopt_.qsgw_regularization != "srg") {
653 throw std::runtime_error("gw.qsgw_regularization must be eta or srg, got " +
654 gwopt_.qsgw_regularization);
655 }
656 gwopt_.qsgw_srg_s =
657 options.ifExistsReturnElseReturnDefault<double>("gw.qsgw_srg_s", 500.0);
658 if (!(gwopt_.qsgw_srg_s > 0.0)) {
659 throw std::runtime_error("gw.qsgw_srg_s must be positive");
660 }
661 gwopt_.out_of_window_shift.mode = OutOfWindowShift::Parse(
662 options.ifExistsReturnElseReturnDefault<std::string>(
663 "gw.out_of_window_shift", "max"));
664 gwopt_.out_of_window_shift.fit_fraction =
665 options.ifExistsReturnElseReturnDefault<double>(
666 "gw.out_of_window_fit_fraction", 0.3);
667 if (gwopt_.out_of_window_shift.mode != OutOfWindowShift::Mode::Max) {
669 << " Levels outside the GW window shifted by: "
670 << OutOfWindowShift::Name(gwopt_.out_of_window_shift.mode)
671 << ((gwopt_.out_of_window_shift.mode == OutOfWindowShift::Mode::Linear)
672 ? " (fit fraction " +
673 std::to_string(gwopt_.out_of_window_shift.fit_fraction) +
674 ")"
675 : std::string())
676 << flush;
677 }
678 if (gwopt_.do_qsgw) {
680 << " QSGW enabled: max_iter=" << gwopt_.qsgw_max_iterations
681 << " sc_limit=" << gwopt_.qsgw_sc_limit << " Ha"
682 << " max_virt_correction=" << gwopt_.qsgw_max_virt_correction << " Ha ("
683 << gwopt_.qsgw_max_virt_correction * 27.2114 << " eV)" << std::flush;
684 }
685
686 if (mode == "evGW") {
687 if (gwopt_.gw_mixing_order == 0) {
688 XTP_LOG(Log::error, *pLog_) << " evGW with plain update " << std::flush;
689 } else if (gwopt_.gw_mixing_order == 1) {
690 XTP_LOG(Log::error, *pLog_) << " evGW with linear update using alpha "
691 << gwopt_.gw_mixing_alpha << std::flush;
692 } else {
693 XTP_LOG(Log::error, *pLog_) << " evGW with Anderson update with history "
694 << gwopt_.gw_mixing_order << " using alpha "
695 << gwopt_.gw_mixing_alpha << std::flush;
696 }
697 if (gwopt_.screening_update == "adaptive") {
699 << " evGW screening update: adaptive (ratio "
700 << gwopt_.screening_update_ratio << ", at most "
701 << gwopt_.screening_update_max_inner << " iterations per W)"
702 << std::flush;
703 } else {
705 << " evGW screening update: every iteration" << std::flush;
706 }
707 }
708
709 if (options.exists("gw.sigma_plot")) {
710 sigma_plot_states_ = options.get("gw.sigma_plot.states").as<std::string>();
711 sigma_plot_steps_ = options.get("gw.sigma_plot.steps").as<Index>();
712 sigma_plot_spacing_ = options.get("gw.sigma_plot.spacing").as<double>();
714 options.get("gw.sigma_plot.filename").as<std::string>();
715
717 << " Sigma plot states: " << sigma_plot_states_ << flush;
719 << " Sigma plot steps: " << sigma_plot_steps_ << flush;
721 << " Sigma plot spacing: " << sigma_plot_spacing_ << flush;
723 << " Sigma plot filename: " << sigma_plot_filename_ << flush;
724 }
725
726 if (options.exists("gw.sigma_dump")) {
727 if (is_uks) {
728 throw std::runtime_error("gw.sigma_dump is not implemented for UKS");
729 }
730 if (gwopt_.sigma_integration != "ppm" &&
731 gwopt_.sigma_integration != "exact") {
732 throw std::runtime_error(
733 "gw.sigma_dump needs sigma_integrator ppm or exact");
734 }
735 if (gwopt_.do_qsgw) {
736 throw std::runtime_error("gw.sigma_dump is not implemented for QSGW");
737 }
738 do_sigma_dump_ = true;
739 sigma_dump_opt_.filename =
740 options.get("gw.sigma_dump.filename").as<std::string>();
741 sigma_dump_opt_.levels_emax_ev =
742 options.get("gw.sigma_dump.levels_emax").as<double>();
743 sigma_dump_opt_.imag_points =
744 options.get("gw.sigma_dump.imag_points").as<Index>();
745 sigma_dump_opt_.imag_scale =
746 options.get("gw.sigma_dump.imag_scale").as<double>();
747 sigma_dump_opt_.spectral_min =
748 options.get("gw.sigma_dump.spectral_min").as<double>();
749 sigma_dump_opt_.spectral_max =
750 options.get("gw.sigma_dump.spectral_max").as<double>();
751 sigma_dump_opt_.spectral_binwidth =
752 options.get("gw.sigma_dump.spectral_binwidth").as<double>();
753 sigma_dump_opt_.plot_steps =
754 options.get("gw.sigma_dump.plot_steps").as<Index>();
755 sigma_dump_opt_.plot_spacing =
756 options.get("gw.sigma_dump.plot_spacing").as<double>();
758 << " Sigma dump filename: " << sigma_dump_opt_.filename << flush;
759 }
760}
761
763
764 const double hrt2ev = tools::conv::hrt2ev;
765 tools::Property& gwbse_summary = summary.add("GWBSE", "");
766 if (do_gw_) {
767 gwbse_summary.setAttribute("units", "eV");
768 gwbse_summary.setAttribute(
769 "DFTEnergy",
770 (boost::format("%1$+1.6f ") % (orbitals_.getDFTTotalEnergy() * hrt2ev))
771 .str());
772
773 if (orbitals_.hasUnrestrictedOrbitals()) {
774 gwbse_summary.add("dft_alpha", "");
775 gwbse_summary.add("dft_beta", "");
776
777 tools::Property& alpha_summary = gwbse_summary.get("dft_alpha");
778 tools::Property& beta_summary = gwbse_summary.get("dft_beta");
779
780 alpha_summary.setAttribute("HOMO", orbitals_.getHomoAlpha());
781 alpha_summary.setAttribute("LUMO", orbitals_.getLumoAlpha());
782 beta_summary.setAttribute("HOMO", orbitals_.getHomoBeta());
783 beta_summary.setAttribute("LUMO", orbitals_.getLumoBeta());
784 for (Index state = 0; state < gwopt_.qpmax + 1 - gwopt_.qpmin; state++) {
785 tools::Property& level_alpha = alpha_summary.add("level", "");
786 level_alpha.setAttribute("number", state + gwopt_.qpmin);
787 level_alpha.add(
788 "dft_energy",
789 (boost::format("%1$+1.6f ") %
790 (orbitals_.MOs().eigenvalues()(state + gwopt_.qpmin) * hrt2ev))
791 .str());
792 level_alpha.add("gw_energy",
793 (boost::format("%1$+1.6f ") %
794 (orbitals_.QPpertEnergiesAlpha()(state) * hrt2ev))
795 .str());
796 level_alpha.add(
797 "qp_energy",
798 (boost::format("%1$+1.6f ") %
799 (orbitals_.QPdiagAlpha().eigenvalues()(state) * hrt2ev))
800 .str());
801
802 tools::Property& level_beta = beta_summary.add("level", "");
803 level_beta.setAttribute("number", state + gwopt_.qpmin);
804 level_beta.add(
805 "dft_energy",
806 (boost::format("%1$+1.6f ") %
807 (orbitals_.MOs_beta().eigenvalues()(state + gwopt_.qpmin) *
808 hrt2ev))
809 .str());
810 level_beta.add("gw_energy",
811 (boost::format("%1$+1.6f ") %
812 (orbitals_.QPpertEnergiesBeta()(state) * hrt2ev))
813 .str());
814 level_beta.add("qp_energy",
815 (boost::format("%1$+1.6f ") %
816 (orbitals_.QPdiagBeta().eigenvalues()(state) * hrt2ev))
817 .str());
818 }
819 } else {
820 tools::Property& dft_summary = gwbse_summary.add("dft", "");
821 dft_summary.setAttribute("HOMO", gwopt_.homo);
822 dft_summary.setAttribute("LUMO", gwopt_.homo + 1);
823
824 for (Index state = 0; state < gwopt_.qpmax + 1 - gwopt_.qpmin; state++) {
825 tools::Property& level_summary = dft_summary.add("level", "");
826 level_summary.setAttribute("number", state + gwopt_.qpmin);
827 level_summary.add(
828 "dft_energy",
829 (boost::format("%1$+1.6f ") %
830 (orbitals_.MOs().eigenvalues()(state + gwopt_.qpmin) * hrt2ev))
831 .str());
832 level_summary.add("gw_energy",
833 (boost::format("%1$+1.6f ") %
834 (orbitals_.QPpertEnergies()(state) * hrt2ev))
835 .str());
836 level_summary.add("qp_energy",
837 (boost::format("%1$+1.6f ") %
838 (orbitals_.QPdiag().eigenvalues()(state) * hrt2ev))
839 .str());
840 }
841 }
842 }
843 if (do_bse_singlets_) {
844 tools::Property& singlet_summary = gwbse_summary.add("singlets", "");
845 for (Index state = 0; state < bseopt_.nmax; ++state) {
846 tools::Property& level_summary = singlet_summary.add("level", "");
847 level_summary.setAttribute("number", state + 1);
848 level_summary.add(
849 "omega", (boost::format("%1$+1.6f ") %
850 (orbitals_.BSESinglets().eigenvalues()(state) * hrt2ev))
851 .str());
852 if (orbitals_.hasTransitionDipoles()) {
853
854 const Eigen::Vector3d& dipoles = (orbitals_.TransitionDipoles())[state];
855 double f = 2 * dipoles.squaredNorm() *
856 orbitals_.BSESinglets().eigenvalues()(state) / 3.0;
857
858 level_summary.add("f", (boost::format("%1$+1.6f ") % f).str());
859 tools::Property& dipol_summary = level_summary.add(
860 "Trdipole", (boost::format("%1$+1.4f %2$+1.4f %3$+1.4f") %
861 dipoles.x() % dipoles.y() % dipoles.z())
862 .str());
863 dipol_summary.setAttribute("unit", "e*bohr");
864 dipol_summary.setAttribute("gauge", "length");
865 }
866 }
867 }
868 if (do_bse_triplets_) {
869 tools::Property& triplet_summary = gwbse_summary.add("triplets", "");
870 for (Index state = 0; state < bseopt_.nmax; ++state) {
871 tools::Property& level_summary = triplet_summary.add("level", "");
872 level_summary.setAttribute("number", state + 1);
873 level_summary.add(
874 "omega", (boost::format("%1$+1.6f ") %
875 (orbitals_.BSETriplets().eigenvalues()(state) * hrt2ev))
876 .str());
877 }
878 }
880 tools::Property& exciton_uks_summary = gwbse_summary.add("exciton_uks", "");
881
882 const bool has_dipoles = orbitals_.hasTransitionDipoles();
883 Eigen::VectorXd oscs = Eigen::VectorXd::Zero(0);
884 if (has_dipoles) {
885 oscs =
886 orbitals_.Oscillatorstrengths(QMStateType(QMStateType::ExcitonUKS));
887 }
888
889 for (Index state = 0;
890 state <
891 std::min<Index>(bseopt_.nmax, orbitals_.BSEUKS().eigenvalues().size());
892 ++state) {
893 tools::Property& level_summary = exciton_uks_summary.add("level", "");
894 level_summary.setAttribute("number", state + 1);
895 level_summary.add("omega",
896 (boost::format("%1$+1.6f ") %
897 (orbitals_.BSEUKS().eigenvalues()(state) * hrt2ev))
898 .str());
899 const Index ndip =
900 static_cast<Index>(orbitals_.TransitionDipoles().size());
901 const Index nosc = static_cast<Index>(oscs.size());
902
903 if (has_dipoles && state < ndip && state < nosc) {
904 const Eigen::Vector3d& dipoles = orbitals_.TransitionDipoles()[state];
905
906 level_summary.add("f",
907 (boost::format("%1$+1.6f ") % oscs(state)).str());
908
909 tools::Property& dipol_summary = level_summary.add(
910 "Trdipole", (boost::format("%1$+1.4f %2$+1.4f %3$+1.4f") %
911 dipoles.x() % dipoles.y() % dipoles.z())
912 .str());
913 dipol_summary.setAttribute("unit", "e*bohr");
914 dipol_summary.setAttribute("gauge", "length");
915 }
916 }
917 }
918
919 return;
920}
921
922/*
923 * Many-body Green's fuctions theory implementation
924 *
925 * data required from orbitals file
926 * - atomic coordinates
927 * - DFT molecular orbitals (energies and coeffcients)
928 * - DFT exchange-correlation potential matrix in atomic orbitals
929 * - number of electrons, number of levels
930 */
931
932Eigen::MatrixXd GWBSE::CalculateVXC(const AOBasis& dftbasis) {
933 if (orbitals_.getXCFunctionalName().empty()) {
934 orbitals_.setXCFunctionalName(functional_);
935 } else {
936 if (!(functional_ == orbitals_.getXCFunctionalName())) {
937 throw std::runtime_error("Functionals from DFT " +
938 orbitals_.getXCFunctionalName() + " GWBSE " +
939 functional_ + " differ!");
940 }
941 }
942
943 Vxc_Grid grid;
944 grid.GridSetup(grid_, orbitals_.QMAtoms(), dftbasis);
946 << TimeStamp() << " Setup grid for integration with gridsize: " << grid_
947 << " with " << grid.getGridSize() << " points, divided into "
948 << grid.getBoxesSize() << " boxes" << flush;
949 Vxc_Potential<Vxc_Grid> vxcpotential(grid);
950 vxcpotential.setXCfunctional(functional_);
952 << TimeStamp() << " Integrating Vxc with functional " << functional_
953 << flush;
954 Eigen::MatrixXd DMAT = orbitals_.DensityMatrixGroundState();
955 Mat_p_Energy e_vxc_ao = vxcpotential.IntegrateVXC(DMAT);
956 XTP_LOG(Log::info, *pLog_) << TimeStamp() << " Calculated Vxc" << flush;
958 << TimeStamp() << " Set hybrid exchange factor: " << orbitals_.getScaHFX()
959 << flush;
960 Index qptotal = gwopt_.qpmax - gwopt_.qpmin + 1;
961 Eigen::MatrixXd mos =
962 orbitals_.MOs().eigenvectors().middleCols(gwopt_.qpmin, qptotal);
963
964 Eigen::MatrixXd vxc = mos.transpose() * e_vxc_ao.matrix() * mos;
966 << TimeStamp() << " Calculated exchange-correlation expectation values "
967 << flush;
968
969 return vxc;
970}
971
972std::pair<Eigen::MatrixXd, Eigen::MatrixXd> GWBSE::CalculateVXCSpinResolved(
973 const AOBasis& dftbasis) {
974 if (orbitals_.getXCFunctionalName().empty()) {
975 orbitals_.setXCFunctionalName(functional_);
976 } else if (!(functional_ == orbitals_.getXCFunctionalName())) {
977 throw std::runtime_error("Functionals from DFT " +
978 orbitals_.getXCFunctionalName() + " GWBSE " +
979 functional_ + " differ!");
980 }
981
982 Vxc_Grid grid;
983 grid.GridSetup(grid_, orbitals_.QMAtoms(), dftbasis);
984 Vxc_Potential<Vxc_Grid> vxcpotential(grid);
985 vxcpotential.setXCfunctional(functional_);
986
987 auto dmats = orbitals_.DensityMatrixGroundStateSpinResolved();
988 auto e_vxc_ao = vxcpotential.IntegrateVXCSpin(dmats[0], dmats[1]);
989
990 Index qptotal = gwopt_.qpmax - gwopt_.qpmin + 1;
991 Eigen::MatrixXd mos_alpha =
992 orbitals_.MOs().eigenvectors().middleCols(gwopt_.qpmin, qptotal);
993 Eigen::MatrixXd mos_beta =
994 orbitals_.MOs_beta().eigenvectors().middleCols(gwopt_.qpmin, qptotal);
995
996 Eigen::MatrixXd vxc_alpha =
997 mos_alpha.transpose() * e_vxc_ao.vxc_alpha * mos_alpha;
998 Eigen::MatrixXd vxc_beta =
999 mos_beta.transpose() * e_vxc_ao.vxc_beta * mos_beta;
1000
1001 return std::make_pair(vxc_alpha, vxc_beta);
1002}
1003
1005 citations::Cite("Wehner:2018");
1006 citations::Cite("Tirimbo:2020a");
1007 if (gwopt_.do_qsgw) {
1008 citations::Cite("vanSchilfgaarde:2006");
1009 }
1010
1011 // set the parallelization
1012 XTP_LOG(Log::error, *pLog_) << TimeStamp() << " Using "
1013 << OPENMP::getMaxThreads() << " threads" << flush;
1014
1016 << TimeStamp() << " Using " << EigenBackendDescription() << flush;
1019 << " Screening eigensolvers and inverses call "
1020 "Accelerate LAPACK directly"
1021 << flush;
1022 }
1024 << TimeStamp() << " Molecule Coordinates [A] " << flush;
1025 for (QMAtom& atom : orbitals_.QMAtoms()) {
1026 std::string output = (boost::format("%5d"
1027 "%5s"
1028 " %1.4f %1.4f %1.4f") %
1029 atom.getId() % atom.getElement() %
1030 (atom.getPos().x() * tools::conv::bohr2ang) %
1031 (atom.getPos().y() * tools::conv::bohr2ang) %
1032 (atom.getPos().z() * tools::conv::bohr2ang))
1033 .str();
1034
1035 XTP_LOG(Log::error, *pLog_) << output << flush;
1036 }
1037
1038 std::string dft_package = orbitals_.getQMpackage();
1040 << TimeStamp() << " DFT data was created by " << dft_package << flush;
1041
1042 BasisSet dftbs;
1043 dftbs.Load(dftbasis_name_);
1044
1046 << TimeStamp() << " Loaded DFT Basis Set " << dftbasis_name_ << flush;
1047
1048 AOBasis dftbasis = orbitals_.getDftBasis();
1049 XTP_LOG(Log::error, *pLog_) << TimeStamp() << " Filled DFT Basis of size "
1050 << dftbasis.AOBasisSize() << flush;
1052 << TimeStamp() << " Loaded Auxbasis Set " << auxbasis_name_ << flush;
1053
1054 orbitals_.SetupAuxBasis(auxbasis_name_);
1055 AOBasis auxbasis = orbitals_.getAuxBasis();
1056 XTP_LOG(Log::error, *pLog_) << TimeStamp() << " Filled Auxbasis of size "
1057 << auxbasis.AOBasisSize() << flush;
1058
1060 fragments_.size() > 0) {
1061 for (const auto& frag : fragments_) {
1062 XTP_LOG(Log::error, *pLog_) << TimeStamp() << " Fragment " << frag.getId()
1063 << " size:" << frag.size() << flush;
1064 }
1065 }
1066
1067 if (!do_gw_) {
1068 if ((!orbitals_.hasUnrestrictedOrbitals() && !orbitals_.hasQPdiag()) ||
1069 (orbitals_.hasUnrestrictedOrbitals() &&
1070 (!orbitals_.hasQPdiagAlpha() || !orbitals_.hasQPdiagBeta()))) {
1071 throw std::runtime_error(
1072 "You want no GW calculation but the orb file has no matching QP "
1073 "coefficients.");
1074 }
1075 }
1076 const bool is_uks = orbitals_.hasUnrestrictedOrbitals();
1077 TCMatrix_gwbse Mmn;
1078 TCMatrix_gwbse_spin Mmn_spin;
1079 // rpamin here, because RPA needs till rpamin
1080 Index max_3c = std::max(bseopt_.cmax, gwopt_.qpmax);
1081 if (is_uks) {
1082 Mmn_spin.alpha.Initialize(auxbasis.AOBasisSize(), gwopt_.rpamin, max_3c,
1083 gwopt_.rpamin, gwopt_.rpamax);
1084 Mmn_spin.beta.Initialize(auxbasis.AOBasisSize(), gwopt_.rpamin, max_3c,
1085 gwopt_.rpamin, gwopt_.rpamax);
1087 << TimeStamp() << " Calculating alpha spin Mmn " << flush;
1088 Mmn_spin.alpha.Fill(auxbasis, dftbasis, orbitals_.MOs().eigenvectors());
1090 << TimeStamp() << " Calculating beta spin Mmn " << flush;
1091 Mmn_spin.beta.Fill(auxbasis, dftbasis, orbitals_.MOs_beta().eigenvectors());
1092 } else {
1093 Mmn.Initialize(auxbasis.AOBasisSize(), gwopt_.rpamin, max_3c, gwopt_.rpamin,
1094 gwopt_.rpamax);
1096 << TimeStamp() << " Calculating Mmn (3-center-repulsion x orbitals) "
1097 << flush;
1098 Mmn.Fill(auxbasis, dftbasis, orbitals_.MOs().eigenvectors());
1100 << TimeStamp() << " Removed " << Mmn.Removedfunctions()
1101 << " functions from Aux Coulomb matrix to avoid near linear "
1102 "dependencies"
1103 << flush;
1105 << TimeStamp() << " Calculated Mmn (3-center-repulsion x orbitals) "
1106 << flush;
1107 }
1108 if (const std::string usage = MemoryBudget::Usage(); !usage.empty()) {
1110 << TimeStamp() << " After Mmn: " << usage << flush;
1111 }
1112
1113 // The environment's reaction field in the metric of Mmn. Needs only the
1114 // auxiliary basis and its metric, so it stays valid however Mmn is later
1115 // rotated, dressed or refilled (QSGW) -- all of it on this basis.
1116 Eigen::MatrixXd reaction_field;
1117 if (!environment_.empty()) {
1118 if (is_uks) {
1119 throw std::runtime_error(
1120 "GWBSE: environment screening is implemented for closed-shell "
1121 "systems only.");
1122 }
1123 std::chrono::time_point<std::chrono::system_clock> start =
1124 std::chrono::system_clock::now();
1125 Index n_explicit = 0;
1126 for (const PolarSegment& seg : environment_.explicit_segments) {
1127 n_explicit += seg.size();
1128 }
1129 Index n_shell = 0;
1130 for (const PolarSegment& seg : environment_.shell_segments) {
1131 n_shell += seg.size();
1132 }
1134 << TimeStamp() << " Environment screening: " << n_explicit
1135 << " explicit Thole sites (exp_damp " << environment_.exp_damp << "), "
1136 << n_shell << " shell sites (epsilon " << environment_.shell_dielectric
1137 << ")" << flush;
1138 const Eigen::MatrixXd B =
1140 reaction_field =
1142 std::chrono::duration<double> elapsed_time =
1143 std::chrono::system_clock::now() - start;
1145 << TimeStamp() << " Built environment reaction field in "
1146 << elapsed_time.count() << " seconds." << flush;
1147 }
1148
1149 Eigen::MatrixXd Hqp;
1150 Eigen::MatrixXd Hqp_alpha;
1151 Eigen::MatrixXd Hqp_beta;
1152 if (do_gw_) {
1153
1154 std::chrono::time_point<std::chrono::system_clock> start =
1155 std::chrono::system_clock::now();
1156 if (is_uks) {
1157 if (gwopt_.do_qsgw) {
1158 throw std::runtime_error(
1159 "QSGW (gw.do_qsgw) is not implemented for open-shell (UKS) "
1160 "references.");
1161 }
1162 auto vxc = CalculateVXCSpinResolved(dftbasis);
1163 GW_UKS::options gwopt_uks;
1164 gwopt_uks.homo_alpha = orbitals_.getHomoAlpha();
1165 gwopt_uks.homo_beta = orbitals_.getHomoBeta();
1166 gwopt_uks.qpmin = gwopt_.qpmin;
1167 gwopt_uks.qpmax = gwopt_.qpmax;
1168 gwopt_uks.rpamin = gwopt_.rpamin;
1169 gwopt_uks.rpamax = gwopt_.rpamax;
1170 gwopt_uks.eta = gwopt_.eta;
1171 gwopt_uks.g_sc_limit = gwopt_.g_sc_limit;
1172 gwopt_uks.g_sc_max_iterations = gwopt_.g_sc_max_iterations;
1173 gwopt_uks.gw_sc_limit = gwopt_.gw_sc_limit;
1174 gwopt_uks.gw_sc_max_iterations = gwopt_.gw_sc_max_iterations;
1175 gwopt_uks.shift = gwopt_.shift;
1176 gwopt_uks.ScaHFX = gwopt_.ScaHFX;
1177 gwopt_uks.sigma_integration = gwopt_.sigma_integration;
1178 gwopt_uks.reset_3c = gwopt_.reset_3c;
1179 gwopt_uks.qp_solver = gwopt_.qp_solver;
1180 gwopt_uks.qp_solver_alpha = gwopt_.qp_solver_alpha;
1181 gwopt_uks.qp_grid_steps = gwopt_.qp_grid_steps;
1182 gwopt_uks.qp_grid_spacing = gwopt_.qp_grid_spacing;
1183
1184 // Forward the already-normalized canonical grid-search controls so that
1185 // RKS and UKS use the same search design and only differ in the
1186 // spin-dependent sigma evaluation.
1187 gwopt_uks.qp_full_window_half_width = gwopt_.qp_full_window_half_width;
1188 gwopt_uks.qp_dense_spacing = gwopt_.qp_dense_spacing;
1189 gwopt_uks.qp_adaptive_shell_width = gwopt_.qp_adaptive_shell_width;
1190 gwopt_uks.qp_adaptive_shell_count = gwopt_.qp_adaptive_shell_count;
1191 gwopt_uks.gw_mixing_order = gwopt_.gw_mixing_order;
1192 gwopt_uks.gw_mixing_alpha = gwopt_.gw_mixing_alpha;
1193 gwopt_uks.quadrature_scheme = gwopt_.quadrature_scheme;
1194 gwopt_uks.order = gwopt_.order;
1195 gwopt_uks.alpha = gwopt_.alpha;
1196 gwopt_uks.out_of_window_shift = gwopt_.out_of_window_shift;
1197 gwopt_uks.qp_restrict_search = gwopt_.qp_restrict_search;
1198 gwopt_uks.qp_root_continuity = gwopt_.qp_root_continuity;
1199 gwopt_uks.screening_update = gwopt_.screening_update;
1200 gwopt_uks.qp_root_tracking = gwopt_.qp_root_tracking;
1201 gwopt_uks.screening_update_ratio = gwopt_.screening_update_ratio;
1202 gwopt_uks.screening_update_max_inner = gwopt_.screening_update_max_inner;
1203 gwopt_uks.qp_zero_margin = gwopt_.qp_zero_margin;
1204 gwopt_uks.qp_virtual_min_energy = gwopt_.qp_virtual_min_energy;
1205 gwopt_uks.qp_root_finder = gwopt_.qp_root_finder;
1206 gwopt_uks.qp_grid_search_mode = gwopt_.qp_grid_search_mode;
1207
1208 GW_UKS gw = GW_UKS(*pLog_, Mmn_spin, vxc.first, vxc.second,
1209 orbitals_.MOs().eigenvalues(),
1210 orbitals_.MOs_beta().eigenvalues());
1211 gw.configure(gwopt_uks);
1212 if (gwopt_.rpamin > 0 && core_exchange_) {
1213 gw.setCoreExchange(
1215 auxbasis, dftbasis, orbitals_.MOs().eigenvectors(),
1216 gwopt_.rpamin, gwopt_.qpmin, gwopt_.qpmax),
1218 auxbasis, dftbasis, orbitals_.MOs_beta().eigenvectors(),
1219 gwopt_.rpamin, gwopt_.qpmin, gwopt_.qpmax));
1221 << TimeStamp() << " Sigma_x includes the exchange with the "
1222 << gwopt_.rpamin << " frozen core levels" << flush;
1223 }
1225 orbitals_.QPpertEnergiesAlpha() = gw.getGWAResultsAlpha();
1226 orbitals_.QPpertEnergiesBeta() = gw.getGWAResultsBeta();
1227 orbitals_.RPAInputEnergiesAlpha() = gw.RPAInputEnergiesAlpha();
1228 orbitals_.RPAInputEnergiesBeta() = gw.RPAInputEnergiesBeta();
1229 gw.CalculateHQP();
1230 Hqp_alpha = gw.getHQPAlpha();
1231 Hqp_beta = gw.getHQPBeta();
1232 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es_alpha =
1234 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es_beta =
1236 orbitals_.QPdiagAlpha().eigenvectors() = es_alpha.eigenvectors();
1237 orbitals_.QPdiagAlpha().eigenvalues() = es_alpha.eigenvalues();
1238 orbitals_.QPdiagBeta().eigenvectors() = es_beta.eigenvectors();
1239 orbitals_.QPdiagBeta().eigenvalues() = es_beta.eigenvalues();
1240 std::chrono::duration<double> elapsed_time =
1241 std::chrono::system_clock::now() - start;
1243 << TimeStamp() << " UKS GW calculation took " << elapsed_time.count()
1244 << " seconds." << flush;
1245 } else {
1246 Eigen::MatrixXd vxc = CalculateVXC(dftbasis);
1247 GW gw = GW(*pLog_, Mmn, vxc, orbitals_.MOs().eigenvalues());
1248 gw.configure(gwopt_);
1250 gw.setReactionField(reaction_field);
1251 if (gwopt_.rpamin > 0 && core_exchange_) {
1253 auxbasis, dftbasis, orbitals_.MOs().eigenvectors(), gwopt_.rpamin,
1254 gwopt_.qpmin, gwopt_.qpmax));
1256 << TimeStamp() << " Sigma_x includes the exchange with the "
1257 << gwopt_.rpamin << " frozen core levels" << flush;
1258 }
1259
1261
1262 if (!sigma_plot_states_.empty()) {
1265 }
1266
1267 orbitals_.QPpertEnergies() = gw.getGWAResults();
1268 orbitals_.RPAInputEnergies() = gw.RPAInputEnergies();
1269
1271 << TimeStamp() << " Calculating offdiagonal part of Sigma " << flush;
1272 if (gwopt_.do_qsgw) {
1273 // QSGW: iterate rotation of Mmn until QP energies converge.
1274 gw.CalculateQSGW();
1275
1276 // Print seed vs QSGW comparison. Label the seed column by what
1277 // CalculateGWPerturbation ran: G0W0 if one iteration, evGW otherwise.
1278 const std::string seed_label =
1279 (gwopt_.gw_sc_max_iterations == 1) ? "G0W0" : "evGW";
1280 Eigen::VectorXd qsgw_energies = gw.getGWAResults();
1281 gw.PrintQSGW_Energies(seed_label, gw.getQSGWSeedEnergies(),
1282 qsgw_energies);
1284
1285 // The QSGW orbitals and energies: QPdiag holds U (DFT MOs -> QSGW
1286 // orbitals, columns) and the energies, so that BSE-only runs from the
1287 // .orb file and everything built from the BSE vectors (transition
1288 // dipoles, densities) use C_qp = C_dft U (Orbitals::BSEOrbitals).
1289 // QPpertEnergies() keeps the G0W0/evGW seed. The RPA energies are
1290 // the QSGW ones in the window.
1291 orbitals_.QPdiag().eigenvalues() = qsgw_energies;
1292 orbitals_.QPdiag().eigenvectors() = gw.getQSGWRotation();
1293 orbitals_.setQSGW(true);
1294 orbitals_.RPAInputEnergies() = gw.RPAInputEnergies();
1295
1296 // The BSE in the QSGW orbitals: integrals refilled with C_qp (levels
1297 // outside the GW window stay DFT MOs, scissor-shifted in the RPA
1298 // energies and in AdjustHqpSize), and H_qp is diagonal.
1300 << TimeStamp() << " Rebuilding Mmn in QSGW QP wavefunction basis"
1301 << flush;
1302 Mmn.Fill(auxbasis, dftbasis, orbitals_.BSEOrbitals());
1304 << TimeStamp() << " Rebuilt Mmn (3-center-repulsion x QP orbitals)"
1305 << flush;
1306 Hqp = qsgw_energies.asDiagonal();
1307 } else {
1308 orbitals_.setQSGW(false);
1309 gw.CalculateHQP();
1311 << TimeStamp() << " Calculated offdiagonal part of Sigma "
1312 << flush;
1313
1314 Hqp = gw.getHQP();
1315
1316 if (do_sigma_dump_) {
1318 (gwopt_.gw_sc_max_iterations > 1) ? "evGW" : "G0W0",
1320 }
1321
1322 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es =
1324 if (es.info() == Eigen::ComputationInfo::Success) {
1326 << TimeStamp() << " Diagonalized QP Hamiltonian " << flush;
1327 }
1328
1329 orbitals_.QPdiag().eigenvectors() = es.eigenvectors();
1330 orbitals_.QPdiag().eigenvalues() = es.eigenvalues();
1331 }
1332 std::chrono::duration<double> elapsed_time =
1333 std::chrono::system_clock::now() - start;
1335 << TimeStamp() << " GW calculation took " << elapsed_time.count()
1336 << " seconds." << flush;
1337 }
1338
1339 } else {
1340 if (orbitals_.getGWAmax() != gwopt_.qpmax ||
1341 orbitals_.getGWAmin() != gwopt_.qpmin ||
1342 orbitals_.getRPAmax() != gwopt_.rpamax ||
1343 orbitals_.getRPAmin() != gwopt_.rpamin) {
1344 throw std::runtime_error(
1345 "The ranges for GW and RPA do not agree with the ranges from the "
1346 ".orb file, rerun your GW calculation");
1347 }
1348
1349 if (is_uks) {
1350 const Eigen::MatrixXd& qpcoeff_alpha =
1351 orbitals_.QPdiagAlpha().eigenvectors();
1352 const Eigen::MatrixXd& qpcoeff_beta =
1353 orbitals_.QPdiagBeta().eigenvectors();
1354
1355 Hqp_alpha = qpcoeff_alpha *
1356 orbitals_.QPdiagAlpha().eigenvalues().asDiagonal() *
1357 qpcoeff_alpha.transpose();
1358 Hqp_beta = qpcoeff_beta *
1359 orbitals_.QPdiagBeta().eigenvalues().asDiagonal() *
1360 qpcoeff_beta.transpose();
1361 } else if (orbitals_.isQSGW()) {
1362 // QSGW BSE-only run: rebuild Mmn_ in the QSGW orbitals stored in
1363 // QPdiag. Hqp is diagonal in that basis.
1365 << TimeStamp()
1366 << " Rebuilding Mmn in QSGW QP wavefunction basis (BSE-only)"
1367 << flush;
1368 Mmn.Fill(auxbasis, dftbasis, orbitals_.BSEOrbitals());
1370 << TimeStamp() << " Rebuilt Mmn (3-center-repulsion x QP orbitals)"
1371 << flush;
1372 Hqp = orbitals_.QPdiag().eigenvalues().asDiagonal();
1373 } else {
1374 const Eigen::MatrixXd& qpcoeff = orbitals_.QPdiag().eigenvectors();
1375
1376 Hqp = qpcoeff * orbitals_.QPdiag().eigenvalues().asDiagonal() *
1377 qpcoeff.transpose();
1378 }
1379 }
1380
1381 // proceed only if BSE requested
1383
1384 std::chrono::time_point<std::chrono::system_clock> start =
1385 std::chrono::system_clock::now();
1386
1387 if (is_uks) {
1388
1389 // Build a single spin-summed dielectric screening from the unrestricted
1390 // RPA response and reuse it for both exciton spin channels.
1391 RPA_UKS rpa_uks_bse(*pLog_, Mmn_spin);
1392 rpa_uks_bse.configure(orbitals_.getHomoAlpha(), orbitals_.getHomoBeta(),
1393 bseopt_.rpamin, bseopt_.rpamax);
1394 rpa_uks_bse.setRPAInputEnergies(orbitals_.RPAInputEnergiesAlpha(),
1395 orbitals_.RPAInputEnergiesBeta());
1396
1397 const SymmetricEigenSystem es_bse =
1398 SymmetricEigen(rpa_uks_bse.calculate_epsilon_r(0.0));
1399
1400 Eigen::VectorXd epsilon_0_inv_bse =
1401 Eigen::VectorXd::Zero(es_bse.values.size());
1402 for (Index i = 0; i < es_bse.values.size(); ++i) {
1403 if (es_bse.values(i) > 1e-8) {
1404 epsilon_0_inv_bse(i) = 1.0 / es_bse.values(i);
1405 }
1406 }
1407
1408 if (do_bse_exciton_uks_) {
1409 BSE_UKS::options bseopt_uks;
1410 bseopt_uks.useTDA = bseopt_.useTDA;
1411 bseopt_uks.rpamin = bseopt_.rpamin;
1412 bseopt_uks.rpamax = bseopt_.rpamax;
1413 bseopt_uks.qpmin = bseopt_.qpmin;
1414 bseopt_uks.qpmax = bseopt_.qpmax;
1415 bseopt_uks.vmin = bseopt_.vmin;
1416 bseopt_uks.cmax = bseopt_.cmax;
1417 bseopt_uks.nmax = bseopt_.nmax;
1418 bseopt_uks.davidson_correction = bseopt_.davidson_correction;
1419 bseopt_uks.davidson_tolerance = bseopt_.davidson_tolerance;
1420 bseopt_uks.davidson_update = bseopt_.davidson_update;
1421 bseopt_uks.davidson_maxiter = bseopt_.davidson_maxiter;
1422 bseopt_uks.min_print_weight = bseopt_.min_print_weight;
1423 bseopt_uks.use_Hqp_offdiag = bseopt_.use_Hqp_offdiag;
1424 bseopt_uks.max_dyn_iter = bseopt_.max_dyn_iter;
1425 bseopt_uks.dyn_tolerance = bseopt_.dyn_tolerance;
1426
1427 BSE_UKS bse_uks(*pLog_, Mmn_spin);
1429 bseopt_uks, orbitals_.getHomoAlpha(), orbitals_.getHomoBeta(),
1430 orbitals_.RPAInputEnergiesAlpha(), orbitals_.RPAInputEnergiesBeta(),
1431 Hqp_alpha, Hqp_beta, epsilon_0_inv_bse, es_bse.vectors);
1432
1435 << TimeStamp() << " Solved combined UKS BSE exciton problem "
1436 << flush;
1438
1441 }
1442 }
1443 } else {
1444 BSE bse = BSE(*pLog_, Mmn);
1445 bse.setReactionField(reaction_field, environment_.include_kreac);
1446 bse.configure(bseopt_, orbitals_.RPAInputEnergies(), Hqp);
1447
1448 if (do_bse_triplets_) {
1451 << TimeStamp() << " Solved BSE for triplets " << flush;
1453 }
1454
1455 if (do_bse_singlets_) {
1458 << TimeStamp() << " Solved BSE for singlets " << flush;
1460 }
1461
1463 if (do_bse_triplets_) {
1465 orbitals_);
1466 }
1467
1468 if (do_bse_singlets_) {
1470 orbitals_);
1471 }
1472 }
1473 }
1474
1475 std::chrono::duration<double> elapsed_time =
1476 std::chrono::system_clock::now() - start;
1477 XTP_LOG(Log::error, *pLog_) << TimeStamp() << " BSE calculation took "
1478 << elapsed_time.count() << " seconds." << flush;
1479 }
1480 if (const std::string usage = MemoryBudget::Usage(); !usage.empty()) {
1482 << TimeStamp() << " End of GWBSE: " << usage << flush;
1483 }
1485 << TimeStamp() << " GWBSE calculation finished " << flush;
1486 return true;
1487}
1488
1489} // namespace xtp
1490} // namespace votca
class to manage program options with xml serialization functionality
Definition property.h:55
Property & add(const std::string &key, const std::string &value)
add a new property to structure
Definition property.cc:108
Property & get(const std::string &key)
get existing property
Definition property.cc:79
bool exists(const std::string &key) const
check whether property exists
Definition property.cc:122
T as() const
return value as type
Definition property.h:283
T ifExistsReturnElseReturnDefault(const std::string &key, T defaultvalue) const
Definition property.h:332
std::vector< Property * > Select(const std::string &filter)
select property based on a filter
Definition property.cc:185
void setAttribute(const std::string &attribute, const T &value)
set an attribute
Definition property.h:325
Container to hold Basisfunctions for all atoms.
Definition aobasis.h:42
Index AOBasisSize() const
Definition aobasis.h:46
void configure_with_precomputed_screening(const options &opt, Index homo_alpha, Index homo_beta, const Eigen::VectorXd &RPAInputEnergiesAlpha, const Eigen::VectorXd &RPAInputEnergiesBeta, const Eigen::MatrixXd &Hqp_alpha_in, const Eigen::MatrixXd &Hqp_beta_in, const Eigen::VectorXd &epsilon_0_inv, const Eigen::MatrixXd &epsilon_eigenvectors)
Definition bse_uks.cc:67
void Perturbative_DynamicalScreening(Orbitals &orb)
Definition bse_uks.cc:674
void Solve_excitons_uks(Orbitals &orb) const
Definition bse_uks.cc:474
void Analyze_excitons_uks(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
Definition bse_uks.cc:631
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
void Analyze_singlets(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
Definition bse.cc:606
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 configure(const options &opt, const Eigen::VectorXd &RPAEnergies, const Eigen::MatrixXd &Hqp_in)
Definition bse.cc:63
void Solve_triplets(Orbitals &orb) const
Definition bse.cc:426
void Load(const std::string &name)
Definition basisset.cc:149
void Load(const std::string &name)
const ECPElement & getElement(std::string element_type) const
Index getNcore() const
Definition ecpbasisset.h:90
static Eigen::MatrixXd Kernel(const AOBasis &auxbasis, const ScreeningEnvironment &env)
B for a whole environment: ReactionFieldKernel of the explicit segments plus ShellKernel of the shell...
static Eigen::MatrixXd SymmetrizedReactionField(const Eigen::MatrixXd &B, const Eigen::MatrixXd &T)
R = T^T B T, the reaction field in the metric of the stored three-centre integrals,...
bool do_bse_exciton_uks_
Definition gwbse.h:92
std::pair< Eigen::MatrixXd, Eigen::MatrixXd > CalculateVXCSpinResolved(const AOBasis &dftbasis)
Definition gwbse.cc:972
std::vector< QMFragment< BSE_Population > > fragments_
Definition gwbse.h:116
std::string sigma_plot_states_
Definition gwbse.h:101
ScreeningEnvironment environment_
Definition gwbse.h:118
BSE::options bseopt_
Definition gwbse.h:99
void addoutput(tools::Property &summary)
Definition gwbse.cc:762
bool do_bse_triplets_
Definition gwbse.h:90
std::string grid_
Definition gwbse.h:96
GW::sigma_dump_options sigma_dump_opt_
Definition gwbse.h:110
std::string auxbasis_name_
Definition gwbse.h:113
bool do_bse_singlets_
Definition gwbse.h:89
bool core_exchange_
Definition gwbse.h:104
Orbitals & orbitals_
Definition gwbse.h:85
Eigen::MatrixXd CalculateVXC(const AOBasis &dftbasis)
Definition gwbse.cc:932
Index sigma_plot_steps_
Definition gwbse.h:105
std::string functional_
Definition gwbse.h:95
std::string dftbasis_name_
Definition gwbse.h:114
bool do_sigma_dump_
Definition gwbse.h:109
void Initialize(tools::Property &options)
Definition gwbse.cc:65
Index CountCoreLevels()
Definition gwbse.cc:51
GW::options gwopt_
Definition gwbse.h:98
double sigma_plot_spacing_
Definition gwbse.h:106
Logger * pLog_
Definition gwbse.h:84
std::string sigma_plot_filename_
Definition gwbse.h:107
bool do_dynamical_screening_bse_
Definition gwbse.h:91
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonianAlpha() const
Definition gw_uks.cc:1028
Eigen::VectorXd getGWAResultsAlpha() const
Definition gw_uks.cc:461
const Eigen::VectorXd & RPAInputEnergiesAlpha() const
Definition gw_uks.cc:471
const Eigen::VectorXd & RPAInputEnergiesBeta() const
Definition gw_uks.cc:474
Eigen::MatrixXd getHQPBeta() const
Definition gw_uks.cc:1021
Eigen::VectorXd getGWAResultsBeta() const
Definition gw_uks.cc:466
Eigen::MatrixXd getHQPAlpha() const
Definition gw_uks.cc:1016
void setCoreExchange(const Eigen::MatrixXd &alpha, const Eigen::MatrixXd &beta)
Frozen-core exchange per spin, see GW::setCoreExchange.
Definition gw_uks.h:103
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonianBeta() const
Definition gw_uks.cc:1035
void configure(const options &opt)
Definition gw_uks.cc:41
void CalculateGWPerturbation()
Definition gw_uks.cc:192
const Eigen::VectorXd & getQSGWSeedEnergies() const
Return the seed (G0W0/evGW) energies that QSGW started from.
Definition gw.h:220
void setReactionField(const Eigen::MatrixXd &R)
Screen by a static polarizable environment (embedded GW).
Definition gw.cc:72
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonian() const
Definition gw.cc:135
void DumpSigma(const sigma_dump_options &dopt, const std::string &gw_mode, const std::string &version)
Write the self-energy and screening data of the finished GW (G0W0 or evGW, ppm or exact) to a separat...
Definition gw.cc:1723
void setCoreExchange(const Eigen::MatrixXd &X)
Definition gw.h:188
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:225
void CalculateQSGW()
Run quasiparticle self-consistent GW (QSGW).
Definition gw.cc:1184
void configure(const options &opt)
Definition gw.cc:43
Eigen::MatrixXd getHQP() const
Definition gw.cc:129
void setKeepScreeningData(bool keep)
Call after configure and before CalculateGWPerturbation.
Definition gw.h:289
void PrintQSGW_Composition(double threshold=0.01) const
Print the dominant DFT-KS orbital contributions to each converged QSGW quasiparticle state.
Definition gw.cc:182
void CalculateHQP()
Definition gw.cc:1144
Eigen::VectorXd getGWAResults() const
Definition gw.cc:551
Eigen::VectorXd RPAInputEnergies() const
Definition gw.h:296
const Eigen::MatrixXd & getQSGWRotation() const
Definition gw.h:217
void PlotSigma(std::string filename, Index steps, double spacing, std::string states)
Definition gw.cc:1663
void CalculateGWPerturbation()
Definition gw.cc:287
Eigen::MatrixXd & matrix()
Definition eigen.h:97
static std::string Usage()
container for QM atoms
Definition qmatom.h:37
Unrestricted RPA helper for spin-resolved GW screening.
Definition rpa_uks.h:70
void setRPAInputEnergies(const Eigen::VectorXd &rpaenergies_alpha, const Eigen::VectorXd &rpaenergies_beta)
Set alpha and beta RPA input energies directly.
Definition rpa_uks.h:168
void configure(Index homo_alpha, Index homo_beta, Index rpamin, Index rpamax)
Definition rpa_uks.h:98
Eigen::MatrixXd calculate_epsilon_r(double frequency) const
Dielectric matrix on the real frequency axis.
Definition rpa_uks.h:131
static Mode Parse(const std::string &name)
void Fill(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &dft_orbitals)
void Initialize(Index basissize, Index mmin, Index mmax, Index nmin, Index nmax)
static Eigen::MatrixXd CoreExchange(const AOBasis &auxbasis, const AOBasis &dftbasis, const Eigen::MatrixXd &mos, Index ncore, Index qpmin, Index qpmax)
const Eigen::MatrixXd & InvSqrt() const
Index Removedfunctions() const
Definition threecenter.h:52
Timestamp returns the current time as a string Example: cout << TimeStamp().
Definition logger.h:224
Index getGridSize() const
Definition vxc_grid.h:41
void GridSetup(const std::string &type, const QMMolecule &atoms, const AOBasis &basis)
Definition vxc_grid.cc:230
Index getBoxesSize() const
Definition vxc_grid.h:42
Mat_p_Energy IntegrateVXC(const Eigen::MatrixXd &density_matrix) const
void setXCfunctional(const std::string &functional)
SpinResult IntegrateVXCSpin(const Eigen::MatrixXd &dmat_alpha, const Eigen::MatrixXd &dmat_beta) const
#define XTP_LOG(level, log)
Definition logger.h:40
const double ev2hrt
Definition constants.h:54
const double hrt2ev
Definition constants.h:53
const double bohr2ang
Definition constants.h:49
const std::string & ToolsVersionStr()
Definition version.cc:33
Index getMaxThreads()
Definition eigen.h:145
bool LapackAvailable()
Whether the routines below can run here (Accelerate build, macOS 13.3+).
void Cite(const std::string &key)
marks a reference as used (thread safe; unknown keys are printed as such)
Definition citations.cc:289
double LegacyAdaptiveShellWidth(const Opt &opt)
void NormalizeGridSearchOptions(Opt &opt)
double LegacyFullWindowHalfWidth(const Opt &opt)
Charge transport classes.
Definition ERIs.h:28
SymmetricEigenSystem SymmetricEigen(const Eigen::MatrixXd &A, bool vectors=true)
With vectors = false only the eigenvalues are computed.
ClassicalSegment< PolarSite > PolarSegment
std::string EigenBackendDescription()
Definition eigen.h:63
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
std::string davidson_update
Definition bse_uks.h:47
std::string davidson_tolerance
Definition bse_uks.h:46
std::string davidson_correction
Definition bse_uks.h:45
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
static Mode Parse(const std::string &name)
static std::string Name(Mode mode)