LCOV - code coverage report
Current view: top level - tools - OFile.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 274 301 91.0 %
Date: 2026-11-05 10:19:04 Functions: 33 35 94.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-2023 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 <string>
      33             : #include <cstdlib>
      34             : #include <cerrno>
      35             : #include <utility>
      36             : 
      37             : #include <sys/types.h>
      38             : #include <sys/stat.h>
      39             : 
      40             : #ifdef __PLUMED_HAS_ZLIB
      41             : #include <zlib.h>
      42             : #endif
      43             : 
      44             : namespace PLMD {
      45             : 
      46     6991287 : size_t OFile::llwrite(const char*ptr,size_t s) {
      47     6991287 :   if(linked) {
      48          52 :     return linked->llwrite(ptr,s);
      49             :   }
      50             :   // Only the first process writes. Until v2.10 this was followed by a Barrier and by a
      51             :   // Bcast of the number of written bytes, i.e. two collective operations per line,
      52             :   // which slowed down runs with many processes and hung if the processes did not
      53             :   // write the same number of lines. The return value is not used.
      54     6991235 :   if(comm && comm->Get_rank()>0) {
      55             :     return s;
      56             :   }
      57     5986188 :   if(!fp) {
      58           0 :     plumed_merror("writing on uninitialized File");
      59             :   }
      60             :   size_t r=0;
      61     5986188 :   if(gzfp) {
      62             : #ifdef __PLUMED_HAS_ZLIB
      63        1265 :     r=gzwrite(gzFile(gzfp),ptr,s);
      64             : #else
      65             :     plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
      66             : #endif
      67             :   } else {
      68     5984923 :     r=std::fwrite(ptr,1,s,fp);
      69             :   }
      70             :   return r;
      71             : }
      72             : 
      73      821661 : OFile::OFile():
      74      821661 :   linked(NULL),
      75      821661 :   fieldChanged(false),
      76      821661 :   backstring("bck"),
      77      821661 :   enforceRestart_(false),
      78      821661 :   enforceBackup_(false) {
      79      821661 :   fmtField();
      80      821661 :   buflen=1;
      81      821661 :   actual_buffer_length=0;
      82      821661 :   buffer.resize(buflen);
      83             : // these are set to zero to avoid valgrind errors
      84     1643322 :   for(int i=0; i<buflen; ++i) {
      85      821661 :     buffer[i]=0;
      86             :   }
      87             : // these are set to zero to avoid valgrind errors
      88      821661 :   buffer_string.resize(1000,0);
      89      821661 : }
      90             : 
      91          14 : OFile& OFile::link(OFile&l) {
      92          14 :   fp=NULL;
      93          14 :   gzfp=NULL;
      94          14 :   linked=&l;
      95          14 :   return *this;
      96             : }
      97             : 
      98      809627 : OFile& OFile::setLinePrefix(const std::string&l) {
      99      809627 :   linePrefix=l;
     100      809627 :   return *this;
     101             : }
     102             : 
     103    28361773 : int OFile::printf(const char*fmt,...) {
     104             :   va_list arg;
     105    28361773 :   va_start(arg, fmt);
     106    28361773 :   int r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
     107    28361773 :   va_end(arg);
     108    28361773 :   if(r>=buflen-actual_buffer_length) {
     109             :     int newlen=buflen;
     110       81470 :     while(newlen<=r+actual_buffer_length) {
     111       53801 :       newlen*=2;
     112             :     }
     113       27669 :     std::vector<char> newbuf(newlen);
     114       27669 :     std::memmove(newbuf.data(),buffer.data(),buflen);
     115    16808090 :     for(int k=buflen; k<newlen; k++) {
     116    16780421 :       newbuf[k]=0;
     117             :     }
     118             :     std::swap(buffer,newbuf);
     119       27669 :     buflen=newlen;
     120             :     va_list args;
     121       27669 :     va_start(args, fmt);
     122       27669 :     r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,args);
     123       27669 :     va_end(args);
     124       27669 :   }
     125    28361773 :   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             :   char*p1=buffer.data();
     129             :   char*p2;
     130             : // newline is only searched in the just added portion:
     131    28361773 :   char*psearch=p1+actual_buffer_length;
     132    28361773 :   actual_buffer_length+=r;
     133    34486495 :   while((p2=std::strchr(psearch,'\n'))) {
     134     6124722 :     if(linePrefix.length()>0) {
     135      866513 :       llwrite(linePrefix.c_str(),linePrefix.length());
     136             :     }
     137     6124722 :     llwrite(p1,p2-p1+1);
     138     6124722 :     actual_buffer_length-=(p2-p1)+1;
     139     6124722 :     p1=p2+1;
     140             :     psearch=p1;
     141             :   };
     142    28361773 :   if(buffer.data()!=p1) {
     143     6099704 :     std::memmove(buffer.data(),p1,actual_buffer_length);
     144             :   }
     145    28361773 :   return r;
     146             : }
     147             : 
     148       30858 : OFile& OFile::addConstantField(const std::string&name) {
     149             :   Field f;
     150             :   f.name=name;
     151       30858 :   const_fields.push_back(f);
     152       30858 :   return *this;
     153             : }
     154             : 
     155             : 
     156        3681 : OFile& OFile::clearFields() {
     157        3681 :   fields.clear();
     158        3681 :   const_fields.clear();
     159        3681 :   previous_fields.clear();
     160        3681 :   return *this;
     161             : }
     162             : 
     163    15942532 : OFile& OFile::fmtField(const std::string&fmt) {
     164    15942532 :   this->fieldFmt=fmt;
     165    15942532 :   return *this;
     166             : }
     167             : 
     168      827532 : OFile& OFile::fmtField() {
     169      827532 :   this->fieldFmt="%23.16lg";
     170      827532 :   return *this;
     171             : }
     172             : 
     173    17948842 : OFile& OFile::printField(const std::string&name,double v) {
     174             : // When one tries to print -nan we print nan instead.
     175             : // The distinction between +nan and -nan is not well defined
     176             : // Always printing nan simplifies some regtest (special functions computed our of range).
     177    17948842 :   if(std::isnan(v)) {
     178             :     v=std::numeric_limits<double>::quiet_NaN();
     179             :   }
     180             :   std::snprintf(buffer_string.data(),buffer_string.size(),fieldFmt.c_str(),v);
     181    17948842 :   printField(name,buffer_string.data());
     182    17948842 :   return *this;
     183             : }
     184             : 
     185     6522567 : OFile& OFile::printField(const std::string&name,int v) {
     186             :   std::snprintf(buffer_string.data(),buffer_string.size()," %d",v);
     187     6522567 :   printField(name,buffer_string.data());
     188     6522567 :   return *this;
     189             : }
     190             : 
     191           1 : OFile& OFile::printField(const std::string&name,long int v) {
     192             :   std::snprintf(buffer_string.data(),buffer_string.size()," %ld",v);
     193           1 :   printField(name,buffer_string.data());
     194           1 :   return *this;
     195             : }
     196             : 
     197           0 : OFile& OFile::printField(const std::string&name,long long int v) {
     198             :   std::snprintf(buffer_string.data(),buffer_string.size()," %lld",v);
     199           0 :   printField(name,buffer_string.data());
     200           0 :   return *this;
     201             : }
     202             : 
     203         267 : OFile& OFile::printField(const std::string&name,unsigned v) {
     204             :   std::snprintf(buffer_string.data(),buffer_string.size()," %u",v);
     205         267 :   printField(name,buffer_string.data());
     206         267 :   return *this;
     207             : }
     208             : 
     209           1 : OFile& OFile::printField(const std::string&name,long unsigned v) {
     210             :   std::snprintf(buffer_string.data(),buffer_string.size()," %lu",v);
     211           1 :   printField(name,buffer_string.data());
     212           1 :   return *this;
     213             : }
     214             : 
     215         137 : OFile& OFile::printField(const std::string&name,long long unsigned v) {
     216             :   std::snprintf(buffer_string.data(),buffer_string.size()," %llu",v);
     217         137 :   printField(name,buffer_string.data());
     218         137 :   return *this;
     219             : }
     220             : 
     221    41621072 : OFile& OFile::printField(const std::string&name,const std::string & v) {
     222             :   unsigned i;
     223   211977882 :   for(i=0; i<const_fields.size(); i++)
     224   192776950 :     if(const_fields[i].name==name) {
     225             :       break;
     226             :     }
     227    41621072 :   if(i>=const_fields.size()) {
     228             :     Field field;
     229             :     field.name=name;
     230             :     field.value=v;
     231    19200932 :     fields.push_back(field);
     232             :   } else {
     233    22420140 :     if(const_fields[i].value!=v) {
     234       30774 :       fieldChanged=true;
     235             :     }
     236             :     const_fields[i].value=v;
     237             :   }
     238    41621072 :   return *this;
     239             : }
     240             : 
     241        9038 : OFile& OFile::setupPrintValue( Value *val ) {
     242        9038 :   if( val->isPeriodic() ) {
     243         869 :     addConstantField("min_" + val->getName() );
     244        1738 :     addConstantField("max_" + val->getName() );
     245             :   }
     246        9038 :   return *this;
     247             : }
     248             : 
     249       55084 : OFile& OFile::printField( Value* val, const double& v ) {
     250       55084 :   printField( val->getName(), v );
     251       55084 :   if( val->isPeriodic() ) {
     252             :     std::string min, max;
     253       14804 :     val->getDomain( min, max );
     254       14804 :     printField( "min_" + val->getName(), min );
     255       29608 :     printField("max_" + val->getName(), max );
     256             :   }
     257       55084 :   return *this;
     258             : }
     259             : 
     260     4190129 : OFile& OFile::printField() {
     261             :   bool reprint=false;
     262     4190129 :   if(fieldChanged || fields.size()!=previous_fields.size()) {
     263             :     reprint=true;
     264             :   } else
     265    22707555 :     for(unsigned i=0; i<fields.size(); i++) {
     266    18524927 :       if( previous_fields[i].name!=fields[i].name ||
     267    18524925 :           (fields[i].constant && fields[i].value!=previous_fields[i].value) ) {
     268             :         reprint=true;
     269             :         break;
     270             :       }
     271             :     }
     272     4190129 :   if(reprint) {
     273        7501 :     printf("#! FIELDS");
     274      683510 :     for(unsigned i=0; i<fields.size(); i++) {
     275      676009 :       printf(" %s",fields[i].name.c_str());
     276             :     }
     277        7501 :     printf("\n");
     278       38069 :     for(unsigned i=0; i<const_fields.size(); i++) {
     279       30568 :       printf("#! SET %s %s",const_fields[i].name.c_str(),const_fields[i].value.c_str());
     280       30568 :       printf("\n");
     281             :     }
     282             :   }
     283    23391061 :   for(unsigned i=0; i<fields.size(); i++) {
     284    19200932 :     printf("%s",fields[i].value.c_str());
     285             :   }
     286     4190129 :   printf("\n");
     287     4190129 :   previous_fields=fields;
     288     4190129 :   fields.clear();
     289     4190129 :   fieldChanged=false;
     290     4190129 :   return *this;
     291             : }
     292             : 
     293         234 : void OFile::setBackupString( const std::string& str ) {
     294         234 :   backstring=str;
     295         234 : }
     296             : 
     297           0 : void OFile::backupAllFiles( const std::string& str ) {
     298           0 :   if(str=="/dev/null") {
     299           0 :     return;
     300             :   }
     301           0 :   plumed_assert( backstring!="bck" && !checkRestart());
     302           0 :   size_t found=str.find_last_of("/\\");
     303           0 :   std::string filename = appendSuffix(str,getSuffix());
     304           0 :   std::string directory=filename.substr(0,found+1);
     305           0 :   std::string file=filename.substr(found+1);
     306           0 :   if( FileExist(filename) ) {
     307           0 :     backupFile("bck", filename);
     308             :   }
     309           0 :   for(int i=0;; i++) {
     310             :     std::string num;
     311           0 :     Tools::convert(i,num);
     312           0 :     std::string filestr = directory + backstring + "." + num + "." + file;
     313           0 :     if( !FileExist(filestr) ) {
     314             :       break;
     315             :     }
     316           0 :     backupFile( "bck", filestr);
     317           0 :   }
     318             : }
     319             : 
     320        4673 : void OFile::backupFile( const std::string& bstring, const std::string& fname ) {
     321        4673 :   if(fname=="/dev/null") {
     322         271 :     return;
     323             :   }
     324        4402 :   int maxbackup=100;
     325        4402 :   if(std::getenv("PLUMED_MAXBACKUP")) {
     326          78 :     Tools::convert(std::getenv("PLUMED_MAXBACKUP"),maxbackup);
     327             :   }
     328        4402 :   if(maxbackup>0 && (!comm || comm->Get_rank()==0)) {
     329        3712 :     FILE* ff=std::fopen(const_cast<char*>(fname.c_str()),"r");
     330        3712 :     if(ff) {
     331             :       // no exception here
     332         150 :       std::fclose(ff);
     333             :       std::string backup;
     334         150 :       size_t found=fname.find_last_of("/\\");
     335         150 :       std::string directory=fname.substr(0,found+1);
     336         150 :       std::string file=fname.substr(found+1);
     337         150 :       for(int i=0;; i++) {
     338             :         std::string num;
     339         224 :         Tools::convert(i,num);
     340         224 :         if(i>maxbackup) {
     341           0 :           plumed_merror("cannot backup file "+file+" maximum number of backup is "+num+"\n");
     342             :         }
     343         896 :         backup=directory+bstring +"."+num+"."+file;
     344         224 :         FILE* fff=std::fopen(backup.c_str(),"r");
     345             :         // no exception here
     346         224 :         if(!fff) {
     347             :           break;
     348             :         } else {
     349          74 :           std::fclose(fff);
     350             :         }
     351          74 :       }
     352         150 :       int check=rename(fname.c_str(),backup.c_str());
     353         150 :       plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+std::strerror(errno));
     354             :     }
     355             :   }
     356             : }
     357             : 
     358        5292 : OFile& OFile::open(const std::string&setpath) {
     359        5292 :   plumed_assert(!cloned);
     360        5292 :   eof=false;
     361        5292 :   err=false;
     362        5292 :   fp=NULL;
     363        5292 :   gzfp=NULL;
     364        5292 :   path=setpath;
     365        5292 :   path=appendSuffix(setpath,getSuffix());
     366             :   // this must be done before backing up the file, otherwise
     367             :   // the backup would rename the file that is being written by another OFile
     368        5292 :   checkNotOpenElsewhere();
     369             :   // Only the writer opens the file (the other processes open /dev/null):
     370             :   // with many processes on a parallel file system, opening (and truncating)
     371             :   // the same file from all of them is slow.
     372        5281 :   if(checkRestart()) {
     373         619 :     openOnWriter("a","a9");
     374         619 :     mode="a";
     375             :   } else {
     376        4662 :     backupFile( backstring, path );
     377        4662 :     if(comm) {
     378        4599 :       comm->Barrier();
     379             :     }
     380        4662 :     openOnWriter("w","w9");
     381        4662 :     mode="w";
     382             :   }
     383        5281 :   syncOpen();
     384        5281 :   if(plumed) {
     385        4858 :     plumed->insertFile(*this);
     386             :   }
     387        5281 :   return *this;
     388             : }
     389             : 
     390        5292 : void OFile::checkNotOpenElsewhere()const {
     391        5292 :   if(!plumed) {
     392         728 :     return;
     393             :   }
     394        4869 :   if(path=="/dev/null") {
     395             :     return;
     396             :   }
     397             :   // The files are compared on the writer only: the other processes have the null device
     398             :   // as file pointer (see openOnWriter), and the files could be different if paths
     399             :   // are local to nodes. The verdict is then broadcast, so that all processes
     400             :   // stop with the same error (if only the writer stopped, the others would hang).
     401        3921 :   const auto findDuplicate=[&]() {
     402             :     std::string msg;
     403             :     struct stat st;
     404        3921 :     const bool exists=(stat(path.c_str(),&st)==0);
     405             :     // sharing devices, pipes, etc is legitimate
     406             :     // (S_ISREG is not defined by MSVC, so the file type is tested explicitly)
     407        3921 :     if(exists && (st.st_mode & S_IFMT)!=S_IFREG) {
     408             :       return std::string();
     409             :     }
     410       14749 :     for(const auto & f : plumed->getFiles()) {
     411       10836 :       const auto other=dynamic_cast<const OFile*>(f);
     412             :       // input files are ignored: reading a file while writing it is allowed (e.g. METAD restart)
     413       10836 :       if(!other || other==this || !other->fp) {
     414        4891 :         continue;
     415             :       }
     416        5945 :       bool same=(other->path==path);
     417             : #ifndef _WIN32
     418             :       // On Windows st_ino is always zero, so two different files on the same drive
     419             :       // would look the same: there only the paths are compared
     420        5945 :       if(!same && exists) {
     421             :         // catch the same file accessed with a different path (e.g. ./FILE, absolute paths, or links)
     422             :         struct stat ost;
     423         420 :         if(fstat(fileno(other->fp),&ost)==0) {
     424         420 :           same=(ost.st_dev==st.st_dev && ost.st_ino==st.st_ino);
     425             :         }
     426             :       }
     427             : #endif
     428        5525 :       if(same) {
     429          16 :         msg="file " + path + " is already open for writing";
     430           8 :         if(other->action) {
     431          24 :           msg+=" by action " + other->action->getLabel() + " (" + other->action->getName() + ")";
     432             :         }
     433           8 :         if(action) {
     434          24 :           msg+=" and cannot be opened again by action " + action->getLabel() + " (" + action->getName() + ")";
     435             :         }
     436             :         msg+=". Writing the same file twice would result in a corrupted file. Please use a different file name";
     437             :         break;
     438             :       }
     439             :     }
     440        3921 :     return msg;
     441        4564 :   };
     442             :   std::string msg;
     443        4564 :   if(isWriter()) {
     444        7842 :     msg=findDuplicate();
     445             :   }
     446        4564 :   if(comm) {
     447        4564 :     unsigned len=msg.length();
     448        4564 :     comm->Bcast(len,0);
     449        4575 :     std::vector<char> chars(msg.begin(),msg.end());
     450        4564 :     chars.resize(len);
     451        4564 :     if(len>0) {
     452          11 :       comm->Bcast(chars,0);
     453             :     }
     454        4564 :     msg.assign(chars.begin(),chars.end());
     455        4564 :   }
     456        4564 :   if(!msg.empty()) {
     457          22 :     plumed_merror(msg);
     458             :   }
     459             : }
     460             : 
     461       14844 : bool OFile::isWriter()const {
     462       14844 :   return !comm || comm->Get_rank()==0;
     463             : }
     464             : 
     465       10280 : void OFile::openOnWriter(const char* fmode,const char* gzmode,bool reopenFp) {
     466             : #ifdef _WIN32
     467             :   constexpr const char* nullDevice="NUL";
     468             : #else
     469             :   constexpr const char* nullDevice="/dev/null";
     470             : #endif
     471       10280 :   const char* p=isWriter() ? path.c_str() : nullDevice;
     472       10280 :   if(reopenFp) {
     473       10256 :     fp=std::fopen(p,fmode);
     474             :   }
     475       10280 :   if(Tools::extension(path)=="gz") {
     476             : #ifdef __PLUMED_HAS_ZLIB
     477          50 :     gzfp=(void*)gzopen(p,gzmode);
     478             : #else
     479             :     (void) gzmode;
     480             :     plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
     481             : #endif
     482             :   }
     483       10280 : }
     484             : 
     485        5854 : void OFile::syncOpen() {
     486        5854 :   if(!comm) {
     487          64 :     return;
     488             :   }
     489        5790 :   int ok=(fp!=NULL);
     490        5790 :   comm->Bcast(ok,0);
     491        5790 :   if(!ok && fp) {
     492             :     // the writer could not open the file: behave as if no process could
     493           0 :     std::fclose(fp);
     494           0 :     fp=NULL;
     495             : #ifdef __PLUMED_HAS_ZLIB
     496           0 :     if(gzfp) {
     497           0 :       gzclose(gzFile(gzfp));
     498             :     }
     499             : #endif
     500           0 :     gzfp=NULL;
     501             :   }
     502             : }
     503             : 
     504         573 : OFile& OFile::rewind() {
     505             : // we use here "hard" rewind, which means close/reopen
     506             : // the reason is that normal rewind does not work when in append mode
     507             : // moreover, we can take a backup of the file
     508         573 :   plumed_assert(fp);
     509         573 :   clearFields();
     510             : 
     511         573 :   if(!comm || comm->Get_rank()==0) {
     512         406 :     std::string fname=this->path;
     513         406 :     size_t found=fname.find_last_of("/\\");
     514         406 :     std::string directory=fname.substr(0,found+1);
     515         406 :     std::string file=fname.substr(found+1);
     516        1218 :     std::string backup=directory+backstring +".last."+file;
     517         406 :     int check=rename(fname.c_str(),backup.c_str());
     518         406 :     plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+std::strerror(errno));
     519             :   }
     520             : 
     521         573 :   if(comm) {
     522         573 :     comm->Barrier();
     523             :   }
     524             : 
     525         573 :   if(gzfp) {
     526             : #ifdef __PLUMED_HAS_ZLIB
     527          15 :     gzclose((gzFile)gzfp);
     528             :     // no exception here
     529          15 :     openOnWriter("w","w9",false);
     530             : #endif
     531             :   } else {
     532         558 :     std::fclose(fp);
     533             :     // no exception here
     534         558 :     openOnWriter("w","w9");
     535             :   }
     536             :   // see OFile::open
     537         573 :   syncOpen();
     538         573 :   return *this;
     539             : }
     540             : 
     541       14564 : FileBase& OFile::flush() {
     542       14564 :   if(heavyFlush) {
     543        4426 :     if(gzfp) {
     544             : #ifdef __PLUMED_HAS_ZLIB
     545           9 :       gzclose(gzFile(gzfp));
     546             :       // no exception here
     547           9 :       openOnWriter("a","a",false);
     548             : #endif
     549             :     } else {
     550        4417 :       std::fclose(fp);
     551             :       // no exception here
     552        4417 :       openOnWriter("a","a");
     553             :     }
     554             :   } else {
     555       10138 :     FileBase::flush();
     556             :     // if(gzfp) gzflush(gzFile(gzfp),Z_FINISH);
     557             :     // for some reason flushing with Z_FINISH has problems on linux
     558             :     // I thus use this (incomplete) flush
     559             : #ifdef __PLUMED_HAS_ZLIB
     560       10138 :     if(gzfp) {
     561          31 :       gzflush(gzFile(gzfp),Z_FULL_FLUSH);
     562             :     }
     563             : #endif
     564             :   }
     565       14564 :   return *this;
     566             : }
     567             : 
     568        5281 : bool OFile::checkRestart()const {
     569        5281 :   if(enforceRestart_) {
     570             :     return true;
     571        5270 :   } else if(enforceBackup_) {
     572             :     return false;
     573        4125 :   } else if(action) {
     574        3703 :     return action->getRestart();
     575         422 :   } else if(plumed) {
     576           0 :     return plumed->getRestart();
     577             :   } else {
     578             :     return false;
     579             :   }
     580             : }
     581             : 
     582          11 : OFile& OFile::enforceRestart() {
     583          11 :   enforceRestart_=true;
     584          11 :   enforceBackup_=false;
     585          11 :   return *this;
     586             : }
     587             : 
     588        1145 : OFile& OFile::enforceBackup() {
     589        1145 :   enforceBackup_=true;
     590        1145 :   enforceRestart_=false;
     591        1145 :   return *this;
     592             : }
     593             : 
     594             : 
     595             : }

Generated by: LCOV version 1.16