23#include <boost/algorithm/string.hpp>
24#include <boost/format.hpp>
52 Index ignored_corelevels = 0;
55 basis.
Load(
"corelevels");
56 Index coreElectrons = 0;
57 for (
const auto& atom :
orbitals_.QMAtoms()) {
60 ignored_corelevels = coreElectrons / 2;
62 return ignored_corelevels;
75 const bool is_uks =
orbitals_.hasUnrestrictedOrbitals();
83 num_of_occlevels = std::max(
orbitals_.getNumberOfAlphaElectrons(),
87 std::string ranges = options.
get(
".ranges").
as<std::string>();
91 if (ranges ==
"factor") {
93 double rpamaxfactor = options.
get(
".rpamax").
as<
double>();
94 rpamax =
Index(rpamaxfactor *
double(num_of_levels)) -
97 double qpminfactor = options.
get(
".qpmin").
as<
double>();
99 num_of_occlevels -
Index(qpminfactor *
double(num_of_occlevels)) - 1;
101 double qpmaxfactor = options.
get(
".qpmax").
as<
double>();
103 num_of_occlevels +
Index(qpmaxfactor *
double(num_of_occlevels)) - 1;
105 double bseminfactor = options.
get(
".bsemin").
as<
double>();
107 num_of_occlevels -
Index(bseminfactor *
double(num_of_occlevels)) - 1;
109 double bsemaxfactor = options.
get(
".bsemax").
as<
double>();
111 num_of_occlevels +
Index(bsemaxfactor *
double(num_of_occlevels)) - 1;
113 }
else if (ranges ==
"explicit") {
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;
123 qpmax = 3 * homo + 1;
125 bse_cmax = 3 * homo + 1;
126 }
else if (ranges ==
"full") {
127 rpamax = num_of_levels - 1;
129 qpmax = num_of_levels - 1;
131 bse_cmax = num_of_levels - 1;
133 std::string ignore_corelevels =
134 options.
get(
".ignore_corelevels").
as<std::string>();
136 if (ignore_corelevels ==
"RPA" || ignore_corelevels ==
"GW" ||
137 ignore_corelevels ==
"BSE") {
139 if (ignore_corelevels ==
"RPA") {
140 rpamin = ignored_corelevels;
142 if (ignore_corelevels ==
"GW" || ignore_corelevels ==
"RPA") {
143 if (qpmin < ignored_corelevels) {
144 qpmin = ignored_corelevels;
147 if (ignore_corelevels ==
"GW" || ignore_corelevels ==
"RPA" ||
148 ignore_corelevels ==
"BSE") {
149 if (bse_vmin < ignored_corelevels) {
150 bse_vmin = ignored_corelevels;
155 <<
TimeStamp() <<
" Ignoring " << ignored_corelevels
156 <<
" core levels for " << ignore_corelevels <<
" and beyond." << flush;
160 if (rpamax >= num_of_levels) {
161 rpamax = num_of_levels - 1;
163 if (qpmax >= num_of_levels) {
164 qpmax = num_of_levels - 1;
166 if (bse_cmax >= num_of_levels) {
167 bse_cmax = num_of_levels - 1;
176 Index bse_vmax = homo;
177 Index bse_cmin = homo + 1;
183 const double qp_emax =
185 const double qp_emin =
187 const double bse_emax =
189 const double bse_emin =
191 std::vector<const Eigen::VectorXd*> spins{&
orbitals_.MOs().eigenvalues()};
192 std::vector<Index> homos{is_uks ?
orbitals_.getHomoAlpha() : homo};
194 spins.push_back(&
orbitals_.MOs_beta().eigenvalues());
195 homos.push_back(
orbitals_.getHomoBeta());
198 constexpr double degenerate = 5
e-4;
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];
205 Index i = homos[s] + 1;
206 while (i + 1 <
e.size() &&
e(i + 1) <= limit) {
209 const double edge =
e(i);
210 while (i + 1 <
e.size() &&
e(i + 1) - edge < degenerate) {
213 last = std::max(last, i);
218 auto lower = [&](
double cap_ev) {
220 for (std::size_t s = 0; s < spins.size(); ++s) {
221 const Eigen::VectorXd&
e = *spins[s];
224 while (i - 1 >= 0 &&
e(i - 1) >= limit) {
227 const double edge =
e(i);
228 while (i - 1 >= 0 && edge -
e(i - 1) < degenerate) {
231 first = std::min(first, i);
235 auto report = [&](
const std::string& what,
const std::string& option,
238 <<
TimeStamp() <<
" " << what <<
" capped by " << option <<
" = "
239 << cap <<
" eV: " << before <<
" -> " << after <<
" ("
240 << std::abs(before - after) <<
" levels removed)" << flush;
243 const Index cap = std::min(qpmax, upper(qp_emax));
244 report(
"GW window top",
"qp_emax", qp_emax, qpmax, cap);
248 const Index cap = std::max(qpmin, lower(qp_emin));
249 report(
"GW window bottom",
"qp_emin", qp_emin, qpmin, cap);
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);
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);
264 if (rpamin < 0 || rpamax < 0 || rpamin > rpamax) {
265 throw std::runtime_error(
"Invalid RPA level range after setup/clamping.");
267 if (qpmin < 0 || qpmax < 0 || qpmin > qpmax) {
268 throw std::runtime_error(
"Invalid GW level range after setup/clamping.");
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.");
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.");
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.");
282 if (bse_vmax >= bse_cmin) {
283 throw std::runtime_error(
"BSE occupied and virtual level ranges overlap.");
302 orbitals_.setBSEindices(bse_vmin, bse_cmax);
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;
311 <<
":" << rpamax <<
"]" << flush;
313 <<
":" << qpmax <<
"]" << flush;
315 <<
TimeStamp() <<
" BSE level range occ[" << bse_vmin <<
":" << bse_vmax
316 <<
"] virt[" << bse_cmin <<
":" << bse_cmax <<
"]" << flush;
326 options.
get(
"bse.davidson.correction").
as<std::string>();
329 options.
get(
"bse.davidson.tolerance").
as<std::string>();
332 options.
get(
"bse.davidson.update").
as<std::string>();
344 Index full_bse_size = (
bseopt_.useTDA) ? bse_size : 2 * bse_size;
346 << full_bse_size <<
"x" << full_bse_size << flush;
348 bseopt_.use_Hqp_offdiag = options.
get(
"bse.use_Hqp_offdiag").
as<
bool>();
351 if (!
bseopt_.use_Hqp_offdiag) {
353 <<
" BSE without Hqp offdiagonal elements" << flush;
356 <<
" BSE with Hqp offdiagonal elements" << flush;
360 bseopt_.dyn_tolerance = options.
get(
"bse.dyn_screen_tol").
as<
double>();
361 if (
bseopt_.max_dyn_iter > 0) {
371 }
else if (options.
exists(
".auxbasisset")) {
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 "
389 std::string mode = options.
get(
"gw.mode").
as<std::string>();
390 if (mode ==
"G0W0") {
391 gwopt_.gw_sc_max_iterations = 1;
397 gwopt_.shift = options.
get(
"gw.scissor_shift").
as<
double>();
399 options.
get(
"gw.qp_sc_limit").
as<
double>();
402 gwopt_.g_sc_max_iterations =
408 if (mode ==
"evGW") {
413 options.
get(
"gw.sc_limit").
as<
double>();
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;
421 bseopt_.min_print_weight = options.
get(
"bse.print_weight").
as<
double>();
425 std::string tasks_string = options.
get(
".tasks").
as<std::string>();
426 boost::algorithm::to_lower(tasks_string);
428 if (tasks_string.find(
"gw") != std::string::npos) {
433 if (tasks_string.find(
"excitons") != std::string::npos ||
434 tasks_string.find(
"exciton_uks") != std::string::npos) {
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.");
447 if (tasks_string.find(
"all") != std::string::npos) {
457 if (tasks_string.find(
"singlets") != std::string::npos) {
460 if (tasks_string.find(
"triplets") != std::string::npos) {
479 if (options.
exists(
"bse.fragments")) {
480 std::vector<tools::Property*> prop_region =
481 options.
Select(
"bse.fragments.fragment");
484 std::string indices = prop->get(
"indices").as<std::string>();
490 gwopt_.sigma_integration =
491 options.
get(
"gw.sigma_integrator").
as<std::string>();
493 <<
" Sigma integration: " <<
gwopt_.sigma_integration << flush;
496 if (
gwopt_.sigma_integration ==
"exact") {
498 <<
" RPA Hamiltonian size: " << (homo + 1 - rpamin) * (rpamax - homo)
501 if (
gwopt_.sigma_integration ==
"cda") {
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
510 gwopt_.alpha = options.
get(
"gw.alpha").
as<
double>();
512 <<
" Alpha smoothing parameter : " <<
gwopt_.alpha << flush;
514 gwopt_.qp_solver = options.
get(
"gw.qp_solver").
as<std::string>();
517 if (
gwopt_.qp_solver ==
"grid") {
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>();
530 if (options.
exists(
"gw.qp_dense_spacing")) {
531 gwopt_.qp_dense_spacing = options.
get(
"gw.qp_dense_spacing").
as<
double>();
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>();
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>();
544 const bool has_legacy_steps = options.
exists(
"gw.qp_grid_steps");
545 const bool has_legacy_spacing = options.
exists(
"gw.qp_grid_spacing");
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.");
553 if (has_legacy_steps && has_legacy_spacing) {
555 gwopt_.qp_grid_spacing = options.
get(
"gw.qp_grid_spacing").
as<
double>();
557 const double legacy_half_width =
559 const double legacy_shell_width =
562 if (
gwopt_.qp_full_window_half_width <= 0.0) {
563 gwopt_.qp_full_window_half_width = legacy_half_width;
565 if (
gwopt_.qp_dense_spacing <= 0.0) {
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;
574 <<
" Deprecated GW QP options detected: " <<
"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
589 <<
" QP full window half-width: " <<
gwopt_.qp_full_window_half_width
592 <<
" QP dense spacing: " <<
gwopt_.qp_dense_spacing << flush;
594 <<
" QP adaptive shell width: " <<
gwopt_.qp_adaptive_shell_width
597 <<
" QP adaptive shell count: " <<
gwopt_.qp_adaptive_shell_count
600 gwopt_.qp_root_finder = options.
get(
"gw.qp_root_finder").
as<std::string>();
602 <<
" QP root finder: " <<
gwopt_.qp_root_finder << flush;
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>();
615 "gw.qp_root_continuity",
true);
617 "gw.qp_root_tracking",
false);
622 "gw.screening_update",
"adaptive");
624 gwopt_.screening_update_ratio =
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>();
638 "gw.qsgw_max_iterations", 50);
641 gwopt_.qsgw_max_virt_correction =
643 "gw.qsgw_max_virt_correction", 0.5);
645 "gw.qsgw_hartree_update",
true);
647 "gw.qsgw_hartree_screened",
true);
648 gwopt_.qsgw_regularization =
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);
658 if (!(
gwopt_.qsgw_srg_s > 0.0)) {
659 throw std::runtime_error(
"gw.qsgw_srg_s must be positive");
663 "gw.out_of_window_shift",
"max"));
664 gwopt_.out_of_window_shift.fit_fraction =
666 "gw.out_of_window_fit_fraction", 0.3);
669 <<
" Levels outside the GW window shifted by: "
672 ?
" (fit fraction " +
673 std::to_string(
gwopt_.out_of_window_shift.fit_fraction) +
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;
686 if (mode ==
"evGW") {
687 if (
gwopt_.gw_mixing_order == 0) {
689 }
else if (
gwopt_.gw_mixing_order == 1) {
691 <<
gwopt_.gw_mixing_alpha << std::flush;
694 <<
gwopt_.gw_mixing_order <<
" using alpha "
695 <<
gwopt_.gw_mixing_alpha << std::flush;
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)"
705 <<
" evGW screening update: every iteration" << std::flush;
709 if (options.
exists(
"gw.sigma_plot")) {
714 options.
get(
"gw.sigma_plot.filename").
as<std::string>();
726 if (options.
exists(
"gw.sigma_dump")) {
728 throw std::runtime_error(
"gw.sigma_dump is not implemented for UKS");
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");
736 throw std::runtime_error(
"gw.sigma_dump is not implemented for QSGW");
740 options.
get(
"gw.sigma_dump.filename").
as<std::string>();
742 options.
get(
"gw.sigma_dump.levels_emax").
as<
double>();
744 options.
get(
"gw.sigma_dump.imag_points").
as<
Index>();
746 options.
get(
"gw.sigma_dump.imag_scale").
as<
double>();
748 options.
get(
"gw.sigma_dump.spectral_min").
as<
double>();
750 options.
get(
"gw.sigma_dump.spectral_max").
as<
double>();
752 options.
get(
"gw.sigma_dump.spectral_binwidth").
as<
double>();
754 options.
get(
"gw.sigma_dump.plot_steps").
as<
Index>();
756 options.
get(
"gw.sigma_dump.plot_spacing").
as<
double>();
770 (boost::format(
"%1$+1.6f ") % (
orbitals_.getDFTTotalEnergy() * hrt2ev))
773 if (
orbitals_.hasUnrestrictedOrbitals()) {
774 gwbse_summary.
add(
"dft_alpha",
"");
775 gwbse_summary.
add(
"dft_beta",
"");
789 (boost::format(
"%1$+1.6f ") %
792 level_alpha.
add(
"gw_energy",
793 (boost::format(
"%1$+1.6f ") %
794 (
orbitals_.QPpertEnergiesAlpha()(state) * hrt2ev))
798 (boost::format(
"%1$+1.6f ") %
799 (
orbitals_.QPdiagAlpha().eigenvalues()(state) * hrt2ev))
806 (boost::format(
"%1$+1.6f ") %
810 level_beta.
add(
"gw_energy",
811 (boost::format(
"%1$+1.6f ") %
812 (
orbitals_.QPpertEnergiesBeta()(state) * hrt2ev))
814 level_beta.
add(
"qp_energy",
815 (boost::format(
"%1$+1.6f ") %
816 (
orbitals_.QPdiagBeta().eigenvalues()(state) * hrt2ev))
829 (boost::format(
"%1$+1.6f ") %
832 level_summary.
add(
"gw_energy",
833 (boost::format(
"%1$+1.6f ") %
834 (
orbitals_.QPpertEnergies()(state) * hrt2ev))
836 level_summary.
add(
"qp_energy",
837 (boost::format(
"%1$+1.6f ") %
838 (
orbitals_.QPdiag().eigenvalues()(state) * hrt2ev))
849 "omega", (boost::format(
"%1$+1.6f ") %
850 (
orbitals_.BSESinglets().eigenvalues()(state) * hrt2ev))
854 const Eigen::Vector3d& dipoles = (
orbitals_.TransitionDipoles())[state];
855 double f = 2 * dipoles.squaredNorm() *
856 orbitals_.BSESinglets().eigenvalues()(state) / 3.0;
858 level_summary.
add(
"f", (boost::format(
"%1$+1.6f ") % f).str());
860 "Trdipole", (boost::format(
"%1$+1.4f %2$+1.4f %3$+1.4f") %
861 dipoles.x() % dipoles.y() % dipoles.z())
874 "omega", (boost::format(
"%1$+1.6f ") %
875 (
orbitals_.BSETriplets().eigenvalues()(state) * hrt2ev))
882 const bool has_dipoles =
orbitals_.hasTransitionDipoles();
883 Eigen::VectorXd oscs = Eigen::VectorXd::Zero(0);
889 for (
Index state = 0;
895 level_summary.
add(
"omega",
896 (boost::format(
"%1$+1.6f ") %
897 (
orbitals_.BSEUKS().eigenvalues()(state) * hrt2ev))
901 const Index nosc =
static_cast<Index>(oscs.size());
903 if (has_dipoles && state < ndip && state < nosc) {
904 const Eigen::Vector3d& dipoles =
orbitals_.TransitionDipoles()[state];
906 level_summary.
add(
"f",
907 (boost::format(
"%1$+1.6f ") % oscs(state)).str());
910 "Trdipole", (boost::format(
"%1$+1.4f %2$+1.4f %3$+1.4f") %
911 dipoles.x() % dipoles.y() % dipoles.z())
933 if (
orbitals_.getXCFunctionalName().empty()) {
937 throw std::runtime_error(
"Functionals from DFT " +
938 orbitals_.getXCFunctionalName() +
" GWBSE " +
946 <<
TimeStamp() <<
" Setup grid for integration with gridsize: " <<
grid_
947 <<
" with " << grid.
getGridSize() <<
" points, divided into "
954 Eigen::MatrixXd DMAT =
orbitals_.DensityMatrixGroundState();
961 Eigen::MatrixXd mos =
964 Eigen::MatrixXd vxc = mos.transpose() * e_vxc_ao.
matrix() * mos;
966 <<
TimeStamp() <<
" Calculated exchange-correlation expectation values "
974 if (
orbitals_.getXCFunctionalName().empty()) {
977 throw std::runtime_error(
"Functionals from DFT " +
978 orbitals_.getXCFunctionalName() +
" GWBSE " +
987 auto dmats =
orbitals_.DensityMatrixGroundStateSpinResolved();
991 Eigen::MatrixXd mos_alpha =
993 Eigen::MatrixXd mos_beta =
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;
1001 return std::make_pair(vxc_alpha, vxc_beta);
1019 <<
" Screening eigensolvers and inverses call "
1020 "Accelerate LAPACK directly"
1024 <<
TimeStamp() <<
" Molecule Coordinates [A] " << flush;
1026 std::string output = (boost::format(
"%5d"
1028 " %1.4f %1.4f %1.4f") %
1029 atom.getId() % atom.getElement() %
1038 std::string dft_package =
orbitals_.getQMpackage();
1040 <<
TimeStamp() <<
" DFT data was created by " << dft_package << flush;
1063 <<
" size:" << frag.size() << flush;
1071 throw std::runtime_error(
1072 "You want no GW calculation but the orb file has no matching QP "
1076 const bool is_uks =
orbitals_.hasUnrestrictedOrbitals();
1087 <<
TimeStamp() <<
" Calculating alpha spin Mmn " << flush;
1090 <<
TimeStamp() <<
" Calculating beta spin Mmn " << flush;
1096 <<
TimeStamp() <<
" Calculating Mmn (3-center-repulsion x orbitals) "
1098 Mmn.
Fill(auxbasis, dftbasis,
orbitals_.MOs().eigenvectors());
1101 <<
" functions from Aux Coulomb matrix to avoid near linear "
1105 <<
TimeStamp() <<
" Calculated Mmn (3-center-repulsion x orbitals) "
1110 <<
TimeStamp() <<
" After Mmn: " << usage << flush;
1116 Eigen::MatrixXd reaction_field;
1119 throw std::runtime_error(
1120 "GWBSE: environment screening is implemented for closed-shell "
1123 std::chrono::time_point<std::chrono::system_clock> start =
1124 std::chrono::system_clock::now();
1125 Index n_explicit = 0;
1127 n_explicit += seg.
size();
1131 n_shell += seg.
size();
1134 <<
TimeStamp() <<
" Environment screening: " << n_explicit
1135 <<
" explicit Thole sites (exp_damp " <<
environment_.exp_damp <<
"), "
1136 << n_shell <<
" shell sites (epsilon " <<
environment_.shell_dielectric
1138 const Eigen::MatrixXd B =
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;
1149 Eigen::MatrixXd Hqp;
1150 Eigen::MatrixXd Hqp_alpha;
1151 Eigen::MatrixXd Hqp_beta;
1154 std::chrono::time_point<std::chrono::system_clock> start =
1155 std::chrono::system_clock::now();
1158 throw std::runtime_error(
1159 "QSGW (gw.do_qsgw) is not implemented for open-shell (UKS) "
1215 auxbasis, dftbasis,
orbitals_.MOs().eigenvectors(),
1218 auxbasis, dftbasis,
orbitals_.MOs_beta().eigenvectors(),
1221 <<
TimeStamp() <<
" Sigma_x includes the exchange with the "
1222 <<
gwopt_.rpamin <<
" frozen core levels" << flush;
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;
1256 <<
TimeStamp() <<
" Sigma_x includes the exchange with the "
1257 <<
gwopt_.rpamin <<
" frozen core levels" << flush;
1271 <<
TimeStamp() <<
" Calculating offdiagonal part of Sigma " << flush;
1278 const std::string seed_label =
1279 (
gwopt_.gw_sc_max_iterations == 1) ?
"G0W0" :
"evGW";
1291 orbitals_.QPdiag().eigenvalues() = qsgw_energies;
1300 <<
TimeStamp() <<
" Rebuilding Mmn in QSGW QP wavefunction basis"
1304 <<
TimeStamp() <<
" Rebuilt Mmn (3-center-repulsion x QP orbitals)"
1306 Hqp = qsgw_energies.asDiagonal();
1311 <<
TimeStamp() <<
" Calculated offdiagonal part of Sigma "
1318 (
gwopt_.gw_sc_max_iterations > 1) ?
"evGW" :
"G0W0",
1322 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es =
1324 if (es.info() == Eigen::ComputationInfo::Success) {
1326 <<
TimeStamp() <<
" Diagonalized QP Hamiltonian " << flush;
1329 orbitals_.QPdiag().eigenvectors() = es.eigenvectors();
1330 orbitals_.QPdiag().eigenvalues() = es.eigenvalues();
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;
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");
1350 const Eigen::MatrixXd& qpcoeff_alpha =
1352 const Eigen::MatrixXd& qpcoeff_beta =
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();
1366 <<
" Rebuilding Mmn in QSGW QP wavefunction basis (BSE-only)"
1370 <<
TimeStamp() <<
" Rebuilt Mmn (3-center-repulsion x QP orbitals)"
1372 Hqp =
orbitals_.QPdiag().eigenvalues().asDiagonal();
1374 const Eigen::MatrixXd& qpcoeff =
orbitals_.QPdiag().eigenvectors();
1376 Hqp = qpcoeff *
orbitals_.QPdiag().eigenvalues().asDiagonal() *
1377 qpcoeff.transpose();
1384 std::chrono::time_point<std::chrono::system_clock> start =
1385 std::chrono::system_clock::now();
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) > 1
e-8) {
1404 epsilon_0_inv_bse(i) = 1.0 / es_bse.
values(i);
1431 Hqp_alpha, Hqp_beta, epsilon_0_inv_bse, es_bse.
vectors);
1435 <<
TimeStamp() <<
" Solved combined UKS BSE exciton problem "
1451 <<
TimeStamp() <<
" Solved BSE for triplets " << flush;
1458 <<
TimeStamp() <<
" Solved BSE for singlets " << flush;
1475 std::chrono::duration<double> elapsed_time =
1476 std::chrono::system_clock::now() - start;
1478 << elapsed_time.count() <<
" seconds." << flush;
1482 <<
TimeStamp() <<
" End of GWBSE: " << usage << flush;
1485 <<
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)
GW::sigma_dump_options sigma_dump_opt_
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()
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 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...
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 setKeepScreeningData(bool keep)
Call after configure and before CalculateGWPerturbation.
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 PlotSigma(std::string filename, Index steps, double spacing, std::string states)
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+).
void Cite(const std::string &key)
marks a reference as used (thread safe; unknown keys are printed as such)
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)