Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-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 "core/ActionPilot.h"
23 : #include "core/ActionWithArguments.h"
24 : #include "core/ActionRegister.h"
25 :
26 : namespace PLMD {
27 : namespace generic {
28 :
29 : //+PLUMEDOC PRINTANALYSIS PRINT
30 : /*
31 : Print quantities to a file.
32 :
33 : This command can be used to output quantities to a file. The following demonstrates a very
34 : simple example:
35 :
36 : ```plumed
37 : d: DISTANCE ATOMS=1,2
38 : PRINT ARG=d FILE=colvar
39 : ```
40 :
41 : This command outputs the distance between atom 1 and 2 to a file called colvar every step of
42 : trajectory. If you want to output the distance less frequently you can use the STRIDE keyword
43 : as illustrated below:
44 :
45 : ```plumed
46 : d: DISTANCE ATOMS=1,2
47 : PRINT ARG=d FILE=colvar STRIDE=10
48 : ```
49 :
50 : With the input above the distance is only output on every 10th step. Notice this distance will only
51 : be calculated on every step as this quantity is not used on every other step.
52 :
53 : You can also control the format of the numbers that are output by using the FMT keyword as shown below:
54 :
55 : ```plumed
56 : d: DISTANCE ATOMS=1,2
57 : PRINT ARG=d FILE=colvar FMT=%10.6f
58 : ```
59 :
60 : The FMT key takes a [C format specifiers](https://www.simplilearn.com/tutorials/c-tutorial/format-specifiers-in-c)
61 : in input, which is what determines the appearance of the numbers output.
62 :
63 : You can also use the PRINT command to output objects that have a rank that is greater than zero.
64 : For example, the following input calculates a vector of three distances. These three distances
65 : are then output to the output colvar file every step.
66 :
67 : ```plumed
68 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6
69 : PRINT ARG=d FILE=colvar
70 : ```
71 :
72 : Alterantively, we can output a matrix by using an input like the one shown below:
73 :
74 : ```plumed
75 : d: DISTANCE_MATRIX GROUP=1-4
76 : PRINT ARG=d FILE=colvar
77 : ```
78 :
79 : The output `colvar` file here will contain the 16 elements of the matrix on each line output. You can
80 : also use PRINT to output functions on grids. However, you are probably better using [DUMPGRID](DUMPGRID.md) or
81 : [DUMPCUBE](DUMPCUBE.md) to output functions on grids.
82 :
83 : The PRINT directive can be used multiple times in the input so you can print files with different strides or print different quantities
84 : to different files as illustrated in the example input below:
85 :
86 : ```plumed
87 : # compute distance:
88 : distance: DISTANCE ATOMS=2,5
89 : # compute total energy (potential)
90 : energy: ENERGY
91 : # print distance on a file
92 : PRINT ARG=distance STRIDE=10 FILE=COLVAR
93 : # print both variables on another file
94 : PRINT ARG=distance,energy STRIDE=1000 FILE=COLVAR_ALL
95 : ```
96 :
97 : The input above instructs plumed to print the distance between atoms 3 and 5 on a file
98 : called COLVAR every 10 steps, and the distance and total energy on a file called COLVAR_ALL
99 : every 1000 steps.
100 :
101 : You can control the buffering of output using the [FLUSH](FLUSH.md) keyword. Furthermore, whether the output file is
102 : appended or backed up depends on whetehr or not the [RESTART](RESTART.md) action is present on the file. If you add `RESTART=yes` on the
103 : line containing the PRINT directive the file will be appended also.
104 :
105 : Printing happens in the so-called "update" phase. This implies that printing
106 : is affected by the presence of [UPDATE_IF](UPDATE_IF.md) actions. One can thus decide to start
107 : and stop printing at preassigned values of time using the `UPDATE_FROM` and `UPDATE_UNTIL` keywords.
108 : Keep into account that even on steps when the action is not updated (and thus the file is not printed)
109 : the argument will be activated. In other words, if you use `UPDATE_FROM` to start printing at a given time,
110 : the collective variables this PRINT statement depends on will be computed also before that time.
111 :
112 : ## PRINT and RESTART
113 :
114 : If you run a calculation with the following input:
115 :
116 : ```plumed
117 : d: DISTANCE ATOMS=1,2
118 : PRINT ARG=d FILE=colvar
119 : ```
120 :
121 : and a file called colvar is already present in the directory where the calculation is running, the existing file is backed up
122 : and renamed to `bck.0.colvar` so that new data can be output to a new file called `colvar`. If you would like to append to the
123 : existing file you can use the RESTART command as shown below:
124 :
125 : ```plumed
126 : d: DISTANCE ATOMS=1,2
127 : PRINT ARG=d FILE=colvar RESTART=YES
128 : ```
129 :
130 : You can achieve the same result by using the [RESTART](RESTART.md) action as shown below:
131 :
132 : ```plumed
133 : RESTART
134 : d: DISTANCE ATOMS=1,2
135 : PRINT ARG=d FILE=colvar
136 : ```
137 :
138 : However, the advantage of using the RESTART keyword is that you can apped to some files and back up others as illustrated below:
139 :
140 : ```plumed
141 : d1: DISTANCE ATOMS=1,2
142 : PRINT ARG=d1 FILE=colvar1
143 : d2: DISTANCE ATOMS=3,4
144 : PRINT ARG=d2 FILE=colvar2 RESTART=YES
145 : ```
146 :
147 : If you use the input above the file `colvar1` is backed up, while new data will be appended to the file `colvar2`. If you use the
148 : [RESTART](RESTART.md) action instead data will be appended to both colvar files.
149 :
150 : ## Switching printing on and off
151 :
152 : You can use the UPDATE_FROM and UPDATE_UNTIL flags to make the PRINT command only output data at certain points during the trajectory.
153 : To see how this works consider the following example:
154 :
155 : ```plumed
156 : d: DISTANCE ATOMS=1,2
157 : PRINT ARG=d FILE=colvar UPDATE_FROM=100 UPDATE_UNTIL=500 STRIDE=1
158 : ```
159 :
160 : During the first 100 ps of the simulation with this input the distance between atoms 1 and 2 is not output to the file called colvar.
161 : The distance is instead first output after the first 100 ps of trajectory have elapsed. Furthermore, output of the distance stops
162 : once the trajectory is longer than 500 ps. In other words, the distance is only output during the 400 ps time interval after the first
163 : 100 ps of the simulation.
164 :
165 : */
166 : //+ENDPLUMEDOC
167 :
168 : class Print :
169 : public ActionPilot,
170 : public ActionWithArguments {
171 : std::string file;
172 : OFile ofile;
173 : std::string fmt;
174 : // small internal utility
175 : /////////////////////////////////////////
176 : // these are crazy things just for debug:
177 : // they allow to change regularly the
178 : // printed argument
179 : int rotate;
180 : int rotateCountdown;
181 : int rotateLast;
182 : std::vector<Value*> rotateArguments;
183 : /////////////////////////////////////////
184 : public:
185 247078 : void calculate() override {}
186 : void prepare() override;
187 : std::string writeInGraph() const override;
188 : explicit Print(const ActionOptions&);
189 : static void registerKeywords(Keywords& keys);
190 246956 : void apply() override {}
191 : void update() override;
192 : ~Print();
193 : };
194 :
195 : PLUMED_REGISTER_ACTION(Print,"PRINT")
196 :
197 1572 : void Print::registerKeywords(Keywords& keys) {
198 1572 : Action::registerKeywords(keys);
199 1572 : ActionPilot::registerKeywords(keys);
200 1572 : ActionWithArguments::registerKeywords(keys);
201 3144 : keys.addInputKeyword("compulsory","ARG","scalar/vector/matrix","the labels of the values that you would like to print to the file");
202 1572 : keys.add("compulsory","STRIDE","1","the frequency with which the quantities of interest should be output");
203 1572 : keys.add("optional","FILE","the name of the file on which to output these quantities");
204 1572 : keys.add("compulsory","FMT","%f","the format that should be used to output real numbers");
205 1572 : keys.add("hidden","_ROTATE","some funky thing implemented by GBussi");
206 1572 : keys.use("RESTART");
207 1572 : keys.use("UPDATE_FROM");
208 1572 : keys.use("UPDATE_UNTIL");
209 1572 : }
210 :
211 1562 : Print::Print(const ActionOptions&ao):
212 : Action(ao),
213 : ActionPilot(ao),
214 : ActionWithArguments(ao),
215 1562 : rotate(0) {
216 1562 : ofile.link(*this);
217 3124 : parse("FILE",file);
218 1562 : if(file.length()>0) {
219 1562 : ofile.open(file);
220 1552 : log.printf(" on file %s\n",file.c_str());
221 : } else {
222 0 : log.printf(" on plumed log file\n");
223 0 : ofile.link(log);
224 : }
225 1552 : parse("FMT",fmt);
226 1552 : fmt=" "+fmt;
227 1552 : log.printf(" with format %s\n",fmt.c_str());
228 9572 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
229 8020 : ofile.setupPrintValue( getPntrToArgument(i) );
230 : }
231 : /////////////////////////////////////////
232 : // these are crazy things just for debug:
233 : // they allow to change regularly the
234 : // printed argument
235 1552 : parse("_ROTATE",rotate);
236 1552 : if(rotate>0) {
237 1 : rotateCountdown=rotate;
238 4 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
239 3 : rotateArguments.push_back( getPntrToArgument(i) );
240 : }
241 11 : std::vector<Value*> a(1,rotateArguments[0]);
242 1 : requestArguments(std::vector<Value*>(1,rotateArguments[0]));
243 1 : rotateLast=0;
244 : }
245 : /////////////////////////////////////////
246 1552 : checkRead();
247 1602 : }
248 :
249 8 : std::string Print::writeInGraph() const {
250 24 : return getName() + "\n" + "FILE=" + file;
251 : }
252 :
253 247239 : void Print::prepare() {
254 : /////////////////////////////////////////
255 : // these are crazy things just for debug:
256 : // they allow to change regularly the
257 : // printed argument
258 247239 : if(rotate>0) {
259 5 : rotateCountdown--;
260 5 : if(rotateCountdown==0) {
261 2 : rotateCountdown=rotate;
262 2 : rotateLast++;
263 2 : rotateLast%=rotateArguments.size();
264 4 : requestArguments(std::vector<Value*>(1,rotateArguments[rotateLast]));
265 : }
266 : }
267 : /////////////////////////////////////////
268 247239 : }
269 :
270 235442 : void Print::update() {
271 235442 : ofile.fmtField(" %f");
272 235442 : ofile.printField("time",getTime());
273 869929 : for(unsigned i=0; i<getNumberOfArguments(); i++) {
274 634487 : ofile.fmtField(fmt);
275 634487 : getPntrToArgument(i)->print( ofile );
276 : }
277 235442 : ofile.printField();
278 235442 : }
279 :
280 3104 : Print::~Print() {
281 3104 : }
282 :
283 : }
284 :
285 :
286 : }
|