All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
HistogramBead.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 "HistogramBead.h"
23 #include <vector>
24 #include <limits>
25 #include "Tools.h"
26 #include "Keywords.h"
27 
28 namespace PLMD{
29 
30 //+PLUMEDOC INTERNAL histogrambead
31 /*
32 A function that can be used to calculate whether quantities are between fixed upper and lower bounds.
33 
34 If we have multiple instances of a variable we can estimate the probability distribution (pdf)
35 for that variable using a process called kernel density estimation:
36 
37 \f[
38 P(s) = \sum_i K\left( \frac{s - s_i}{w} \right)
39 \f]
40 
41 In this equation \f$K\f$ is a symmetric funciton that must integrate to one that is often
42 called a kernel function and \f$w\f$ is a smearing parameter. From a pdf calculated using
43 kernel density estimation we can calculate the number/fraction of values between an upper and lower
44 bound using:
45 
46 \f[
47 w(s) = \int_a^b \sum_i K\left( \frac{s - s_i}{w} \right)
48 \f]
49 
50 All the input to calculate a quantity like \f$w(s)\f$ is generally provided through a single
51 keyword that will have the following form:
52 
53 KEYWORD={TYPE UPPER=\f$a\f$ LOWER=\f$b\f$ SMEAR=\f$\frac{w}{b-a}\f$}
54 
55 This will calculate the number of values between \f$a\f$ and \f$b\f$. To calculate
56 the fraction of values you add the word NORM to the input specification. If the
57 function keyword SMEAR is not present \f$w\f$ is set equal to \f$0.5(b-a)\f$. Finally,
58 type should specify one of the kernel types that is present in plumed. These are listed
59 in the table below:
60 
61 <table align=center frame=void width=95%% cellpadding=5%%>
62 <tr>
63 <td> TYPE </td> <td> FUNCTION </td>
64 </tr> <tr>
65 <td> GAUSSIAN </td> <td> \f$\frac{1}{\sqrt{2\pi}w} \exp\left( -\frac{(s-s_i)^2}{2w^2} \right)\f$ </td>
66 </tr> <tr>
67 <td> TRIANGULAR </td> <td> \f$ \frac{1}{2w} \left( 1. - \left| \frac{s-s_i}{w} \right| \right) \quad \frac{s-s_i}{w}<1 \f$ </td>
68 </tr>
69 </table>
70 
71 Some keywords can also be used to calculate a descretized version of the histogram. That
72 is to say the number of values between \f$a\f$ and \f$b\f$, the number of values between
73 \f$b\f$ and \f$c\f$ and so on. A keyword that specifies this sort of calculation would look
74 something like
75 
76 KEYWORD={TYPE UPPER=\f$a\f$ LOWER=\f$b\f$ NBINS=\f$n\f$ SMEAR=\f$\frac{w}{n(b-a)}\f$}
77 
78 This specification would calculate the following vector of quantities:
79 
80 \f[
81 w_j(s) = \int_{a + \frac{j-1}{n}(b-a)}^{a + \frac{j}{n}(b-a)} \sum_i K\left( \frac{s - s_i}{w} \right)
82 \f]
83 
84 */
85 //+ENDPLUMEDOC
86 
88  keys.add("compulsory","LOWER","the lower boundary for this particular bin");
89  keys.add("compulsory","UPPER","the upper boundary for this particular bin");
90  keys.add("compulsory","SMEAR","0.5","the ammount to smear the Gaussian for each value in the distribution");
91 }
92 
94 init(false),
95 lowb(0.0),
96 highb(0.0),
97 width(0.0),
98 type(gaussian),
99 periodicity(unset),
100 min(0.0),
101 max(0.0),
102 max_minus_min(0.0),
103 inv_max_minus_min(0.0)
104 {
105 }
106 
107 std::string HistogramBead::description() const {
108  std::ostringstream ostr;
109  ostr<<"betweeen "<<lowb<<" and "<<highb<<" width of gaussian window equals "<<width;
110  return ostr.str();
111 }
112 
113 void HistogramBead::generateBins( const std::string& params, const std::string& dd, std::vector<std::string>& bins ){
114  if( dd.size()!=0 && params.find(dd)==std::string::npos) return;
115  std::vector<std::string> data=Tools::getWords(params);
116  plumed_massert(data.size()>=1,"There is no input for this keyword");
117 
118  std::string name=data[0];
119 
120  unsigned nbins; std::vector<double> range(2); std::string smear;
121  bool found_nb=Tools::parse(data,dd+"NBINS",nbins);
122  plumed_massert(found_nb,"Number of bins in histogram not found");
123  bool found_r=Tools::parse(data,dd+"LOWER",range[0]);
124  plumed_massert(found_r,"Lower bound for histogram not specified");
125  found_r=Tools::parse(data,dd+"UPPER",range[1]);
126  plumed_massert(found_r,"Upper bound for histogram not specified");
127  plumed_massert(range[0]<range[1],"Range specification is dubious");
128  bool found_b=Tools::parse(data,dd+"SMEAR",smear);
129  if(!found_b){ Tools::convert(0.5,smear); }
130 
131  std::string lb,ub; double delr = ( range[1]-range[0] ) / static_cast<double>( nbins );
132  for(unsigned i=0;i<nbins;++i){
133  Tools::convert( range[0]+i*delr, lb );
134  Tools::convert( range[0]+(i+1)*delr, ub );
135  bins.push_back( name + " " + dd + "LOWER=" + lb + " " + dd + "UPPER=" + ub + " " + dd + "SMEAR=" + smear );
136  }
137  plumed_assert(bins.size()==nbins);
138 }
139 
140 void HistogramBead::set( const std::string& params, const std::string& dd, std::string& errormsg ){
141  if( dd.size()!=0 && params.find(dd)==std::string::npos) return;
142  std::vector<std::string> data=Tools::getWords(params);
143  if(data.size()<1) errormsg="No input has been specified";
144 
145  std::string name=data[0];
146  if(name=="GAUSSIAN") type=gaussian;
147  else if(name=="TRIANGULAR") type=triangular;
148  else plumed_merror("cannot understand kernel type " + name );
149 
150  double smear;
151  bool found_r=Tools::parse(data,dd+"LOWER",lowb);
152  if( !found_r ) errormsg="Lower bound has not been specified use LOWER";
153  found_r=Tools::parse(data,dd+"UPPER",highb);
154  if( !found_r ) errormsg="Upper bound has not been specified use UPPER";
155  if( lowb>=highb ) errormsg="Lower bound is higher than upper bound";
156 
157  smear=0.5; Tools::parse(data,dd+"SMEAR",smear);
158  width=smear*(highb-lowb); init=true;
159 }
160 
161 void HistogramBead::set( double l, double h, double w){
162  init=true; lowb=l; highb=h; width=w;
163 }
164 
165 void HistogramBead::setKernelType( const std::string& ktype ){
166  if(ktype=="gaussian") type=gaussian;
167  else if(ktype=="triangular") type=triangular;
168  else plumed_merror("cannot understand kernel type " + ktype );
169 }
170 
171 double HistogramBead::calculate( double x, double& df ) const {
172  const double pi=3.141592653589793238462643383279502884197169399375105820974944592307;
173  plumed_dbg_assert(init && periodicity!=unset );
174  double lowB, upperB, f;
175  if( type==gaussian ){
176  lowB = difference( x, lowb ) / ( sqrt(2.0) * width );
177  upperB = difference( x, highb ) / ( sqrt(2.0) * width );
178  df = ( exp( -lowB*lowB ) - exp( -upperB*upperB ) ) / ( sqrt(2*pi)*width );
179  f = 0.5*( erf( upperB ) - erf( lowB ) );
180  } else if( type==triangular ){
181  lowB = ( difference( x, lowb ) / width );
182  upperB = ( difference( x, highb ) / width );
183  df=0;
184  if( fabs(lowB)<1. ) df = 1 - fabs(lowB) / width;
185  if( fabs(upperB)<1. ) df -= fabs(upperB) / width;
186  if (upperB<=-1. || lowB >=1.){
187  f=0.;
188  } else {
189  double ia, ib;
190  if( lowB>-1.0 ){ ia=lowB; }else{ ia=-1.0; }
191  if( upperB<1.0 ){ ib=upperB; } else{ ib=1.0; }
192  f = (ib*(2.-fabs(ib))-ia*(2.-fabs(ia)))*0.5;
193  }
194  } else {
195  plumed_merror("function type does not exist");
196  }
197  return f;
198 }
199 
200 }
void setKernelType(const std::string &ktype)
static bool convert(const std::string &str, double &t)
Convert a string to a double, reading it.
Definition: Tools.cpp:74
enum PLMD::HistogramBead::@3 periodicity
static void registerKeywords(Keywords &keys)
static bool parse(std::vector< std::string > &line, const std::string &key, T &val)
Find a keyword on the input line, eventually deleting it, and saving its value to val...
Definition: Tools.h:127
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
static void generateBins(const std::string &params, const std::string &dd, std::vector< std::string > &bins)
void const char * range
Definition: Matrix.h:42
This class holds the keywords and their documentation.
Definition: Keywords.h:36
std::string description() const
static std::vector< std::string > getWords(const std::string &line, const char *sep=NULL, int *parlevel=NULL, const char *parenthesis="{")
Split the line in words using separators.
Definition: Tools.cpp:112
void const char const char int double int double double int int double int double * w
Definition: Matrix.h:42
enum PLMD::HistogramBead::@2 type
void set(const std::string &params, const std::string &dd, std::string &errormsg)
const double pi(3.141592653589793238462643383279502884197169399375105820974944592307)
PI.
double calculate(double x, double &df) const
double difference(const double &d1, const double &d2) const
Definition: HistogramBead.h:92