Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2012-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/ActionRegister.h"
23 : #include "FunctionShortcut.h"
24 : #include "FunctionOfScalar.h"
25 : #include "FunctionOfVector.h"
26 : #include "FunctionWithSingleArgument.h"
27 : #include "FunctionSetup.h"
28 :
29 : namespace PLMD {
30 : namespace function {
31 :
32 : //+PLUMEDOC FUNCTION HIGHEST
33 : /*
34 : This function can be used to find the highest colvar by magnitude in a set.
35 :
36 : This action allows you to find the highest of the input arguments. As a first example of how it might be used consider the following input:
37 :
38 : ```plumed
39 : d1: DISTANCE ATOMS=1,2
40 : d2: DISTANCE ATOMS=3,4
41 : h1: HIGHEST ARG=d1,d2
42 : PRINT ARG=h1 FILE=colvar
43 : ```
44 :
45 : The value, `h1`, that is output to the file `colvar` here will be equal to `d1` if `d1>d2` and will be equal to `d2` if `d2>d1`. In other words, if
46 : all the arguments input to a HIGHEST action are scalars then the output value will be a scalar that is equal to the largest of the input arguments.
47 : Notice that you can also use this command with more than two arguments as illustrated below:
48 :
49 : ```plumed
50 : d1: DISTANCE ATOMS=1,2
51 : d2: DISTANCE ATOMS=3,4
52 : d3: DISTANCE ATOMS=5,6
53 : d4: DISTANCE ATOMS=7,8
54 : h1: HIGHEST ARG=d1,d2,d3,d4
55 : PRINT ARG=h1 FILE=colvar
56 : ```
57 :
58 : ## Using a single vector as input
59 :
60 : Instead of inputting multiple scalars you can input a single vector to this action instead as is illustrated below:
61 :
62 : ```plumed
63 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4
64 : h1: HIGHEST ARG=d
65 : PRINT ARG=h1 FILE=colvar
66 : ```
67 :
68 : The output from this action is a single scalar once again. This single scalar is equal to the largest element of the input vector.
69 :
70 : ## Using multiple vectors in input
71 :
72 : If you input multiple vectors with the same numbers of elements to this action, as shown below, the output will be a vector.
73 :
74 :
75 : ```plumed
76 : d1: DISTANCE ATOMS1=1,2 ATOMS2=3,4
77 : d2: DISTANCE ATOMS1=5,6 ATOMS2=7,8
78 : d3: DISTANCE ATOMS1=9,10 ATOMS2=11,12
79 : h2: HIGHEST ARG=d1,d2,d3
80 : PRINT ARG=h2 FILE=colvar
81 : ```
82 :
83 : The elements of the output vector here are determined by doing an elementwise comparison of the elements in the input vectors. In the above
84 : input the first element of `h2` is equal to the distance between atoms 1 and 2 if this distance is larger than the distances between atoms 5 and 6 and the distance between atoms 9 and 10.
85 : By the same token the second element of `h2` is equal to the distance between atoms 3 and 4 if this is larger than the distance between atoms 7 and 8 and the distance between atoms 11 and 12.
86 : In other words, if the elements of the $j$th input vector are given by $v_i^{(j)}$ then the elements of the output vector, $h_i$ are given by:
87 :
88 : $$
89 : h_i = \max_j v_i^{(j)}
90 : $$
91 :
92 : Notice that you can also use a combination of scalars and vectors in the input to this action as shown below:
93 :
94 : ```plumed
95 : c: CONSTANT VALUE=0.05
96 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4
97 : h: HIGHEST ARG=d,c
98 : PRINT ARG=h FILE=colvar
99 : ```
100 :
101 : For the input above the HIGHEST action outputs a vector with two elements. The elements of this vector are equal to the distances between the pairs
102 : of atoms that are specified in the DISTANCE command as long as those distances are greater than 0.05 nm. If either of the two input distances is less
103 : than 0.05 nm then the corresponding value in the vector `h` is set equal to 0.05 nm.
104 :
105 : ## The MASK keyword
106 :
107 : You should only use the MASK keyword for this action if you are using multiple arguments and at least one vector in the input to this action.
108 : The following input illustrates how this keyword works:
109 :
110 : ```plumed
111 : m: CONSTANT VALUES=1,0
112 : d1: DISTANCE ATOMS1=1,2 ATOMS2=3,4
113 : d2: DISTANCE ATOMS1=5,6 ATOMS2=7,8
114 : d3: DISTANCE ATOMS1=9,10 ATOMS2=11,12
115 : h2: HIGHEST ARG=d1,d2,d3 MASK=m
116 : ```
117 :
118 : By using the MASK keyword here you ensure that only the first element of the output vector for `h2` is calculated. This element of the output vector
119 : is evaluated as the corresponding element of the vector that is passed in the input to the MASK keyword is one. By the same logic the second element
120 : of the output vector is not computed because the corresponding element in the mask vector is 0.
121 :
122 : The input above illustrates the key idea for the MASK keyword and is probably not very useful. To see an example where using a MASK for this type of action
123 : is useful you should look at the expanded shortcuts in the documentation for [PARABETARMSD](PARABETARMSD.md).
124 :
125 : */
126 : //+ENDPLUMEDOC
127 :
128 : //+PLUMEDOC FUNCTION LOWEST
129 : /*
130 : This function can be used to find the lowest colvar by magnitude in a set.
131 :
132 : This action allows you to find the lowest of the input arguments. As a first example of how it might be used consider the following input:
133 :
134 : ```plumed
135 : d1: DISTANCE ATOMS=1,2
136 : d2: DISTANCE ATOMS=3,4
137 : l1: LOWEST ARG=d1,d2
138 : PRINT ARG=l1 FILE=colvar
139 : ```
140 :
141 : The value, `l1`, that is output to the file `colvar` here will be equal to `d1` if `d1<d2` and will be equal to `d2` if `d2<d1`. In other words, if
142 : all the arguments input to a LOWEST action are scalars then the output value will be a scalar that is equal to the smallest of the input arguments.
143 : Notice that you can also use this command with more than two arguments as illustrated below:
144 :
145 : ```plumed
146 : d1: DISTANCE ATOMS=1,2
147 : d2: DISTANCE ATOMS=3,4
148 : d3: DISTANCE ATOMS=5,6
149 : d4: DISTANCE ATOMS=7,8
150 : l1: LOWEST ARG=d1,d2,d3,d4
151 : PRINT ARG=l1 FILE=colvar
152 : ```
153 :
154 : ## Using a single vector as input
155 :
156 : Instead of inputting multiple scalars you can input a single vector to this action instead as is illustrated below:
157 :
158 : ```plumed
159 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4
160 : l1: LOWEST ARG=d
161 : PRINT ARG=l1 FILE=colvar
162 : ```
163 :
164 : The output from this action is a single scalar once again. This single scalar is equal to the smallest element of the input vector.
165 :
166 : ## Using multiple vectors in input
167 :
168 : If you input multiple vectors with the same numbers of elements to this action, as shown below, the output will be a vector.
169 :
170 :
171 : ```plumed
172 : d1: DISTANCE ATOMS1=1,2 ATOMS2=3,4
173 : d2: DISTANCE ATOMS1=5,6 ATOMS2=7,8
174 : d3: DISTANCE ATOMS1=9,10 ATOMS2=11,12
175 : l2: LOWEST ARG=d1,d2,d3
176 : PRINT ARG=l2 FILE=colvar
177 : ```
178 :
179 : The elements of the output vector here are determined by doing an elementwise comparison of the elements in the input vectors. In the above
180 : input the first element of `h2` is equal to the distance between atoms 1 and 2 if this distance is smaller than the distances between atoms 5 and 6 and the distance between atoms 9 and 10.
181 : By the same token the second element of `h2` is equal to the distance between atoms 3 and 4 if this is smaller than the distance between atoms 7 and 8 and the distance between atoms 11 and 12.
182 : In other words, if the elements of the $j$th input vector are given by $v_i^{(j)}$ then the elements of the output vector, $h_i$ are given by:
183 :
184 : $$
185 : h_i = \min_j v_i^{(j)}
186 : $$
187 :
188 : Notice that you can also use a combination of scalars and vectors in the input to this action as shown below:
189 :
190 : ```plumed
191 : c: CONSTANT VALUE=0.5
192 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4
193 : h: LOWEST ARG=d,c
194 : PRINT ARG=h FILE=colvar
195 : ```
196 :
197 : For the input above the LOWEST action outputs a vector with two elements. The elements of this vector are equal to the distances between the pairs
198 : of atoms that are specified in the DISTANCE command as long as those distances are less than 0.5 nm. If either of the two input distances is more
199 : than 0.5 nm then the corresponding value in the vector `h` is set equal to 0.5 nm.
200 :
201 : ## The MASK keyword
202 :
203 : You should only use the MASK keyword for this action if you are using multiple arguments and at least one vector in the input to this action.
204 : The following input illustrates how this keyword works:
205 :
206 : ```plumed
207 : m: CONSTANT VALUES=1,0
208 : d1: DISTANCE ATOMS1=1,2 ATOMS2=3,4
209 : d2: DISTANCE ATOMS1=5,6 ATOMS2=7,8
210 : d3: DISTANCE ATOMS1=9,10 ATOMS2=11,12
211 : h2: LOWEST ARG=d1,d2,d3 MASK=m
212 : ```
213 :
214 : By using the MASK keyword here you ensure that only the first element of the output vector for `h2` is calculated. This element of the output vector
215 : is evaluated as the corresponding element of the vector that is passed in the input to the MASK keyword is one. By the same logic the second element
216 : of the output vector is not computed because the corresponding element in the mask vector is 0.
217 :
218 : The input above illustrates the key idea for the MASK keyword and is probably not very useful. To see an example where using a MASK for this type of action
219 : is useful you should look at the expanded shortcuts in the documentation for [PARABETARMSD](PARABETARMSD.md).
220 :
221 : */
222 : //+ENDPLUMEDOC
223 :
224 : class Highest {
225 : public:
226 : bool min;
227 : static void registerKeywords( Keywords& keys );
228 : static void read( Highest& func, ActionWithArguments* action, FunctionOptions& options );
229 : static void calc( const Highest& func, bool noderiv, const View<const double>& args, FunctionOutput& funcout );
230 : };
231 :
232 : typedef FunctionShortcut<Highest> HighestShortcut;
233 : PLUMED_REGISTER_ACTION(HighestShortcut,"HIGHEST")
234 : PLUMED_REGISTER_ACTION(HighestShortcut,"LOWEST")
235 : typedef FunctionWithSingleArgument<Highest> OneargHighest;
236 : PLUMED_REGISTER_ACTION(OneargHighest,"HIGHEST_ONEARG")
237 : PLUMED_REGISTER_ACTION(OneargHighest,"LOWEST_ONEARG")
238 : typedef FunctionOfScalar<Highest> ScalarHighest;
239 : PLUMED_REGISTER_ACTION(ScalarHighest,"HIGHEST_SCALAR")
240 : PLUMED_REGISTER_ACTION(ScalarHighest,"LOWEST_SCALAR")
241 : typedef FunctionOfVector<Highest> VectorHighest;
242 : PLUMED_REGISTER_ACTION(VectorHighest,"HIGHEST_VECTOR")
243 : PLUMED_REGISTER_ACTION(VectorHighest,"LOWEST_VECTOR")
244 :
245 298 : void Highest::registerKeywords( Keywords& keys ) {
246 596 : if( keys.getDisplayName().find("LOWEST")!=std::string::npos ) {
247 386 : keys.setValueDescription("scalar","the lowest of the input values");
248 : } else {
249 210 : keys.setValueDescription("scalar","the highest of the input values");
250 : }
251 298 : keys.add("hidden","MASKED_INPUT_ALLOWED","turns on that you are allowed to use masked inputs");
252 298 : }
253 :
254 66 : void Highest::read( Highest& func, ActionWithArguments* action, FunctionOptions& options ) {
255 66 : func.min=action->getName().find("LOWEST")!=std::string::npos;
256 66 : if( !func.min ) {
257 23 : plumed_assert( action->getName().find("HIGHEST")!=std::string::npos );
258 : }
259 188 : for(unsigned i=0; i<action->getNumberOfArguments(); ++i) {
260 122 : if( action->getPntrToArgument(i)->isPeriodic() ) {
261 0 : action->error("Cannot sort periodic values (check argument "+ action->getPntrToArgument(i)->getName() +")");
262 : }
263 : }
264 66 : }
265 :
266 103548 : void Highest::calc( const Highest& func, bool noderiv, const View<const double>& args, FunctionOutput& funcout ) {
267 103548 : if( !noderiv ) {
268 340561 : for(unsigned i=0; i<args.size(); ++i) {
269 288808 : funcout.derivs[0][i] = 0;
270 : }
271 : }
272 103548 : if( func.min ) {
273 103409 : funcout.values[0] = *std::min_element(args.begin(), args.end());
274 103409 : if( !noderiv ) {
275 51742 : funcout.derivs[0][std::min_element(args.begin(), args.end()) - args.begin()] = 1;
276 : }
277 : } else {
278 139 : funcout.values[0] = *std::max_element(args.begin(), args.end());
279 139 : if( !noderiv ) {
280 11 : funcout.derivs[0][std::max_element(args.begin(), args.end()) - args.begin()] = 1;
281 : }
282 : }
283 103548 : }
284 :
285 : }
286 : }
287 :
288 :
|