Loading...
Searching...
No Matches
wavefunction_transformer.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4
5/**
6 * WavefunctionTransformer — G ↔ real-space transforms for wavefunction coefficients.
7 */
8
9#include <vector>
10
14
15namespace q3 {
16
18 public:
19 static void g_to_r(const GVectorsGrid& g_vectors_grid,
20 const FFTGrid& fft_wave,
21 const std::vector<Complex>& coefficients_g_space,
22 const std::vector<int>& g_vector_indices,
23 int number_of_plane_waves,
24 std::vector<Complex>& coefficients_real_space) {
25 int local_points = fft_wave.local_grid_points();
26 // Sized for either layout: the scatter fills reciprocal space, the transform leaves real.
27 coefficients_real_space.assign(
28 static_cast<std::size_t>(std::max(local_points, fft_wave.local_g_space_points())),
29 Complex(0.0, 0.0));
30
31 const auto& g_vectors = g_vectors_grid.g_vectors();
32 for (int plane_wave_index = 0; plane_wave_index < number_of_plane_waves;
33 plane_wave_index++) {
34 const auto& g_vector_entry = g_vectors[g_vector_indices[plane_wave_index]];
35 int fft_grid_index = fft_wave.g_vector_to_fft_grid_index(
36 g_vector_entry.miller.x, g_vector_entry.miller.y, g_vector_entry.miller.z);
37 /**
38 * With slab-aligned G-vectors, fft_grid_index MUST be >= 0 if the partitioning
39 * is correct. We keep the check as a safety measure but it should never trigger.
40 */
41 if (fft_grid_index >= 0) {
42 coefficients_real_space[fft_grid_index] = coefficients_g_space[plane_wave_index];
43 }
44 }
45
46 fft_wave.inverse(coefficients_real_space.data());
47 }
48
49 static void r_to_g(const GVectorsGrid& g_vectors_grid,
50 const FFTGrid& fft_wave,
51 const std::vector<Complex>& coefficients_real_space,
52 const std::vector<int>& g_vector_indices,
53 int number_of_plane_waves,
54 std::vector<Complex>& coefficients_g_space) {
55 int local_points = fft_wave.local_grid_points();
56 std::vector<Complex> work(coefficients_real_space.begin(), coefficients_real_space.end());
57 work.resize(
58 static_cast<std::size_t>(std::max(local_points, fft_wave.local_g_space_points())),
59 Complex(0.0, 0.0));
60
61 fft_wave.forward(work.data());
62
63 const auto& g_vectors = g_vectors_grid.g_vectors();
64 coefficients_g_space.assign(number_of_plane_waves, Complex(0.0, 0.0));
65 for (int plane_wave_index = 0; plane_wave_index < number_of_plane_waves;
66 plane_wave_index++) {
67 const auto& g_vector_entry = g_vectors[g_vector_indices[plane_wave_index]];
68 int fft_grid_index = fft_wave.g_vector_to_fft_grid_index(
69 g_vector_entry.miller.x, g_vector_entry.miller.y, g_vector_entry.miller.z);
70 if (fft_grid_index >= 0) {
71 coefficients_g_space[plane_wave_index] = work[fft_grid_index];
72 }
73 }
74
75 /**
76 * REDUNDANCY REMOVED: In band-parallel mode, G-space coefficients are now
77 * truly partitioned. Collectives like dot_product or the Hamiltonian application (kinetic)
78 * handle the reduction themselves. We no longer need to Allreduce the
79 * entire wavefunction after every FFT.
80 */
81 }
82};
83
84} // namespace q3
virtual int g_vector_to_fft_grid_index(int miller_1, int miller_2, int miller_3) const =0
virtual int local_g_space_points() const
Definition fft_grid.hpp:88
virtual void forward(Complex *data) const =0
virtual void inverse(Complex *data) const =0
virtual int local_grid_points() const =0
const std::vector< GVector > & g_vectors() const
static void r_to_g(const GVectorsGrid &g_vectors_grid, const FFTGrid &fft_wave, const std::vector< Complex > &coefficients_real_space, const std::vector< int > &g_vector_indices, int number_of_plane_waves, std::vector< Complex > &coefficients_g_space)
static void g_to_r(const GVectorsGrid &g_vectors_grid, const FFTGrid &fft_wave, const std::vector< Complex > &coefficients_g_space, const std::vector< int > &g_vector_indices, int number_of_plane_waves, std::vector< Complex > &coefficients_real_space)
std::complex< double > Complex