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.h"
27 : #include "Tensor.h"
28 : #include "small_vector/small_vector.h"
29 : #include <vector>
30 : #include <string>
31 : #include <cctype>
32 : #include <cstdio>
33 : #include <cmath>
34 : #include <limits>
35 : #include <algorithm>
36 : #include <sstream>
37 : #include <memory>
38 : #include <cstddef>
39 : #include <queue>
40 : #include <mutex>
41 : #include <filesystem>
42 : #include <utility>
43 : #include <unordered_map>
44 : #include <map>
45 : #include <condition_variable>
46 :
47 : namespace PLMD {
48 :
49 : class IFile;
50 :
51 : /// \ingroup TOOLBOX
52 : /// Very small non-zero number
53 : constexpr double epsilon(std::numeric_limits<double>::epsilon());
54 :
55 : /// \ingroup TOOLBOX
56 : /// Boltzman constant in kj/K
57 : constexpr double kBoltzmann(0.0083144621);
58 :
59 : /// \ingroup TOOLBOX
60 : /// PI
61 : constexpr double pi(3.141592653589793238462643383279502884197169399375105820974944592307);
62 :
63 : constexpr double dp2cutoff(6.25);
64 :
65 : constexpr double dp2cutoffA=1.00193418799744762399; // 1.0/(1-std::exp(-dp2cutoff));
66 : constexpr double dp2cutoffB=-.00193418799744762399; // -std::exp(-dp2cutoff)/(1-std::exp(-dp2cutoff));
67 :
68 5719 : inline static bool dp2cutoffNoStretch() {
69 5719 : static const auto* res=std::getenv("PLUMED_DP2CUTOFF_NOSTRETCH");
70 5719 : return res;
71 : }
72 :
73 : /// \ingroup TOOLBOX
74 : /// Empty class which just contains several (static) tools
75 : class Tools {
76 : /// class to convert a string to a generic type T
77 : template<class T>
78 : static bool convertToAny(const std::string & str,T &t);
79 : /// class to convert a string to a real type T.
80 : /// T should be either float, double, or long double
81 : template<class T>
82 : static bool convertToReal(const std::string & str,T &t);
83 : /// class to convert a string to a int type T
84 : template<class T>
85 : static bool convertToInt(const std::string & str,T &t);
86 : /// @brief the recursive part of the template fastpow implementation
87 : template <int exp, typename T=double, std::enable_if_t< (exp >=0), bool> = true>
88 : static inline /*consteval*/ T fastpow_rec(T base, T result);
89 : public:
90 : /// Split the line in words using separators.
91 : /// It also take into account parenthesis. Outer parenthesis found are removed from
92 : /// output, and the text between them is considered as a single word. Only the
93 : /// outer parenthesis are processed, to allow nesting them.
94 : /// parlevel, if not NULL, is increased or decreased according to the number of opened/closed parenthesis
95 : static std::vector<std::string> getWords(std::string_view line,const char* sep=NULL,int* parlevel=NULL,const char* parenthesis="{", const bool& delete_parenthesis=true);
96 : /// Faster version
97 : /// This version does not parse parenthesis and operates on a preallocated small_vector of string_view's
98 : static void getWordsSimple(gch::small_vector<std::string_view> & words,std::string_view line);
99 : /// Get a line from the file pointer ifile
100 : static bool getline(FILE*,std::string & line);
101 : /// Get a parsed line from the file pointer ifile
102 : /// This function already takes care of joining continued lines and splitting the
103 : /// resulting line into an array of words
104 : static bool getParsedLine(IFile&ifile,std::vector<std::string> & line, const bool trimcomments=true);
105 : /// compare two string in a case insensitive manner
106 : static bool caseInSensStringCompare(const std::string & str1, const std::string &str2);
107 : /// Convert a string to a double, reading it
108 : static bool convertNoexcept(const std::string & str,double & t);
109 : /// Convert a string to a long double, reading it
110 : static bool convertNoexcept(const std::string & str,long double & t);
111 : /// Convert a string to a float, reading it
112 : static bool convertNoexcept(const std::string & str,float & t);
113 : /// Convert a string to a int, reading it
114 : static bool convertNoexcept(const std::string & str,int & t);
115 : /// Convert a string to a long int, reading it
116 : static bool convertNoexcept(const std::string & str,long int & t);
117 : /// Convert a string to a long long int, reading it
118 : static bool convertNoexcept(const std::string & str,long long int & t);
119 : /// Convert a string to an unsigned int, reading it
120 : static bool convertNoexcept(const std::string & str,unsigned & t);
121 : /// Convert a string to a long unsigned int, reading it
122 : static bool convertNoexcept(const std::string & str,long unsigned & t);
123 : /// Convert a string to a long long unsigned int, reading it
124 : static bool convertNoexcept(const std::string & str,long long unsigned & t);
125 : /// Convert a string to a atom number, reading it
126 : static bool convertNoexcept(const std::string & str,AtomNumber & t);
127 : /// Convert a string to a string (i.e. copy)
128 : static bool convertNoexcept(const std::string & str,std::string & t);
129 : /// Convert anything into a string
130 : template<typename T>
131 : static bool convertNoexcept(T i,std::string & str);
132 : /// Convert anything into anything, throwing an exception in case there is an error
133 : /// Remove trailing blanks
134 : static void trim(std::string & s);
135 : /// Remove leading blanks
136 : static void ltrim(std::string & s);
137 : /// Remove trailing comments
138 : static void trimComments(std::string & s);
139 : /// Apply pbc for a unitary cell
140 : static double pbc(double);
141 : /// Retrieve a key from a vector of options.
142 : /// It finds a key starting with "key=" or equal to "key" and copy the
143 : /// part after the = on s. E.g.:
144 : /// line.push_back("aa=xx");
145 : /// getKey(line,"aa",s);
146 : /// will set s="xx"
147 : static bool getKey(std::vector<std::string>& line,const std::string & key,std::string & s,int rep=-1);
148 : /// Find a keyword on the input line, eventually deleting it, and saving its value to val
149 : template <typename T,typename U>
150 23817899 : static void convert(const T & t,U & u) {
151 23818942 : plumed_assert(convertNoexcept(t,u)) <<"Error converting "<<t;
152 23817898 : }
153 : template <typename T>
154 : static bool parse(std::vector<std::string>&line,const std::string&key,T&val,int rep=-1);
155 : /// Find a keyword on the input line, eventually deleting it, and saving its value to a vector
156 : template <class T>
157 : static bool parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep=-1);
158 : /// Find a keyword without arguments on the input line
159 : static bool parseFlag(std::vector<std::string>&line,const std::string&key,bool&val);
160 : /// Find a keyword on the input line, just reporting if it exists or not
161 : static bool findKeyword(const std::vector<std::string>&line,const std::string&key);
162 : /// Interpret atom ranges
163 : static void interpretRanges(std::vector<std::string>&);
164 : /// Remove duplicates from a vector of type T
165 : template <typename T>
166 : static void removeDuplicates(std::vector<T>& vec);
167 : /// interpret ":" syntax for labels
168 : static void interpretLabel(std::vector<std::string>&s);
169 : /// list files in a directory
170 : static std::vector<std::string> ls(const std::string&);
171 : /// removes leading and trailing blanks from a string
172 : static void stripLeadingAndTrailingBlanks( std::string& str );
173 : /// Extract the extensions from a file name.
174 : /// E.g.: extension("pippo.xyz")="xyz".
175 : /// It only returns extensions with a length between 1 and 4
176 : /// E.g.: extension("pippo.12345")="" whereas extenion("pippo.1234")="1234";
177 : /// It is also smart enough to detect "/", so that
178 : /// extension("pippo/.t")="" whereas extension("pippo/a.t")="t"
179 : static std::string extension(const std::string&);
180 : /// Fast int power
181 : static double fastpow(double base,int exp);
182 : /// Fast int power for power known at compile time
183 : template <int exp, typename T=double>
184 : static inline /*consteval*/ T fastpow(T base);
185 : /// Modified 0th-order Bessel function of the first kind
186 : static double bessel0(const double& val);
187 : /// Check if a string full starts with string start.
188 : /// Same as full.find(start)==0
189 : static bool startWith(const std::string & full,const std::string &start);
190 : /**
191 : Tool to create a vector of raw pointers from a vector of unique_pointers (const version).
192 : Returning a vector is fast in C++11. It can be used in order to feed a vector<unique_ptr<T>>
193 : to a function that takes a vector<T*>.
194 : \verbatim
195 : // some function that takes a vec
196 : void func(std::vector<Data*> & vec);
197 : std::vector<std::unique_ptr<Data>> vec;
198 : // func(vec); // does not compile
199 : func(Tools::unique2raw(vec)); // compiles
200 : \endverbatim
201 : Notice that the conversion is fast but takes
202 : some time to allocate the new vector and copy the pointers. In case the function
203 : acting on the vector<T*> is very fast and we do not want to add significant overhead,
204 : it might be convenient to store a separate set of raw pointers.
205 : \verbatim
206 : // some function that takes a vec
207 : void func(std::vector<Data*> & vec);
208 : std::vector<std::unique_ptr<Data>> vec;
209 :
210 : // conversion done only once:
211 : auto vec_ptr=Tools::unique2raw(vec);
212 :
213 : for(int i=0;i<1000;i++){
214 : func(vec_ptr);
215 : }
216 : \endverbatim
217 : */
218 : template <typename T>
219 : static std::vector<T*> unique2raw(const std::vector<std::unique_ptr<T>>&);
220 : /// Tool to create a vector of raw pointers from a vector of unique_pointers.
221 : /// See the non const version.
222 : template <typename T>
223 : static std::vector<const T*> unique2raw(const std::vector<std::unique_ptr<const T>>&);
224 : /// Tiny class that changes directory and comes back when going out of scope.
225 : /// In case system calls to change dir are not available it throws an exception.
226 : /// \warning By construction, changing directory breaks thread safety! Use with care.
227 : class DirectoryChanger {
228 : const std::filesystem::path path;
229 : public:
230 : explicit DirectoryChanger(const char*path);
231 : ~DirectoryChanger();
232 : };
233 :
234 : template<class T, class... Args>
235 : static auto make_unique(Args&&... args) {
236 152587 : return std::make_unique<T>(std::forward<Args>(args)...);
237 : }
238 :
239 : static void set_to_zero(double*ptr,unsigned n) {
240 1276640 : for(unsigned i=0; i<n; i++) ptr[i]=0.0;
241 : }
242 :
243 : template<unsigned n>
244 28739 : static void set_to_zero(std::vector<VectorGeneric<n>> & vec) {
245 28739 : unsigned s=vec.size();
246 28739 : if(s==0) return;
247 28739 : set_to_zero(&vec[0][0],s*n);
248 : }
249 :
250 : template<unsigned n,unsigned m>
251 : static void set_to_zero(std::vector<TensorGeneric<n,m>> & vec) {
252 : unsigned s=vec.size();
253 : if(s==0) return;
254 : set_to_zero(&vec[0](0,0),s*n*m);
255 : }
256 :
257 : static std::unique_ptr<std::lock_guard<std::mutex>> molfile_lock();
258 : /// Build a concatenated exception message.
259 : /// Should be called with an in-flight exception.
260 : static std::string concatenateExceptionMessages();
261 :
262 :
263 : /// Tiny class implementing faster std::string_view access to an unordered_map
264 : /// It exposes a limited number of methods of std::unordered_map. Others could be added.
265 : /// Importantly, when it is accessed via a std::string_view, the access does not
266 : /// require constructing a std::string and is thus faster.
267 : /// Deletion would be slower instead. It's not even implemented yet.
268 : template<class T>
269 806722 : class FastStringUnorderedMap {
270 : std::unordered_map<std::string_view,T> map;
271 : std::vector<std::unique_ptr<const char[]>> keys;
272 :
273 : // see https://stackoverflow.com/questions/34596768/stdunordered-mapfind-using-a-type-different-than-the-key-type
274 493136 : std::unique_ptr<const char[]> conv(std::string_view str) {
275 493136 : auto p=std::make_unique<char[]>(str.size()+1);
276 : std::memcpy(p.get(), str.data(), str.size()+1);
277 493136 : return p;
278 : }
279 :
280 : public:
281 :
282 : FastStringUnorderedMap() = default;
283 10761 : FastStringUnorderedMap(std::initializer_list<std::pair<const std::string_view,T>> init) {
284 490139 : for(const auto & c : init) {
285 479378 : (*this)[c.first]=c.second;
286 : }
287 10761 : }
288 :
289 3510609 : T& operator[]( const std::string_view & key ) {
290 : auto f=map.find(key);
291 3510609 : if(f!=map.end()) return f->second;
292 986272 : keys.push_back(conv(key));
293 493136 : return map[keys.back().get()];
294 : }
295 :
296 : auto begin() {
297 : return map.begin();
298 : }
299 : auto end() {
300 : return map.end();
301 : }
302 : auto begin() const {
303 : return map.begin();
304 : }
305 : auto end() const {
306 : return map.end();
307 : }
308 : auto find(const std::string_view & key) {
309 : return map.find(key);
310 : }
311 : auto find(const std::string_view & key) const {
312 : return map.find(key);
313 : }
314 : };
315 :
316 : /// Utility to create named critical sections
317 : /// Key should be usable in a std::map
318 : template<class Key>
319 : class CriticalSectionWithKey {
320 : std::mutex mutex;
321 : std::condition_variable notify;
322 : std::map<Key, int> in_progress;
323 : public:
324 23 : void start(const Key & key) {
325 23 : std::unique_lock<std::mutex> lock(mutex);
326 128 : while (in_progress[key] > 0) {
327 : // Wait if this command is already in progress.
328 105 : notify.wait(lock);
329 : }
330 : // Mark this command as in progress.
331 23 : in_progress[key]++;
332 23 : }
333 23 : void stop(const Key & key) {
334 23 : std::unique_lock<std::mutex> lock(mutex);
335 : // Mark this command as completed.
336 23 : in_progress[key]--;
337 : // Notify other threads that may be waiting for this command to complete.
338 23 : notify.notify_all();
339 23 : }
340 : class Handler {
341 : CriticalSectionWithKey* section{nullptr};
342 : Key key;
343 23 : Handler(CriticalSectionWithKey* section,const Key& key):
344 23 : section(section),
345 23 : key(key)
346 : {
347 23 : section->start(key);
348 23 : }
349 : friend class CriticalSectionWithKey;
350 : public:
351 : /// Default constructor
352 : Handler() = default;
353 : /// Default copy constructor is deleted (not copyable)
354 : Handler(const Handler & handler) = delete;
355 : /// Default copy assignment is deleted (not copyable)
356 : Handler & operator=(const Handler & handler) = delete;
357 : /// Move constructor.
358 : Handler(Handler && handler) noexcept :
359 : section(handler.section),
360 : key(std::move(handler.key))
361 : {
362 : handler.section=nullptr;
363 : };
364 : /// Move assignment.
365 : Handler & operator=(Handler && handler) noexcept {
366 : if(this!=&handler) {
367 : if(section) section->stop(key);
368 : section=handler.section;
369 : key=std::move(handler.key);
370 : }
371 : handler.section=nullptr;
372 : return *this;
373 : }
374 : /// Destructor
375 23 : ~Handler() {
376 23 : if(section) section->stop(key);
377 23 : }
378 : };
379 :
380 : Handler startStop(const Key & key) {
381 23 : return Handler(this,key);
382 : }
383 :
384 : };
385 :
386 : };
387 :
388 : template <class T>
389 355133 : bool Tools::parse(std::vector<std::string>&line,const std::string&key,T&val,int rep) {
390 : std::string s;
391 710266 : if(!getKey(line,key+"=",s,rep)) return false;
392 281438 : if(s.length()>0 && !convertNoexcept(s,val))return false;
393 : return true;
394 : }
395 :
396 : template <class T>
397 255787 : bool Tools::parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep) {
398 : std::string s;
399 511574 : if(!getKey(line,key+"=",s,rep)) return false;
400 : val.clear();
401 233417 : std::vector<std::string> words=getWords(s,"\t\n ,");
402 4663367 : for(unsigned i=0; i<words.size(); ++i) {
403 : T v;
404 4429950 : std::string s=words[i];
405 4429950 : const std::string multi("@replicas:");
406 4429950 : if(rep>=0 && startWith(s,multi)) {
407 6 : s=s.substr(multi.length(),s.length());
408 6 : std::vector<std::string> words=getWords(s,"\t\n ,");
409 6 : plumed_assert(rep<static_cast<int>(words.size()));
410 6 : s=words[rep];
411 6 : }
412 4429950 : if(!convertNoexcept(s,v))return false;
413 4429950 : val.push_back(v);
414 : }
415 : return true;
416 233417 : }
417 :
418 : template<typename T>
419 92127 : void Tools::removeDuplicates(std::vector<T>& vec)
420 : {
421 92127 : std::sort(vec.begin(), vec.end());
422 92127 : vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
423 92127 : }
424 :
425 : inline
426 98346 : bool Tools::parseFlag(std::vector<std::string>&line,const std::string&key,bool&val) {
427 697456 : for(auto p=line.begin(); p!=line.end(); ++p) {
428 611058 : if(key==*p) {
429 11948 : val=true;
430 : line.erase(p);
431 : return true;
432 : }
433 : }
434 : return false;
435 : }
436 :
437 : /// beware: this brings any number into a pbc that ranges from -0.5 to 0.5
438 : inline
439 1784385455 : double Tools::pbc(double x) {
440 : #ifdef __PLUMED_PBC_WHILE
441 : while (x>0.5) x-=1.0;
442 : while (x<-0.5) x+=1.0;
443 : return x;
444 : #else
445 : if constexpr (std::numeric_limits<int>::round_style == std::round_toward_zero) {
446 : constexpr double offset=100.0;
447 1784385455 : const double y=x+offset;
448 1784385455 : if(y>=0) return y-int(y+0.5);
449 4578 : else return y-int(y-0.5);
450 : } else if constexpr (std::numeric_limits<int>::round_style == std::round_to_nearest) {
451 : return x-int(x);
452 : } else return x-floor(x+0.5);
453 : #endif
454 : }
455 :
456 : template<typename T>
457 7151658 : bool Tools::convertNoexcept(T i,std::string & str) {
458 7151658 : std::ostringstream ostr;
459 778612 : ostr<<i;
460 7151658 : str=ostr.str();
461 7151658 : return true;
462 7151658 : }
463 :
464 : inline
465 56252767 : double Tools::fastpow(double base, int exp)
466 : {
467 56252767 : if(exp<0) {
468 0 : exp=-exp;
469 0 : base=1.0/base;
470 : }
471 : double result = 1.0;
472 289015368 : while (exp)
473 : {
474 199162409 : if (exp & 1)
475 140896039 : result *= base;
476 199162409 : exp >>= 1;
477 199162409 : base *= base;
478 : }
479 :
480 56252767 : return result;
481 : }
482 :
483 : template <int exp, typename T, std::enable_if_t< (exp >=0), bool>>
484 : inline T Tools::fastpow_rec(T const base, T result) {
485 : if constexpr (exp == 0) {
486 : return result;
487 : }
488 : if constexpr (exp & 1) {
489 19283644 : result *= base;
490 : }
491 11328670 : return fastpow_rec<(exp>>1),T> (base*base, result);
492 : }
493 :
494 : template <int exp, typename T>
495 : inline T Tools::fastpow(T const base) {
496 : if constexpr (exp<0) {
497 : return fastpow_rec<-exp,T>(1.0/base,1.0);
498 : } else {
499 : return fastpow_rec<exp,T>(base, 1.0);
500 : }
501 : }
502 :
503 : template<typename T>
504 2307 : std::vector<T*> Tools::unique2raw(const std::vector<std::unique_ptr<T>> & x) {
505 2307 : std::vector<T*> v(x.size());
506 3681 : for(unsigned i=0; i<x.size(); i++) v[i]=x[i].get();
507 2307 : return v;
508 : }
509 :
510 : template<typename T>
511 : std::vector<const T*> Tools::unique2raw(const std::vector<std::unique_ptr<const T>> & x) {
512 : std::vector<const T*> v(x.size());
513 : for(unsigned i=0; i<x.size(); i++) v[i]=x[i].get();
514 : return v;
515 : }
516 :
517 : }
518 :
519 : #endif
|