41 const std::vector<KPointNeighborDirection>& directions) {
56 return static_cast<int>(neighbor_table_.size());
59 return static_cast<int>(weights_.size());
63 [[nodiscard]]
int neighbor(
int kpoint,
int direction)
const {
64 return neighbor_table_[
static_cast<std::size_t
>(kpoint)]
65 [
static_cast<std::size_t
>(direction)];
69 return weights_[
static_cast<std::size_t
>(direction)];
71 [[nodiscard]]
const std::vector<Real>&
weights()
const {
83 return !b_vectors_.empty();
88 return b_vectors_[
static_cast<std::size_t
>(direction)];
90 [[nodiscard]]
const std::vector<Vector3D>&
b_vectors()
const {
97 return !grid_steps_.empty();
101 throw std::logic_error(
"KPointStencil: a stencil built from a table carries no grid "
104 return grid_steps_[
static_cast<std::size_t
>(direction)];
107 return grid_dimensions_;
123 for (std::size_t direction = 0; direction < grid_steps_.size(); direction++) {
128 return static_cast<int>(direction);
136 const std::vector<KPointNeighborDirection>& directions)
138 for (
int axis = 0; axis < 3; axis++) {
140 throw std::invalid_argument(
141 "KPointStencil: the grid dimensions must be positive, got " +
146 for (
const KPointNeighborDirection& direction : directions) {
147 weights_.push_back(direction.weight);
148 b_vectors_.push_back(direction.reciprocal_lattice_translation);
149 grid_steps_.push_back(direction.grid_step);
154 std::vector<int> row;
155 row.reserve(directions.size());
156 for (
const KPointNeighborDirection& direction : directions) {
160 neighbor_table_.push_back(std::move(row));
162 require_consistent();
165 KPointStencil(std::vector<std::vector<int>> neighbor_table,
168 : neighbor_table_(std::move(neighbor_table))
171 require_consistent();
174 void require_consistent()
const {
175 if (neighbor_table_.empty()) {
176 throw std::invalid_argument(
"KPointStencil: no k-points");
178 if (weights_.empty()) {
179 throw std::invalid_argument(
180 "KPointStencil: no neighbour directions; there is nothing to make a subspace "
181 "smooth against and no phase to read");
183 if (!b_vectors_.empty() && b_vectors_.size() != weights_.size()) {
184 throw std::invalid_argument(
"KPointStencil: one b-vector per direction or none; " +
185 std::to_string(b_vectors_.size()) +
" were given for " +
186 std::to_string(weights_.size()) +
" directions");
189 for (std::size_t kpoint = 0; kpoint < neighbor_table_.size(); kpoint++) {
190 if (neighbor_table_[kpoint].size() != weights_.size()) {
191 throw std::invalid_argument(
"KPointStencil: k-point " + std::to_string(kpoint) +
192 " does not carry one neighbour per direction");
194 for (
const int neighbor : neighbor_table_[kpoint]) {
196 throw std::invalid_argument(
197 "KPointStencil: k-point " + std::to_string(kpoint) +
" names k-point " +
198 std::to_string(
neighbor) +
" as a neighbour, which is outside the " +
205 void require_b_vectors()
const {
206 if (b_vectors_.empty()) {
207 throw std::logic_error(
"KPointStencil: this stencil carries no b-vectors, so nothing "
208 "that reads a phase can run on it");
212 std::vector<std::vector<int>> neighbor_table_;
213 std::vector<Real> weights_;
214 std::vector<Vector3D> b_vectors_;
215 std::vector<IntegerVector3D> grid_steps_;
216 std::array<int, 3> grid_dimensions_ = {0, 0, 0};
static KPointStencil from_grid(const std::array< int, 3 > &grid_dimensions, const std::vector< KPointNeighborDirection > &directions)
From a full grid and its neighbour shells: k + b resolved for every k and every direction.