107 std::streamoff coefficient_block_offset,
109 std::vector<int> plane_waves_per_kpoint)
110 : file_path_(std::move(file_path))
111 , coefficient_block_offset_(coefficient_block_offset)
112 , number_of_bands_(number_of_bands)
113 , plane_waves_per_kpoint_(std::move(plane_waves_per_kpoint)) {
114 kpoint_start_offsets_.resize(plane_waves_per_kpoint_.size() + 1, 0);
115 for (
size_t kpoint_index = 0; kpoint_index < plane_waves_per_kpoint_.size();
117 kpoint_start_offsets_[kpoint_index + 1] =
118 kpoint_start_offsets_[kpoint_index] +
119 static_cast<std::streamoff
>(number_of_bands_) *
120 plane_waves_per_kpoint_[kpoint_index] *
121 static_cast<std::streamoff
>(
sizeof(
Complex));
126 int band_index)
const override {
127 if (kpoint_state_index != cached_kpoint_state_index_) {
128 load_kpoint(kpoint_state_index);
130 int plane_wave_count = plane_waves_per_kpoint_[kpoint_state_index];
131 return cached_coefficients_.data() +
132 static_cast<size_t>(band_index) *
static_cast<size_t>(plane_wave_count);
136 void load_kpoint(
int kpoint_state_index)
const {
137 if (kpoint_state_index < 0 ||
138 kpoint_state_index >=
static_cast<int>(plane_waves_per_kpoint_.size())) {
139 throw std::runtime_error(
"mean-field record: k-point state index " +
140 std::to_string(kpoint_state_index) +
" is out of range.");
142 std::ifstream stream(file_path_, std::ios::binary);
143 if (!stream.is_open()) {
144 throw std::runtime_error(
"mean-field record: cannot reopen '" + file_path_ +
145 "' to read wavefunction coefficients.");
147 int plane_wave_count = plane_waves_per_kpoint_[kpoint_state_index];
148 size_t value_count =
static_cast<size_t>(number_of_bands_) * plane_wave_count;
149 cached_coefficients_.resize(value_count);
150 stream.seekg(coefficient_block_offset_ + kpoint_start_offsets_[kpoint_state_index]);
151 stream.read(
reinterpret_cast<char*
>(cached_coefficients_.data()),
152 static_cast<std::streamsize
>(value_count *
sizeof(
Complex)));
154 throw std::runtime_error(
"mean-field record: '" + file_path_ +
155 "' ended while reading coefficients for k-point state " +
156 std::to_string(kpoint_state_index) +
157 "; the file is truncated or corrupt.");
159 cached_kpoint_state_index_ = kpoint_state_index;
162 std::string file_path_;
163 std::streamoff coefficient_block_offset_;
164 int number_of_bands_;
165 std::vector<int> plane_waves_per_kpoint_;
166 std::vector<std::streamoff> kpoint_start_offsets_;
167 mutable std::vector<Complex> cached_coefficients_;
168 mutable int cached_kpoint_state_index_ = -1;
173 using namespace internal;
174 std::ofstream stream(file_path, std::ios::binary);
175 if (!stream.is_open())
176 throw std::runtime_error(
"mean-field record: cannot open '" + file_path +
"' for writing.");
178 write_scalar<uint32_t>(stream, mean_field_record_magic);
179 write_scalar<uint32_t>(stream, mean_field_record_version);
185 for (
int row = 0; row < 3; row++)
187 for (
int row = 0; row < 3; row++)
190 write_scalar<int64_t>(stream,
static_cast<int64_t
>(record.
atomic_numbers.size()));
192 write_vector3d(stream, position);
197 for (
int row = 0; row < 3; row++)
198 for (
int column = 0; column < 3; column++)
199 write_scalar<int32_t>(stream, operation.rotation[row][column]);
200 for (
int row = 0; row < 3; row++)
201 for (
int column = 0; column < 3; column++)
202 write_scalar<int32_t>(stream, operation.reciprocal_rotation[row][column]);
203 write_vector3d(stream, operation.fractional_translation);
204 write_array(stream, operation.atom_map);
207 for (
int axis = 0; axis < 3; axis++)
214 for (
int axis = 0; axis < 3; axis++)
216 for (
int axis = 0; axis < 3; axis++)
218 write_scalar<int64_t>(stream,
static_cast<int64_t
>(record.
kpoint_coordinates.size()));
220 write_vector3d(stream, coordinates);
225 write_array(stream, indices);
231 write_array(stream, row);
232 write_scalar<int64_t>(stream,
static_cast<int64_t
>(record.
occupations.size()));
234 write_array(stream, row);
236 write_scalar<int64_t>(stream,
static_cast<int64_t
>(record.
charge_density_g.size()));
238 write_array(stream, spin_density);
246 throw std::runtime_error(
"mean-field record: the record has no band source, so its "
247 "wavefunction coefficients cannot be written.");
251 for (
int band_index = 0; band_index < record.
number_of_bands; band_index++) {
252 const Complex* coefficients = record.
band_source->coefficients(state_index, band_index);
253 stream.write(
reinterpret_cast<const char*
>(coefficients),
254 static_cast<std::streamsize
>(plane_wave_count *
sizeof(
Complex)));
259 throw std::runtime_error(
"mean-field record: writing '" + file_path +
"' failed.");
264 using namespace internal;
265 std::ifstream stream(file_path, std::ios::binary);
266 if (!stream.is_open())
267 throw std::runtime_error(
"mean-field record: cannot open '" + file_path +
"' for reading.");
269 uint32_t magic = read_scalar<uint32_t>(stream);
270 if (magic != mean_field_record_magic) {
271 throw std::runtime_error(
"mean-field record: '" + file_path +
272 "' is not a Q3 mean-field record (bad magic number).");
274 uint32_t
version = read_scalar<uint32_t>(stream);
275 if (
version != mean_field_record_version) {
276 throw std::runtime_error(
"mean-field record: '" + file_path +
"' is version " +
277 std::to_string(
version) +
", but this build reads version " +
278 std::to_string(mean_field_record_version) +
279 ". Re-run the calculation to regenerate it.");
287 for (
int row = 0; row < 3; row++)
289 for (
int row = 0; row < 3; row++)
292 int64_t number_of_atoms = read_scalar<int64_t>(stream);
295 position = read_vector3d(stream);
298 int64_t number_of_symmetry_operations = read_scalar<int64_t>(stream);
301 for (
int row = 0; row < 3; row++)
302 for (
int column = 0; column < 3; column++)
303 operation.rotation[row][column] = read_scalar<int32_t>(stream);
304 for (
int row = 0; row < 3; row++)
305 for (
int column = 0; column < 3; column++)
306 operation.reciprocal_rotation[row][column] = read_scalar<int32_t>(stream);
307 operation.fractional_translation = read_vector3d(stream);
308 operation.atom_map = read_array<int>(stream);
311 for (
int axis = 0; axis < 3; axis++)
318 for (
int axis = 0; axis < 3; axis++)
320 for (
int axis = 0; axis < 3; axis++)
322 int64_t number_of_kpoints = read_scalar<int64_t>(stream);
325 coordinates = read_vector3d(stream);
328 int64_t kpoint_g_set_count = read_scalar<int64_t>(stream);
331 indices = read_array<int>(stream);
335 int64_t eigenvalue_row_count = read_scalar<int64_t>(stream);
338 row = read_array<Real>(stream);
339 int64_t occupation_row_count = read_scalar<int64_t>(stream);
340 record.
occupations.resize(
static_cast<size_t>(occupation_row_count));
342 row = read_array<Real>(stream);
344 int64_t spin_channel_count = read_scalar<int64_t>(stream);
347 spin_density = read_array<Complex>(stream);
351 throw std::runtime_error(
"mean-field record: '" + file_path +
352 "' ended before the header was fully read; it is truncated.");
355 record.
band_source = std::make_shared<FileMeanFieldBandSource>(