74 std::ofstream output_file(file_path, std::ios::binary);
75 if (!output_file.is_open()) {
76 throw std::runtime_error(
"cannot open " + file_path +
" for writing");
80 header.
write(output_file);
86 write_atom_species_record(output_file);
87 write_projectors_per_species_record(output_file);
88 write_nonlocal_coefficients_record(output_file);
90 write_body(output_file, record_writer);
92 log::info(
" Wrote BerkeleyGW Kleinman-Bylander projector file: {}", file_path);
99 void check_record()
const {
101 throw std::runtime_error(
"the mean-field record carries no projectors; request them "
102 "with control.mean_field_export_kleinman_bylander_projectors");
107 throw std::runtime_error(
"the mean-field record's nonlocal pseudopotential does not "
108 "match its atoms and spin channels");
113 [[nodiscard]] std::array<int32_t, 3> projector_dimensions()
const {
114 int32_t number_of_projectors = 0;
115 for (
int species_index : record_.atom_species_indices) {
118 int32_t maximum_projectors_per_atom =
124 number_of_projectors,
125 maximum_projectors_per_atom};
129 void write_atom_species_record(std::ofstream& output_file)
const {
131 for (
size_t atom_index = 0; atom_index < species.size(); atom_index++) {
135 output_file, species.data(),
static_cast<int32_t
>(species.size() *
sizeof(int32_t)));
139 void write_projectors_per_species_record(std::ofstream& output_file)
const {
143 output_file, counts.data(),
static_cast<int32_t
>(counts.size() *
sizeof(int32_t)));
147 void write_nonlocal_coefficients_record(std::ofstream& output_file)
const {
148 const size_t maximum_channels =
static_cast<size_t>(projector_dimensions()[2]);
149 const size_t number_of_atoms =
static_cast<size_t>(record_.
number_of_atoms());
150 const size_t block_size = maximum_channels * maximum_channels;
151 std::vector<double> coefficients(
154 for (
size_t atom_index = 0; atom_index < number_of_atoms; atom_index++) {
156 size_t number_of_channels =
static_cast<size_t>(
158 double* destination =
159 coefficients.data() + block_size * (atom_index + number_of_atoms * spin_index);
160 for (
size_t channel_j = 0; channel_j < number_of_channels; channel_j++) {
161 for (
size_t channel_i = 0; channel_i < number_of_channels; channel_i++) {
162 destination[channel_i + maximum_channels * channel_j] =
163 block[channel_i + number_of_channels * channel_j];
170 static_cast<int32_t
>(coefficients.size() *
sizeof(double)));
179 void write_body(std::ofstream& output_file,
const BerkeleyGWRecordWriter& record_writer)
const {
180 std::vector<int> first_projector_of_atom(record_.
number_of_atoms() + 1, 0);
181 for (
int atom_index = 0; atom_index < record_.
number_of_atoms(); atom_index++) {
182 first_projector_of_atom[atom_index + 1] =
183 first_projector_of_atom[atom_index] +
187 for (
int kpoint_index = 0; kpoint_index < record_.
number_of_kpoints(); kpoint_index++) {
188 record_writer.write_kpoint_gvectors(output_file, kpoint_index);
191 const Matrix<Complex>& projectors = record_.
projector_source->projectors(kpoint_index);
192 if (
static_cast<int>(projectors.rows()) != first_projector_of_atom.back() ||
193 static_cast<int32_t
>(projectors.cols()) != number_of_plane_waves) {
194 throw std::runtime_error(
"the projector source returned a " +
195 std::to_string(projectors.rows()) +
" x " +
196 std::to_string(projectors.cols()) +
" matrix at k-point " +
197 std::to_string(kpoint_index) +
", expected " +
198 std::to_string(first_projector_of_atom.back()) +
" x " +
199 std::to_string(number_of_plane_waves));
203 for (
int species_index = 0;
206 for (
int atom_index = 0; atom_index < record_.
number_of_atoms(); atom_index++) {
210 for (
int projector_index = first_projector_of_atom[atom_index];
211 projector_index < first_projector_of_atom[atom_index + 1];
213 record_writer.write_complex_block(output_file,
214 number_of_plane_waves,
215 projectors[projector_index],
216 number_of_plane_waves);