LCOV - code coverage report
Current view: top level - tools - OFile.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 205 211 97.2 %
Date: 2020-11-18 11:20:57 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     3904837 : size_t OFile::llwrite(const char*ptr,size_t s) {
      44             :   size_t r;
      45     3904837 :   if(linked) return linked->llwrite(ptr,s);
      46     3904832 :   if(! (comm && comm->Get_rank()>0)) {
      47     3213423 :     if(!fp) plumed_merror("writing on uninitilized File");
      48     3213423 :     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     3212169 :       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     3904832 :   if(comm) comm->Barrier();
      65             : 
      66             : 
      67     3904832 :   if(comm) comm->Bcast(r,0);
      68     3904832 :   return r;
      69             : }
      70             : 
      71        5620 : OFile::OFile():
      72             :   linked(NULL),
      73             :   fieldChanged(false),
      74             :   backstring("bck"),
      75             :   enforceRestart_(false),
      76       28100 :   enforceBackup_(false)
      77             : {
      78        5620 :   fmtField();
      79        5620 :   buflen=1;
      80        5620 :   actual_buffer_length=0;
      81        5620 :   buffer=new char[buflen];
      82             : // these are set to zero to avoid valgrind errors
      83       11240 :   for(int i=0; i<buflen; ++i) buffer[i]=0;
      84        5620 :   buffer_string=new char [1000];
      85             : // these are set to zero to avoid valgrind errors
      86     5625620 :   for(unsigned i=0; i<1000; ++i) buffer_string[i]=0;
      87        5620 : }
      88             : 
      89       21135 : OFile::~OFile() {
      90        5620 :   delete [] buffer_string;
      91        5620 :   delete [] buffer;
      92        6508 : }
      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        2233 : OFile& OFile::setLinePrefix(const std::string&l) {
     102        2233 :   linePrefix=l;
     103        2233 :   return *this;
     104             : }
     105             : 
     106    18077884 : int OFile::printf(const char*fmt,...) {
     107             :   va_list arg;
     108    18077884 :   va_start(arg, fmt);
     109    18077884 :   int r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
     110    18077884 :   va_end(arg);
     111    18077884 :   if(r>=buflen-actual_buffer_length) {
     112             :     int newlen=buflen;
     113       33324 :     while(newlen<=r+actual_buffer_length) newlen*=2;
     114       10664 :     char* newbuf=new char [newlen];
     115       10664 :     memmove(newbuf,buffer,buflen);
     116     1846599 :     for(int k=buflen; k<newlen; k++) newbuf[k]=0;
     117       10664 :     delete [] buffer;
     118       10664 :     buffer=newbuf;
     119       10664 :     buflen=newlen;
     120             :     va_list arg;
     121       10664 :     va_start(arg, fmt);
     122       10664 :     r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
     123       10664 :     va_end(arg);
     124             :   }
     125    18077884 :   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    18077884 :   char*p1=buffer;
     129             :   char*p2;
     130             : // newline is only searched in the just added portion:
     131    18077884 :   char*psearch=p1+actual_buffer_length;
     132    18077884 :   actual_buffer_length+=r;
     133    25507632 :   while((p2=strchr(psearch,'\n'))) {
     134     3904832 :     if(linePrefix.length()>0) llwrite(linePrefix.c_str(),linePrefix.length());
     135     3714874 :     llwrite(p1,p2-p1+1);
     136     3714874 :     actual_buffer_length-=(p2-p1)+1;
     137     3714874 :     p1=p2+1;
     138             :     psearch=p1;
     139             :   };
     140    18077884 :   if(buffer!=p1) memmove(buffer,p1,actual_buffer_length);
     141    18077884 :   return r;
     142             : }
     143             : 
     144       24541 : OFile& OFile::addConstantField(const std::string&name) {
     145             :   Field f;
     146             :   f.name=name;
     147       24541 :   const_fields.push_back(f);
     148       24541 :   return *this;
     149             : }
     150             : 
     151             : 
     152        2965 : OFile& OFile::clearFields() {
     153             :   fields.clear();
     154             :   const_fields.clear();
     155             :   previous_fields.clear();
     156        2965 :   return *this;
     157             : }
     158             : 
     159    12467756 : OFile& OFile::fmtField(const std::string&fmt) {
     160    12467756 :   this->fieldFmt=fmt;
     161    12467756 :   return *this;
     162             : }
     163             : 
     164       11188 : OFile& OFile::fmtField() {
     165       11188 :   this->fieldFmt="%23.16lg";
     166       11188 :   return *this;
     167             : }
     168             : 
     169    13055585 : OFile& OFile::printField(const std::string&name,double v) {
     170    13055585 :   sprintf(buffer_string,fieldFmt.c_str(),v);
     171    26111170 :   printField(name,buffer_string);
     172    13055585 :   return *this;
     173             : }
     174             : 
     175     5587149 : OFile& OFile::printField(const std::string&name,int v) {
     176     5587149 :   sprintf(buffer_string," %d",v);
     177    11174298 :   printField(name,buffer_string);
     178     5587149 :   return *this;
     179             : }
     180             : 
     181    33527832 : OFile& OFile::printField(const std::string&name,const std::string & v) {
     182             :   unsigned i;
     183   511356388 :   for(i=0; i<const_fields.size(); i++) if(const_fields[i].name==name) break;
     184    33527832 :   if(i>=const_fields.size()) {
     185             :     Field field;
     186             :     field.name=name;
     187             :     field.value=v;
     188    13974929 :     fields.push_back(field);
     189             :   } else {
     190    39105806 :     if(const_fields[i].value!=v) fieldChanged=true;
     191             :     const_fields[i].value=v;
     192             :   }
     193    33527832 :   return *this;
     194             : }
     195             : 
     196        4004 : OFile& OFile::setupPrintValue( Value *val ) {
     197        4004 :   if( val->isPeriodic() ) {
     198         450 :     addConstantField("min_" + val->getName() );
     199         450 :     addConstantField("max_" + val->getName() );
     200             :   }
     201        4004 :   return *this;
     202             : }
     203             : 
     204      113957 : OFile& OFile::printField( Value* val, const double& v ) {
     205      227914 :   printField( val->getName(), v );
     206      113957 :   if( val->isPeriodic() ) {
     207        6475 :     std::string min, max; val->getDomain( min, max );
     208       12950 :     printField( "min_" + val->getName(), min );
     209       12950 :     printField("max_" + val->getName(), max );
     210             :   }
     211      113957 :   return *this;
     212             : }
     213             : 
     214     3378878 : OFile& OFile::printField() {
     215             :   bool reprint=false;
     216     6753510 :   if(fieldChanged || fields.size()!=previous_fields.size()) {
     217             :     reprint=true;
     218    31253863 :   } else for(unsigned i=0; i<fields.size(); i++) {
     219    55760142 :       if( previous_fields[i].name!=fields[i].name ||
     220    13940034 :           (fields[i].constant && fields[i].value!=previous_fields[i].value) ) {
     221             :         reprint=true;
     222             :         break;
     223             :       }
     224             :     }
     225     3378878 :   if(reprint) {
     226        5085 :     printf("#! FIELDS");
     227      114861 :     for(unsigned i=0; i<fields.size(); i++) printf(" %s",fields[i].name.c_str());
     228        5085 :     printf("\n");
     229       83721 :     for(unsigned i=0; i<const_fields.size(); i++) {
     230       24517 :       printf("#! SET %s %s",const_fields[i].name.c_str(),const_fields[i].value.c_str());
     231       24517 :       printf("\n");
     232             :     }
     233             :   }
     234    48682543 :   for(unsigned i=0; i<fields.size(); i++) printf("%s",fields[i].value.c_str());
     235     3378878 :   printf("\n");
     236     3378878 :   previous_fields=fields;
     237             :   fields.clear();
     238     3378878 :   fieldChanged=false;
     239     3378878 :   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           4 :   if(str=="/dev/null") return;
     248           8 :   plumed_assert( backstring!="bck" && !checkRestart());
     249             :   size_t found=str.find_last_of("/\\");
     250           8 :   std::string filename = appendSuffix(str,getSuffix());
     251           4 :   std::string directory=filename.substr(0,found+1);
     252           4 :   std::string file=filename.substr(found+1);
     253           4 :   if( FileExist(filename) ) backupFile("bck", filename);
     254           0 :   for(int i=0;; i++) {
     255           4 :     std::string num; Tools::convert(i,num);
     256          20 :     std::string filestr = directory + backstring + "." + num + "." + file;
     257           4 :     if( !FileExist(filestr) ) break;
     258           0 :     backupFile( "bck", filestr);
     259           0 :   }
     260             : }
     261             : 
     262        2514 : void OFile::backupFile( const std::string& bstring, const std::string& fname ) {
     263        2662 :   if(fname=="/dev/null") return;
     264        2366 :   int maxbackup=100;
     265        2366 :   if(std::getenv("PLUMED_MAXBACKUP")) Tools::convert(std::getenv("PLUMED_MAXBACKUP"),maxbackup);
     266        2366 :   if(maxbackup>0 && (!comm || comm->Get_rank()==0)) {
     267        1979 :     FILE* ff=std::fopen(const_cast<char*>(fname.c_str()),"r");
     268        1979 :     if(ff) {
     269          52 :       std::fclose(ff);
     270             :       std::string backup;
     271             :       size_t found=fname.find_last_of("/\\");
     272          52 :       std::string directory=fname.substr(0,found+1);
     273          52 :       std::string file=fname.substr(found+1);
     274           0 :       for(int i=0;; i++) {
     275             :         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         312 :         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          52 :       plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno));
     285             :     }
     286             :   }
     287             : }
     288             : 
     289        2743 : OFile& OFile::open(const std::string&path) {
     290        2743 :   plumed_assert(!cloned);
     291        2743 :   eof=false;
     292        2743 :   err=false;
     293        2743 :   fp=NULL;
     294        2743 :   gzfp=NULL;
     295        2743 :   this->path=path;
     296        8229 :   this->path=appendSuffix(path,getSuffix());
     297        2743 :   if(checkRestart()) {
     298         458 :     fp=std::fopen(const_cast<char*>(this->path.c_str()),"a");
     299         229 :     mode="a";
     300         458 :     if(Tools::extension(this->path)=="gz") {
     301             : #ifdef __PLUMED_HAS_ZLIB
     302          48 :       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        2514 :     backupFile( backstring, this->path );
     309        2514 :     if(comm)comm->Barrier();
     310        5028 :     fp=std::fopen(const_cast<char*>(this->path.c_str()),"w");
     311        2514 :     mode="w";
     312        5028 :     if(Tools::extension(this->path)=="gz") {
     313             : #ifdef __PLUMED_HAS_ZLIB
     314           2 :       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        2743 :   if(plumed) plumed->insertFile(*this);
     321        2743 :   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             :     size_t found=fname.find_last_of("/\\");
     338          76 :     std::string directory=fname.substr(0,found+1);
     339          76 :     std::string file=fname.substr(found+1);
     340         228 :     std::string backup=directory+backstring +".last."+file;
     341          76 :     int check=rename(fname.c_str(),backup.c_str());
     342          76 :     plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno));
     343             :   }
     344             : 
     345          94 :   if(comm) comm->Barrier();
     346             : 
     347          94 :   if(gzfp) {
     348             : #ifdef __PLUMED_HAS_ZLIB
     349          15 :     gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"w9");
     350             : #endif
     351          79 :   } else fp=std::fopen(const_cast<char*>(path.c_str()),"w");
     352          94 :   return *this;
     353             : }
     354             : 
     355        7160 : FileBase& OFile::flush() {
     356        7160 :   if(heavyFlush) {
     357        3751 :     if(gzfp) {
     358             : #ifdef __PLUMED_HAS_ZLIB
     359           9 :       gzclose(gzFile(gzfp));
     360          18 :       gzfp=(void*)gzopen(const_cast<char*>(path.c_str()),"a");
     361             : #endif
     362             :     } else {
     363        3742 :       fclose(fp);
     364        7484 :       fp=std::fopen(const_cast<char*>(path.c_str()),"a");
     365             :     }
     366             :   } else {
     367        3409 :     FileBase::flush();
     368             :     // if(gzfp) gzflush(gzFile(gzfp),Z_FINISH);
     369             :     // for some reason flushing with Z_FINISH has problems on linux
     370             :     // I thus use this (incomplete) flush
     371             : #ifdef __PLUMED_HAS_ZLIB
     372        3409 :     if(gzfp) gzflush(gzFile(gzfp),Z_FULL_FLUSH);
     373             : #endif
     374             :   }
     375        7160 :   return *this;
     376             : }
     377             : 
     378        2747 : bool OFile::checkRestart()const {
     379        2747 :   if(enforceRestart_) return true;
     380        2746 :   else if(enforceBackup_) return false;
     381        3370 :   else if(action) return action->getRestart();
     382         170 :   else if(plumed) return plumed->getRestart();
     383             :   else return false;
     384             : }
     385             : 
     386           1 : OFile& OFile::enforceRestart() {
     387           1 :   enforceRestart_=true;
     388           1 :   enforceBackup_=false;
     389           1 :   return *this;
     390             : }
     391             : 
     392         976 : OFile& OFile::enforceBackup() {
     393         976 :   enforceBackup_=true;
     394         976 :   enforceRestart_=false;
     395         976 :   return *this;
     396             : }
     397             : 
     398             : 
     399        4839 : }

Generated by: LCOV version 1.13