All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
OFile.cpp
Go to the documentation of this file.
1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2  Copyright (c) 2013 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-code.org for more information.
6 
7  This file is part of plumed, version 2.0.
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 "File.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 namespace PLMD{
38 
39 size_t OFile::llwrite(const char*ptr,size_t s){
40  size_t r;
41  if(linked) return linked->llwrite(ptr,s);
42  if(! (comm && comm->Get_rank()>0)){
43  if(!fp) plumed_merror("writing on uninitilized File");
44  r=fwrite(ptr,1,s,fp);
45  }
46  if(comm) comm->Bcast(&r,1,0);
47  return r;
48 }
49 
51  linked(NULL),
52  fieldChanged(false),
53  backstring("bck")
54 {
55  fmtField();
56  buflen=1;
58  buffer=new char[buflen];
59 // these are set to zero to avoid valgrind errors
60  for(unsigned i=0;i<buflen;++i) buffer[i]=0;
61  buffer_string=new char [1000];
62 // these are set to zero to avoid valgrind errors
63  for(unsigned i=0;i<1000;++i) buffer_string[i]=0;
64 }
65 
67  delete [] buffer_string;
68  delete [] buffer;
69 }
70 
72  fp=NULL;
73  linked=&l;
74  return *this;
75 }
76 
77 OFile& OFile::setLinePrefix(const std::string&l){
78  linePrefix=l;
79  return *this;
80 }
81 
82 int OFile::printf(const char*fmt,...){
83  va_list arg;
84  va_start(arg, fmt);
85  int r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
86  va_end(arg);
87  if(r>=buflen-actual_buffer_length){
88  int newlen=buflen;
89  while(newlen<=r+actual_buffer_length) newlen*=2;
90  char* newbuf=new char [newlen];
91  memmove(newbuf,buffer,buflen);
92  for(int k=buflen;k<newlen;k++) newbuf[k]=0;
93  delete [] buffer;
94  buffer=newbuf;
95  buflen=newlen;
96  va_list arg;
97  va_start(arg, fmt);
98  r=std::vsnprintf(&buffer[actual_buffer_length],buflen-actual_buffer_length,fmt,arg);
99  va_end(arg);
100  }
101  plumed_massert(r>-1 && r<buflen-actual_buffer_length,"error using fmt string " + std::string(fmt));
102 
103 // Line is buffered until newline, then written with a PLUMED: prefix
104  char*p1=buffer;
105  char*p2;
106 // newline is only searched in the just added portion:
107  char*psearch=p1+actual_buffer_length;
108  actual_buffer_length+=r;
109  while((p2=strchr(psearch,'\n'))){
110  if(linePrefix.length()>0) llwrite(linePrefix.c_str(),linePrefix.length());
111  llwrite(p1,p2-p1+1);
112  actual_buffer_length-=(p2-p1)+1;
113  p1=p2+1;
114  psearch=p1;
115  };
116  if(buffer!=p1) memmove(buffer,p1,actual_buffer_length);
117  return r;
118 }
119 
120 OFile& OFile::addConstantField(const std::string&name){
121  Field f;
122  f.name=name;
123  const_fields.push_back(f);
124  return *this;
125 }
126 
127 
129  fields.clear();
130  const_fields.clear();
131  previous_fields.clear();
132  return *this;
133 }
134 
135 OFile& OFile::fmtField(const std::string&fmt){
136  this->fieldFmt=fmt;
137  return *this;
138 }
139 
141  this->fieldFmt="%23.16lg";
142  return *this;
143 }
144 
145 OFile& OFile::printField(const std::string&name,double v){
146  sprintf(buffer_string,fieldFmt.c_str(),v);
148  return *this;
149 }
150 
151 OFile& OFile::printField(const std::string&name,int v){
152  sprintf(buffer_string," %d",v);
154  return *this;
155 }
156 
157 OFile& OFile::printField(const std::string&name,const std::string & v){
158  unsigned i;
159  for(i=0;i<const_fields.size();i++) if(const_fields[i].name==name) break;
160  if(i>=const_fields.size()){
161  Field field;
162  field.name=name;
163  field.value=v;
164  fields.push_back(field);
165  } else {
166  if(const_fields[i].value!=v) fieldChanged=true;
167  const_fields[i].value=v;
168  }
169  return *this;
170 }
171 
173  if( val->isPeriodic() ){
174  addConstantField("min_" + val->getName() );
175  addConstantField("max_" + val->getName() );
176  }
177  return *this;
178 }
179 
180 OFile& OFile::printField( Value* val, const double& v ){
181  printField( val->getName(), v );
182  if( val->isPeriodic() ){
183  std::string min, max; val->getDomain( min, max );
184  printField( "min_" + val->getName(), min );
185  printField("max_" + val->getName(), max );
186  }
187  return *this;
188 }
189 
191  bool reprint=false;
192  if(fieldChanged || fields.size()!=previous_fields.size()){
193  reprint=true;
194  } else for(unsigned i=0;i<fields.size();i++){
195  if( previous_fields[i].name!=fields[i].name ||
196  (fields[i].constant && fields[i].value!=previous_fields[i].value) ){
197  reprint=true;
198  break;
199  }
200  }
201  if(reprint){
202  printf("#! FIELDS");
203  for(unsigned i=0;i<fields.size();i++) printf(" %s",fields[i].name.c_str());
204  printf("\n");
205  for(unsigned i=0;i<const_fields.size();i++){
206  printf("#! SET %s %s",const_fields[i].name.c_str(),const_fields[i].value.c_str());
207  printf("\n");
208  }
209  }
210  for(unsigned i=0;i<fields.size();i++) printf("%s",fields[i].value.c_str());
211  printf("\n");
213  fields.clear();
214  fieldChanged=false;
215  return *this;
216 }
217 
218 void OFile::setBackupString( const std::string& str ){
219  backstring=str;
220 }
221 
222 void OFile::backupAllFiles( const std::string& str ){
223  plumed_assert( backstring!="bck" && plumed && !plumed->getRestart() );
224  size_t found=str.find_last_of("/\\");
225  std::string filename = str + plumed->getSuffix();
226  std::string directory=filename.substr(0,found+1);
227  std::string file=filename.substr(found+1);
228  if( FileExist(filename) ) backupFile("bck", filename);
229  for(int i=0;;i++){
230  std::string num; Tools::convert(i,num);
231  std::string filestr = directory + backstring + "." + num + "." + file;
232  if( !FileExist(filestr) ) break;
233  backupFile( "bck", filestr);
234  }
235 }
236 
237 void OFile::backupFile( const std::string& bstring, const std::string& fname ){
238  int maxbackup=100;
239  if(std::getenv("PLUMED_MAXBACKUP")) Tools::convert(std::getenv("PLUMED_MAXBACKUP"),maxbackup);
240  if(maxbackup>0 && (!comm || comm->Get_rank()==0)){
241  FILE* ff=std::fopen(const_cast<char*>(fname.c_str()),"r");
242  FILE* fff=NULL;
243  if(ff){
244  std::fclose(ff);
245  std::string backup;
246  size_t found=fname.find_last_of("/\\");
247  std::string directory=fname.substr(0,found+1);
248  std::string file=fname.substr(found+1);
249  for(int i=0;;i++){
250  std::string num;
251  Tools::convert(i,num);
252  if(i>maxbackup) plumed_merror("cannot backup file "+file+" maximum number of backup is "+num+"\n");
253  backup=directory+bstring +"."+num+"."+file;
254  fff=std::fopen(backup.c_str(),"r");
255  if(!fff) break;
256  else std::fclose(fff);
257  }
258  int check=rename(fname.c_str(),backup.c_str());
259  plumed_massert(check==0,"renaming "+fname+" into "+backup+" failed for reason: "+strerror(errno));
260  }
261  }
262 }
263 
264 OFile& OFile::open(const std::string&path){
265  plumed_assert(!cloned);
266  eof=false;
267  err=false;
268  fp=NULL;
269  this->path=path;
270  if(plumed){
271  this->path+=plumed->getSuffix();
272  }
273  if(plumed && plumed->getRestart()){
274  fp=std::fopen(const_cast<char*>(this->path.c_str()),"a");
275  } else {
276  backupFile( backstring, this->path );
277  if(comm)comm->Barrier();
278  fp=std::fopen(const_cast<char*>(this->path.c_str()),"w");
279  }
280  if(plumed) plumed->insertFile(*this);
281  return *this;
282 }
283 
285 // we use here "hard" rewind, which means close/reopen
286 // the reason is that normal rewind does not work when in append mode
287  plumed_assert(fp);
288  clearFields();
289  fclose(fp);
290  fp=std::fopen(const_cast<char*>(path.c_str()),"w");
291  return *this;
292 }
293 
294 }
295 
296 
std::string linePrefix
Prefix for line (e.g. "PLUMED: ")
Definition: OFile.h:116
const std::string & getName() const
Get the name of the quantity.
Definition: Value.h:196
std::string path
path of the opened file
Definition: FileBase.h:75
~OFile()
Destructor.
Definition: OFile.cpp:66
OFile & rewind()
Rewind a file.
Definition: OFile.cpp:284
std::string backstring
The string used for backing up files.
Definition: OFile.h:120
void backupAllFiles(const std::string &str)
This backs up all the files that would have been created with the name str.
Definition: OFile.cpp:222
Class identifying a single field for fielded output.
Definition: OFile.h:98
OFile & fmtField()
Reset the format for writing double precision fields to its default.
Definition: OFile.cpp:140
A class for holding the value of a function together with its derivatives.
Definition: Value.h:46
void Bcast(T *, int, int)
Definition: Communicator.h:134
static bool convert(const std::string &str, double &t)
Convert a string to a double, reading it.
Definition: Tools.cpp:74
char * buffer_string
Internal buffer for printf.
Definition: OFile.h:90
OFile & printField()
Close a line.
Definition: OFile.cpp:190
OFile & addConstantField(const std::string &)
Definition: OFile.cpp:120
std::vector< Field > previous_fields
All the previously defined variable fields.
Definition: OFile.h:110
void getDomain(std::string &, std::string &) const
Get the domain of the quantity.
Definition: Value.cpp:99
int Get_rank() const
Obtain the rank of the present process.
Communicator * comm
communicator. NULL if not set
Definition: FileBase.h:59
int buflen
Internal buffer length.
Definition: OFile.h:94
size_t llwrite(const char *, size_t)
Low-level write.
Definition: OFile.cpp:39
OFile & link(OFile &)
Allows linking this OFile to another one.
Definition: OFile.cpp:71
int printf(const char *fmt,...)
Formatted output with explicit format - a la printf.
Definition: OFile.cpp:82
bool eof
Set to true when end of file is encountered.
Definition: FileBase.h:71
std::string fieldFmt
Format for fields writing.
Definition: OFile.h:108
OFile()
Constructor.
Definition: OFile.cpp:50
bool cloned
Control closing on destructor.
Definition: FileBase.h:66
void backupFile(const std::string &bstring, const std::string &fname)
Backup a file by giving it a different name.
Definition: OFile.cpp:237
std::vector< Field > fields
All the defined variable fields.
Definition: OFile.h:112
FILE * fp
file pointer
Definition: FileBase.h:57
Class for output files.
Definition: OFile.h:84
bool FileExist(const std::string &path)
Check if the file exists.
Definition: FileBase.cpp:118
bool err
Set to true when error is encountered.
Definition: FileBase.h:73
Main plumed object.
Definition: Plumed.h:201
bool isPeriodic() const
Check if the value is periodic.
Definition: Value.cpp:75
void Barrier() const
Wrapper to MPI_Barrier.
OFile & clearFields()
Resets the list of fields.
Definition: OFile.cpp:128
unsigned actual_buffer_length
This variables stores the actual buffer length.
Definition: OFile.h:96
bool fieldChanged
True if fields has changed.
Definition: OFile.h:106
char * buffer
Internal buffer (generic use)
Definition: OFile.h:92
std::vector< Field > const_fields
All the defined constant fields.
Definition: OFile.h:114
void setBackupString(const std::string &)
Set the string name to be used for automatic backup.
Definition: OFile.cpp:218
OFile & setLinePrefix(const std::string &)
Set the prefix for output.
Definition: OFile.cpp:77
OFile & open(const std::string &name)
Opens the file using automatic append/backup.
Definition: OFile.cpp:264
OFile * linked
Pointer to a linked OFile.
Definition: OFile.h:88
OFile & setupPrintValue(Value *val)
Used to setup printing of values.
Definition: OFile.cpp:172