LCOV - code coverage report
Current view: top level - tools - Tools.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 94 96 97.9 %
Date: 2024-10-18 14:00:25 Functions: 51 56 91.1 %

          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    23822528 :   static void convert(const T & t,U & u) {
     151    23823571 :     plumed_assert(convertNoexcept(t,u)) <<"Error converting  "<<t;
     152    23822527 :   }
     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      152594 :     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      359808 : bool Tools::parse(std::vector<std::string>&line,const std::string&key,T&val,int rep) {
     390             :   std::string s;
     391      719616 :   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  1784385287 : 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  1784385287 :     const double y=x+offset;
     448  1784385287 :     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     7155935 : bool Tools::convertNoexcept(T i,std::string & str) {
     458     7155935 :   std::ostringstream ostr;
     459      778612 :   ostr<<i;
     460     7155935 :   str=ostr.str();
     461     7155935 :   return true;
     462     7155935 : }
     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

Generated by: LCOV version 1.16