Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
Cubic_spline.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 //////////////////////////////////////////////////////////////////////
11 ///
12 /// @brief
13 /// read the header file!
14 ///
15 /// @references
16 /// Numerical Recipes in c++ 2nd edition
17 /// Ralf Mueller
18 ///
19 ///
20 /// @author Steven Combs, Ralf Mueller, Jens Meiler
21 ///
22 /////////////////////////////////////////////////////////////////////////
24 #include <numeric/MathMatrix.hh>
26 
27 #include <numeric/types.hh>
28 
29 #ifdef SERIALIZATION
30 // Utility serialization headers
32 
33 // Numeric serialization headers
35 #endif // SERIALIZATION
36 
37 
38 namespace numeric {
39 namespace interpolation {
40 namespace spline {
41 
42 
43 // train CubicSpline
44 // BORDER determines the behavior of the spline at the borders (natural, first derivative, periodic)
45 // START the start of the interval the spline is defined on
46 // DELTA the distance between two support points of the spline
47 // RESULTS the function values at the support points of the spline
48 // FIRSTBE values for the first order derivative at begin and end of spline (only FIRSTDER)
49 CubicSpline &CubicSpline::train
50 (
51  const BorderFlag BORDER,
52  const Real START,
53  const Real DELTA,
54  const MathVector< Real> &RESULTS,
55  const std::pair< Real, Real> &FIRSTBE
56 )
57 {
58 
59  // determine value for dimension of x
60  const int dim( RESULTS.size());
61 
62  // assigning values
63  border_ = BORDER;
64  start_ = START;
65  delta_ = DELTA;
66 
67  // auxiliary variables
68  const Real delta1( DELTA / 6), delta2( 2 * DELTA / 3);
69 
70  values_ = RESULTS;
71 
72 
73  MathMatrix< Real> coeffs( dim, dim);
74  MathVector< Real> derivs( dim);
75 
76  // train once for the values of fxx
77  // those values are equivalent for every type of spline considered here
78  for ( int i( 1); i < dim - 1; ++i ) {
79  coeffs( i, i - 1) = delta1;
80  coeffs( i, i ) = delta2;
81  coeffs( i, i + 1) = delta1;
82 
83  derivs( i) = ( values_( i + 1) - 2 * values_( i) + values_( i-1)) / DELTA;
84  }
85 
86  // setting the second order derivative on start and end to 0, "natural" cubic spline
87  if ( border_ == e_Natural ) {
88  coeffs( 0, 0) = 1;
89  coeffs( dim-1, dim-1) = 1;
90  }
91 
92  // periodic, the function starts over after reaching the ends, continuously differentiable everywhere
93  if ( border_ == e_Periodic ) {
94  coeffs( 0, dim - 1) = delta1;
95  coeffs( 0, 0) = delta2;
96  coeffs( 0, 1) = delta1;
97  derivs( 0) = ( values_( 1) - 2 * values_( 0) + values_( dim-1)) / DELTA;
98 
99  coeffs( dim - 1, dim - 2) = delta1;
100  coeffs( dim - 1, dim - 1) = delta2;
101  coeffs( dim - 1, 0) = delta1;
102  derivs( dim - 1) = ( values_( 0) - 2 * values_( dim-1) + values_( dim-2)) / DELTA;
103  }
104 
105  // set the first order derivative at x_0 to first_start and at x_dim-1 to first_end
106  if ( border_ == e_FirstDer ) {
107  coeffs( 0, 0) = -delta2/2;
108  coeffs( 0, 1) = -delta1;
109  derivs( 0) = FIRSTBE.first - ( values_( 1) - values_( 0)) / DELTA;
110 
111  coeffs( dim - 1, dim - 1) = delta2 / 2;
112  coeffs( dim - 1, dim - 2) = delta1;
113  derivs( dim - 1) = FIRSTBE.second - ( values_( dim - 1) - values_( dim - 2)) / DELTA;
114  }
115 
116  // computation of the second order derivatives in every given point of the spline
117  derivs = coeffs.inverse() * derivs;
118  dsecox_ = derivs;
119 
120  return *this;
121 }
122 
123 
124 /// @brief return value at certain ARGUMENT
125 /// @param ARGUMENT x value
126 /// @return function value at ARGUMENT
127 Real CubicSpline::F( const Real &ARGUMENT) const
128 {
129  // number of grid points
130  const int dim( values_.size());
131 
132  // determine i with start_+(i-1)*delta_ < ARGUMENT < start_+i*delta_ for the correct supporting points
133  int i( int( floor( ( ARGUMENT - start_) / delta_)) + 1);
134 
135  // not within supporting points - left
136  if ( i < 1 ) {
137  // if the spline is periodic, adjust i to be positive ( > 0) and within range
138  if ( border_ == e_Periodic ) {
139  // bring close to actual range
140  i %= dim;
141 
142  // if between end and start
143  if ( i == 0 ) {
144  // see Numerical recipes in C++, pages 116-118
145  Real dxp( fmod( ARGUMENT - start_, delta_) / delta_); // relative offset from the beginning of the actual interval
146  if ( dxp < 0.0 ) {
147  dxp += 1.0;
148  }
149 
150  // return
151  return Function( dim - 1, 0, dxp);
152  }
153  // generate positive index value ( > 0)
154  while ( i < 1 )
155  {
156  i += dim;
157  }
158  } else {
159  return Function( 0, 1, Real( 0)) + ( ARGUMENT - start_) * Derivative( 0, 1, Real( 0));
160  }
161  } else if ( i >= dim ) {
162  // not within supporting points - right
163  const int end( dim - 1);
164 
165  // if the spline is periodic, adjust i to be positive ( > 0)
166  if ( border_ == e_Periodic ) {
167  // generate index value within range
168  i %= dim;
169 
170  // special case, where interpolation happens between end and beginning
171  if ( i == 0 ) {
172  // see Numerical recipes in C++, pages 116-118
173  const Real dxp( fmod( ARGUMENT - start_, delta_) / delta_); // relative offset from the beginning of the actual interval
174 
175  // return
176  return Function( end, 0, dxp);
177  }
178  } else {
179  // derivative at last supporting points
180  return Function( end -1, end, 1.0) + ( ARGUMENT - start_ - ( dim - 1) * delta_) * Derivative( end -1, end, 1.0);
181  }
182  }
183 
184  // see Numerical recipes in C++, pages 116-118
185  Real dxp( fmod( ARGUMENT - start_, delta_) / delta_); // delta_akt is an offset from the beginning of the actual interval\n";
186  if ( dxp < 0.0 ) {
187  dxp += 1.0;
188  }
189 
190  return Function( i - 1, i, dxp);
191 }
192 
193 
194 /// @brief return derivative at certain ARGUMENT
195 /// @param ARGUMENT x value
196 /// @return derivative at ARGUMENT
197 Real CubicSpline::dF( const Real &ARGUMENT) const
198 {
199  // number of grid points
200  const int dim( values_.size());
201 
202  // determine i with start_+(i-1)*delta_ < ARGUMENT < start_+i*delta_ for the correct supporting points
203  int i( int( floor( ( ARGUMENT - start_) / delta_)) + 1);
204 
205  // not within supporting points - left
206  if ( i < 1 ) {
207  // if the spline is periodic, adjust i to be positive ( > 0) and within range
208  if ( border_ == e_Periodic ) {
209  // bring close to actual range
210  i %= dim;
211 
212  // if between end and start
213  if ( i == 0 ) {
214  // see Numerical recipes in C++, pages 116-118
215  Real dxp( fmod( ARGUMENT - start_, delta_) / delta_); // relative offset from the beginning of the actual interval
216  if ( dxp < 0.0 ) {
217  dxp += 1.0;
218  }
219 
220  // return
221  return Derivative( dim - 1, 0, dxp);
222  }
223  // generate positive index value ( > 0)
224  while ( i < 1 )
225  {
226  i += dim;
227  }
228  } else {
229  return Derivative( 0, 1, Real( 0));
230  }
231  } else if ( i >= dim ) {
232  // not within supporting points - right
233  const int end( dim - 1);
234 
235  // if the spline is periodic, adjust i to be positive ( > 0)
236  if ( border_ == e_Periodic ) {
237  // generate index value within range
238  i %= dim;
239 
240  // special case, where interpolation happens between end and beginning
241  if ( i == 0 ) {
242  // see Numerical recipes in C++, pages 116-118
243  const Real dxp( fmod( ARGUMENT - start_, delta_) / delta_); // relative offset from the beginning of the actual interval
244 
245  // return
246  return Derivative( end, 0, dxp);
247  }
248  } else {
249  // derivative at last supporting points
250  return Derivative( end -1, end, 1.0);
251  }
252  }
253 
254  // see Numerical recipes in C++, pages 116-118
255  Real dxp( fmod( ARGUMENT - start_, delta_) / delta_); // delta_akt is an offset from the beginning of the actual interval\n";
256  if ( dxp < 0.0 ) {
257  dxp += 1.0;
258  }
259 
260  return Derivative( i - 1, i, dxp);
261 }
262 
263 /// @brief return derivative and value at certain ARGUMENT
264 /// @param ARGUMENT x value
265 /// @return value and derivative at ARGUMENT
266 std::pair< Real, Real> CubicSpline::FdF( const Real &ARGUMENT) const
267 {
268  return std::pair<Real, Real>( F( ARGUMENT), dF( ARGUMENT));
269 }
270 
271 
272 ///////////////////////
273 // helper functions //
274 ///////////////////////
275 
276 /// @brief calculate function between two cells
277 /// @param INDEX_LEFT index of left grid point
278 /// @param INDEX_RIGHT index of right grid point
279 /// @param DXP relative distance from left grid point, must be element [0, 1]
280 /// @return function depending on relative distance DXP
281 Real CubicSpline::Function( const int INDEX_LEFT, const int INDEX_RIGHT, const Real DXP) const
282 {
283  // see Numerical recipes in C++, pages 116-118
284  // relative distance from right grid point
285  const Real dxm( 1 - DXP);
286  const Real dx3p( ( DXP * DXP * DXP - DXP) * sqr( delta_) / 6); // =0 at the gridpoints, adds cubic part of the spline
287  const Real dx3m( ( dxm * dxm * dxm - dxm) * sqr( delta_) / 6); // =0 at the gridpoints, adds cubic part of the spline
288 
289  return
290  dxm * values_( INDEX_LEFT) + DXP * values_( INDEX_RIGHT)
291  + dx3m * dsecox_( INDEX_LEFT) + dx3p * dsecox_( INDEX_RIGHT);
292 }
293 
294 
295 /// @brief calculate derivative between two cells
296 /// @param INDEX_LEFT index of left grid point
297 /// @param INDEX_RIGHT index of right grid point
298 /// @param DXP relative distance from left grid point, must be element [0, 1]
299 /// @return derivative depending on relative distance DXP
300 Real CubicSpline::Derivative( const int INDEX_LEFT, const int INDEX_RIGHT, const Real DXP) const
301 {
302  // see Numerical recipes in C++, pages 116-118
303  // relative distance from right grid point
304  const Real dxm( 1 - DXP);
305 
306  return
307  ( values_( INDEX_RIGHT) - values_( INDEX_LEFT)) / delta_
308  - ( 3 * dxm * dxm - 1) / 6 * delta_ * dsecox_( INDEX_LEFT)
309  + ( 3 * DXP * DXP - 1) / 6 * delta_ * dsecox_( INDEX_RIGHT);
310 }
311 
312 }//spline
313 }//interpolation
314 }//numeric
315 
316 
317 #ifdef SERIALIZATION
318 
319 /// @brief Automatically generated serialization method
320 template< class Archive >
321 void
322 numeric::interpolation::spline::CubicSpline::save( Archive & arc ) const {
323  arc( CEREAL_NVP( border_ ) ); // enum numeric::interpolation::spline::BorderFlag
324  arc( CEREAL_NVP( start_ ) ); // Real
325  arc( CEREAL_NVP( delta_ ) ); // Real
326  arc( CEREAL_NVP( values_ ) ); // MathVector<Real>
327  arc( CEREAL_NVP( dsecox_ ) ); // MathVector<Real>
328 }
329 
330 /// @brief Automatically generated deserialization method
331 template< class Archive >
332 void
334  arc( border_ ); // enum numeric::interpolation::spline::BorderFlag
335  arc( start_ ); // Real
336  arc( delta_ ); // Real
337  arc( values_ ); // MathVector<Real>
338  arc( dsecox_ ); // MathVector<Real>
339 }
340 
341 SAVE_AND_LOAD_SERIALIZABLE( numeric::interpolation::spline::CubicSpline );
342 #endif // SERIALIZATION
Real dF(const Real &ARGUMENT) const
return derivative at ARGUMENT
CubicSpline & train(const BorderFlag BORDER, const Real START, const Real DELTA, const MathVector< Real > &RESULTS, const std::pair< Real, Real > &FIRSTBE)
Definition: Cubic_spline.cc:50
Real F(const Real &ARGUMENT) const
return value at certain ARGUMENT
Real Derivative(const int INDEX_LEFT, const int INDEX_RIGHT, const Real DXP) const
calculate derivative between two cells
Serlialization routines for MathVector.
utility::keys::lookup::end< KeyType > const end
BorderFlag border_
controls the behavior at x_0 and x_dim-1
Commons serlialization routines.
MathMatrix< T > & inverse()
Definition: MathMatrix.hh:348
Real delta_
gives the arguments as a sequence of equidistant points
rosetta project type declarations. Should be kept updated with core/types.hh. This exists because num...
double Real
Definition: types.hh:39
std::pair< Real, Real > FdF(const double &ARGUMENT) const
return value and derivative at ARGUMENT
Size size() const
size of vector
Definition: MathVector.hh:125
MathVector< Real > dsecox_
second order derivatives
Real Function(const int INDEX_LEFT, const int INDEX_RIGHT, const Real DXP) const
calculate function between two cells
def load
Definition: IO.py:5