All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
CubicInterpolation.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 "CubicInterpolation.h"
23 
24 namespace PLMD {
25 
26 CInterpolation::CInterpolation( const std::vector<unsigned>& dd, const std::vector<double>& fmin, const std::vector<double>& fmax ) :
27 bold(0)
28 {
29  plumed_assert( fmin.size()==dd.size() && fmax.size()==dd.size() );
30 
31  np.resize( dd.size() ); stride.resize( dd.size() ); unsigned totalp=1;
32  for(unsigned i=0;i<dd.size();++i){ np[i]=dd[i]; stride[dd.size()-1-i]=totalp; totalp*=np[i]; }
33 
34  unsigned ii,kk;
35  splinepoints.resize( totalp, np.size() );
36  std::vector<double> delr( np.size() );
37  for(unsigned j=0;j<np.size();++j) delr[j] = ( fmax[j] - fmin[j] )/static_cast<double>(np[j]-1);
38 
39  for(unsigned i=0;i<totalp;++i){
40  ii=i;
41  for(unsigned j=0;j<np.size();++j){
42  kk=std::floor( double(ii) / double(stride[j]) );
43  ii-=kk*stride[j];
44  splinepoints(i,j)=fmin[j] + kk*delr[j];
45  }
46  plumed_assert(ii==0);
47  }
48  lb.resize( np.size() ); ub.resize( np.size() );
49 }
50 
52  splinepoints.resize(0,0); lb.resize(0); ub.resize(0); np.resize(0); stride.resize(0);
53 }
54 
55 void CInterpolation::getNumbersOfPoints( std::vector<unsigned>& nspline ) const {
56  nspline.resize( np.size() );
57  for(unsigned i=0;i<np.size();++i) nspline[i]=np[i];
58 }
59 
60 unsigned CInterpolation::findBox( const std::vector<double>& pos ){
61  plumed_dbg_massert( pos.size()==np.size(), "position size does not match the size of the grid");
62 
63  unsigned jold, ccf_box, bnew=0;
64  for(unsigned i=0;i<np.size();++i){
65  jold=static_cast<int>( std::floor( double(bold)/double(stride[i]) ) );
66  bold-=jold*stride[i];
67  ccf_box=search1( i, pos[i], jold );
68  bnew+=ccf_box;
69  }
70  plumed_dbg_assert( bold==0 ); bold=bnew;
71  for(unsigned i=0;i<np.size();++i){ lb[i]=splinepoints(bold,i); ub[i]=splinepoints(bold+stride[i],i); }
72  return bold;
73 }
74 
75 unsigned CInterpolation::search1( const unsigned& kk, const double& x, const unsigned& jold ) const {
76  int inc=stride[kk], jl=jold*stride[kk], ju=(jold+1)*stride[kk], jm;
77  if ( x>=splinepoints(jl,kk) && x<splinepoints( ju, kk ) ) return jl;
78  else {
79  if( x>=splinepoints(jl, kk ) ){
80  while(true){
81  ju=jl+inc;
82  if( x<splinepoints( ju, kk ) ) break;
83  else if( ju>=(np[kk]-1)*inc ){ju=(np[kk]-1)*inc; break; }
84  jl=ju;
85  }
86  }
87  else{
88  ju=jl;
89  while(true){
90  jl=jl-inc;
91  if( x>=splinepoints( jl, kk ) ) break;
92  else if( jl<=0 ){ jl=0; break; }
93  ju=jl;
94  }
95  }
96  }
97  while( ju-jl>inc ){
98  jm = (ju+jl) / (2*inc) ;
99  if ( x>splinepoints(jm*inc,kk) ) jl=jm*inc; else ju=jm*inc;
100  }
101  plumed_dbg_assert( jl%stride[kk]==0 && ju==jl+stride[kk] );
102  return jl;
103 }
104 
105 InterpolateCubic::InterpolateCubic( const std::vector<unsigned>& dd, const std::vector<double>& fmin, const std::vector<double>& fmax ) :
106 CInterpolation(dd,fmin,fmax)
107 {
108  plumed_massert(np.size()==1,"should be one dimensional data");
109  clist.resize( 4*np[0] );
110 }
111 
112 void InterpolateCubic::set_table( const std::vector<Value>& ff ){
113  plumed_assert( getNumberOfSplinePoints()==ff.size() );
114  plumed_assert( ff[0].getNumberOfDerivatives()==1 );
115 
116  double d1, norm; unsigned pij;
117  for(unsigned i=0;i<np[0]-1;++i){
118  d1 = getPointSpacing( 0, i );
119  norm=(d1*d1)/6.0; pij=i*4;
120  clist[pij]=ff[i].get(); pij++;
121  clist[pij]=ff[i+1].get(); pij++;
122  clist[pij]=ff[i].getDerivative(0)*norm; pij++;
123  clist[pij]=ff[i+1].getDerivative(0)*norm;
124  }
125 }
126 
127 double InterpolateCubic::get_fdf( const std::vector<double>& pos ){
128  plumed_dbg_assert( pos.size()==1 );
129 
130  unsigned mybox=findBox( pos );
131  double d1=ub[0] - lb[0];
132  double b=( pos[0] - lb[0] ) / d1, a=( ub[0] - pos[0] ) / d1;
133 
134  double *cbase=&clist[(mybox*4)+3], *c3=cbase-1, *c2=c3-1, *c1=c2-1;
135  double f=a*(*c1) + b*(*c2) + (a*a*a-a)*(*c3) + (b*b*b-b)*(*cbase);
136  return f;
137 }
138 
139 InterpolateBicubic::InterpolateBicubic( const std::vector<unsigned>& dd, const std::vector<double>& fmin, const std::vector<double>& fmax ) :
140 CInterpolation(dd,fmin,fmax)
141 {
142  plumed_massert(np.size()==2,"should be two dimensional data");
143  static int wt_d[16*16]=
144  {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
145  0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
146  -3, 0, 0, 3, 0, 0, 0, 0,-2, 0, 0,-1, 0, 0, 0, 0,
147  2, 0, 0,-2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
148  0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
149  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
150  0, 0, 0, 0,-3, 0, 0, 3, 0, 0, 0, 0,-2, 0, 0,-1,
151  0, 0, 0, 0, 2, 0, 0,-2, 0, 0, 0, 0, 1, 0, 0, 1,
152  -3, 3, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
153  0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0,
154  9,-9, 9,-9, 6, 3,-3,-6, 6,-6,-3, 3, 4, 2, 1, 2,
155  -6, 6,-6, 6,-4,-2, 2, 4,-3, 3, 3,-3,-2,-1,-1,-2,
156  2,-2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
157  0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0,
158  -6, 6,-6, 6,-3,-3, 3, 3,-4, 4, 2,-2,-2,-2,-1,-1,
159  4,-4, 4,-4, 2, 2,-2,-2, 2,-2,-2, 2, 1, 1, 1, 1};
160 
161  // This is to set up the coefficient matrix
162  unsigned l=0; wt.resize(16,16); t1.resize(16); t2.resize(16);
163  for (unsigned i=0;i<16;i++) for (unsigned j=0;j<16;j++){ wt(i,j)=wt_d[l++]; }
164  // Resize everything
165  dcross.resize( np[0], np[1] ); clist.resize( np[0] * np[1] * 4 * 4 );
166 }
167 
168 void InterpolateBicubic::set_table( const std::vector<Value>& ff ){
169  plumed_assert( getNumberOfSplinePoints()==ff.size() );
170  plumed_assert( ff[0].getNumberOfDerivatives()==2 );
171 
172  dcross=0.0; unsigned iplus, iminus;
173  for(unsigned i=1;i<np[0]-1;++i){
174  iplus=(i+1)*stride[0]; iminus=(i-1)*stride[0];
175  for(unsigned j=1;j<np[1]-1;++j){
176  dcross(i,j) = ( ff[iplus+j+1].get() + ff[iminus+j-1].get() - ff[iplus+j-1].get() - ff[iminus+j+1].get() ) /
177  getCrossTermDenominator( i, j );
178  }
179  }
180 
181  double d1, d2; Matrix<double> tc(4,4);
182  std::vector<double> y(4), dy1(4), dy2(4), d2y12(4);
183 
184  unsigned pij=0; unsigned ipos;
185  for (unsigned i=0;i<np[0]-1;++i){
186  ipos=i*stride[0]; d1 = getPointSpacing( 0, i );
187  for (unsigned j=0; j<np[1]-1;++j){
188  d2 = getPointSpacing( 1, j );
189  y[0] = ff[ipos+j].get(); y[1] = ff[ipos+stride[0]+j].get(); y[2] = ff[ipos+stride[0]+j+1].get(); y[3] = ff[ipos+j+1].get();
190  dy1[0] = ff[ipos+j].getDerivative(0); dy1[1] = ff[ipos+stride[0]+j].getDerivative(0);
191  dy1[2] = ff[ipos+stride[0]+j+1].getDerivative(0); dy1[3] = ff[ipos+j+1].getDerivative(0);
192  dy2[0] = ff[ipos+j].getDerivative(1); dy2[1] = ff[ipos+stride[0]+j].getDerivative(1);
193  dy2[2] = ff[ipos+stride[0]+j+1].getDerivative(1); dy2[3] = ff[ipos+j+1].getDerivative(1);
194  d2y12[0] = dcross( i, j ); d2y12[1] = dcross( i+1, j ); d2y12[2] = dcross( i+1, j+1 ); d2y12[3] = dcross( i, j+1 );
195  IBicCoeff( y, dy1, dy2, d2y12, d1, d2, tc);
196 
197  pij=( ipos+j )*16;
198  for(unsigned k=0; k<4; ++k){ for(unsigned n=0; n<4; ++n){ clist[pij++]=tc(k,n); } }
199  }
200  }
201 }
202 
203 void InterpolateBicubic::IBicCoeff( const std::vector<double>& y, const std::vector<double>& dy1, const std::vector<double>& dy2,
204  const std::vector<double>& d2y12, const double& d1, const double& d2, Matrix<double>& c ){
205  double xx, d1d2=d1*d2;
206  for(unsigned i=0;i<4;i++){ t1[i] = y[i]; t1[i+4] = dy1[i]*d1; t1[i+8] = dy2[i]*d2; t1[i+12] = d2y12[i]*d1d2; }
207  for(unsigned i=0;i<16;i++){ xx=0.0; for(unsigned k=0;k<16;k++){ xx += wt(i,k)*t1[k]; } t2[i]=xx; }
208  unsigned l=0; for(unsigned i=0;i<4;i++){ for(unsigned j=0;j<4;j++){ c(i,j)=t2[l++]; } }
209 }
210 
211 double InterpolateBicubic::get_fdf( const std::vector<double>& pos ){
212 
213  plumed_dbg_assert( pos.size()==2 );
214  unsigned mybox=findBox( pos );
215  double d1 = ub[0] - lb[0], d2 = ub[1] - lb[1];
216  double t = (pos[0] - lb[0]) / d1, u = (pos[1] - lb[1]) / d2;
217 
218  //faster access by pointer arithmetic (dirty dirty dirty)
219  double *cbase=&clist[(mybox+1)*16-1], *c3, *c2, *c1, *c0;
220 
221  double f=0.;
222  for (int i=3; i>=0; i--) { // Note to self - this has to be an int as unsigned cannot be less than zero - duh!!
223  c3=cbase; c2=c3-1; c1=c2-1; c0=c1-1; cbase=c0-1;
224  f= t*f + ( ( (*c3)*u + (*c2) )*u + (*c1) )*u + (*c0);
225  }
226  delete cbase; delete c3; delete c2; delete c1; delete c0;
227  return f;
228 }
229 
230 }
double getPointSpacing(const unsigned dir, const unsigned k) const
Matrix< double > splinepoints
double getCrossTermDenominator(const unsigned i, const unsigned j) const
InterpolateBicubic(const std::vector< unsigned > &dd, const std::vector< double > &fmin, const std::vector< double > &fmax)
void const char const char int * n
Definition: Matrix.h:42
std::vector< double > t2
double get_fdf(const std::vector< double > &pos)
std::vector< double > clist
void set_table(const std::vector< Value > &ff)
void getNumbersOfPoints(std::vector< unsigned > &nspline) const
std::vector< unsigned > np
unsigned findBox(const std::vector< double > &pos)
unsigned search1(const unsigned &kk, const double &x, const unsigned &jold) const
std::vector< double > lb
std::vector< unsigned > stride
double get_fdf(const std::vector< double > &pos)
unsigned getNumberOfSplinePoints() const
std::vector< double > clist
std::vector< double > ub
std::vector< double > t1
void resize(const unsigned nr, const unsigned nc)
Resize the matrix.
Definition: Matrix.h:106
void set_table(const std::vector< Value > &ff)
void const char const char int double * a
Definition: Matrix.h:42
CInterpolation(const std::vector< unsigned > &dd, const std::vector< double > &fmin, const std::vector< double > &fmax)
void IBicCoeff(const std::vector< double > &y, const std::vector< double > &dy1, const std::vector< double > &dy2, const std::vector< double > &d2y12, const double &d1, const double &d2, Matrix< double > &c)
InterpolateCubic(const std::vector< unsigned > &dd, const std::vector< double > &fmin, const std::vector< double > &fmax)
T norm(const std::vector< T > &A)
Calculate the dot product between a vector and itself.
Definition: Matrix.h:61