23#include <boost/algorithm/string.hpp>
24#include <boost/format.hpp>
50 Index ignored_corelevels = 0;
53 basis.
Load(
"corelevels");
54 Index coreElectrons = 0;
55 for (
const auto& atom :
orbitals_.QMAtoms()) {
58 ignored_corelevels = coreElectrons / 2;
60 return ignored_corelevels;
73 const bool is_uks =
orbitals_.hasUnrestrictedOrbitals();
81 num_of_occlevels = std::max(
orbitals_.getNumberOfAlphaElectrons(),
85 std::string ranges = options.
get(
".ranges").
as<std::string>();
89 if (ranges ==
"factor") {
91 double rpamaxfactor = options.
get(
".rpamax").
as<
double>();
92 rpamax =
Index(rpamaxfactor *
double(num_of_levels)) -
95 double qpminfactor = options.
get(
".qpmin").
as<
double>();
97 num_of_occlevels -
Index(qpminfactor *
double(num_of_occlevels)) - 1;
99 double qpmaxfactor = options.
get(
".qpmax").
as<
double>();
101 num_of_occlevels +
Index(qpmaxfactor *
double(num_of_occlevels)) - 1;
103 double bseminfactor = options.
get(
".bsemin").
as<
double>();
105 num_of_occlevels -
Index(bseminfactor *
double(num_of_occlevels)) - 1;
107 double bsemaxfactor = options.
get(
".bsemax").
as<
double>();
109 num_of_occlevels +
Index(bsemaxfactor *
double(num_of_occlevels)) - 1;
111 }
else if (ranges ==
"explicit") {
116 bse_vmin = options.
get(
".bsemin").
as<
Index>();
117 bse_cmax = options.
get(
".bsemax").
as<
Index>();
118 }
else if (ranges ==
"default") {
119 rpamax = num_of_levels - 1;
121 qpmax = 3 * homo + 1;
123 bse_cmax = 3 * homo + 1;
124 }
else if (ranges ==
"full") {
125 rpamax = num_of_levels - 1;
127 qpmax = num_of_levels - 1;
129 bse_cmax = num_of_levels - 1;
131 std::string ignore_corelevels =
132 options.
get(
".ignore_corelevels").
as<std::string>();
134 if (ignore_corelevels ==
"RPA" || ignore_corelevels ==
"GW" ||
135 ignore_corelevels ==
"BSE") {
137 if (ignore_corelevels ==
"RPA") {
138 rpamin = ignored_corelevels;
140 if (ignore_corelevels ==
"GW" || ignore_corelevels ==
"RPA") {
141 if (qpmin < ignored_corelevels) {
142 qpmin = ignored_corelevels;
145 if (ignore_corelevels ==
"GW" || ignore_corelevels ==
"RPA" ||
146 ignore_corelevels ==
"BSE") {
147 if (bse_vmin < ignored_corelevels) {
148 bse_vmin = ignored_corelevels;
153 <<
TimeStamp() <<
" Ignoring " << ignored_corelevels
154 <<
" core levels for " << ignore_corelevels <<
" and beyond." << flush;
158 if (rpamax >= num_of_levels) {
159 rpamax = num_of_levels - 1;
161 if (qpmax >= num_of_levels) {
162 qpmax = num_of_levels - 1;
164 if (bse_cmax >= num_of_levels) {
165 bse_cmax = num_of_levels - 1;
174 Index bse_vmax = homo;
175 Index bse_cmin = homo + 1;
181 const double qp_emax =
183 const double qp_emin =
185 const double bse_emax =
187 const double bse_emin =
189 std::vector<const Eigen::VectorXd*> spins{&
orbitals_.MOs().eigenvalues()};
190 std::vector<Index> homos{is_uks ?
orbitals_.getHomoAlpha() : homo};
192 spins.push_back(&
orbitals_.MOs_beta().eigenvalues());
193 homos.push_back(
orbitals_.getHomoBeta());
196 constexpr double degenerate = 5
e-4;
198 auto upper = [&](
double cap_ev) {
199 Index last = homo + 1;
200 for (std::size_t s = 0; s < spins.size(); ++s) {
201 const Eigen::VectorXd&
e = *spins[s];
203 Index i = homos[s] + 1;
204 while (i + 1 <
e.size() &&
e(i + 1) <= limit) {
207 const double edge =
e(i);
208 while (i + 1 <
e.size() &&
e(i + 1) - edge < degenerate) {
211 last = std::max(last, i);
216 auto lower = [&](
double cap_ev) {
218 for (std::size_t s = 0; s < spins.size(); ++s) {
219 const Eigen::VectorXd&
e = *spins[s];
222 while (i - 1 >= 0 &&
e(i - 1) >= limit) {
225 const double edge =
e(i);
226 while (i - 1 >= 0 && edge -
e(i - 1) < degenerate) {
229 first = std::min(first, i);
233 auto report = [&](
const std::string& what,
const std::string& option,
236 <<
TimeStamp() <<
" " << what <<
" capped by " << option <<
" = "
237 << cap <<
" eV: " << before <<
" -> " << after <<
" ("
238 << std::abs(before - after) <<
" levels removed)" << flush;
241 const Index cap = std::min(qpmax, upper(qp_emax));
242 report(
"GW window top",
"qp_emax", qp_emax, qpmax, cap);
246 const Index cap = std::max(qpmin, lower(qp_emin));
247 report(
"GW window bottom",
"qp_emin", qp_emin, qpmin, cap);
250 if (bse_emax > 0.0) {
251 const Index cap = std::min(bse_cmax, upper(bse_emax));
252 report(
"BSE window top",
"bse_emax", bse_emax, bse_cmax, cap);
255 if (bse_emin > 0.0) {
256 const Index cap = std::max(bse_vmin, lower(bse_emin));
257 report(
"BSE window bottom",
"bse_emin", bse_emin, bse_vmin, cap);
262 if (rpamin < 0 || rpamax < 0 || rpamin > rpamax) {
263 throw std::runtime_error(
"Invalid RPA level range after setup/clamping.");
265 if (qpmin < 0 || qpmax < 0 || qpmin > qpmax) {
266 throw std::runtime_error(
"Invalid GW level range after setup/clamping.");
268 if (bse_vmin < 0 || bse_vmax < 0 || bse_vmin > bse_vmax) {
269 throw std::runtime_error(
270 "Invalid BSE occupied level range after setup/clamping.");
272 if (bse_cmin < 0 || bse_cmax < 0 || bse_cmin > bse_cmax) {
273 throw std::runtime_error(
274 "Invalid BSE virtual level range after setup/clamping.");
276 if (bse_vmax >= num_of_levels || bse_cmax >= num_of_levels) {
277 throw std::runtime_error(
278 "BSE level range exceeds available orbital indices.");
280 if (bse_vmax >= bse_cmin) {
281 throw std::runtime_error(
"BSE occupied and virtual level ranges overlap.");
300 orbitals_.setBSEindices(bse_vmin, bse_cmax);
304 Index bse_vtotal = bse_vmax - bse_vmin + 1;
305 Index bse_ctotal = bse_cmax - bse_cmin + 1;
306 Index bse_size = bse_vtotal * bse_ctotal;
309 <<
":" << rpamax <<
"]" << flush;
311 <<
":" << qpmax <<
"]" << flush;
313 <<
TimeStamp() <<
" BSE level range occ[" << bse_vmin <<
":" << bse_vmax
314 <<
"] virt[" << bse_cmin <<
":" << bse_cmax <<
"]" << flush;
324 options.
get(
"bse.davidson.correction").
as<std::string>();
327 options.
get(
"bse.davidson.tolerance").
as<std::string>();
330 options.
get(
"bse.davidson.update").
as<std::string>();
342 Index full_bse_size = (
bseopt_.useTDA) ? bse_size : 2 * bse_size;
344 << full_bse_size <<
"x" << full_bse_size << flush;
346 bseopt_.use_Hqp_offdiag = options.
get(
"bse.use_Hqp_offdiag").
as<
bool>();
349 if (!
bseopt_.use_Hqp_offdiag) {
351 <<
" BSE without Hqp offdiagonal elements" << flush;
354 <<
" BSE with Hqp offdiagonal elements" << flush;
358 bseopt_.dyn_tolerance = options.
get(
"bse.dyn_screen_tol").
as<
double>();
359 if (
bseopt_.max_dyn_iter > 0) {
369 }
else if (options.
exists(
".auxbasisset")) {
376 }
catch (std::runtime_error&) {
377 throw std::runtime_error(
378 "There is no auxbasis from the dftcalculation nor did you specify an "
379 "auxbasisset for the gwbse calculation. Also no auxiliary basisset "
387 std::string mode = options.
get(
"gw.mode").
as<std::string>();
388 if (mode ==
"G0W0") {
389 gwopt_.gw_sc_max_iterations = 1;
395 gwopt_.shift = options.
get(
"gw.scissor_shift").
as<
double>();
397 options.
get(
"gw.qp_sc_limit").
as<
double>();
400 gwopt_.g_sc_max_iterations =
406 if (mode ==
"evGW") {
411 options.
get(
"gw.sc_limit").
as<
double>();
414 <<
" qp_sc_limit [Hartree]: " <<
gwopt_.g_sc_limit << flush;
415 if (
gwopt_.gw_sc_max_iterations > 1) {
417 <<
" gw_sc_limit [Hartree]: " <<
gwopt_.gw_sc_limit << flush;
419 bseopt_.min_print_weight = options.
get(
"bse.print_weight").
as<
double>();
423 std::string tasks_string = options.
get(
".tasks").
as<std::string>();
424 boost::algorithm::to_lower(tasks_string);
426 if (tasks_string.find(
"gw") != std::string::npos) {
431 if (tasks_string.find(
"excitons") != std::string::npos ||
432 tasks_string.find(
"exciton_uks") != std::string::npos) {
437 if (tasks_string.find(
"singlets") != std::string::npos ||
438 tasks_string.find(
"triplets") != std::string::npos) {
439 throw std::runtime_error(
440 "Invalid gwbse task for UKS reference: 'singlets' and 'triplets' "
441 "are not defined for open-shell systems.\n"
442 "Use 'exciton_uks' (or 'excitons') instead.");
445 if (tasks_string.find(
"all") != std::string::npos) {
455 if (tasks_string.find(
"singlets") != std::string::npos) {
458 if (tasks_string.find(
"triplets") != std::string::npos) {
477 if (options.
exists(
"bse.fragments")) {
478 std::vector<tools::Property*> prop_region =
479 options.
Select(
"bse.fragments.fragment");
482 std::string indices = prop->get(
"indices").as<std::string>();
488 gwopt_.sigma_integration =
489 options.
get(
"gw.sigma_integrator").
as<std::string>();
491 <<
" Sigma integration: " <<
gwopt_.sigma_integration << flush;
494 if (
gwopt_.sigma_integration ==
"exact") {
496 <<
" RPA Hamiltonian size: " << (homo + 1 - rpamin) * (rpamax - homo)
499 if (
gwopt_.sigma_integration ==
"cda") {
502 <<
" Quadrature integration order : " <<
gwopt_.order << flush;
503 gwopt_.quadrature_scheme =
504 options.
get(
"gw.quadrature_scheme").
as<std::string>();
506 <<
" Quadrature integration scheme : " <<
gwopt_.quadrature_scheme
508 gwopt_.alpha = options.
get(
"gw.alpha").
as<
double>();
510 <<
" Alpha smoothing parameter : " <<
gwopt_.alpha << flush;
512 gwopt_.qp_solver = options.
get(
"gw.qp_solver").
as<std::string>();
515 if (
gwopt_.qp_solver ==
"grid") {
524 if (options.
exists(
"gw.qp_full_window_half_width")) {
525 gwopt_.qp_full_window_half_width =
526 options.
get(
"gw.qp_full_window_half_width").
as<
double>();
528 if (options.
exists(
"gw.qp_dense_spacing")) {
529 gwopt_.qp_dense_spacing = options.
get(
"gw.qp_dense_spacing").
as<
double>();
531 if (options.
exists(
"gw.qp_adaptive_shell_width")) {
532 gwopt_.qp_adaptive_shell_width =
533 options.
get(
"gw.qp_adaptive_shell_width").
as<
double>();
535 if (options.
exists(
"gw.qp_adaptive_shell_count")) {
536 gwopt_.qp_adaptive_shell_count =
537 options.
get(
"gw.qp_adaptive_shell_count").
as<
Index>();
542 const bool has_legacy_steps = options.
exists(
"gw.qp_grid_steps");
543 const bool has_legacy_spacing = options.
exists(
"gw.qp_grid_spacing");
545 if (has_legacy_steps != has_legacy_spacing) {
546 throw std::runtime_error(
547 "Deprecated gw.qp_grid_steps and gw.qp_grid_spacing must be given "
548 "together if either is used.");
551 if (has_legacy_steps && has_legacy_spacing) {
553 gwopt_.qp_grid_spacing = options.
get(
"gw.qp_grid_spacing").
as<
double>();
555 const double legacy_half_width =
557 const double legacy_shell_width =
560 if (
gwopt_.qp_full_window_half_width <= 0.0) {
561 gwopt_.qp_full_window_half_width = legacy_half_width;
563 if (
gwopt_.qp_dense_spacing <= 0.0) {
566 if (
gwopt_.qp_adaptive_shell_count <= 0 &&
567 gwopt_.qp_adaptive_shell_width <= 0.0) {
568 gwopt_.qp_adaptive_shell_width = legacy_shell_width;
572 <<
" Deprecated GW QP options detected: " <<
"qp_grid_steps="
574 <<
" qp_grid_spacing=" <<
gwopt_.qp_grid_spacing
575 <<
" -> mapped to qp_full_window_half_width="
576 <<
gwopt_.qp_full_window_half_width
577 <<
" qp_dense_spacing=" <<
gwopt_.qp_dense_spacing
578 <<
" qp_adaptive_shell_width=" <<
gwopt_.qp_adaptive_shell_width
587 <<
" QP full window half-width: " <<
gwopt_.qp_full_window_half_width
590 <<
" QP dense spacing: " <<
gwopt_.qp_dense_spacing << flush;
592 <<
" QP adaptive shell width: " <<
gwopt_.qp_adaptive_shell_width
595 <<
" QP adaptive shell count: " <<
gwopt_.qp_adaptive_shell_count
598 gwopt_.qp_root_finder = options.
get(
"gw.qp_root_finder").
as<std::string>();
600 <<
" QP root finder: " <<
gwopt_.qp_root_finder << flush;
608 gwopt_.gw_mixing_alpha = options.
get(
"gw.mixing_alpha").
as<
double>();
609 gwopt_.qp_grid_search_mode =
610 options.
get(
"gw.qp_grid_search_mode").
as<std::string>();
611 gwopt_.qp_restrict_search = options.
get(
"gw.qp_restrict_search").
as<
bool>();
613 "gw.qp_root_continuity",
true);
615 "gw.qp_root_tracking",
false);
620 "gw.screening_update",
"adaptive");
622 gwopt_.screening_update_ratio =
624 "gw.screening_update_ratio", 0.1);
625 gwopt_.screening_update_max_inner =
627 "gw.screening_update_max_inner", 10);
628 gwopt_.qp_zero_margin = options.
get(
"gw.qp_zero_margin").
as<
double>();
629 gwopt_.qp_virtual_min_energy =
630 options.
get(
"gw.qp_virtual_min_energy").
as<
double>();
636 "gw.qsgw_max_iterations", 50);
639 gwopt_.qsgw_max_virt_correction =
641 "gw.qsgw_max_virt_correction", 0.5);
644 "gw.out_of_window_shift",
"max"));
645 gwopt_.out_of_window_shift.fit_fraction =
647 "gw.out_of_window_fit_fraction", 0.3);
650 <<
" Levels outside the GW window shifted by: "
653 ?
" (fit fraction " +
654 std::to_string(
gwopt_.out_of_window_shift.fit_fraction) +
661 <<
" QSGW enabled: max_iter=" <<
gwopt_.qsgw_max_iterations
662 <<
" sc_limit=" <<
gwopt_.qsgw_sc_limit <<
" Ha"
663 <<
" max_virt_correction=" <<
gwopt_.qsgw_max_virt_correction <<
" Ha ("
664 <<
gwopt_.qsgw_max_virt_correction * 27.2114 <<
" eV)" << std::flush;
667 if (mode ==
"evGW") {
668 if (
gwopt_.gw_mixing_order == 0) {
670 }
else if (
gwopt_.gw_mixing_order == 1) {
672 <<
gwopt_.gw_mixing_alpha << std::flush;
675 <<
gwopt_.gw_mixing_order <<
" using alpha "
676 <<
gwopt_.gw_mixing_alpha << std::flush;
678 if (
gwopt_.screening_update ==
"adaptive") {
680 <<
" evGW screening update: adaptive (ratio "
681 <<
gwopt_.screening_update_ratio <<
", at most "
682 <<
gwopt_.screening_update_max_inner <<
" iterations per W)"
686 <<
" evGW screening update: every iteration" << std::flush;
690 if (options.
exists(
"gw.sigma_plot")) {
695 options.
get(
"gw.sigma_plot.filename").
as<std::string>();
716 (boost::format(
"%1$+1.6f ") % (
orbitals_.getDFTTotalEnergy() * hrt2ev))
719 if (
orbitals_.hasUnrestrictedOrbitals()) {
720 gwbse_summary.
add(
"dft_alpha",
"");
721 gwbse_summary.
add(
"dft_beta",
"");
735 (boost::format(
"%1$+1.6f ") %
738 level_alpha.
add(
"gw_energy",
739 (boost::format(
"%1$+1.6f ") %
740 (
orbitals_.QPpertEnergiesAlpha()(state) * hrt2ev))
744 (boost::format(
"%1$+1.6f ") %
745 (
orbitals_.QPdiagAlpha().eigenvalues()(state) * hrt2ev))
752 (boost::format(
"%1$+1.6f ") %
756 level_beta.
add(
"gw_energy",
757 (boost::format(
"%1$+1.6f ") %
758 (
orbitals_.QPpertEnergiesBeta()(state) * hrt2ev))
760 level_beta.
add(
"qp_energy",
761 (boost::format(
"%1$+1.6f ") %
762 (
orbitals_.QPdiagBeta().eigenvalues()(state) * hrt2ev))
775 (boost::format(
"%1$+1.6f ") %
778 level_summary.
add(
"gw_energy",
779 (boost::format(
"%1$+1.6f ") %
780 (
orbitals_.QPpertEnergies()(state) * hrt2ev))
782 level_summary.
add(
"qp_energy",
783 (boost::format(
"%1$+1.6f ") %
784 (
orbitals_.QPdiag().eigenvalues()(state) * hrt2ev))
795 "omega", (boost::format(
"%1$+1.6f ") %
796 (
orbitals_.BSESinglets().eigenvalues()(state) * hrt2ev))
800 const Eigen::Vector3d& dipoles = (
orbitals_.TransitionDipoles())[state];
801 double f = 2 * dipoles.squaredNorm() *
802 orbitals_.BSESinglets().eigenvalues()(state) / 3.0;
804 level_summary.
add(
"f", (boost::format(
"%1$+1.6f ") % f).str());
806 "Trdipole", (boost::format(
"%1$+1.4f %2$+1.4f %3$+1.4f") %
807 dipoles.x() % dipoles.y() % dipoles.z())
820 "omega", (boost::format(
"%1$+1.6f ") %
821 (
orbitals_.BSETriplets().eigenvalues()(state) * hrt2ev))
828 const bool has_dipoles =
orbitals_.hasTransitionDipoles();
829 Eigen::VectorXd oscs = Eigen::VectorXd::Zero(0);
835 for (
Index state = 0;
841 level_summary.
add(
"omega",
842 (boost::format(
"%1$+1.6f ") %
843 (
orbitals_.BSEUKS().eigenvalues()(state) * hrt2ev))
847 const Index nosc =
static_cast<Index>(oscs.size());
849 if (has_dipoles && state < ndip && state < nosc) {
850 const Eigen::Vector3d& dipoles =
orbitals_.TransitionDipoles()[state];
852 level_summary.
add(
"f",
853 (boost::format(
"%1$+1.6f ") % oscs(state)).str());
856 "Trdipole", (boost::format(
"%1$+1.4f %2$+1.4f %3$+1.4f") %
857 dipoles.x() % dipoles.y() % dipoles.z())
879 if (
orbitals_.getXCFunctionalName().empty()) {
883 throw std::runtime_error(
"Functionals from DFT " +
884 orbitals_.getXCFunctionalName() +
" GWBSE " +
892 <<
TimeStamp() <<
" Setup grid for integration with gridsize: " <<
grid_
893 <<
" with " << grid.
getGridSize() <<
" points, divided into "
900 Eigen::MatrixXd DMAT =
orbitals_.DensityMatrixGroundState();
907 Eigen::MatrixXd mos =
910 Eigen::MatrixXd vxc = mos.transpose() * e_vxc_ao.
matrix() * mos;
912 <<
TimeStamp() <<
" Calculated exchange-correlation expectation values "
920 if (
orbitals_.getXCFunctionalName().empty()) {
923 throw std::runtime_error(
"Functionals from DFT " +
924 orbitals_.getXCFunctionalName() +
" GWBSE " +
933 auto dmats =
orbitals_.DensityMatrixGroundStateSpinResolved();
937 Eigen::MatrixXd mos_alpha =
939 Eigen::MatrixXd mos_beta =
942 Eigen::MatrixXd vxc_alpha =
943 mos_alpha.transpose() * e_vxc_ao.vxc_alpha * mos_alpha;
944 Eigen::MatrixXd vxc_beta =
945 mos_beta.transpose() * e_vxc_ao.vxc_beta * mos_beta;
947 return std::make_pair(vxc_alpha, vxc_beta);
960 <<
" Screening eigensolvers and inverses call "
961 "Accelerate LAPACK directly"
965 <<
TimeStamp() <<
" Molecule Coordinates [A] " << flush;
967 std::string output = (boost::format(
"%5d"
969 " %1.4f %1.4f %1.4f") %
970 atom.getId() % atom.getElement() %
979 std::string dft_package =
orbitals_.getQMpackage();
981 <<
TimeStamp() <<
" DFT data was created by " << dft_package << flush;
1004 <<
" size:" << frag.size() << flush;
1012 throw std::runtime_error(
1013 "You want no GW calculation but the orb file has no matching QP "
1017 const bool is_uks =
orbitals_.hasUnrestrictedOrbitals();
1028 <<
TimeStamp() <<
" Calculating alpha spin Mmn " << flush;
1031 <<
TimeStamp() <<
" Calculating beta spin Mmn " << flush;
1037 <<
TimeStamp() <<
" Calculating Mmn (3-center-repulsion x orbitals) "
1039 Mmn.
Fill(auxbasis, dftbasis,
orbitals_.MOs().eigenvectors());
1042 <<
" functions from Aux Coulomb matrix to avoid near linear "
1046 <<
TimeStamp() <<
" Calculated Mmn (3-center-repulsion x orbitals) "
1051 <<
TimeStamp() <<
" After Mmn: " << usage << flush;
1057 Eigen::MatrixXd reaction_field;
1060 throw std::runtime_error(
1061 "GWBSE: environment screening is implemented for closed-shell "
1064 std::chrono::time_point<std::chrono::system_clock> start =
1065 std::chrono::system_clock::now();
1066 Index n_explicit = 0;
1068 n_explicit += seg.
size();
1072 n_shell += seg.
size();
1075 <<
TimeStamp() <<
" Environment screening: " << n_explicit
1076 <<
" explicit Thole sites (exp_damp " <<
environment_.exp_damp <<
"), "
1077 << n_shell <<
" shell sites (epsilon " <<
environment_.shell_dielectric
1079 const Eigen::MatrixXd B =
1083 std::chrono::duration<double> elapsed_time =
1084 std::chrono::system_clock::now() - start;
1086 <<
TimeStamp() <<
" Built environment reaction field in "
1087 << elapsed_time.count() <<
" seconds." << flush;
1090 Eigen::MatrixXd Hqp;
1091 Eigen::MatrixXd Hqp_alpha;
1092 Eigen::MatrixXd Hqp_beta;
1095 std::chrono::time_point<std::chrono::system_clock> start =
1096 std::chrono::system_clock::now();
1099 throw std::runtime_error(
1100 "QSGW (gw.do_qsgw) is not implemented for open-shell (UKS) "
1156 auxbasis, dftbasis,
orbitals_.MOs().eigenvectors(),
1159 auxbasis, dftbasis,
orbitals_.MOs_beta().eigenvectors(),
1162 <<
TimeStamp() <<
" Sigma_x includes the exchange with the "
1163 <<
gwopt_.rpamin <<
" frozen core levels" << flush;
1173 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es_alpha =
1175 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es_beta =
1177 orbitals_.QPdiagAlpha().eigenvectors() = es_alpha.eigenvectors();
1178 orbitals_.QPdiagAlpha().eigenvalues() = es_alpha.eigenvalues();
1179 orbitals_.QPdiagBeta().eigenvectors() = es_beta.eigenvectors();
1180 orbitals_.QPdiagBeta().eigenvalues() = es_beta.eigenvalues();
1181 std::chrono::duration<double> elapsed_time =
1182 std::chrono::system_clock::now() - start;
1184 <<
TimeStamp() <<
" UKS GW calculation took " << elapsed_time.count()
1185 <<
" seconds." << flush;
1196 <<
TimeStamp() <<
" Sigma_x includes the exchange with the "
1197 <<
gwopt_.rpamin <<
" frozen core levels" << flush;
1211 <<
TimeStamp() <<
" Calculating offdiagonal part of Sigma " << flush;
1218 const std::string seed_label =
1219 (
gwopt_.gw_sc_max_iterations == 1) ?
"G0W0" :
"evGW";
1231 orbitals_.QPdiag().eigenvalues() = qsgw_energies;
1240 <<
TimeStamp() <<
" Rebuilding Mmn in QSGW QP wavefunction basis"
1244 <<
TimeStamp() <<
" Rebuilt Mmn (3-center-repulsion x QP orbitals)"
1246 Hqp = qsgw_energies.asDiagonal();
1251 <<
TimeStamp() <<
" Calculated offdiagonal part of Sigma "
1256 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es =
1258 if (es.info() == Eigen::ComputationInfo::Success) {
1260 <<
TimeStamp() <<
" Diagonalized QP Hamiltonian " << flush;
1263 orbitals_.QPdiag().eigenvectors() = es.eigenvectors();
1264 orbitals_.QPdiag().eigenvalues() = es.eigenvalues();
1266 std::chrono::duration<double> elapsed_time =
1267 std::chrono::system_clock::now() - start;
1269 <<
TimeStamp() <<
" GW calculation took " << elapsed_time.count()
1270 <<
" seconds." << flush;
1278 throw std::runtime_error(
1279 "The ranges for GW and RPA do not agree with the ranges from the "
1280 ".orb file, rerun your GW calculation");
1284 const Eigen::MatrixXd& qpcoeff_alpha =
1286 const Eigen::MatrixXd& qpcoeff_beta =
1289 Hqp_alpha = qpcoeff_alpha *
1290 orbitals_.QPdiagAlpha().eigenvalues().asDiagonal() *
1291 qpcoeff_alpha.transpose();
1292 Hqp_beta = qpcoeff_beta *
1293 orbitals_.QPdiagBeta().eigenvalues().asDiagonal() *
1294 qpcoeff_beta.transpose();
1300 <<
" Rebuilding Mmn in QSGW QP wavefunction basis (BSE-only)"
1304 <<
TimeStamp() <<
" Rebuilt Mmn (3-center-repulsion x QP orbitals)"
1306 Hqp =
orbitals_.QPdiag().eigenvalues().asDiagonal();
1308 const Eigen::MatrixXd& qpcoeff =
orbitals_.QPdiag().eigenvectors();
1310 Hqp = qpcoeff *
orbitals_.QPdiag().eigenvalues().asDiagonal() *
1311 qpcoeff.transpose();
1318 std::chrono::time_point<std::chrono::system_clock> start =
1319 std::chrono::system_clock::now();
1334 Eigen::VectorXd epsilon_0_inv_bse =
1335 Eigen::VectorXd::Zero(es_bse.
values.size());
1336 for (
Index i = 0; i < es_bse.
values.size(); ++i) {
1337 if (es_bse.
values(i) > 1
e-8) {
1338 epsilon_0_inv_bse(i) = 1.0 / es_bse.
values(i);
1365 Hqp_alpha, Hqp_beta, epsilon_0_inv_bse, es_bse.
vectors);
1369 <<
TimeStamp() <<
" Solved combined UKS BSE exciton problem "
1385 <<
TimeStamp() <<
" Solved BSE for triplets " << flush;
1392 <<
TimeStamp() <<
" Solved BSE for singlets " << flush;
1409 std::chrono::duration<double> elapsed_time =
1410 std::chrono::system_clock::now() - start;
1412 << elapsed_time.count() <<
" seconds." << flush;
1415 <<
TimeStamp() <<
" GWBSE calculation finished " << flush;
Container to hold Basisfunctions for all atoms.
Index AOBasisSize() const
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)
void Perturbative_DynamicalScreening(Orbitals &orb)
void Solve_excitons_uks(Orbitals &orb) const
void Analyze_excitons_uks(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
void setReactionField(const Eigen::MatrixXd &R, bool include_kreac)
Screen by a static polarizable environment (embedded BSE).
void Solve_singlets(Orbitals &orb) const
void Analyze_singlets(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
void Perturbative_DynamicalScreening(const QMStateType &type, Orbitals &orb)
void Analyze_triplets(std::vector< QMFragment< BSE_Population > > fragments, const Orbitals &orb) const
void configure(const options &opt, const Eigen::VectorXd &RPAEnergies, const Eigen::MatrixXd &Hqp_in)
void Solve_triplets(Orbitals &orb) const
void Load(const std::string &name)
void Load(const std::string &name)
const ECPElement & getElement(std::string element_type) const
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,...
std::pair< Eigen::MatrixXd, Eigen::MatrixXd > CalculateVXCSpinResolved(const AOBasis &dftbasis)
std::vector< QMFragment< BSE_Population > > fragments_
std::string sigma_plot_states_
ScreeningEnvironment environment_
void addoutput(tools::Property &summary)
std::string auxbasis_name_
Eigen::MatrixXd CalculateVXC(const AOBasis &dftbasis)
std::string dftbasis_name_
void Initialize(tools::Property &options)
double sigma_plot_spacing_
std::string sigma_plot_filename_
bool do_dynamical_screening_bse_
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonianAlpha() const
Eigen::VectorXd getGWAResultsAlpha() const
const Eigen::VectorXd & RPAInputEnergiesAlpha() const
const Eigen::VectorXd & RPAInputEnergiesBeta() const
Eigen::MatrixXd getHQPBeta() const
Eigen::VectorXd getGWAResultsBeta() const
Eigen::MatrixXd getHQPAlpha() const
void setCoreExchange(const Eigen::MatrixXd &alpha, const Eigen::MatrixXd &beta)
Frozen-core exchange per spin, see GW::setCoreExchange.
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonianBeta() const
void configure(const options &opt)
void CalculateGWPerturbation()
void PlotSigma(std::string filename, Index steps, double spacing, std::string states) const
const Eigen::VectorXd & getQSGWSeedEnergies() const
Return the seed (G0W0/evGW) energies that QSGW started from.
void setReactionField(const Eigen::MatrixXd &R)
Screen by a static polarizable environment (embedded GW).
Eigen::SelfAdjointEigenSolver< Eigen::MatrixXd > DiagonalizeQPHamiltonian() const
void setCoreExchange(const Eigen::MatrixXd &X)
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.
void CalculateQSGW()
Run quasiparticle self-consistent GW (QSGW).
void configure(const options &opt)
Eigen::MatrixXd getHQP() const
void PrintQSGW_Composition(double threshold=0.01) const
Print the dominant DFT-KS orbital contributions to each converged QSGW quasiparticle state.
Eigen::VectorXd getGWAResults() const
Eigen::VectorXd RPAInputEnergies() const
const Eigen::MatrixXd & getQSGWRotation() const
void CalculateGWPerturbation()
Eigen::MatrixXd & matrix()
static std::string Usage()
Unrestricted RPA helper for spin-resolved GW screening.
void setRPAInputEnergies(const Eigen::VectorXd &rpaenergies_alpha, const Eigen::VectorXd &rpaenergies_beta)
Set alpha and beta RPA input energies directly.
void configure(Index homo_alpha, Index homo_beta, Index rpamin, Index rpamax)
Eigen::MatrixXd calculate_epsilon_r(double frequency) const
Dielectric matrix on the real frequency axis.
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
Timestamp returns the current time as a string Example: cout << TimeStamp().
Index getGridSize() const
void GridSetup(const std::string &type, const QMMolecule &atoms, const AOBasis &basis)
Index getBoxesSize() const
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)
bool LapackAvailable()
Whether the routines below can run here (Accelerate build, macOS 13.3+).
double LegacyAdaptiveShellWidth(const Opt &opt)
void NormalizeGridSearchOptions(Opt &opt)
double LegacyFullWindowHalfWidth(const Opt &opt)
Charge transport classes.
SymmetricEigenSystem SymmetricEigen(const Eigen::MatrixXd &A, bool vectors=true)
With vectors = false only the eigenvalues are computed.
ClassicalSegment< PolarSite > PolarSegment
std::string EigenBackendDescription()
Provides a means for comparing floating point numbers.
std::string davidson_update
std::string davidson_tolerance
std::string davidson_correction
Index qp_adaptive_shell_count
std::string screening_update
double qp_virtual_min_energy
double screening_update_ratio
std::string quadrature_scheme
OutOfWindowShift out_of_window_shift
Index screening_update_max_inner
double qp_full_window_half_width
std::string qp_grid_search_mode
std::string sigma_integration
Index g_sc_max_iterations
std::string qp_root_finder
Index gw_sc_max_iterations
double qp_adaptive_shell_width
static Mode Parse(const std::string &name)
static std::string Name(Mode mode)