Quantum 3xplorer (Q3)
An AI-native quantum simulation engine
Loading...
Searching...
No Matches
importer.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * import_wannier90_files — another code's (or Q3's own) Wannier90-format
5 * files into an InterpolationRecord, so the same interpolator that evaluates
6 * a native record evaluates them.
7 *
8 * This is how the interpolation engine is validated independently of Q3's
9 * plane-wave kernels: pw2wannier90's matrices go through exactly the code
10 * path Q3's do, and a disagreement points at one side or the other rather
11 * than at the pair. It is also how a user brings matrices from Quantum
12 * ESPRESSO into Q3.
13 *
14 * What is imported is what the interpolation uses: the k-points and lattice
15 * from `.nnkp`, the projections from `.amn`, the eigenvalues from `.eig`
16 * (eV, converted to Rydberg). The overlaps are NOT imported: the projection
17 * gauge never reads them, the localizer that would is not built yet, and
18 * carrying them faithfully means re-deriving pw2wannier90's neighbour order
19 * against Q3's own shell enumeration -- work with no consumer today. The
20 * record says so by having no overlaps, and the Wannier90 exporter refuses
21 * to write an empty `.mmn` for it. The Fermi energy is likewise unknown to
22 * these files and left at zero.
23 *
24 * `grid` must be given: a `.nnkp` lists k-points without saying what grid
25 * they came from, and the Wigner-Seitz construction needs the shape.
26 */
27
28#include <array>
29#include <cmath>
30#include <complex>
31#include <stdexcept>
32#include <string>
33#include <vector>
34
39
40namespace q3 {
41
42[[nodiscard]] inline InterpolationRecord import_wannier90_files(const std::string& seedname,
43 const std::array<int, 3>& grid) {
44 for (int axis = 0; axis < 3; axis++) {
45 if (grid[axis] <= 0) {
46 throw std::invalid_argument(
47 "import_wannier90_files: the k-point grid must be three positive integers");
48 }
49 }
50 const auto neighbor_list = Wannier90FormatReader::read_neighbor_list(seedname + ".nnkp");
51 const auto projections = Wannier90FormatReader::read_projections(seedname + ".amn");
52 const auto eigenvalues = Wannier90FormatReader::read_eigenvalues(seedname + ".eig");
53
54 const int number_of_kpoints = projections.number_of_kpoints;
55 if (eigenvalues.number_of_kpoints != number_of_kpoints) {
56 throw std::runtime_error("import_wannier90_files: the .eig and .amn disagree on the "
57 "k-point count (" +
58 std::to_string(eigenvalues.number_of_kpoints) + " vs " +
59 std::to_string(number_of_kpoints) + ")");
60 }
61 if (eigenvalues.number_of_bands != projections.number_of_bands) {
62 throw std::runtime_error(
63 "import_wannier90_files: the .eig and .amn disagree on the band count (" +
64 std::to_string(eigenvalues.number_of_bands) + " vs " +
65 std::to_string(projections.number_of_bands) +
66 "); the gauge would be applied to the wrong eigenvalues");
67 }
68 if (static_cast<int>(neighbor_list.kpoints.size()) != number_of_kpoints) {
69 throw std::runtime_error("import_wannier90_files: the .nnkp and .amn disagree on the "
70 "k-point count (" +
71 std::to_string(neighbor_list.kpoints.size()) + " vs " +
72 std::to_string(number_of_kpoints) + ")");
73 }
74 if (grid[0] * grid[1] * grid[2] != number_of_kpoints) {
75 throw std::runtime_error("import_wannier90_files: a " + std::to_string(grid[0]) + "x" +
76 std::to_string(grid[1]) + "x" + std::to_string(grid[2]) +
77 " grid implies " + std::to_string(grid[0] * grid[1] * grid[2]) +
78 " k-points, but the files hold " +
79 std::to_string(number_of_kpoints));
80 }
81
83 record.method = "wannier";
84 for (int row = 0; row < 3; row++) {
85 record.real_lattice_bohr[row] =
86 neighbor_list.real_lattice[row] * constants::ANGSTROM_TO_BOHR;
88 neighbor_list.reciprocal_lattice[row] * constants::BOHR_RADIUS_ANGSTROM;
89 }
90
91 WannierInputs& wannier = record.wannier;
92 wannier.kpoint_grid_dimensions = grid;
93 wannier.kpoint_coordinates = neighbor_list.kpoints;
94 wannier.number_of_bands = projections.number_of_bands;
95 wannier.number_of_trial_orbitals = projections.number_of_wannier_functions;
96 wannier.projection_matrices = projections.projections;
97 wannier.eigenvalues_rydberg = eigenvalues.eigenvalues_rydberg;
98
99 /// p_nk = sum_m |A_mn|^2 over the trial orbitals, same layout the builder writes.
100 wannier.projectabilities.resize(static_cast<std::size_t>(number_of_kpoints));
101 for (int kpoint_index = 0; kpoint_index < number_of_kpoints; kpoint_index++) {
102 std::vector<Real>& row = wannier.projectabilities[kpoint_index];
103 row.assign(static_cast<std::size_t>(wannier.number_of_bands), 0.0);
104 const std::vector<Complex>& block = wannier.projection_matrices[kpoint_index];
105 for (int band = 0; band < wannier.number_of_bands; band++) {
106 for (int orbital = 0; orbital < wannier.number_of_trial_orbitals; orbital++) {
107 row[band] += std::norm(block[orbital * wannier.number_of_bands + band]);
108 }
109 }
110 }
111 return record;
112}
113
114} // namespace q3
static ProjectionData read_projections(const std::string &file_path)
Definition reader.hpp:262
static EigenvalueData read_eigenvalues(const std::string &file_path)
Definition reader.hpp:333
static NeighborListData read_neighbor_list(const std::string &file_path)
Definition reader.hpp:134
constexpr Real ANGSTROM_TO_BOHR
Ångström → Bohr (ANGSTROM_AU)
constexpr Real BOHR_RADIUS_ANGSTROM
Bohr radius in Ångströms (BOHR_RADIUS_SI * 1e10; BOHR_RADIUS_ANGSTROM)
InterpolationRecord import_wannier90_files(const std::string &seedname, const std::array< int, 3 > &grid)
Definition importer.hpp:42
WannierInputs wannier
Payload for method == "wannier": interface matrices on the full k-grid.
Definition record.hpp:46
Matrix3x3 real_lattice_bohr
Rows a1, a2, a3, Cartesian, in bohr.
Definition record.hpp:34
std::string method
The method that built the payload: "wannier".
Definition record.hpp:31
Matrix3x3 reciprocal_lattice_inverse_bohr
Rows b1, b2, b3, Cartesian, in inverse bohr, with the 2 pi included.
Definition record.hpp:36
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::vector< std::vector< Real > > projectabilities
p_nk = sum_m |A_mn(k)|^2, indexed [kpoint_index][band_index].
Definition inputs.hpp:76
std::array< int, 3 > kpoint_grid_dimensions
Definition inputs.hpp:37
int number_of_trial_orbitals
Definition inputs.hpp:72
std::vector< std::vector< Complex > > projection_matrices
Definition inputs.hpp:68