LCOV - code coverage report
Current view: top level - tools - Tools.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 188 205 91.7 %
Date: 2021-11-18 15:22:58 Functions: 32 35 91.4 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2020 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     4382051 : bool Tools::convertToAny(const string & str,T & t) {
      40    13146153 :   istringstream istr(str.c_str());
      41     4382051 :   bool ok=static_cast<bool>(istr>>t);
      42     4382051 :   if(!ok) return false;
      43             :   string remaining;
      44     2279621 :   istr>>remaining;
      45     2279621 :   return remaining.length()==0;
      46             : }
      47             : 
      48      214852 : bool Tools::convert(const string & str,int & t) {
      49      214852 :   return convertToAny(str,t);
      50             : }
      51             : 
      52          83 : bool Tools::convert(const string & str,long int & t) {
      53          83 :   return convertToAny(str,t);
      54             : }
      55             : 
      56      327484 : bool Tools::convert(const string & str,unsigned & t) {
      57      327484 :   return convertToAny(str,t);
      58             : }
      59             : 
      60      185727 : bool Tools::convert(const string & str,AtomNumber &a) {
      61             :   unsigned i;
      62      185727 :   bool r=convert(str,i);
      63      185727 :   if(r) a.setSerial(i);
      64      185727 :   return r;
      65             : }
      66             : 
      67             : template<class T>
      68     3839632 : bool Tools::convertToReal(const string & str,T & t) {
      69     3839632 :   if(convertToAny(str,t)) return true;
      70     8376097 :   if(str=="PI" || str=="+PI" || str=="+pi" || str=="pi") {
      71     1047063 :     t=pi; return true;
      72     2094004 :   } else if(str=="-PI" || str=="-pi") {
      73     1046980 :     t=-pi; return true;
      74             :   }
      75             :   try {
      76          48 :     t=lepton::Parser::parse(str).evaluate(lepton::Constants());
      77           4 :     return true;
      78          18 :   } catch(const PLMD::lepton::Exception& exc) {
      79             :   }
      80          18 :   if( str.find("PI")!=std::string::npos ) {
      81             :     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             :     std::size_t pi_start=str.find_first_of("pi");
      91          28 :     if(str.substr(pi_start)!="pi") return false;
      92          42 :     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          14 :     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     3839504 : bool Tools::convert(const string & str,double & t) {
     110     3839504 :   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       30326 : bool Tools::convert(const string & str,string & t) {
     118             :   t=str;
     119       30326 :   return true;
     120             : }
     121             : 
     122      672029 : vector<string> Tools::getWords(const string & line,const char* separators,int * parlevel,const char* parenthesis) {
     123      672029 :   plumed_massert(strlen(parenthesis)==1,"multiple parenthesis type not available");
     124      672029 :   plumed_massert(parenthesis[0]=='(' || parenthesis[0]=='[' || parenthesis[0]=='{',
     125             :                  "only ( [ { allowed as parenthesis");
     126      672029 :   if(!separators) separators=" \t\n";
     127      672029 :   const string sep(separators);
     128      672029 :   char openpar=parenthesis[0];
     129             :   char closepar;
     130             :   if(openpar=='(') closepar=')';
     131      672029 :   if(openpar=='[') closepar=']';
     132      672029 :   if(openpar=='{') closepar='}';
     133             :   vector<string> words;
     134             :   string word;
     135             :   int parenthesisLevel=0;
     136      672029 :   if(parlevel) parenthesisLevel=*parlevel;
     137    66199138 :   for(unsigned i=0; i<line.length(); i++) {
     138             :     bool found=false;
     139             :     bool onParenthesis=false;
     140    21618360 :     if(line[i]==openpar || line[i]==closepar) onParenthesis=true;
     141    21618360 :     if(line[i]==closepar) {
     142        1895 :       parenthesisLevel--;
     143        1895 :       plumed_massert(parenthesisLevel>=0,"Extra closed parenthesis in '" + line + "'");
     144             :     }
     145   172818428 :     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    21618360 :     if(!(parenthesisLevel==0 && (found||onParenthesis))) word.push_back(line[i]);
     148             :     //if(onParenthesis) word.push_back(' ');
     149    21618360 :     if(line[i]==openpar) parenthesisLevel++;
     150    27077695 :     if(found && word.length()>0) {
     151     1123203 :       if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
     152     1123203 :       words.push_back(word);
     153             :       word.clear();
     154             :     }
     155             :   }
     156      672029 :   if(word.length()>0) {
     157      561473 :     if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
     158      561473 :     words.push_back(word);
     159             :   }
     160      672029 :   if(parlevel) *parlevel=parenthesisLevel;
     161      672029 :   return words;
     162             : }
     163             : 
     164        6359 : bool Tools::getParsedLine(IFile& ifile,vector<string> & words) {
     165        6359 :   string line("");
     166        6359 :   words.clear();
     167             :   bool stat;
     168             :   bool inside=false;
     169        6359 :   int parlevel=0;
     170             :   bool mergenext=false;
     171       20457 :   while((stat=ifile.getline(line))) {
     172       19821 :     trimComments(line);
     173       19821 :     trim(line);
     174       19821 :     if(line.length()==0) continue;
     175       24353 :     vector<string> w=getWords(line,NULL,&parlevel);
     176       15038 :     if(!w.empty()) {
     177       24351 :       if(inside && *(w.begin())=="...") {
     178             :         inside=false;
     179        1897 :         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         979 :         plumed_massert(w.size()<=2,"terminating \"...\" lines cannot consist of more than two words");
     181         979 :         w.clear();
     182       14058 :       } else if(*(w.end()-1)=="...") {
     183             :         inside=true;
     184             :         w.erase(w.end()-1);
     185             :       };
     186             :       int i0=0;
     187       15165 :       if(mergenext && words.size()>0 && w.size()>0) {
     188         192 :         words[words.size()-1]+=" "+w[0];
     189             :         i0=1;
     190             :       }
     191       92166 :       for(unsigned i=i0; i<w.size(); ++i) words.push_back(w[i]);
     192             :     }
     193       15038 :     mergenext=(parlevel>0);
     194       15038 :     if(!inside)break;
     195             :   }
     196        6359 :   plumed_massert(parlevel==0,"non matching parenthesis");
     197        6359 :   if(words.size()>0) return true;
     198         636 :   return stat;
     199             : }
     200             : 
     201             : 
     202     1908289 : bool Tools::getline(FILE* fp,string & line) {
     203             :   line="";
     204             :   const int bufferlength=1024;
     205             :   char buffer[bufferlength];
     206             :   bool ret;
     207  1955996225 :   for(int i=0; i<bufferlength; i++) buffer[i]='\0';
     208     1908289 :   while((ret=fgets(buffer,bufferlength,fp))) {
     209     1907646 :     line.append(buffer);
     210     1907646 :     unsigned ss=strlen(buffer);
     211     1907646 :     if(ss>0) if(buffer[ss-1]=='\n') break;
     212             :   };
     213     3815935 :   if(line.length()>0) if(*(line.end()-1)=='\n') line.erase(line.end()-1);
     214     3815935 :   if(line.length()>0) if(*(line.end()-1)=='\r') line.erase(line.end()-1);
     215     1908289 :   return ret;
     216             : }
     217             : 
     218      398811 : void Tools::trim(string & s) {
     219             :   size_t n=s.find_last_not_of(" \t");
     220      797622 :   s=s.substr(0,n+1);
     221      398811 : }
     222             : 
     223      138543 : void Tools::trimComments(string & s) {
     224             :   size_t n=s.find_first_of("#");
     225      277086 :   s=s.substr(0,n);
     226      138543 : }
     227             : 
     228       60351 : bool Tools::getKey(vector<string>& line,const string & key,string & s,int rep) {
     229             :   s.clear();
     230      317108 :   for(auto p=line.begin(); p!=line.end(); ++p) {
     231      285422 :     if((*p).length()==0) continue;
     232      285422 :     string x=(*p).substr(0,key.length());
     233      285422 :     if(x==key) {
     234       28665 :       if((*p).length()==key.length())return false;
     235       28664 :       string tmp=(*p).substr(key.length(),(*p).length());
     236             :       line.erase(p);
     237             :       s=tmp;
     238       28664 :       const std::string multi("@replicas:");
     239       28664 :       if(rep>=0 && startWith(s,multi)) {
     240          48 :         s=s.substr(multi.length(),s.length());
     241          48 :         std::vector<std::string> words=getWords(s,"\t\n ,");
     242          24 :         plumed_massert(rep<static_cast<int>(words.size()),"Number of fields in " + s + " not consistent with number of replicas");
     243          24 :         s=words[rep];
     244             :       }
     245             :       return true;
     246             :     }
     247             :   };
     248             :   return false;
     249             : }
     250             : 
     251        3989 : void Tools::interpretRanges(std::vector<std::string>&s) {
     252        3989 :   vector<string> news;
     253       12889 :   for(const auto & p :s) {
     254        8900 :     news.push_back(p);
     255             :     size_t dash=p.find("-");
     256       16852 :     if(dash==string::npos) continue;
     257             :     int first;
     258        3064 :     if(!Tools::convert(p.substr(0,dash),first)) continue;
     259         948 :     int stride=1;
     260             :     int second;
     261        1896 :     size_t colon=p.substr(dash+1).find(":");
     262         948 :     if(colon!=string::npos) {
     263          68 :       if(!Tools::convert(p.substr(dash+1).substr(0,colon),second) ||
     264          68 :           !Tools::convert(p.substr(dash+1).substr(colon+1),stride)) continue;
     265             :     } else {
     266        1862 :       if(!Tools::convert(p.substr(dash+1),second)) continue;
     267             :     }
     268         948 :     news.resize(news.size()-1);
     269         948 :     if(first<=second) {
     270         947 :       plumed_massert(stride>0,"interpreting ranges "+ p + ", stride should be positive");
     271      358045 :       for(int i=first; i<=second; i+=stride) {
     272             :         string ss;
     273      178549 :         convert(i,ss);
     274      178549 :         news.push_back(ss);
     275             :       }
     276             :     } else {
     277           1 :       plumed_massert(stride<0,"interpreting ranges "+ p + ", stride should be positive");
     278           5 :       for(int i=first; i>=second; i+=stride) {
     279             :         string ss;
     280           2 :         convert(i,ss);
     281           2 :         news.push_back(ss);
     282             :       }
     283             :     }
     284             :   }
     285        3989 :   s=news;
     286        3989 : }
     287             : 
     288        6020 : void Tools::interpretLabel(vector<string>&s) {
     289        6256 :   if(s.size()<2)return;
     290             :   string s0=s[0];
     291        5784 :   unsigned l=s0.length();
     292        5784 :   if(l<1) return;
     293       11568 :   if(s0[l-1]==':') {
     294             :     s[0]=s[1];
     295       12776 :     s[1]="LABEL="+s0.substr(0,l-1);
     296             :   }
     297             : }
     298             : 
     299        3584 : vector<string> Tools::ls(const string&d) {
     300             :   DIR*dir;
     301             :   vector<string> result;
     302        3584 :   if ((dir=opendir(d.c_str()))) {
     303             : #if defined(__PLUMED_HAS_READDIR_R)
     304             :     struct dirent ent;
     305             : #endif
     306             :     while(true) {
     307             :       struct dirent *res;
     308             : #if defined(__PLUMED_HAS_READDIR_R)
     309       52434 :       readdir_r(dir,&ent,&res);
     310             : #else
     311             : // cppcheck complains about this:
     312             : // (portability) Non reentrant function 'readdir' called. For threadsafe applications it is recommended to use the reentrant replacement function 'readdir_r'.
     313             : // since we use it only if readdir_r is not available, I suppress the warning
     314             : // GB
     315             : // cppcheck-suppress readdirCalled
     316             :       res=readdir(dir);
     317             : #endif
     318       52434 :       if(!res) break;
     319      282348 :       if(string(res->d_name)!="." && string(res->d_name)!="..") result.push_back(res->d_name);
     320       48850 :     }
     321        3584 :     closedir (dir);
     322             :   }
     323        3584 :   return result;
     324             : }
     325             : 
     326        4202 : void Tools::stripLeadingAndTrailingBlanks( std::string& str ) {
     327        4202 :   std::size_t first=str.find_first_not_of(' ');
     328        4202 :   std::size_t last=str.find_last_not_of(' ');
     329        8371 :   if( first<=last && first!=std::string::npos) str=str.substr(first,last+1);
     330        4202 : }
     331             : 
     332        9341 : std::string Tools::extension(const std::string&s) {
     333             :   size_t n=s.find_last_of(".");
     334             :   std::string ext;
     335       16304 :   if(n!=std::string::npos && n+1<s.length() && n+5>=s.length()) {
     336       13598 :     ext=s.substr(n+1);
     337        6799 :     if(ext.find("/")!=std::string::npos) ext="";
     338        6799 :     string base=s.substr(0,n);
     339        6799 :     if(base.length()==0) ext="";
     340       13598 :     if(base.length()>0 && base[base.length()-1]=='/') ext="";
     341             :   }
     342        9341 :   return ext;
     343             : }
     344             : 
     345          14 : double Tools::bessel0( const double& val ) {
     346          14 :   if (fabs(val)<3.75) {
     347           2 :     double y = Tools::fastpow( val/3.75, 2 );
     348           2 :     return 1 + y*(3.5156229 +y*(3.0899424 + y*(1.2067492+y*(0.2659732+y*(0.0360768+y*0.0045813)))));
     349             :   }
     350          12 :   double ax=fabs(val), y=3.75/ax, bx=std::exp(ax)/sqrt(ax);
     351          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)))))));
     352          12 :   return ax*bx;
     353             : }
     354             : 
     355      705660 : bool Tools::startWith(const std::string & full,const std::string &start) {
     356     1411320 :   return (full.substr(0,start.length())==start);
     357             : }
     358             : 
     359       52360 : bool Tools::findKeyword(const std::vector<std::string>&line,const std::string&key) {
     360       52360 :   const std::string search(key+"=");
     361      515645 :   for(const auto & p : line) {
     362      485277 :     if(startWith(p,search)) return true;
     363             :   }
     364             :   return false;
     365             : }
     366             : 
     367         469 : Tools::DirectoryChanger::DirectoryChanger(const char*path) {
     368         469 :   if(!path) return;
     369         469 :   if(std::strlen(path)==0) return;
     370             : #ifdef __PLUMED_HAS_GETCWD
     371           0 :   char* ret=getcwd(cwd,buffersize);
     372           0 :   plumed_assert(ret)<<"Name of current directory too long, increase buffer size";
     373             : #else
     374             :   plumed_error()<<"You are trying to use DirectoryChanger but your system does not support getcwd";
     375             : #endif
     376             : #ifdef __PLUMED_HAS_CHDIR
     377           0 :   int r=chdir(path);
     378           0 :   plumed_assert(r==0) <<"Cannot chdir to directory "<<path<<". The directory must exist!";
     379             : #else
     380             :   plumed_error()<<"You are trying to use DirectoryChanger but your system does not support chdir";
     381             : #endif
     382             : }
     383             : 
     384         469 : Tools::DirectoryChanger::~DirectoryChanger() {
     385             : #ifdef __PLUMED_HAS_CHDIR
     386         469 :   if(strlen(cwd)==0) return;
     387           0 :   int ret=chdir(cwd);
     388             : // we cannot put an assertion here (in a destructor) otherwise cppcheck complains
     389             : // we thus just report the problem
     390           0 :   if(ret!=0) fprintf(stderr,"+++ WARNING: cannot cd back to directory %s\n",cwd);
     391             : #endif
     392         469 : }
     393             : 
     394        5517 : }

Generated by: LCOV version 1.14