67 std::vector<Real> g_squared,
69 int first_nonzero_g_index,
70 std::function<
void(
const std::vector<Real>&, std::vector<Complex>&)> to_reciprocal_space,
71 std::function<
void(
const std::vector<Complex>&, std::vector<Real>&)> to_real_space,
72 std::function<
void(std::vector<Real>&)> reduce_within_pool = {})
73 : g_squared_(std::move(g_squared))
74 , q0_squared_(q0_squared)
75 , first_nonzero_g_index_(first_nonzero_g_index)
76 , to_reciprocal_space_(std::move(to_reciprocal_space))
77 , to_real_space_(std::move(to_real_space))
78 , reduce_within_pool_(std::move(reduce_within_pool)) {
84 mean_screening_ = q0_squared_;
101 void update(
const std::vector<Real>& density_real)
override {
102 screening_real_.resize(density_real.size());
104 for (std::size_t index = 0; index < density_real.size(); ++index) {
110 Real density = std::max(density_real[index], 0.0);
111 Real fermi_wavevector = std::cbrt(3.0 * M_PI * M_PI * density);
112 Real screening = 4.0 * fermi_wavevector / M_PI;
113 screening_real_[index] = std::max(screening, q0_squared_);
114 sum += screening_real_[index];
116 std::vector<Real> sum_and_count = {sum,
static_cast<Real>(density_real.size())};
117 if (reduce_within_pool_) {
118 reduce_within_pool_(sum_and_count);
121 sum_and_count[1] > 0.0 ? sum_and_count[0] / sum_and_count[1] : q0_squared_;
122 has_screening_ =
true;
125 void apply(std::vector<Complex>& residual_g)
const override {
132 if (!has_screening_) {
138 for (std::size_t g_index = first_index(); g_index < residual_g.size(); ++g_index) {
139 residual_g[g_index] *=
140 g_squared_[g_index] / (g_squared_[g_index] + mean_screening_);
145 std::size_t count = residual_g.size();
146 std::vector<Complex> right_hand_side(count,
Complex(0.0, 0.0));
147 for (std::size_t g_index = first_index(); g_index < count; ++g_index) {
148 right_hand_side[g_index] = g_squared_[g_index] * residual_g[g_index];
160 std::vector<Complex> solution(count,
Complex(0.0, 0.0));
161 apply_diagonal_inverse(right_hand_side, solution);
163 std::vector<Complex> operator_times_solution(count,
Complex(0.0, 0.0));
164 apply_operator(solution, operator_times_solution);
166 std::vector<Complex> gradient(count,
Complex(0.0, 0.0));
167 for (std::size_t g_index = first_index(); g_index < count; ++g_index) {
168 gradient[g_index] = right_hand_side[g_index] - operator_times_solution[g_index];
171 Real right_hand_side_norm = std::sqrt(dot_product(right_hand_side, right_hand_side));
172 if (right_hand_side_norm <= 0.0) {
173 for (std::size_t g_index = first_index(); g_index < count; ++g_index) {
174 residual_g[g_index] = solution[g_index];
178 Real tolerance = relative_tolerance_ * right_hand_side_norm;
180 std::vector<Complex> preconditioned_gradient(count,
Complex(0.0, 0.0));
181 apply_diagonal_inverse(gradient, preconditioned_gradient);
182 std::vector<Complex> search_direction = preconditioned_gradient;
183 Real gradient_dot = dot_product(gradient, preconditioned_gradient);
185 std::vector<Complex> operator_times_direction(count,
Complex(0.0, 0.0));
187 for (; iteration < maximum_iterations_; ++iteration) {
188 if (std::sqrt(dot_product(gradient, gradient)) <= tolerance)
191 apply_operator(search_direction, operator_times_direction);
192 Real curvature = dot_product(search_direction, operator_times_direction);
193 if (curvature <= 0.0)
196 Real step = gradient_dot / curvature;
197 for (std::size_t g_index = first_index(); g_index < count; ++g_index) {
198 solution[g_index] += step * search_direction[g_index];
199 gradient[g_index] -= step * operator_times_direction[g_index];
202 apply_diagonal_inverse(gradient, preconditioned_gradient);
203 Real gradient_dot_new = dot_product(gradient, preconditioned_gradient);
204 Real direction_weight = gradient_dot_new / gradient_dot;
205 gradient_dot = gradient_dot_new;
206 for (std::size_t g_index = first_index(); g_index < count; ++g_index) {
207 search_direction[g_index] =
208 preconditioned_gradient[g_index] + direction_weight * search_direction[g_index];
212 if (iteration == maximum_iterations_ &&
213 std::sqrt(dot_product(gradient, gradient)) > tolerance) {
219 log::info(
" local-TF preconditioner: conjugate gradients hit the {}-iteration cap "
220 "(relative residual {:.3e}); the preconditioner is only partly applied",
222 std::sqrt(dot_product(gradient, gradient)) / right_hand_side_norm);
230 for (std::size_t g_index = first_index(); g_index < count; ++g_index) {
231 residual_g[g_index] = solution[g_index];