54 log::error(
"Usage: q3_utility interpolate <input.yml> [--output <file>]");
55 log::error(
" <input.yml> a manifest with calculation: interpolation and a "
56 "control.interpolation block;");
57 log::error(
" its control.outdir/prefix name the run whose NSCF saved the "
59 log::error(
" --output <file> where to write the JSON results (default "
60 "<outdir>/<prefix>_interpolation_results.json)");
64 static int run(
const std::vector<std::string>& arguments) {
65 std::string input_file;
66 std::string output_file;
67 for (std::size_t index = 0; index < arguments.size(); index++) {
68 const std::string& argument = arguments[index];
69 auto take_value = [&](
const char* flag) -> std::string {
70 if (index + 1 >= arguments.size()) {
71 throw std::runtime_error(std::string(flag) +
" needs a value");
73 return arguments[++index];
75 if (argument ==
"--output") {
76 output_file = take_value(
"--output");
77 }
else if (argument ==
"-h" || argument ==
"--help") {
80 }
else if (argument.rfind(
"-", 0) == 0) {
84 }
else if (input_file.empty()) {
85 input_file = argument;
87 log::error(
"Unexpected extra argument '{}'", argument);
92 if (input_file.empty()) {
96 evaluate(input_file, output_file);
102 static void evaluate(
const std::string& input_file,
const std::string& output_file) {
103 const InputData input = evaluation_input(input_file);
104 const std::string record_path =
115 document.describe_model(record.
method, record_path, interpolator);
116 document.add_construction(
121 const std::vector<Vector3D> kpoints = evaluation_kpoints(input);
122 if (!kpoints.empty()) {
123 document.add_bands(kpoints,
125 log::info(
"evaluated {} k-points", kpoints.size());
129 document.add_density_of_states(
130 InterpolatedDensityOfStatesCalculator(interpolator)
134 "evaluated a density of states on a {}x{}x{} mesh", mesh[0], mesh[1], mesh[2]);
137 log::warn(
"nothing to evaluate: give control.kpoints_list (or a band_path whose "
138 "vertices carry coordinates) for bands, or control.interpolation.dos_mesh "
139 "for a density of states");
143 "_interpolation_results.json"
148 [[nodiscard]]
static InputData evaluation_input(
const std::string& input_file) {
150 if (input.calculation !=
"interpolation") {
151 throw std::runtime_error(
152 "q3_utility interpolate evaluates inputs with calculation: interpolation; this one "
153 "has calculation: " +
155 ". A build request (calculation: nscf with a control.interpolation block) runs "
156 "with q3, which saves the record this command reads.");
158 if (!input.interpolation.requested()) {
159 throw std::runtime_error(
160 "the input has no control.interpolation block, so there is nothing to evaluate");
166 [[nodiscard]]
static InterpolationRecord
167 saved_record(
const std::string& record_path,
const InterpolationSpecification& specification) {
168 if (!std::filesystem::exists(record_path)) {
169 throw std::runtime_error(
170 "no interpolation record at '" + record_path +
171 "'. An NSCF run (calculation: nscf) whose control.interpolation block asked for "
172 "it writes the record into its own outdir/prefix; point this input's "
173 "control.outdir and control.prefix at that run, or import Wannier90 files with "
174 "`q3_utility convert --from wannier90`.");
177 if (!specification.method.empty() && specification.method != record.method) {
178 throw std::runtime_error(
"the input asks for control.interpolation.method '" +
179 specification.method +
"' but the record at '" + record_path +
180 "' was built by '" + record.method +
"'");
186 [[nodiscard]]
static std::vector<Vector3D> atom_positions_crystal(
const InputData& input) {
187 std::vector<Vector3D> positions;
188 positions.reserve(input.atoms.size());
189 for (
const Atom& atom : input.atoms) {
190 positions.push_back(atom.position);
206 [[nodiscard]]
static std::vector<Vector3D> evaluation_kpoints(
const InputData& input) {
207 std::vector<Vector3D> kpoints;
208 if (!input.kpoints_list.empty()) {
209 kpoints.reserve(input.kpoints_list.size());
210 for (
const auto& entry : input.kpoints_list) {
211 kpoints.push_back(entry.first);
215 if (input.band_path.empty()) {
218 const int per_segment = std::max(1, input.band_path_points_per_segment);
219 for (std::size_t segment = 0; segment + 1 < input.band_path.size(); segment++) {
220 const Vector3D& start = input.band_path[segment].second;
221 const Vector3D& end = input.band_path[segment + 1].second;
222 for (
int step = 0; step < per_segment; step++) {
223 const Real fraction =
static_cast<Real>(step) /
static_cast<Real>(per_segment);
224 kpoints.push_back(start + (end - start) * fraction);
227 kpoints.push_back(input.band_path.back().second);