Quantum 3xplorer (Q3)
An AI-native quantum simulation engine
Loading...
Searching...
No Matches
functional_label.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * The functional a pseudopotential's header names, as a name Q3's
5 * exchange-correlation factory runs.
6 *
7 * Datasets record the functional they were generated with in Quantum
8 * ESPRESSO's vocabulary: UPF v2's `functional` header attribute, or the UPF v1
9 * header line that ends "Exchange-Correlation functional". The label takes one
10 * of two shapes:
11 *
12 * - a short name, such as "PBE" or "PZ";
13 * - the four components the functional is assembled from, in the order local
14 * exchange, local correlation, gradient correction to exchange, gradient
15 * correction to correlation, so "SLA PW PBX PBC" is PBE. Generators
16 * separate them with spaces or dashes, older files spell PBE's two gradient
17 * terms "PBE PBE", and v1 headers append the short name as a fifth word.
18 *
19 * Case never matters. Every name returned is lower-cased, the spelling Q3
20 * records a functional in, so labels that differ only in case compare equal
21 * when the datasets of one input are checked for agreement. QE's LibXC
22 * spelling ("XC-000I-000I-101L-130L") is already a name the factory reads, so
23 * it passes through, lower-cased like the rest.
24 *
25 * Only labels whose meaning is unambiguous are mapped. Anything else returns
26 * empty: Perdew-Wang LDA ("PW", which is not Q3's PZ), a nonlocal or meta-GGA
27 * term, or a dataset title that names no functional. The caller then asks the
28 * input to name the functional rather than choosing a nearby one.
29 */
30
31#include <cctype>
32#include <cstddef>
33#include <map>
34#include <string>
35#include <vector>
36
37namespace q3 {
38
39/// The functional a pseudopotential label names, or empty when it names none Q3 maps.
40inline std::string functional_from_pseudopotential_label(const std::string& label) {
41 const std::size_t first = label.find_first_not_of(" \t\r\n");
42 if (first == std::string::npos)
43 return {};
44 std::string trimmed = label.substr(first, label.find_last_not_of(" \t\r\n") - first + 1);
45 for (auto& character : trimmed)
46 character = static_cast<char>(std::tolower(static_cast<unsigned char>(character)));
47
48 std::vector<std::string> words;
49 std::string word;
50 for (char character : trimmed + " ") {
51 if (std::isspace(static_cast<unsigned char>(character)) || character == '-' ||
52 character == '+') {
53 if (!word.empty())
54 words.push_back(word);
55 word.clear();
56 continue;
57 }
58 word += character;
59 }
60
61 if (words.empty())
62 return {};
63 if (words.front() == "xc" && trimmed[2] == '-')
64 return trimmed;
65
66 static const std::map<std::string, std::string> short_names = {
67 {"pz", "pz"},
68 {"lda", "pz"},
69 {"pbe", "pbe"},
70 {"pbesol", "pbesol"},
71 {"blyp", "blyp"},
72 {"revpbe", "revpbe"},
73 {"rpbe", "rpbe"},
74 };
75 if (words.size() == 1) {
76 auto found = short_names.find(words.front());
77 return found == short_names.end() ? std::string{} : found->second;
78 }
79
80 static const std::map<std::vector<std::string>, std::string> component_sets = {
81 {{"sla", "pz", "nogx", "nogc"}, "pz"},
82 {{"sla", "pw", "pbx", "pbc"}, "pbe"},
83 {{"sla", "pw", "pbe", "pbe"}, "pbe"},
84 {{"sla", "pw", "psx", "psc"}, "pbesol"},
85 {{"sla", "lyp", "b88", "blyp"}, "blyp"},
86 {{"sla", "pw", "revx", "pbc"}, "revpbe"},
87 {{"sla", "pw", "rpb", "pbc"}, "revpbe"},
88 };
89 if (words.size() < 4)
90 return {};
91 auto found = component_sets.find(std::vector<std::string>(words.begin(), words.begin() + 4));
92 if (found == component_sets.end())
93 return {};
94
95 /**
96 * A word past the fourth is either the short name a v1 header repeats,
97 * which must agree, or a further term, such as a nonlocal correlation
98 * kernel, that names a functional Q3 does not run.
99 */
100 for (auto extra = words.begin() + 4; extra != words.end(); ++extra) {
101 auto short_name = short_names.find(*extra);
102 if (short_name == short_names.end() || short_name->second != found->second)
103 return {};
104 }
105 return found->second;
106}
107
108} // namespace q3
std::string functional_from_pseudopotential_label(const std::string &label)
The functional a pseudopotential label names, or empty when it names none Q3 maps.