Loading...
Searching...
No Matches
q3.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * Q3PlanewaveKohnShamQuantumSystemCheckpoint — Q3 native format.
5 *
6 * Serializes and deserializes the full SCF state (header, charge density,
7 * eigenvalues, and optionally wavefunctions) to/from a binary file.
8 * File format: magic number + version, then raw arrays. Version 2 added the
9 * effective potential; version 3 adds the PAW on-site occupations after it,
10 * which a version-2 file lacks and reads back as empty.
11 *
12 * Implements save/load from KohnShamQuantumSystemCheckpoint. When
13 * save_wavefunctions is true, the snapshot must be a
14 * PlanewaveKohnShamQuantumSystemSnapshot (dynamic_cast).
15 */
16
17#include <cstdint>
18#include <fstream>
19#include <string>
20#include <vector>
21
22#include "io/logger.hpp"
24
25namespace q3 {
26
28 public:
29 static constexpr uint32_t MAGIC = 0x51334350; // "Q3CP"
30 static constexpr uint32_t VERSION = 3;
31
32 bool save(const std::string& filename,
33 const KohnShamQuantumSystemSnapshot& snapshot,
34 bool save_wavefunctions = false) const override {
35 std::ofstream file_stream(filename, std::ios::binary);
36 if (!file_stream.is_open())
37 return false;
38
39 write_header(file_stream, snapshot, save_wavefunctions);
40 write_charge_density(file_stream, snapshot);
41 write_eigenvalues(file_stream, snapshot);
42 write_effective_potential(file_stream, snapshot);
43 write_one_center_occupations(file_stream, snapshot);
44
45 if (save_wavefunctions) {
46 const auto* planewave_snapshot =
47 dynamic_cast<const PlanewaveKohnShamQuantumSystemSnapshot*>(&snapshot);
48 if (planewave_snapshot) {
49 write_wavefunctions(file_stream, *planewave_snapshot);
50 }
51 }
52
53 return file_stream.good();
54 }
55
56 bool load(const std::string& filename, KohnShamQuantumSystemSnapshot& snapshot) const override {
57 std::ifstream file_stream(filename, std::ios::binary);
58 if (!file_stream.is_open())
59 return false;
60
61 uint8_t has_wavefunctions = 0;
62 uint32_t file_version = 0;
63 if (!read_header(file_stream, snapshot, has_wavefunctions, file_version))
64 return false;
65
66 read_charge_density(file_stream, snapshot);
67 read_eigenvalues(file_stream, snapshot);
68
69 // V_eff is present only in v2+. Leave empty for v1 — NSCF will reconstruct.
70 if (file_version >= 2) {
71 read_effective_potential(file_stream, snapshot);
72 }
73 // The PAW on-site occupations are present only in v3+; an older file leaves them empty.
74 if (file_version >= 3) {
75 read_one_center_occupations(file_stream, snapshot);
76 }
77
78 if (has_wavefunctions) {
79 auto* planewave_snapshot =
80 dynamic_cast<PlanewaveKohnShamQuantumSystemSnapshot*>(&snapshot);
81 if (planewave_snapshot) {
82 read_wavefunctions(file_stream, *planewave_snapshot);
83 }
84 }
85
86 return file_stream.good();
87 }
88
89 private:
90 template <typename T> static void write_value(std::ofstream& file_stream, const T& value) {
91 file_stream.write(reinterpret_cast<const char*>(&value), sizeof(T));
92 }
93
94 template <typename T> static void read_value(std::ifstream& file_stream, T& value) {
95 file_stream.read(reinterpret_cast<char*>(&value), sizeof(T));
96 }
97
98 static void write_header(std::ofstream& file_stream,
99 const KohnShamQuantumSystemSnapshot& snapshot,
100 bool save_wavefunctions) {
101 write_value(file_stream, MAGIC);
102 write_value(file_stream, VERSION);
103 write_value(file_stream, snapshot.iteration);
104 write_value(file_stream, snapshot.number_of_spin_components);
105 write_value(file_stream, snapshot.number_of_bands);
106 write_value(file_stream, snapshot.number_of_kpoint_states);
107 write_value(file_stream, snapshot.total_energy);
108 write_value(file_stream, snapshot.converged);
109 uint8_t has_wavefunctions = save_wavefunctions ? 1 : 0;
110 write_value(file_stream, has_wavefunctions);
111 }
112
113 static void write_charge_density(std::ofstream& file_stream,
114 const KohnShamQuantumSystemSnapshot& snapshot) {
115 int number_of_spin_density_components =
116 static_cast<int>(snapshot.charge_density_real.size());
117 write_value(file_stream, number_of_spin_density_components);
118 for (const auto& density_component : snapshot.charge_density_real) {
119 int number_of_grid_points = static_cast<int>(density_component.size());
120 write_value(file_stream, number_of_grid_points);
121 file_stream.write(reinterpret_cast<const char*>(density_component.data()),
122 number_of_grid_points * sizeof(Real));
123 }
124 }
125
126 static void write_eigenvalues(std::ofstream& file_stream,
127 const KohnShamQuantumSystemSnapshot& snapshot) {
128 for (size_t kpoint_state_index = 0; kpoint_state_index < snapshot.eigenvalues.rows();
129 kpoint_state_index++) {
130 int number_of_bands_column = static_cast<int>(snapshot.eigenvalues.cols());
131 write_value(file_stream, number_of_bands_column);
132 file_stream.write(
133 reinterpret_cast<const char*>(snapshot.eigenvalues[kpoint_state_index]),
134 number_of_bands_column * sizeof(Real));
135 }
136 }
137
138 static void write_wavefunctions(std::ofstream& file_stream,
139 const PlanewaveKohnShamQuantumSystemSnapshot& snapshot) {
140 for (const auto& kpoint_bands : snapshot.wavefunction_coefficients) {
141 for (const auto& band : kpoint_bands) {
142 int number_of_plane_waves = static_cast<int>(band.size());
143 write_value(file_stream, number_of_plane_waves);
144 file_stream.write(reinterpret_cast<const char*>(band.data()),
145 number_of_plane_waves * sizeof(Complex));
146 }
147 }
148 }
149
150 static bool read_header(std::ifstream& file_stream,
151 KohnShamQuantumSystemSnapshot& snapshot,
152 uint8_t& has_wavefunctions,
153 uint32_t& file_version) {
154 uint32_t magic, version;
155 read_value(file_stream, magic);
156 read_value(file_stream, version);
157 if (magic != MAGIC || version < 1 || version > VERSION)
158 return false;
159
160 file_version = version;
161 read_value(file_stream, snapshot.iteration);
162 read_value(file_stream, snapshot.number_of_spin_components);
163 read_value(file_stream, snapshot.number_of_bands);
164 read_value(file_stream, snapshot.number_of_kpoint_states);
165 read_value(file_stream, snapshot.total_energy);
166 read_value(file_stream, snapshot.converged);
167 read_value(file_stream, has_wavefunctions);
168 return true;
169 }
170
171 static void read_charge_density(std::ifstream& file_stream,
172 KohnShamQuantumSystemSnapshot& snapshot) {
173 int number_of_spin_density_components;
174 read_value(file_stream, number_of_spin_density_components);
175 if (number_of_spin_density_components != snapshot.number_of_spin_components) {
177 "Checkpoint corrupt: header declares {} spin component(s) but charge density "
178 "section has {}.",
179 snapshot.number_of_spin_components,
180 number_of_spin_density_components);
181 file_stream.setstate(std::ios::failbit);
182 return;
183 }
184 snapshot.charge_density_real.resize(number_of_spin_density_components);
185 for (auto& density_component : snapshot.charge_density_real) {
186 int number_of_grid_points;
187 read_value(file_stream, number_of_grid_points);
188 density_component.resize(number_of_grid_points);
189 file_stream.read(reinterpret_cast<char*>(density_component.data()),
190 number_of_grid_points * sizeof(Real));
191 }
192 }
193
194 static void read_eigenvalues(std::ifstream& file_stream,
195 KohnShamQuantumSystemSnapshot& snapshot) {
196 snapshot.eigenvalues.resize(
197 snapshot.number_of_kpoint_states, snapshot.number_of_bands, 0.0);
198 for (int kpoint_state_index = 0; kpoint_state_index < snapshot.number_of_kpoint_states;
199 kpoint_state_index++) {
200 int number_of_bands_column;
201 read_value(file_stream, number_of_bands_column);
202 if (number_of_bands_column != snapshot.number_of_bands) {
203 log::error("Checkpoint corrupt: header declares {} band(s) per k-point but "
204 "eigenvalue row {} has {}.",
205 snapshot.number_of_bands,
206 kpoint_state_index,
207 number_of_bands_column);
208 file_stream.setstate(std::ios::failbit);
209 return;
210 }
211 file_stream.read(reinterpret_cast<char*>(snapshot.eigenvalues[kpoint_state_index]),
212 number_of_bands_column * sizeof(Real));
213 }
214 }
215
216 static void write_effective_potential(std::ofstream& file_stream,
217 const KohnShamQuantumSystemSnapshot& snapshot) {
218 int number_of_spin_components = static_cast<int>(snapshot.effective_potential_real.size());
219 write_value(file_stream, number_of_spin_components);
220 for (const auto& potential_component : snapshot.effective_potential_real) {
221 int number_of_grid_points = static_cast<int>(potential_component.size());
222 write_value(file_stream, number_of_grid_points);
223 file_stream.write(reinterpret_cast<const char*>(potential_component.data()),
224 number_of_grid_points * sizeof(Real));
225 }
226 }
227
228 static void read_effective_potential(std::ifstream& file_stream,
229 KohnShamQuantumSystemSnapshot& snapshot) {
230 int number_of_spin_components;
231 read_value(file_stream, number_of_spin_components);
232 snapshot.effective_potential_real.resize(number_of_spin_components);
233 for (auto& potential_component : snapshot.effective_potential_real) {
234 int number_of_grid_points;
235 read_value(file_stream, number_of_grid_points);
236 potential_component.resize(number_of_grid_points);
237 file_stream.read(reinterpret_cast<char*>(potential_component.data()),
238 number_of_grid_points * sizeof(Real));
239 }
240 }
241
242 static void write_one_center_occupations(std::ofstream& file_stream,
243 const KohnShamQuantumSystemSnapshot& snapshot) {
244 int number_of_spin_components = static_cast<int>(snapshot.one_center_occupations.size());
245 write_value(file_stream, number_of_spin_components);
246 for (const auto& occupations : snapshot.one_center_occupations) {
247 int number_of_atoms = static_cast<int>(occupations.rows());
248 int row_length = static_cast<int>(occupations.cols());
249 write_value(file_stream, number_of_atoms);
250 write_value(file_stream, row_length);
251 file_stream.write(reinterpret_cast<const char*>(occupations.raw().data()),
252 occupations.raw().size() * sizeof(Real));
253 }
254 }
255
256 static void read_one_center_occupations(std::ifstream& file_stream,
257 KohnShamQuantumSystemSnapshot& snapshot) {
258 int number_of_spin_components;
259 read_value(file_stream, number_of_spin_components);
260 if (!file_stream.good() || number_of_spin_components < 0 || number_of_spin_components > 2) {
261 log::error("Checkpoint corrupt: the on-site occupation section declares {} spin "
262 "component(s).",
263 number_of_spin_components);
264 file_stream.setstate(std::ios::failbit);
265 return;
266 }
267 snapshot.one_center_occupations.assign(number_of_spin_components, {});
268 for (auto& occupations : snapshot.one_center_occupations) {
269 int number_of_atoms;
270 int row_length;
271 read_value(file_stream, number_of_atoms);
272 read_value(file_stream, row_length);
273 if (!file_stream.good() || number_of_atoms < 0 || row_length < 0) {
274 log::error("Checkpoint corrupt: on-site occupations declared as {} atom(s) by "
275 "{} entries.",
276 number_of_atoms,
277 row_length);
278 file_stream.setstate(std::ios::failbit);
279 return;
280 }
281 occupations.assign(number_of_atoms, row_length, 0.0);
282 file_stream.read(reinterpret_cast<char*>(occupations.raw().data()),
283 occupations.raw().size() * sizeof(Real));
284 }
285 }
286
287 static void read_wavefunctions(std::ifstream& file_stream,
288 PlanewaveKohnShamQuantumSystemSnapshot& snapshot) {
289 snapshot.wavefunction_coefficients.resize(snapshot.number_of_kpoint_states);
290 for (auto& kpoint_bands : snapshot.wavefunction_coefficients) {
291 kpoint_bands.resize(snapshot.number_of_bands);
292 for (auto& band : kpoint_bands) {
293 int number_of_plane_waves;
294 read_value(file_stream, number_of_plane_waves);
295 band.resize(number_of_plane_waves);
296 file_stream.read(reinterpret_cast<char*>(band.data()),
297 number_of_plane_waves * sizeof(Complex));
298 }
299 }
300 }
301};
302
303} // namespace q3
bool save(const std::string &filename, const KohnShamQuantumSystemSnapshot &snapshot, bool save_wavefunctions=false) const override
Definition q3.hpp:32
bool load(const std::string &filename, KohnShamQuantumSystemSnapshot &snapshot) const override
Definition q3.hpp:56
static constexpr uint32_t MAGIC
Definition q3.hpp:29
static constexpr uint32_t VERSION
Definition q3.hpp:30
void error(spdlog::format_string_t< Args... > fmt, Args &&... args)
Definition logger.hpp:192
constexpr const char * version
Definition version.hpp:26
double Real
std::complex< double > Complex