Loading...
Searching...
No Matches
miller_index_lookup.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * MillerIndexLookup — Miller (h,k,l) -> global charge-density G-vector index.
5 *
6 * Every plane-wave calculator that needs to find a G-vector by its integer
7 * Miller triple (rather than iterate the sorted-by-magnitude list) needs
8 * this reverse lookup; the Wannier overlap kernels are the first callers
9 * with a hot inner loop over it (matching a k-point's plane-wave G-set
10 * against its k+b neighbor's, after the periodic-image Miller shift). The
11 * packing scheme generalizes the ad hoc packed-key map built inline in
12 * layer_4_computation/charge_density/planewave/init.hpp -- same idea (pack
13 * three small integers into one int64_t hash-map key), but the offset is
14 * sized from the actual Miller range on construction instead of a fixed
15 * assumed bound, so it cannot silently collide on a denser G-sphere.
16 */
17
18#include <algorithm>
19#include <cstdint>
20#include <cstdlib>
21#include <unordered_map>
22#include <vector>
23
26
27namespace q3 {
28
30 public:
31 MillerIndexLookup() = default;
32
33 /**
34 * Build the lookup table from a charge-density G-vector list: index i's
35 * Miller triple maps to i. `g_vectors` is typically
36 * GVectorsGrid::g_vectors() -- the sphere every per-k-point plane-wave
37 * set and every augmentation-function table is indexed into.
38 */
39 void build(const std::vector<GVector>& g_vectors) {
40 index_by_key_.clear();
41 index_by_key_.reserve(g_vectors.size());
42
43 offset_ = 1;
44 for (const GVector& g_vector : g_vectors) {
45 offset_ = std::max({offset_,
46 std::abs(g_vector.miller.x) + 1,
47 std::abs(g_vector.miller.y) + 1,
48 std::abs(g_vector.miller.z) + 1});
49 }
50
51 for (int g_vector_index = 0; g_vector_index < static_cast<int>(g_vectors.size());
52 g_vector_index++) {
53 const IntegerVector3D& miller = g_vectors[g_vector_index].miller;
54 index_by_key_[pack(miller.x, miller.y, miller.z)] = g_vector_index;
55 }
56 }
57
58 /**
59 * The global G-vector index for the given Miller triple, or -1 if it
60 * falls outside the charge-density sphere this lookup was built from.
61 * A miss is a legitimate outcome (a k+b plane wave can fall just
62 * outside the sphere at the zone boundary) -- callers count misses
63 * rather than treat them as errors.
64 */
65 [[nodiscard]] int find(const IntegerVector3D& miller) const {
66 return find(miller.x, miller.y, miller.z);
67 }
68
69 [[nodiscard]] int find(int miller_h, int miller_k, int miller_l) const {
70 if (std::abs(miller_h) >= offset_ || std::abs(miller_k) >= offset_ ||
71 std::abs(miller_l) >= offset_) {
72 return -1;
73 }
74 auto iterator = index_by_key_.find(pack(miller_h, miller_k, miller_l));
75 return iterator == index_by_key_.end() ? -1 : iterator->second;
76 }
77
78 [[nodiscard]] int size() const {
79 return static_cast<int>(index_by_key_.size());
80 }
81
82 private:
83 [[nodiscard]] int64_t pack(int miller_h, int miller_k, int miller_l) const {
84 const int64_t span = 2 * static_cast<int64_t>(offset_) + 1;
85 return (static_cast<int64_t>(miller_h) + offset_) * span * span +
86 (static_cast<int64_t>(miller_k) + offset_) * span +
87 (static_cast<int64_t>(miller_l) + offset_);
88 }
89
90 std::unordered_map<int64_t, int> index_by_key_;
91 int offset_ = 1;
92};
93
94} // namespace q3
int find(int miller_h, int miller_k, int miller_l) const
MillerIndexLookup()=default
void build(const std::vector< GVector > &g_vectors)
int find(const IntegerVector3D &miller) const
A reciprocal lattice vector with Miller indices, used in plane-wave calculations.
Definition g_vector.hpp:17
Integer 3-vector for Miller indices / FFT grid indices.