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 explicitely 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::unique_ptr<char[]> buffer_string;
158 : /// Internal buffer (generic use)
159 : std::unique_ptr<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 64909204 : 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 : public:
197 : /// Constructor
198 : OFile();
199 : /// Allows overloading of link
200 : using FileBase::link;
201 : /// Allows overloading of open
202 : using FileBase::open;
203 : /// Allows linking this OFile to another one.
204 : /// In this way, everything written to this OFile will be immediately
205 : /// written on the linked OFile. Notice that a OFile should
206 : /// be either opened explicitly, linked to a FILE or linked to a OFile
207 : OFile& link(OFile&);
208 : /// Set the string name to be used for automatic backup
209 : void setBackupString( const std::string& );
210 : /// Backup a file by giving it a different name
211 : void backupFile( const std::string& bstring, const std::string& fname );
212 : /// This backs up all the files that would have been created with the
213 : /// name str. It is used in analysis when you are not restarting. Analysis
214 : /// output files at different times, which are names analysis.0.<filename>,
215 : /// analysis.1.<filename> and <filename>, are backed up to bck.0.analysis.0.<filename>,
216 : /// bck.0.analysis.1.<filename> and bck.0.<filename>
217 : void backupAllFiles( const std::string& str );
218 : /// Opens the file using automatic append/backup
219 : OFile& open(const std::string&name) override;
220 : /// Set the prefix for output.
221 : /// Typically "PLUMED: ". Notice that lines with a prefix cannot
222 : /// be parsed using fields in a IFile.
223 : OFile& setLinePrefix(const std::string&);
224 : /// Set the format for writing double precision fields
225 : OFile& fmtField(const std::string&);
226 : /// Reset the format for writing double precision fields to its default
227 : OFile& fmtField();
228 : /// Set the value of a double precision field
229 : OFile& printField(const std::string&,double);
230 : /// Set the value of a int type field
231 : OFile& printField(const std::string&,int);
232 : OFile& printField(const std::string&,long int);
233 : OFile& printField(const std::string&,unsigned);
234 : OFile& printField(const std::string&,long unsigned);
235 : /// Set the value of a string field
236 : OFile& printField(const std::string&,const std::string&);
237 : ///
238 : OFile& addConstantField(const std::string&);
239 : /// Used to setup printing of values
240 : OFile& setupPrintValue( Value *val );
241 : /// Print a value
242 : OFile& printField( Value* val, const double& v );
243 : /** Close a line.
244 : Typically used as
245 : \verbatim
246 : of.printField("a",a).printField("b",b).printField();
247 : \endverbatim
248 : */
249 : OFile& printField();
250 : /**
251 : Resets the list of fields.
252 : As it is only possible to add new constant fields (addConstantField()),
253 : this method can be used to clean the field list.
254 : */
255 : OFile& clearFields();
256 : /// Formatted output with explicit format - a la printf
257 : int printf(const char*fmt,...);
258 : /// Formatted output with << operator
259 : template <class T>
260 : friend OFile& operator<<(OFile&,const T &);
261 : /// Rewind a file
262 : OFile&rewind();
263 : /// Flush a file
264 : FileBase&flush() override;
265 : /// Enforce restart, also if the attached plumed object is not restarting.
266 : /// Useful for tests
267 : OFile&enforceRestart();
268 : /// Enforce backup, even if the attached plumed object is restarting.
269 : OFile&enforceBackup();
270 : };
271 :
272 : /// Write using << syntax
273 : template <class T>
274 1161839 : OFile& operator<<(OFile&of,const T &t) {
275 1161839 : of.oss<<t;
276 1161839 : of.printf("%s",of.oss.str().c_str());
277 1161839 : of.oss.str("");
278 1161839 : return of;
279 : }
280 :
281 :
282 : }
283 :
284 : #endif
|