Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2018 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/ActionWithValue.h"
23 : #include "core/ActionRegister.h"
24 : #include "tools/IFile.h"
25 :
26 : //+PLUMEDOC COLVAR CONSTANT
27 : /*
28 : Create a constant value that can be passed to actions
29 :
30 : This action can be used to create constant scalars, vectors or matrices. These
31 : constants are assigned to a value, which can then be used later in the input. For example,
32 : the following input creates a value `c` and sets it equal to the constant value 4.5.
33 :
34 : ```plumed
35 : c: CONSTANT VALUE=4.5
36 : PRINT ARG=c STRIDE=1 FILE=constant_scalar
37 : ```
38 :
39 : The output file printed by this input will contain a column in which every element is 4.5
40 :
41 : By contrast, this input creates a five element vector called `v` with elements equal to
42 : 1, 2, 3, 4 and 5:
43 :
44 : ```plumed
45 : v: CONSTANT VALUES=1,2,3,4,5
46 : PRINT ARG=v FILE=constant_vector
47 : ```
48 :
49 : The PRINT action will now output a file with 6 columns. The first of these columns will be the time.
50 : Every element of the second column will be 1, every element of the second column will be 2 and so on.
51 :
52 : Notice that can generate 5 scalar constant rather than a vector using an input like this:
53 :
54 : ```plumed
55 : c: CONSTANT VALUES=1,2,3,4,5 SCALARS
56 : PRINT ARG=c.v-0,c.v-1,c.v-2,c.v-3,c.v-4 FILE=five_scalars
57 : ```
58 :
59 : or you can use five separate constant actions like this:
60 :
61 : ```plumed
62 : c1: CONSTANT VALUE=1
63 : c2: CONSTANT VALUE=2
64 : c3: CONSTANT VALUE=3
65 : c4: CONSTANT VALUE=4
66 : c5: CONSTANT VALUE=5
67 : PRINT ARG=c1,c2,c3,c4,c5 FILE=five_scalars
68 : ```
69 :
70 : If you want to create a constant $2\times 3$ matrix you would use an input like the one below:
71 :
72 : ```plumed
73 : c: CONSTANT VALUES=1,2,3,4,5,6 NROWS=2 NCOLS=3
74 : PRINT ARG=c FILE=constant_matrix
75 : ```
76 :
77 : The constant matrix that this action generates is as follows:
78 :
79 : $$
80 : M = \left(
81 : \begin{matrix}
82 : 1 & 2 & 3 \\
83 : 4 & 5 & 6
84 : \end{matrix}
85 : \right)
86 : $$
87 :
88 : The print action ensures that the six elements of this constant matrix are output on every step.
89 :
90 : Notice, that you can also read matrices from files by using a command like the one shown below:
91 :
92 : ```plumed
93 : #SETTINGS INPUTFILES=regtest/landmarks/rt-read-dissims/mymatrix.dat
94 : c: CONSTANT FILE=regtest/landmarks/rt-read-dissims/mymatrix.dat NOLOG
95 : PRINT ARG=c FILE=constant_matrix
96 : ```
97 :
98 : The `NOLOG` flag that is used in this example ensures that all the values read in from the input file are not output
99 : in the plumed log file.
100 :
101 : The CONSTANT action is useful in combination with functions that take in input constants or parameters.
102 : For example, the following input instructs plumed to compute the distance
103 : between atoms 1 and 2. If this distance is between 1.0 and 2.0, it is
104 : printed. If it is lower than 1.0 (larger than 2.0), 1.0 (2.0) is printed
105 :
106 : ```plumed
107 : cn: CONSTANT VALUES=1.0,2.0 SCALARS
108 : dis: DISTANCE ATOMS=1,2
109 : sss: SORT ARG=cn.v-0,dis,cn.v-1
110 : PRINT ARG=sss.2
111 : ```
112 :
113 : By contrast this input only prints the distance between atom 1 and 2 if it is less than 1.
114 :
115 : ```plumed
116 : cn: CONSTANT VALUE=1.0
117 : dis: DISTANCE ATOMS=1,2
118 : sss: SORT ARG=cn,dis
119 : PRINT ARG=sss.1
120 : ```
121 :
122 : Lastly, note that if you have an action that only takes constant values in input its output values will be treated as constants. For example,
123 : in the following input the values `d` and `f` are evaluated on every step. `c`, however, is only evaluated once during start up.
124 :
125 : ```plumed
126 : p: CONSTANT VALUE=1.0
127 : c: CUSTOM ARG=p FUNC=2*x+1 PERIODIC=NO
128 : d: DISTANCE ATOMS=1,2
129 : f: CUSTOM ARG=p,d FUNC=x*y PERIODIC=NO
130 : PRINT ARG=f FILE=colvar STRIDE=1
131 : ```
132 :
133 : */
134 : //+ENDPLUMEDOC
135 :
136 : namespace PLMD {
137 : namespace generic {
138 :
139 : class Constant : public ActionWithValue {
140 : public:
141 : static void registerKeywords( Keywords& keys );
142 : explicit Constant(const ActionOptions&ao);
143 0 : void clearDerivatives( const bool& =false ) override {}
144 6011 : unsigned getNumberOfDerivatives() override {
145 6011 : return 0;
146 : }
147 0 : void calculate() override {}
148 0 : void apply() override {}
149 : };
150 :
151 : PLUMED_REGISTER_ACTION(Constant,"CONSTANT")
152 :
153 1811 : void Constant::registerKeywords( Keywords& keys ) {
154 1811 : Action::registerKeywords(keys);
155 1811 : ActionWithValue::registerKeywords(keys);
156 3622 : keys.remove("NUMERICAL_DERIVATIVES");
157 1811 : keys.add("optional","FILE","an input file containing the matrix");
158 1811 : keys.add("compulsory","NROWS","0","the number of rows in your input matrix");
159 1811 : keys.add("compulsory","NCOLS","0","the number of columns in your matrix");
160 1811 : keys.add("optional","VALUE","the single number that you would like to store");
161 1811 : keys.add("optional","VALUES","the numbers that are in your constant value");
162 1811 : keys.add("compulsory","PERIODIC","NO","the domain of the values in your constant, the default implies that the constant is not periodic");
163 1811 : keys.addFlag("SCALARS",false,"treat the input list of numbers as a set of scalars");
164 1811 : keys.addFlag("NOLOG",false,"do not report all the read in scalars in the log");
165 3622 : keys.addOutputComponent("v","SCALARS","scalar","the # value");
166 3622 : keys.setValueDescription("scalar/vector/matrix","the constant value that was read from the plumed input");
167 1811 : }
168 :
169 1005 : Constant::Constant(const ActionOptions&ao):
170 : Action(ao),
171 1005 : ActionWithValue(ao) {
172 1005 : bool nolog=false;
173 1005 : parseFlag("NOLOG",nolog);
174 1005 : bool scalars=false;
175 : std::string fname, vname;
176 1005 : parse("FILE",fname);
177 1005 : std::vector<std::size_t> shape;
178 1005 : std::vector<double> vals;
179 1005 : if( fname.length()>0 ) {
180 3 : IFile mfile;
181 3 : mfile.open(fname);
182 : // Read in first line
183 3 : std::vector<std::string> words;
184 : unsigned nline=0;
185 6 : while( nline==0 ) {
186 3 : Tools::getParsedLine( mfile, words );
187 3 : nline=words.size();
188 : }
189 3 : std::vector<std::vector<double> > dissimilarities;
190 3 : if( nline==1 ) {
191 0 : shape.resize(1);
192 0 : error("invalid matrix in input file");
193 : }
194 3 : shape.resize(2);
195 3 : shape[1]=nline;
196 3 : std::vector<double> tmpdis( shape[1] );
197 34 : for(unsigned j=0; j<shape[1]; ++j) {
198 31 : Tools::convert( words[j], tmpdis[j] );
199 : }
200 3 : dissimilarities.push_back( tmpdis );
201 :
202 31 : while( Tools::getParsedLine( mfile, words ) ) {
203 28 : if( words.size()!=nline ) {
204 0 : error("bad formatting in matrix file");
205 : }
206 360 : for(unsigned j=0; j<nline; ++j) {
207 332 : Tools::convert( words[j], tmpdis[j] );
208 : }
209 28 : dissimilarities.push_back( tmpdis );
210 : }
211 3 : mfile.close();
212 3 : shape[0] = dissimilarities.size();
213 3 : vals.resize(shape[0]);
214 3 : if( shape.size()==2 ) {
215 3 : vals.resize( shape[0]*shape[1] );
216 : }
217 34 : for(unsigned i=0; i<shape[0]; ++i) {
218 394 : for(unsigned j=0; j<nline; ++j) {
219 363 : vals[i*nline+j] = dissimilarities[i][j];
220 : }
221 : }
222 3 : } else {
223 : std::size_t nr, nc;
224 1002 : parse("NROWS",nr);
225 1002 : parse("NCOLS",nc);
226 1002 : if( nr>0 && nc>0 ) {
227 95 : shape.resize(2);
228 95 : shape[0]=nr;
229 95 : shape[1]=nc;
230 95 : vals.resize( nr*nc );
231 95 : log.printf(" reading in %zu by %zu matrix \n", nr, nc );
232 907 : } else if( nr>0 || nc>0 ) {
233 0 : error("makes no sense to set only one of NROWS and NCOLS to a non-zero value");
234 : }
235 1002 : parseVector("VALUES",vals);
236 2004 : parseFlag("SCALARS",scalars);
237 1002 : if( vals.size()==0 ) {
238 162 : parseVector("VALUE",vals);
239 81 : if( vals.size()!=1 ) {
240 0 : error("VALUE keyword should take a single scalar");
241 : }
242 921 : } else if( vals.size()==1 ) {
243 226 : scalars=false;
244 : }
245 :
246 1002 : log.printf(" read in %zu values :", vals.size() );
247 1002 : if( !nolog ) {
248 33206 : for(unsigned i=0; i<vals.size(); ++i) {
249 32700 : log.printf(" %f", vals[i] );
250 : }
251 : }
252 1002 : log.printf("\n");
253 1002 : if( !scalars && shape.size()==0 && vals.size()>1 ) {
254 599 : shape.resize(1);
255 599 : shape[0] = vals.size();
256 : }
257 : }
258 1005 : std::vector<std::string> domain(2);
259 1005 : parseVector("PERIODIC",domain);
260 1005 : if( !scalars ) {
261 : // Now set the value
262 1004 : addValue( shape );
263 1004 : if( domain[0]!="NO" ) {
264 0 : setPeriodic( domain[0], domain[1] );
265 : } else {
266 1004 : setNotPeriodic();
267 : }
268 1004 : getPntrToComponent(0)->setConstant();
269 1629551 : for(unsigned i=0; i<vals.size(); ++i) {
270 1628547 : getPntrToComponent(0)->set( i, vals[i] );
271 : }
272 : } else {
273 1 : if( domain[0]!="NO") {
274 0 : error("use multiple CONSTANT commands to create scalar constants with a periodic domain");
275 : }
276 3 : for(unsigned i=0; i<vals.size(); i++) {
277 : std::string num;
278 2 : Tools::convert(i,num);
279 4 : addComponent("v-"+num);
280 2 : componentIsNotPeriodic("v-"+num);
281 2 : Value* comp=getPntrToComponent("v-"+num);
282 2 : comp->setConstant();
283 2 : comp->set(vals[i]);
284 : }
285 : }
286 2010 : }
287 :
288 : }
289 : }
290 :
|