Newer
Older
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
(see the PEOPLE file at the root of the distribution for a list of names)
plumed is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
plumed is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with plumed. If not, see <http://www.gnu.org/licenses/>.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
#include "core/Action.h"
#include "core/PlumedMain.h"
#include "core/Value.h"
#include "Communicator.h"
#include "Tools.h"
#include <cstdarg>
#include <cstring>
#include <iostream>
#include <string>
#ifdef __PLUMED_HAS_ZLIB
#include <zlib.h>
#endif
size_t OFile::llwrite(const char*ptr,size_t s) {
size_t r;
if(linked) return linked->llwrite(ptr,s);
if(!fp) plumed_merror("writing on uninitilized File");
#ifdef __PLUMED_HAS_ZLIB
r=gzwrite(gzFile(gzfp),ptr,s);
#else
plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
// This barrier is apparently useless since it comes
// just before a Bcast.
// Anyway, it looks like it is solving an issue that appeared on
// TRAVIS (at least on my laptop) so I add it here.
// GB
if(comm) comm->Barrier();
if(comm) comm->Bcast(r,0);
return r;
}
OFile::OFile():
linked(NULL),
enforceRestart_(false),
enforceBackup_(false)
buffer=new char[buflen];
// these are set to zero to avoid valgrind errors
buffer_string=new char [1000];
// these are set to zero to avoid valgrind errors
for(unsigned i=0; i<1000; ++i) buffer_string[i]=0;
delete [] buffer_string;
delete [] buffer;
}
linked=&l;
return *this;
}
OFile& OFile::setLinePrefix(const std::string&l) {
linePrefix=l;
return *this;
}
va_list arg;
va_start(arg, fmt);
int r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
char* newbuf=new char [newlen];
memmove(newbuf,buffer,buflen);
for(int k=buflen; k<newlen; k++) newbuf[k]=0;
delete [] buffer;
buffer=newbuf;
buflen=newlen;
va_list arg;
va_start(arg, fmt);
r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
plumed_massert(r>-1 && r<buflen-actual_buffer_length,"error using fmt string " + std::string(fmt));
// Line is buffered until newline, then written with a PLUMED: prefix
char*p1=buffer;
char*p2;
// newline is only searched in the just added portion:
char*psearch=p1+actual_buffer_length;
actual_buffer_length+=r;
if(linePrefix.length()>0) llwrite(linePrefix.c_str(),linePrefix.length());
llwrite(p1,p2-p1+1);
actual_buffer_length-=(p2-p1)+1;
if(buffer!=p1) memmove(buffer,p1,actual_buffer_length);
OFile& OFile::addConstantField(const std::string&name) {
Field f;
f.name=name;
const_fields.push_back(f);
return *this;
}
fields.clear();
const_fields.clear();
previous_fields.clear();
return *this;
}
OFile& OFile::fmtField(const std::string&fmt) {
this->fieldFmt=fmt;
return *this;
}
this->fieldFmt="%23.16lg";
return *this;
}
OFile& OFile::printField(const std::string&name,double v) {
sprintf(buffer_string,fieldFmt.c_str(),v);
printField(name,buffer_string);
return *this;
}
OFile& OFile::printField(const std::string&name,int v) {
sprintf(buffer_string," %d",v);
printField(name,buffer_string);
return *this;
}
OFile& OFile::printField(const std::string&name,const std::string & v) {
for(i=0; i<const_fields.size(); i++) if(const_fields[i].name==name) break;
if(i>=const_fields.size()) {
Field field;
field.name=name;
field.value=v;
fields.push_back(field);
} else {
if(const_fields[i].value!=v) fieldChanged=true;
const_fields[i].value=v;
}
return *this;
}
OFile& OFile::setupPrintValue( Value *val ) {
if( val->isPeriodic() ) {
addConstantField("min_" + val->getName() );
addConstantField("max_" + val->getName() );
OFile& OFile::printField( Value* val, const double& v ) {
printField( val->getName(), v );
if( val->isPeriodic() ) {
std::string min, max; val->getDomain( min, max );
printField( "min_" + val->getName(), min );
printField("max_" + val->getName(), max );
}
if(fieldChanged || fields.size()!=previous_fields.size()) {
} else for(unsigned i=0; i<fields.size(); i++) {
if( previous_fields[i].name!=fields[i].name ||
(fields[i].constant && fields[i].value!=previous_fields[i].value) ) {
reprint=true;
break;
}
for(unsigned i=0; i<fields.size(); i++) printf(" %s",fields[i].name.c_str());
for(unsigned i=0; i<const_fields.size(); i++) {
printf("#! SET %s %s",const_fields[i].name.c_str(),const_fields[i].value.c_str());
printf("\n");
for(unsigned i=0; i<fields.size(); i++) printf("%s",fields[i].value.c_str());
printf("\n");
previous_fields=fields;
fields.clear();
fieldChanged=false;
return *this;
}
void OFile::setBackupString( const std::string& str ) {
void OFile::backupAllFiles( const std::string& str ) {
plumed_assert( backstring!="bck" && !checkRestart());
size_t found=str.find_last_of("/\\");
std::string filename = appendSuffix(str,getSuffix());
std::string directory=filename.substr(0,found+1);
std::string file=filename.substr(found+1);
if( FileExist(filename) ) backupFile("bck", filename);
for(int i=0;; i++) {
std::string num; Tools::convert(i,num);
std::string filestr = directory + backstring + "." + num + "." + file;
if( !FileExist(filestr) ) break;
backupFile( "bck", filestr);
void OFile::backupFile( const std::string& bstring, const std::string& fname ) {
if(fname=="/dev/null") return;
int maxbackup=100;
if(std::getenv("PLUMED_MAXBACKUP")) Tools::convert(std::getenv("PLUMED_MAXBACKUP"),maxbackup);
if(maxbackup>0 && (!comm || comm->Get_rank()==0)) {
FILE* ff=std::fopen(const_cast<char*>(fname.c_str()),"r");
if(ff) {
std::fclose(ff);
std::string backup;
size_t found=fname.find_last_of("/\\");
std::string directory=fname.substr(0,found+1);
std::string file=fname.substr(found+1);
for(int i=0;; i++) {
std::string num;
Tools::convert(i,num);
if(i>maxbackup) plumed_merror("cannot backup file "+file+" maximum number of backup is "+num+"\n");
backup=directory+bstring +"."+num+"."+file;
FILE* fff=std::fopen(backup.c_str(),"r");
if(!fff) break;
else std::fclose(fff);
}
int check=rename(fname.c_str(),backup.c_str());
plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno));
}
}
OFile& OFile::open(const std::string&path) {
plumed_assert(!cloned);
eof=false;
err=false;
fp=NULL;
if(checkRestart()) {
fp=std::fopen(const_cast<char*>(this->path.c_str()),"a");
mode="a";
if(Tools::extension(this->path)=="gz") {
gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"a9");
plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
backupFile( backstring, this->path );
if(comm)comm->Barrier();
fp=std::fopen(const_cast<char*>(this->path.c_str()),"w");
mode="w";
if(Tools::extension(this->path)=="gz") {
gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"w9");
plumed_merror("file " + getPath() + ": trying to use a gz file without zlib being linked");
}
if(plumed) plumed->insertFile(*this);
return *this;
}
// we use here "hard" rewind, which means close/reopen
// the reason is that normal rewind does not work when in append mode
// moreover, we can take a backup of the file
#ifdef __PLUMED_HAS_ZLIB
gzclose((gzFile)gzfp);
#endif
std::string fname=this->path;
size_t found=fname.find_last_of("/\\");
std::string directory=fname.substr(0,found+1);
std::string file=fname.substr(found+1);
std::string backup=directory+backstring +".last."+file;
int check=rename(fname.c_str(),backup.c_str());
plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno));
if(comm) comm->Barrier();
#ifdef __PLUMED_HAS_ZLIB
gzfp=(void*)gzopen(const_cast<char*>(this->path.c_str()),"w9");
#endif
} else fp=std::fopen(const_cast<char*>(path.c_str()),"w");
FileBase& OFile::flush() {
if(heavyFlush) {
if(gzfp) {
#ifdef __PLUMED_HAS_ZLIB
gzclose(gzFile(gzfp));
gzfp=(void*)gzopen(const_cast<char*>(path.c_str()),"a");
#endif
fclose(fp);
fp=std::fopen(const_cast<char*>(path.c_str()),"a");
}
} else {
FileBase::flush();
// if(gzfp) gzflush(gzFile(gzfp),Z_FINISH);
// for some reason flushing with Z_FINISH has problems on linux
// I thus use this (incomplete) flush
#ifdef __PLUMED_HAS_ZLIB
if(gzfp) gzflush(gzFile(gzfp),Z_FULL_FLUSH);
#endif
}
else if(enforceBackup_) return false;
else if(action) return action->getRestart();
else if(plumed) return plumed->getRestart();
enforceRestart_=true;
enforceBackup_=false;
return *this;
}
enforceBackup_=true;
enforceRestart_=false;
return *this;