47 "Usage: q3_utility convert <save-directory> [--format <name>] [--outdir <directory>]");
49 " q3_utility convert --from wannier90 --seedname <s> --grid <nx> <ny> <nz> "
50 "[--outdir <directory>] [--prefix <p>]");
51 log::error(
" <save-directory> a run's <prefix>.save directory, holding mean-field.q3mf "
52 "and/or interpolation.q3ip");
53 log::error(
" --format berkeleygw (from the mean-field record) or wannier90 (from "
54 "the interpolation record);");
55 log::error(
" defaults to the one format the directory's record allows");
56 log::error(
" --outdir where to write (default: the save directory's parent, or . "
58 log::error(
" --from wannier90 import <seedname>.amn/.eig/.nnkp on --grid into "
59 "<outdir>/<prefix>.save/interpolation.q3ip");
60 log::error(
" --prefix the run prefix an import is filed under (default: the "
61 "seedname's basename)");
65 static int run(
const std::vector<std::string>& arguments) {
66 std::string save_directory;
68 std::string output_directory;
72 std::array<int, 3> grid = {0, 0, 0};
73 for (std::size_t index = 0; index < arguments.size(); index++) {
74 const std::string& argument = arguments[index];
75 auto take_value = [&](
const char* flag) -> std::string {
76 if (index + 1 >= arguments.size()) {
77 throw std::runtime_error(std::string(flag) +
" needs a value");
79 return arguments[++index];
81 if (argument ==
"--format") {
82 format = take_value(
"--format");
83 }
else if (argument ==
"--outdir") {
84 output_directory = take_value(
"--outdir");
85 }
else if (argument ==
"--from") {
86 from = take_value(
"--from");
87 }
else if (argument ==
"--seedname") {
88 seedname = take_value(
"--seedname");
89 }
else if (argument ==
"--prefix") {
90 prefix = take_value(
"--prefix");
91 }
else if (argument ==
"--grid") {
92 for (
int axis = 0; axis < 3; axis++) {
93 grid[axis] = parse_positive_integer(
"--grid", take_value(
"--grid"));
95 }
else if (argument ==
"-h" || argument ==
"--help") {
98 }
else if (argument.rfind(
"-", 0) == 0) {
102 }
else if (save_directory.empty()) {
103 save_directory = argument;
105 log::error(
"Unexpected extra argument '{}'", argument);
112 return import_record(from, seedname, grid, output_directory, prefix);
114 if (save_directory.empty()) {
118 return export_record(save_directory, format, output_directory);
122 static int parse_positive_integer(
const char* flag,
const std::string& text) {
123 std::size_t consumed = 0;
126 value = std::stoi(text, &consumed);
127 }
catch (
const std::exception&) {
128 throw std::runtime_error(std::string(flag) +
" expects positive integers, got '" +
131 if (consumed != text.size() || value <= 0) {
132 throw std::runtime_error(std::string(flag) +
" expects positive integers, got '" +
138 static int import_record(
const std::string& from,
139 const std::string& seedname,
140 const std::array<int, 3>& grid,
141 const std::string& output_directory,
142 const std::string& prefix) {
143 if (from !=
"wannier90") {
144 throw std::runtime_error(
"--from supports only wannier90, not '" + from +
"'");
146 if (seedname.empty() || grid[0] <= 0) {
147 throw std::runtime_error(
148 "--from wannier90 needs --seedname <s> (the files are <s>.amn/.eig/.nnkp) and "
149 "--grid nx ny nz (a .nnkp lists k-points without saying what grid they came "
153 const std::string prefix_name =
154 prefix.empty() ? std::filesystem::path(seedname).filename().string() : prefix;
155 const std::string directory =
156 output_directory.empty() ? std::string(
".") : output_directory;
157 std::filesystem::create_directories(directory +
"/" + prefix_name +
".save");
160 log::info(
"Imported {} k-points, {} bands, {} Wannier functions from {}.amn/.eig/.nnkp "
162 record.wannier.number_of_kpoints(),
163 record.wannier.number_of_bands,
164 record.wannier.number_of_trial_orbitals,
170 static int export_record(
const std::string& save_directory,
172 std::string output_directory) {
180 std::filesystem::path save_path =
181 std::filesystem::absolute(save_directory).lexically_normal();
182 if (save_path.filename().empty()) {
183 save_path = save_path.parent_path();
185 const std::filesystem::path mean_field_path = save_path /
"mean-field.q3mf";
186 const std::filesystem::path interpolation_path = save_path /
"interpolation.q3ip";
187 const bool has_mean_field = std::filesystem::exists(mean_field_path);
188 const bool has_interpolation = std::filesystem::exists(interpolation_path);
190 if (format.empty()) {
191 if (has_mean_field && has_interpolation) {
192 throw std::runtime_error(
193 "'" + save_directory +
194 "' holds both a mean-field and an interpolation record; say which to "
195 "convert with --format berkeleygw or --format wannier90.");
197 if (has_mean_field) {
198 format =
"berkeleygw";
199 }
else if (has_interpolation) {
200 format =
"wannier90";
206 throw std::runtime_error(
207 "No record in '" + save_directory +
208 "': neither mean-field.q3mf (written by a "
209 "run with control.mean_field_export set to something other than 'none') nor "
210 "interpolation.q3ip (written by an NSCF run with a control.interpolation "
211 "block). Re-run that calculation with the export enabled to produce one.");
215 if (output_directory.empty()) {
216 const std::filesystem::path parent = save_path.parent_path();
217 output_directory = parent.empty() ? std::string(
".") : parent.string();
220 if (format ==
"berkeleygw") {
221 if (!has_mean_field) {
222 throw std::runtime_error(
"No mean-field record at '" + mean_field_path.string() +
223 "'. It is written only by a run that set "
224 "control.mean_field_export to something other than "
225 "'none'; re-run that calculation with the export "
226 "enabled to produce it.");
229 log::info(
"Read mean-field record: {} k-points, {} bands, {} G-vectors",
230 record.number_of_kpoints(),
231 record.number_of_bands,
232 record.number_of_g_vectors());
234 log::info(
"Converted to '{}' in {}", format, output_directory);
237 if (format ==
"wannier90") {
238 if (!has_interpolation) {
239 throw std::runtime_error(
"No interpolation record at '" +
240 interpolation_path.string() +
241 "'. It is written by an NSCF run with a "
242 "control.interpolation block; re-run that NSCF, or "
243 "import Wannier90 files with --from wannier90.");
245 const InterpolationRecord record =
248 std::string prefix_name = save_path.filename().string();
249 const std::string suffix =
".save";
250 if (prefix_name.size() > suffix.size() &&
251 prefix_name.compare(prefix_name.size() - suffix.size(), suffix.size(), suffix) ==
253 prefix_name.erase(prefix_name.size() - suffix.size());
255 log::info(
"Read interpolation record ({}): {} k-points, {} bands",
257 record.wannier.number_of_kpoints(),
258 record.wannier.number_of_bands);
260 record, output_directory, prefix_name);
261 log::info(
"Converted to '{}' in {}", format, output_directory);
264 throw std::runtime_error(
"Unknown format '" + format +
265 "'. Supported: berkeleygw (from the mean-field record), "
266 "wannier90 (from the interpolation record)");