68 const std::vector<std::vector<Complex>>& values_at_kpoints,
69 const std::vector<IntegerVector3D>& lattice_translations) {
70 const std::size_t number_of_kpoints = kpoints_crystal.size();
71 if (number_of_kpoints == 0) {
72 throw std::invalid_argument(
"lattice_fourier_transform::to_real_space: no k-points");
74 if (values_at_kpoints.size() != number_of_kpoints) {
75 throw std::invalid_argument(
76 "lattice_fourier_transform::to_real_space: " + std::to_string(number_of_kpoints) +
77 " k-points but " + std::to_string(values_at_kpoints.size()) +
" value blocks");
79 if (lattice_translations.empty()) {
80 throw std::invalid_argument(
"lattice_fourier_transform::to_real_space: no lattice vectors");
82 const std::size_t block_size = values_at_kpoints[0].size();
83 if (block_size == 0) {
84 throw std::invalid_argument(
"lattice_fourier_transform::to_real_space: empty value block");
86 for (std::size_t kpoint_index = 1; kpoint_index < number_of_kpoints; kpoint_index++) {
87 if (values_at_kpoints[kpoint_index].size() != block_size) {
88 throw std::invalid_argument(
89 "lattice_fourier_transform::to_real_space: the block at k-point " +
90 std::to_string(kpoint_index) +
" holds " +
91 std::to_string(values_at_kpoints[kpoint_index].size()) +
" values, not " +
92 std::to_string(block_size) +
" as the first one does");
96 const Real inverse_kpoint_count = 1.0 /
static_cast<Real>(number_of_kpoints);
97 std::vector<std::vector<Complex>> values_at_lattice_vectors(
98 lattice_translations.size(), std::vector<Complex>(block_size,
Complex(0.0, 0.0)));
104 for (std::size_t kpoint_index = 0; kpoint_index < number_of_kpoints; kpoint_index++) {
105 const std::vector<Complex>& block_at_kpoint = values_at_kpoints[kpoint_index];
106 for (std::size_t vector_index = 0; vector_index < lattice_translations.size();
109 lattice_translations[vector_index],
111 inverse_kpoint_count;
112 std::vector<Complex>& block_at_lattice_vector = values_at_lattice_vectors[vector_index];
113 for (std::size_t element = 0; element < block_size; element++) {
114 block_at_lattice_vector[element] += weighted_phase * block_at_kpoint[element];
118 return values_at_lattice_vectors;
133 const std::vector<std::vector<Complex>>& values_at_lattice_vectors,
134 const std::vector<IntegerVector3D>& lattice_translations,
135 const std::vector<Real>& weights) {
136 const std::size_t number_of_vectors = lattice_translations.size();
137 if (number_of_vectors == 0) {
138 throw std::invalid_argument(
"lattice_fourier_transform::to_kpoint: no lattice vectors");
140 if (values_at_lattice_vectors.size() != number_of_vectors ||
141 weights.size() != number_of_vectors) {
142 throw std::invalid_argument(
143 "lattice_fourier_transform::to_kpoint: " + std::to_string(number_of_vectors) +
144 " lattice vectors but " + std::to_string(values_at_lattice_vectors.size()) +
145 " value blocks and " + std::to_string(weights.size()) +
" weights");
147 const std::size_t block_size = values_at_lattice_vectors[0].size();
148 if (block_size == 0) {
149 throw std::invalid_argument(
"lattice_fourier_transform::to_kpoint: empty value block");
152 std::vector<Complex> value_at_kpoint(block_size,
Complex(0.0, 0.0));
153 for (std::size_t vector_index = 0; vector_index < number_of_vectors; vector_index++) {
154 const std::vector<Complex>& block = values_at_lattice_vectors[vector_index];
155 if (block.size() != block_size) {
156 throw std::invalid_argument(
157 "lattice_fourier_transform::to_kpoint: the block at lattice vector " +
158 std::to_string(vector_index) +
" holds " + std::to_string(block.size()) +
159 " values, not " + std::to_string(block_size) +
" as the first one does");
162 internal::phase(kpoint_crystal, lattice_translations[vector_index], 1.0) *
163 weights[vector_index];
164 for (std::size_t element = 0; element < block_size; element++) {
165 value_at_kpoint[element] += weighted_phase * block[element];
168 return value_at_kpoint;