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
Approximate.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 
29 #include <limits>
30 #include <algorithm>
31 #include <numeric>
32 #include "Eigen/Core"
33 #include "Eigen/LU"
34 #include "boost/format.hpp"
35 #include "boost/shared_ptr.hpp"
36 #include "lsst/utils/ieee.h"
37 #include "lsst/pex/exceptions.h"
41 
42 namespace lsst {
43 namespace ex = pex::exceptions;
44 namespace afw {
45 namespace math {
46 
49  int orderX,
50  int orderY,
51  bool weighting
52  ) :
53  _style(style), _orderX(orderX), _orderY(orderY < 0 ? orderX : orderY), _weighting(weighting) {
54  if (_orderX != _orderY) {
55  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
56  str(boost::format("X- and Y-orders must be equal (%d != %d) "
57  "due to a limitation in math::Chebyshev1Function2")
58  % _orderX % _orderY));
59  }
60 }
61 
62 /************************************************************************************************************/
63 
64 namespace {
68 template<typename PixelT>
69 class ApproximateChebyshev : public Approximate<PixelT> {
70  template<typename T>
71  friend PTR(Approximate<T>)
72  math::makeApproximate(std::vector<double> const &xVec, std::vector<double> const &yVec,
73  image::MaskedImage<T> const& im, geom::Box2I const& bbox,
74  ApproximateControl const& ctrl);
75 public:
76  virtual ~ApproximateChebyshev();
77 private:
78  math::Chebyshev1Function2<double> _poly;
79 
80  ApproximateChebyshev(std::vector<double> const &xVec, std::vector<double> const &yVec,
81  image::MaskedImage<PixelT> const& im, geom::Box2I const& bbox,
82  ApproximateControl const& ctrl);
83  virtual PTR(image::Image<typename Approximate<PixelT>::OutPixelT>)
84  doGetImage(int orderX, int orderY) const;
85  virtual PTR(image::MaskedImage<typename Approximate<PixelT>::OutPixelT>)
86  doGetMaskedImage(int orderX, int orderY) const;
87 };
88 
89 /************************************************************************************************************/
90 
91 namespace {
92  // N.b. physically inlining these routines into ApproximateChebyshev
93  // causes clang++ 3.1 problems; I suspect a clang bug (see http://llvm.org/bugs/show_bug.cgi?id=14162)
94  inline void
95  solveMatrix_Eigen(Eigen::MatrixXd &a,
96  Eigen::VectorXd &b,
97  Eigen::Map<Eigen::VectorXd> &c
98  ) {
99  Eigen::PartialPivLU<Eigen::MatrixXd> lu(a);
100  c = lu.solve(b);
101  }
102 }
103 
107 template<typename PixelT>
108 ApproximateChebyshev<PixelT>::ApproximateChebyshev(
109  std::vector<double> const &xVec,
110  std::vector<double> const &yVec,
111  image::MaskedImage<PixelT> const& im,
112  geom::Box2I const& bbox,
113  ApproximateControl const& ctrl
114  )
115  : Approximate<PixelT>(xVec, yVec, bbox, ctrl),
116  _poly(math::Chebyshev1Function2<double>(ctrl.getOrderX(), geom::Box2D(bbox)))
117 {
118 #if !defined(NDEBUG)
119  {
120  std::vector<double> const& coeffs = _poly.getParameters();
121  assert(std::accumulate(coeffs.begin(), coeffs.end(), 0.0) == 0.0); // i.e. coeffs is initialised to 0.0
122  }
123 #endif
124  int const nTerm = _poly.getNParameters(); // number of terms in polynomial
125  int const nData = im.getWidth()*im.getHeight(); // number of data points
126  /*
127  * N.b. in the comments,
128  * i runs over the 0..nTerm-1 coefficients
129  * alpha runs over the 0..nData-1 data points
130  */
131 
132  /*
133  * We need the value of the polynomials evaluated at every data point, so it's more
134  * efficient to pre-calculate the values: termCoeffs[i][alpha]
135  */
136  std::vector<std::vector<double> > termCoeffs(nTerm);
137 
138  for (int i = 0; i != nTerm; ++i) {
139  termCoeffs[i].reserve(nData);
140  }
141 
142  for (int iy = 0; iy != im.getHeight(); ++iy) {
143  double const y = yVec[iy];
144 
145  for (int ix = 0; ix != im.getWidth(); ++ix) {
146  double const x = xVec[ix];
147 
148  for (int i = 0; i != nTerm; ++i) {
149  _poly.setParameter(i, 1.0);
150  termCoeffs[i].push_back(_poly(x, y));
151  _poly.setParameter(i, 0.0);
152  }
153  }
154  }
155  // We'll solve A*c = b
156  Eigen::MatrixXd A; A.setZero(nTerm, nTerm); // We'll solve A*c = b
157  Eigen::VectorXd b; b.setZero(nTerm);
158  /*
159  * Go through the data accumulating the values of the A and b matrix/vector
160  */
161  int alpha = 0;
162  for (int iy = 0; iy != im.getHeight(); ++iy) {
163  for (typename image::MaskedImage<PixelT>::const_x_iterator ptr = im.row_begin(iy),
164  end = im.row_end(iy); ptr != end; ++ptr, ++alpha) {
165  double const val = ptr.image();
166  double const ivar = ctrl.getWeighting() ? 1/ptr.variance() : 1.0;
167  if (!lsst::utils::isfinite(val + ivar)) {
168  continue;
169  }
170 
171  for (int i = 0; i != nTerm; ++i) {
172  double const c_i = termCoeffs[i][alpha];
173  double const tmp = c_i*ivar;
174 
175  b(i) += val*tmp;
176  A(i, i) += c_i*tmp;
177  for (int j = 0; j < i; ++j) {
178  double const c_j = termCoeffs[j][alpha];
179  A(i, j) += c_j*tmp;
180  }
181  }
182  }
183  }
184  if (A.isZero()) {
185  throw LSST_EXCEPT(pex::exceptions::RuntimeError,
186  "No valid points to fit. Variance is likely zero. Try weighting=False");
187  }
188  // We only filled out the lower triangular part of A
189  for (int j = 0; j != nTerm; ++j) {
190  for (int i = j + 1; i != nTerm; ++i) {
191  A(j, i) = A(i, j);
192  }
193  }
194  /*
195  * OK, now all we ned do is solve that...
196  */
197  std::vector<double> cvec(nTerm);
198  Eigen::Map<Eigen::VectorXd> c(&cvec[0], nTerm); // N.b. c shares memory with cvec
199 
200  solveMatrix_Eigen(A, b, c);
201 
202  _poly.setParameters(cvec);
203 }
204 
206 template<typename PixelT>
207 ApproximateChebyshev<PixelT>::~ApproximateChebyshev() {
208 }
209 
217 template<typename PixelT>
218 PTR(image::Image<typename Approximate<PixelT>::OutPixelT>)
219 ApproximateChebyshev<PixelT>::doGetImage(int orderX,
220  int orderY
221  ) const
222 {
223  if (orderX < 0) orderX = Approximate<PixelT>::_ctrl.getOrderX();
224  if (orderY < 0) orderY = Approximate<PixelT>::_ctrl.getOrderY();
225 
227  (orderX == Approximate<PixelT>::_ctrl.getOrderX() &&
228  orderY == Approximate<PixelT>::_ctrl.getOrderY()) ? _poly : _poly.truncate(orderX);
229 
231 
232  PTR(ImageT) im(new ImageT(Approximate<PixelT>::_bbox));
233  for (int iy = 0; iy != im->getHeight(); ++iy) {
234  double const y = iy;
235 
236  int ix = 0;
237  for (typename ImageT::x_iterator ptr = im->row_begin(iy),
238  end = im->row_end(iy); ptr != end; ++ptr, ++ix) {
239  double const x = ix;
240 
241  *ptr = poly(x, y);
242  }
243  }
244 
245  return im;
246 }
255 template<typename PixelT>
256 PTR(image::MaskedImage<typename Approximate<PixelT>::OutPixelT>)
257 ApproximateChebyshev<PixelT>::doGetMaskedImage(
258  int orderX,
259  int orderY
260  ) const
261 {
263 
264  PTR(MImageT) mi(new MImageT(Approximate<PixelT>::_bbox));
265  PTR(typename MImageT::Image) im = mi->getImage();
266 
267  for (int iy = 0; iy != im->getHeight(); ++iy) {
268  double const y = iy;
269 
270  int ix = 0;
271  for (typename MImageT::Image::x_iterator ptr = im->row_begin(iy),
272  end = im->row_end(iy); ptr != end; ++ptr, ++ix) {
273  double const x = ix;
274 
275  *ptr = _poly(x, y);
276  }
277  }
278 
279  return mi;
280 }
281 }
282 
283 /************************************************************************************************************/
287 template<typename PixelT>
288 PTR(Approximate<PixelT>)
289 makeApproximate(std::vector<double> const &x,
290  std::vector<double> const &y,
291  image::MaskedImage<PixelT> const& im,
292  geom::Box2I const& bbox,
293  ApproximateControl const& ctrl
294  )
295 {
296  switch (ctrl.getStyle()) {
297  case ApproximateControl::CHEBYSHEV:
298  return PTR(Approximate<PixelT>)(new ApproximateChebyshev<PixelT>(x, y, im, bbox, ctrl));
299  default:
300  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
301  str(boost::format("Unknown ApproximationStyle: %d") % ctrl.getStyle()));
302  }
303 }
305 /*
306  * Explicit instantiations
307  *
308  */
309 #define INSTANTIATE(PIXEL_T) \
310  template \
311  PTR(Approximate<PIXEL_T>) makeApproximate( \
312  std::vector<double> const &x, std::vector<double> const &y, \
313  image::MaskedImage<PIXEL_T> const& im, \
314  geom::Box2I const& bbox, \
315  ApproximateControl const& ctrl)
316 
317 INSTANTIATE(float);
318 //INSTANTIATE(int);
319 
321 
322 }}}
int y
2-dimensional weighted sum of Chebyshev polynomials of the first kind.
int getWidth() const
Return the number of columns in the image.
Definition: MaskedImage.h:901
for(FootprintList::const_iterator ptr=feet->begin(), end=feet->end();ptr!=end;++ptr)
Definition: saturated.cc:82
Define a collection of useful Functions.
x_iterator row_end(int y) const
Return an x_iterator to the end of the image.
Definition: MaskedImage.cc:703
#define PTR(...)
Definition: base.h:41
Approximate values for a MaskedImage.
Definition: Approximate.h:38
Matrix alpha
An integer coordinate rectangle.
Definition: Box.h:53
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
ApproximateControl(Style style, int orderX, int orderY=-1, bool weighting=true)
ctor
Definition: Approximate.cc:48
math::Chebyshev1Function2< double > _poly
Definition: Approximate.cc:78
Control how to make an approximation.
Definition: Approximate.h:47
#define INSTANTIATE(TYPE)
Definition: ImagePca.cc:128
geom::Box2I const & _bbox
Definition: fits_io_mpl.h:80
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:77
Style
Choose the type of approximation to use.
Definition: Approximate.h:50
int isfinite(T t)
Definition: ieee.h:100
int x
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
boost::shared_ptr< Approximate< PixelT > > makeApproximate(std::vector< double > const &x, std::vector< double > const &y, image::MaskedImage< PixelT > const &im, geom::Box2I const &bbox, ApproximateControl const &ctrl)
Construct a new Approximate object, inferring the type from the type of the given MaskedImage...
Definition: Approximate.cc:289
afw::table::Key< double > b
x_iterator row_begin(int y) const
Return an x_iterator to the start of the image.
Definition: MaskedImage.cc:693
Implementation of the Class MaskedImage.
int getHeight() const
Return the number of rows in the image.
Definition: MaskedImage.h:903
ImageT val
Definition: CR.cc:154
A class to represent a 2-dimensional array of pixels.
Definition: PSF.h:43
Include files required for standard LSST Exception handling.