Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2023 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 : #ifndef __PLUMED_tools_Tools_h
23 : #define __PLUMED_tools_Tools_h
24 :
25 : #include "AtomNumber.h"
26 : #include <vector>
27 : #include <string>
28 : #include <cctype>
29 : #include <cstdio>
30 : #include <cmath>
31 : #include <limits>
32 : #include <algorithm>
33 : #include <sstream>
34 : #include <memory>
35 : #include <cstddef>
36 :
37 : namespace PLMD {
38 :
39 : class IFile;
40 :
41 : /// \ingroup TOOLBOX
42 : /// Very small non-zero number
43 : const double epsilon(std::numeric_limits<double>::epsilon());
44 :
45 : /// \ingroup TOOLBOX
46 : /// Boltzman constant in kj/K
47 : const double kBoltzmann(0.0083144621);
48 :
49 : /// \ingroup TOOLBOX
50 : /// PI
51 : const double pi(3.141592653589793238462643383279502884197169399375105820974944592307);
52 :
53 : const double dp2cutoff(6.25);
54 :
55 : const double dp2cutoffA=1.00193418799744762399; // 1.0/(1-std::exp(-dp2cutoff));
56 : const double dp2cutoffB=-.00193418799744762399; // -std::exp(-dp2cutoff)/(1-std::exp(-dp2cutoff));
57 :
58 30395 : inline static bool dp2cutoffNoStretch() {
59 30395 : static const auto* res=std::getenv("PLUMED_DP2CUTOFF_NOSTRETCH");
60 30395 : return res;
61 : }
62 :
63 : /// \ingroup TOOLBOX
64 : /// Empty class which just contains several (static) tools
65 : class Tools {
66 : /// class to convert a string to a generic type T
67 : template<class T>
68 : static bool convertToAny(const std::string & str,T &t);
69 : /// class to convert a string to a real type T.
70 : /// T should be either float, double, or long double
71 : template<class T>
72 : static bool convertToReal(const std::string & str,T &t);
73 : /// class to convert a string to a int type T
74 : template<class T>
75 : static bool convertToInt(const std::string & str,T &t);
76 : public:
77 : /// Split the line in words using separators.
78 : /// It also take into account parenthesis. Outer parenthesis found are removed from
79 : /// output, and the text between them is considered as a single word. Only the
80 : /// outer parenthesis are processed, to allow nesting them.
81 : /// parlevel, if not NULL, is increased or decreased according to the number of opened/closed parenthesis
82 : static std::vector<std::string> getWords(const std::string & line,const char* sep=NULL,int* parlevel=NULL,const char* parenthesis="{", const bool& delete_parenthesis=true);
83 : /// Get a line from the file pointer ifile
84 : static bool getline(FILE*,std::string & line);
85 : /// Get a parsed line from the file pointer ifile
86 : /// This function already takes care of joining continued lines and splitting the
87 : /// resulting line into an array of words
88 : static bool getParsedLine(IFile&ifile,std::vector<std::string> & line, const bool trimcomments=true);
89 : /// compare two string in a case insensitive manner
90 : static bool caseInSensStringCompare(const std::string & str1, const std::string &str2);
91 : /// Convert a string to a double, reading it
92 : static bool convertNoexcept(const std::string & str,double & t);
93 : /// Convert a string to a long double, reading it
94 : static bool convertNoexcept(const std::string & str,long double & t);
95 : /// Convert a string to a float, reading it
96 : static bool convertNoexcept(const std::string & str,float & t);
97 : /// Convert a string to a int, reading it
98 : static bool convertNoexcept(const std::string & str,int & t);
99 : /// Convert a string to a long int, reading it
100 : static bool convertNoexcept(const std::string & str,long int & t);
101 : /// Convert a string to an unsigned int, reading it
102 : static bool convertNoexcept(const std::string & str,unsigned & t);
103 : /// Convert a string to a long unsigned int, reading it
104 : static bool convertNoexcept(const std::string & str,long unsigned & t);
105 : /// Convert a string to a atom number, reading it
106 : static bool convertNoexcept(const std::string & str,AtomNumber & t);
107 : /// Convert a string to a string (i.e. copy)
108 : static bool convertNoexcept(const std::string & str,std::string & t);
109 : /// Convert anything into a string
110 : template<typename T>
111 : static bool convertNoexcept(T i,std::string & str);
112 : /// Convert anything into anything, throwing an exception in case there is an error
113 : /// Remove trailing blanks
114 : static void trim(std::string & s);
115 : /// Remove trailing comments
116 : static void trimComments(std::string & s);
117 : /// Apply pbc for a unitary cell
118 : static double pbc(double);
119 : /// Retrieve a key from a vector of options.
120 : /// It finds a key starting with "key=" or equal to "key" and copy the
121 : /// part after the = on s. E.g.:
122 : /// line.push_back("aa=xx");
123 : /// getKey(line,"aa",s);
124 : /// will set s="xx"
125 : static bool getKey(std::vector<std::string>& line,const std::string & key,std::string & s,int rep=-1);
126 : /// Find a keyword on the input line, eventually deleting it, and saving its value to val
127 : template <typename T,typename U>
128 14244283 : static void convert(const T & t,U & u) {
129 14245070 : plumed_assert(convertNoexcept(t,u)) <<"Error converting "<<t;
130 14244282 : }
131 : template <typename T>
132 : static bool parse(std::vector<std::string>&line,const std::string&key,T&val,int rep=-1);
133 : /// Find a keyword on the input line, eventually deleting it, and saving its value to a vector
134 : template <class T>
135 : static bool parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep=-1);
136 : /// Find a keyword without arguments on the input line
137 : static bool parseFlag(std::vector<std::string>&line,const std::string&key,bool&val);
138 : /// Find a keyword on the input line, just reporting if it exists or not
139 : static bool findKeyword(const std::vector<std::string>&line,const std::string&key);
140 : /// Interpret atom ranges
141 : static void interpretRanges(std::vector<std::string>&);
142 : /// Remove duplicates from a vector of type T
143 : template <typename T>
144 : static void removeDuplicates(std::vector<T>& vec);
145 : /// interpret ":" syntax for labels
146 : static void interpretLabel(std::vector<std::string>&s);
147 : /// list files in a directory
148 : static std::vector<std::string> ls(const std::string&);
149 : /// removes leading and trailing blanks from a string
150 : static void stripLeadingAndTrailingBlanks( std::string& str );
151 : /// Extract the extensions from a file name.
152 : /// E.g.: extension("pippo.xyz")="xyz".
153 : /// It only returns extensions with a length between 1 and 4
154 : /// E.g.: extension("pippo.12345")="" whereas extenion("pippo.1234")="1234";
155 : /// It is also smart enough to detect "/", so that
156 : /// extension("pippo/.t")="" whereas extension("pippo/a.t")="t"
157 : static std::string extension(const std::string&);
158 : /// Fast int power
159 : static double fastpow(double base,int exp);
160 : /// Modified 0th-order Bessel function of the first kind
161 : static double bessel0(const double& val);
162 : /// Check if a string full starts with string start.
163 : /// Same as full.find(start)==0
164 : static bool startWith(const std::string & full,const std::string &start);
165 : /**
166 : Tool to create a vector of raw pointers from a vector of unique_pointers (const version).
167 : Returning a vector is fast in C++11. It can be used in order to feed a vector<unique_ptr<T>>
168 : to a function that takes a vector<T*>.
169 : \verbatim
170 : // some function that takes a vec
171 : void func(std::vector<Data*> & vec);
172 : std::vector<std::unique_ptr<Data>> vec;
173 : // func(vec); // does not compile
174 : func(Tools::unique2raw(vec)); // compiles
175 : \endverbatim
176 : Notice that the conversion is fast but takes
177 : some time to allocate the new vector and copy the pointers. In case the function
178 : acting on the vector<T*> is very fast and we do not want to add significant overhead,
179 : it might be convenient to store a separate set of raw pointers.
180 : \verbatim
181 : // some function that takes a vec
182 : void func(std::vector<Data*> & vec);
183 : std::vector<std::unique_ptr<Data>> vec;
184 :
185 : // conversion done only once:
186 : auto vec_ptr=Tools::unique2raw(vec);
187 :
188 : for(int i=0;i<1000;i++){
189 : func(vec_ptr);
190 : }
191 : \endverbatim
192 : */
193 : template <typename T>
194 : static std::vector<T*> unique2raw(const std::vector<std::unique_ptr<T>>&);
195 : /// Tool to create a vector of raw pointers from a vector of unique_pointers.
196 : /// See the non const version.
197 : template <typename T>
198 : static std::vector<const T*> unique2raw(const std::vector<std::unique_ptr<const T>>&);
199 : /// Tiny class that changes directory and comes back when going out of scope.
200 : /// In case system calls to change dir are not available it throws an exception.
201 : /// \warning By construction, changing directory breaks thread safety! Use with care.
202 : class DirectoryChanger {
203 : static const std::size_t buffersize=4096;
204 : char cwd[buffersize]= {0};
205 : public:
206 : explicit DirectoryChanger(const char*path);
207 : ~DirectoryChanger();
208 : };
209 : /// Mimic C++14 std::make_unique
210 : template<class T> struct _Unique_if {
211 : typedef std::unique_ptr<T> _Single_object;
212 : };
213 : template<class T> struct _Unique_if<T[]> {
214 : typedef std::unique_ptr<T[]> _Unknown_bound;
215 : };
216 : template<class T, std::size_t N> struct _Unique_if<T[N]> {
217 : typedef void _Known_bound;
218 : };
219 : template<class T, class... Args>
220 : static typename _Unique_if<T>::_Single_object
221 4987385 : make_unique(Args&&... args) {
222 8581959 : return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
223 : }
224 : template<class T>
225 : static typename _Unique_if<T>::_Unknown_bound
226 853191 : make_unique(std::size_t n) {
227 : typedef typename std::remove_extent<T>::type U;
228 426515820 : return std::unique_ptr<T>(new U[n]());
229 : }
230 : template<class T, class... Args>
231 : static typename _Unique_if<T>::_Known_bound
232 : make_unique(Args&&...) = delete;
233 : };
234 :
235 : template <class T>
236 55575 : bool Tools::parse(std::vector<std::string>&line,const std::string&key,T&val,int rep) {
237 : std::string s;
238 111150 : if(!getKey(line,key+"=",s,rep)) return false;
239 28048 : if(s.length()>0 && !convertNoexcept(s,val))return false;
240 : return true;
241 : }
242 :
243 : template <class T>
244 35005 : bool Tools::parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep) {
245 : std::string s;
246 70010 : if(!getKey(line,key+"=",s,rep)) return false;
247 16271 : val.clear();
248 25939 : std::vector<std::string> words=getWords(s,"\t\n ,");
249 113132 : for(unsigned i=0; i<words.size(); ++i) {
250 : T v;
251 87193 : std::string s=words[i];
252 87193 : const std::string multi("@replicas:");
253 87193 : if(rep>=0 && startWith(s,multi)) {
254 6 : s=s.substr(multi.length(),s.length());
255 6 : std::vector<std::string> words=getWords(s,"\t\n ,");
256 6 : plumed_assert(rep<static_cast<int>(words.size()));
257 6 : s=words[rep];
258 6 : }
259 87193 : if(!convertNoexcept(s,v))return false;
260 87193 : val.push_back(v);
261 : }
262 : return true;
263 25939 : }
264 :
265 : template<typename T>
266 3186 : void Tools::removeDuplicates(std::vector<T>& vec)
267 : {
268 3186 : std::sort(vec.begin(), vec.end());
269 3186 : vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
270 3186 : }
271 :
272 : inline
273 42714 : bool Tools::parseFlag(std::vector<std::string>&line,const std::string&key,bool&val) {
274 103986 : for(auto p=line.begin(); p!=line.end(); ++p) {
275 62760 : if(key==*p) {
276 1488 : val=true;
277 : line.erase(p);
278 : return true;
279 : }
280 : }
281 : return false;
282 : }
283 :
284 : /// beware: this brings any number into a pbc that ranges from -0.5 to 0.5
285 : inline
286 1820307219 : double Tools::pbc(double x) {
287 : #ifdef __PLUMED_PBC_WHILE
288 : while (x>0.5) x-=1.0;
289 : while (x<-0.5) x+=1.0;
290 : return x;
291 : #else
292 : if(std::numeric_limits<int>::round_style == std::round_toward_zero) {
293 : const double offset=100.0;
294 1820307219 : const double y=x+offset;
295 1820307219 : if(y>=0) return y-int(y+0.5);
296 4577 : else return y-int(y-0.5);
297 : } else if(std::numeric_limits<int>::round_style == std::round_to_nearest) {
298 : return x-int(x);
299 : } else return x-floor(x+0.5);
300 : #endif
301 : }
302 :
303 : template<typename T>
304 323884 : bool Tools::convertNoexcept(T i,std::string & str) {
305 323884 : std::ostringstream ostr;
306 210598 : ostr<<i;
307 323884 : str=ostr.str();
308 323884 : return true;
309 323884 : }
310 :
311 : inline
312 79175734 : double Tools::fastpow(double base, int exp)
313 : {
314 79175734 : if(exp<0) {
315 0 : exp=-exp;
316 0 : base=1.0/base;
317 : }
318 : double result = 1.0;
319 375014649 : while (exp)
320 : {
321 262238721 : if (exp & 1)
322 181137188 : result *= base;
323 262238721 : exp >>= 1;
324 262238721 : base *= base;
325 : }
326 :
327 79175734 : return result;
328 : }
329 :
330 : template<typename T>
331 13703470 : std::vector<T*> Tools::unique2raw(const std::vector<std::unique_ptr<T>> & x) {
332 13703470 : std::vector<T*> v(x.size());
333 52721172 : for(unsigned i=0; i<x.size(); i++) v[i]=x[i].get();
334 13703470 : return v;
335 : }
336 :
337 : template<typename T>
338 : std::vector<const T*> Tools::unique2raw(const std::vector<std::unique_ptr<const T>> & x) {
339 : std::vector<const T*> v(x.size());
340 : for(unsigned i=0; i<x.size(); i++) v[i]=x[i].get();
341 : return v;
342 : }
343 :
344 : }
345 :
346 : #endif
347 :
|