LSSTApplications  1.1.2+25,10.0+13,10.0+132,10.0+133,10.0+224,10.0+41,10.0+8,10.0-1-g0f53050+14,10.0-1-g4b7b172+19,10.0-1-g61a5bae+98,10.0-1-g7408a83+3,10.0-1-gc1e0f5a+19,10.0-1-gdb4482e+14,10.0-11-g3947115+2,10.0-12-g8719d8b+2,10.0-15-ga3f480f+1,10.0-2-g4f67435,10.0-2-gcb4bc6c+26,10.0-28-gf7f57a9+1,10.0-3-g1bbe32c+14,10.0-3-g5b46d21,10.0-4-g027f45f+5,10.0-4-g86f66b5+2,10.0-4-gc4fccf3+24,10.0-40-g4349866+2,10.0-5-g766159b,10.0-5-gca2295e+25,10.0-6-g462a451+1
LSSTDataManagementBasePackage
Interpolate.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
30 #include <limits>
31 #include <algorithm>
32 #include <map>
33 #include "boost/format.hpp"
34 #include "boost/shared_ptr.hpp"
35 #include "gsl/gsl_errno.h"
36 #include "gsl/gsl_interp.h"
37 #include "gsl/gsl_spline.h"
38 #include "lsst/pex/exceptions.h"
40 
41 namespace lsst {
42 namespace afw {
43 namespace math {
44 
45 /************************************************************************************************************/
46 
47 namespace {
48  std::pair<std::vector<double>, std::vector<double> >
49  recenter(std::vector<double> const &x,
50  std::vector<double> const &y)
51  {
52  if (x.size() != y.size()) {
53  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
54  str(boost::format("Dimensions of x and y must match; %ul != %ul")
55  % x.size() % y.size()));
56  }
57  unsigned int const len = x.size();
58  if (len == 0) {
59  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
60  "You must provide at least 1 point");
61  } else if (len == 1) {
62  return std::make_pair(x, y);
63  }
64 
65  std::vector<double> recentered_x(len + 1);
66  std::vector<double> recentered_y(len + 1);
67 
68  int j = 0;
69  recentered_x[j] = 0.5*(3*x[0] - x[1]);
70  recentered_y[j] = y[0];
71 
72  for (unsigned int i = 0; i < x.size(); ++i) {
73  ++j;
74  recentered_x[j] = 0.5*(x[i] + x[i + 1]);
75  recentered_y[j] = 0.5*(y[i] + y[i + 1]);
76  }
77  recentered_x[j] = 0.5*(3*x[len - 1] - x[len - 2]);
78  recentered_y[j] = y[len - 1];
79 
80  return std::make_pair(recentered_x, recentered_y);
81  }
82 }
83 
85  friend PTR(Interpolate) makeInterpolate(std::vector<double> const &x, std::vector<double> const &y,
86  Interpolate::Style const style);
87 public:
88  virtual ~InterpolateConstant() {}
89  virtual double interpolate(double const x) const;
90 private:
91  InterpolateConstant(std::vector<double> const &x,
92  std::vector<double> const &y,
93  Interpolate::Style const style
94  ) :
95  Interpolate(recenter(x, y)), _old(_x.begin()) {}
96  mutable std::vector<double>::const_iterator _old; // last position we found xInterp at
97 };
98 
99 
101 double InterpolateConstant::interpolate(double const xInterp // the value we want to interpolate to
102  ) const
103 {
104  //
105  // Look for the interval wherein lies xInterp. We could naively use std::upper_bound, but that requires a
106  // logarithmic time lookup so we'll cache the previous answer in _old -- this is a good idea if people
107  // usually call this routine repeatedly for a range of x
108  //
109  // We start by searching up from _old
110  //
111  if (xInterp < *_old) { // We're to the left of the cache
112  if (_old == _x.begin()) { // ... actually off the array
113  return _y[0];
114  }
115  _old = _x.begin(); // reset the cached point to the start of the array
116  } else { // see if we're still in the same interval
117  if (_old < _x.end() - 1 and xInterp < *(_old + 1)) { // we are, so we're done
118  return _y[_old - _x.begin()];
119  }
120  }
121  // We're to the right of the cached point and not in the same inverval, so search up from _old
122  std::vector<double>::const_iterator low = std::upper_bound(_old, _x.end(), xInterp);
123  //
124  // Did that work?
125  if (low == _old && _old != _x.begin()) {
126  // No. Sigh. Search the entire range.
127  low = std::upper_bound(_x.begin(), low + 1, xInterp);
128  }
129  //
130  // OK, we've found the right interval. Return the desired value, being careful at the ends
131  //
132  if (low == _x.end()) {
133  return _y[_y.size() - 1];
134  } else if (low == _x.begin()) {
135  return _y[0];
136  } else {
137  --low;
138  _old = low;
139  return _y[low - _x.begin()];
140  }
141 }
142 
143 /************************************************************************************************************/
144 namespace {
145 /*
146  * Conversion function to switch an Interpolate::Style to a gsl_interp_type.
147  */
148 ::gsl_interp_type const *
149 styleToGslInterpType(Interpolate::Style const style)
150 {
151  switch (style) {
153  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "CONSTANT interpolation not supported.");
154  case Interpolate::LINEAR:
155  return ::gsl_interp_linear;
157  return ::gsl_interp_cspline;
159  return ::gsl_interp_cspline;
161  return ::gsl_interp_cspline_periodic;
163  return ::gsl_interp_akima;
165  return ::gsl_interp_akima_periodic;
167  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
168  "I am unable to make an interpolator of type UNKNOWN");
170  throw LSST_EXCEPT(pex::exceptions::LogicError,
171  str(boost::format("You can't get here: style == %") % style));
172  }
173 }
174 }
175 
176 class InterpolateGsl : public Interpolate {
177  friend PTR(Interpolate) makeInterpolate(std::vector<double> const &x, std::vector<double> const &y,
178  Interpolate::Style const style);
179 public:
180  virtual ~InterpolateGsl();
181  virtual double interpolate(double const x) const;
182 private:
183  InterpolateGsl(std::vector<double> const &x, std::vector<double> const &y, Interpolate::Style const style);
184 
185  ::gsl_interp_type const *_interpType;
186  ::gsl_interp_accel *_acc;
187  ::gsl_interp *_interp;
188 };
189 
190 InterpolateGsl::InterpolateGsl(std::vector<double> const &x,
191  std::vector<double> const &y,
192  Interpolate::Style const style
193  ) :
194  Interpolate(x, y), _interpType(styleToGslInterpType(style))
195 {
196  _acc = ::gsl_interp_accel_alloc();
197  if (!_acc) {
198  throw LSST_EXCEPT(pex::exceptions::MemoryError, "gsl_interp_accel_alloc failed");
199  }
200 
201  _interp = ::gsl_interp_alloc(_interpType, _y.size());
202  if (!_interp) {
203  throw LSST_EXCEPT(pex::exceptions::OutOfRangeError,
204  str(boost::format("Failed to initialise spline for type %s, length %d")
205  % _interpType->name % _y.size()));
206 
207  }
208  // Note, "x" and "y" are vector<double>; gsl_inter_init requires double[].
209  // The &(x[0]) here is valid because std::vector guarantees that the values are
210  // stored contiguously in memory (for types other than bool); C++0X 23.3.6.1 for
211  // those of you reading along.
212  int const status = ::gsl_interp_init(_interp, &x[0], &y[0], _y.size());
213  if (status != 0) {
214  throw LSST_EXCEPT(pex::exceptions::RuntimeError,
215  str(boost::format("gsl_interp_init failed: %s [%d]")
216  % ::gsl_strerror(status) % status));
217  }
218 }
219 
221  ::gsl_interp_free(_interp);
222  ::gsl_interp_accel_free(_acc);
223 }
224 
225 double InterpolateGsl::interpolate(double const xInterp) const
226 {
227  // New GSL versions refuse to extrapolate.
228  // gsl_interp_init() requires x to be ordered, so can just check
229  // the array endpoints for out-of-bounds.
230  if ((xInterp < _x.front() || (xInterp > _x.back()))) {
231  // do our own quadratic extrapolation.
232  // (GSL only provides first and second derivative functions)
233  /* could also just fail via:
234  throw LSST_EXCEPT(
235  pex::exceptions::InvalidParameterError,
236  (boost::format("Interpolation point %f outside range [%f, %f]")
237  % x % _x.front() % _x.back()).str()
238  );
239  */
240  double x0, y0;
241  if (xInterp < _x.front()) {
242  x0 = _x.front();
243  y0 = _y.front();
244  } else {
245  x0 = _x.back();
246  y0 = _y.back();
247  }
248  // first derivative at endpoint
249  double d = ::gsl_interp_eval_deriv(_interp, &_x[0], &_y[0], x0, _acc);
250  // second derivative at endpoint
251  double d2 = ::gsl_interp_eval_deriv2(_interp, &_x[0], &_y[0], x0, _acc);
252  return y0 + (xInterp - x0)*d + 0.5*(xInterp - x0)*(xInterp - x0)*d2;
253  }
254  assert(xInterp >= _x.front());
255  assert(xInterp <= _x.back());
256  return ::gsl_interp_eval(_interp, &_x[0], &_y[0], xInterp, _acc);
257 }
258 
259 /************************************************************************************************************/
264 Interpolate::Style stringToInterpStyle(std::string const &style
265  )
266 {
267  static std::map<std::string, Interpolate::Style> gslInterpTypeStrings;
268  if (gslInterpTypeStrings.empty()) {
269  gslInterpTypeStrings["CONSTANT"] = Interpolate::CONSTANT;
270  gslInterpTypeStrings["LINEAR"] = Interpolate::LINEAR;
271  gslInterpTypeStrings["CUBIC_SPLINE"] = Interpolate::CUBIC_SPLINE;
272  gslInterpTypeStrings["NATURAL_SPLINE"] = Interpolate::NATURAL_SPLINE;
273  gslInterpTypeStrings["CUBIC_SPLINE_PERIODIC"] = Interpolate::CUBIC_SPLINE_PERIODIC;
274  gslInterpTypeStrings["AKIMA_SPLINE"] = Interpolate::AKIMA_SPLINE;
275  gslInterpTypeStrings["AKIMA_SPLINE_PERIODIC"] = Interpolate::AKIMA_SPLINE_PERIODIC;
276  }
277 
278  if ( gslInterpTypeStrings.find(style) == gslInterpTypeStrings.end()) {
279  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Interp style not found: "+style);
280  }
281  return gslInterpTypeStrings[style];
282 }
283 
288  ) {
289  if (n < 1) {
290  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "n must be greater than 0");
291  } else if (n > 4) {
293  } else {
294  static std::vector<Interpolate::Style> styles;
295  if (styles.empty()) {
296  styles.resize(5);
297 
298  styles[0] = Interpolate::UNKNOWN; // impossible to reach as we check for n < 1
299  styles[1] = Interpolate::CONSTANT;
300  styles[2] = Interpolate::LINEAR;
301  styles[3] = Interpolate::CUBIC_SPLINE;
302  styles[4] = Interpolate::CUBIC_SPLINE;
303  }
304  return styles[n];
305  }
306 }
307 
312  ) {
313  static std::vector<int> minPoints;
314  if (minPoints.empty()) {
315  minPoints.resize(Interpolate::NUM_STYLES);
316  minPoints[Interpolate::CONSTANT] = 1;
317  minPoints[Interpolate::LINEAR] = 2;
318  minPoints[Interpolate::NATURAL_SPLINE] = 3;
319  minPoints[Interpolate::CUBIC_SPLINE] = 3;
320  minPoints[Interpolate::CUBIC_SPLINE_PERIODIC] = 3;
321  minPoints[Interpolate::AKIMA_SPLINE] = 5;
322  minPoints[Interpolate::AKIMA_SPLINE_PERIODIC] = 5;
323  }
324 
325  if (style >= 0 && style < Interpolate::NUM_STYLES) {
326  return minPoints[style];
327  } else {
328  throw LSST_EXCEPT(pex::exceptions::OutOfRangeError,
329  str(boost::format("Style %d is out of range 0..%d")
330  % style % (Interpolate::NUM_STYLES - 1)));
331  }
332 }
333 
334 /************************************************************************************************************/
344  std::pair<std::vector<double>, std::vector<double> > const xy,
345  Interpolate::Style const style
347  ) : _x(xy.first), _y(xy.second), _style(style)
348 {
349  ;
350 }
351 
355 PTR(Interpolate) makeInterpolate(std::vector<double> const &x,
356  std::vector<double> const &y,
357  Interpolate::Style const style
358  )
359 {
360  switch (style) {
362  return PTR(Interpolate)(new InterpolateConstant(x, y, style));
363  default: // use GSL
364  return PTR(Interpolate)(new InterpolateGsl(x, y, style));
365  }
366 }
367 
368 }}}
int y
Interpolate::Style stringToInterpStyle(std::string const &style)
Conversion function to switch a string to an Interpolate::Style.
Definition: Interpolate.cc:264
Interpolate values for a set of x,y vector&lt;&gt;s.
Definition: Interpolate.h:37
friend boost::shared_ptr< Interpolate > makeInterpolate(std::vector< double > const &x, std::vector< double > const &y, Interpolate::Style const style)
std::vector< double > const _y
Definition: Interpolate.h:68
boost::shared_ptr< Interpolate > makeInterpolate(std::vector< double > const &x, std::vector< double > const &y, Interpolate::Style const style=Interpolate::AKIMA_SPLINE)
Definition: Interpolate.cc:355
::gsl_interp_accel * _acc
Definition: Interpolate.cc:186
virtual double interpolate(double const x) const
Definition: Interpolate.cc:225
InterpolateConstant(std::vector< double > const &x, std::vector< double > const &y, Interpolate::Style const style)
Definition: Interpolate.cc:91
InterpolateGsl(std::vector< double > const &x, std::vector< double > const &y, Interpolate::Style const style)
Definition: Interpolate.cc:190
#define PTR(...)
Definition: base.h:41
int const x0
Definition: saturated.cc:45
std::vector< double >::const_iterator _old
Definition: Interpolate.cc:96
int d
Definition: KDTree.cc:89
std::vector< double > const _x
Definition: Interpolate.h:67
virtual double interpolate(double const x) const
Interpolate a constant to the point xInterp.
Definition: Interpolate.cc:101
double _y
Definition: ImageUtils.cc:328
::gsl_interp_type const * _interpType
Definition: Interpolate.cc:185
Interpolate::Style lookupMaxInterpStyle(int const n)
Get the highest order Interpolation::Style available for &#39;n&#39; points.
Definition: Interpolate.cc:287
int x
int lookupMinInterpPoints(Interpolate::Style const style)
Get the minimum number of points needed to use the requested interpolation style. ...
Definition: Interpolate.cc:311
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
friend boost::shared_ptr< Interpolate > makeInterpolate(std::vector< double > const &x, std::vector< double > const &y, Interpolate::Style const style)
int status
int const y0
Definition: saturated.cc:45
Include files required for standard LSST Exception handling.
Interpolate(std::vector< double > const &x, std::vector< double > const &y, Interpolate::Style const style=UNKNOWN)
Definition: Interpolate.h:60