LCOV - code coverage report
Current view: top level - tools - OFile.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 229 232 98.7 %
Date: 2019-08-13 10:39:37 Functions: 30 30 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-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 "OFile.h"
      23             : #include "Exception.h"
      24             : #include "core/Action.h"
      25             : #include "core/PlumedMain.h"
      26             : #include "core/Value.h"
      27             : #include "Communicator.h"
      28             : #include "Tools.h"
      29             : #include <cstdarg>
      30             : #include <cstring>
      31             : 
      32             : #include <iostream>
      33             : #include <string>
      34             : #include <cstdlib>
      35             : #include <cerrno>
      36             : 
      37             : #ifdef __PLUMED_HAS_ZLIB
      38             : #include <zlib.h>
      39             : #endif
      40             : 
      41             : namespace PLMD {
      42             : 
      43     3775319 : size_t OFile::llwrite(const char*ptr,size_t s) {
      44             :   size_t r;
      45     3775319 :   if(linked) return linked->llwrite(ptr,s);
      46     3775314 :   if(! (comm && comm->Get_rank()>0)) {
      47     3083905 :     if(!fp) plumed_merror("writing on uninitilized File");
      48     3083905 :     if(gzfp) {
      49             : #ifdef __PLUMED_HAS_ZLIB
      50        1254 :       r=gzwrite(gzFile(gzfp),ptr,s);
      51             : #else
      52             :       plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
      53             : #endif
      54             :     } else {
      55     3082651 :       r=fwrite(ptr,1,s,fp);
      56             :     }
      57             :   }
      58             : //  This barrier is apparently useless since it comes
      59             : //  just before a Bcast.
      60             : //
      61             : //  Anyway, it looks like it is solving an issue that appeared on
      62             : //  TRAVIS (at least on my laptop) so I add it here.
      63             : //  GB
      64     3775314 :   if(comm) comm->Barrier();
      65             : 
      66             : 
      67     3775314 :   if(comm) comm->Bcast(r,0);
      68     3775314 :   return r;
      69             : }
      70             : 
      71        5579 : OFile::OFile():
      72             :   linked(NULL),
      73             :   fieldChanged(false),
      74             :   backstring("bck"),
      75             :   enforceRestart_(false),
      76        5579 :   enforceBackup_(false)
      77             : {
      78        5579 :   fmtField();
      79        5579 :   buflen=1;
      80        5579 :   actual_buffer_length=0;
      81        5579 :   buffer=new char[buflen];
      82             : // these are set to zero to avoid valgrind errors
      83        5579 :   for(int i=0; i<buflen; ++i) buffer[i]=0;
      84        5579 :   buffer_string=new char [1000];
      85             : // these are set to zero to avoid valgrind errors
      86        5579 :   for(unsigned i=0; i<1000; ++i) buffer_string[i]=0;
      87        5579 : }
      88             : 
      89       15374 : OFile::~OFile() {
      90        5579 :   delete [] buffer_string;
      91        5579 :   delete [] buffer;
      92        9795 : }
      93             : 
      94           1 : OFile& OFile::link(OFile&l) {
      95           1 :   fp=NULL;
      96           1 :   gzfp=NULL;
      97           1 :   linked=&l;
      98           1 :   return *this;
      99             : }
     100             : 
     101        2225 : OFile& OFile::setLinePrefix(const std::string&l) {
     102        2225 :   linePrefix=l;
     103        2225 :   return *this;
     104             : }
     105             : 
     106    17495067 : int OFile::printf(const char*fmt,...) {
     107             :   va_list arg;
     108    17495067 :   va_start(arg, fmt);
     109    17495067 :   int r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
     110    17495067 :   va_end(arg);
     111    17495067 :   if(r>=buflen-actual_buffer_length) {
     112       10573 :     int newlen=buflen;
     113       10573 :     while(newlen<=r+actual_buffer_length) newlen*=2;
     114       10573 :     char* newbuf=new char [newlen];
     115       10573 :     memmove(newbuf,buffer,buflen);
     116       10573 :     for(int k=buflen; k<newlen; k++) newbuf[k]=0;
     117       10573 :     delete [] buffer;
     118       10573 :     buffer=newbuf;
     119       10573 :     buflen=newlen;
     120             :     va_list arg;
     121       10573 :     va_start(arg, fmt);
     122       10573 :     r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
     123       10573 :     va_end(arg);
     124             :   }
     125    17495067 :   plumed_massert(r>-1 && r<buflen-actual_buffer_length,"error using fmt string " + std::string(fmt));
     126             : 
     127             : // Line is buffered until newline, then written with a PLUMED: prefix
     128    17495067 :   char*p1=buffer;
     129             :   char*p2;
     130             : // newline is only searched in the just added portion:
     131    17495067 :   char*psearch=p1+actual_buffer_length;
     132    17495067 :   actual_buffer_length+=r;
     133    38575688 :   while((p2=strchr(psearch,'\n'))) {
     134     3585554 :     if(linePrefix.length()>0) llwrite(linePrefix.c_str(),linePrefix.length());
     135     3585554 :     llwrite(p1,p2-p1+1);
     136     3585554 :     actual_buffer_length-=(p2-p1)+1;
     137     3585554 :     p1=p2+1;
     138     3585554 :     psearch=p1;
     139             :   };
     140    17495067 :   if(buffer!=p1) memmove(buffer,p1,actual_buffer_length);
     141    17495067 :   return r;
     142             : }
     143             : 
     144       24288 : OFile& OFile::addConstantField(const std::string&name) {
     145       24288 :   Field f;
     146       24288 :   f.name=name;
     147       24288 :   const_fields.push_back(f);
     148       24288 :   return *this;
     149             : }
     150             : 
     151             : 
     152        2954 : OFile& OFile::clearFields() {
     153        2954 :   fields.clear();
     154        2954 :   const_fields.clear();
     155        2954 :   previous_fields.clear();
     156        2954 :   return *this;
     157             : }
     158             : 
     159    12012778 : OFile& OFile::fmtField(const std::string&fmt) {
     160    12012778 :   this->fieldFmt=fmt;
     161    12012778 :   return *this;
     162             : }
     163             : 
     164       11125 : OFile& OFile::fmtField() {
     165       11125 :   this->fieldFmt="%23.16lg";
     166       11125 :   return *this;
     167             : }
     168             : 
     169    12600607 : OFile& OFile::printField(const std::string&name,double v) {
     170    12600607 :   sprintf(buffer_string,fieldFmt.c_str(),v);
     171    12600607 :   printField(name,buffer_string);
     172    12600607 :   return *this;
     173             : }
     174             : 
     175     5335694 : OFile& OFile::printField(const std::string&name,int v) {
     176     5335694 :   sprintf(buffer_string," %d",v);
     177     5335694 :   printField(name,buffer_string);
     178     5335694 :   return *this;
     179             : }
     180             : 
     181    32063837 : OFile& OFile::printField(const std::string&name,const std::string & v) {
     182             :   unsigned i;
     183    32063837 :   for(i=0; i<const_fields.size(); i++) if(const_fields[i].name==name) break;
     184    32063837 :   if(i>=const_fields.size()) {
     185    13521895 :     Field field;
     186    13521895 :     field.name=name;
     187    13521895 :     field.value=v;
     188    13521895 :     fields.push_back(field);
     189             :   } else {
     190    18541942 :     if(const_fields[i].value!=v) fieldChanged=true;
     191    18541942 :     const_fields[i].value=v;
     192             :   }
     193    32063837 :   return *this;
     194             : }
     195             : 
     196        4001 : OFile& OFile::setupPrintValue( Value *val ) {
     197        4001 :   if( val->isPeriodic() ) {
     198         223 :     addConstantField("min_" + val->getName() );
     199         223 :     addConstantField("max_" + val->getName() );
     200             :   }
     201        4001 :   return *this;
     202             : }
     203             : 
     204      113894 : OFile& OFile::printField( Value* val, const double& v ) {
     205      113894 :   printField( val->getName(), v );
     206      113894 :   if( val->isPeriodic() ) {
     207       12866 :     std::string min, max; val->getDomain( min, max );
     208        6433 :     printField( "min_" + val->getName(), min );
     209       12866 :     printField("max_" + val->getName(), max );
     210             :   }
     211      113894 :   return *this;
     212             : }
     213             : 
     214     3251368 : OFile& OFile::printField() {
     215     3251368 :   bool reprint=false;
     216     3251368 :   if(fieldChanged || fields.size()!=previous_fields.size()) {
     217        5043 :     reprint=true;
     218    16733461 :   } else for(unsigned i=0; i<fields.size(); i++) {
     219    26974276 :       if( previous_fields[i].name!=fields[i].name ||
     220    13487136 :           (fields[i].constant && fields[i].value!=previous_fields[i].value) ) {
     221           2 :         reprint=true;
     222           2 :         break;
     223             :       }
     224             :     }
     225     3251368 :   if(reprint) {
     226        5045 :     printf("#! FIELDS");
     227        5045 :     for(unsigned i=0; i<fields.size(); i++) printf(" %s",fields[i].name.c_str());
     228        5045 :     printf("\n");
     229       29309 :     for(unsigned i=0; i<const_fields.size(); i++) {
     230       24264 :       printf("#! SET %s %s",const_fields[i].name.c_str(),const_fields[i].value.c_str());
     231       24264 :       printf("\n");
     232             :     }
     233             :   }
     234     3251368 :   for(unsigned i=0; i<fields.size(); i++) printf("%s",fields[i].value.c_str());
     235     3251368 :   printf("\n");
     236     3251368 :   previous_fields=fields;
     237     3251368 :   fields.clear();
     238     3251368 :   fieldChanged=false;
     239     3251368 :   return *this;
     240             : }
     241             : 
     242          55 : void OFile::setBackupString( const std::string& str ) {
     243          55 :   backstring=str;
     244          55 : }
     245             : 
     246           4 : void OFile::backupAllFiles( const std::string& str ) {
     247           8 :   if(str=="/dev/null") return;
     248           4 :   plumed_assert( backstring!="bck" && !checkRestart());
     249           4 :   size_t found=str.find_last_of("/\\");
     250           4 :   std::string filename = appendSuffix(str,getSuffix());
     251           8 :   std::string directory=filename.substr(0,found+1);
     252           8 :   std::string file=filename.substr(found+1);
     253           4 :   if( FileExist(filename) ) backupFile("bck", filename);
     254           4 :   for(int i=0;; i++) {
     255           4 :     std::string num; Tools::convert(i,num);
     256           4 :     std::string filestr = directory + backstring + "." + num + "." + file;
     257           4 :     if( !FileExist(filestr) ) break;
     258           0 :     backupFile( "bck", filestr);
     259           4 :   }
     260             : }
     261             : 
     262        2483 : void OFile::backupFile( const std::string& bstring, const std::string& fname ) {
     263        4966 :   if(fname=="/dev/null") return;
     264        2335 :   int maxbackup=100;
     265        2335 :   if(std::getenv("PLUMED_MAXBACKUP")) Tools::convert(std::getenv("PLUMED_MAXBACKUP"),maxbackup);
     266        2335 :   if(maxbackup>0 && (!comm || comm->Get_rank()==0)) {
     267        1948 :     FILE* ff=std::fopen(const_cast<char*>(fname.c_str()),"r");
     268        1948 :     if(ff) {
     269          52 :       std::fclose(ff);
     270          52 :       std::string backup;
     271          52 :       size_t found=fname.find_last_of("/\\");
     272         104 :       std::string directory=fname.substr(0,found+1);
     273         104 :       std::string file=fname.substr(found+1);
     274          52 :       for(int i=0;; i++) {
     275          52 :         std::string num;
     276          52 :         Tools::convert(i,num);
     277          52 :         if(i>maxbackup) plumed_merror("cannot backup file "+file+" maximum number of backup is "+num+"\n");
     278          52 :         backup=directory+bstring +"."+num+"."+file;
     279          52 :         FILE* fff=std::fopen(backup.c_str(),"r");
     280          52 :         if(!fff) break;
     281           0 :         else std::fclose(fff);
     282           0 :       }
     283          52 :       int check=rename(fname.c_str(),backup.c_str());
     284         104 :       plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno));
     285             :     }
     286             :   }
     287             : }
     288             : 
     289        2712 : OFile& OFile::open(const std::string&path) {
     290        2712 :   plumed_assert(!cloned);
     291        2712 :   eof=false;
     292        2712 :   err=false;
     293        2712 :   fp=NULL;
     294        2712 :   gzfp=NULL;
     295        2712 :   this->path=path;
     296        2712 :   this->path=appendSuffix(path,getSuffix());
     297        2712 :   if(checkRestart()) {
     298         229 :     fp=std::fopen(const_cast<char*>(this->path.c_str()),"a");
     299         229 :     mode="a";
     300         229 :     if(Tools::extension(this->path)=="gz") {
     301             : #ifdef __PLUMED_HAS_ZLIB
     302          24 :       gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"a9");
     303             : #else
     304             :       plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
     305             : #endif
     306             :     }
     307             :   } else {
     308        2483 :     backupFile( backstring, this->path );
     309        2483 :     if(comm)comm->Barrier();
     310        2483 :     fp=std::fopen(const_cast<char*>(this->path.c_str()),"w");
     311        2483 :     mode="w";
     312        2483 :     if(Tools::extension(this->path)=="gz") {
     313             : #ifdef __PLUMED_HAS_ZLIB
     314           1 :       gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"w9");
     315             : #else
     316             :       plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
     317             : #endif
     318             :     }
     319             :   }
     320        2712 :   if(plumed) plumed->insertFile(*this);
     321        2712 :   return *this;
     322             : }
     323             : 
     324          94 : OFile& OFile::rewind() {
     325             : // we use here "hard" rewind, which means close/reopen
     326             : // the reason is that normal rewind does not work when in append mode
     327             : // moreover, we can take a backup of the file
     328          94 :   plumed_assert(fp);
     329          94 :   clearFields();
     330          94 :   if(gzfp) {
     331             : #ifdef __PLUMED_HAS_ZLIB
     332          15 :     gzclose((gzFile)gzfp);
     333             : #endif
     334          79 :   } else fclose(fp);
     335          94 :   if(!comm || comm->Get_rank()==0) {
     336          76 :     std::string fname=this->path;
     337          76 :     size_t found=fname.find_last_of("/\\");
     338         152 :     std::string directory=fname.substr(0,found+1);
     339         152 :     std::string file=fname.substr(found+1);
     340         152 :     std::string backup=directory+backstring +".last."+file;
     341          76 :     int check=rename(fname.c_str(),backup.c_str());
     342         152 :     plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno));
     343             :   }
     344          94 :   if(gzfp) {
     345             : #ifdef __PLUMED_HAS_ZLIB
     346          15 :     gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"w9");
     347             : #endif
     348          79 :   } else fp=std::fopen(const_cast<char*>(path.c_str()),"w");
     349          94 :   return *this;
     350             : }
     351             : 
     352        7149 : FileBase& OFile::flush() {
     353        7149 :   if(heavyFlush) {
     354        3747 :     if(gzfp) {
     355             : #ifdef __PLUMED_HAS_ZLIB
     356           9 :       gzclose(gzFile(gzfp));
     357           9 :       gzfp=(void*)gzopen(const_cast<char*>(path.c_str()),"a");
     358             : #endif
     359             :     } else {
     360        3738 :       fclose(fp);
     361        3738 :       fp=std::fopen(const_cast<char*>(path.c_str()),"a");
     362             :     }
     363             :   } else {
     364        3402 :     FileBase::flush();
     365             :     // if(gzfp) gzflush(gzFile(gzfp),Z_FINISH);
     366             :     // for some reason flushing with Z_FINISH has problems on linux
     367             :     // I thus use this (incomplete) flush
     368             : #ifdef __PLUMED_HAS_ZLIB
     369        3402 :     if(gzfp) gzflush(gzFile(gzfp),Z_FULL_FLUSH);
     370             : #endif
     371             :   }
     372        7149 :   return *this;
     373             : }
     374             : 
     375        2716 : bool OFile::checkRestart()const {
     376        2716 :   if(enforceRestart_) return true;
     377        2715 :   else if(enforceBackup_) return false;
     378        1763 :   else if(action) return action->getRestart();
     379         170 :   else if(plumed) return plumed->getRestart();
     380         170 :   else return false;
     381             : }
     382             : 
     383           1 : OFile& OFile::enforceRestart() {
     384           1 :   enforceRestart_=true;
     385           1 :   enforceBackup_=false;
     386           1 :   return *this;
     387             : }
     388             : 
     389         952 : OFile& OFile::enforceBackup() {
     390         952 :   enforceBackup_=true;
     391         952 :   enforceRestart_=false;
     392         952 :   return *this;
     393             : }
     394             : 
     395             : 
     396        4821 : }

Generated by: LCOV version 1.13