Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-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 "Combine.h"
23 : #include "FunctionTemplateBase.h"
24 : #include "FunctionShortcut.h"
25 : #include "FunctionOfScalar.h"
26 : #include "FunctionOfVector.h"
27 : #include "FunctionOfMatrix.h"
28 : #include "core/ActionRegister.h"
29 :
30 : namespace PLMD {
31 : namespace function {
32 :
33 : //+PLUMEDOC FUNCTION COMBINE
34 : /*
35 : Calculate a polynomial combination of a set of other variables.
36 :
37 : This action takes in $N_{arg}$ arguments ($x_i$) and computes the following function of them:
38 :
39 : \f[
40 : C=\sum_{i=1}^{N_{arg}} c_i (x_i-a_i)^{p_i}
41 : \f]
42 :
43 : The $c_i$, $a_i$ and $p_i$ values in this expression are provided through the COEFFICIENTS, PARAMETERS and POWERS keywords respectively.
44 : The following example illustrates how this action can be used to calculate and print the square of the distance between atom 1 and atom 2.
45 :
46 : ```plumed
47 : d: DISTANCE ATOMS=1,2 COMPONENTS
48 : c: COMBINE ARG=d.x,d.y,d.z COEFFICIENTS=1,1,1 PARAMETERS=0,0,0 POWERS=2,2,2 PERIODIC=NO
49 : PRINT ARG=c FILE=colvar
50 : ```
51 :
52 : Notice that if the COEFFICIENTS keyword is absent all the $c_i$ values are set equal to 1.
53 : Furthermore, if the PARAMETERS keyword is absent all the $a_i$ values are set equal to 0.
54 : We can thus make use of these defaults and rewrite the input above as:
55 :
56 : ```plumed
57 : d: DISTANCE ATOMS=1,2 COMPONENTS
58 : c: COMBINE ARG=d.x,d.y,d.z POWERS=2,2,2 PERIODIC=NO
59 : PRINT ARG=c FILE=colvar
60 : ```
61 :
62 : Notice that we cannot remove the POWERS keyword here as if it is absent all the $p_i$ values are set equal to 1.
63 :
64 : ## Periodic arguments
65 :
66 : The COMBINE action is not able to predict the periodic domain for the function that is computed from the arguments
67 : automatically. The user is thus forced to specify it explicitly. Use PERIODIC=NO if the resulting variable is not periodic,
68 : and PERIODIC=A,B where A and B are the two boundaries for the periodic domain if the resulting variable is periodic.
69 : The following provides an example where the output from combine has a periodic domain. In this input we are taking the
70 : cube of a dihedral angle. The dihedral angle has a periodic domain that runs from $-\pi$ to $\pi$. The cube of this variable
71 : thus has a periodic domain that runs from $-\pi^3$ to $\pi^3$ as indicated in the following input.
72 :
73 : ```plumed
74 : t: TORSION ATOMS=1,3,5,7
75 : #c: COMBINE ARG=t POWERS=3 PERIODIC=-31.0062766802998,31.0062766802998
76 : c: COMBINE ARG=t POWERS=3 PERIODIC=-pi^3,pi^3
77 : PRINT ARG=c FILE=colvar
78 : ```
79 :
80 : ## Vector arguments
81 :
82 : The two examples in the previous section demonstrate how to use the COMBINE action with scalar arguments. However, you can also
83 : pass arguments to this action that have a rank greater than zero. For example, in the example below COMBINE accepts three
84 : vectors with 4 elements in input:
85 :
86 : ```plumed
87 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8 COMPONENTS
88 : c: COMBINE ARG=d.x,d.y,d.z POWERS=2,2,2 PERIODIC=NO
89 : PRINT ARG=c FILE=colvar
90 : ```
91 :
92 : The output from the COMBINE action here is also a vector with four elements. The first element of this vector is the square of the
93 : distance betwen atoms 1 and 2, the secton is the square of the distance between atoms 3 and 4 and so on.
94 :
95 : The COMBINE action can also take a mixture of scalars and vectors in input. The following input illustrates an
96 : COMBINE action that takes vectors and scalars in input.
97 :
98 : ```plumed
99 : p: CONSTANT VALUE=2
100 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8
101 : c: COMBINE ARG=d,p COEFFICIENTS=4,-1 POWERS=2.5,1 PERIODIC=NO
102 : PRINT ARG=c FILE=colvar
103 : ```
104 :
105 : The elements of the vector that is calculated by the COMBINE action here are given by:
106 :
107 : $$
108 : c_i = 4d_i^{2.5} - 2
109 : $$
110 :
111 : The $d_i$ in this expression are the distances that were calculated by the DISTANCE action. The 2 comes
112 : from the scalar `p` that passed to the ARG action in input. As a single scalar is passed the same number is
113 : used when calculating all 4 elements of the output vector. In other words, the scalar behaves as if it is a
114 : vector with four components that all have the same value.
115 :
116 : Lastly, notice that if you pass a single vector in input to COMBINE as in the following example, the output is still a vector:
117 :
118 : ```plumed
119 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8
120 : c: COMBINE ARG=d COEFFICIENTS=4 POWERS=2.5 PARAMETERS=0.5 PERIODIC=NO
121 : PRINT ARG=c FILE=colvar
122 : ```
123 :
124 : To calculate the 4-dimensional output by the COMBINE action here we subtract 0.5 from each of the input distances, raise
125 : the result from this subtraction to the power 2.5 and then multiply the result by 4.
126 :
127 : If you want to calculate a linear combination of the elements of a vector using the formula at the top of the page you should use
128 : the [CUSTOM](CUSTOM.md) action to transform all the components of the input vector. You can then add all the results from these
129 : transformations together using [SUM](SUM.md).
130 :
131 : ## Matrix arguments
132 :
133 : You can also use matrices in the input to the COMBINE action as illustrated below:
134 :
135 : ```plumed
136 : d: DISTANCE_MATRIX GROUPA=1,2 GROUPB=3,4,5 COMPONENTS
137 : c: COMBINE ARG=d.x,d.y,d.z POWERS=2,2,2 PERIODIC=NO
138 : PRINT ARG=c FILE=colvar
139 : ```
140 :
141 : The input to the combine action here consists of three $2\times3$ matrices. The output is thus a $2\times3$ matrix that contains the squares of the
142 : distances between the atoms in GROUPA and the atoms in GROUPB. Notice that all the input matrices must have the same size as the elements of the final
143 : matrix are calculated by applying the formula in the first section of this input to each set of elements to the input matrices in turn.
144 :
145 : The input to this action can be a combination of matrices and scalars. If your input arguments are an $N\times M$ matrix and a scalar the scalar is treated as if
146 : it is a $N\times M$ matrix which has all its elements equal to the input scalar. You __cannot__ use a mixture of vectors and matrices in the input to this action.
147 :
148 : Furthermore, if you pass a single matrix to COMBINE the output is a matrix. To calculate a linear combination of all the elements in a matrix using the formula at the top of the page you should use
149 : the [CUSTOM](CUSTOM.md) action to transform all the components of the input vector. You can then add all the results from these transformations together using [SUM](SUM.md).
150 :
151 : */
152 : //+ENDPLUMEDOC
153 :
154 : //+PLUMEDOC FUNCTION COMBINE_SCALAR
155 : /*
156 : Calculate a polynomial combination of a set of other variables.
157 :
158 : \par Examples
159 :
160 : */
161 : //+ENDPLUMEDOC
162 :
163 : //+PLUMEDOC FUNCTION COMBINE_VECTOR
164 : /*
165 : Add together the elements of a set of vectors elementwise
166 :
167 : \par Examples
168 :
169 : */
170 : //+ENDPLUMEDOC
171 :
172 : //+PLUMEDOC COLVAR COMBINE_MATRIX
173 : /*
174 : Calculate the sum of a number of matrices
175 :
176 : \par Examples
177 :
178 : */
179 : //+ENDPLUMEDOC
180 :
181 : typedef FunctionShortcut<Combine> CombineShortcut;
182 : PLUMED_REGISTER_ACTION(CombineShortcut,"COMBINE")
183 : typedef FunctionOfScalar<Combine> ScalarCombine;
184 : PLUMED_REGISTER_ACTION(ScalarCombine,"COMBINE_SCALAR")
185 : typedef FunctionOfVector<Combine> VectorCombine;
186 : PLUMED_REGISTER_ACTION(VectorCombine,"COMBINE_VECTOR")
187 : typedef FunctionOfMatrix<Combine> MatrixCombine;
188 : PLUMED_REGISTER_ACTION(MatrixCombine,"COMBINE_MATRIX")
189 :
190 1072 : void Combine::registerKeywords(Keywords& keys) {
191 1072 : keys.use("PERIODIC");
192 1072 : keys.add("compulsory","COEFFICIENTS","1.0","the coefficients of the arguments in your function");
193 1072 : keys.add("compulsory","PARAMETERS","0.0","the parameters of the arguments in your function");
194 1072 : keys.add("compulsory","POWERS","1.0","the powers to which you are raising each of the arguments in your function");
195 1072 : keys.addFlag("NORMALIZE",false,"normalize all the coefficients so that in total they are equal to one");
196 2144 : keys.setValueDescription("scalar/vector/matrix","a linear compbination");
197 1072 : }
198 :
199 306 : void Combine::read( ActionWithArguments* action ) {
200 306 : coefficients.resize( action->getNumberOfArguments() );
201 306 : parameters.resize( action->getNumberOfArguments() );
202 306 : powers.resize( action->getNumberOfArguments() );
203 611 : parseVector(action,"COEFFICIENTS",coefficients);
204 305 : if(coefficients.size()!=static_cast<unsigned>(action->getNumberOfArguments())) {
205 0 : action->error("Size of COEFFICIENTS array should be the same as number for arguments");
206 : }
207 609 : parseVector(action,"PARAMETERS",parameters);
208 304 : if(parameters.size()!=static_cast<unsigned>(action->getNumberOfArguments())) {
209 0 : action->error("Size of PARAMETERS array should be the same as number for arguments");
210 : }
211 607 : parseVector(action,"POWERS",powers);
212 303 : if(powers.size()!=static_cast<unsigned>(action->getNumberOfArguments())) {
213 0 : action->error("Size of POWERS array should be the same as number for arguments");
214 : }
215 :
216 303 : parseFlag(action,"NORMALIZE",normalize);
217 303 : if(normalize) {
218 : double n=0.0;
219 43 : for(unsigned i=0; i<coefficients.size(); i++) {
220 38 : n+=coefficients[i];
221 : }
222 43 : for(unsigned i=0; i<coefficients.size(); i++) {
223 38 : coefficients[i]*=(1.0/n);
224 : }
225 : }
226 :
227 303 : action->log.printf(" with coefficients:");
228 1506 : for(unsigned i=0; i<coefficients.size(); i++) {
229 1203 : action->log.printf(" %f",coefficients[i]);
230 : }
231 303 : action->log.printf("\n with parameters:");
232 1506 : for(unsigned i=0; i<parameters.size(); i++) {
233 1203 : action->log.printf(" %f",parameters[i]);
234 : }
235 303 : action->log.printf("\n and powers:");
236 1506 : for(unsigned i=0; i<powers.size(); i++) {
237 1203 : action->log.printf(" %f",powers[i]);
238 : }
239 303 : action->log.printf("\n");
240 303 : }
241 :
242 4369200 : void Combine::calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const {
243 4369200 : vals[0]=0.0;
244 10983391 : for(unsigned i=0; i<coefficients.size(); ++i) {
245 6614191 : double cv = action->difference( i, parameters[i], args[i] );
246 6614191 : vals[0] += coefficients[i]*pow( cv, powers[i] );
247 6614191 : derivatives(0,i) = coefficients[i]*powers[i]*pow(cv,powers[i]-1.0);
248 : }
249 4369200 : }
250 :
251 : }
252 : }
253 :
254 :
|