35 const std::string& pseudopotential_directory) {
37 if (std::filesystem::path(pseudopotential_file).is_absolute()) {
38 return pseudopotential_file;
41 bool already_prepended =
false;
42 if (!pseudopotential_directory.empty() && pseudopotential_directory !=
"." &&
43 pseudopotential_directory !=
"./") {
44 std::string normalized_directory = pseudopotential_directory;
45 if (normalized_directory.back() ==
'/') {
46 normalized_directory.pop_back();
48 if (pseudopotential_file.rfind(normalized_directory, 0) == 0) {
49 already_prepended =
true;
53 if (already_prepended || std::filesystem::exists(pseudopotential_file)) {
54 return pseudopotential_file;
57 std::string full_path = pseudopotential_directory;
58 if (!full_path.empty() && full_path.back() !=
'/') {
61 full_path += pseudopotential_file;
76 const std::string& pseudopotential_directory) {
78 species[species_index].pseudopotential_file, pseudopotential_directory);
79 int dataset_index = 0;
80 for (
int earlier = 0; earlier < species_index; ++earlier) {
82 pseudopotential_directory) == pseudopotential_path)
110 const std::string& pseudopotential_directory) {
111 const std::string remedy =
" Name the functional in the input: model.functional in a YAML "
112 "deck, input_dft in a QE-format deck, or the functional tag "
113 "of the format in use.";
116 for (
const auto& one_species : species) {
117 if (one_species.pseudopotential_file.empty())
121 std::string resolved_functional;
122 std::string resolved_from;
123 for (
int species_index = 0; species_index < static_cast<int>(species.size()); ++species_index) {
125 species[species_index].pseudopotential_file, pseudopotential_directory);
126 const std::string source =
127 pseudopotential_path +
" (" + species[species_index].symbol +
")";
133 pseudopotential_path,
136 }
catch (
const std::exception& error) {
137 throw std::runtime_error(
138 "The input names no exchange-correlation functional, so Q3 takes it from the "
139 "pseudopotentials, and " +
140 source +
" cannot be read: " + error.what());
144 if (functional.empty())
145 throw std::runtime_error(
146 "The input names no exchange-correlation functional, and the pseudopotential " +
149 ? std::string(
" states none")
150 :
" states '" + label +
"', which Q3 does not map to a functional it runs") +
153 if (resolved_functional.empty()) {
154 resolved_functional = functional;
155 resolved_from = source;
156 }
else if (functional != resolved_functional) {
157 throw std::runtime_error(
158 "The input names no exchange-correlation functional, and its pseudopotentials "
159 "were generated with different ones: " +
160 resolved_from +
" states " + resolved_functional +
", " + source +
" states " +
161 functional +
". Q3 will not pick one, because the result would belong to neither." +
166 log::info(
" Exchange-correlation functional: {}, as the pseudopotentials state (the "
168 resolved_functional);
169 return resolved_functional;
192 const std::string& pseudopotential_directory) {
196 for (
int species_index = 0; species_index < static_cast<int>(species.size()); ++species_index) {
198 species[species_index].pseudopotential_file, pseudopotential_directory);
203 pseudopotential_path,
204 dataset_index > 0 ?
" (dataset " + std::to_string(dataset_index + 1) +
")" :
"");
207 const auto* paw_pseudopotential =
209 if (paw_pseudopotential !=
nullptr && paw_pseudopotential->has_core_energy) {
210 throw std::runtime_error(
211 "PAW UPF dataset " + pseudopotential_path +
212 " declares a core_energy reference constant, which Q3 does not yet apply. "
213 "Use a supported PAW dataset without core_energy; refusing "
214 "this dataset prevents a silently wrong absolute energy and unstable SCF.");
218 species[species_index].valence_charge = pseudopotential->valence_charge;
220 pseudopotential_set.
push_back(std::move(pseudopotential));
223 return pseudopotential_set;