LCOV - code coverage report
Current view: top level - tools - Tools.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 201 220 91.4 %
Date: 2019-08-13 10:15:31 Functions: 34 37 91.9 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2019 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "Tools.h"
      23             : #include "AtomNumber.h"
      24             : #include "Exception.h"
      25             : #include "IFile.h"
      26             : #include "lepton/Lepton.h"
      27             : #include <cstring>
      28             : #include <dirent.h>
      29             : #include <iostream>
      30             : #include <map>
      31             : #if defined(__PLUMED_HAS_CHDIR) || defined(__PLUMED_HAS_GETCWD)
      32             : #include <unistd.h>
      33             : #endif
      34             : 
      35             : using namespace std;
      36             : namespace PLMD {
      37             : 
      38             : template<class T>
      39     6492614 : bool Tools::convertToAny(const string & str,T & t) {
      40    12985245 :   istringstream istr(str.c_str());
      41     6492626 :   bool ok=static_cast<bool>(istr>>t);
      42     6492626 :   if(!ok) return false;
      43             :   string remaining;
      44     4404333 :   istr>>remaining;
      45    10896942 :   return remaining.length()==0;
      46             : }
      47             : 
      48      213328 : bool Tools::convert(const string & str,int & t) {
      49      213328 :   return convertToAny(str,t);
      50             : }
      51             : 
      52          85 : bool Tools::convert(const string & str,long int & t) {
      53          85 :   return convertToAny(str,t);
      54             : }
      55             : 
      56      357408 : bool Tools::convert(const string & str,unsigned & t) {
      57      357408 :   return convertToAny(str,t);
      58             : }
      59             : 
      60      207977 : bool Tools::convert(const string & str,AtomNumber &a) {
      61             :   unsigned i;
      62      207977 :   bool r=convert(str,i);
      63      207977 :   if(r) a.setSerial(i);
      64      207977 :   return r;
      65             : }
      66             : 
      67             : template<class T>
      68     5921793 : bool Tools::convertToReal(const string & str,T & t) {
      69     5921793 :   if(convertToAny(str,t)) return true;
      70     8319635 :   if(str=="PI" || str=="+PI" || str=="+pi" || str=="pi") {
      71     1040008 :     t=pi; return true;
      72     2079887 :   } else if(str=="-PI" || str=="-pi") {
      73     1039924 :     t=-pi; return true;
      74             :   }
      75             :   try {
      76          22 :     t=lepton::Parser::parse(str).evaluate(lepton::Constants());
      77           2 :     return true;
      78          18 :   } catch(const PLMD::lepton::Exception& exc) {
      79             :   }
      80          18 :   if( str.find("PI")!=std::string::npos ) {
      81           0 :     std::size_t pi_start=str.find_first_of("PI");
      82           0 :     if(str.substr(pi_start)!="PI") return false;
      83           0 :     istringstream nstr(str.substr(0,pi_start));
      84           0 :     T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
      85           0 :     if(!ok) return false;
      86           0 :     t=ff*pi;
      87           0 :     std::string remains; nstr>>remains;
      88           0 :     return remains.length()==0;
      89          18 :   } else if( str.find("pi")!=std::string::npos ) {
      90          14 :     std::size_t pi_start=str.find_first_of("pi");
      91          28 :     if(str.substr(pi_start)!="pi") return false;
      92          28 :     istringstream nstr(str.substr(0,pi_start));
      93          28 :     T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
      94          14 :     if(!ok) return false;
      95          14 :     t=ff*pi;
      96          14 :     std::string remains; nstr>>remains;
      97          28 :     return remains.length()==0;
      98           4 :   } else if(str=="NAN") {
      99           0 :     t=std::numeric_limits<double>::quiet_NaN();
     100           0 :     return true;
     101             :   }
     102             :   return false;
     103             : }
     104             : 
     105           0 : bool Tools::convert(const string & str,float & t) {
     106           0 :   return convertToReal(str,t);
     107             : }
     108             : 
     109     5921668 : bool Tools::convert(const string & str,double & t) {
     110     5921668 :   return convertToReal(str,t);
     111             : }
     112             : 
     113         128 : bool Tools::convert(const string & str,long double & t) {
     114         128 :   return convertToReal(str,t);
     115             : }
     116             : 
     117       31312 : bool Tools::convert(const string & str,string & t) {
     118             :   t=str;
     119       31312 :   return true;
     120             : }
     121             : 
     122      904226 : vector<string> Tools::getWords(const string & line,const char* separators,int * parlevel,const char* parenthesis) {
     123      904226 :   plumed_massert(strlen(parenthesis)==1,"multiple parenthesis type not available");
     124      904226 :   plumed_massert(parenthesis[0]=='(' || parenthesis[0]=='[' || parenthesis[0]=='{',
     125           0 :                  "only ( [ { allowed as parenthesis");
     126      904226 :   if(!separators) separators=" \t\n";
     127      904226 :   const string sep(separators);
     128      904226 :   char openpar=parenthesis[0];
     129             :   char closepar;
     130             :   if(openpar=='(') closepar=')';
     131      904226 :   if(openpar=='[') closepar=']';
     132      904226 :   if(openpar=='{') closepar='}';
     133             :   vector<string> words;
     134             :   string word;
     135             :   int parenthesisLevel=0;
     136      904226 :   if(parlevel) parenthesisLevel=*parlevel;
     137    52471068 :   for(unsigned i=0; i<line.length(); i++) {
     138             :     bool found=false;
     139             :     bool onParenthesis=false;
     140    25783421 :     if(line[i]==openpar || line[i]==closepar) onParenthesis=true;
     141    25783421 :     if(line[i]==closepar) {
     142        1915 :       parenthesisLevel--;
     143        1915 :       plumed_massert(parenthesisLevel>=0,"Extra closed parenthesis in '" + line + "'");
     144             :     }
     145   206139958 :     if(parenthesisLevel==0) for(unsigned j=0; j<sep.length(); j++) if(line[i]==sep[j]) found=true;
     146             : // If at parenthesis level zero (outer)
     147    25783421 :     if(!(parenthesisLevel==0 && (found||onParenthesis))) word.push_back(line[i]);
     148             :     //if(onParenthesis) word.push_back(' ');
     149    25783421 :     if(line[i]==openpar) parenthesisLevel++;
     150    31303148 :     if(found && word.length()>0) {
     151     1322673 :       if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
     152     1322673 :       words.push_back(word);
     153             :       word.clear();
     154             :     }
     155             :   }
     156      904226 :   if(word.length()>0) {
     157      791300 :     if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
     158      791300 :     words.push_back(word);
     159             :   }
     160      904226 :   if(parlevel) *parlevel=parenthesisLevel;
     161      904226 :   return words;
     162             : }
     163             : 
     164        6639 : bool Tools::getParsedLine(IFile& ifile,vector<string> & words) {
     165        6639 :   string line("");
     166        6639 :   words.clear();
     167             :   bool stat;
     168             :   bool inside=false;
     169        6639 :   int parlevel=0;
     170             :   bool mergenext=false;
     171       28591 :   while((stat=ifile.getline(line))) {
     172       21281 :     trimComments(line);
     173       21281 :     trim(line);
     174       26416 :     if(line.length()==0) continue;
     175       16146 :     vector<string> w=getWords(line,NULL,&parlevel);
     176       16146 :     if(!w.empty()) {
     177       26322 :       if(inside && *(w.begin())=="...") {
     178             :         inside=false;
     179        2091 :         if(w.size()==2) plumed_massert(w[1]==words[0],"second word in terminating \"...\" "+w[1]+" line, if present, should be equal to first word of directive: "+words[0]);
     180        1085 :         plumed_massert(w.size()<=2,"terminating \"...\" lines cannot consist of more than two words");
     181        1085 :         w.clear();
     182       15060 :       } else if(*(w.end()-1)=="...") {
     183             :         inside=true;
     184        1085 :         w.erase(w.end()-1);
     185             :       };
     186             :       int i0=0;
     187       16273 :       if(mergenext && words.size()>0 && w.size()>0) {
     188         192 :         words[words.size()-1]+=" "+w[0];
     189             :         i0=1;
     190             :       }
     191       97462 :       for(unsigned i=i0; i<w.size(); ++i) words.push_back(w[i]);
     192             :     }
     193       16146 :     mergenext=(parlevel>0);
     194       16146 :     if(!inside)break;
     195       10178 :   }
     196        6639 :   plumed_massert(parlevel==0,"non matching parenthesis");
     197        6639 :   if(words.size()>0) return true;
     198         671 :   return stat;
     199             : }
     200             : 
     201             : 
     202     2557435 : bool Tools::getline(FILE* fp,string & line) {
     203             :   line="";
     204             :   const int bufferlength=1024;
     205             :   char buffer[bufferlength];
     206             :   bool ret;
     207  2618813440 :   for(int i=0; i<bufferlength; i++) buffer[i]='\0';
     208     2557435 :   while((ret=fgets(buffer,bufferlength,fp))) {
     209     2556778 :     line.append(buffer);
     210     2556778 :     unsigned ss=strlen(buffer);
     211     2556778 :     if(ss>0) if(buffer[ss-1]=='\n') break;
     212             :   };
     213     7670991 :   if(line.length()>0) if(*(line.end()-1)=='\n') line.erase(line.end()-1);
     214     5115393 :   if(line.length()>0) if(*(line.end()-1)=='\r') line.erase(line.end()-1);
     215     2557435 :   return ret;
     216             : }
     217             : 
     218      415252 : void Tools::trim(string & s) {
     219      415252 :   size_t n=s.find_last_not_of(" \t");
     220      830504 :   s=s.substr(0,n+1);
     221      415252 : }
     222             : 
     223      178685 : void Tools::trimComments(string & s) {
     224      178685 :   size_t n=s.find_first_of("#");
     225      357370 :   s=s.substr(0,n);
     226      178685 : }
     227             : 
     228      290537 : bool Tools::caseInSensStringCompare(const std::string & str1, const std::string &str2)
     229             : {
     230     1019762 :   return ((str1.size() == str2.size()) && std::equal(str1.begin(), str1.end(), str2.begin(), [](char c1, char c2) {
     231      465184 :     return (c1 == c2 || std::toupper(c1) == std::toupper(c2));
     232     1019762 :   }));
     233             : }
     234             : 
     235       62558 : bool Tools::getKey(vector<string>& line,const string & key,string & s,int rep) {
     236             :   s.clear();
     237      385883 :   for(auto p=line.begin(); p!=line.end(); ++p) {
     238      290537 :     if((*p).length()==0) continue;
     239      290537 :     string x=(*p).substr(0,key.length());
     240      290537 :     if(caseInSensStringCompare(x,key)) {
     241       29770 :       if((*p).length()==key.length())return false;
     242       29769 :       string tmp=(*p).substr(key.length(),(*p).length());
     243       29769 :       line.erase(p);
     244             :       s=tmp;
     245       29769 :       const std::string multi("@replicas:");
     246       29769 :       if(rep>=0 && startWith(s,multi)) {
     247          48 :         s=s.substr(multi.length(),s.length());
     248          24 :         std::vector<std::string> words=getWords(s,"\t\n ,");
     249          24 :         plumed_massert(rep<static_cast<int>(words.size()),"Number of fields in " + s + " not consistent with number of replicas");
     250          48 :         s=words[rep];
     251             :       }
     252             :       return true;
     253             :     }
     254             :   };
     255             :   return false;
     256             : }
     257             : 
     258        4007 : void Tools::interpretRanges(std::vector<std::string>&s) {
     259             :   vector<string> news;
     260       16972 :   for(const auto & p :s) {
     261        8958 :     news.push_back(p);
     262        8958 :     size_t dash=p.find("-");
     263       16953 :     if(dash==string::npos) continue;
     264             :     int first;
     265        3064 :     if(!Tools::convert(p.substr(0,dash),first)) continue;
     266         963 :     int stride=1;
     267             :     int second;
     268        1926 :     size_t colon=p.substr(dash+1).find(":");
     269         963 :     if(colon!=string::npos) {
     270          68 :       if(!Tools::convert(p.substr(dash+1).substr(0,colon),second) ||
     271          68 :           !Tools::convert(p.substr(dash+1).substr(colon+1),stride)) continue;
     272             :     } else {
     273        1892 :       if(!Tools::convert(p.substr(dash+1),second)) continue;
     274             :     }
     275         963 :     news.resize(news.size()-1);
     276         963 :     if(first<=second) {
     277         962 :       plumed_massert(stride>0,"interpreting ranges "+ p + ", stride should be positive");
     278      197024 :       for(int i=first; i<=second; i+=stride) {
     279             :         string ss;
     280      197024 :         convert(i,ss);
     281      197024 :         news.push_back(ss);
     282             :       }
     283             :     } else {
     284           1 :       plumed_massert(stride<0,"interpreting ranges "+ p + ", stride should be positive");
     285           2 :       for(int i=first; i>=second; i+=stride) {
     286             :         string ss;
     287           2 :         convert(i,ss);
     288           2 :         news.push_back(ss);
     289             :       }
     290             :     }
     291             :   }
     292        4007 :   s=news;
     293        4007 : }
     294             : 
     295        6228 : void Tools::interpretLabel(vector<string>&s) {
     296        6477 :   if(s.size()<2)return;
     297        5979 :   string s0=s[0];
     298        5979 :   unsigned l=s0.length();
     299        5979 :   if(l<1) return;
     300       11958 :   if(s0[l-1]==':') {
     301        3245 :     s[0]=s[1];
     302       12980 :     s[1]="LABEL="+s0.substr(0,l-1);
     303             :   }
     304       11958 :   std::transform(s[0].begin(), s[0].end(), s[0].begin(), ::toupper);
     305             : }
     306             : 
     307        3822 : vector<string> Tools::ls(const string&d) {
     308             :   DIR*dir;
     309             :   vector<string> result;
     310        3822 :   if ((dir=opendir(d.c_str()))) {
     311             : #if defined(__PLUMED_HAS_READDIR_R)
     312             :     struct dirent ent;
     313             : #endif
     314             :     while(true) {
     315             :       struct dirent *res;
     316             : #if defined(__PLUMED_HAS_READDIR_R)
     317       59718 :       readdir_r(dir,&ent,&res);
     318             : #else
     319             : // cppcheck complains about this:
     320             : // (portability) Non reentrant function 'readdir' called. For threadsafe applications it is recommended to use the reentrant replacement function 'readdir_r'.
     321             : // since we use it only if readdir_r is not available, I suppress the warning
     322             : // GB
     323             : // cppcheck-suppress readdirCalled
     324             :       res=readdir(dir);
     325             : #endif
     326       59718 :       if(!res) break;
     327      320088 :       if(string(res->d_name)!="." && string(res->d_name)!="..") result.push_back(res->d_name);
     328             :     }
     329       55896 :     closedir (dir);
     330             :   }
     331        3822 :   return result;
     332             : }
     333             : 
     334        4137 : void Tools::stripLeadingAndTrailingBlanks( std::string& str ) {
     335        4137 :   std::size_t first=str.find_first_not_of(' ');
     336        4137 :   std::size_t last=str.find_last_not_of(' ');
     337        8242 :   if( first<=last && first!=std::string::npos) str=str.substr(first,last+1);
     338        4137 : }
     339             : 
     340       10159 : std::string Tools::extension(const std::string&s) {
     341       10159 :   size_t n=s.find_last_of(".");
     342             :   std::string ext;
     343       17777 :   if(n!=std::string::npos && n+1<s.length() && n+5>=s.length()) {
     344       14908 :     ext=s.substr(n+1);
     345        7454 :     if(ext.find("/")!=std::string::npos) ext="";
     346        7454 :     string base=s.substr(0,n);
     347        7454 :     if(base.length()==0) ext="";
     348       14908 :     if(base.length()>0 && base[base.length()-1]=='/') ext="";
     349             :   }
     350       10159 :   return ext;
     351             : }
     352             : 
     353          14 : double Tools::bessel0( const double& val ) {
     354          14 :   if (fabs(val)<3.75) {
     355           2 :     double y = Tools::fastpow( val/3.75, 2 );
     356           2 :     return 1 + y*(3.5156229 +y*(3.0899424 + y*(1.2067492+y*(0.2659732+y*(0.0360768+y*0.0045813)))));
     357             :   }
     358          12 :   double ax=fabs(val), y=3.75/ax, bx=std::exp(ax)/sqrt(ax);
     359          12 :   ax=0.39894228+y*(0.01328592+y*(0.00225319+y*(-0.00157565+y*(0.00916281+y*(-0.02057706+y*(0.02635537+y*(-0.01647633+y*0.00392377)))))));
     360          12 :   return ax*bx;
     361             : }
     362             : 
     363      728701 : bool Tools::startWith(const std::string & full,const std::string &start) {
     364     1457402 :   return (full.substr(0,start.length())==start);
     365             : }
     366             : 
     367       54537 : bool Tools::findKeyword(const std::vector<std::string>&line,const std::string&key) {
     368       54537 :   const std::string search(key+"=");
     369      576473 :   for(const auto & p : line) {
     370      490434 :     if(startWith(p,search)) return true;
     371             :   }
     372             :   return false;
     373             : }
     374             : 
     375         469 : Tools::DirectoryChanger::DirectoryChanger(const char*path) {
     376         469 :   if(!path) return;
     377         469 :   if(std::strlen(path)==0) return;
     378             : #ifdef __PLUMED_HAS_GETCWD
     379           0 :   char* ret=getcwd(cwd,buffersize);
     380           0 :   plumed_assert(ret)<<"Name of current directory too long, increase buffer size";
     381             : #else
     382             :   plumed_error()<<"You are trying to use DirectoryChanger but your system does not support getcwd";
     383             : #endif
     384             : #ifdef __PLUMED_HAS_CHDIR
     385           0 :   int r=chdir(path);
     386           0 :   plumed_assert(r==0) <<"Cannot chdir to directory "<<path<<". The directory must exist!";
     387             : #else
     388             :   plumed_error()<<"You are trying to use DirectoryChanger but your system does not support chdir";
     389             : #endif
     390             : }
     391             : 
     392         469 : Tools::DirectoryChanger::~DirectoryChanger() {
     393             : #ifdef __PLUMED_HAS_CHDIR
     394         469 :   if(strlen(cwd)==0) return;
     395           0 :   int ret=chdir(cwd);
     396             : // we cannot put an assertion here (in a destructor) otherwise cppcheck complains
     397             : // we thus just report the problem
     398           0 :   if(ret!=0) fprintf(stderr,"+++ WARNING: cannot cd back to directory %s\n",cwd);
     399             : #endif
     400         469 : }
     401             : 
     402        5874 : }

Generated by: LCOV version 1.14