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 : #ifndef __PLUMED_tools_OFile_h
23 : #define __PLUMED_tools_OFile_h
24 :
25 : #include "FileBase.h"
26 : #include <vector>
27 : #include <sstream>
28 : #include <memory>
29 : #include <cstddef>
30 :
31 : namespace PLMD {
32 :
33 : class Value;
34 :
35 : /**
36 : \ingroup TOOLBOX
37 : Class for output files
38 :
39 : This class provides features similar to those in the standard C "FILE*" type,
40 : but only for sequential output. See IFile for sequential input.
41 :
42 : See the example here for a possible use:
43 : \verbatim
44 : #include "File.h"
45 :
46 : int main(){
47 : PLMD::OFile pof;
48 : pof.open("ciao");
49 : pof.printf("%s\n","test1");
50 : pof.setLinePrefix("plumed: ");
51 : pof.printf("%s\n","test2");
52 : pof.setLinePrefix("");
53 : pof.addConstantField("x2").printField("x2",67.0);
54 : pof.printField("x1",10.0).printField("x3",20.12345678901234567890).printField();
55 : pof.printField("x1",10.0).printField("x3",-1e70*20.12345678901234567890).printField();
56 : pof.printField("x3",10.0).printField("x2",777.0).printField("x1",-1e70*20.12345678901234567890).printField();
57 : pof.printField("x3",67.0).printField("x1",18.0).printField();
58 : return 0;
59 : }
60 : \endverbatim
61 :
62 : This program is expected to produce a file "ciao" which reads
63 : \verbatim
64 : test1
65 : plumed: test2
66 : #! FIELDS x1 x3
67 : #! SET x2 67
68 : 10 20.12345678901234
69 : 10 -2.012345678901235e+71
70 : #! FIELDS x1 x3
71 : #! SET x2 777
72 : -2.012345678901235e+71 10
73 : 18 67
74 : \endverbatim
75 :
76 : Notes
77 : - "x2" is declared as "constant", which means that it is written using the "SET"
78 : keyword. Thus, everytime it is modified, all the headers are repeated in the output file.
79 : - printField() without arguments is used as a "newline".
80 : - most methods return a reference to the OFile itself, to allow chaining many calls on the same line
81 : (this is similar to << operator in std::ostream)
82 :
83 : \section using-correctly-ofile Using correctly OFile in PLUMED
84 :
85 : When a OFile object is used in PLUMED it can be convenient to link() it
86 : to the Action object where it is defined, or to the PlumedMain object.
87 : This will save in the OFile a pointer to the linked object and will
88 : allow to have some extra information. E.g., if PLUMED is restarting,
89 : files will be appended. Notice that one can enforce this behavior using
90 : the enforceRestart() method before opening a file.
91 :
92 : To have all files managed consistently, it is important to use OFile in the proper way.
93 : This should allow multi-replica plumed, restart and backups to work in
94 : the expected way. For this reason all the operations in OFile and IFile
95 : are synchronizing all the processors of the group, so call to OFile functions
96 : should always be performed by all processes; for this reason is also not useful
97 : to use Log for debugging because only master threads will actually write.
98 : For debugging is better to use the standard stderr.
99 :
100 : \verbatim
101 : int main(){
102 : // this is a growing file, containing a full history
103 : // (frames are appended, as in traditional HILLS and COLVAR)
104 : OFile grw;
105 : // this is a single-snapshopt file used e.g. for checkpointing
106 : // (rewritten every time)
107 : OFile snp;
108 :
109 : // open both files at the beginning
110 : // (will go in \ref Action constructor)
111 : grw.open("growing");
112 : snp.open("snapshot");
113 :
114 : // trajectory loop
115 : for(int i=0;i<nsteps;i++){
116 :
117 : // files should be written in the update() method of an \ref Action
118 :
119 : // write on growing file
120 : grw<<"data at step "<<i<<\n";
121 :
122 : // flushing
123 : // it takes time, so do it only if data is critical
124 : // better to leave this choice to the user with the FLUSH keyword
125 : // grw.flush();
126 :
127 : // write on snapshot file
128 : snp.rewind();
129 : snp<<"snapshot at step "<<i<<"\n";
130 : snp.flush();
131 : // the only difference is that snp is rewound
132 : // notice that it should be rewound just before writing
133 : // because rewind is going to move the file out of the way
134 : // to have a safe copy of the file ("bck.last.filename")
135 : // Also notice that snapshots should be flushed
136 : // for this reason, it is better to write them only
137 : // rarely to avoid excessive slow down
138 :
139 : }
140 : }
141 :
142 : \notice
143 : Notice that it is not necessary to explicitly close files, since they are closed implicitly
144 : when the object goes out of scope. In case you need to explicitly close the file before it is
145 : destroyed, please check it the procedure is exception safe and, if necessary, add some `try/catch`
146 : statement.
147 :
148 : \endverbatim
149 : */
150 :
151 : class OFile:
152 : public virtual FileBase {
153 : /// Pointer to a linked OFile.
154 : /// see link(OFile&)
155 : OFile* linked;
156 : /// Internal buffer for printf
157 : std::vector<char> buffer_string;
158 : /// Internal buffer (generic use)
159 : std::vector<char> buffer;
160 : /// Internal buffer length
161 : int buflen;
162 : /// This variables stores the actual buffer length
163 : int actual_buffer_length;
164 : /// Class identifying a single field for fielded output
165 59134769 : class Field:
166 : public FieldBase {
167 : };
168 : /// Low-level write
169 : std::size_t llwrite(const char*,std::size_t);
170 : /// True if fields has changed.
171 : /// This could be due to a change in the list of fields or a reset
172 : /// of a nominally constant field
173 : bool fieldChanged;
174 : /// Format for fields writing
175 : std::string fieldFmt;
176 : /// All the previously defined variable fields
177 : std::vector<Field> previous_fields;
178 : /// All the defined variable fields
179 : std::vector<Field> fields;
180 : /// All the defined constant fields
181 : std::vector<Field> const_fields;
182 : /// Prefix for line (e.g. "PLUMED: ")
183 : std::string linePrefix;
184 : /// Temporary ostringstream for << output
185 : std::ostringstream oss;
186 : /// The string used for backing up files
187 : std::string backstring;
188 : /// Find field index given name
189 : unsigned findField(const std::string&name)const;
190 : /// check if we are restarting
191 : bool checkRestart()const;
192 : /// True if restart behavior should be forced
193 : bool enforceRestart_;
194 : /// True if backup behavior (i.e. non restart) should be forced
195 : bool enforceBackup_;
196 : /// Check that no other OFile linked to the same PlumedMain object
197 : /// is currently writing on the file this->path.
198 : /// Throws an exception if this is the case.
199 : void checkNotOpenElsewhere()const;
200 : /// True if this process writes the file: the first process of the communicator,
201 : /// or every process if there is no communicator
202 : bool isWriter()const;
203 : /// Open fp (and gzfp for gz files) with the given modes.
204 : /// Only the writer opens the file: the other processes open the null device (/dev/null, NUL on Windows),
205 : /// so that fp is valid on all processes but the file is opened (and truncated) only once.
206 : void openOnWriter(const char* fmode,const char* gzmode,bool reopenFp=true);
207 : /// After the writer opened the file: let all processes know whether it succeeded.
208 : /// This is also a synchronization point: the other processes continue
209 : /// only after the writer has opened (and created) the file.
210 : void syncOpen();
211 : public:
212 : /// Constructor
213 : OFile();
214 : /// Allows overloading of link
215 : using FileBase::link;
216 : /// Allows overloading of open
217 : using FileBase::open;
218 : /// Allows linking this OFile to another one.
219 : /// In this way, everything written to this OFile will be immediately
220 : /// written on the linked OFile. Notice that a OFile should
221 : /// be either opened explicitly, linked to a FILE or linked to a OFile
222 : OFile& link(OFile&);
223 : /// Set the string name to be used for automatic backup
224 : void setBackupString( const std::string& );
225 : /// Backup a file by giving it a different name
226 : void backupFile( const std::string& bstring, const std::string& fname );
227 : /// This backs up all the files that would have been created with the
228 : /// name str. It is used in analysis when you are not restarting. Analysis
229 : /// output files at different times, which are names analysis.0.<filename>,
230 : /// analysis.1.<filename> and <filename>, are backed up to bck.0.analysis.0.<filename>,
231 : /// bck.0.analysis.1.<filename> and bck.0.<filename>
232 : void backupAllFiles( const std::string& str );
233 : /// Opens the file using automatic append/backup
234 : OFile& open(const std::string&name) override;
235 : /// Set the prefix for output.
236 : /// Typically "PLUMED: ". Notice that lines with a prefix cannot
237 : /// be parsed using fields in a IFile.
238 : OFile& setLinePrefix(const std::string&);
239 : /// Set the format for writing double precision fields
240 : OFile& fmtField(const std::string&);
241 : /// Reset the format for writing double precision fields to its default
242 : OFile& fmtField();
243 : /// Set the value of a double precision field
244 : OFile& printField(const std::string&,double);
245 : /// Set the value of a int type field
246 : OFile& printField(const std::string&,int);
247 : OFile& printField(const std::string&,long int);
248 : OFile& printField(const std::string&,long long int);
249 : OFile& printField(const std::string&,unsigned);
250 : OFile& printField(const std::string&,long unsigned);
251 : OFile& printField(const std::string&,long long unsigned);
252 : /// Set the value of a string field
253 : OFile& printField(const std::string&,const std::string&);
254 : ///
255 : OFile& addConstantField(const std::string&);
256 : /// Used to setup printing of values
257 : OFile& setupPrintValue( Value *val );
258 : /// Print a value
259 : OFile& printField( Value* val, const double& v );
260 : /** Close a line.
261 : Typically used as
262 : \verbatim
263 : of.printField("a",a).printField("b",b).printField();
264 : \endverbatim
265 : */
266 : OFile& printField();
267 : /**
268 : Resets the list of fields.
269 : As it is only possible to add new constant fields (addConstantField()),
270 : this method can be used to clean the field list.
271 : */
272 : OFile& clearFields();
273 : /// Formatted output with explicit format - a la printf
274 : int printf(const char*fmt,...);
275 : /// Formatted output with << operator
276 : template <class T>
277 : friend OFile& operator<<(OFile&,const T &);
278 : /// Rewind a file
279 : OFile&rewind();
280 : /// Flush a file
281 : FileBase&flush() override;
282 : /// Enforce restart, also if the attached plumed object is not restarting.
283 : /// Useful for tests
284 : OFile&enforceRestart();
285 : /// Enforce backup, even if the attached plumed object is restarting.
286 : OFile&enforceBackup();
287 : };
288 :
289 : /// Write using << syntax
290 : template <class T>
291 1867371 : OFile& operator<<(OFile&of,const T &t) {
292 1867371 : of.oss<<t;
293 1867371 : of.printf("%s",of.oss.str().c_str());
294 1867371 : of.oss.str("");
295 1867371 : return of;
296 : }
297 :
298 :
299 : }
300 :
301 : #endif
|