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 : Lastly, 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 : The CONSTANT action is useful in combination with functions that take in input constants or parameters.
91 : For example, the following input instructs plumed to compute the distance
92 : between atoms 1 and 2. If this distance is between 1.0 and 2.0, it is
93 : printed. If it is lower than 1.0 (larger than 2.0), 1.0 (2.0) is printed
94 :
95 : ```plumed
96 : cn: CONSTANT VALUES=1.0,2.0 SCALARS
97 : dis: DISTANCE ATOMS=1,2
98 : sss: SORT ARG=cn.v-0,dis,cn.v-1
99 : PRINT ARG=sss.2
100 : ```
101 :
102 : By contrast this input only prints the distance between atom 1 and 2 if it is less than 1.
103 :
104 : ```plumed
105 : cn: CONSTANT VALUE=1.0
106 : dis: DISTANCE ATOMS=1,2
107 : sss: SORT ARG=cn,dis
108 : PRINT ARG=sss.1
109 : ```
110 :
111 : 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,
112 : in the following input the values `d` and `f` are evaluated on every step. `c`, however, is only evaluated once during start up.
113 :
114 : ```plumed
115 : p: CONSTANT VALUE=1.0
116 : c: CUSTOM ARG=p FUNC=2*x+1 PERIODIC=NO
117 : d: DISTANCE ATOMS=1,2
118 : f: CUSTOM ARG=p,d FUNC=x*y PERIODIC=NO
119 : PRINT ARG=f FILE=colvar STRIDE=1
120 : ```
121 :
122 : */
123 : //+ENDPLUMEDOC
124 :
125 : namespace PLMD {
126 : namespace generic {
127 :
128 : class Constant : public ActionWithValue {
129 : public:
130 : static void registerKeywords( Keywords& keys );
131 : explicit Constant(const ActionOptions&ao);
132 0 : void clearDerivatives( const bool& force=false ) {}
133 6041 : unsigned getNumberOfDerivatives() override {
134 6041 : return 0;
135 : }
136 0 : void calculate() override {}
137 0 : void apply() override {}
138 : };
139 :
140 : PLUMED_REGISTER_ACTION(Constant,"CONSTANT")
141 :
142 1508 : void Constant::registerKeywords( Keywords& keys ) {
143 1508 : Action::registerKeywords(keys);
144 1508 : ActionWithValue::registerKeywords(keys);
145 3016 : keys.remove("NUMERICAL_DERIVATIVES");
146 1508 : keys.add("optional","FILE","an input file containing the matrix");
147 1508 : keys.add("compulsory","NROWS","0","the number of rows in your input matrix");
148 1508 : keys.add("compulsory","NCOLS","0","the number of columns in your matrix");
149 1508 : keys.add("optional","VALUE","the single number that you would like to store");
150 1508 : keys.add("optional","VALUES","the numbers that are in your constant value");
151 1508 : keys.addFlag("SCALARS",false,"treat the input list of numbers as a set of scalars");
152 1508 : keys.addFlag("NOLOG",false,"do not report all the read in scalars in the log");
153 3016 : keys.addOutputComponent("v","SCALARS","scalar","the # value");
154 3016 : keys.setValueDescription("scalar/vector/matrix","the constant value that was read from the plumed input");
155 1508 : }
156 :
157 851 : Constant::Constant(const ActionOptions&ao):
158 : Action(ao),
159 851 : ActionWithValue(ao) {
160 851 : bool nolog=false;
161 851 : parseFlag("NOLOG",nolog);
162 851 : bool scalars=false;
163 : std::string fname, vname;
164 1702 : parse("FILE",fname);
165 : std::vector<unsigned> shape;
166 : std::vector<double> vals;
167 851 : if( fname.length()>0 ) {
168 3 : IFile mfile;
169 3 : mfile.open(fname);
170 : // Read in first line
171 : std::vector<std::string> words;
172 : unsigned nline=0;
173 6 : while( nline==0 ) {
174 3 : Tools::getParsedLine( mfile, words );
175 3 : nline=words.size();
176 : }
177 : std::vector<std::vector<double> > dissimilarities;
178 3 : if( nline==1 ) {
179 0 : shape.resize(1);
180 0 : error("invalid matrix in input file");
181 : }
182 3 : shape.resize(2);
183 3 : shape[1]=nline;
184 3 : std::vector<double> tmpdis( shape[1] );
185 34 : for(unsigned j=0; j<shape[1]; ++j) {
186 31 : Tools::convert( words[j], tmpdis[j] );
187 : }
188 3 : dissimilarities.push_back( tmpdis );
189 :
190 31 : while( Tools::getParsedLine( mfile, words ) ) {
191 28 : if( words.size()!=nline ) {
192 0 : error("bad formatting in matrix file");
193 : }
194 360 : for(unsigned j=0; j<nline; ++j) {
195 332 : Tools::convert( words[j], tmpdis[j] );
196 : }
197 28 : dissimilarities.push_back( tmpdis );
198 : }
199 3 : mfile.close();
200 3 : shape[0] = dissimilarities.size();
201 3 : vals.resize(shape[0]);
202 3 : if( shape.size()==2 ) {
203 3 : vals.resize( shape[0]*shape[1] );
204 : }
205 34 : for(unsigned i=0; i<shape[0]; ++i) {
206 394 : for(unsigned j=0; j<nline; ++j) {
207 363 : vals[i*nline+j] = dissimilarities[i][j];
208 : }
209 : }
210 3 : } else {
211 : unsigned nr, nc;
212 848 : parse("NROWS",nr);
213 848 : parse("NCOLS",nc);
214 848 : if( nr>0 && nc>0 ) {
215 73 : shape.resize(2);
216 73 : shape[0]=nr;
217 73 : shape[1]=nc;
218 73 : vals.resize( nr*nc );
219 73 : log.printf(" reading in %d by %d matrix \n", nr, nc );
220 775 : } else if( nr>0 || nc>0 ) {
221 0 : error("makes no sense to set only one of NROWS and NCOLS to a non-zero value");
222 : }
223 848 : parseVector("VALUES",vals);
224 1696 : parseFlag("SCALARS",scalars);
225 848 : if( vals.size()==0 ) {
226 132 : parseVector("VALUE",vals);
227 66 : if( vals.size()!=1 ) {
228 0 : error("VALUE keyword should take a single scalar");
229 : }
230 782 : } else if( vals.size()==1 ) {
231 236 : scalars=false;
232 : }
233 :
234 848 : log.printf(" read in %d values :", vals.size() );
235 848 : if( !nolog ) {
236 25705 : for(unsigned i=0; i<vals.size(); ++i) {
237 25112 : log.printf(" %f", vals[i] );
238 : }
239 : }
240 848 : log.printf("\n");
241 848 : if( !scalars && shape.size()==0 && vals.size()>1 ) {
242 472 : shape.resize(1);
243 472 : shape[0] = vals.size();
244 : }
245 : }
246 851 : if( !scalars ) {
247 : // Now set the value
248 850 : addValue( shape );
249 850 : setNotPeriodic();
250 850 : getPntrToComponent(0)->setConstant();
251 147242 : for(unsigned i=0; i<vals.size(); ++i) {
252 146392 : getPntrToComponent(0)->set( i, vals[i] );
253 : }
254 : } else {
255 3 : for(unsigned i=0; i<vals.size(); i++) {
256 : std::string num;
257 2 : Tools::convert(i,num);
258 4 : addComponent("v-"+num);
259 2 : componentIsNotPeriodic("v-"+num);
260 2 : Value* comp=getPntrToComponent("v-"+num);
261 2 : comp->setConstant();
262 2 : comp->set(vals[i]);
263 : }
264 : }
265 851 : }
266 :
267 : }
268 : }
269 :
|