Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2016-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/ActionWithArguments.h"
23 : #include "core/ActionWithValue.h"
24 : #include "core/ActionPilot.h"
25 : #include "core/ActionRegister.h"
26 : #include "core/PlumedMain.h"
27 : #include "tools/Communicator.h"
28 : #include "tools/OFile.h"
29 :
30 : namespace PLMD {
31 : namespace generic {
32 :
33 : //+PLUMEDOC PRINTANALYSIS DUMPVECTOR
34 : /*
35 : Print a vector to a file
36 :
37 : In the following input the four distances calculated by the [DISTANCE](DISTANCE.md) command
38 : are output to files using this command and using [PRINT](PRINT.md)
39 :
40 : ```plumed
41 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8
42 : PRINT ARG=d FILE=colvar1 STRIDE=1
43 : DUMPVECTOR ARG=d FILE=colvar2 STRIDE=1
44 : ```
45 :
46 : The PRINT command outputs the instantaneous values of the four distances on a single row. If we have a trajectory
47 : with four frames the `colvar1` file will look like the one shown below:
48 :
49 : ````
50 : ! FIELDS time d.1 d.2 d.3 d.4
51 : 0.000000 1.000000 1.000000 1.414214 1.000000
52 : 1.000000 1.000000 1.000000 1.414214 1.000000
53 : 2.000000 1.000000 1.000000 1.414214 1.000000
54 : 3.000000 1.000000 1.000000 1.414214 1.000000
55 : ````
56 :
57 : By contrast the DUMPVECTOR command will produce four output files - for each step of the simulation. Each of these
58 : output files looks like this:
59 :
60 : ````
61 : ! FIELDS time parameter d
62 : 3.000000 0 1.000000
63 : 3.000000 1 1.000000
64 : 3.000000 2 1.414214
65 : 3.000000 3 1.000000
66 : ````
67 :
68 : In other words, the four elements of the vector are printed on different rows of the output.
69 : The latest file output will be called `colvar2` and all earlier files will be called `analysis.n.colvar` where
70 : n is an integer that indicates the order in which files were produced. By adding the flag `PRINT_ONE_FILE` as shown below:
71 :
72 : ```plumed
73 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8
74 : DUMPVECTOR ARG=d FILE=colvar2 STRIDE=1 PRINT_ONE_FILE
75 : ```
76 :
77 : We can ensure that all the data from all four frames is concatenated to a single file that looks as follows:
78 :
79 : ````
80 : #! FIELDS time parameter d
81 : 3.000000 0 1.000000
82 : 3.000000 1 1.000000
83 : 3.000000 2 1.414214
84 : 3.000000 3 1.000000
85 : #! FIELDS time parameter d
86 : 0.000000 0 1.000000
87 : 0.000000 1 1.000000
88 : 0.000000 2 1.414214
89 : 0.000000 3 1.000000
90 : #! FIELDS time parameter d
91 : 1.000000 0 1.000000
92 : 1.000000 1 1.000000
93 : 1.000000 2 1.414214
94 : 1.000000 3 1.000000
95 : #! FIELDS time parameter d
96 : 2.000000 0 1.000000
97 : 2.000000 1 1.000000
98 : 2.000000 2 1.414214
99 : 2.000000 3 1.000000
100 : ````
101 :
102 : This command is useful for printing out time series that have been stored using the [COLLECT](COLLECT.md)
103 : action or for printing out projections that have been generating using the tools in the [dimred](module_dimred.md)
104 : module. The following input shows how you can use it to calculate and print the time series of values for the
105 : distances between atoms 1 and 2 and atoms 3 and 4.
106 :
107 : ```plumed
108 : d1: DISTANCE ATOMS=1,2
109 : d2: DISTANCE ATOMS=3,4
110 : c1: COLLECT ARG=d1 STRIDE=1
111 : c2: COLLECT ARG=d2 STRIDE=1
112 : DUMPVECTOR ARG=c1,c2 FMT=%10.5f FILE=timeseries
113 : ```
114 :
115 : In the example input above the time series is output at the end of the calculation. Further notice how we have used
116 : the FMT keyword here to control the appearance of the numbers in the output using a [C format specifier](https://www.simplilearn.com/tutorials/c-tutorial/format-specifiers-in-c)
117 :
118 : ## Outputing matrices
119 :
120 : You can also use this command to output matrices as the following input demonstrates:
121 :
122 : ```plumed
123 : d: DISTANCE_MATRIX GROUPA=1,2 GROUPB=3-6
124 : DUMPVECTOR ARG=d FILE=matrix STRIDE=1
125 : ```
126 :
127 : The files `matrix` and `analysis.n.matrix` that are output on each step here looks as follows:
128 :
129 : ````
130 : ! FIELDS time parameter d.1 d.2 d.3 d.4
131 : 4.000000 0 2.000000 2.000000 1.000000 1.000000
132 : 4.000000 1 1.000000 2.000000 2.000000 1.414214
133 : ````
134 :
135 : In other words, the rows and columns of the file are used to display the rows and columns of the input matrix.
136 :
137 : Further note that if your input matrix was constructed using the [VSTACK](VSTACK.md) and [COLLECT](COLLECT.md) commands
138 : as shown below:
139 :
140 : ```plumed
141 : d1: DISTANCE ATOMS=1,2
142 : d2: DISTANCE ATOMS=3,4
143 : d3: DISTANCE ATOMS=5,6
144 : c1: COLLECT ARG=d1 STRIDE=1
145 : c2: COLLECT ARG=d2 STRIDE=1
146 : c3: COLLECT ARG=d3 STRIDE=1
147 : v: VSTACK ARG=c1,c2,c3
148 : DUMPVECTOR ARG=v FILE=matrix
149 : ```
150 :
151 : The output file looks as follows:
152 :
153 : ````
154 : #! FIELDS time parameter d1 d2 d3
155 : 3.000000 0 1.000000 1.000000 1.414214
156 : 3.000000 1 1.000000 1.000000 1.414214
157 : 3.000000 2 1.000000 1.000000 1.414214
158 : ````
159 :
160 : In other words, the names of the columns in the output reflect the names of the underlying variables that were
161 : collected and stacked together to form the input matrix.
162 :
163 : */
164 : //+ENDPLUMEDOC
165 :
166 : class DumpVector :
167 : public ActionWithArguments,
168 : public ActionPilot {
169 : private:
170 : bool onefile;
171 : std::vector<std::string> argnames;
172 : std::string fmt, filename;
173 : void buildArgnames();
174 : public:
175 : static void registerKeywords( Keywords& keys );
176 : explicit DumpVector(const ActionOptions&ao);
177 80 : ~DumpVector() {}
178 15 : void calculate() override {}
179 15 : void apply() override {}
180 : void update() override ;
181 : };
182 :
183 : PLUMED_REGISTER_ACTION(DumpVector,"DUMPVECTOR")
184 :
185 50 : void DumpVector::registerKeywords( Keywords& keys ) {
186 50 : Action::registerKeywords( keys );
187 50 : ActionPilot::registerKeywords( keys );
188 50 : ActionWithArguments::registerKeywords( keys );
189 100 : keys.addInputKeyword("compulsory","ARG","vector/matrix","the labels of vectors/matrices that should be output in the file");
190 50 : keys.add("compulsory","STRIDE","0","the frequency with which the grid should be output to the file.");
191 50 : keys.add("compulsory","FILE","density","the file on which to write the vetors");
192 50 : keys.add("optional","FMT","the format that should be used to output real numbers");
193 50 : keys.addFlag("PRINT_ONE_FILE",false,"output vectors one after the other in a single file");
194 50 : }
195 :
196 40 : DumpVector::DumpVector(const ActionOptions&ao):
197 : Action(ao),
198 : ActionWithArguments(ao),
199 : ActionPilot(ao),
200 40 : fmt("%f") {
201 40 : if( getNumberOfArguments()==0 ) {
202 0 : error("found no arguments");
203 : }
204 40 : buildArgnames();
205 40 : parse("FILE",filename);
206 80 : parseFlag("PRINT_ONE_FILE", onefile);
207 40 : if(filename.length()==0) {
208 0 : error("name out output file was not specified");
209 : }
210 :
211 40 : log.printf(" outputting data with label %s to file named %s",getPntrToArgument(0)->getName().c_str(), filename.c_str() );
212 40 : parse("FMT",fmt);
213 40 : log.printf(" with format %s \n", fmt.c_str() );
214 40 : fmt = " " + fmt;
215 40 : if( onefile ) {
216 0 : log.printf(" printing all grids on a single file \n");
217 : } else {
218 40 : log.printf(" printing all grids on separate files \n");
219 : }
220 40 : }
221 :
222 44 : void DumpVector::buildArgnames() {
223 44 : argnames.resize(0);
224 44 : unsigned nvals = getPntrToArgument(0)->getShape()[0];
225 : if( getPntrToArgument(0)->getRank()==2 ) {
226 : nvals = getPntrToArgument(0)->getShape()[0];
227 : }
228 109 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
229 65 : if( getPntrToArgument(i)->getShape()[0]!=nvals ) {
230 0 : error("all arguments should have same number of values");
231 : }
232 65 : if( getPntrToArgument(i)->getRank()==1 ) {
233 28 : argnames.push_back( getPntrToArgument(i)->getName() );
234 37 : } else if( getPntrToArgument(i)->getRank()==2 ) {
235 37 : (getPntrToArgument(i)->getPntrToAction())->getMatrixColumnTitles( argnames );
236 : }
237 : }
238 44 : }
239 :
240 49 : void DumpVector::update() {
241 49 : OFile ofile;
242 49 : ofile.link(*this);
243 49 : if( onefile ) {
244 0 : ofile.enforceRestart();
245 : } else {
246 98 : ofile.setBackupString("analysis");
247 : }
248 49 : ofile.open( filename );
249 :
250 : unsigned totargs = 0;
251 125 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
252 76 : if( getPntrToArgument(i)->getRank()==1 ) {
253 34 : totargs += 1;
254 42 : } else if( getPntrToArgument(i)->getRank()==2 ) {
255 42 : totargs += getPntrToArgument(i)->getShape()[1];
256 : }
257 : }
258 49 : if( totargs!=argnames.size() ) {
259 4 : buildArgnames();
260 : }
261 :
262 49 : unsigned nvals = getPntrToArgument(0)->getShape()[0];
263 5189 : for(unsigned i=0; i<nvals; ++i) {
264 : unsigned n=0;
265 5140 : ofile.fmtField(" %f");
266 5140 : ofile.printField("time",getTime());
267 5140 : ofile.printField("parameter",int(i));
268 13037 : for(unsigned j=0; j<getNumberOfArguments(); j++) {
269 7897 : if( getPntrToArgument(j)->getRank()==1 ) {
270 4947 : ofile.fmtField(fmt);
271 4947 : ofile.printField(argnames[n],getPntrToArgument(j)->get(i) );
272 4947 : n++;
273 2950 : } else if( getPntrToArgument(j)->getRank()==2 ) {
274 2950 : unsigned ncols = getPntrToArgument(j)->getShape()[1];
275 13591 : for(unsigned k=0; k<ncols; ++k) {
276 10641 : ofile.fmtField(fmt);
277 10641 : ofile.printField(argnames[n],getPntrToArgument(j)->get(i*ncols+k));
278 10641 : n++;
279 : }
280 : }
281 : }
282 5140 : ofile.printField();
283 : }
284 49 : }
285 :
286 : }
287 : }
|