Loading...
Searching...
No Matches
payload.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * The Wannier method's payload inside an interpolation record: WannierInputs
5 * to bytes and back.
6 *
7 * Split from the envelope in `io/interpolation/checkpoint.hpp` because it is
8 * the one part of that file that knows a method. The envelope holds what every
9 * record has -- magic, version, method name, lattice, Fermi level -- and
10 * dispatches to a payload; a second method adds a file beside this one and a
11 * case there, and touches nothing else.
12 *
13 * `wannier/` is the METHOD, not the file format: `wannier90/` beside it holds
14 * the interchange format that another code reads. This payload is Q3's own
15 * `.q3ip` layout and is not interchangeable with anything.
16 *
17 * Layout, in order: the grid, band, trial-orbital and spin counts, the Fermi
18 * level, the k-points, the neighbour directions, the overlaps, the
19 * projections, the eigenvalues, the projectabilities, the trial-orbital
20 * centres. Anything added here is a
21 * format change and needs the envelope's version bumped: a field added without
22 * one decodes as garbage in a consumer far from the mistake.
23 */
24
25#include <cstddef>
26#include <cstdint>
27#include <istream>
28#include <ostream>
29#include <stdexcept>
30#include <string>
31#include <vector>
32
37
39
41
42inline void write(std::ostream& stream, const WannierInputs& record) {
43 for (int axis = 0; axis < 3; axis++) {
44 write_scalar<int32_t>(stream, record.kpoint_grid_dimensions[axis]);
45 }
46 write_scalar<int32_t>(stream, record.number_of_bands);
47 write_scalar<int32_t>(stream, record.number_of_trial_orbitals);
48 write_scalar<int32_t>(stream, record.number_of_spin_components);
49 write_scalar<double>(stream, record.fermi_energy_rydberg);
50
51 write_scalar<int64_t>(stream, static_cast<int64_t>(record.kpoint_coordinates.size()));
52 for (const Vector3D& kpoint : record.kpoint_coordinates) {
53 write_vector3d(stream, kpoint);
54 }
55
56 write_scalar<int64_t>(stream, static_cast<int64_t>(record.neighbor_directions.size()));
57 for (const KPointNeighborDirection& direction : record.neighbor_directions) {
58 write_scalar<int32_t>(stream, direction.grid_step.x);
59 write_scalar<int32_t>(stream, direction.grid_step.y);
60 write_scalar<int32_t>(stream, direction.grid_step.z);
61 write_vector3d(stream, direction.reciprocal_lattice_translation);
62 write_scalar<double>(stream, direction.weight);
63 }
64
65 write_scalar<int64_t>(stream, static_cast<int64_t>(record.overlap_matrices.size()));
66 for (const auto& per_direction : record.overlap_matrices) {
67 write_nested_arrays(stream, per_direction);
68 }
72 /**
73 * Format version 2: the trial-orbital centres. Zero of them is a legitimate
74 * count -- a record imported from projections and eigenvalues has none.
75 */
76 write_scalar<int64_t>(stream, static_cast<int64_t>(record.trial_orbital_centers_bohr.size()));
77 for (const Vector3D& center : record.trial_orbital_centers_bohr) {
78 write_vector3d(stream, center);
79 }
80}
81
82inline WannierInputs read(std::istream& stream) {
83 WannierInputs record;
84 for (int axis = 0; axis < 3; axis++) {
85 record.kpoint_grid_dimensions[axis] = read_scalar<int32_t>(stream);
86 }
87 record.number_of_bands = read_scalar<int32_t>(stream);
88 record.number_of_trial_orbitals = read_scalar<int32_t>(stream);
89 record.number_of_spin_components = read_scalar<int32_t>(stream);
90 record.fermi_energy_rydberg = read_scalar<double>(stream);
91 for (int axis = 0; axis < 3; axis++) {
92 if (record.kpoint_grid_dimensions[axis] <= 0) {
93 throw std::runtime_error("interpolation record: non-positive k-point grid dimension; "
94 "the file is corrupt.");
95 }
96 }
97 if (record.number_of_bands <= 0 || record.number_of_trial_orbitals <= 0) {
98 throw std::runtime_error("interpolation record: non-positive band or trial-orbital "
99 "count; the file is corrupt.");
100 }
101
102 const int64_t number_of_kpoints = read_scalar<int64_t>(stream);
103 if (number_of_kpoints < 0) {
104 throw std::runtime_error("interpolation record: negative k-point count; the file is "
105 "corrupt.");
106 }
107 if (static_cast<int64_t>(record.kpoint_grid_dimensions[0]) * record.kpoint_grid_dimensions[1] *
108 record.kpoint_grid_dimensions[2] !=
109 number_of_kpoints) {
110 throw std::runtime_error("interpolation record: the k-point count does not match the "
111 "grid dimensions; the file is corrupt.");
112 }
114 static_cast<std::uint64_t>(number_of_kpoints) * 3 * sizeof(double));
115 record.kpoint_coordinates.reserve(static_cast<std::size_t>(number_of_kpoints));
116 for (int64_t index = 0; index < number_of_kpoints; index++) {
117 record.kpoint_coordinates.push_back(read_vector3d(stream));
118 }
119
120 const int64_t number_of_directions = read_scalar<int64_t>(stream);
121 if (number_of_directions < 0) {
122 throw std::runtime_error("interpolation record: negative neighbour count; the file is "
123 "corrupt.");
124 }
126 static_cast<std::uint64_t>(number_of_directions) *
127 (3 * sizeof(int32_t) + 3 * sizeof(double) + sizeof(double)));
128 for (int64_t index = 0; index < number_of_directions; index++) {
129 KPointNeighborDirection direction;
130 direction.grid_step.x = read_scalar<int32_t>(stream);
131 direction.grid_step.y = read_scalar<int32_t>(stream);
132 direction.grid_step.z = read_scalar<int32_t>(stream);
134 direction.weight = read_scalar<double>(stream);
135 record.neighbor_directions.push_back(direction);
136 }
137
138 const int64_t overlap_kpoints = read_scalar<int64_t>(stream);
139 if (overlap_kpoints < 0) {
140 throw std::runtime_error("interpolation record: negative overlap count; the file is "
141 "corrupt.");
142 }
143 require_bytes_available(stream, static_cast<std::uint64_t>(overlap_kpoints) * sizeof(int64_t));
144 record.overlap_matrices.reserve(static_cast<std::size_t>(overlap_kpoints));
145 for (int64_t index = 0; index < overlap_kpoints; index++) {
146 record.overlap_matrices.push_back(read_nested_arrays<Complex>(stream));
147 }
148 record.projection_matrices = read_nested_arrays<Complex>(stream);
149 record.eigenvalues_rydberg = read_nested_arrays<Real>(stream);
150 record.projectabilities = read_nested_arrays<Real>(stream);
151 const int64_t number_of_centers = read_scalar<int64_t>(stream);
152 if (number_of_centers != 0 && number_of_centers != record.number_of_trial_orbitals) {
153 throw std::runtime_error("interpolation record: " + std::to_string(number_of_centers) +
154 " trial-orbital centres for " +
155 std::to_string(record.number_of_trial_orbitals) +
156 " trial orbitals; the file is corrupt.");
157 }
158 record.trial_orbital_centers_bohr.clear();
159 for (int64_t index = 0; index < number_of_centers; index++) {
160 record.trial_orbital_centers_bohr.push_back(read_vector3d(stream));
161 }
162
163 /**
164 * Every per-k array either covers the k-point list or is absent -- an
165 * imported record carries no overlaps -- and nothing in between; a partial
166 * one would misassign k-points silently downstream.
167 */
168 auto check_coverage = [&](std::size_t count, const char* name) {
169 if (count != 0 && count != record.kpoint_coordinates.size()) {
170 throw std::runtime_error(std::string("interpolation record: ") + name + " cover " +
171 std::to_string(count) + " k-points, the record has " +
172 std::to_string(record.kpoint_coordinates.size()) +
173 "; the file is corrupt.");
174 }
175 };
176 check_coverage(record.overlap_matrices.size(), "the overlaps");
177 check_coverage(record.projection_matrices.size(), "the projections");
178 check_coverage(record.eigenvalues_rydberg.size(), "the eigenvalues");
179 check_coverage(record.projectabilities.size(), "the projectabilities");
180
181 /**
182 * Shapes inside each k-point, too. A file whose layout drifted from this
183 * reader's (a field added without a version bump, a truncated write)
184 * decodes into plausible-looking counts with impossible blocks; refusing
185 * here names the file, where a consumer's later out-of-range access
186 * would name nothing.
187 */
188 if (record.number_of_bands <= 0 || record.number_of_trial_orbitals < 0) {
189 throw std::runtime_error("interpolation record: impossible band or orbital count; the "
190 "file is corrupt or predates this reader's format.");
191 }
192 const std::size_t projection_block =
193 static_cast<std::size_t>(record.number_of_bands) * record.number_of_trial_orbitals;
194 for (const std::vector<Complex>& block : record.projection_matrices) {
195 if (block.size() != projection_block) {
196 throw std::runtime_error("interpolation record: a projection block has " +
197 std::to_string(block.size()) + " entries, expected " +
198 std::to_string(projection_block) +
199 "; the file is corrupt or predates this reader's format.");
200 }
201 }
202 for (const std::vector<Real>& row : record.eigenvalues_rydberg) {
203 if (row.size() != static_cast<std::size_t>(record.number_of_bands)) {
204 throw std::runtime_error("interpolation record: an eigenvalue row has " +
205 std::to_string(row.size()) + " entries, expected " +
206 std::to_string(record.number_of_bands) +
207 "; the file is corrupt or predates this reader's format.");
208 }
209 }
210 return record;
211}
212
213} // namespace q3::internal::wannier_payload
void write_nested_arrays(std::ostream &stream, const std::vector< std::vector< ValueType > > &rows)
Vector3D read_vector3d(std::istream &stream)
void require_bytes_available(std::istream &stream, std::uint64_t bytes)
void write_vector3d(std::ostream &stream, const Vector3D &vector)
WannierInputs read(std::istream &stream)
Definition payload.hpp:82
void write(std::ostream &stream, const WannierInputs &record)
Definition payload.hpp:42
std::vector< KPointNeighborDirection > neighbor_directions
Definition inputs.hpp:49
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< Vector3D > trial_orbital_centers_bohr
Definition inputs.hpp:87
std::vector< std::vector< Real > > projectabilities
p_nk = sum_m |A_mn(k)|^2, indexed [kpoint_index][band_index].
Definition inputs.hpp:76
Real fermi_energy_rydberg
Definition inputs.hpp:77
std::array< int, 3 > kpoint_grid_dimensions
Definition inputs.hpp:37
int number_of_trial_orbitals
Definition inputs.hpp:72
int number_of_spin_components
Definition inputs.hpp:78
std::vector< std::vector< Complex > > projection_matrices
Definition inputs.hpp:68
std::vector< std::vector< std::vector< Complex > > > overlap_matrices
Definition inputs.hpp:60