LCOV - code coverage report
Current view: top level - tools - Tools.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 174 187 93.0 %
Date: 2020-11-18 11:20:57 Functions: 26 32 81.2 %

          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             : 
      32             : using namespace std;
      33             : namespace PLMD {
      34             : 
      35        3226 : static std::map<string, double> leptonConstants= {
      36             :   {"e", std::exp(1.0)},
      37             :   {"log2e", 1.0/std::log(2.0)},
      38             :   {"log10e", 1.0/std::log(10.0)},
      39             :   {"ln2", std::log(2.0)},
      40             :   {"ln10", std::log(10.0)},
      41             :   {"pi", pi},
      42             :   {"pi_2", pi*0.5},
      43             :   {"pi_4", pi*0.25},
      44             : //  {"1_pi", 1.0/pi},
      45             : //  {"2_pi", 2.0/pi},
      46             : //  {"2_sqrtpi", 2.0/std::sqrt(pi)},
      47             :   {"sqrt2", std::sqrt(2.0)},
      48             :   {"sqrt1_2", std::sqrt(0.5)}
      49             : };
      50             : 
      51             : template<class T>
      52     3974712 : bool Tools::convertToAny(const string & str,T & t) {
      53    11924136 :   istringstream istr(str.c_str());
      54     3974712 :   bool ok=static_cast<bool>(istr>>t);
      55     3974712 :   if(!ok) return false;
      56             :   string remaining;
      57     1887317 :   istr>>remaining;
      58     1887317 :   return remaining.length()==0;
      59             : }
      60             : 
      61      212337 : bool Tools::convert(const string & str,int & t) {
      62      212337 :   return convertToAny(str,t);
      63             : }
      64             : 
      65          82 : bool Tools::convert(const string & str,long int & t) {
      66          82 :   return convertToAny(str,t);
      67             : }
      68             : 
      69      259856 : bool Tools::convert(const string & str,unsigned & t) {
      70      259856 :   return convertToAny(str,t);
      71             : }
      72             : 
      73      159413 : bool Tools::convert(const string & str,AtomNumber &a) {
      74             :   unsigned i;
      75      159413 :   bool r=convert(str,i);
      76      159413 :   if(r) a.setSerial(i);
      77      159413 :   return r;
      78             : }
      79             : 
      80             : template<class T>
      81     3502437 : bool Tools::convertToReal(const string & str,T & t) {
      82     3502437 :   if(convertToAny(str,t)) return true;
      83     8322138 :   if(str=="PI" || str=="+PI" || str=="+pi" || str=="pi") {
      84     1040319 :     t=pi; return true;
      85     2080512 :   } else if(str=="-PI" || str=="-pi") {
      86     1040236 :     t=-pi; return true;
      87             :   }
      88             :   try {
      89          42 :     t=lepton::Parser::parse(str).evaluate(leptonConstants);
      90           2 :     return true;
      91          18 :   } catch(PLMD::lepton::Exception& exc) {
      92             :   }
      93          18 :   if( str.find("PI")!=std::string::npos ) {
      94             :     std::size_t pi_start=str.find_first_of("PI");
      95           0 :     if(str.substr(pi_start)!="PI") return false;
      96           0 :     istringstream nstr(str.substr(0,pi_start));
      97           0 :     T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
      98           0 :     if(!ok) return false;
      99           0 :     t=ff*pi;
     100           0 :     std::string remains; nstr>>remains;
     101           0 :     return remains.length()==0;
     102          18 :   } else if( str.find("pi")!=std::string::npos ) {
     103             :     std::size_t pi_start=str.find_first_of("pi");
     104          28 :     if(str.substr(pi_start)!="pi") return false;
     105          42 :     istringstream nstr(str.substr(0,pi_start));
     106          28 :     T ff=0.0; bool ok=static_cast<bool>(nstr>>ff);
     107          14 :     if(!ok) return false;
     108          14 :     t=ff*pi;
     109          14 :     std::string remains; nstr>>remains;
     110          14 :     return remains.length()==0;
     111           4 :   } else if(str=="NAN") {
     112           0 :     t=NAN;
     113           0 :     return true;
     114             :   }
     115             :   return false;
     116             : }
     117             : 
     118           0 : bool Tools::convert(const string & str,float & t) {
     119           0 :   return convertToReal(str,t);
     120             : }
     121             : 
     122     3502437 : bool Tools::convert(const string & str,double & t) {
     123     3502437 :   return convertToReal(str,t);
     124             : }
     125             : 
     126           0 : bool Tools::convert(const string & str,long double & t) {
     127           0 :   return convertToReal(str,t);
     128             : }
     129             : 
     130       26303 : bool Tools::convert(const string & str,string & t) {
     131             :   t=str;
     132       26303 :   return true;
     133             : }
     134             : 
     135      570310 : vector<string> Tools::getWords(const string & line,const char* separators,int * parlevel,const char* parenthesis) {
     136      570310 :   plumed_massert(strlen(parenthesis)==1,"multiple parenthesis type not available");
     137      570310 :   plumed_massert(parenthesis[0]=='(' || parenthesis[0]=='[' || parenthesis[0]=='{',
     138             :                  "only ( [ { allowed as parenthesis");
     139      570310 :   if(!separators) separators=" \t\n";
     140      570310 :   const string sep(separators);
     141      570310 :   char openpar=parenthesis[0];
     142             :   char closepar;
     143             :   if(openpar=='(') closepar=')';
     144      570310 :   if(openpar=='[') closepar=']';
     145      570310 :   if(openpar=='{') closepar='}';
     146             :   vector<string> words;
     147             :   string word;
     148             :   int parenthesisLevel=0;
     149      570310 :   if(parlevel) parenthesisLevel=*parlevel;
     150    61520408 :   for(unsigned i=0; i<line.length(); i++) {
     151             :     bool found=false;
     152             :     bool onParenthesis=false;
     153    20126596 :     if(line[i]==openpar || line[i]==closepar) onParenthesis=true;
     154    20126596 :     if(line[i]==closepar) {
     155        1456 :       parenthesisLevel--;
     156        1456 :       plumed_massert(parenthesisLevel>=0,"Extra closed parenthesis in '" + line + "'");
     157             :     }
     158   160981124 :     if(parenthesisLevel==0) for(unsigned j=0; j<sep.length(); j++) if(line[i]==sep[j]) found=true;
     159             : // If at parenthesis level zero (outer)
     160    20126596 :     if(!(parenthesisLevel==0 && (found||onParenthesis))) word.push_back(line[i]);
     161             :     //if(onParenthesis) word.push_back(' ');
     162    20126596 :     if(line[i]==openpar) parenthesisLevel++;
     163    25418579 :     if(found && word.length()>0) {
     164     1063860 :       if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
     165     1063860 :       words.push_back(word);
     166             :       word.clear();
     167             :     }
     168             :   }
     169      570310 :   if(word.length()>0) {
     170      460664 :     if(!parlevel) plumed_massert(parenthesisLevel==0,"Unmatching parenthesis in '" + line + "'");
     171      460664 :     words.push_back(word);
     172             :   }
     173      570310 :   if(parlevel) *parlevel=parenthesisLevel;
     174      570310 :   return words;
     175             : }
     176             : 
     177        5678 : bool Tools::getParsedLine(IFile& ifile,vector<string> & words) {
     178        5678 :   string line("");
     179        5678 :   words.clear();
     180             :   bool stat;
     181             :   bool inside=false;
     182        5678 :   int parlevel=0;
     183             :   bool mergenext=false;
     184       18499 :   while((stat=ifile.getline(line))) {
     185       17943 :     trimComments(line);
     186       17943 :     trim(line);
     187       17943 :     if(line.length()==0) continue;
     188       21918 :     vector<string> w=getWords(line,NULL,&parlevel);
     189       13520 :     if(!w.empty()) {
     190       21916 :       if(inside && *(w.begin())=="...") {
     191             :         inside=false;
     192        1791 :         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]);
     193         923 :         plumed_massert(w.size()<=2,"terminating \"...\" lines cannot consist of more than two words");
     194         923 :         w.clear();
     195       12596 :       } else if(*(w.end()-1)=="...") {
     196             :         inside=true;
     197             :         w.erase(w.end()-1);
     198             :       };
     199             :       int i0=0;
     200       13539 :       if(mergenext && words.size()>0 && w.size()>0) {
     201          30 :         words[words.size()-1]+=" "+w[0];
     202             :         i0=1;
     203             :       }
     204       81076 :       for(unsigned i=i0; i<w.size(); ++i) words.push_back(w[i]);
     205             :     }
     206       13520 :     mergenext=(parlevel>0);
     207       13520 :     if(!inside)break;
     208             :   }
     209        5678 :   plumed_massert(parlevel==0,"non matching parenthesis");
     210        5678 :   if(words.size()>0) return true;
     211         556 :   return stat;
     212             : }
     213             : 
     214             : 
     215     1801118 : bool Tools::getline(FILE* fp,string & line) {
     216             :   line="";
     217             :   const int bufferlength=1024;
     218             :   char buffer[bufferlength];
     219             :   bool ret;
     220  1846145950 :   for(int i=0; i<bufferlength; i++) buffer[i]='\0';
     221     1801118 :   while((ret=fgets(buffer,bufferlength,fp))) {
     222     1800526 :     line.append(buffer);
     223     1800526 :     unsigned ss=strlen(buffer);
     224     1800526 :     if(ss>0) if(buffer[ss-1]=='\n') break;
     225             :   };
     226     3601644 :   if(line.length()>0) if(*(line.end()-1)=='\n') line.erase(line.end()-1);
     227     3601644 :   if(line.length()>0) if(*(line.end()-1)=='\r') line.erase(line.end()-1);
     228     1801118 :   return ret;
     229             : }
     230             : 
     231      214297 : void Tools::trim(string & s) {
     232             :   size_t n=s.find_last_not_of(" \t");
     233      428594 :   s=s.substr(0,n+1);
     234      214297 : }
     235             : 
     236      131443 : void Tools::trimComments(string & s) {
     237             :   size_t n=s.find_first_of("#");
     238      262886 :   s=s.substr(0,n);
     239      131443 : }
     240             : 
     241       52111 : bool Tools::getKey(vector<string>& line,const string & key,string & s,int rep) {
     242             :   s.clear();
     243      257036 :   for(auto p=line.begin(); p!=line.end(); ++p) {
     244      229990 :     if((*p).length()==0) continue;
     245      229990 :     string x=(*p).substr(0,key.length());
     246      229990 :     if(x==key) {
     247       25065 :       if((*p).length()==key.length())return false;
     248       25064 :       string tmp=(*p).substr(key.length(),(*p).length());
     249             :       line.erase(p);
     250             :       s=tmp;
     251       25064 :       const std::string multi("@replicas:");
     252       25064 :       if(rep>=0 && startWith(s,multi)) {
     253          36 :         s=s.substr(multi.length(),s.length());
     254          36 :         std::vector<std::string> words=getWords(s,"\t\n ,");
     255          18 :         plumed_massert(rep<static_cast<int>(words.size()),"Number of fields in " + s + " not consistent with number of replicas");
     256          18 :         s=words[rep];
     257             :       }
     258             :       return true;
     259             :     }
     260             :   };
     261             :   return false;
     262             : }
     263             : 
     264        3353 : void Tools::interpretRanges(std::vector<std::string>&s) {
     265        3353 :   vector<string> news;
     266       11117 :   for(const auto & p :s) {
     267        7764 :     news.push_back(p);
     268             :     size_t dash=p.find("-");
     269       14698 :     if(dash==string::npos) continue;
     270             :     int first;
     271        2676 :     if(!Tools::convert(p.substr(0,dash),first)) continue;
     272         830 :     int stride=1;
     273             :     int second;
     274        1660 :     size_t colon=p.substr(dash+1).find(":");
     275         830 :     if(colon!=string::npos) {
     276          44 :       if(!Tools::convert(p.substr(dash+1).substr(0,colon),second) ||
     277          44 :           !Tools::convert(p.substr(dash+1).substr(colon+1),stride)) continue;
     278             :     } else {
     279        1638 :       if(!Tools::convert(p.substr(dash+1),second)) continue;
     280             :     }
     281         830 :     news.resize(news.size()-1);
     282         830 :     if(first<=second) {
     283         829 :       plumed_massert(stride>0,"interpreting ranges "+ p + ", stride should be positive");
     284      307323 :       for(int i=first; i<=second; i+=stride) {
     285             :         string ss;
     286      153247 :         convert(i,ss);
     287      153247 :         news.push_back(ss);
     288             :       }
     289             :     } else {
     290           1 :       plumed_massert(stride<0,"interpreting ranges "+ p + ", stride should be positive");
     291           5 :       for(int i=first; i>=second; i+=stride) {
     292             :         string ss;
     293           2 :         convert(i,ss);
     294           2 :         news.push_back(ss);
     295             :       }
     296             :     }
     297             :   }
     298        3353 :   s=news;
     299        3353 : }
     300             : 
     301        5280 : void Tools::interpretLabel(vector<string>&s) {
     302        5510 :   if(s.size()<2)return;
     303             :   string s0=s[0];
     304        5050 :   unsigned l=s0.length();
     305        5050 :   if(l<1) return;
     306       10100 :   if(s0[l-1]==':') {
     307             :     s[0]=s[1];
     308       11028 :     s[1]="LABEL="+s0.substr(0,l-1);
     309             :   }
     310             : }
     311             : 
     312        3168 : vector<string> Tools::ls(const string&d) {
     313             :   DIR*dir;
     314             :   vector<string> result;
     315        3168 :   if ((dir=opendir(d.c_str()))) {
     316             : #if defined(__PLUMED_HAS_READDIR_R)
     317             :     struct dirent ent;
     318             : #endif
     319             :     while(true) {
     320             :       struct dirent *res;
     321             : #if defined(__PLUMED_HAS_READDIR_R)
     322       44752 :       readdir_r(dir,&ent,&res);
     323             : #else
     324             : // cppcheck complains about this:
     325             : // (portability) Non reentrant function 'readdir' called. For threadsafe applications it is recommended to use the reentrant replacement function 'readdir_r'.
     326             : // since we use it only if readdir_r is not available, I suppress the warning
     327             : // GB
     328             : // cppcheck-suppress readdirCalled
     329             :       res=readdir(dir);
     330             : #endif
     331       44752 :       if(!res) break;
     332      240000 :       if(string(res->d_name)!="." && string(res->d_name)!="..") result.push_back(res->d_name);
     333       41584 :     }
     334        3168 :     closedir (dir);
     335             :   }
     336        3168 :   return result;
     337             : }
     338             : 
     339        1862 : void Tools::stripLeadingAndTrailingBlanks( std::string& str ) {
     340        1862 :   std::size_t first=str.find_first_not_of(' ');
     341        1862 :   std::size_t last=str.find_last_not_of(' ');
     342        3692 :   if( first<=last && first!=std::string::npos) str=str.substr(first,last+1);
     343        1862 : }
     344             : 
     345        8523 : std::string Tools::extension(const std::string&s) {
     346             :   size_t n=s.find_last_of(".");
     347             :   std::string ext;
     348       14969 :   if(n!=std::string::npos && n+1<s.length() && n+5>=s.length()) {
     349       12580 :     ext=s.substr(n+1);
     350        6290 :     if(ext.find("/")!=std::string::npos) ext="";
     351        6290 :     string base=s.substr(0,n);
     352        6290 :     if(base.length()==0) ext="";
     353       12580 :     if(base.length()>0 && base[base.length()-1]=='/') ext="";
     354             :   }
     355        8523 :   return ext;
     356             : }
     357             : 
     358      608680 : bool Tools::startWith(const std::string & full,const std::string &start) {
     359     1217360 :   return (full.substr(0,start.length())==start);
     360             : }
     361             : 
     362       44791 : bool Tools::findKeyword(const std::vector<std::string>&line,const std::string&key) {
     363       44791 :   const std::string search(key+"=");
     364      437112 :   for(const auto & p : line) {
     365      411338 :     if(startWith(p,search)) return true;
     366             :   }
     367             :   return false;
     368             : }
     369             : 
     370             : 
     371             : 
     372        4839 : }

Generated by: LCOV version 1.13