Loading...
Searching...
No Matches
kerker.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * KerkerPreconditioner — the average (global) Thomas-Fermi screening filter.
5 *
6 * K(G) = G² / (G² + q0²)
7 *
8 * Damps the long-wavelength (small-G) components of the residual, where the
9 * Coulomb kernel amplifies a small density error into a large potential error
10 * and drives charge sloshing. As G → ∞ the filter tends to 1 and leaves the
11 * short-wavelength residual alone. Kerker, PRB 23, 3082 (1981).
12 *
13 * The screening wavevector q0 is a single number for the whole cell, which
14 * makes the operator diagonal in G: one multiply per component, no transforms.
15 */
16
17#include <algorithm>
18#include <string>
19#include <vector>
20
22
23namespace q3 {
24
25/// Diagonal G²/(G²+q0²) residual filter.
27 public:
28 /**
29 * @param g_squared |G|² per G-vector, in bohr⁻².
30 * @param q0_squared screening wavevector squared, in bohr⁻².
31 * @param first_nonzero_g_index index of the first G ≠ 0 component; every
32 * component below it is left untouched.
33 */
34 KerkerPreconditioner(const std::vector<Real>& g_squared,
35 Real q0_squared,
36 int first_nonzero_g_index)
37 : first_nonzero_g_index_(first_nonzero_g_index) {
38 weights_.assign(g_squared.size(), 1.0);
39 for (std::size_t g_index = static_cast<std::size_t>(first_nonzero_g_index);
40 g_index < g_squared.size();
41 ++g_index) {
42 weights_[g_index] = g_squared[g_index] / (g_squared[g_index] + q0_squared);
43 }
44 }
45
46 [[nodiscard]] std::string name() const override {
47 return "kerker";
48 }
49
50 void apply(std::vector<Complex>& residual_g) const override {
51 std::size_t count = std::min(residual_g.size(), weights_.size());
52 for (std::size_t g_index = static_cast<std::size_t>(first_nonzero_g_index_);
53 g_index < count;
54 ++g_index) {
55 residual_g[g_index] *= weights_[g_index];
56 }
57 }
58
59 /// The filter values, exposed for the local-TF inner preconditioner and for tests.
60 [[nodiscard]] const std::vector<Real>& weights() const {
61 return weights_;
62 }
63
64 private:
65 std::vector<Real> weights_;
66 int first_nonzero_g_index_{0};
67};
68
69} // namespace q3
Diagonal G²/(G²+q0²) residual filter.
Definition kerker.hpp:26
const std::vector< Real > & weights() const
The filter values, exposed for the local-TF inner preconditioner and for tests.
Definition kerker.hpp:60
KerkerPreconditioner(const std::vector< Real > &g_squared, Real q0_squared, int first_nonzero_g_index)
Definition kerker.hpp:34
std::string name() const override
Definition kerker.hpp:46
void apply(std::vector< Complex > &residual_g) const override
Definition kerker.hpp:50
Abstract base class for all SCF residual preconditioners.
Definition init.hpp:26
double Real