votca 2026-dev
Loading...
Searching...
No Matches
out_of_window_shift.h
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#pragma once
21#ifndef VOTCA_XTP_OUT_OF_WINDOW_SHIFT_H
22#define VOTCA_XTP_OUT_OF_WINDOW_SHIFT_H
23
24// Standard includes
25#include <algorithm>
26#include <cmath>
27#include <stdexcept>
28#include <string>
29
30// Local VOTCA includes
31#include "eigen.h"
32
33namespace votca {
34namespace xtp {
35
58 enum class Mode { Max, Nearest, Linear };
60 double fit_fraction = 0.3;
61
62 static Mode Parse(const std::string& name) {
63 if (name == "max") {
64 return Mode::Max;
65 } else if (name == "nearest") {
66 return Mode::Nearest;
67 } else if (name == "linear") {
68 return Mode::Linear;
69 }
70 throw std::runtime_error("Unknown out_of_window_shift '" + name +
71 "'; choices are max, nearest, linear");
72 }
73 static std::string Name(Mode mode) {
74 switch (mode) {
75 case Mode::Nearest:
76 return "nearest";
77 case Mode::Linear:
78 return "linear";
79 default:
80 return "max";
81 }
82 }
83
87 void Apply(Eigen::VectorXd& energies, const Eigen::VectorXd& dft,
88 Index rpamin, Index rpamax, Index homo, Index qpmin,
89 Index qpmax) const {
90 const Index lumo = homo + 1;
91 if (qpmin > rpamin) {
92 ShiftSide(energies, dft, rpamin, rpamin, qpmin - 1, qpmin,
93 std::min(homo, qpmax), true);
94 }
95 if (qpmax < rpamax) {
96 ShiftSide(energies, dft, rpamin, qpmax + 1, rpamax, std::max(lumo, qpmin),
97 qpmax, false);
98 }
99 }
100
101 private:
102 // Shifts levels [out_first, out_last] using the corrections of the window
103 // levels [win_first, win_last] of the same kind; below is true for the
104 // occupied side (boundary win_first), false for the virtual side (boundary
105 // win_last).
106 void ShiftSide(Eigen::VectorXd& energies, const Eigen::VectorXd& dft,
107 Index rpamin, Index out_first, Index out_last, Index win_first,
108 Index win_last, bool below) const {
109 const Index nwin = win_last - win_first + 1;
110 auto correction = [&](Index level) {
111 return energies(level - rpamin) - dft(level);
112 };
113 auto out = energies.segment(out_first - rpamin, out_last - out_first + 1);
114 if (nwin <= 0) {
115 return;
116 }
117 if (mode == Mode::Max) {
118 double max_correction = 0.0;
119 for (Index l = win_first; l <= win_last; ++l) {
120 max_correction = std::max(max_correction, std::abs(correction(l)));
121 }
122 out.array() += below ? -max_correction : max_correction;
123 return;
124 }
125 const Index boundary = below ? win_first : win_last;
126 const Index nfit =
128 ? 1
129 : std::min(nwin,
130 std::max<Index>(
131 2, Index(std::ceil(fit_fraction * double(nwin)))));
132 if (nfit < 2) {
133 out.array() += correction(boundary);
134 return;
135 }
136 // least squares D = a + b x over the nfit levels next to the boundary,
137 // x = e - e_boundary
138 const Index fit_first = below ? win_first : win_last - nfit + 1;
139 const double e_b = dft(boundary);
140 double sx = 0, sy = 0, sxx = 0, sxy = 0, span = 0;
141 for (Index l = fit_first; l < fit_first + nfit; ++l) {
142 const double x = dft(l) - e_b;
143 const double y = correction(l);
144 sx += x;
145 sy += y;
146 sxx += x * x;
147 sxy += x * y;
148 span = std::max(span, std::abs(x));
149 }
150 const double n = double(nfit);
151 const double var = sxx - sx * sx / n;
152 const double b = (var > 1e-12 * n) ? (sxy - sx * sy / n) / var : 0.0;
153 const double a = (sy - b * sx) / n;
154 for (Index l = out_first; l <= out_last; ++l) {
155 const double x = std::clamp(dft(l) - e_b, -span, span);
156 energies(l - rpamin) += a + b * x;
157 }
158 }
159};
160
161} // namespace xtp
162} // namespace votca
163
164#endif // VOTCA_XTP_OUT_OF_WINDOW_SHIFT_H
Provides a means for comparing floating point numbers.
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26
How the RPA energies of levels outside the GW window are shifted.
void Apply(Eigen::VectorXd &energies, const Eigen::VectorXd &dft, Index rpamin, Index rpamax, Index homo, Index qpmin, Index qpmax) const
void ShiftSide(Eigen::VectorXd &energies, const Eigen::VectorXd &dft, Index rpamin, Index out_first, Index out_last, Index win_first, Index win_last, bool below) const
static Mode Parse(const std::string &name)
static std::string Name(Mode mode)