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 "FunctionTemplateBase.h"
27 :
28 : namespace PLMD {
29 : namespace function {
30 :
31 : //+PLUMEDOC FUNCTION HIGHEST
32 : /*
33 : This function can be used to find the highest colvar by magnitude in a set.
34 :
35 : 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:
36 :
37 : ```plumed
38 : d1: DISTANCE ATOMS=1,2
39 : d2: DISTANCE ATOMS=3,4
40 : h1: HIGHEST ARG=d1,d2
41 : PRINT ARG=h1 FILE=colvar
42 : ```
43 :
44 : 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
45 : 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.
46 : Notice that you can also use this command with more than two arguments as illustrated below:
47 :
48 : ```plumed
49 : d1: DISTANCE ATOMS=1,2
50 : d2: DISTANCE ATOMS=3,4
51 : d3: DISTANCE ATOMS=5,6
52 : d4: DISTANCE ATOMS=7,8
53 : h1: HIGHEST ARG=d1,d2,d3,d4
54 : PRINT ARG=h1 FILE=colvar
55 : ```
56 :
57 : ## Using a single vector as input
58 :
59 : Instead of inputting multiple scalars you can input a single vector to this action instead as is illustrated below:
60 :
61 : ```plumed
62 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4
63 : h1: HIGHEST ARG=d
64 : PRINT ARG=h1 FILE=colvar
65 : ```
66 :
67 : The output from this action is a single scalar once again. This single scalar is equal to the largest element of the input vector.
68 :
69 : ## Using multiple vectors in input
70 :
71 : If you input multiple vectors with the same numbers of elements to this action, as shown below, the output will be a vector.
72 :
73 :
74 : ```plumed
75 : d1: DISTANCE ATOMS1=1,2 ATOMS2=3,4
76 : d2: DISTANCE ATOMS1=5,6 ATOMS2=7,8
77 : d3: DISTANCE ATOMS1=9,10 ATOMS2=11,12
78 : h2: HIGHEST ARG=d1,d2,d3
79 : PRINT ARG=h2 FILE=colvar
80 : ```
81 :
82 : The elements of the output vector here are determined by doing an elementwise comparison of the elements in the input vectors. In the above
83 : 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.
84 : 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.
85 : 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:
86 :
87 : $$
88 : h_i = \max_j v_i^{(j)}
89 : $$
90 :
91 : Notice that you can also use a combination of scalars and vectors in the input to this action as shown below:
92 :
93 : ```plumed
94 : c: CONSTANT VALUE=0.05
95 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4
96 : h: HIGHEST ARG=d,c
97 : PRINT ARG=h FILE=colvar
98 : ```
99 :
100 : 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
101 : 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
102 : than 0.05 nm then the corresponding value in the vector `h` is set equal to 0.05 nm.
103 :
104 : */
105 : //+ENDPLUMEDOC
106 :
107 : //+PLUMEDOC COLVAR HIGHEST_SCALAR
108 : /*
109 : Calculate the highest of a set of sclalar arguments
110 :
111 : \par Examples
112 :
113 : */
114 : //+ENDPLUMEDOC
115 :
116 : //+PLUMEDOC COLVAR HIGHEST_VECTOR
117 : /*
118 : Calculate the largest element in a vector of inputs
119 :
120 : \par Examples
121 :
122 : */
123 : //+ENDPLUMEDOC
124 :
125 : //+PLUMEDOC FUNCTION LOWEST
126 : /*
127 : This function can be used to find the lowest colvar by magnitude in a set.
128 :
129 : 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:
130 :
131 : ```plumed
132 : d1: DISTANCE ATOMS=1,2
133 : d2: DISTANCE ATOMS=3,4
134 : l1: LOWEST ARG=d1,d2
135 : PRINT ARG=l1 FILE=colvar
136 : ```
137 :
138 : 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
139 : 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.
140 : Notice that you can also use this command with more than two arguments as illustrated below:
141 :
142 : ```plumed
143 : d1: DISTANCE ATOMS=1,2
144 : d2: DISTANCE ATOMS=3,4
145 : d3: DISTANCE ATOMS=5,6
146 : d4: DISTANCE ATOMS=7,8
147 : l1: LOWEST ARG=d1,d2,d3,d4
148 : PRINT ARG=l1 FILE=colvar
149 : ```
150 :
151 : ## Using a single vector as input
152 :
153 : Instead of inputting multiple scalars you can input a single vector to this action instead as is illustrated below:
154 :
155 : ```plumed
156 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4
157 : l1: LOWEST ARG=d
158 : PRINT ARG=l1 FILE=colvar
159 : ```
160 :
161 : The output from this action is a single scalar once again. This single scalar is equal to the smallest element of the input vector.
162 :
163 : ## Using multiple vectors in input
164 :
165 : If you input multiple vectors with the same numbers of elements to this action, as shown below, the output will be a vector.
166 :
167 :
168 : ```plumed
169 : d1: DISTANCE ATOMS1=1,2 ATOMS2=3,4
170 : d2: DISTANCE ATOMS1=5,6 ATOMS2=7,8
171 : d3: DISTANCE ATOMS1=9,10 ATOMS2=11,12
172 : l2: LOWEST ARG=d1,d2,d3
173 : PRINT ARG=l2 FILE=colvar
174 : ```
175 :
176 : The elements of the output vector here are determined by doing an elementwise comparison of the elements in the input vectors. In the above
177 : 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.
178 : 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.
179 : 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:
180 :
181 : $$
182 : h_i = \min_j v_i^{(j)}
183 : $$
184 :
185 : Notice that you can also use a combination of scalars and vectors in the input to this action as shown below:
186 :
187 : ```plumed
188 : c: CONSTANT VALUE=0.5
189 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4
190 : h: LOWEST ARG=d,c
191 : PRINT ARG=h FILE=colvar
192 : ```
193 :
194 : 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
195 : 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
196 : han 0.5 nm then the corresponding value in the vector `h` is set equal to 0.5 nm.
197 :
198 : */
199 : //+ENDPLUMEDOC
200 :
201 : //+PLUMEDOC COLVAR LOWEST_SCALAR
202 : /*
203 : Calculate the lowest of a set of sclalar arguments
204 :
205 : \par Examples
206 :
207 : */
208 : //+ENDPLUMEDOC
209 :
210 : //+PLUMEDOC COLVAR LOWEST_VECTOR
211 : /*
212 : Calculate the lowest element in a vector of inputs
213 :
214 : \par Examples
215 :
216 : */
217 : //+ENDPLUMEDOC
218 :
219 334 : class Highest : public FunctionTemplateBase {
220 : private:
221 : bool min, scalar_out;
222 : public:
223 : void registerKeywords( Keywords& keys ) override ;
224 : void read( ActionWithArguments* action ) override;
225 0 : bool zeroRank() const override {
226 51 : return scalar_out;
227 : }
228 0 : bool doWithTasks() const override {
229 5341 : return !scalar_out;
230 : }
231 : void calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const override;
232 : };
233 :
234 : typedef FunctionShortcut<Highest> HighestShortcut;
235 : PLUMED_REGISTER_ACTION(HighestShortcut,"HIGHEST")
236 : PLUMED_REGISTER_ACTION(HighestShortcut,"LOWEST")
237 : typedef FunctionOfScalar<Highest> ScalarHighest;
238 : PLUMED_REGISTER_ACTION(ScalarHighest,"HIGHEST_SCALAR")
239 : PLUMED_REGISTER_ACTION(ScalarHighest,"LOWEST_SCALAR")
240 : typedef FunctionOfVector<Highest> VectorHighest;
241 : PLUMED_REGISTER_ACTION(VectorHighest,"HIGHEST_VECTOR")
242 : PLUMED_REGISTER_ACTION(VectorHighest,"LOWEST_VECTOR")
243 :
244 228 : void Highest::registerKeywords( Keywords& keys ) {
245 456 : if( keys.getDisplayName().find("LOWEST") ) {
246 176 : keys.setValueDescription("scalar","the lowest of the input values");
247 : } else {
248 280 : keys.setValueDescription("scalar","the highest of the input values");
249 : }
250 228 : }
251 :
252 53 : void Highest::read( ActionWithArguments* action ) {
253 53 : min=action->getName().find("LOWEST")!=std::string::npos;
254 53 : if( !min ) {
255 21 : plumed_assert( action->getName().find("HIGHEST")!=std::string::npos );
256 : }
257 130 : for(unsigned i=0; i<action->getNumberOfArguments(); ++i) {
258 77 : if( action->getPntrToArgument(i)->isPeriodic() ) {
259 0 : action->error("Cannot sort periodic values (check argument "+ action->getPntrToArgument(i)->getName() +")");
260 : }
261 : }
262 53 : scalar_out = action->getNumberOfArguments()==1;
263 53 : if( scalar_out && action->getPntrToArgument(0)->getRank()==0 ) {
264 0 : action->error("sorting a single scalar is trivial");
265 : }
266 53 : }
267 :
268 41979 : void Highest::calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const {
269 41979 : if( min ) {
270 41845 : vals[0] = *std::min_element(args.begin(), args.end());
271 41845 : derivatives(0,std::min_element(args.begin(), args.end()) - args.begin()) = 1;
272 : } else {
273 134 : vals[0] = *std::max_element(args.begin(), args.end());
274 134 : derivatives(0,std::max_element(args.begin(), args.end()) - args.begin()) = 1;
275 : }
276 41979 : }
277 :
278 : }
279 : }
280 :
281 :
|