All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
SwitchingFunction.cpp
Go to the documentation of this file.
1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2  Copyright (c) 2013 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-code.org for more information.
6 
7  This file is part of plumed, version 2.0.
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 "SwitchingFunction.h"
23 #include "Tools.h"
24 #include "Keywords.h"
25 #include <vector>
26 #include <limits>
27 
28 using namespace std;
29 namespace PLMD{
30 
31 //+PLUMEDOC INTERNAL switchingfunction
32 /*
33 Functions that measure whether values are less than a certain quantity.
34 
35 Switching functions \f$s(r)\f$ take a minimum of one input parameter \f$d_0\f$.
36 For \f$r \le d_0 \quad s(r)=1.0\f$ while for \f$r > d_0\f$ the function decays smoothly to 0.
37 The various switching functions available in plumed differ in terms of how this decay is performed.
38 
39 Where there is an accepted convention in the literature (e.g. \ref COORDINATION) on the form of the
40 switching function we use the convention as the default. However, the flexibility to use different
41 switching functions is always present generally through a single keyword. This keyword generally
42 takes an input with the following form:
43 
44 \verbatim
45 KEYWORD={TYPE <list of parameters>}
46 \endverbatim
47 
48 The following table contains a list of the various switching functions that are available in plumed 2
49 together with an example input.
50 
51 <table align=center frame=void width=95%% cellpadding=5%%>
52 <tr>
53 <td> TYPE </td> <td> FUNCTION </td> <td> EXAMPLE INPUT </td> <td> DEFAULT PARAMETERS </td>
54 </tr> <tr> <td>RATIONAL </td> <td>
55 \f$
56 s(r)=\frac{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{n} }{ 1 - \left(\frac{ r - d_0 }{ r_0 }\right)^{m} }
57 \f$
58 </td> <td>
59 {RATIONAL R_0=\f$r_0\f$ D_0=\f$d_0\f$ NN=\f$n\f$ MM=\f$m\f$}
60 </td> <td> \f$d_0=0.0\f$, \f$n=6\f$, \f$m=12\f$ </td>
61 </tr> <tr>
62 <td> EXP </td> <td>
63 \f$
64 s(r)=\exp\left(-\frac{ r - d_0 }{ r_0 }\right)
65 \f$
66 </td> <td>
67 {EXP R_0=\f$r_0\f$ D_0=\f$d_0\f$}
68 </td> <td> \f$d_0=0.0\f$ </td>
69 </tr> <tr>
70 <td> GAUSSIAN </td> <td>
71 \f$
72 s(r)=\exp\left(-\frac{ (r - d_0)^2 }{ 2r_0^2 }\right)
73 \f$
74 </td> <td>
75 {GAUSSIAN R_0=\f$r_0\f$ D_0=\f$d_0\f$}
76 </td> <td> \f$d_0=0.0\f$ </td>
77 </tr> <tr>
78 <td> SMAP </td> <td>
79 \f$
80 s(r) = \left[ 1 + ( 2^{a/b} -1 )\left( \frac{r-d_0}{r_0} \right)\right]^{-b/a}
81 \f$
82 </td> <td>
83 {SMAP R_0=\f$r_0\f$ D_0=\f$d_0\f$ A=\f$a\f$ B=\f$b\f$}
84 </td> <td> \f$d_0=0.0\f$ </td>
85 </tr>
86 </table>
87 
88 For all the switching functions in the above table one can also specify a further (optional) parameter using the parameter
89 keyword D_MAX to assert that for \f$r>d_{\textrm{max}}\f$ the switching function can be assumed equal to zero.
90 */
91 //+ENDPLUMEDOC
92 
93 void SwitchingFunction::registerKeywords( Keywords& keys ){
94  keys.add("compulsory","R_0","the value of R_0 in the switching function");
95  keys.add("compulsory","D_0","0.0","the value of D_0 in the switching function");
96  keys.add("optional","D_MAX","the value at which the switching function can be assumed equal to zero");
97  keys.add("compulsory","NN","6","the value of n in the switching function (only needed for TYPE=RATIONAL)");
98  keys.add("compulsory","MM","12","the value of m in the switching function (only needed for TYPE=RATIONAL)");
99  keys.add("compulsory","A","the value of a in the switching funciton (only needed for TYPE=SMAP)");
100  keys.add("compulsory","B","the value of b in the switching funciton (only needed for TYPE=SMAP)");
101 }
102 
103 void SwitchingFunction::set(const std::string & definition,std::string& errormsg){
104  vector<string> data=Tools::getWords(definition);
105  if( data.size()<1 ) errormsg="missing all input for switching function";
106  string name=data[0];
107  data.erase(data.begin());
108  invr0=0.0;
109  d0=0.0;
110  dmax=std::numeric_limits<double>::max();
111  init=true;
112 
113  double r0;
114  bool found_r0=Tools::parse(data,"R_0",r0);
115  if(!found_r0) errormsg="R_0 is required";
116  invr0=1.0/r0;
117  Tools::parse(data,"D_0",d0);
118  Tools::parse(data,"D_MAX",dmax);
119 
120  if(name=="RATIONAL"){
121  type=spline;
122  nn=6;
123  mm=12;
124  Tools::parse(data,"NN",nn);
125  Tools::parse(data,"MM",mm);
126  } else if(name=="SMAP"){
127  type=smap;
128  Tools::parse(data,"A",a);
129  Tools::parse(data,"B",b);
130  c=pow(2., static_cast<double>(a)/static_cast<double>(b) ) - 1;
131  d = -static_cast<double>(b) / static_cast<double>(a);
132  } else if(name=="EXP") type=exponential;
133  else if(name=="GAUSSIAN") type=gaussian;
134  else errormsg="cannot understand switching function type '"+name+"'";
135  if( !data.empty() ){
136  errormsg="found the following rogue keywords in switching function input : ";
137  for(unsigned i=0;i<data.size();++i) errormsg = errormsg + data[i] + " ";
138  }
139 }
140 
141 std::string SwitchingFunction::description() const {
142  std::ostringstream ostr;
143  ostr<<1./invr0<<". Using ";
144  if(type==spline){
145  ostr<<"rational";
146  } else if(type==exponential){
147  ostr<<"exponential";
148  } else if(type==gaussian){
149  ostr<<"gaussian";
150  } else if(type==smap){
151  ostr<<"smap";
152  } else{
153  plumed_merror("Unknown switching function type");
154  }
155  ostr<<" swiching function with parameters d0="<<d0;
156  if(type==spline){
157  ostr<<" nn="<<nn<<" mm="<<mm;
158  } else if(type==smap){
159  ostr<<" a="<<a<<" b="<<b;
160  }
161  return ostr.str();
162 }
163 
164 double SwitchingFunction::calculate(double distance,double&dfunc)const{
165  plumed_massert(init,"you are trying to use an unset SwitchingFunction");
166  if(distance>dmax){
167  dfunc=0.0;
168  return 0.0;
169  }
170  const double rdist = (distance-d0)*invr0;
171  double result;
172  if(rdist<=0.){
173  result=1.;
174  dfunc=0.0;
175  }else{
176  if(type==smap){
177  double sx=c*pow( rdist, a );
178  result=pow( 1.0 + sx, d );
179  dfunc=-b*sx/rdist*result/(1.0+sx);
180  } else if(type==spline){
181  if(2*nn==mm){
182 // if 2*N==M, then (1.0-rdist^N)/(1.0-rdist^M) = 1.0/(1.0+rdist^N)
183  double rNdist=Tools::fastpow(rdist,nn-1);
184  double iden=1.0/(1+rNdist*rdist);
185  dfunc = -nn*rNdist*iden*iden;
186  result = iden;
187  } else {
188  if(rdist>(1.-100.0*epsilon) && rdist<(1+100.0*epsilon)){
189  result=nn/mm;
190  dfunc=0.5*nn*(nn-mm)/mm;
191  }else{
192  double rNdist=Tools::fastpow(rdist,nn-1);
193  double rMdist=Tools::fastpow(rdist,mm-1);
194  double num = 1.-rNdist*rdist;
195  double iden = 1./(1.-rMdist*rdist);
196  double func = num*iden;
197  result = func;
198  dfunc = ((-nn*rNdist*iden)+(func*(iden*mm)*rMdist));
199  }
200  }
201  }else if(type==exponential){
202  result=exp(-rdist);
203  dfunc=-result;
204  }else if(type==gaussian){
205  result=exp(-0.5*rdist*rdist);
206  dfunc=-rdist*result;
207  }else plumed_merror("Unknown switching function type");
208 // this is for the chain rule:
209  dfunc*=invr0;
210 // this is because calculate() sets dfunc to the derivative divided times the distance.
211 // (I think this is misleading and I would like to modify it - GB)
212  dfunc/=distance;
213  }
214  return result;
215 }
216 
217 SwitchingFunction::SwitchingFunction():
218  init(false),
219  type(spline),
220  nn(6),
221  mm(12),
222  invr0(0.0),
223  d0(0.0),
224  dmax(0.0)
225 {
226 }
227 
228 void SwitchingFunction::set(int nn,int mm,double r0,double d0){
229  init=true;
230  type=spline;
231  this->nn=nn;
232  this->mm=mm;
233  this->invr0=1.0/r0;
234  this->d0=d0;
235  this->dmax=d0+r0*pow(0.00001,1./(nn-mm));
236 }
237 
239  return 1./invr0;
240 }
241 
243  return d0;
244 }
245 
246 }
247 
248 
249 
const double epsilon
void set(int nn, int mm, double r_0, double d_0)
STL namespace.
void add(const std::string &t, const std::string &k, const std::string &d)
Add a new keyword of type t with name k and description d.
Definition: Keywords.cpp:167
This class holds the keywords and their documentation.
Definition: Keywords.h:36
void const char const char int double * a
Definition: Matrix.h:42
enum PLMD::SwitchingFunction::@7 type