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 = select_set_node("nonlocal-projectors");
60 bool has_semilocal_potentials = select_set_node("semilocal-potentials");
61 bool has_pseudo_wavefunctions = select_set_node("pseudo-wave-functions");
62 if (has_nl_projectors && has_local_potential) {
63 type_ = pseudopotential::type::KLEINMAN_BYLANDER;
64 } else if (has_semilocal_potentials && has_pseudo_wavefunctions) {
65 type_ = pseudopotential::type::SEMILOCAL;
66 } else {
67 throw status::UNSUPPORTED_TYPE;
68 }
69
70 {
71 // read lmax
72 std::string tag1, tag2;
73 if (type_ == pseudopotential::type::KLEINMAN_BYLANDER) {
74 tag1 = "nonlocal-projectors";
75 tag2 = "proj";
76 } else if (type_ == pseudopotential::type::SEMILOCAL) {
77 tag1 = "semilocal-potentials";
78 tag2 = "slps";
79 } else {
80 assert(false);
81 }
82
83 lmax_ = -1;
84 rapidxml::xml_node<> *node = select_set_node(tag1.c_str());
85 assert(node);
86 node = node->first_node(tag2.c_str());
87 while (node) {
88 int read_l = letter_to_l(node->first_attribute("l")->value());
89 lmax_ = std::max(lmax_, read_l);
90 node = node->next_sibling(tag2.c_str());
91 }
92 assert(lmax_ >= 0);
93 assert(lmax_ < 9);
94 }
95
96 // read grid
97 {
98 rapidxml::xml_node<> *node = root_node_->first_node("grid");
99
100 assert(node);
101
102 int size = value<int>(node->first_attribute("npts"));
103 grid_.resize(size);
104 std::istringstream stst(node->first_node("grid-data")->value());
105 for (int ii = 0; ii < size; ii++) {
106 stst >> grid_[ii];
107 if (ii > 0)
108 assert(grid_[ii] > grid_[ii - 1]);
109 }
110
111 assert(fabs(grid_[0]) <= 1e-10);
112
113 mesh_size_ = 0;
114 for (double rr = 0.0; rr <= grid_[grid_.size() - 1]; rr += mesh_spacing())
115 mesh_size_++;
116
117 grid_weights_.resize(grid_.size());
118
119 // the integration weights are not available, we approximate them
120 grid_weights_[0] = 0.5 * (grid_[1] - grid_[0]);
121 for (unsigned ii = 1; ii < grid_.size() - 1; ii++)
122 grid_weights_[ii] = grid_[ii + 1] - grid_[ii - 1];
123 grid_weights_[grid_.size() - 1] =
124 0.5 * (grid_[grid_.size() - 1] - grid_[grid_.size() - 2]);
125 }
126 }
127
128 pseudopotential::format format() const {
129 return pseudopotential::format::PSML;
130 }
131
132 int size() const { return buffer_.size(); };
133
134 std::string description() const { return ""; }
135
136 std::string symbol() const {
137 return element::trim(spec_node_->first_attribute("atomic-label")->value());
138 }
139
140 int atomic_number() const {
141 return value<int>(spec_node_->first_attribute("atomic-number"));
142 }
143
144 double mass() const {
145 element el(symbol());
146 return el.mass();
147 }
148
149 double valence_charge() const {
150 return value<double>(spec_node_->first_node("valence-configuration")
151 ->first_attribute("total-valence-charge"));
152 }
153
154 int llocal() const { return -1; }
155
156 pseudopotential::exchange exchange() const {
157 // PSML uses libxc ids, so we just need to read the value
158 rapidxml::xml_node<> *node = spec_node_->first_node("exchange-correlation")
159 ->first_node("libxc-info")
160 ->first_node("functional");
161 while (node) {
162 if (value<std::string>(node->first_attribute("type")) == "exchange") {
163 return pseudopotential::exchange(
164 value<int>(node->first_attribute("id")));
165 }
166 node = node->next_sibling("functional");
167 }
168 return pseudopotential::exchange::UNKNOWN;
169 }
170
171 pseudopotential::correlation correlation() const {
172 // PSML uses libxc ids, so we just need to read the value
173 rapidxml::xml_node<> *node = spec_node_->first_node("exchange-correlation")
174 ->first_node("libxc-info")
175 ->first_node("functional");
176 while (node) {
177 if (value<std::string>(node->first_attribute("type")) == "correlation") {
178 return pseudopotential::correlation(
179 value<int>(node->first_attribute("id")));
180 }
181 node = node->next_sibling("functional");
182 }
183 return pseudopotential::correlation::UNKNOWN;
184 }
185
186 int nchannels() const {
187 if (type_ == pseudopotential::type::SEMILOCAL)
188 return 1;
189 if (is_fully_relativistic()) {
190 int nc = 0;
191 for (int l = 0; l <= lmax_; l++)
192 nc = std::max(nc, nprojectors_per_l(l));
193 return nc;
194 }
195
196 int nc = 0;
197 rapidxml::xml_node<> *node = nonlocal_projectors_node();
198 assert(node);
199 node = node->first_node("proj");
200 while (node) {
201 int read_ic = value<int>(node->first_attribute("seq")) - 1;
202 nc = std::max(nc, read_ic + 1);
203 node = node->next_sibling("proj");
204 }
205 return nc;
206 }
207
208 void local_potential(std::vector<double> &val) const {
209 read_function(root_node_->first_node("local-potential"), val, true);
210 }
211
212 int nprojectors() const {
213 rapidxml::xml_node<> *node =
214 nonlocal_projectors_node()->first_node("proj");
215 int count = 0;
216 while (node) {
217 count++;
218 node = node->next_sibling("proj");
219 }
220 return count;
221 }
222
223 int nprojectors_per_l(int l) const {
224 if (type_ == pseudopotential::type::SEMILOCAL)
225 return 1;
226
227 rapidxml::xml_node<> *node =
228 nonlocal_projectors_node()->first_node("proj");
229 int count = 0;
230 while (node) {
231 int read_l = letter_to_l(node->first_attribute("l")->value());
232 if (read_l == l) count++;
233 node = node->next_sibling("proj");
234 }
235 return count;
236 }
237
238
239 void projector(int l, int ic, std::vector<double> &val) const {
240 rapidxml::xml_node<> *node = projector_node(l, ic);
241 read_function(node, val);
242 }
243
244 double d_ij(int l, int ic, int jc) const {
245 if (ic != jc)
246 return 0.0;
247
248 rapidxml::xml_node<> *node = projector_node(l, ic);
249 if (!node)
250 return 0.0;
251 return value<double>(node->first_attribute("ekb"));
252 }
253
254 bool has_radial_function(int l) const {
255 return wavefunction_node_for_l(l) != nullptr;
256 }
257
258 void radial_function(int l, std::vector<double> &val) const {
259 rapidxml::xml_node<> *node = wavefunction_node_for_l(l);
260 read_function(node, val);
261 }
262
263 void radial_potential(int l, std::vector<double> &val) const {
264 rapidxml::xml_node<> *node =
265 semilocal_potentials_node()->first_node("slps");
266 while (node) {
267 int read_l = letter_to_l(node->first_attribute("l")->value());
268 if (l == read_l)
269 break;
270 node = node->next_sibling("slps");
271 }
272 read_function(node, val);
273 }
274
275 bool has_nlcc() const {
276 rapidxml::xml_node<> *node = root_node_->first_node("pseudocore-charge");
277 return node;
278 }
279
280 void nlcc_density(std::vector<double> &val) const {
281 read_function(root_node_->first_node("pseudocore-charge"), val);
282 for (unsigned ii = 0; ii < val.size(); ii++)
283 val[ii] /= 4.0 * M_PI;
284 }
285
286 bool has_density() { return root_node_->first_node("valence-charge"); }
287
288 void density(std::vector<double> &val) const {
289 read_function(root_node_->first_node("valence-charge"), val);
290 for (unsigned ii = 0; ii < val.size(); ii++)
291 val[ii] /= 4.0 * M_PI;
292 }
293
294 bool has_total_angular_momentum() const {
295 return spec_node_->first_attribute("relativity")->value() ==
296 std::string("dirac");
297 }
298
299 int projector_2j(int l, int ic) const {
300 rapidxml::xml_node<> *node = projector_node(l, ic);
301 assert(node);
302 double read_j = value<double>(node->first_attribute("j"));
303 return lrint(2.0 * read_j);
304 }
305
306 int nwavefunctions() const {
307 rapidxml::xml_node<> *wf_set = pseudo_wavefunctions_node();
308 if (!wf_set)
309 return 0;
310
311 int count = 0;
312 for (rapidxml::xml_node<> *shell = first_valence_shell();
313 shell; shell = shell->next_sibling("shell")) {
314 rapidxml::xml_node<> *node = wf_set->first_node("pswf");
315 while (node) {
316 if (wavefunction_matches_shell(node, shell))
317 count++;
318 node = node->next_sibling("pswf");
319 }
320 }
321
322 if (count > 0)
323 return count;
324
325 count = 0;
326 rapidxml::xml_node<> *node = wf_set->first_node("pswf");
327 while (node) {
328 count++;
329 node = node->next_sibling("pswf");
330 }
331 return count;
332 }
333
334 void wavefunction(int index, int &n, int &l, double &occ,
335 std::vector<double> &val) const {
336 rapidxml::xml_node<> *node = wavefunction_node(index);
337 assert(node);
338
339 n = value<int>(node->first_attribute("n"));
340 l = letter_to_l(node->first_attribute("l")->value());
341 occ = wavefunction_occupation(node);
342
343 read_function(node, val);
344 }
345
346 int wavefunction_2j(int ii) const {
347 rapidxml::xml_node<> *node = wavefunction_node(ii - 1);
348 assert(node);
349
350 auto *j_attr = node->first_attribute("j");
351 if (!j_attr)
352 return 0;
353
354 return lrint(2.0 * value<double>(j_attr));
355 }
356
357private:
358 bool is_fully_relativistic() const {
359 auto *attr = spec_node_->first_attribute("relativity");
360 return attr && std::string(attr->value()) == "dirac";
361 }
362
363 rapidxml::xml_node<> *select_set_node(const char *name) const {
364 rapidxml::xml_node<> *node = root_node_->first_node(name);
365 rapidxml::xml_node<> *fallback = nullptr;
366 const std::string preferred_set =
367 is_fully_relativistic() ? "lj" : "scalar_relativistic";
368
369 while (node) {
370 auto *set_attr = node->first_attribute("set");
371 if (!set_attr)
372 return node;
373
374 std::string set_name = set_attr->value();
375 if (set_name == preferred_set)
376 return node;
377 if (set_name == "scalar_relativistic" && fallback == nullptr)
378 fallback = node;
379 if (fallback == nullptr)
380 fallback = node;
381
382 node = node->next_sibling(name);
383 }
384
385 return fallback;
386 }
387
388 rapidxml::xml_node<> *nonlocal_projectors_node() const {
389 return select_set_node("nonlocal-projectors");
390 }
391
392 rapidxml::xml_node<> *semilocal_potentials_node() const {
393 return select_set_node("semilocal-potentials");
394 }
395
396 rapidxml::xml_node<> *pseudo_wavefunctions_node() const {
397 return select_set_node("pseudo-wave-functions");
398 }
399
400 rapidxml::xml_node<> *projector_node(int l, int ic) const {
401 assert(l >= 0);
402 rapidxml::xml_node<> *node = nonlocal_projectors_node()->first_node("proj");
403 int current_ic = 0;
404 int desired_2j = 0;
405 int desired_seq = 0;
406
407 if (is_fully_relativistic() && l > 0) {
408 desired_seq = ic / 2 + 1;
409 desired_2j = (ic % 2 == 0) ? 2 * l + 1 : 2 * l - 1;
410 }
411
412 while (node) {
413 int read_l = letter_to_l(node->first_attribute("l")->value());
414 if (l == read_l) {
415 if (is_fully_relativistic()) {
416 if (l == 0) {
417 if (current_ic == ic)
418 return node;
419 current_ic++;
420 } else {
421 int read_ic = value<int>(node->first_attribute("seq"));
422 int read_2j = lrint(2.0 * value<double>(node->first_attribute("j")));
423 if (read_ic == desired_seq && read_2j == desired_2j)
424 return node;
425 }
426 } else {
427 int read_ic = value<int>(node->first_attribute("seq")) - 1;
428 if (ic == read_ic)
429 return node;
430 }
431 }
432 node = node->next_sibling("proj");
433 }
434
435 return nullptr;
436 }
437
438 rapidxml::xml_node<> *first_valence_shell() const {
439 rapidxml::xml_node<> *node = spec_node_->first_node("valence-configuration");
440 if (!node)
441 return nullptr;
442 return node->first_node("shell");
443 }
444
445 bool wavefunction_matches_shell(rapidxml::xml_node<> *wavefunction,
446 rapidxml::xml_node<> *shell) const {
447 assert(wavefunction);
448 assert(shell);
449
450 return value<int>(wavefunction->first_attribute("n")) ==
451 value<int>(shell->first_attribute("n")) &&
452 std::string(wavefunction->first_attribute("l")->value()) ==
453 shell->first_attribute("l")->value();
454 }
455
456 double wavefunction_occupation(rapidxml::xml_node<> *wavefunction) const {
457 assert(wavefunction);
458
459 auto *occupation_attr = wavefunction->first_attribute("occupation");
460 if (occupation_attr)
461 return value<double>(occupation_attr);
462
463 rapidxml::xml_node<> *shell = first_valence_shell();
464 while (shell) {
465 if (wavefunction_matches_shell(wavefunction, shell)) {
466 double occupation = value<double>(shell->first_attribute("occupation"));
467 auto *j_attr = wavefunction->first_attribute("j");
468 if (!j_attr)
469 return occupation;
470
471 double j = value<double>(j_attr);
472 int l = letter_to_l(wavefunction->first_attribute("l")->value());
473 return occupation * (2.0 * j + 1.0) / (2.0 * (2.0 * l + 1.0));
474 }
475 shell = shell->next_sibling("shell");
476 }
477
478 return 0.0;
479 }
480
481 rapidxml::xml_node<> *wavefunction_node_for_l(int l) const {
482 rapidxml::xml_node<> *wf_set = pseudo_wavefunctions_node();
483 if (!wf_set)
484 return nullptr;
485
486 rapidxml::xml_node<> *node = wf_set->first_node("pswf");
487 while (node) {
488 int read_l = letter_to_l(node->first_attribute("l")->value());
489 if (l == read_l) {
490 rapidxml::xml_node<> *shell = first_valence_shell();
491 while (shell) {
492 if (wavefunction_matches_shell(node, shell))
493 return node;
494 shell = shell->next_sibling("shell");
495 }
496 return node;
497 }
498 node = node->next_sibling("pswf");
499 }
500
501 return nullptr;
502 }
503
504 rapidxml::xml_node<> *wavefunction_node(int index) const {
505 rapidxml::xml_node<> *wf_set = pseudo_wavefunctions_node();
506 assert(wf_set);
507
508 int current = 0;
509 for (rapidxml::xml_node<> *shell = first_valence_shell();
510 shell; shell = shell->next_sibling("shell")) {
511 rapidxml::xml_node<> *best_high_j = nullptr;
512 rapidxml::xml_node<> *best_low_j = nullptr;
513
514 for (rapidxml::xml_node<> *node = wf_set->first_node("pswf"); node;
515 node = node->next_sibling("pswf")) {
516 if (!wavefunction_matches_shell(node, shell))
517 continue;
518
519 auto *j_attr = node->first_attribute("j");
520 if (!j_attr) {
521 if (current == index)
522 return node;
523 current++;
524 continue;
525 }
526
527 double j = value<double>(j_attr);
528 int shell_l = letter_to_l(shell->first_attribute("l")->value());
529 if (j > shell_l)
530 best_high_j = node;
531 else
532 best_low_j = node;
533 }
534
535 if (best_high_j) {
536 if (current == index)
537 return best_high_j;
538 current++;
539 }
540 if (best_low_j) {
541 if (current == index)
542 return best_low_j;
543 current++;
544 }
545 }
546
547 for (rapidxml::xml_node<> *node = wf_set->first_node("pswf"); node;
548 node = node->next_sibling("pswf")) {
549 if (current == index)
550 return node;
551 current++;
552 }
553
554 return nullptr;
555 }
556
557 void read_function(rapidxml::xml_node<> *base_node, std::vector<double> &val,
558 bool potential_padding = false) const {
559 assert(base_node);
560 rapidxml::xml_node<> *node =
561 base_node->first_node("radfunc")->first_node("data");
562 assert(node);
563 int size = grid_.size();
564 if (node->first_attribute("npts"))
565 size = value<int>(node->first_attribute("npts"));
566 val.resize(grid_.size());
567 std::istringstream stst(node->value());
568 for (int ii = 0; ii < size; ii++)
569 stst >> val[ii];
570
571 if (potential_padding) {
572 for (unsigned ii = size; ii < grid_.size(); ii++)
573 val[ii] = -valence_charge() / grid_[ii];
574 } else {
575 for (unsigned ii = size; ii < grid_.size(); ii++)
576 val[ii] = 0.0;
577 }
578
579 interpolate(val);
580 }
581
582 // for some stupid reason psml uses letters instead of numbers for angular
583 // momentum
584 static int letter_to_l(const std::string &letter) {
585 if (letter == "s")
586 return 0;
587 if (letter == "p")
588 return 1;
589 if (letter == "d")
590 return 2;
591 if (letter == "f")
592 return 3;
593 if (letter == "g")
594 return 4;
595 if (letter == "h")
596 return 5;
597 return -1;
598 }
599
600 std::ifstream file_;
601 std::vector<char> buffer_;
602 rapidxml::xml_document<> doc_;
603 rapidxml::xml_node<> *root_node_;
604 rapidxml::xml_node<> *spec_node_;
605};
606
607} // namespace pseudopotential
608
609#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__
ptrdiff_t l
ptrdiff_t j
const int *restrict index
Definition: operate_inc.c:13