40 const std::string& file_content,
41 const std::string& source_description)
42 : pseudopotential_(pseudopotential)
43 , content_(file_content)
44 , source_description_(source_description) {}
47 read_augmentation_metadata();
50 read_multipole_moments();
55 void read_augmentation_metadata() {
56 using namespace upf_utilities;
57 auto position = content_.find(
"<PP_AUGMENTATION");
58 if (position == std::string::npos)
59 throw std::runtime_error(
"Malformed PAW UPF file " + source_description_ +
60 ": no PP_AUGMENTATION section");
62 auto tag_end = content_.find(
">", position);
63 std::string tag_line = content_.substr(position, tag_end - position);
67 std::string cutoff_radius = xml_attribute(tag_line,
"cutoff_r");
68 if (!cutoff_radius.empty())
75 std::string cutoff_index = xml_attribute(tag_line,
"cutoff_r_index");
76 if (cutoff_index.empty())
77 cutoff_index = xml_attribute(tag_line,
"iraug");
78 if (!cutoff_index.empty())
81 std::string maximum_angular_momentum_augmentation = xml_attribute(tag_line,
"lmax_aug");
82 if (maximum_angular_momentum_augmentation.empty())
83 maximum_angular_momentum_augmentation = xml_attribute(tag_line,
"l_max_aug");
84 if (!maximum_angular_momentum_augmentation.empty())
86 std::stoi(maximum_angular_momentum_augmentation);
92 std::string number_of_channels = xml_attribute(tag_line,
"nqlc");
95 : std::stoi(number_of_channels);
98 void read_partial_waves() {
99 using namespace upf_utilities;
100 auto block_start = content_.find(
"<PP_FULL_WFC");
101 if (block_start == std::string::npos)
102 throw std::runtime_error(
103 "Malformed PAW UPF file " + source_description_ +
104 ": no PP_FULL_WFC section, so the all-electron and pseudo partial waves "
105 "the one-center terms are built from are absent");
106 auto block_end = content_.find(
"</PP_FULL_WFC>", block_start);
107 if (block_end == std::string::npos)
108 throw std::runtime_error(
"Malformed PAW UPF file " + source_description_ +
109 ": unterminated PP_FULL_WFC section");
115 for (
int channel_index = 0; channel_index < number_of_channels; channel_index++) {
116 read_partial_wave(
"PP_AEWFC",
121 read_partial_wave(
"PP_PSWFC",
129 void read_partial_wave(
const std::string& tag_prefix,
133 PartialWave& partial_wave) {
134 using namespace upf_utilities;
135 std::string tag =
"<" + tag_prefix +
"." + std::to_string(channel_index + 1);
136 auto position = content_.find(tag, block_start);
137 if (position == std::string::npos || position >= block_end)
138 throw std::runtime_error(
"Malformed PAW UPF file " + source_description_ +
139 ": missing " + tag.substr(1) +
" inside PP_FULL_WFC");
141 auto tag_end = content_.find(
">", position);
142 std::string tag_line = content_.substr(position, tag_end - position);
144 std::string angular_momentum =
xml_attribute(tag_line,
" l");
145 if (angular_momentum.empty())
147 partial_wave.angular_momentum = angular_momentum.empty() ? 0 : std::stoi(angular_momentum);
149 std::string close_tag =
"</" + tag_prefix +
"." + std::to_string(channel_index + 1) +
">";
150 auto close_position = content_.find(close_tag, position);
151 if (close_position == std::string::npos)
152 throw std::runtime_error(
"Malformed PAW UPF file " + source_description_ +
153 ": unterminated " + tag.substr(1));
155 std::string
section = content_.substr(tag_end + 1, close_position - tag_end - 1);
156 partial_wave.radial_values =
xml_data(section);
157 partial_wave.radial_values.resize(pseudopotential_.
mesh_size, 0.0);
160 void read_paw_block() {
161 using namespace upf_utilities;
162 auto block_start = content_.find(
"<PP_PAW");
163 if (block_start == std::string::npos)
164 throw std::runtime_error(
"Malformed PAW UPF file " + source_description_ +
165 ": no PP_PAW section");
167 auto tag_end = content_.find(
">", block_start);
168 std::string tag_line = content_.substr(block_start, tag_end - block_start);
169 std::string core_energy =
xml_attribute(tag_line,
"core_energy");
170 if (!core_energy.empty()) {
171 pseudopotential_.
core_energy = std::stod(core_energy);
179 read_section(
"PP_AE_NLCC", block_start);
184 read_section(
"PP_AE_VLOC", block_start);
189 void read_multipole_moments() {
190 using namespace upf_utilities;
195 number_of_angular_momenta,
196 std::vector<std::vector<Real>>(number_of_channels,
197 std::vector<Real>(number_of_channels, 0.0)));
199 std::vector<Real> flat = read_section(
"PP_MULTIPOLES", 0);
209 auto expected_size =
static_cast<size_t>(number_of_angular_momenta) * number_of_channels *
211 if (flat.size() < expected_size)
212 throw std::runtime_error(
"Malformed PAW UPF file " + source_description_ +
213 ": PP_MULTIPOLES holds " + std::to_string(flat.size()) +
214 " values, expected " + std::to_string(expected_size));
216 for (
int angular_momentum = 0; angular_momentum < number_of_angular_momenta;
217 angular_momentum++) {
218 for (
int channel_1 = 0; channel_1 < number_of_channels; channel_1++) {
219 for (
int channel_2 = 0; channel_2 < number_of_channels; channel_2++) {
220 size_t flat_index =
static_cast<size_t>(angular_momentum) * number_of_channels *
222 static_cast<size_t>(channel_1) * number_of_channels +
232 std::vector<Real> read_section(
const std::string& tag_name,
size_t search_from) {
233 using namespace upf_utilities;
234 auto position = content_.find(
"<" + tag_name +
" ", search_from);
235 if (position == std::string::npos)
236 position = content_.find(
"<" + tag_name +
">", search_from);
237 if (position == std::string::npos)
240 auto tag_end = content_.find(
">", position);
241 auto close_position = content_.find(
"</" + tag_name +
">", tag_end);
242 if (close_position == std::string::npos)
245 return xml_data(content_.substr(tag_end + 1, close_position - tag_end - 1));
249 log::info(
" UPFv2 PAW: {} channels, aug shape={} r_aug={:.4f} bohr (index {}) l_max={}",
257 PawPseudopotential& pseudopotential_;
258 const std::string& content_;
259 std::string source_description_;