Octopus
psml.hpp
Go to the documentation of this file.
1#ifndef PSEUDO_PSML_HPP
2#define PSEUDO_PSML_HPP
3
4/*
5 Copyright (C) 2018 Xavier Andrade
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20*/
21
22#include <cassert>
23#include <cmath>
24#include <fstream>
25#include <iostream>
26#include <sstream>
27#include <vector>
28
29#include "anygrid.hpp"
30#include "base.hpp"
31#include "element.hpp"
32#include <rapidxml.hpp>
33
34namespace pseudopotential {
35
36class psml : public pseudopotential::anygrid {
37
38public:
39 psml(const std::string &filename, bool uniform_grid = false)
40 : pseudopotential::anygrid(uniform_grid), file_(filename.c_str()),
41 buffer_((std::istreambuf_iterator<char>(file_)),
42 std::istreambuf_iterator<char>()) {
43
44 filename_ = filename;
45
46 buffer_.push_back('\0');
47 doc_.parse<0>(&buffer_[0]);
48
49 root_node_ = doc_.first_node("psml");
50
51 spec_node_ = root_node_->first_node("pseudo-atom-spec");
52 // some files do not have "pseudo-atom-spec" but "header"
53 if (!spec_node_)
54 spec_node_ = root_node_->first_node("header");
55 assert(spec_node_);
56
57 // now check the type
58 bool has_local_potential = root_node_->first_node("local-potential");
59 bool has_nl_projectors = root_node_->first_node("nonlocal-projectors");
60 bool has_semilocal_potentials =
61 root_node_->first_node("semilocal-potentials");
62 bool has_pseudo_wavefunctions =
63 root_node_->first_node("pseudo-wave-functions");
64 if (has_nl_projectors && has_local_potential) {
65 type_ = pseudopotential::type::KLEINMAN_BYLANDER;
66 } else if (has_semilocal_potentials && has_pseudo_wavefunctions) {
67 type_ = pseudopotential::type::SEMILOCAL;
68 } else {
69 throw status::UNSUPPORTED_TYPE;
70 }
71
72 {
73 // read lmax
74 std::string tag1, tag2;
75 if (type_ == pseudopotential::type::KLEINMAN_BYLANDER) {
76 tag1 = "nonlocal-projectors";
77 tag2 = "proj";
78 } else if (type_ == pseudopotential::type::SEMILOCAL) {
79 tag1 = "semilocal-potentials";
80 tag2 = "slps";
81 } else {
82 assert(false);
83 }
84
85 lmax_ = -1;
86 rapidxml::xml_node<> *node = root_node_->first_node(tag1.c_str());
87 assert(node);
88 node = node->first_node(tag2.c_str());
89 while (node) {
90 int read_l = letter_to_l(node->first_attribute("l")->value());
91 lmax_ = std::max(lmax_, read_l);
92 node = node->next_sibling(tag2.c_str());
93 }
94 assert(lmax_ >= 0);
95 assert(lmax_ < 9);
96 }
97
98 // read grid
99 {
100 rapidxml::xml_node<> *node = root_node_->first_node("grid");
101
102 assert(node);
103
104 int size = value<int>(node->first_attribute("npts"));
105 grid_.resize(size);
106 std::istringstream stst(node->first_node("grid-data")->value());
107 for (int ii = 0; ii < size; ii++) {
108 stst >> grid_[ii];
109 if (ii > 0)
110 assert(grid_[ii] > grid_[ii - 1]);
111 }
112
113 assert(fabs(grid_[0]) <= 1e-10);
114
115 mesh_size_ = 0;
116 for (double rr = 0.0; rr <= grid_[grid_.size() - 1]; rr += mesh_spacing())
117 mesh_size_++;
118
119 grid_weights_.resize(grid_.size());
120
121 // the integration weights are not available, we approximate them
122 grid_weights_[0] = 0.5 * (grid_[1] - grid_[0]);
123 for (unsigned ii = 1; ii < grid_.size() - 1; ii++)
124 grid_weights_[ii] = grid_[ii + 1] - grid_[ii - 1];
125 grid_weights_[grid_.size() - 1] =
126 0.5 * (grid_[grid_.size() - 1] - grid_[grid_.size() - 2]);
127 }
128 }
129
130 pseudopotential::format format() const {
131 return pseudopotential::format::PSML;
132 }
133
134 int size() const { return buffer_.size(); };
135
136 std::string description() const { return ""; }
137
138 std::string symbol() const {
139 return element::trim(spec_node_->first_attribute("atomic-label")->value());
140 }
141
142 int atomic_number() const {
143 return value<int>(spec_node_->first_attribute("atomic-number"));
144 }
145
146 double mass() const {
147 element el(symbol());
148 return el.mass();
149 }
150
151 double valence_charge() const {
152 return value<double>(spec_node_->first_node("valence-configuration")
153 ->first_attribute("total-valence-charge"));
154 }
155
156 int llocal() const { return -1; }
157
158 pseudopotential::exchange exchange() const {
159 // PSML uses libxc ids, so we just need to read the value
160 rapidxml::xml_node<> *node = spec_node_->first_node("exchange-correlation")
161 ->first_node("libxc-info")
162 ->first_node("functional");
163 while (node) {
164 if (value<std::string>(node->first_attribute("type")) == "exchange") {
165 return pseudopotential::exchange(
166 value<int>(node->first_attribute("id")));
167 }
168 node = node->next_sibling("functional");
169 }
170 return pseudopotential::exchange::UNKNOWN;
171 }
172
173 pseudopotential::correlation correlation() const {
174 // PSML uses libxc ids, so we just need to read the value
175 rapidxml::xml_node<> *node = spec_node_->first_node("exchange-correlation")
176 ->first_node("libxc-info")
177 ->first_node("functional");
178 while (node) {
179 if (value<std::string>(node->first_attribute("type")) == "correlation") {
180 return pseudopotential::correlation(
181 value<int>(node->first_attribute("id")));
182 }
183 node = node->next_sibling("functional");
184 }
185 return pseudopotential::correlation::UNKNOWN;
186 }
187
188 int nchannels() const {
189 if (type_ == pseudopotential::type::SEMILOCAL)
190 return 1;
191 int nc = 0;
192 rapidxml::xml_node<> *node = root_node_->first_node("nonlocal-projectors");
193 assert(node);
194 node = node->first_node("proj");
195 while (node) {
196 int read_ic = value<int>(node->first_attribute("seq")) - 1;
197 nc = std::max(nc, read_ic + 1);
198 node = node->next_sibling("proj");
199 }
200 return nc;
201 }
202
203 void local_potential(std::vector<double> &val) const {
204 read_function(root_node_->first_node("local-potential"), val, true);
205 }
206
207 int nprojectors() const {
208 rapidxml::xml_node<> *node =
209 root_node_->first_node("nonlocal-projectors")->first_node("proj");
210 int count = 0;
211 while (node) {
212 count++;
213 node = node->next_sibling("proj");
214 }
215 return count;
216 }
217
218 int nprojectors_per_l(int l) const {
219 if (type_ == pseudopotential::type::SEMILOCAL)
220 return 1;
221
222 rapidxml::xml_node<> *node =
223 root_node_->first_node("nonlocal-projectors")->first_node("proj");
224 int count = 0;
225 while (node) {
226 int read_l = letter_to_l(node->first_attribute("l")->value());
227 if (read_l == l) count++;
228 node = node->next_sibling("proj");
229 }
230 return count;
231 }
232
233
234 void projector(int l, int ic, std::vector<double> &val) const {
235 rapidxml::xml_node<> *node =
236 root_node_->first_node("nonlocal-projectors")->first_node("proj");
237 while (node) {
238 int read_l = letter_to_l(node->first_attribute("l")->value());
239 int read_ic = value<int>(node->first_attribute("seq")) - 1;
240 if (l == read_l && ic == read_ic)
241 break;
242 node = node->next_sibling("proj");
243 }
244 read_function(node, val);
245 }
246
247 double d_ij(int l, int ic, int jc) const {
248 if (ic != jc)
249 return 0.0;
250
251 rapidxml::xml_node<> *node =
252 root_node_->first_node("nonlocal-projectors")->first_node("proj");
253 while (node) {
254 int read_l = letter_to_l(node->first_attribute("l")->value());
255 int read_ic = value<int>(node->first_attribute("seq")) - 1;
256 if (l == read_l && ic == read_ic)
257 break;
258 node = node->next_sibling("proj");
259 }
260 assert(node);
261 return value<double>(node->first_attribute("ekb"));
262 }
263
264 bool has_radial_function(int l) const { return false; }
265
266 void radial_function(int l, std::vector<double> &val) const {
267 rapidxml::xml_node<> *node =
268 root_node_->first_node("pseudo-wave-functions")->first_node("pswf");
269 while (node) {
270 int read_l = letter_to_l(node->first_attribute("l")->value());
271 if (l == read_l)
272 break;
273 node = node->next_sibling("pswf");
274 }
275 read_function(node, val);
276 }
277
278 void radial_potential(int l, std::vector<double> &val) const {
279 rapidxml::xml_node<> *node =
280 root_node_->first_node("semilocal-potentials")->first_node("slps");
281 while (node) {
282 int read_l = letter_to_l(node->first_attribute("l")->value());
283 if (l == read_l)
284 break;
285 node = node->next_sibling("slps");
286 }
287 read_function(node, val);
288 }
289
290 bool has_nlcc() const {
291 rapidxml::xml_node<> *node = root_node_->first_node("pseudocore-charge");
292 return node;
293 }
294
295 void nlcc_density(std::vector<double> &val) const {
296 read_function(root_node_->first_node("pseudocore-charge"), val);
297 for (unsigned ii = 0; ii < val.size(); ii++)
298 val[ii] /= 4.0 * M_PI;
299 }
300
301 bool has_density() { return root_node_->first_node("valence-charge"); }
302
303 void density(std::vector<double> &val) const {
304 read_function(root_node_->first_node("valence-charge"), val);
305 for (unsigned ii = 0; ii < val.size(); ii++)
306 val[ii] /= 4.0 * M_PI;
307 }
308
309 bool has_total_angular_momentum() const {
310 return spec_node_->first_attribute("relativity")->value() ==
311 std::string("dirac");
312 }
313
314 int projector_2j(int l, int ic) const {
315 rapidxml::xml_node<> *node =
316 root_node_->first_node("nonlocal-projectors")->first_node("proj");
317 while (node) {
318 int read_l = letter_to_l(node->first_attribute("l")->value());
319 int read_ic = value<int>(node->first_attribute("seq")) - 1;
320 if (l == read_l && ic == read_ic) {
321 double read_j = value<double>(node->first_attribute("j"));
322 std::cout << l << " " << ic << " " << read_j << std::endl;
323 return lrint(2.0 * read_j);
324 }
325 node = node->next_sibling("proj");
326 }
327 assert(false);
328 return 0;
329 }
330
331private:
332 void read_function(rapidxml::xml_node<> *base_node, std::vector<double> &val,
333 bool potential_padding = false) const {
334 assert(base_node);
335 rapidxml::xml_node<> *node =
336 base_node->first_node("radfunc")->first_node("data");
337 assert(node);
338 int size = grid_.size();
339 if (node->first_attribute("npts"))
340 size = value<int>(node->first_attribute("npts"));
341 val.resize(grid_.size());
342 std::istringstream stst(node->value());
343 for (int ii = 0; ii < size; ii++)
344 stst >> val[ii];
345
346 if (potential_padding) {
347 for (unsigned ii = size; ii < grid_.size(); ii++)
348 val[ii] = -valence_charge() / grid_[ii];
349 } else {
350 for (unsigned ii = size; ii < grid_.size(); ii++)
351 val[ii] = 0.0;
352 }
353
354 interpolate(val);
355 }
356
357 // for some stupid reason psml uses letters instead of numbers for angular
358 // momentum
359 static int letter_to_l(const std::string &letter) {
360 if (letter == "s")
361 return 0;
362 if (letter == "p")
363 return 1;
364 if (letter == "d")
365 return 2;
366 if (letter == "f")
367 return 3;
368 if (letter == "g")
369 return 4;
370 if (letter == "h")
371 return 5;
372 return -1;
373 }
374
375 std::ifstream file_;
376 std::vector<char> buffer_;
377 rapidxml::xml_document<> doc_;
378 rapidxml::xml_node<> *root_node_;
379 rapidxml::xml_node<> *spec_node_;
380};
381
382} // namespace pseudopotential
383
384#endif
if write to the Free Software Franklin Fifth USA !If the compiler accepts long Fortran it is better to use that and build all the preprocessor definitions in one line In !this the debuggers will provide the right line numbers !If the compiler accepts line number then CARDINAL and ACARDINAL !will put them just a new line or a ampersand plus a new line !These macros should be used in macros that span several lines They should by !put immedialty before a line where a compilation error might occur and at the !end of the macro !Note that the cardinal and newline words are substituted by the program !preprocess pl by the ampersand and by a real new line just before compilation !The assertions are ignored if the code is compiled in not debug when !prints out the assertion string
Definition: global.h:46
double fabs(double __x) __attribute__((__nothrow__
integer, parameter, public density
Definition: quantity.F90:146
integer, parameter, public mass
Definition: quantity.F90:146
ptrdiff_t l
Definition: operate_inc.c:12