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 FILE=timeseries
113 : ```
114 :
115 : In the example input above the time series is output at the end of the calculation.
116 :
117 : ## Outputing matrices
118 :
119 : You can also use this command to output matrices as the following input demonstrates:
120 :
121 : ```plumed
122 : d: DISTANCE_MATRIX GROUPA=1,2 GROUPB=3-6
123 : DUMPVECTOR ARG=d FILE=matrix STRIDE=1
124 : ```
125 :
126 : The files `matrix` and `analysis.n.matrix` that are output on each step here looks as follows:
127 :
128 : ````
129 : ! FIELDS time parameter d.1 d.2 d.3 d.4
130 : 4.000000 0 2.000000 2.000000 1.000000 1.000000
131 : 4.000000 1 1.000000 2.000000 2.000000 1.414214
132 : ````
133 :
134 : In other words, the rows and columns of the file are used to display the rows and columns of the input matrix.
135 :
136 : Further note that if your input matrix was constructed using the [VSTACK](VSTACK.md) and [COLLECT](COLLECT.md) commands
137 : as shown below:
138 :
139 : ```plumed
140 : d1: DISTANCE ATOMS=1,2
141 : d2: DISTANCE ATOMS=3,4
142 : d3: DISTANCE ATOMS=5,6
143 : c1: COLLECT ARG=d1 STRIDE=1
144 : c2: COLLECT ARG=d2 STRIDE=1
145 : c3: COLLECT ARG=d3 STRIDE=1
146 : v: VSTACK ARG=c1,c2,c3
147 : DUMPVECTOR ARG=v FILE=matrix
148 : ```
149 :
150 : The output file looks as follows:
151 :
152 : ````
153 : #! FIELDS time parameter d1 d2 d3
154 : 3.000000 0 1.000000 1.000000 1.414214
155 : 3.000000 1 1.000000 1.000000 1.414214
156 : 3.000000 2 1.000000 1.000000 1.414214
157 : ````
158 :
159 : In other words, the names of the columns in the output reflect the names of the underlying variables that were
160 : collected and stacked together to form the input matrix.
161 :
162 : */
163 : //+ENDPLUMEDOC
164 :
165 : class DumpVector :
166 : public ActionWithArguments,
167 : public ActionPilot {
168 : private:
169 : bool onefile;
170 : std::vector<std::string> argnames;
171 : std::string fmt, filename;
172 : void buildArgnames();
173 : public:
174 : static void registerKeywords( Keywords& keys );
175 : explicit DumpVector(const ActionOptions&ao);
176 72 : ~DumpVector() {}
177 16 : void calculate() override {}
178 16 : void apply() override {}
179 : void update() override ;
180 : };
181 :
182 : PLUMED_REGISTER_ACTION(DumpVector,"DUMPVECTOR")
183 :
184 44 : void DumpVector::registerKeywords( Keywords& keys ) {
185 44 : Action::registerKeywords( keys );
186 44 : ActionPilot::registerKeywords( keys );
187 44 : ActionWithArguments::registerKeywords( keys );
188 88 : keys.addInputKeyword("compulsory","ARG","vector/matrix","the labels of vectors/matrices that should be output in the file");
189 44 : keys.add("compulsory","STRIDE","0","the frequency with which the grid should be output to the file.");
190 44 : keys.add("compulsory","FILE","density","the file on which to write the vetors");
191 44 : keys.add("optional","FMT","the format that should be used to output real numbers");
192 44 : keys.addFlag("PRINT_ONE_FILE",false,"output vectors one after the other in a single file");
193 44 : }
194 :
195 36 : DumpVector::DumpVector(const ActionOptions&ao):
196 : Action(ao),
197 : ActionWithArguments(ao),
198 : ActionPilot(ao),
199 36 : fmt("%f") {
200 36 : if( getNumberOfArguments()==0 ) {
201 0 : error("found no arguments");
202 : }
203 36 : buildArgnames();
204 36 : parse("FILE",filename);
205 72 : parseFlag("PRINT_ONE_FILE", onefile);
206 36 : if(filename.length()==0) {
207 0 : error("name out output file was not specified");
208 : }
209 :
210 36 : log.printf(" outputting data with label %s to file named %s",getPntrToArgument(0)->getName().c_str(), filename.c_str() );
211 36 : parse("FMT",fmt);
212 36 : log.printf(" with format %s \n", fmt.c_str() );
213 36 : fmt = " " + fmt;
214 36 : if( onefile ) {
215 0 : log.printf(" printing all grids on a single file \n");
216 : } else {
217 36 : log.printf(" printing all grids on separate files \n");
218 : }
219 36 : }
220 :
221 40 : void DumpVector::buildArgnames() {
222 40 : argnames.resize(0);
223 40 : unsigned nvals = getPntrToArgument(0)->getShape()[0];
224 : if( getPntrToArgument(0)->getRank()==2 ) {
225 : nvals = getPntrToArgument(0)->getShape()[0];
226 : }
227 97 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
228 57 : if( getPntrToArgument(i)->getShape()[0]!=nvals ) {
229 0 : error("all arguments should have same number of values");
230 : }
231 57 : if( getPntrToArgument(i)->getRank()==1 ) {
232 24 : argnames.push_back( getPntrToArgument(i)->getName() );
233 33 : } else if( getPntrToArgument(i)->getRank()==2 ) {
234 33 : (getPntrToArgument(i)->getPntrToAction())->getMatrixColumnTitles( argnames );
235 : }
236 57 : getPntrToArgument(i)->buildDataStore();
237 : }
238 40 : }
239 :
240 46 : void DumpVector::update() {
241 46 : OFile ofile;
242 46 : ofile.link(*this);
243 46 : if( onefile ) {
244 0 : ofile.enforceRestart();
245 : } else {
246 92 : ofile.setBackupString("analysis");
247 : }
248 46 : ofile.open( filename );
249 :
250 : unsigned totargs = 0;
251 116 : for(unsigned i=0; i<getNumberOfArguments(); ++i) {
252 70 : if( getPntrToArgument(i)->getRank()==1 ) {
253 31 : totargs += 1;
254 39 : } else if( getPntrToArgument(i)->getRank()==2 ) {
255 39 : totargs += getPntrToArgument(i)->getShape()[1];
256 : }
257 : }
258 46 : if( totargs!=argnames.size() ) {
259 4 : buildArgnames();
260 : }
261 :
262 46 : unsigned nvals = getPntrToArgument(0)->getShape()[0];
263 5228 : for(unsigned i=0; i<nvals; ++i) {
264 : unsigned n=0;
265 5182 : ofile.fmtField(" %f");
266 5182 : ofile.printField("time",getTime());
267 5182 : ofile.printField("parameter",int(i));
268 13163 : for(unsigned j=0; j<getNumberOfArguments(); j++) {
269 7981 : if( getPntrToArgument(j)->getRank()==1 ) {
270 4989 : ofile.fmtField(fmt);
271 4989 : ofile.printField(argnames[n],getPntrToArgument(j)->get(i) );
272 4989 : n++;
273 2992 : } else if( getPntrToArgument(j)->getRank()==2 ) {
274 2992 : unsigned ncols = getPntrToArgument(j)->getShape()[1];
275 13725 : for(unsigned k=0; k<ncols; ++k) {
276 10733 : ofile.fmtField(fmt);
277 10733 : ofile.printField(argnames[n],getPntrToArgument(j)->get(i*ncols+k));
278 10733 : n++;
279 : }
280 : }
281 : }
282 5182 : ofile.printField();
283 : }
284 46 : }
285 :
286 : }
287 : }
|