votca 2026-dev
Loading...
Searching...
No Matches
sigma_ppm_uks.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 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
21#include <votca/tools/globals.h>
22
23#include "sigma_ppm_uks.h"
25#include "votca/xtp/ppm.h"
27
28namespace votca {
29namespace xtp {
30
32 if (ppm_ == nullptr) {
33 throw std::runtime_error(
34 "Sigma_PPM_UKS: shared PPM parameters were not set before "
35 "PrepareScreening().");
36 }
37 Mmn_.MultiplyRightWithAuxMatrix(ppm_->getPpm_phi());
38 const Eigen::VectorXd& weight = ppm_->getPpm_weight();
39 const Eigen::VectorXd& omega = ppm_->getPpm_freq();
40 mode_factors_.resize(weight.size());
41 for (Index i = 0; i < weight.size(); ++i) {
42 mode_factors_(i) = (weight(i) < 1.e-9) ? 0.0 : 0.5 * weight(i) * omega(i);
43 }
44}
45
46// As Sigma_PPM::AccumulateDiag: lazily evaluated array expressions, no
47// temporaries per mode (this runs inside the parallel QP solver).
48template <class Term>
49double Sigma_PPM_UKS::AccumulateDiag(Index gw_level, double frequency,
50 Term term) const {
51 // first virtual level, counted from rpamin like the energies and the
52 // rows of Mmn_
53 const Index lumo = opt_.homo + 1 - opt_.rpamin;
54 const Index levelsum = Mmn_.nsize();
55 const Index qpmin_offset = opt_.qpmin - opt_.rpamin;
56 const Eigen::MatrixXd& M = Mmn_[gw_level + qpmin_offset];
57 const auto e = getSpinRPAInputEnergies().array();
58 const Eigen::VectorXd& weight = ppm_->getPpm_weight();
59 const Eigen::VectorXd& omega = ppm_->getPpm_freq();
60 double result = 0.0;
61 for (Index i_aux = 0; i_aux < Mmn_.auxsize(); i_aux++) {
62 if (weight(i_aux) < 1.e-9) {
63 continue;
64 }
65 const double ppm_freq = omega(i_aux);
66 const double fac = 0.5 * weight(i_aux) * ppm_freq;
67 const auto m2 = M.col(i_aux).array().square();
68 const auto t_occ = (frequency + ppm_freq) - e.head(lumo);
69 const auto t_virt = (frequency - ppm_freq) - e.tail(levelsum - lumo);
70 result += fac * ((m2.head(lumo) * term(t_occ)).sum() +
71 (m2.tail(levelsum - lumo) * term(t_virt)).sum());
72 }
73 return result;
74}
75
77 double frequency) const {
78 const double eta2 = opt_.eta * opt_.eta;
79 return AccumulateDiag(gw_level, frequency, [eta2](const auto& t) {
80 return t / (t.square() + eta2);
81 });
82}
83
85 Index gw_level, const Eigen::VectorXd& frequencies) const {
86 const Index qpmin_offset = opt_.qpmin - opt_.rpamin;
87 const ExactPoles poles{getSpinRPAInputEnergies(), opt_.homo + 1 - opt_.rpamin,
88 ppm_->getPpm_freq(), opt_.eta};
89 return exact_pole_sums::Values(poles, Mmn_[gw_level + qpmin_offset].data(),
90 frequencies, mode_factors_.data());
91}
92
94 Index gw_level, double frequency) const {
95 const double eta2 = opt_.eta * opt_.eta;
96 return AccumulateDiag(gw_level, frequency, [eta2](const auto& t) {
97 return (eta2 - t.square()) / (t.square() + eta2).square();
98 });
99}
100
102 Index gw_level2,
103 double frequency1,
104 double frequency2) const {
105 // first virtual level, counted from rpamin like the energies and the
106 // rows of Mmn_
107 const Index lumo = opt_.homo + 1 - opt_.rpamin;
108 const double eta2 = opt_.eta * opt_.eta;
109 const Index levelsum = Mmn_.nsize();
110 const Index auxsize = Mmn_.auxsize();
111 const Eigen::VectorXd ppm_weight = ppm_->getPpm_weight();
112 const Eigen::VectorXd ppm_freqs = ppm_->getPpm_freq();
113 const Index qpmin_offset = opt_.qpmin - opt_.rpamin;
114 const Eigen::VectorXd& energies = getSpinRPAInputEnergies();
115
116 double sigma_c = 0.0;
117 for (Index i_aux = 0; i_aux < auxsize; i_aux++) {
118 if (ppm_weight(i_aux) < 1.e-9) {
119 continue;
120 }
121
122 const double ppm_freq = ppm_freqs(i_aux);
123 const double fac = 0.25 * ppm_weight(i_aux) * ppm_freq;
124
125 const Eigen::MatrixXd& Mmn1 = Mmn_[gw_level1 + qpmin_offset];
126 const Eigen::MatrixXd& Mmn2 = Mmn_[gw_level2 + qpmin_offset];
127
128 const Eigen::ArrayXd Mmn1xMmn2 =
129 Mmn1.col(i_aux).cwiseProduct(Mmn2.col(i_aux));
130
131 Eigen::ArrayXd temp1 = energies.array();
132 temp1.segment(0, lumo) -= ppm_freq;
133 temp1.segment(lumo, levelsum - lumo) += ppm_freq;
134
135 Eigen::ArrayXd temp2 = (frequency2 - temp1);
136 temp1 = (frequency1 - temp1);
137
138 sigma_c +=
139 fac * ((temp1 / (temp1.abs2() + eta2) + temp2 / (temp2.abs2() + eta2)) *
140 Mmn1xMmn2)
141 .sum();
142 }
143 return sigma_c;
144}
145
146} // namespace xtp
147} // namespace votca
double CalcCorrelationDiagElementDerivative(Index gw_level, double frequency) const final
double CalcCorrelationOffDiagElement(Index gw_level1, Index gw_level2, double frequency1, double frequency2) const final
double CalcCorrelationDiagElement(Index gw_level, double frequency) const final
double AccumulateDiag(Index gw_level, double frequency, Term term) const
Eigen::VectorXd CalcCorrelationDiagElements(Index gw_level, const Eigen::VectorXd &frequencies) const final
Eigen::VectorXd mode_factors_
const Eigen::VectorXd & getSpinRPAInputEnergies() const
Eigen::VectorXd Values(const ExactPoles &poles, const double *residues, const Eigen::VectorXd &w)
Charge transport classes.
Definition ERIs.h:28
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
Pole sums of the exact (RPA spectral) correlation self-energy.