Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2019 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 : #include "Tools.h"
23 : #include "AtomNumber.h"
24 : #include "Exception.h"
25 : #include "IFile.h"
26 : #include "lepton/Lepton.h"
27 : #include <cstring>
28 : #include <dirent.h>
29 : #include <iostream>
30 : #include <map>
31 :
32 : using namespace std;
33 : namespace PLMD {
34 :
35 17677 : static std::map<string, double> leptonConstants= {
36 : {"e", std::exp(1.0)},
37 : {"log2e", 1.0/std::log(2.0)},
38 : {"log10e", 1.0/std::log(10.0)},
39 : {"ln2", std::log(2.0)},
40 : {"ln10", std::log(10.0)},
41 : {"pi", pi},
42 : {"pi_2", pi*0.5},
43 : {"pi_4", pi*0.25},
44 : // {"1_pi", 1.0/pi},
45 : // {"2_pi", 2.0/pi},
46 : // {"2_sqrtpi", 2.0/std::sqrt(pi)},
47 : {"sqrt2", std::sqrt(2.0)},
48 : {"sqrt1_2", std::sqrt(0.5)}
49 16070 : };
50 :
51 : template<class T>
52 4053529 : bool Tools::convertToAny(const string & str,T & t) {
53 4053529 : istringstream istr(str.c_str());
54 4053565 : bool ok=static_cast<bool>(istr>>t);
55 4053548 : if(!ok) return false;
56 3960540 : string remaining;
57 1980282 : istr>>remaining;
58 6033826 : return remaining.length()==0;
59 : }
60 :
61 212327 : bool Tools::convert(const string & str,int & t) {
62 212327 : return convertToAny(str,t);
63 : }
64 :
65 82 : bool Tools::convert(const string & str,long int & t) {
66 82 : return convertToAny(str,t);
67 : }
68 :
69 356552 : bool Tools::convert(const string & str,unsigned & t) {
70 356552 : return convertToAny(str,t);
71 : }
72 :
73 256130 : bool Tools::convert(const string & str,AtomNumber &a) {
74 : unsigned i;
75 256130 : bool r=convert(str,i);
76 256130 : if(r) a.setSerial(i);
77 256130 : return r;
78 : }
79 :
80 : template<class T>
81 3484571 : bool Tools::convertToReal(const string & str,T & t) {
82 3484571 : if(convertToAny(str,t)) return true;
83 2066459 : if(str=="PI" || str=="+PI" || str=="+pi" || str=="pi") {
84 1033259 : t=pi; return true;
85 1033199 : } else if(str=="-PI" || str=="-pi") {
86 1033177 : t=-pi; return true;
87 : }
88 : try {
89 20 : t=lepton::Parser::parse(str).evaluate(leptonConstants);
90 2 : return true;
91 18 : } catch(PLMD::lepton::Exception& exc) {
92 : }
93 18 : if( str.find("PI")!=std::string::npos ) {
94 0 : std::size_t pi_start=str.find_first_of("PI");
95 0 : if(str.substr(pi_start)!="PI") return false;
96 0 : istringstream nstr(str.substr(0,pi_start));
97 0 : T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
98 0 : if(!ok) return false;
99 0 : t=ff*pi;
100 0 : std::string remains; nstr>>remains;
101 0 : return remains.length()==0;
102 18 : } else if( str.find("pi")!=std::string::npos ) {
103 14 : std::size_t pi_start=str.find_first_of("pi");
104 14 : if(str.substr(pi_start)!="pi") return false;
105 14 : istringstream nstr(str.substr(0,pi_start));
106 14 : T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
107 14 : if(!ok) return false;
108 14 : t=ff*pi;
109 28 : std::string remains; nstr>>remains;
110 28 : return remains.length()==0;
111 4 : } else if(str=="NAN") {
112 0 : t=NAN;
113 0 : return true;
114 : }
115 4 : return false;
116 : }
117 :
118 0 : bool Tools::convert(const string & str,float & t) {
119 0 : return convertToReal(str,t);
120 : }
121 :
122 3484564 : bool Tools::convert(const string & str,double & t) {
123 3484564 : return convertToReal(str,t);
124 : }
125 :
126 0 : bool Tools::convert(const string & str,long double & t) {
127 0 : return convertToReal(str,t);
128 : }
129 :
130 26196 : bool Tools::convert(const string & str,string & t) {
131 26196 : t=str;
132 26196 : return true;
133 : }
134 :
135 569528 : vector<string> Tools::getWords(const string & line,const char* separators,int * parlevel,const char* parenthesis) {
136 569528 : plumed_massert(strlen(parenthesis)==1,"multiple parenthesis type not available");
137 569528 : plumed_massert(parenthesis[0]=='(' || parenthesis[0]=='[' || parenthesis[0]=='{',
138 0 : "only ( [ { allowed as parenthesis");
139 569528 : if(!separators) separators=" \t\n";
140 569528 : const string sep(separators);
141 569528 : char openpar=parenthesis[0];
142 : char closepar;
143 569528 : if(openpar=='(') closepar=')';
144 569528 : if(openpar=='[') closepar=']';
145 569528 : if(openpar=='{') closepar='}';
146 569528 : vector<string> words;
147 1139056 : string word;
148 569528 : int parenthesisLevel=0;
149 569528 : if(parlevel) parenthesisLevel=*parlevel;
150 20654731 : for(unsigned i=0; i<line.length(); i++) {
151 20085203 : bool found=false;
152 20085203 : bool onParenthesis=false;
153 20085203 : if(line[i]==openpar || line[i]==closepar) onParenthesis=true;
154 20085203 : if(line[i]==closepar) {
155 1456 : parenthesisLevel--;
156 1456 : plumed_massert(parenthesisLevel>=0,"Extra closed parenthesis in '" + line + "'");
157 : }
158 20085203 : if(parenthesisLevel==0) for(unsigned j=0; j<sep.length(); j++) if(line[i]==sep[j]) found=true;
159 : // If at parenthesis level zero (outer)
160 20085203 : if(!(parenthesisLevel==0 && (found||onParenthesis))) word.push_back(line[i]);
161 : //if(onParenthesis) word.push_back(' ');
162 20085203 : if(line[i]==openpar) parenthesisLevel++;
163 20085203 : if(found && word.length()>0) {
164 1062270 : if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
165 1062270 : words.push_back(word);
166 1062270 : word.clear();
167 : }
168 : }
169 569528 : if(word.length()>0) {
170 459882 : if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
171 459882 : words.push_back(word);
172 : }
173 569528 : if(parlevel) *parlevel=parenthesisLevel;
174 1139056 : return words;
175 : }
176 :
177 5657 : bool Tools::getParsedLine(IFile& ifile,vector<string> & words) {
178 5657 : string line("");
179 5657 : words.clear();
180 : bool stat;
181 5657 : bool inside=false;
182 5657 : int parlevel=0;
183 5657 : bool mergenext=false;
184 24075 : while((stat=ifile.getline(line))) {
185 17864 : trimComments(line);
186 17864 : trim(line);
187 17864 : if(line.length()==0) continue;
188 13458 : vector<string> w=getWords(line,NULL,&parlevel);
189 13458 : if(!w.empty()) {
190 13457 : if(inside && *(w.begin())=="...") {
191 918 : inside=false;
192 918 : if(w.size()==2) plumed_massert(w[1]==words[0],"second word in terminating \"...\" "+w[1]+" line, if present, should be equal to first word of directive: "+words[0]);
193 918 : plumed_massert(w.size()<=2,"terminating \"...\" lines cannot consist of more than two words");
194 918 : w.clear();
195 12539 : } else if(*(w.end()-1)=="...") {
196 918 : inside=true;
197 918 : w.erase(w.end()-1);
198 : };
199 13457 : int i0=0;
200 13457 : if(mergenext && words.size()>0 && w.size()>0) {
201 10 : words[words.size()-1]+=" "+w[0];
202 10 : i0=1;
203 : }
204 13457 : for(unsigned i=i0; i<w.size(); ++i) words.push_back(w[i]);
205 : }
206 13458 : mergenext=(parlevel>0);
207 13458 : if(!inside)break;
208 8355 : }
209 5657 : plumed_massert(parlevel==0,"non matching parenthesis");
210 5657 : if(words.size()>0) return true;
211 554 : return stat;
212 : }
213 :
214 :
215 1800066 : bool Tools::getline(FILE* fp,string & line) {
216 1800066 : line="";
217 1800066 : const int bufferlength=1024;
218 : char buffer[bufferlength];
219 : bool ret;
220 1800066 : for(int i=0; i<bufferlength; i++) buffer[i]='\0';
221 3600132 : while((ret=fgets(buffer,bufferlength,fp))) {
222 1799476 : line.append(buffer);
223 1799476 : unsigned ss=strlen(buffer);
224 1799476 : if(ss>0) if(buffer[ss-1]=='\n') break;
225 : };
226 1800066 : if(line.length()>0) if(*(line.end()-1)=='\n') line.erase(line.end()-1);
227 1800066 : if(line.length()>0) if(*(line.end()-1)=='\r') line.erase(line.end()-1);
228 1800066 : return ret;
229 : }
230 :
231 117485 : void Tools::trim(string & s) {
232 117485 : size_t n=s.find_last_not_of(" \t");
233 117485 : s=s.substr(0,n+1);
234 117485 : }
235 :
236 131264 : void Tools::trimComments(string & s) {
237 131264 : size_t n=s.find_first_of("#");
238 131264 : s=s.substr(0,n);
239 131264 : }
240 :
241 51924 : bool Tools::getKey(vector<string>& line,const string & key,string & s,int rep) {
242 51924 : s.clear();
243 256451 : for(auto p=line.begin(); p!=line.end(); ++p) {
244 229502 : if((*p).length()==0) continue;
245 229502 : string x=(*p).substr(0,key.length());
246 229502 : if(x==key) {
247 24975 : if((*p).length()==key.length())return false;
248 24974 : string tmp=(*p).substr(key.length(),(*p).length());
249 24974 : line.erase(p);
250 24974 : s=tmp;
251 49948 : const std::string multi("@replicas:");
252 24974 : if(rep>=0 && startWith(s,multi)) {
253 18 : s=s.substr(multi.length(),s.length());
254 18 : std::vector<std::string> words=getWords(s,"\t\n ,");
255 18 : plumed_massert(rep<static_cast<int>(words.size()),"Number of fields in " + s + " not consistent with number of replicas");
256 18 : s=words[rep];
257 : }
258 49948 : return true;
259 : }
260 204527 : };
261 26949 : return false;
262 : }
263 :
264 3349 : void Tools::interpretRanges(std::vector<std::string>&s) {
265 3349 : vector<string> news;
266 11097 : for(const auto & p :s) {
267 7748 : news.push_back(p);
268 7748 : size_t dash=p.find("-");
269 14666 : if(dash==string::npos) continue;
270 : int first;
271 1338 : if(!Tools::convert(p.substr(0,dash),first)) continue;
272 830 : int stride=1;
273 : int second;
274 830 : size_t colon=p.substr(dash+1).find(":");
275 830 : if(colon!=string::npos) {
276 44 : if(!Tools::convert(p.substr(dash+1).substr(0,colon),second) ||
277 33 : !Tools::convert(p.substr(dash+1).substr(colon+1),stride)) continue;
278 : } else {
279 819 : if(!Tools::convert(p.substr(dash+1),second)) continue;
280 : }
281 830 : news.resize(news.size()-1);
282 830 : if(first<=second) {
283 829 : plumed_massert(stride>0,"interpreting ranges "+ p + ", stride should be positive");
284 154076 : for(int i=first; i<=second; i+=stride) {
285 153247 : string ss;
286 153247 : convert(i,ss);
287 153247 : news.push_back(ss);
288 153247 : }
289 : } else {
290 1 : plumed_massert(stride<0,"interpreting ranges "+ p + ", stride should be positive");
291 3 : for(int i=first; i>=second; i+=stride) {
292 2 : string ss;
293 2 : convert(i,ss);
294 2 : news.push_back(ss);
295 2 : }
296 : }
297 : }
298 3349 : s=news;
299 3349 : }
300 :
301 5260 : void Tools::interpretLabel(vector<string>&s) {
302 5489 : if(s.size()<2)return;
303 5031 : string s0=s[0];
304 5031 : unsigned l=s0.length();
305 5031 : if(l<1) return;
306 5031 : if(s0[l-1]==':') {
307 2750 : s[0]=s[1];
308 2750 : s[1]="LABEL="+s0.substr(0,l-1);
309 5031 : }
310 : }
311 :
312 3156 : vector<string> Tools::ls(const string&d) {
313 : DIR*dir;
314 3156 : vector<string> result;
315 3156 : if ((dir=opendir(d.c_str()))) {
316 : #if defined(__PLUMED_HAS_READDIR_R)
317 : struct dirent ent;
318 : #endif
319 : while(true) {
320 : struct dirent *res;
321 : #if defined(__PLUMED_HAS_READDIR_R)
322 44579 : readdir_r(dir,&ent,&res);
323 : #else
324 : // cppcheck complains about this:
325 : // (portability) Non reentrant function 'readdir' called. For threadsafe applications it is recommended to use the reentrant replacement function 'readdir_r'.
326 : // since we use it only if readdir_r is not available, I suppress the warning
327 : // GB
328 : // cppcheck-suppress readdirCalled
329 : res=readdir(dir);
330 : #endif
331 44579 : if(!res) break;
332 41423 : if(string(res->d_name)!="." && string(res->d_name)!="..") result.push_back(res->d_name);
333 : }
334 44579 : closedir (dir);
335 : }
336 3156 : return result;
337 : }
338 :
339 1862 : void Tools::stripLeadingAndTrailingBlanks( std::string& str ) {
340 1862 : std::size_t first=str.find_first_not_of(' ');
341 1862 : std::size_t last=str.find_last_not_of(' ');
342 1862 : if( first<=last && first!=std::string::npos) str=str.substr(first,last+1);
343 1862 : }
344 :
345 8418 : std::string Tools::extension(const std::string&s) {
346 8418 : size_t n=s.find_last_of(".");
347 8418 : std::string ext;
348 8418 : if(n!=std::string::npos && n+1<s.length() && n+5>=s.length()) {
349 6193 : ext=s.substr(n+1);
350 6193 : if(ext.find("/")!=std::string::npos) ext="";
351 6193 : string base=s.substr(0,n);
352 6193 : if(base.length()==0) ext="";
353 6193 : if(base.length()>0 && base[base.length()-1]=='/') ext="";
354 : }
355 8418 : return ext;
356 : }
357 :
358 607627 : bool Tools::startWith(const std::string & full,const std::string &start) {
359 607627 : return (full.substr(0,start.length())==start);
360 : }
361 :
362 44630 : bool Tools::findKeyword(const std::vector<std::string>&line,const std::string&key) {
363 44630 : const std::string search(key+"=");
364 436588 : for(const auto & p : line) {
365 410907 : if(startWith(p,search)) return true;
366 : }
367 25681 : return false;
368 : }
369 :
370 :
371 :
372 4821 : }
|