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 "MoreThan.h"
23 : #include "FunctionShortcut.h"
24 : #include "FunctionOfScalar.h"
25 : #include "FunctionOfVector.h"
26 : #include "FunctionOfMatrix.h"
27 : #include "core/ActionRegister.h"
28 :
29 : #include <cmath>
30 :
31 : namespace PLMD {
32 : namespace function {
33 :
34 : //+PLUMEDOC FUNCTION MORE_THAN
35 : /*
36 : Use a switching function to determine how many of the input variables are more than a certain cutoff.
37 :
38 : This action takes one argument, $r$ and evaluates the following function:
39 :
40 : $$
41 : w(s) = 1 - s(r)
42 : $$
43 :
44 : In this equation $s(r)$ is one of the switching functions described in the documentation for the action [LESS_THAN](LESS_THAN.md).
45 : The output value $w$ is thus a number between 0 and 1 that tells you if the input value is greater than some cutoff. Furthermore,
46 : the value of $w$ smoothly from zero to one as the input value $r$ crosses the threshold of interest so any function of this value
47 : is differentiable.
48 :
49 : The following example, shows how we can apply the function above on the instantaneous value of the distance between atom 1 and 2.
50 : The MORE_THAN action here is used to determine whether the input distance is greater than 0.2 nm.
51 :
52 : ```plumed
53 : d: DISTANCE ATOMS=1,2
54 : b: MORE_THAN ARG=d SWITCH={RATIONAL R_0=0.2}
55 : ```
56 :
57 : You can use all the switching function options described in the documentation for [LESS_THAN](LESS_THAN.md) here in place of RATIONAL.
58 :
59 : ## Non rank zero arguments
60 :
61 : Instead of passing a single scalar in the input to the `MORE_THAN` action you can pass a single vector as shown here:
62 :
63 : ```plumed
64 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8
65 : b: MORE_THAN ARG=d SWITCH={RATIONAL R_0=0.2}
66 : ```
67 :
68 : The input to the `MORE_THAN` action here is a vector with four elements. The output from the action `b` is similarly
69 : a vector with four elements. In calculating the elements of this vector PLUMED applies the function described in the previous
70 : section on each of the distances in turn. The first element of `b` thus tells you if the distance between atoms 1 and 2 is between
71 : greater than 0.2 nm, the second element tells you if the distance between atoms 3 and 4 is greater than 0.2 nm and so on.
72 :
73 : You can use the commands in the above example input to evaluate the number of distances that greater than a threshold as follows:
74 :
75 : ```plumed
76 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8
77 : b: MORE_THAN ARG=d SWITCH={RATIONAL R_0=0.2}
78 : s: SUM ARG=b PERIODIC=NO
79 : PRINT ARG=s FILE=colvar
80 : ```
81 :
82 : The final scalar that is output here is evaluated using the following summation:
83 :
84 : $$
85 : s = \sum_i 1 - s(d_i)
86 : $$
87 :
88 : where the sum over $i$ here runs over the four distances in the above expression. This scalar tells you the number of distances that are
89 : more than 0.2 nm.
90 :
91 : Notice that you can do something similar with a matrix as input as shown below:
92 :
93 : ```plumed
94 : d: DISTANCE_MATRIX GROUPA=1-10 GROUPB=11-20
95 : b: MORE_THAN ARG=d SWITCH={RATIONAL R_0=0.2}
96 : s: SUM ARG=b PERIODIC=NO
97 : PRINT ARG=s FILE=colvar
98 : ```
99 :
100 : This input tells PLUMED to calculate the 100 distances between the atoms in the two input groups. The final value that is printed to the colvar file then
101 : tells you how many of these distances are greater than 0.2 nm.
102 :
103 : */
104 : //+ENDPLUMEDOC
105 :
106 : //+PLUMEDOC FUNCTION MORE_THAN_VECTOR
107 : /*
108 : Use a switching function to determine how many of elements in the input vector are more than a certain cutoff.
109 :
110 : \par Examples
111 :
112 : */
113 : //+ENDPLUMEDOC
114 :
115 : //+PLUMEDOC COLVAR MORE_THAN_MATRIX
116 : /*
117 : Transform all the elements of a matrix using a switching function that is one when the input value is larger than a threshold
118 :
119 : \par Examples
120 :
121 : */
122 : //+ENDPLUMEDOC
123 :
124 : typedef FunctionShortcut<MoreThan> MoreThanShortcut;
125 : PLUMED_REGISTER_ACTION(MoreThanShortcut,"MORE_THAN")
126 : typedef FunctionOfScalar<MoreThan> ScalarMoreThan;
127 : PLUMED_REGISTER_ACTION(ScalarMoreThan,"MORE_THAN_SCALAR")
128 : typedef FunctionOfVector<MoreThan> VectorMoreThan;
129 : PLUMED_REGISTER_ACTION(VectorMoreThan,"MORE_THAN_VECTOR")
130 : typedef FunctionOfMatrix<MoreThan> MatrixMoreThan;
131 : PLUMED_REGISTER_ACTION(MatrixMoreThan,"MORE_THAN_MATRIX")
132 :
133 248 : void MoreThan::registerKeywords(Keywords& keys) {
134 248 : keys.add("compulsory","NN","6","The n parameter of the switching function ");
135 248 : keys.add("compulsory","MM","0","The m parameter of the switching function; 0 implies 2*NN");
136 248 : keys.add("compulsory","D_0","0.0","The d_0 parameter of the switching function");
137 248 : keys.add("compulsory","R_0","The r_0 parameter of the switching function");
138 248 : keys.add("optional","SWITCH","This keyword is used if you want to employ an alternative to the continuous swiching function defined above. "
139 : "The following provides information on the \\ref switchingfunction that are available. "
140 : "When this keyword is present you no longer need the NN, MM, D_0 and R_0 keywords.");
141 248 : keys.addFlag("SQUARED",false,"is the input quantity the square of the value that you would like to apply the switching function to");
142 496 : keys.setValueDescription("scalar/vector/matrix","a function that is one if the if the input is more than a threshold");
143 248 : }
144 :
145 68 : void MoreThan::read( ActionWithArguments* action ) {
146 68 : if( action->getNumberOfArguments()!=1 ) {
147 0 : action->error("should only be one argument to more_than actions");
148 : }
149 68 : if( action->getPntrToArgument(0)->isPeriodic() ) {
150 0 : action->error("cannot use this function on periodic functions");
151 : }
152 :
153 :
154 : std::string sw,errors;
155 136 : action->parse("SWITCH",sw);
156 68 : if(sw.length()>0) {
157 68 : switchingFunction.set(sw,errors);
158 68 : if( errors.length()!=0 ) {
159 0 : action->error("problem reading SWITCH keyword : " + errors );
160 : }
161 : } else {
162 0 : int nn=6;
163 0 : int mm=0;
164 0 : double d0=0.0;
165 0 : double r0=0.0;
166 0 : action->parse("R_0",r0);
167 0 : if(r0<=0.0) {
168 0 : action->error("R_0 should be explicitly specified and positive");
169 : }
170 0 : action->parse("D_0",d0);
171 0 : action->parse("NN",nn);
172 0 : action->parse("MM",mm);
173 0 : switchingFunction.set(nn,mm,r0,d0);
174 : }
175 68 : action->log<<" using switching function with cutoff "<<switchingFunction.description()<<"\n";
176 68 : action->parseFlag("SQUARED",squared);
177 68 : if( squared ) {
178 6 : action->log<<" input quantity is square of quantity that switching function acts upon\n";
179 : }
180 68 : }
181 :
182 556662 : void MoreThan::calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const {
183 : plumed_dbg_assert( args.size()==1 );
184 556662 : if( squared ) {
185 469112 : vals[0] = 1.0 - switchingFunction.calculateSqr( args[0], derivatives(0,0) );
186 : } else {
187 87550 : vals[0] = 1.0 - switchingFunction.calculate( args[0], derivatives(0,0) );
188 : }
189 556662 : derivatives(0,0) = -args[0]*derivatives(0,0);
190 556662 : }
191 :
192 : }
193 : }
194 :
195 :
|