votca 2026-dev
Loading...
Searching...
No Matches
ImaginaryAxisIntegration.cc
Go to the documentation of this file.
1
2/*
3 * Copyright 2009-2023 The VOTCA Development Team
4 * (http://www.votca.org)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License")
7 *
8 * You may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */
20
22
23#include <algorithm>
24#include <cstdlib>
25#include <limits>
26#include <set>
27#include <sstream>
28
33
34namespace votca {
35namespace xtp {
36
37namespace {
38
39bool CdaDebugEnabled() {
40 const char* env = std::getenv("VOTCA_XTP_CDA_DEBUG");
41 return env != nullptr && std::string(env) == "1";
42}
43
44bool CdaDebugLevelMatch(Index level) {
45 const char* env = std::getenv("VOTCA_XTP_CDA_DEBUG_LEVELS");
46 if (env == nullptr) {
47 return true;
48 }
49
50 std::set<int> allowed;
51 std::stringstream ss(env);
52 std::string token;
53 while (std::getline(ss, token, ',')) {
54 if (!token.empty()) {
55 allowed.insert(std::stoi(token));
56 }
57 }
58 return allowed.count(static_cast<int>(level)) > 0;
59}
60
61bool CdaDebugMatch(Index level) {
62 return CdaDebugEnabled() && CdaDebugLevelMatch(level);
63}
64
65} // namespace
66
68 const Eigen::VectorXd& energies, const TCMatrix_gwbse& Mmn)
69 : energies_(energies), Mmn_(Mmn) {}
70
72 options opt, const RPA& rpa, const Eigen::MatrixXd& kDielMxInv_zero) {
73 opt_ = opt;
74 gq_ = QuadratureFactory().Create(opt_.quadrature_scheme);
75 gq_->configure(opt_.order);
76
77 CalcDielInvVector(rpa, kDielMxInv_zero);
78}
79
81 options opt, const RPA_UKS& rpa, const Eigen::MatrixXd& kDielMxInv_zero) {
82 opt_ = opt;
83 gq_ = QuadratureFactory().Create(opt_.quadrature_scheme);
84 gq_->configure(opt_.order);
85
86 CalcDielInvVector(rpa, kDielMxInv_zero);
87}
88
90 const Eigen::MatrixXd& M, const Eigen::MatrixXd& K) {
91 return (M * K).cwiseProduct(M).rowwise().sum();
92}
93
94// The inverse microscopic dielectric matrix at every quadrature node, with
95// the Gaussian tail of the zero-frequency one subtracted, enters only as
96// Imx W_j Imx^T diagonals (see CalcNodeTerms).
97template <class RPAType>
99 const RPAType& rpa, const Eigen::MatrixXd& kDielMxInv_zero) {
100 std::vector<Eigen::MatrixXd> dielinv_matrices(std::size_t(gq_->Order()));
101 for (Index j = 0; j < gq_->Order(); j++) {
102 double newpoint = gq_->ScaledPoint(j);
103 Eigen::MatrixXd eps_inv_j = InverseSPD(rpa.calculate_epsilon_i(newpoint));
104 eps_inv_j.diagonal().array() -= 1.0;
105 dielinv_matrices[std::size_t(j)] =
106 -eps_inv_j +
107 kDielMxInv_zero * std::exp(-std::pow(opt_.alpha * newpoint, 2));
108 }
109 CalcNodeTerms(dielinv_matrices);
110}
111
113 const RPA& rpa, const Eigen::MatrixXd& kDielMxInv_zero);
115 const RPA_UKS& rpa, const Eigen::MatrixXd& kDielMxInv_zero);
116
118 const std::vector<Eigen::MatrixXd>& dielinv_matrices) {
119 const Index order = Index(dielinv_matrices.size());
120 const Index offset = opt_.qpmin - opt_.rpamin;
121 node_terms_.assign(std::size_t(opt_.qptotal), Eigen::MatrixXd());
122#pragma omp parallel for schedule(dynamic)
123 for (Index level = 0; level < opt_.qptotal; level++) {
124 const Eigen::MatrixXd& Imx = Mmn_[level + offset];
125 Eigen::MatrixXd terms(Imx.rows(), order);
126 for (Index j = 0; j < order; j++) {
127 terms.col(j) = RowQuadraticForms(Imx, dielinv_matrices[std::size_t(j)]);
128 }
129 node_terms_[std::size_t(level)] = std::move(terms);
130 }
131}
132
134 public:
135 FunctionEvaluation(const Eigen::MatrixXd& node_terms,
136 const Eigen::ArrayXcd& DeltaE)
137 : node_terms_(node_terms), DeltaE_(DeltaE) {};
138
139 // sum_i den_i (Imx W_j Imx^T)_ii, W_j real
140 double operator()(Index j, double point, bool symmetry) const {
141 Eigen::ArrayXcd denominator;
142 const std::complex<double> cpoint(0.0, point);
143 if (symmetry) {
144 denominator = (DeltaE_ + cpoint).inverse() + (DeltaE_ - cpoint).inverse();
145 } else {
146 denominator = (DeltaE_ + cpoint).inverse();
147 }
148 return 0.5 / tools::conv::Pi *
149 (denominator.real() * node_terms_.col(j).array()).sum();
150 }
151
152 private:
153 const Eigen::MatrixXd& node_terms_;
154 const Eigen::ArrayXcd& DeltaE_;
155};
156
157double ImaginaryAxisIntegration::SigmaGQDiag(double frequency, Index gw_level,
158 double eta) const {
159 Index lumo = opt_.homo + 1;
160 const Index occ = lumo - opt_.rpamin;
161 const Index unocc = opt_.rpamax - opt_.homo;
162 Index gw_level_offset = gw_level + opt_.qpmin - opt_.rpamin;
163 const Eigen::MatrixXd& Imx = Mmn_[gw_level_offset];
164 Eigen::ArrayXcd DeltaE = frequency - energies_.array();
165 DeltaE.imag().head(occ) = eta;
166 DeltaE.imag().tail(unocc) = -eta;
167
168 if (CdaDebugMatch(gw_level)) {
169 double min_abs = std::numeric_limits<double>::max();
170 for (Index i = 0; i < DeltaE.size(); ++i) {
171 min_abs = std::min(min_abs, std::abs(DeltaE(i)));
172 }
173
174 std::cout << "\n [CDA-DEBUG] ImagAxis level=" << gw_level
175 << " freq=" << frequency << " eta=" << eta
176 << " min|DeltaE|=" << min_abs << " ||Imx||=" << Imx.norm();
177
178 for (Index i = 0; i < DeltaE.size(); ++i) {
179 std::cout << "\n [CDA-DEBUG] ImagAxis i=" << i
180 << " occ=" << (i < occ ? 1 : 0) << " DeltaE=" << DeltaE(i);
181 }
182 std::cout << std::flush;
183 }
184
185 FunctionEvaluation f(node_terms_[std::size_t(gw_level)], DeltaE);
186 return gq_->Integrate(f);
187}
188
189} // namespace xtp
190} // namespace votca
virtual std::unique_ptr< T > Create(const key_t &key, args_t &&...arguments)
double operator()(Index j, double point, bool symmetry) const
FunctionEvaluation(const Eigen::MatrixXd &node_terms, const Eigen::ArrayXcd &DeltaE)
double SigmaGQDiag(double frequency, Index gw_level, double eta) const
ImaginaryAxisIntegration(const Eigen::VectorXd &energies, const TCMatrix_gwbse &Mmn)
void configure(options opt, const RPA &rpa, const Eigen::MatrixXd &kDielMxInv_zero)
void CalcDielInvVector(const RPAType &rpa, const Eigen::MatrixXd &kDielMxInv_zero)
std::unique_ptr< GaussianQuadratureBase > gq_
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.
std::vector< Eigen::MatrixXd > node_terms_
void CalcNodeTerms(const std::vector< Eigen::MatrixXd > &dielinv_matrices)
Unrestricted RPA helper for spin-resolved GW screening.
Definition rpa_uks.h:70
const double Pi
Definition constants.h:36
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