votca 2026-dev
Loading...
Searching...
No Matches
sigma_cda_uks.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2026 The VOTCA Development Team
3 * (http://www.votca.org)
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License")
6 *
7 * You may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20#include "sigma_cda_uks.h"
21#include "votca/xtp/gw.h"
22
23#include <algorithm>
24#include <iostream>
25#include <limits>
26
27namespace votca {
28namespace xtp {
29
30namespace {
31
32constexpr double kResidueFactorTol = 1e-10;
33constexpr double kCdaWarnMinDelta = 1e-4; // Ha
34constexpr double kCdaWarnKappa = 1e3;
35constexpr double kTiny = 1e-14;
36
37const char* SpinName(TCMatrix::SpinChannel spin) {
38 return (spin == TCMatrix::SpinChannel::Alpha) ? "alpha" : "beta";
39}
40
41} // namespace
42
45 opt.homo = opt_.homo;
46 opt.order = opt_.order;
47 opt.qptotal = qptotal_;
48 opt.qpmin = opt_.qpmin;
49 opt.rpamax = opt_.rpamax;
50 opt.rpamin = opt_.rpamin;
51 opt.alpha = opt_.alpha;
52 opt.quadrature_scheme = opt_.quadrature_scheme;
53
54 // epsilon at zero frequency is positive definite
56 InverseSPD(rpa_.calculate_epsilon_r(std::complex<double>(0.0, 0.0)));
57 kDielMxInv_zero_.diagonal().array() -= 1.0;
58 gq_.configure(opt, rpa_, kDielMxInv_zero_);
59
60 tail_terms_.assign(std::size_t(qptotal_), Eigen::VectorXd());
61 const Index offset = opt_.qpmin - opt_.rpamin;
62#pragma omp parallel for schedule(dynamic)
63 for (Index level = 0; level < qptotal_; level++) {
64 tail_terms_[std::size_t(level)] =
67 }
68}
69
71 const Eigen::MatrixXd::ConstRowXpr& Imx_row, double delta,
72 double eta) const {
73 std::complex<double> delta_eta(delta, eta);
74
75 Eigen::MatrixXd DielMxInv = rpa_.calculate_epsilon_r(delta_eta);
76 Eigen::VectorXd x =
77 DielMxInv.partialPivLu().solve(Imx_row.transpose()) - Imx_row.transpose();
78
79 return x.dot(Imx_row.transpose());
80}
81
82double Sigma_CDA_UKS::CalcResiduePrefactor(double e_f, double e_m,
83 double frequency) const {
84 double factor = 0.0;
85 double tolerance = 1e-10;
86 if (e_f < e_m && e_m < frequency) {
87 factor = 1.0;
88 } else if (e_f > e_m && e_m > frequency) {
89 factor = -1.0;
90 } else if (std::abs(e_m - frequency) < tolerance && e_f > e_m) {
91 factor = -0.5;
92 } else if (std::abs(e_m - frequency) < tolerance && e_f < e_m) {
93 factor = 0.5;
94 }
95 return factor;
96}
97
99 Index gw_level) const {
100 const Eigen::VectorXd& rpa_energies = getSpinRPAInputEnergies();
101 Index rpatotal = rpa_energies.size();
102 Index gw_level_offset = gw_level + opt_.qpmin - opt_.rpamin;
103
104 double sigma_c = 0.0;
105 double sigma_c_tail = 0.0;
106 Index homo = opt_.homo - opt_.rpamin;
107 Index lumo = homo + 1;
108 double fermi_rpa = (rpa_energies(lumo) + rpa_energies(homo)) / 2.0;
109
110 double min_abs_delta = std::numeric_limits<double>::infinity();
111 double sum_abs_contributions = 0.0;
112 double sum_signed_contributions = 0.0;
113
114 const Eigen::MatrixXd& Imx = Mmn_[gw_level_offset];
115
116 for (Index i = 0; i < rpatotal; ++i) {
117 double delta = rpa_energies(i) - frequency;
118 double abs_delta = std::abs(delta);
119 min_abs_delta = std::min(min_abs_delta, abs_delta);
120
121 double factor = CalcResiduePrefactor(fermi_rpa, rpa_energies(i), frequency);
122
123 if (std::abs(factor) > kResidueFactorTol) {
124 double diag = CalcDiagContribution(Imx.row(i), abs_delta, rpa_.getEta());
125 double contribution = factor * diag;
126 sigma_c += contribution;
127
128 sum_abs_contributions += std::abs(contribution);
129 sum_signed_contributions += contribution;
130 }
131
132 if (abs_delta > kResidueFactorTol) {
133 double tail = CalcDiagContributionValue_tail(
134 tail_terms_[std::size_t(gw_level)](i), delta, opt_.alpha);
135 sigma_c_tail += tail;
136 }
137 }
138
139 double kappa =
140 sum_abs_contributions / (std::abs(sum_signed_contributions) + kTiny);
141
142 if (min_abs_delta < kCdaWarnMinDelta || kappa > kCdaWarnKappa) {
143 std::cout << "\nWarning: CDA may be unreliable for " << SpinName(spin_)
144 << " GW level " << (gw_level + opt_.qpmin)
145 << " at omega = " << frequency
146 << " Ha: min |e_m - omega| = " << min_abs_delta
147 << " Ha, cancellation metric = " << kappa << std::flush;
148 }
149
150 return sigma_c + sigma_c_tail;
151}
152
154 double frequency) const {
155 double sigma_c_residue = CalcResidueContribution(frequency, gw_level);
156 double sigma_c_integral = gq_.SigmaGQDiag(frequency, gw_level, rpa_.getEta());
157 return sigma_c_residue + sigma_c_integral;
158}
159
161 double delta,
162 double alpha) const {
163 double erfc_factor = 0.5 * std::copysign(1.0, delta) *
164 std::exp(std::pow(alpha * delta, 2)) *
165 std::erfc(std::abs(alpha * delta));
166
167 return row_term * erfc_factor;
168}
169
170} // namespace xtp
171} // namespace votca
static Eigen::VectorXd RowQuadraticForms(const Eigen::MatrixXd &M, const Eigen::MatrixXd &K)
q(i) = M.row(i) K M.row(i)^T for all rows of M.
double CalcCorrelationDiagElement(Index gw_level, double frequency) const final
double CalcResiduePrefactor(double e_f, double e_m, double frequency) const
double CalcResidueContribution(double frequency, Index gw_level) const
ImaginaryAxisIntegration gq_
Eigen::MatrixXd kDielMxInv_zero_
std::vector< Eigen::VectorXd > tail_terms_
double CalcDiagContribution(const Eigen::MatrixXd::ConstRowXpr &Imx_row, double delta, double eta) const
double CalcDiagContributionValue_tail(double row_term, double delta, double alpha) const
const Eigen::VectorXd & getSpinRPAInputEnergies() const
TCMatrix::SpinChannel spin_
Charge transport classes.
Definition ERIs.h:28
Eigen::MatrixXd InverseSPD(const Eigen::MatrixXd &A)
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26