Loading...
Searching...
No Matches
init.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * WannierHamiltonianBuilder — the Wannier method: captured interface
5 * matrices to a local-orbital Hamiltonian H(R), with a report of how.
6 *
7 * Four steps, and only the middle two are Wannier's own. The inputs are
8 * checked and their neighbour geometry resolved once
9 * (WannierConstructionInputs). A SubspaceSelection chooses the N states the
10 * gauge is built from -- the window as it stands, or a subspace
11 * disentangled out of a wider one -- and hands them over as frames in the
12 * projection gauge. A GaugeChoice fixes the gauge inside them: kept, or
13 * rotated to minimise the spread. Rotating the eigenvalues by the final
14 * frames gives H^W(k) = C^dagger E C at each mesh point, and transforming
15 * that to real space is a lattice Fourier sum that belongs to nobody in
16 * particular, so it is layer 1's (lattice_fourier_transform), taken over the
17 * Wigner-Seitz supercell of the k-mesh so that boundary vectors carry their
18 * degeneracy weight.
19 *
20 * The builder holds the settings and nothing else; which strategy runs is
21 * decided by the two factories, so no step here branches on what was asked
22 * for. Nothing here touches a basis either: it works on any inputs of the
23 * right shape -- Q3's own, or a set imported from another code's
24 * Wannier90-format files -- which is what lets the method be validated
25 * against Quantum ESPRESSO's matrices independently of Q3's plane-wave
26 * kernels.
27 */
28
29#include <cstddef>
30#include <memory>
31#include <utility>
32#include <vector>
33
53
54namespace q3 {
55
57 public:
58 /// The defaults are an isolated manifold in the projection gauge: what a record alone supports.
60 : settings_(std::move(settings)) {}
61
62 /**
63 * `real_lattice` rows are a1, a2, a3 in any consistent length unit; only
64 * the Wigner-Seitz geometry depends on it, and that is unit-free.
65 */
66 [[nodiscard]] WannierConstruction build(const WannierInputs& record,
67 const Matrix3x3& real_lattice) const {
68 const WannierConstructionInputs inputs(record);
69 const std::unique_ptr<SubspaceSelection> selection = create_subspace_selection(settings_);
70 const std::unique_ptr<GaugeChoice> choice = create_gauge_choice(settings_, inputs);
71
72 const WannierSubspace subspace = selection->choose(inputs);
73 const WannierGauge gauge = choice->choose(inputs, subspace);
74
75 WannierConstruction construction;
76 construction.report.disentanglement = subspace.report;
77 construction.report.spread = gauge.spread;
78 construction.hamiltonian =
79 real_space_hamiltonian(inputs, subspace.classification, gauge.frames, real_lattice);
80 construction.report.hamiltonian_decay =
82 return construction;
83 }
84
85 private:
86 /**
87 * H^W(k) = C(k)^dagger E(k) C(k), one N x N block per k-point, summed to
88 * H(R) over the Wigner-Seitz supercell of the k-mesh.
89 */
90 [[nodiscard]] static LocalOrbitalHamiltonian
91 real_space_hamiltonian(const WannierConstructionInputs& inputs,
92 const BandClassification& classification,
93 const std::vector<DenseMatrix<Complex>>& frames,
94 const Matrix3x3& real_lattice) {
95 const WannierInputs& record = inputs.record();
96 const int number_of_kpoints = inputs.number_of_kpoints();
97
98 WignerSeitzSupercell supercell;
99 supercell.compute(real_lattice,
100 record.kpoint_grid_dimensions[0],
101 record.kpoint_grid_dimensions[1],
102 record.kpoint_grid_dimensions[2]);
103 log::info("Wigner-Seitz supercell: {} lattice vectors, total weight {:.6f} (expected {})",
104 supercell.number_of_lattice_vectors(),
105 supercell.total_weight(),
106 number_of_kpoints);
107
108 std::vector<LocalOrbitalLatticeVector> domain;
109 std::vector<IntegerVector3D> translations;
110 domain.reserve(supercell.lattice_vectors().size());
111 translations.reserve(supercell.lattice_vectors().size());
112 for (const WignerSeitzLatticeVector& entry : supercell.lattice_vectors()) {
113 domain.push_back({entry.lattice_translation,
114 entry.cartesian,
115 1.0 / static_cast<Real>(entry.degeneracy)});
116 translations.push_back(entry.lattice_translation);
117 }
118
119 std::vector<std::vector<Complex>> hamiltonian_at_kpoints;
120 hamiltonian_at_kpoints.reserve(static_cast<std::size_t>(number_of_kpoints));
121 for (int kpoint_index = 0; kpoint_index < number_of_kpoints; kpoint_index++) {
122 const KPointBandClassification& entry =
123 classification.kpoints[static_cast<std::size_t>(kpoint_index)];
124 std::vector<Real> kept_eigenvalues;
125 kept_eigenvalues.reserve(entry.kept_bands.size());
126 for (const int band : entry.kept_bands) {
127 kept_eigenvalues.push_back(record.eigenvalues_rydberg[kpoint_index][band]);
128 }
129 const DenseMatrix<Complex>& frame = frames[static_cast<std::size_t>(kpoint_index)];
130 hamiltonian_at_kpoints.push_back(multiply(MatrixOperation::ConjugateTranspose,
131 frame,
133 frame.scaled_rows(kept_eigenvalues))
134 .raw());
135 }
136
137 LocalOrbitalHamiltonian hamiltonian;
138 hamiltonian.set_domain(record.number_of_trial_orbitals, std::move(domain));
139 hamiltonian.set_hamiltonian(lattice_fourier_transform::to_real_space(
140 record.kpoint_coordinates, hamiltonian_at_kpoints, translations));
141 return hamiltonian;
142 }
143
144 WannierConstructionSettings settings_;
145};
146
147} // namespace q3
const std::vector< T > & raw() const
Read-only: a caller that could resize the buffer could break rows() x columns().
const WannierInputs & record() const
The inputs as the record stores them.
WannierConstruction build(const WannierInputs &record, const Matrix3x3 &real_lattice) const
Definition init.hpp:66
WannierHamiltonianBuilder(WannierConstructionSettings settings={})
The defaults are an isolated manifold in the projection gauge: what a record alone supports.
Definition init.hpp:59
const std::vector< WignerSeitzLatticeVector > & lattice_vectors() const
void compute(const Matrix3x3 &lattice_vectors, int grid_dimension_x, int grid_dimension_y, int grid_dimension_z, Real distance_tolerance=1e-6)
std::vector< std::vector< Complex > > to_real_space(const std::vector< Vector3D > &kpoints_crystal, const std::vector< std::vector< Complex > > &values_at_kpoints, const std::vector< IntegerVector3D > &lattice_translations)
void info(spdlog::format_string_t< Args... > fmt, Args &&... args)
Definition logger.hpp:183
std::unique_ptr< SubspaceSelection > create_subspace_selection(const WannierConstructionSettings &settings)
Definition factory.hpp:19
double Real
std::unique_ptr< GaugeChoice > create_gauge_choice(const WannierConstructionSettings &settings, const WannierConstructionInputs &inputs)
Definition factory.hpp:31
DenseMatrix< Complex > multiply(MatrixOperation left_operation, const DenseMatrix< Complex > &left, MatrixOperation right_operation, const DenseMatrix< Complex > &right, Complex alpha=Complex(1.0, 0.0))
alpha * op(left) * op(right), as a new matrix of the product's shape.
Every k-point's verdict, and the summary of the whole.
std::vector< KPointBandClassification > kpoints
static HamiltonianDecay measured_on(const LocalOrbitalHamiltonian &hamiltonian)
3×3 matrix stored row-major: row i = mat[i]
DisentanglementReport disentanglement
Definition init.hpp:25
HamiltonianDecay hamiltonian_decay
How far H(R) has decayed by the edge of its Wigner-Seitz domain.
Definition init.hpp:28
LocalOrbitalHamiltonian hamiltonian
WannierConstructionReport report
SpreadReport spread
std::vector< DenseMatrix< Complex > > frames
std::vector< Vector3D > kpoint_coordinates
Definition inputs.hpp:42
std::vector< std::vector< Real > > eigenvalues_rydberg
Eigenvalues in Rydberg, indexed [kpoint_index][band_index].
Definition inputs.hpp:74
std::array< int, 3 > kpoint_grid_dimensions
Definition inputs.hpp:37
int number_of_trial_orbitals
Definition inputs.hpp:72
BandClassification classification
DisentanglementReport report
One retained lattice vector with the number of images it ties with.