Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2017 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 "function/FunctionShortcut.h"
23 : #include "function/FunctionOfScalar.h"
24 : #include "function/FunctionOfVector.h"
25 : #include "core/ActionRegister.h"
26 : #include "function/FunctionTemplateBase.h"
27 :
28 : #include <cmath>
29 :
30 : namespace PLMD {
31 : namespace refdist {
32 :
33 : //+PLUMEDOC FUNCTION DIFFERENCE
34 : /*
35 : Calculate the differences between two scalars or vectors
36 :
37 : This action can be used to calculate the difference between two values. For example, if we want to calculate the difference
38 : between the distances between atoms 1 and 2 and 3 and 4 we can use an input like the one shown below:
39 :
40 : ```plumed
41 : d1: DISTANCE ATOMS=1,2
42 : d2: DISTANCE ATOMS=3,4
43 : diff: DIFFERENCE ARG=d1,d2
44 : PRINT ARG=diff FILE=colvar
45 : ```
46 :
47 : At first sight this action appears pointless as you can achieve the same result with the following input:
48 :
49 : ```plumed
50 : d1: DISTANCE ATOMS=1,2
51 : d2: DISTANCE ATOMS=3,4
52 : diff: CUSTOM ARG=d1,d2 FUNC=x-y PERIODIC=NO
53 : PRINT ARG=diff FILE=colvar
54 : ```
55 :
56 : However, this second example will not give an equivalent result to the following input:
57 :
58 : ```plumed
59 : t1: TORSION ATOMS=1,2,3,4
60 : t2: TORSION ATOMS=5,6,7,8
61 : diff: DIFFERENCE ARG=t1,t2
62 : PRINT ARG=diff FILE=colvar
63 : ```
64 :
65 : as the [CUSTOM](CUSTOM.md) command cannot caclulate differences between periodic input variables. In this case you have to
66 : use DIFFERENCE to ensure that the periodic boundary conditions are applied when the final difference is calculated.
67 :
68 : ## Difference from reference value/s
69 :
70 : The DIFFERENCE command is frequently used to determine the difference between the instantaneous value of a quantity and
71 : a reference value as illustrated in the example below:
72 :
73 : ```plumed
74 : ref_psi: CONSTANT VALUES=2.25029540
75 : t: TORSION ATOMS=1,2,3,4
76 : diff: DIFFERENCE ARG=t,ref_psi
77 : PRINT ARG=diff FILE=colvar
78 : ```
79 :
80 : You can also use this action to calculate the difference between the instaneous values of a vector of quantities and a
81 : reference vector as illustrated in the example below:
82 :
83 : ```plumed
84 : ref: CONSTANT VALUES=1.387980,1.126120,1.269380,1.321120,1.212420
85 : d: DISTANCES ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8 ATOMS5=9,10
86 : diff: DIFFERENCE ARG=d,ref
87 : PRINT ARG=diff FILE=colvar
88 : ```
89 :
90 : The output in this case is a five dimensional vector. Each element of this vector contains the difference between the
91 : corresponding elements of the two input vectors.
92 :
93 : Notice that you __cannot__ use a mixture of scalars and vectors in the input for this action. Only two values can be input
94 : to this action and these two input values __must__ have the same rank and the same number of elements.
95 :
96 : */
97 : //+ENDPLUMEDOC
98 :
99 : //+PLUMEDOC FUNCTION DIFFERENCE_SCALAR
100 : /*
101 : Calculate the differences between two scalars
102 :
103 : \par Examples
104 :
105 : */
106 : //+ENDPLUMEDOC
107 :
108 : //+PLUMEDOC FUNCTION DIFFERENCE_VECTOR
109 : /*
110 : Calculate the differences between the elements of two vectors
111 :
112 : \par Examples
113 :
114 : */
115 : //+ENDPLUMEDOC
116 :
117 :
118 1105 : class Difference : public function::FunctionTemplateBase {
119 : private:
120 : bool periodic;
121 : std::string min0, max0;
122 : public:
123 : void registerKeywords(Keywords& keys) override ;
124 : void read( ActionWithArguments* action ) override;
125 : void setPeriodicityForOutputs( ActionWithValue* action ) override;
126 : void calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const override;
127 : };
128 :
129 :
130 : typedef function::FunctionShortcut<Difference> DifferenceShortcut;
131 : PLUMED_REGISTER_ACTION(DifferenceShortcut,"DIFFERENCE")
132 : typedef function::FunctionOfScalar<Difference> ScalarDifference;
133 : PLUMED_REGISTER_ACTION(ScalarDifference,"DIFFERENCE_SCALAR")
134 : typedef function::FunctionOfVector<Difference> VectorDifference;
135 : PLUMED_REGISTER_ACTION(VectorDifference,"DIFFERENCE_VECTOR")
136 :
137 737 : void Difference::registerKeywords(Keywords& keys) {
138 1474 : keys.setValueDescription("scalar/vector","a function that measures the difference");
139 737 : }
140 :
141 184 : void Difference::read( ActionWithArguments* action ) {
142 184 : if( action->getNumberOfArguments()!=2 ) {
143 0 : action->error("should be two arguments to this action");
144 : }
145 184 : if( action->getPntrToArgument(0)->getRank()==action->getPntrToArgument(1)->getRank() ) {
146 51 : std::vector<unsigned> shape( action->getPntrToArgument(0)->getShape() );
147 61 : for(unsigned i=0; i<shape.size(); ++i) {
148 10 : if( shape[i]!=action->getPntrToArgument(1)->getShape()[i] ) {
149 0 : action->error("shapes of input actions do not match");
150 : }
151 : }
152 : }
153 :
154 184 : periodic=false;
155 184 : if( action->getPntrToArgument(0)->isPeriodic() ) {
156 43 : periodic=true;
157 43 : action->getPntrToArgument(0)->getDomain( min0, max0 );
158 43 : if( !action->getPntrToArgument(1)->isConstant() && !action->getPntrToArgument(1)->isPeriodic() ) {
159 0 : action->error("period for input variables " + action->getPntrToArgument(0)->getName() + " and " + action->getPntrToArgument(1)->getName() + " should be the same 0");
160 : }
161 43 : if( !action->getPntrToArgument(1)->isConstant() ) {
162 : std::string min1, max1;
163 1 : action->getPntrToArgument(1)->getDomain( min1, max1 );
164 1 : if( min0!=min0 || max0!=max1 ) {
165 0 : action->error("domain for input variables should be the same");
166 : }
167 : } else {
168 42 : action->getPntrToArgument(1)->setDomain( min0, max0 );
169 : }
170 141 : } else if( action->getPntrToArgument(1)->isPeriodic() ) {
171 0 : periodic=true;
172 0 : action->getPntrToArgument(1)->getDomain( min0, max0 );
173 0 : if( !action->getPntrToArgument(0)->isConstant() ) {
174 0 : action->error("period for input variables " + action->getPntrToArgument(0)->getName() + " and " + action->getPntrToArgument(1)->getName() + " should be the same 1");
175 : } else {
176 0 : action->getPntrToArgument(0)->setDomain( min0, max0 );
177 : }
178 : }
179 184 : }
180 :
181 184 : void Difference::setPeriodicityForOutputs( ActionWithValue* action ) {
182 184 : if( periodic ) {
183 43 : action->setPeriodic( min0, max0 );
184 : } else {
185 141 : action->setNotPeriodic();
186 : }
187 184 : }
188 :
189 2877849 : void Difference::calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const {
190 : plumed_dbg_assert( args.size()==2 );
191 2877849 : vals[0] = action->getPntrToArgument(0)->difference( args[1], args[0] );
192 2877849 : derivatives(0,0) = 1.0;
193 2877849 : derivatives(0,1)=-1;
194 2877849 : }
195 :
196 : }
197 : }
198 :
199 :
|