Octopus
set.hpp
Go to the documentation of this file.
1#ifndef PSEUDO_SET_HPP
2#define PSEUDO_SET_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 <fstream>
23#include <map>
24#include <string>
25
26#include "element.hpp"
27
28#include "detect_format.hpp"
29#include "psml.hpp"
30#include "psp8.hpp"
31#include "qso.hpp"
32#include "upf1.hpp"
33#include "upf2.hpp"
34#include <dirent.h>
35#include <iostream>
36
37namespace pseudopotential {
38
39class set {
40
41private:
42 struct element_values {
43 std::string file_rel_path_;
44 std::string file_dir_;
45 int lmax_;
46 int llocal_;
47 };
48
49 typedef std::map<std::string, element_values> element_map;
50
51 element_map map_;
52 bool automatic_;
53
54public:
55 set(const std::string &dirname) {
56
57 // Load the element mapping file, or regenerate it if not present
58 load_element_map(dirname);
59
60 for (auto& [key, elem] : map_) {
61 elem.file_dir_ = dirname;
62 }
63
64 }
65
66 bool has(const element &el) const {
67 return map_.find(el.symbol()) != map_.end();
68 }
69
70 std::string file_path(const element &el) const {
71 return map_.at(el.symbol()).file_dir_ + "/" + map_.at(el.symbol()).file_rel_path_;
72 }
73
74 int lmax(const element &el) const { return map_.at(el.symbol()).lmax_; }
75
76 int llocal(const element &el) const { return map_.at(el.symbol()).llocal_; }
77
78 // Generate a mapping file that stores the map
79 void generate_element_map(const std::string &dirname) {
80
81 DIR *dir = opendir(dirname.c_str());
82
83 struct dirent *ent;
84 while ((ent = readdir(dir)) != NULL) {
85 const std::string filename(ent->d_name);
86 const std::string fullname = dirname + "/" + filename;
87
88 if (filename == "." || filename == "..")
89 continue;
90
91 pseudopotential::format format = detect_format(fullname);
92
93 if (format == pseudopotential::format::FILE_NOT_FOUND ||
94 format == pseudopotential::format::UNKNOWN)
95 continue;
96
97 // we open the pseudo just to get the species symbol, this could be done
98 // in a better way
99 pseudopotential::base *pseudo = NULL;
100
101 std::string symbol;
102
103 switch (format) {
104 case pseudopotential::format::QSO:
105 pseudo = new pseudopotential::qso(fullname);
106 break;
107 case pseudopotential::format::UPF1:
108 pseudo = new pseudopotential::upf1(fullname, /*uniform_grid = */ true);
109 break;
110 case pseudopotential::format::UPF2:
111 pseudo = new pseudopotential::upf2(fullname, /*uniform_grid = */ true);
112 break;
113 case pseudopotential::format::PSML:
114 pseudo = new pseudopotential::psml(fullname, /*uniform_grid = */ true);
115 break;
116 case pseudopotential::format::PSP8:
117 pseudo = new pseudopotential::psp8(fullname);
118 break;
119 default:
120 // get the symbol from the name
121 for (int ii = 0; ii < 3; ii++) {
122 char cc = filename[ii];
123 bool is_letter = (cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z');
124 if (!is_letter)
125 break;
126 symbol.push_back(cc);
127 }
128 }
129
130 if (pseudo)
131 symbol = pseudo->symbol();
132
133 delete pseudo;
134
135 element_values vals;
136
137 vals.file_rel_path_ = filename;
138 vals.lmax_ = INVALID_L;
139 vals.llocal_ = INVALID_L;
140
141 map_[symbol] = vals;
142 }
143
144 std::ifstream defaults_file((dirname + "/set_defaults").c_str());
145
146 if (defaults_file) {
147 std::string line;
148
149 // first line are comments
150 getline(defaults_file, line);
151
152 while (true) {
153 std::string symbol;
154 defaults_file >> symbol;
155 if (defaults_file.eof())
156 break;
157
158 if (has(symbol)) {
159 int z;
160 std::string fname;
161
162 defaults_file >> fname;
163 defaults_file >> z;
164 defaults_file >> map_[symbol].lmax_;
165 defaults_file >> map_[symbol].llocal_;
166 }
167
168 getline(defaults_file, line);
169 }
170
171 defaults_file.close();
172 }
173 closedir(dir);
174
175 // Write the element mapping file
176 const std::string file_name = dirname + "/elements_map.dat";
177 std::ofstream map_file(file_name);
178
179 if (!map_file.is_open()) {
180 throw std::ios_base::failure("Failed to open file for writing: " + file_name);
181 }
182
183 for (const auto& [symbol, elem] : map_) {
184 map_file << trim(symbol) << " "
185 << trim(elem.file_rel_path_) << " "
186 << elem.lmax_ << " "
187 << elem.llocal_ << "\n";
188 }
189
190 map_file.close();
191
192 }
193
194 // Load the map from the mapping file
195 void load_element_map(const std::string &dirname) {
196
197 // If this occurs, it means that we have a new set or a modified one.
198 // The generated file then needs to be copied in the source share folder and be added to the repo.
199 // Else, the parsing occurs at each run (sub-optimal).
200
201 std::ifstream map_file((dirname + "/elements_map.dat").c_str());
202 if (!map_file) {
203 std::cerr << "Internal warning: cannot open file element_map.dat for the pseudopotential set."
204 << std::endl;
205 std::cerr << "This will be regenerated in the installation folder."
206 << std::endl;
207 generate_element_map(dirname);
208 return;
209 }
210
211 std::string symbol;
212 while (map_file >> symbol) {
213 element_values vals;
214 // I didn't test this line
215 if (!(map_file >> vals.file_rel_path_ >> vals.lmax_ >> vals.llocal_)) {
216 std::cerr << "Error parsing the file: " << vals.file_rel_path_ << std::endl;
217 break;
218 }
219 map_[symbol] = vals;
220 }
221
222 }
223
224 static std::string &ltrim(std::string &str,
225 const std::string &chars = "\t\n\v\f\r ") {
226 str.erase(0, str.find_first_not_of(chars));
227 return str;
228 }
229
230 static std::string &rtrim(std::string &str,
231 const std::string &chars = "\t\n\v\f\r ") {
232 str.erase(str.find_last_not_of(chars) + 1);
233 return str;
234 }
235
236 static std::string trim(std::string str,
237 const std::string &chars = "\t\n\v\f\r ") {
238 return ltrim(rtrim(str, chars), chars);
239 }
240
241
242 // Iterator interface
243
244 class iterator {
245
246 private:
247 element_map::iterator map_it_;
248
249 public:
250 iterator(const element_map::iterator &map_it) : map_it_(map_it) {}
251
252 iterator &operator++() {
253 ++map_it_;
254 return *this;
255 }
256
257 friend bool operator!=(const iterator &a, const iterator &b) {
258 return a.map_it_ != b.map_it_;
259 }
260
261 element operator*() { return element(map_it_->first); }
262 };
263
264 iterator begin() { return iterator(map_.begin()); }
265 iterator end() { return iterator(map_.end()); }
266};
267
268} // namespace pseudopotential
269
270#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
type(oct_iterator_t), save iterator
struct __dirstream DIR
Definition: oct_f.c:4654
DIR DIR struct dirent * readdir(DIR *__dirp) __attribute__((__nonnull__(1)))
DIR * opendir(const char *__name) __attribute__((__nonnull__(1))) __attribute__((__malloc__)) __attribute__((__malloc__(closedir
int closedir(DIR *__dirp) __attribute__((__nonnull__(1)))