LCOV - code coverage report
Current view: top level - tools - Tools.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 82 102 80.4 %
Date: 2026-03-30 13:16:06 Functions: 401 434 92.4 %

          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 <vector>
      29             : #include <string>
      30             : #include <cctype>
      31             : #include <cstdio>
      32             : #include <cmath>
      33             : #include <limits>
      34             : #include <algorithm>
      35             : #include <sstream>
      36             : #include <memory>
      37             : #include <cstddef>
      38             : #include <queue>
      39             : #include <mutex>
      40             : 
      41             : namespace PLMD {
      42             : 
      43             : class IFile;
      44             : 
      45             : /// \ingroup TOOLBOX
      46             : /// Very small non-zero number
      47             : const double epsilon(std::numeric_limits<double>::epsilon());
      48             : 
      49             : /// \ingroup TOOLBOX
      50             : /// Boltzman constant in kj/K
      51             : const double kBoltzmann(0.0083144621);
      52             : 
      53             : /// \ingroup TOOLBOX
      54             : /// PI
      55             : const double pi(3.141592653589793238462643383279502884197169399375105820974944592307);
      56             : 
      57             : const double dp2cutoff(6.25);
      58             : 
      59             : const double dp2cutoffA=1.00193418799744762399; // 1.0/(1-std::exp(-dp2cutoff));
      60             : const double dp2cutoffB=-.00193418799744762399; // -std::exp(-dp2cutoff)/(1-std::exp(-dp2cutoff));
      61             : 
      62       30397 : inline static bool dp2cutoffNoStretch() {
      63       30397 :   static const auto* res=std::getenv("PLUMED_DP2CUTOFF_NOSTRETCH");
      64       30397 :   return res;
      65             : }
      66             : 
      67             : /// \ingroup TOOLBOX
      68             : /// Empty class which just contains several (static) tools
      69             : class Tools {
      70             : /// class to convert a string to a generic type T
      71             :   template<class T>
      72             :   static bool convertToAny(const std::string & str,T &t);
      73             : /// class to convert a string to a real type T.
      74             : /// T should be either float, double, or long double
      75             :   template<class T>
      76             :   static bool convertToReal(const std::string & str,T &t);
      77             : /// class to convert a string to a int type T
      78             :   template<class T>
      79             :   static bool convertToInt(const std::string & str,T &t);
      80             : public:
      81             : /// Split the line in words using separators.
      82             : /// It also take into account parenthesis. Outer parenthesis found are removed from
      83             : /// output, and the text between them is considered as a single word. Only the
      84             : /// outer parenthesis are processed, to allow nesting them.
      85             : /// parlevel, if not NULL, is increased or decreased according to the number of opened/closed parenthesis
      86             :   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);
      87             : /// Get a line from the file pointer ifile
      88             :   static bool getline(FILE*,std::string & line);
      89             : /// Get a parsed line from the file pointer ifile
      90             : /// This function already takes care of joining continued lines and splitting the
      91             : /// resulting line into an array of words
      92             :   static bool getParsedLine(IFile&ifile,std::vector<std::string> & line, const bool trimcomments=true);
      93             : /// compare two string in a case insensitive manner
      94             :   static bool caseInSensStringCompare(const std::string & str1, const std::string &str2);
      95             : /// Convert a string to a double, reading it
      96             :   static bool convertNoexcept(const std::string & str,double & t);
      97             : /// Convert a string to a long double, reading it
      98             :   static bool convertNoexcept(const std::string & str,long double & t);
      99             : /// Convert a string to a float, reading it
     100             :   static bool convertNoexcept(const std::string & str,float & t);
     101             : /// Convert a string to a int, reading it
     102             :   static bool convertNoexcept(const std::string & str,int & t);
     103             : /// Convert a string to a long int, reading it
     104             :   static bool convertNoexcept(const std::string & str,long int & t);
     105             : /// Convert a string to a long long int, reading it
     106             :   static bool convertNoexcept(const std::string & str,long long int & t);
     107             : /// Convert a string to an unsigned int, reading it
     108             :   static bool convertNoexcept(const std::string & str,unsigned & t);
     109             : /// Convert a string to a long unsigned int, reading it
     110             :   static bool convertNoexcept(const std::string & str,long unsigned & t);
     111             : /// Convert a string to a long long unsigned int, reading it
     112             :   static bool convertNoexcept(const std::string & str,long long unsigned & t);
     113             : /// Convert a string to a atom number, reading it
     114             :   static bool convertNoexcept(const std::string & str,AtomNumber & t);
     115             : /// Convert a string to a string (i.e. copy)
     116             :   static bool convertNoexcept(const std::string & str,std::string & t);
     117             : /// Convert anything into a string
     118             :   template<typename T>
     119             :   static bool convertNoexcept(T i,std::string & str);
     120             : /// Convert anything into anything, throwing an exception in case there is an error
     121             : /// Remove trailing blanks
     122             :   static void trim(std::string & s);
     123             : /// Remove trailing comments
     124             :   static void trimComments(std::string & s);
     125             : /// Apply pbc for a unitary cell
     126             :   static double pbc(double);
     127             : /// Retrieve a key from a vector of options.
     128             : /// It finds a key starting with "key=" or equal to "key" and copy the
     129             : /// part after the = on s. E.g.:
     130             : /// line.push_back("aa=xx");
     131             : /// getKey(line,"aa",s);
     132             : /// will set s="xx"
     133             :   static bool getKey(std::vector<std::string>& line,const std::string & key,std::string & s,int rep=-1);
     134             : /// Find a keyword on the input line, eventually deleting it, and saving its value to val
     135             :   template <typename T,typename U>
     136    14737602 :   static void convert(const T & t,U & u) {
     137    14738431 :     plumed_assert(convertNoexcept(t,u)) <<"Error converting  "<<t;
     138    14737601 :   }
     139             :   template <typename T>
     140             :   static bool parse(std::vector<std::string>&line,const std::string&key,T&val,int rep=-1);
     141             : /// Find a keyword on the input line, eventually deleting it, and saving its value to a vector
     142             :   template <class T>
     143             :   static bool parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep=-1);
     144             : /// Find a keyword without arguments on the input line
     145             :   static bool parseFlag(std::vector<std::string>&line,const std::string&key,bool&val);
     146             : /// Find a keyword on the input line, just reporting if it exists or not
     147             :   static bool findKeyword(const std::vector<std::string>&line,const std::string&key);
     148             : /// Interpret atom ranges
     149             :   static void interpretRanges(std::vector<std::string>&);
     150             : /// Remove duplicates from a vector of type T
     151             :   template <typename T>
     152             :   static void removeDuplicates(std::vector<T>& vec);
     153             : /// interpret ":" syntax for labels
     154             :   static void interpretLabel(std::vector<std::string>&s);
     155             : /// list files in a directory
     156             :   static std::vector<std::string> ls(const std::string&);
     157             : /// removes leading and trailing blanks from a string
     158             :   static void stripLeadingAndTrailingBlanks( std::string& str );
     159             : /// Extract the extensions from a file name.
     160             : /// E.g.: extension("pippo.xyz")="xyz".
     161             : /// It only returns extensions with a length between 1 and 4
     162             : /// E.g.: extension("pippo.12345")="" whereas extenion("pippo.1234")="1234";
     163             : /// It is also smart enough to detect "/", so that
     164             : /// extension("pippo/.t")="" whereas extension("pippo/a.t")="t"
     165             :   static std::string extension(const std::string&);
     166             : /// Fast int power
     167             :   static double fastpow(double base,int exp);
     168             : /// Modified 0th-order Bessel function of the first kind
     169             :   static double bessel0(const double& val);
     170             : /// Check if a string full starts with string start.
     171             : /// Same as full.find(start)==0
     172             :   static bool startWith(const std::string & full,const std::string &start);
     173             :   /**
     174             :     Tool to create a vector of raw pointers from a vector of unique_pointers (const version).
     175             :   Returning a vector is fast in C++11. It can be used in order to feed a vector<unique_ptr<T>>
     176             :   to a function that takes a vector<T*>.
     177             :   \verbatim
     178             :   // some function that takes a vec
     179             :   void func(std::vector<Data*> & vec);
     180             :   std::vector<std::unique_ptr<Data>> vec;
     181             :   // func(vec); // does not compile
     182             :   func(Tools::unique2raw(vec)); // compiles
     183             :   \endverbatim
     184             :   Notice that the conversion is fast but takes
     185             :   some time to allocate the new vector and copy the pointers. In case the function
     186             :   acting on the vector<T*> is very fast and we do not want to add significant overhead,
     187             :   it might be convenient to store a separate set of raw pointers.
     188             :   \verbatim
     189             :   // some function that takes a vec
     190             :   void func(std::vector<Data*> & vec);
     191             :   std::vector<std::unique_ptr<Data>> vec;
     192             : 
     193             :   // conversion done only once:
     194             :   auto vec_ptr=Tools::unique2raw(vec);
     195             : 
     196             :   for(int i=0;i<1000;i++){
     197             :     func(vec_ptr);
     198             :   }
     199             :   \endverbatim
     200             :   */
     201             :   template <typename T>
     202             :   static std::vector<T*> unique2raw(const std::vector<std::unique_ptr<T>>&);
     203             : /// Tool to create a vector of raw pointers from a vector of unique_pointers.
     204             : /// See the non const version.
     205             :   template <typename T>
     206             :   static std::vector<const T*> unique2raw(const std::vector<std::unique_ptr<const T>>&);
     207             : /// Tiny class that changes directory and comes back when going out of scope.
     208             : /// In case system calls to change dir are not available it throws an exception.
     209             : /// \warning By construction, changing directory breaks thread safety! Use with care.
     210             :   class DirectoryChanger {
     211             :     static const std::size_t buffersize=4096;
     212             :     char cwd[buffersize]= {0};
     213             :   public:
     214             :     explicit DirectoryChanger(const char*path);
     215             :     ~DirectoryChanger();
     216             :   };
     217             : /// Mimic C++14 std::make_unique
     218             :   template<class T> struct _Unique_if {
     219             :     typedef std::unique_ptr<T> _Single_object;
     220             :   };
     221             :   template<class T> struct _Unique_if<T[]> {
     222             :     typedef std::unique_ptr<T[]> _Unknown_bound;
     223             :   };
     224             :   template<class T, std::size_t N> struct _Unique_if<T[N]> {
     225             :     typedef void _Known_bound;
     226             :   };
     227             :   template<class T, class... Args>
     228             :   static typename _Unique_if<T>::_Single_object
     229     5815131 :   make_unique(Args&&... args) {
     230     9430972 :     return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
     231             :   }
     232             :   template<class T>
     233             :   static typename _Unique_if<T>::_Unknown_bound
     234         189 :   make_unique(std::size_t n) {
     235             :     typedef typename std::remove_extent<T>::type U;
     236        9473 :     return std::unique_ptr<T>(new U[n]());
     237             :   }
     238             :   template<class T, class... Args>
     239             :   static typename _Unique_if<T>::_Known_bound
     240             :   make_unique(Args&&...) = delete;
     241             : 
     242             :   static void set_to_zero(double*ptr,unsigned n) {
     243    24392902 :     for(unsigned i=0; i<n; i++) {
     244    24190788 :       ptr[i]=0.0;
     245             :     }
     246             :   }
     247             : 
     248             :   template<unsigned n>
     249      226744 :   static void set_to_zero(std::vector<VectorGeneric<n>> & vec) {
     250      226744 :     unsigned s=vec.size();
     251      226744 :     if(s==0) {
     252             :       return;
     253             :     }
     254      202114 :     set_to_zero(&vec[0][0],s*n);
     255             :   }
     256             : 
     257             :   template<unsigned n,unsigned m>
     258             :   static void set_to_zero(std::vector<TensorGeneric<n,m>> & vec) {
     259             :     unsigned s=vec.size();
     260             :     if(s==0) {
     261             :       return;
     262             :     }
     263             :     set_to_zero(&vec[0](0,0),s*n*m);
     264             :   }
     265             : 
     266             : 
     267             : 
     268             : 
     269             :   /// Merge sorted vectors.
     270             :   /// Takes a vector of pointers to containers and merge them.
     271             :   /// Containers should be already sorted.
     272             :   /// The content is appended to the result vector.
     273             :   /// Optionally, uses a priority_queue implementation.
     274             :   template<class C>
     275       27378 :   static void mergeSortedVectors(const std::vector<C*> & vecs, std::vector<typename C::value_type> & result,bool priority_queue=false) {
     276             : 
     277             :     /// local class storing the range of remaining objects to be pushed
     278             :     struct Entry {
     279             :       typename C::const_iterator fwdIt,endIt;
     280             : 
     281       54587 :       explicit Entry(C const& v) : fwdIt(v.begin()), endIt(v.end()) {}
     282             :       /// check if this vector still contains something to be pushed
     283             :       explicit operator bool () const {
     284             :         return fwdIt != endIt;
     285             :       }
     286             :       /// to allow using a priority_queu, which selects the highest element.
     287             :       /// we here (counterintuitively) define < as >
     288             :       bool operator< (Entry const& rhs) const {
     289             :         return *fwdIt > *rhs.fwdIt;
     290             :       }
     291             :     };
     292             : 
     293       27378 :     if(priority_queue) {
     294             :       std::priority_queue<Entry> queue;
     295             :       // note: queue does not have reserve() method
     296             : 
     297             :       // add vectors to the queue
     298             :       {
     299             :         std::size_t maxsize=0;
     300           0 :         for(unsigned i=0; i<vecs.size(); i++) {
     301           0 :           if(vecs[i]->size()>maxsize) {
     302             :             maxsize=vecs[i]->size();
     303             :           }
     304           0 :           if(!vecs[i]->empty()) {
     305           0 :             queue.push(Entry(*vecs[i]));
     306             :           }
     307             :         }
     308             :         // this is just to save multiple reallocations on push_back
     309           0 :         result.reserve(maxsize);
     310             :       }
     311             : 
     312             :       // first iteration (to avoid a if in the main loop)
     313           0 :       if(queue.empty()) {
     314             :         return;
     315             :       }
     316           0 :       auto tmp=queue.top();
     317           0 :       queue.pop();
     318           0 :       result.push_back(*tmp.fwdIt);
     319             :       tmp.fwdIt++;
     320           0 :       if(tmp) {
     321           0 :         queue.push(tmp);
     322             :       }
     323             : 
     324             :       // main loop
     325           0 :       while(!queue.empty()) {
     326           0 :         auto tmp=queue.top();
     327           0 :         queue.pop();
     328           0 :         if(result.back() < *tmp.fwdIt) {
     329           0 :           result.push_back(*tmp.fwdIt);
     330             :         }
     331             :         tmp.fwdIt++;
     332           0 :         if(tmp) {
     333           0 :           queue.push(tmp);
     334             :         }
     335             :       }
     336             :     } else {
     337             : 
     338             :       std::vector<Entry> entries;
     339       27378 :       entries.reserve(vecs.size());
     340             : 
     341             :       {
     342             :         std::size_t maxsize=0;
     343       84706 :         for(int i=0; i<vecs.size(); i++) {
     344       57328 :           if(vecs[i]->size()>maxsize) {
     345             :             maxsize=vecs[i]->size();
     346             :           }
     347       57328 :           if(!vecs[i]->empty()) {
     348       54587 :             entries.push_back(Entry(*vecs[i]));
     349             :           }
     350             :         }
     351             :         // this is just to save multiple reallocations on push_back
     352       27378 :         result.reserve(maxsize);
     353             :       }
     354             : 
     355      424403 :       while(!entries.empty()) {
     356             :         // find smallest pending element
     357             :         // we use max_element instead of min_element because we are defining < as > (see above)
     358      397025 :         const auto minval=*std::max_element(entries.begin(),entries.end())->fwdIt;
     359             : 
     360             :         // push it
     361      397025 :         result.push_back(minval);
     362             : 
     363             :         // fast forward vectors with elements equal to minval (to avoid duplicates)
     364     1562323 :         for(auto & e : entries)
     365     1962677 :           while(e && *e.fwdIt==minval) {
     366             :             ++e.fwdIt;
     367             :           }
     368             : 
     369             :         // remove from the entries vector all exhausted vectors
     370      397025 :         auto erase=std::remove_if(entries.begin(),entries.end(),[](const Entry & e) {
     371             :           return !e;
     372             :         });
     373             :         entries.erase(erase,entries.end());
     374             :       }
     375             :     }
     376             : 
     377             :   }
     378             :   static std::unique_ptr<std::lock_guard<std::mutex>> molfile_lock();
     379             :   /// Build a concatenated exception message.
     380             :   /// Should be called with an in-flight exception.
     381             :   static std::string concatenateExceptionMessages();
     382             : };
     383             : 
     384             : template <class T>
     385       75820 : bool Tools::parse(std::vector<std::string>&line,const std::string&key,T&val,int rep) {
     386             :   std::string s;
     387      151640 :   if(!getKey(line,key+"=",s,rep)) {
     388             :     return false;
     389             :   }
     390       31264 :   if(s.length()>0 && !convertNoexcept(s,val)) {
     391           3 :     return false;
     392             :   }
     393             :   return true;
     394             : }
     395             : 
     396             : template <class T>
     397       36605 : bool Tools::parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep) {
     398             :   std::string s;
     399       73210 :   if(!getKey(line,key+"=",s,rep)) {
     400             :     return false;
     401             :   }
     402             :   val.clear();
     403       26929 :   std::vector<std::string> words=getWords(s,"\t\n ,");
     404      115814 :   for(unsigned i=0; i<words.size(); ++i) {
     405             :     T v;
     406       88885 :     std::string s=words[i];
     407       88885 :     const std::string multi("@replicas:");
     408       88885 :     if(rep>=0 && startWith(s,multi)) {
     409           6 :       s=s.substr(multi.length(),s.length());
     410           6 :       std::vector<std::string> words=getWords(s,"\t\n ,");
     411           6 :       plumed_assert(rep<static_cast<int>(words.size()));
     412           6 :       s=words[rep];
     413           6 :     }
     414       88885 :     if(!convertNoexcept(s,v)) {
     415             :       return false;
     416             :     }
     417       88885 :     val.push_back(v);
     418             :   }
     419             :   return true;
     420       26929 : }
     421             : 
     422             : template<typename T>
     423       13572 : void Tools::removeDuplicates(std::vector<T>& vec) {
     424       13572 :   std::sort(vec.begin(), vec.end());
     425       13572 :   vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
     426       13572 : }
     427             : 
     428             : inline
     429       44485 : bool Tools::parseFlag(std::vector<std::string>&line,const std::string&key,bool&val) {
     430      118481 :   for(auto p=line.begin(); p!=line.end(); ++p) {
     431       75628 :     if(key==*p) {
     432        1632 :       val=true;
     433             :       line.erase(p);
     434             :       return true;
     435             :     }
     436             :   }
     437             :   return false;
     438             : }
     439             : 
     440             : /// beware: this brings any number into a pbc that ranges from -0.5 to 0.5
     441             : inline
     442  1856147440 : double Tools::pbc(double x) {
     443             : #ifdef __PLUMED_PBC_WHILE
     444             :   while (x>0.5) {
     445             :     x-=1.0;
     446             :   }
     447             :   while (x<-0.5) {
     448             :     x+=1.0;
     449             :   }
     450             :   return x;
     451             : #else
     452             :   if(std::numeric_limits<int>::round_style == std::round_toward_zero) {
     453             :     const double offset=100.0;
     454  1856147440 :     const double y=x+offset;
     455  1856147440 :     if(y>=0) {
     456  1856142863 :       return y-int(y+0.5);
     457             :     } else {
     458        4577 :       return y-int(y-0.5);
     459             :     }
     460             :   } else if(std::numeric_limits<int>::round_style == std::round_to_nearest) {
     461             :     return x-int(x);
     462             :   } else {
     463             :     return x-floor(x+0.5);
     464             :   }
     465             : #endif
     466             : }
     467             : 
     468             : template<typename T>
     469      540013 : bool Tools::convertNoexcept(T i,std::string & str) {
     470      540013 :   std::ostringstream ostr;
     471      421822 :   ostr<<i;
     472      540013 :   str=ostr.str();
     473      540013 :   return true;
     474      540013 : }
     475             : 
     476             : inline
     477    79275828 : double Tools::fastpow(double base, int exp) {
     478    79275828 :   if(exp<0) {
     479           0 :     exp=-exp;
     480           0 :     base=1.0/base;
     481             :   }
     482             :   double result = 1.0;
     483   375463658 :   while (exp) {
     484   262587636 :     if (exp & 1) {
     485   181434484 :       result *= base;
     486             :     }
     487   262587636 :     exp >>= 1;
     488   262587636 :     base *= base;
     489             :   }
     490             : 
     491    79275828 :   return result;
     492             : }
     493             : 
     494             : template<typename T>
     495    13703470 : std::vector<T*> Tools::unique2raw(const std::vector<std::unique_ptr<T>> & x) {
     496    13703470 :   std::vector<T*> v(x.size());
     497    52721172 :   for(unsigned i=0; i<x.size(); i++) {
     498    39017702 :     v[i]=x[i].get();
     499             :   }
     500    13703470 :   return v;
     501             : }
     502             : 
     503             : template<typename T>
     504             : std::vector<const T*> Tools::unique2raw(const std::vector<std::unique_ptr<const T>> & x) {
     505             :   std::vector<const T*> v(x.size());
     506             :   for(unsigned i=0; i<x.size(); i++) {
     507             :     v[i]=x[i].get();
     508             :   }
     509             :   return v;
     510             : }
     511             : 
     512             : }
     513             : 
     514             : #endif
     515             : 

Generated by: LCOV version 1.16