LSSTApplications  11.0-13-gbb96280,12.1+18,12.1+7,12.1-1-g14f38d3+72,12.1-1-g16c0db7+5,12.1-1-g5961e7a+84,12.1-1-ge22e12b+23,12.1-11-g06625e2+4,12.1-11-g0d7f63b+4,12.1-19-gd507bfc,12.1-2-g7dda0ab+38,12.1-2-gc0bc6ab+81,12.1-21-g6ffe579+2,12.1-21-gbdb6c2a+4,12.1-24-g941c398+5,12.1-3-g57f6835+7,12.1-3-gf0736f3,12.1-37-g3ddd237,12.1-4-gf46015e+5,12.1-5-g06c326c+20,12.1-5-g648ee80+3,12.1-5-gc2189d7+4,12.1-6-ga608fc0+1,12.1-7-g3349e2a+5,12.1-7-gfd75620+9,12.1-9-g577b946+5,12.1-9-gc4df26a+10
LSSTDataManagementBasePackage
KernelSolution.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
11 #include <iterator>
12 #include <cmath>
13 #include <algorithm>
14 #include <limits>
15 
16 #include <memory>
17 #include "boost/timer.hpp"
18 
19 #include "Eigen/Core"
20 #include "Eigen/Cholesky"
21 #include "Eigen/QR"
22 #include "Eigen/LU"
23 #include "Eigen/Eigenvalues"
24 #include "Eigen/SVD"
25 
26 #include "lsst/afw/math.h"
27 #include "lsst/afw/geom.h"
28 #include "lsst/afw/image.h"
29 #include "lsst/afw/detection.h"
30 #include "lsst/afw/detection/FootprintArray.cc"
31 #include "lsst/log/Log.h"
33 
36 
37 #include "ndarray.h"
38 #include "ndarray/eigen.h"
39 
40 #define DEBUG_MATRIX 0
41 #define DEBUG_MATRIX2 0
42 
43 namespace afwDet = lsst::afw::detection;
44 namespace afwMath = lsst::afw::math;
45 namespace afwGeom = lsst::afw::geom;
46 namespace afwImage = lsst::afw::image;
47 namespace pexExcept = lsst::pex::exceptions;
48 
49 namespace lsst {
50 namespace ip {
51 namespace diffim {
52 
53  /* Unique identifier for solution */
55 
57  std::shared_ptr<Eigen::MatrixXd> mMat,
58  std::shared_ptr<Eigen::VectorXd> bVec,
59  bool fitForBackground
60  ) :
61  _id(++_SolutionId),
62  _mMat(mMat),
63  _bVec(bVec),
64  _aVec(),
65  _solvedBy(NONE),
66  _fitForBackground(fitForBackground)
67  {};
68 
70  bool fitForBackground
71  ) :
72  _id(++_SolutionId),
73  _mMat(),
74  _bVec(),
75  _aVec(),
76  _solvedBy(NONE),
77  _fitForBackground(fitForBackground)
78  {};
79 
81  _id(++_SolutionId),
82  _mMat(),
83  _bVec(),
84  _aVec(),
85  _solvedBy(NONE),
86  _fitForBackground(true)
87  {};
88 
90  solve(*_mMat, *_bVec);
91  }
92 
94  return getConditionNumber(*_mMat, conditionType);
95  }
96 
97  double KernelSolution::getConditionNumber(Eigen::MatrixXd mMat,
98  ConditionNumberType conditionType) {
99  switch (conditionType) {
100  case EIGENVALUE:
101  {
102  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(mMat);
103  Eigen::VectorXd eValues = eVecValues.eigenvalues();
104  double eMax = eValues.maxCoeff();
105  double eMin = eValues.minCoeff();
106  LOGL_DEBUG("TRACE3.ip.diffim.KernelSolution.getConditionNumber",
107  "EIGENVALUE eMax / eMin = %.3e", eMax / eMin);
108  return (eMax / eMin);
109  break;
110  }
111  case SVD:
112  {
113  Eigen::VectorXd sValues = mMat.jacobiSvd().singularValues();
114  double sMax = sValues.maxCoeff();
115  double sMin = sValues.minCoeff();
116  LOGL_DEBUG("TRACE3.ip.diffim.KernelSolution.getConditionNumber",
117  "SVD eMax / eMin = %.3e", sMax / sMin);
118  return (sMax / sMin);
119  break;
120  }
121  default:
122  {
123  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
124  "Undefined ConditionNumberType : only EIGENVALUE, SVD allowed.");
125  break;
126  }
127  }
128  }
129 
130  void KernelSolution::solve(Eigen::MatrixXd mMat,
131  Eigen::VectorXd bVec) {
132 
133  if (DEBUG_MATRIX) {
134  std::cout << "M " << std::endl;
135  std::cout << mMat << std::endl;
136  std::cout << "B " << std::endl;
137  std::cout << bVec << std::endl;
138  }
139 
140  Eigen::VectorXd aVec = Eigen::VectorXd::Zero(bVec.size());
141 
142  boost::timer t;
143  t.restart();
144 
145  LOGL_DEBUG("TRACE2.ip.diffim.KernelSolution.solve",
146  "Solving for kernel");
147  _solvedBy = LU;
148  Eigen::FullPivLU<Eigen::MatrixXd> lu(mMat);
149  if (lu.isInvertible()) {
150  aVec = lu.solve(bVec);
151  } else {
152  LOGL_DEBUG("TRACE3.ip.diffim.KernelSolution.solve",
153  "Unable to determine kernel via LU");
154  /* LAST RESORT */
155  try {
156 
158  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(mMat);
159  Eigen::MatrixXd const& rMat = eVecValues.eigenvectors();
160  Eigen::VectorXd eValues = eVecValues.eigenvalues();
161 
162  for (int i = 0; i != eValues.rows(); ++i) {
163  if (eValues(i) != 0.0) {
164  eValues(i) = 1.0/eValues(i);
165  }
166  }
167 
168  aVec = rMat * eValues.asDiagonal() * rMat.transpose() * bVec;
169  } catch (pexExcept::Exception& e) {
170 
171  _solvedBy = NONE;
172  LOGL_DEBUG("TRACE3.ip.diffim.KernelSolution.solve",
173  "Unable to determine kernel via eigen-values");
174 
175  throw LSST_EXCEPT(pexExcept::Exception, "Unable to determine kernel solution");
176  }
177  }
178 
179  double time = t.elapsed();
180  LOGL_DEBUG("TRACE3.ip.diffim.KernelSolution.solve",
181  "Compute time for matrix math : %.2f s", time);
182 
183  if (DEBUG_MATRIX) {
184  std::cout << "A " << std::endl;
185  std::cout << aVec << std::endl;
186  }
187 
188  _aVec = std::shared_ptr<Eigen::VectorXd>(new Eigen::VectorXd(aVec));
189  }
190 
191  /*******************************************************************************************************/
192 
193  template <typename InputT>
195  lsst::afw::math::KernelList const& basisList,
196  bool fitForBackground
197  )
198  :
199  KernelSolution(fitForBackground),
200  _cMat(),
201  _iVec(),
202  _ivVec(),
203  _kernel(),
204  _background(0.0),
205  _kSum(0.0)
206  {
207  std::vector<double> kValues(basisList.size());
208  _kernel = std::shared_ptr<afwMath::Kernel>(
209  new afwMath::LinearCombinationKernel(basisList, kValues)
210  );
211  };
212 
213  template <typename InputT>
215  if (_solvedBy == KernelSolution::NONE) {
216  throw LSST_EXCEPT(pexExcept::Exception, "Kernel not solved; cannot return solution");
217  }
218  return _kernel;
219  }
220 
221  template <typename InputT>
223  if (_solvedBy == KernelSolution::NONE) {
224  throw LSST_EXCEPT(pexExcept::Exception, "Kernel not solved; cannot return image");
225  }
228  );
229  (void)_kernel->computeImage(*image, false);
230  return image;
231  }
232 
233  template <typename InputT>
235  if (_solvedBy == KernelSolution::NONE) {
236  throw LSST_EXCEPT(pexExcept::Exception, "Kernel not solved; cannot return background");
237  }
238  return _background;
239  }
240 
241  template <typename InputT>
243  if (_solvedBy == KernelSolution::NONE) {
244  throw LSST_EXCEPT(pexExcept::Exception, "Kernel not solved; cannot return ksum");
245  }
246  return _kSum;
247  }
248 
249  template <typename InputT>
250  std::pair<std::shared_ptr<lsst::afw::math::Kernel>, double>
252  if (_solvedBy == KernelSolution::NONE) {
253  throw LSST_EXCEPT(pexExcept::Exception, "Kernel not solved; cannot return solution");
254  }
255 
256  return std::make_pair(_kernel, _background);
257  }
258 
259  template <typename InputT>
261  lsst::afw::image::Image<InputT> const &templateImage,
262  lsst::afw::image::Image<InputT> const &scienceImage,
264  ) {
265 
266  afwMath::Statistics varStats = afwMath::makeStatistics(varianceEstimate, afwMath::MIN);
267  if (varStats.getValue(afwMath::MIN) < 0.0) {
269  "Error: variance less than 0.0");
270  }
271  if (varStats.getValue(afwMath::MIN) == 0.0) {
273  "Error: variance equals 0.0, cannot inverse variance weight");
274  }
275 
276  lsst::afw::math::KernelList basisList =
277  std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList();
278 
279  unsigned int const nKernelParameters = basisList.size();
280  unsigned int const nBackgroundParameters = _fitForBackground ? 1 : 0;
281  unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
282 
283  std::vector<std::shared_ptr<afwMath::Kernel> >::const_iterator kiter = basisList.begin();
284 
285  /* Ignore buffers around edge of convolved images :
286  *
287  * If the kernel has width 5, it has center pixel 2. The first good pixel
288  * is the (5-2)=3rd pixel, which is array index 2, and ends up being the
289  * index of the central pixel.
290  *
291  * You also have a buffer of unusable pixels on the other side, numbered
292  * width-center-1. The last good usable pixel is N-width+center+1.
293  *
294  * Example : the kernel is width = 5, center = 2
295  *
296  * ---|---|-c-|---|---|
297  *
298  * the image is width = N
299  * convolve this with the kernel, and you get
300  *
301  * |-x-|-x-|-g-|---|---| ... |---|---|-g-|-x-|-x-|
302  *
303  * g = first/last good pixel
304  * x = bad
305  *
306  * the first good pixel is the array index that has the value "center", 2
307  * the last good pixel has array index N-(5-2)+1
308  * eg. if N = 100, you want to use up to index 97
309  * 100-3+1 = 98, and the loops use i < 98, meaning the last
310  * index you address is 97.
311  */
312 
313  /* NOTE - we are accessing particular elements of Eigen arrays using
314  these coordinates, therefore they need to be in LOCAL coordinates.
315  This was written before ndarray unification.
316  */
317  afwGeom::Box2I goodBBox = (*kiter)->shrinkBBox(templateImage.getBBox(afwImage::LOCAL));
318  unsigned int const startCol = goodBBox.getMinX();
319  unsigned int const startRow = goodBBox.getMinY();
320  // endCol/Row is one past the index of the last good col/row
321  unsigned int endCol = goodBBox.getMaxX() + 1;
322  unsigned int endRow = goodBBox.getMaxY() + 1;
323 
324  boost::timer t;
325  t.restart();
326 
327  /* Eigen representation of input images; only the pixels that are unconvolved in cimage below */
328  Eigen::MatrixXd eigenTemplate = imageToEigenMatrix(templateImage).block(startRow,
329  startCol,
330  endRow-startRow,
331  endCol-startCol);
332  Eigen::MatrixXd eigenScience = imageToEigenMatrix(scienceImage).block(startRow,
333  startCol,
334  endRow-startRow,
335  endCol-startCol);
336  Eigen::MatrixXd eigeniVariance = imageToEigenMatrix(varianceEstimate).block(
337  startRow, startCol, endRow-startRow, endCol-startCol
338  ).array().inverse().matrix();
339 
340  /* Resize into 1-D for later usage */
341  eigenTemplate.resize(eigenTemplate.rows()*eigenTemplate.cols(), 1);
342  eigenScience.resize(eigenScience.rows()*eigenScience.cols(), 1);
343  eigeniVariance.resize(eigeniVariance.rows()*eigeniVariance.cols(), 1);
344 
345  /* Holds image convolved with basis function */
346  afwImage::Image<PixelT> cimage(templateImage.getDimensions());
347 
348  /* Holds eigen representation of image convolved with all basis functions */
349  std::vector<std::shared_ptr<Eigen::MatrixXd> > convolvedEigenList(nKernelParameters);
350 
351  /* Iterators over convolved image list and basis list */
352  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiter =
353  convolvedEigenList.begin();
354  /* Create C_i in the formalism of Alard & Lupton */
355  for (kiter = basisList.begin(); kiter != basisList.end(); ++kiter, ++eiter) {
356  afwMath::convolve(cimage, templateImage, **kiter, false); /* cimage stores convolved image */
357 
358  std::shared_ptr<Eigen::MatrixXd> cMat (
359  new Eigen::MatrixXd(imageToEigenMatrix(cimage).block(startRow,
360  startCol,
361  endRow-startRow,
362  endCol-startCol))
363  );
364  cMat->resize(cMat->rows()*cMat->cols(), 1);
365  *eiter = cMat;
366 
367  }
368 
369  double time = t.elapsed();
370  LOGL_DEBUG("TRACE3.ip.diffim.StaticKernelSolution.build",
371  "Total compute time to do basis convolutions : %.2f s", time);
372  t.restart();
373 
374  /*
375  Load matrix with all values from convolvedEigenList : all images
376  (eigeniVariance, convolvedEigenList) must be the same size
377  */
378  Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
379  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiterj =
380  convolvedEigenList.begin();
381  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiterE =
382  convolvedEigenList.end();
383  for (unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
384  cMat.col(kidxj) = (*eiterj)->col(0);
385  }
386  /* Treat the last "image" as all 1's to do the background calculation. */
387  if (_fitForBackground)
388  cMat.col(nParameters-1).fill(1.);
389 
390  _cMat.reset(new Eigen::MatrixXd(cMat));
391  _ivVec.reset(new Eigen::VectorXd(eigeniVariance.col(0)));
392  _iVec.reset(new Eigen::VectorXd(eigenScience.col(0)));
393 
394  /* Make these outside of solve() so I can check condition number */
395  _mMat.reset(new Eigen::MatrixXd((*_cMat).transpose() * ((*_ivVec).asDiagonal() * (*_cMat))));
396  _bVec.reset(new Eigen::VectorXd((*_cMat).transpose() * ((*_ivVec).asDiagonal() * (*_iVec))));
397  }
398 
399  template <typename InputT>
401  LOGL_DEBUG("TRACE3.ip.diffim.StaticKernelSolution.solve",
402  "mMat is %d x %d; bVec is %d; cMat is %d x %d; vVec is %d; iVec is %d",
403  (*_mMat).rows(), (*_mMat).cols(), (*_bVec).size(),
404  (*_cMat).rows(), (*_cMat).cols(), (*_ivVec).size(), (*_iVec).size());
405 
406  /* If I put this here I can't check for condition number before solving */
407  /*
408  _mMat.reset(new Eigen::MatrixXd((*_cMat).transpose() * ((*_ivVec).asDiagonal() * (*_cMat))));
409  _bVec.reset(new Eigen::VectorXd((*_cMat).transpose() * ((*_ivVec).asDiagonal() * (*_iVec))));
410  */
411 
412  if (DEBUG_MATRIX) {
413  std::cout << "C" << std::endl;
414  std::cout << (*_cMat) << std::endl;
415  std::cout << "iV" << std::endl;
416  std::cout << (*_ivVec) << std::endl;
417  std::cout << "I" << std::endl;
418  std::cout << (*_iVec) << std::endl;
419  }
420 
421  try {
423  } catch (pexExcept::Exception &e) {
424  LSST_EXCEPT_ADD(e, "Unable to solve static kernel matrix");
425  throw e;
426  }
427  /* Turn matrices into _kernel and _background */
428  _setKernel();
429  }
430 
431  template <typename InputT>
433  if (_solvedBy == KernelSolution::NONE) {
434  throw LSST_EXCEPT(pexExcept::Exception, "Kernel not solved; cannot make solution");
435  }
436 
437  unsigned int const nParameters = _aVec->size();
438  unsigned int const nBackgroundParameters = _fitForBackground ? 1 : 0;
439  unsigned int const nKernelParameters =
440  std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList().size();
441  if (nParameters != (nKernelParameters + nBackgroundParameters))
442  throw LSST_EXCEPT(pexExcept::Exception, "Mismatched sizes in kernel solution");
443 
444  /* Fill in the kernel results */
445  std::vector<double> kValues(nKernelParameters);
446  for (unsigned int idx = 0; idx < nKernelParameters; idx++) {
447  if (std::isnan((*_aVec)(idx))) {
449  str(boost::format("Unable to determine kernel solution %d (nan)") % idx));
450  }
451  kValues[idx] = (*_aVec)(idx);
452  }
453  _kernel->setKernelParameters(kValues);
454 
457  );
458  _kSum = _kernel->computeImage(*image, false);
459 
460  if (_fitForBackground) {
461  if (std::isnan((*_aVec)(nParameters-1))) {
463  str(boost::format("Unable to determine background solution %d (nan)") %
464  (nParameters-1)));
465  }
466  _background = (*_aVec)(nParameters-1);
467  }
468  }
469 
470 
471  template <typename InputT>
473  throw LSST_EXCEPT(pexExcept::Exception, "Uncertainty calculation not supported");
474 
475  /* Estimate of parameter uncertainties comes from the inverse of the
476  * covariance matrix (noise spectrum).
477  * N.R. 15.4.8 to 15.4.15
478  *
479  * Since this is a linear problem no need to use Fisher matrix
480  * N.R. 15.5.8
481  *
482  * Although I might be able to take advantage of the solution above.
483  * Since this now works and is not the rate limiting step, keep as-is for DC3a.
484  *
485  * Use Cholesky decomposition again.
486  * Cholkesy:
487  * Cov = L L^t
488  * Cov^(-1) = (L L^t)^(-1)
489  * = (L^T)^-1 L^(-1)
490  *
491  * Code would be:
492  *
493  * Eigen::MatrixXd cov = (*_mMat).transpose() * (*_mMat);
494  * Eigen::LLT<Eigen::MatrixXd> llt = cov.llt();
495  * Eigen::MatrixXd error2 = llt.matrixL().transpose().inverse()*llt.matrixL().inverse();
496  */
497  }
498 
499  /*******************************************************************************************************/
500 
501  template <typename InputT>
503  lsst::afw::math::KernelList const& basisList,
504  bool fitForBackground
505  ) :
506  StaticKernelSolution<InputT>(basisList, fitForBackground)
507  {};
508 
509  template <typename InputT>
511  lsst::afw::image::Image<InputT> const &templateImage,
512  lsst::afw::image::Image<InputT> const &scienceImage,
515  ) {
516 
517  afwMath::Statistics varStats = afwMath::makeStatistics(varianceEstimate, afwMath::MIN);
518  if (varStats.getValue(afwMath::MIN) < 0.0) {
520  "Error: variance less than 0.0");
521  }
522  if (varStats.getValue(afwMath::MIN) == 0.0) {
524  "Error: variance equals 0.0, cannot inverse variance weight");
525  }
526 
527  /* Full footprint of all input images */
528  afwDet::Footprint::Ptr fullFp(new afwDet::Footprint(templateImage.getBBox()));
529 
530  afwMath::KernelList basisList =
531  std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
532  std::vector<std::shared_ptr<afwMath::Kernel> >::const_iterator kiter = basisList.begin();
533 
534  /* Only BAD pixels marked in this mask */
535  afwImage::MaskPixel bitMask =
540 
541  /* Create a Footprint that contains all the masked pixels set above */
543  afwDet::FootprintSet maskFpSet(pixelMask, threshold, true);
544 
545  /* And spread it by the kernel half width */
546  int growPix = (*kiter)->getCtr().getX();
547  afwDet::FootprintSet maskedFpSetGrown(maskFpSet, growPix, true);
548 
549 #if 0
550  for (typename afwDet::FootprintSet::FootprintList::iterator
551  ptr = maskedFpSetGrown.getFootprints()->begin(),
552  end = maskedFpSetGrown.getFootprints()->end();
553  ptr != end;
554  ++ptr) {
555 
556  afwDet::setMaskFromFootprint(finalMask,
557  (**ptr),
559  }
560 #endif
561 
562  afwImage::Mask<afwImage::MaskPixel> finalMask(pixelMask.getDimensions());
564  *(maskedFpSetGrown.getFootprints()),
566  pixelMask.writeFits("pixelmask.fits");
567  finalMask.writeFits("finalmask.fits");
568 
569 
570  ndarray::Array<int, 1, 1> maskArray =
571  ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
572  afwDet::flattenArray(*fullFp, finalMask.getArray(),
573  maskArray, templateImage.getXY0()); /* Need to fake the XY0 */
574  ndarray::EigenView<int, 1, 1> maskEigen(maskArray);
575 
576  ndarray::Array<InputT, 1, 1> arrayTemplate =
577  ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
578  afwDet::flattenArray(*fullFp, templateImage.getArray(),
579  arrayTemplate, templateImage.getXY0());
580  ndarray::EigenView<InputT, 1, 1> eigenTemplate0(arrayTemplate);
581 
582  ndarray::Array<InputT, 1, 1> arrayScience =
583  ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
584  afwDet::flattenArray(*fullFp, scienceImage.getArray(),
585  arrayScience, scienceImage.getXY0());
586  ndarray::EigenView<InputT, 1, 1> eigenScience0(arrayScience);
587 
588  ndarray::Array<afwImage::VariancePixel, 1, 1> arrayVariance =
589  ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
590  afwDet::flattenArray(*fullFp, varianceEstimate.getArray(),
591  arrayVariance, varianceEstimate.getXY0());
592  ndarray::EigenView<afwImage::VariancePixel, 1, 1> eigenVariance0(arrayVariance);
593 
594  int nGood = 0;
595  for (int i = 0; i < maskEigen.size(); i++) {
596  if (maskEigen(i) == 0.0)
597  nGood += 1;
598  }
599 
600  Eigen::VectorXd eigenTemplate(nGood);
601  Eigen::VectorXd eigenScience(nGood);
602  Eigen::VectorXd eigenVariance(nGood);
603  int nUsed = 0;
604  for (int i = 0; i < maskEigen.size(); i++) {
605  if (maskEigen(i) == 0.0) {
606  eigenTemplate(nUsed) = eigenTemplate0(i);
607  eigenScience(nUsed) = eigenScience0(i);
608  eigenVariance(nUsed) = eigenVariance0(i);
609  nUsed += 1;
610  }
611  }
612 
613 
614  boost::timer t;
615  t.restart();
616 
617  unsigned int const nKernelParameters = basisList.size();
618  unsigned int const nBackgroundParameters = this->_fitForBackground ? 1 : 0;
619  unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
620 
621  /* Holds image convolved with basis function */
622  afwImage::Image<InputT> cimage(templateImage.getDimensions());
623 
624  /* Holds eigen representation of image convolved with all basis functions */
625  std::vector<std::shared_ptr<Eigen::VectorXd> >
626  convolvedEigenList(nKernelParameters);
627 
628  /* Iterators over convolved image list and basis list */
629  typename std::vector<std::shared_ptr<Eigen::VectorXd> >::iterator eiter =
630  convolvedEigenList.begin();
631 
632  /* Create C_i in the formalism of Alard & Lupton */
633  for (kiter = basisList.begin(); kiter != basisList.end(); ++kiter, ++eiter) {
634  afwMath::convolve(cimage, templateImage, **kiter, false); /* cimage stores convolved image */
635 
636  ndarray::Array<InputT, 1, 1> arrayC =
637  ndarray::allocate(ndarray::makeVector(fullFp->getArea()));
638  afwDet::flattenArray(*fullFp, cimage.getArray(),
639  arrayC, cimage.getXY0());
640  ndarray::EigenView<InputT, 1, 1> eigenC0(arrayC);
641 
642  Eigen::VectorXd eigenC(nGood);
643  int nUsed = 0;
644  for (int i = 0; i < maskEigen.size(); i++) {
645  if (maskEigen(i) == 0.0) {
646  eigenC(nUsed) = eigenC0(i);
647  nUsed += 1;
648  }
649  }
650 
651  std::shared_ptr<Eigen::VectorXd>
652  eigenCptr (new Eigen::VectorXd(eigenC));
653 
654  *eiter = eigenCptr;
655  }
656  double time = t.elapsed();
657  LOGL_DEBUG("TRACE3.ip.diffim.StaticKernelSolution.buildWithMask",
658  "Total compute time to do basis convolutions : %.2f s", time);
659  t.restart();
660 
661  /* Load matrix with all convolved images */
662  Eigen::MatrixXd cMat(eigenTemplate.size(), nParameters);
663  typename std::vector<std::shared_ptr<Eigen::VectorXd> >::iterator eiterj =
664  convolvedEigenList.begin();
665  typename std::vector<std::shared_ptr<Eigen::VectorXd> >::iterator eiterE =
666  convolvedEigenList.end();
667  for (unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
668  cMat.block(0, kidxj, eigenTemplate.size(), 1) =
669  Eigen::MatrixXd(**eiterj).block(0, 0, eigenTemplate.size(), 1);
670  }
671  /* Treat the last "image" as all 1's to do the background calculation. */
672  if (this->_fitForBackground)
673  cMat.col(nParameters-1).fill(1.);
674 
675  this->_cMat.reset(new Eigen::MatrixXd(cMat));
676  //this->_ivVec.reset(new Eigen::VectorXd((eigenVariance.template cast<double>()).cwise().inverse()));
677  //this->_iVec.reset(new Eigen::VectorXd(eigenScience.template cast<double>()));
678  this->_ivVec.reset(new Eigen::VectorXd(eigenVariance.array().inverse().matrix()));
679  this->_iVec.reset(new Eigen::VectorXd(eigenScience));
680 
681  /* Make these outside of solve() so I can check condition number */
682  this->_mMat.reset(
683  new Eigen::MatrixXd(this->_cMat->transpose() * this->_ivVec->asDiagonal() * *(this->_cMat))
684  );
685  this->_bVec.reset(
686  new Eigen::VectorXd(this->_cMat->transpose() * this->_ivVec->asDiagonal() * *(this->_iVec))
687  );
688  }
689 
690 
691  template <typename InputT>
693  lsst::afw::image::Image<InputT> const &templateImage,
694  lsst::afw::image::Image<InputT> const &scienceImage,
697  ) {
698 
699  afwMath::Statistics varStats = afwMath::makeStatistics(varianceEstimate, afwMath::MIN);
700  if (varStats.getValue(afwMath::MIN) < 0.0) {
702  "Error: variance less than 0.0");
703  }
704  if (varStats.getValue(afwMath::MIN) == 0.0) {
706  "Error: variance equals 0.0, cannot inverse variance weight");
707  }
708 
709  lsst::afw::math::KernelList basisList =
710  std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
711  std::vector<std::shared_ptr<afwMath::Kernel> >::const_iterator kiter = basisList.begin();
712 
713  /* Only BAD pixels marked in this mask */
715  afwImage::MaskPixel bitMask =
719  sMask &= bitMask;
720  /* TBD: Need to figure out a way to spread this; currently done in Python */
721 
722  unsigned int const nKernelParameters = basisList.size();
723  unsigned int const nBackgroundParameters = this->_fitForBackground ? 1 : 0;
724  unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
725 
726  /* NOTE - we are accessing particular elements of Eigen arrays using
727  these coordinates, therefore they need to be in LOCAL coordinates.
728  This was written before ndarray unification.
729  */
730  /* Ignore known EDGE pixels for speed */
731  afwGeom::Box2I shrunkLocalBBox = (*kiter)->shrinkBBox(templateImage.getBBox(afwImage::LOCAL));
732  LOGL_DEBUG("TRACE3.ip.diffim.MaskedKernelSolution.build",
733  "Limits of good pixels after convolution: %d,%d -> %d,%d (local)",
734  shrunkLocalBBox.getMinX(), shrunkLocalBBox.getMinY(),
735  shrunkLocalBBox.getMaxX(), shrunkLocalBBox.getMaxY());
736 
737  /* Subimages are addressed in raw pixel coordinates */
738  unsigned int startCol = shrunkLocalBBox.getMinX();
739  unsigned int startRow = shrunkLocalBBox.getMinY();
740  unsigned int endCol = shrunkLocalBBox.getMaxX();
741  unsigned int endRow = shrunkLocalBBox.getMaxY();
742  /* Needed for Eigen block slicing operation */
743  endCol += 1;
744  endRow += 1;
745 
746  boost::timer t;
747  t.restart();
748 
749  /* Eigen representation of input images; only the pixels that are unconvolved in cimage below */
750  Eigen::MatrixXi eMask = maskToEigenMatrix(sMask).block(startRow,
751  startCol,
752  endRow-startRow,
753  endCol-startCol);
754 
755  Eigen::MatrixXd eigenTemplate = imageToEigenMatrix(templateImage).block(startRow,
756  startCol,
757  endRow-startRow,
758  endCol-startCol);
759  Eigen::MatrixXd eigenScience = imageToEigenMatrix(scienceImage).block(startRow,
760  startCol,
761  endRow-startRow,
762  endCol-startCol);
763  Eigen::MatrixXd eigeniVariance = imageToEigenMatrix(varianceEstimate).block(
764  startRow, startCol, endRow-startRow, endCol-startCol
765  ).array().inverse().matrix();
766 
767  /* Resize into 1-D for later usage */
768  eMask.resize(eMask.rows()*eMask.cols(), 1);
769  eigenTemplate.resize(eigenTemplate.rows()*eigenTemplate.cols(), 1);
770  eigenScience.resize(eigenScience.rows()*eigenScience.cols(), 1);
771  eigeniVariance.resize(eigeniVariance.rows()*eigeniVariance.cols(), 1);
772 
773  /* Do the masking, slowly for now... */
774  Eigen::MatrixXd maskedEigenTemplate(eigenTemplate.rows(), 1);
775  Eigen::MatrixXd maskedEigenScience(eigenScience.rows(), 1);
776  Eigen::MatrixXd maskedEigeniVariance(eigeniVariance.rows(), 1);
777  int nGood = 0;
778  for (int i = 0; i < eMask.rows(); i++) {
779  if (eMask(i, 0) == 0) {
780  maskedEigenTemplate(nGood, 0) = eigenTemplate(i, 0);
781  maskedEigenScience(nGood, 0) = eigenScience(i, 0);
782  maskedEigeniVariance(nGood, 0) = eigeniVariance(i, 0);
783  nGood += 1;
784  }
785  }
786  /* Can't resize() since all values are lost; use blocks */
787  eigenTemplate = maskedEigenTemplate.block(0, 0, nGood, 1);
788  eigenScience = maskedEigenScience.block(0, 0, nGood, 1);
789  eigeniVariance = maskedEigeniVariance.block(0, 0, nGood, 1);
790 
791 
792  /* Holds image convolved with basis function */
793  afwImage::Image<InputT> cimage(templateImage.getDimensions());
794 
795  /* Holds eigen representation of image convolved with all basis functions */
796  std::vector<std::shared_ptr<Eigen::MatrixXd> > convolvedEigenList(nKernelParameters);
797 
798  /* Iterators over convolved image list and basis list */
799  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiter =
800  convolvedEigenList.begin();
801  /* Create C_i in the formalism of Alard & Lupton */
802  for (kiter = basisList.begin(); kiter != basisList.end(); ++kiter, ++eiter) {
803  afwMath::convolve(cimage, templateImage, **kiter, false); /* cimage stores convolved image */
804 
805  Eigen::MatrixXd cMat = imageToEigenMatrix(cimage).block(startRow,
806  startCol,
807  endRow-startRow,
808  endCol-startCol);
809  cMat.resize(cMat.rows() * cMat.cols(), 1);
810 
811  /* Do masking */
812  Eigen::MatrixXd maskedcMat(cMat.rows(), 1);
813  int nGood = 0;
814  for (int i = 0; i < eMask.rows(); i++) {
815  if (eMask(i, 0) == 0) {
816  maskedcMat(nGood, 0) = cMat(i, 0);
817  nGood += 1;
818  }
819  }
820  cMat = maskedcMat.block(0, 0, nGood, 1);
821  std::shared_ptr<Eigen::MatrixXd> cMatPtr (new Eigen::MatrixXd(cMat));
822  *eiter = cMatPtr;
823  }
824 
825  double time = t.elapsed();
826  LOGL_DEBUG("TRACE3.ip.diffim.StaticKernelSolution.build",
827  "Total compute time to do basis convolutions : %.2f s", time);
828  t.restart();
829 
830  /*
831  Load matrix with all values from convolvedEigenList : all images
832  (eigeniVariance, convolvedEigenList) must be the same size
833  */
834  Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
835  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiterj =
836  convolvedEigenList.begin();
837  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiterE =
838  convolvedEigenList.end();
839  for (unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
840  cMat.col(kidxj) = (*eiterj)->col(0);
841  }
842  /* Treat the last "image" as all 1's to do the background calculation. */
843  if (this->_fitForBackground)
844  cMat.col(nParameters-1).fill(1.);
845 
846  this->_cMat.reset(new Eigen::MatrixXd(cMat));
847  this->_ivVec.reset(new Eigen::VectorXd(eigeniVariance.col(0)));
848  this->_iVec.reset(new Eigen::VectorXd(eigenScience.col(0)));
849 
850  /* Make these outside of solve() so I can check condition number */
851  this->_mMat.reset(
852  new Eigen::MatrixXd(this->_cMat->transpose() * this->_ivVec->asDiagonal() * *(this->_cMat))
853  );
854  this->_bVec.reset(
855  new Eigen::VectorXd(this->_cMat->transpose() * this->_ivVec->asDiagonal() * *(this->_iVec))
856  );
857 
858  }
859 
860  /* NOTE - this was written before the ndarray unification. I am rewriting
861  buildSingleMask to use the ndarray stuff */
862  template <typename InputT>
864  lsst::afw::image::Image<InputT> const &templateImage,
865  lsst::afw::image::Image<InputT> const &scienceImage,
867  lsst::afw::geom::Box2I maskBox
868  ) {
869 
870  afwMath::Statistics varStats = afwMath::makeStatistics(varianceEstimate, afwMath::MIN);
871  if (varStats.getValue(afwMath::MIN) < 0.0) {
873  "Error: variance less than 0.0");
874  }
875  if (varStats.getValue(afwMath::MIN) == 0.0) {
877  "Error: variance equals 0.0, cannot inverse variance weight");
878  }
879 
880  lsst::afw::math::KernelList basisList =
881  std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(this->_kernel)->getKernelList();
882 
883  unsigned int const nKernelParameters = basisList.size();
884  unsigned int const nBackgroundParameters = this->_fitForBackground ? 1 : 0;
885  unsigned int const nParameters = nKernelParameters + nBackgroundParameters;
886 
887  std::vector<std::shared_ptr<afwMath::Kernel> >::const_iterator kiter = basisList.begin();
888 
889  /*
890  NOTE : If we are using these views in Afw's Image space, we need to
891  make sure and compensate for the XY0 of the image:
892 
893  afwGeom::Box2I fullBBox = templateImage.getBBox();
894  int maskStartCol = maskBox.getMinX();
895  int maskStartRow = maskBox.getMinY();
896  int maskEndCol = maskBox.getMaxX();
897  int maskEndRow = maskBox.getMaxY();
898 
899 
900  If we are going to be doing the slicing in Eigen matrices derived from
901  the images, ignore the XY0.
902 
903  afwGeom::Box2I fullBBox = templateImage.getBBox(afwImage::LOCAL);
904 
905  int maskStartCol = maskBox.getMinX() - templateImage.getX0();
906  int maskStartRow = maskBox.getMinY() - templateImage.getY0();
907  int maskEndCol = maskBox.getMaxX() - templateImage.getX0();
908  int maskEndRow = maskBox.getMaxY() - templateImage.getY0();
909 
910  */
911 
912 
913  afwGeom::Box2I shrunkBBox = (*kiter)->shrinkBBox(templateImage.getBBox());
914 
915  LOGL_DEBUG("TRACE3.ip.diffim.MaskedKernelSolution.build",
916  "Limits of good pixels after convolution: %d,%d -> %d,%d",
917  shrunkBBox.getMinX(), shrunkBBox.getMinY(),
918  shrunkBBox.getMaxX(), shrunkBBox.getMaxY());
919 
920  unsigned int const startCol = shrunkBBox.getMinX();
921  unsigned int const startRow = shrunkBBox.getMinY();
922  unsigned int const endCol = shrunkBBox.getMaxX();
923  unsigned int const endRow = shrunkBBox.getMaxY();
924 
925  /* NOTE: no endCol/endRow += 1 for block slicing, since we are doing the
926  slicing using Afw, not Eigen
927 
928  Eigen arrays have index 0,0 in the upper right, while LSST images
929  have 0,0 in the lower left. The y-axis is flipped. When translating
930  Images to Eigen matrices in ipDiffim::imageToEigenMatrix this is
931  accounted for. However, we still need to be aware of this fact if
932  addressing subregions of an Eigen matrix. This is why the slicing is
933  done in Afw, its cleaner.
934 
935  Please see examples/maskedKernel.cc for elaboration on some of the
936  tests done to make sure this indexing gets done right.
937 
938  */
939 
940 
941  /* Inner limits; of mask box */
942  int maskStartCol = maskBox.getMinX();
943  int maskStartRow = maskBox.getMinY();
944  int maskEndCol = maskBox.getMaxX();
945  int maskEndRow = maskBox.getMaxY();
946 
947  /*
948 
949  |---------------------------|
950  | Kernel Boundary |
951  | |---------------------| |
952  | | Top | |
953  | |......_________......| |
954  | | | | | |
955  | | L | Box | R | |
956  | | | | | |
957  | |......---------......| |
958  | | Bottom | |
959  | |---------------------| |
960  | |
961  |---------------------------|
962 
963  4 regions we want to extract from the pixels: top bottom left right
964 
965  */
966  afwGeom::Box2I tBox = afwGeom::Box2I(afwGeom::Point2I(startCol, maskEndRow + 1),
967  afwGeom::Point2I(endCol, endRow));
968 
969  afwGeom::Box2I bBox = afwGeom::Box2I(afwGeom::Point2I(startCol, startRow),
970  afwGeom::Point2I(endCol, maskStartRow - 1));
971 
972  afwGeom::Box2I lBox = afwGeom::Box2I(afwGeom::Point2I(startCol, maskStartRow),
973  afwGeom::Point2I(maskStartCol - 1, maskEndRow));
974 
975  afwGeom::Box2I rBox = afwGeom::Box2I(afwGeom::Point2I(maskEndCol + 1, maskStartRow),
976  afwGeom::Point2I(endCol, maskEndRow));
977 
978  LOGL_DEBUG("TRACE3.ip.diffim.MaskedKernelSolution.build",
979  "Upper good pixel region: %d,%d -> %d,%d",
980  tBox.getMinX(), tBox.getMinY(), tBox.getMaxX(), tBox.getMaxY());
981  LOGL_DEBUG("TRACE3.ip.diffim.MaskedKernelSolution.build",
982  "Bottom good pixel region: %d,%d -> %d,%d",
983  bBox.getMinX(), bBox.getMinY(), bBox.getMaxX(), bBox.getMaxY());
984  LOGL_DEBUG("TRACE3.ip.diffim.MaskedKernelSolution.build",
985  "Left good pixel region: %d,%d -> %d,%d",
986  lBox.getMinX(), lBox.getMinY(), lBox.getMaxX(), lBox.getMaxY());
987  LOGL_DEBUG("TRACE3.ip.diffim.MaskedKernelSolution.build",
988  "Right good pixel region: %d,%d -> %d,%d",
989  rBox.getMinX(), rBox.getMinY(), rBox.getMaxX(), rBox.getMaxY());
990 
991  std::vector<afwGeom::Box2I> boxArray;
992  boxArray.push_back(tBox);
993  boxArray.push_back(bBox);
994  boxArray.push_back(lBox);
995  boxArray.push_back(rBox);
996 
997  int totalSize = tBox.getWidth() * tBox.getHeight();
998  totalSize += bBox.getWidth() * bBox.getHeight();
999  totalSize += lBox.getWidth() * lBox.getHeight();
1000  totalSize += rBox.getWidth() * rBox.getHeight();
1001 
1002  Eigen::MatrixXd eigenTemplate(totalSize, 1);
1003  Eigen::MatrixXd eigenScience(totalSize, 1);
1004  Eigen::MatrixXd eigeniVariance(totalSize, 1);
1005  eigenTemplate.setZero();
1006  eigenScience.setZero();
1007  eigeniVariance.setZero();
1008 
1009  boost::timer t;
1010  t.restart();
1011 
1012  int nTerms = 0;
1013  typename std::vector<afwGeom::Box2I>::iterator biter = boxArray.begin();
1014  for (; biter != boxArray.end(); ++biter) {
1015  int area = (*biter).getWidth() * (*biter).getHeight();
1016 
1017  afwImage::Image<InputT> siTemplate(templateImage, *biter);
1018  afwImage::Image<InputT> siScience(scienceImage, *biter);
1019  afwImage::Image<InputT> sVarEstimate(varianceEstimate, *biter);
1020 
1021  Eigen::MatrixXd eTemplate = imageToEigenMatrix(siTemplate);
1022  Eigen::MatrixXd eScience = imageToEigenMatrix(siScience);
1023  Eigen::MatrixXd eiVarEstimate = imageToEigenMatrix(sVarEstimate).array().inverse().matrix();
1024 
1025  eTemplate.resize(area, 1);
1026  eScience.resize(area, 1);
1027  eiVarEstimate.resize(area, 1);
1028 
1029  eigenTemplate.block(nTerms, 0, area, 1) = eTemplate.block(0, 0, area, 1);
1030  eigenScience.block(nTerms, 0, area, 1) = eScience.block(0, 0, area, 1);
1031  eigeniVariance.block(nTerms, 0, area, 1) = eiVarEstimate.block(0, 0, area, 1);
1032 
1033  nTerms += area;
1034  }
1035 
1036  afwImage::Image<InputT> cimage(templateImage.getDimensions());
1037 
1038  std::vector<std::shared_ptr<Eigen::MatrixXd> > convolvedEigenList(nKernelParameters);
1039  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiter =
1040  convolvedEigenList.begin();
1041  /* Create C_i in the formalism of Alard & Lupton */
1042  for (kiter = basisList.begin(); kiter != basisList.end(); ++kiter, ++eiter) {
1043  afwMath::convolve(cimage, templateImage, **kiter, false); /* cimage stores convolved image */
1044  Eigen::MatrixXd cMat(totalSize, 1);
1045  cMat.setZero();
1046 
1047  int nTerms = 0;
1048  typename std::vector<afwGeom::Box2I>::iterator biter = boxArray.begin();
1049  for (; biter != boxArray.end(); ++biter) {
1050  int area = (*biter).getWidth() * (*biter).getHeight();
1051 
1052  afwImage::Image<InputT> csubimage(cimage, *biter);
1053  Eigen::MatrixXd esubimage = imageToEigenMatrix(csubimage);
1054  esubimage.resize(area, 1);
1055  cMat.block(nTerms, 0, area, 1) = esubimage.block(0, 0, area, 1);
1056 
1057  nTerms += area;
1058  }
1059 
1060  std::shared_ptr<Eigen::MatrixXd> cMatPtr (new Eigen::MatrixXd(cMat));
1061  *eiter = cMatPtr;
1062 
1063  }
1064 
1065  double time = t.elapsed();
1066  LOGL_DEBUG("TRACE3.ip.diffim.MaskedKernelSolution.build",
1067  "Total compute time to do basis convolutions : %.2f s", time);
1068  t.restart();
1069 
1070  /*
1071  Load matrix with all values from convolvedEigenList : all images
1072  (eigeniVariance, convolvedEigenList) must be the same size
1073  */
1074  Eigen::MatrixXd cMat(eigenTemplate.col(0).size(), nParameters);
1075  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiterj =
1076  convolvedEigenList.begin();
1077  typename std::vector<std::shared_ptr<Eigen::MatrixXd> >::iterator eiterE =
1078  convolvedEigenList.end();
1079  for (unsigned int kidxj = 0; eiterj != eiterE; eiterj++, kidxj++) {
1080  cMat.col(kidxj) = (*eiterj)->col(0);
1081  }
1082  /* Treat the last "image" as all 1's to do the background calculation. */
1083  if (this->_fitForBackground)
1084  cMat.col(nParameters-1).fill(1.);
1085 
1086  this->_cMat.reset(new Eigen::MatrixXd(cMat));
1087  this->_ivVec.reset(new Eigen::VectorXd(eigeniVariance.col(0)));
1088  this->_iVec.reset(new Eigen::VectorXd(eigenScience.col(0)));
1089 
1090  /* Make these outside of solve() so I can check condition number */
1091  this->_mMat.reset(
1092  new Eigen::MatrixXd(this->_cMat->transpose() * this->_ivVec->asDiagonal() * *(this->_cMat))
1093  );
1094  this->_bVec.reset(
1095  new Eigen::VectorXd(this->_cMat->transpose() * this->_ivVec->asDiagonal() * *(this->_iVec))
1096  );
1097 
1098  }
1099  /*******************************************************************************************************/
1100 
1101 
1102  template <typename InputT>
1104  lsst::afw::math::KernelList const& basisList,
1105  bool fitForBackground,
1106  std::shared_ptr<Eigen::MatrixXd> hMat,
1108  )
1109  :
1110  StaticKernelSolution<InputT>(basisList, fitForBackground),
1111  _hMat(hMat),
1112  _policy(policy)
1113  {};
1114 
1115  template <typename InputT>
1117  Eigen::MatrixXd vMat = (this->_cMat)->jacobiSvd().matrixV();
1118  Eigen::MatrixXd vMatvMatT = vMat * vMat.transpose();
1119 
1120  /* Find pseudo inverse of mMat, which may be ill conditioned */
1121  Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> eVecValues(*(this->_mMat));
1122  Eigen::MatrixXd const& rMat = eVecValues.eigenvectors();
1123  Eigen::VectorXd eValues = eVecValues.eigenvalues();
1124  double eMax = eValues.maxCoeff();
1125  for (int i = 0; i != eValues.rows(); ++i) {
1126  if (eValues(i) == 0.0) {
1127  eValues(i) = 0.0;
1128  }
1129  else if ((eMax / eValues(i)) > maxCond) {
1130  LOGL_DEBUG("TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1131  "Truncating eValue %d; %.5e / %.5e = %.5e vs. %.5e",
1132  i, eMax, eValues(i), eMax / eValues(i), maxCond);
1133  eValues(i) = 0.0;
1134  }
1135  else {
1136  eValues(i) = 1.0 / eValues(i);
1137  }
1138  }
1139  Eigen::MatrixXd mInv = rMat * eValues.asDiagonal() * rMat.transpose();
1140 
1141  std::vector<double> lambdas = _createLambdaSteps();
1142  std::vector<double> risks;
1143  for (unsigned int i = 0; i < lambdas.size(); i++) {
1144  double l = lambdas[i];
1145  Eigen::MatrixXd mLambda = *(this->_mMat) + l * (*_hMat);
1146 
1147  try {
1148  KernelSolution::solve(mLambda, *(this->_bVec));
1149  } catch (pexExcept::Exception &e) {
1150  LSST_EXCEPT_ADD(e, "Unable to solve regularized kernel matrix");
1151  throw e;
1152  }
1153  Eigen::VectorXd term1 = (this->_aVec->transpose() * vMatvMatT * *(this->_aVec));
1154  if (term1.size() != 1)
1155  throw LSST_EXCEPT(pexExcept::Exception, "Matrix size mismatch");
1156 
1157  double term2a = (vMatvMatT * mLambda.inverse()).trace();
1158 
1159  Eigen::VectorXd term2b = (this->_aVec->transpose() * (mInv * *(this->_bVec)));
1160  if (term2b.size() != 1)
1161  throw LSST_EXCEPT(pexExcept::Exception, "Matrix size mismatch");
1162 
1163  double risk = term1(0) + 2 * (term2a - term2b(0));
1164  LOGL_DEBUG("TRACE4.ip.diffim.RegularizedKernelSolution.estimateRisk",
1165  "Lambda = %.3f, Risk = %.5e",
1166  l, risk);
1167  LOGL_DEBUG("TRACE5.ip.diffim.RegularizedKernelSolution.estimateRisk",
1168  "%.5e + 2 * (%.5e - %.5e)",
1169  term1(0), term2a, term2b(0));
1170  risks.push_back(risk);
1171  }
1172  std::vector<double>::iterator it = min_element(risks.begin(), risks.end());
1173  int index = distance(risks.begin(), it);
1174  LOGL_DEBUG("TRACE3.ip.diffim.RegularizedKernelSolution.estimateRisk",
1175  "Minimum Risk = %.3e at lambda = %.3e", risks[index], lambdas[index]);
1176 
1177  return lambdas[index];
1178 
1179  }
1180 
1181  template <typename InputT>
1182  std::shared_ptr<Eigen::MatrixXd> RegularizedKernelSolution<InputT>::getM(bool includeHmat) {
1183  if (includeHmat == true) {
1184  return (std::shared_ptr<Eigen::MatrixXd>(
1185  new Eigen::MatrixXd(*(this->_mMat) + _lambda * (*_hMat))
1186  ));
1187  }
1188  else {
1189  return this->_mMat;
1190  }
1191  }
1192 
1193  template <typename InputT>
1195 
1196  LOGL_DEBUG("TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1197  "cMat is %d x %d; vVec is %d; iVec is %d; hMat is %d x %d",
1198  (*this->_cMat).rows(), (*this->_cMat).cols(), (*this->_ivVec).size(),
1199  (*this->_iVec).size(), (*_hMat).rows(), (*_hMat).cols());
1200 
1201  if (DEBUG_MATRIX2) {
1202  std::cout << "ID: " << (this->_id) << std::endl;
1203  std::cout << "C:" << std::endl;
1204  std::cout << (*this->_cMat) << std::endl;
1205  std::cout << "Sigma^{-1}:" << std::endl;
1206  std::cout << Eigen::MatrixXd((*this->_ivVec).asDiagonal()) << std::endl;
1207  std::cout << "Y:" << std::endl;
1208  std::cout << (*this->_iVec) << std::endl;
1209  std::cout << "H:" << std::endl;
1210  std::cout << (*_hMat) << std::endl;
1211  }
1212 
1213 
1214  this->_mMat.reset(
1215  new Eigen::MatrixXd(this->_cMat->transpose() * this->_ivVec->asDiagonal() * *(this->_cMat))
1216  );
1217  this->_bVec.reset(
1218  new Eigen::VectorXd(this->_cMat->transpose() * this->_ivVec->asDiagonal() * *(this->_iVec))
1219  );
1220 
1221 
1222  /* See N.R. 18.5
1223 
1224  Matrix equation to solve is Y = C a + N
1225  Y = vectorized version of I (I = image to not convolve)
1226  C_i = K_i (x) R (R = image to convolve)
1227  a = kernel coefficients
1228  N = noise
1229 
1230  If we reweight everything by the inverse square root of the noise
1231  covariance, we get a linear model with the identity matrix for
1232  the noise. The problem can then be solved using least squares,
1233  with the normal equations
1234 
1235  C^T Y = C^T C a
1236 
1237  or
1238 
1239  b = M a
1240 
1241  with
1242 
1243  b = C^T Y
1244  M = C^T C
1245  a = (C^T C)^{-1} C^T Y
1246 
1247 
1248  We can regularize the least square problem
1249 
1250  Y = C a + lambda a^T H a (+ N, which can be ignored)
1251 
1252  or the normal equations
1253 
1254  (C^T C + lambda H) a = C^T Y
1255 
1256 
1257  The solution to the regularization of the least squares problem is
1258 
1259  a = (C^T C + lambda H)^{-1} C^T Y
1260 
1261  The approximation to Y is
1262 
1263  C a = C (C^T C + lambda H)^{-1} C^T Y
1264 
1265  with smoothing matrix
1266 
1267  S = C (C^T C + lambda H)^{-1} C^T
1268 
1269  */
1270 
1271  std::string lambdaType = _policy.getString("lambdaType");
1272  if (lambdaType == "absolute") {
1273  _lambda = _policy.getDouble("lambdaValue");
1274  }
1275  else if (lambdaType == "relative") {
1276  _lambda = this->_mMat->trace() / this->_hMat->trace();
1277  _lambda *= _policy.getDouble("lambdaScaling");
1278  }
1279  else if (lambdaType == "minimizeBiasedRisk") {
1280  double tol = _policy.getDouble("maxConditionNumber");
1281  _lambda = estimateRisk(tol);
1282  }
1283  else if (lambdaType == "minimizeUnbiasedRisk") {
1284  _lambda = estimateRisk(std::numeric_limits<double>::max());
1285  }
1286  else {
1287  throw LSST_EXCEPT(pexExcept::Exception, "lambdaType in Policy not recognized");
1288  }
1289 
1290  LOGL_DEBUG("TRACE3.ip.diffim.RegularizedKernelSolution.solve",
1291  "Applying kernel regularization with lambda = %.2e", _lambda);
1292 
1293 
1294  try {
1295  KernelSolution::solve(*(this->_mMat) + _lambda * (*_hMat), *(this->_bVec));
1296  } catch (pexExcept::Exception &e) {
1297  LSST_EXCEPT_ADD(e, "Unable to solve static kernel matrix");
1298  throw e;
1299  }
1300  /* Turn matrices into _kernel and _background */
1302  }
1303 
1304  template <typename InputT>
1306  std::vector<double> lambdas;
1307 
1308  std::string lambdaStepType = _policy.getString("lambdaStepType");
1309  if (lambdaStepType == "linear") {
1310  double lambdaLinMin = _policy.getDouble("lambdaLinMin");
1311  double lambdaLinMax = _policy.getDouble("lambdaLinMax");
1312  double lambdaLinStep = _policy.getDouble("lambdaLinStep");
1313  for (double l = lambdaLinMin; l <= lambdaLinMax; l += lambdaLinStep) {
1314  lambdas.push_back(l);
1315  }
1316  }
1317  else if (lambdaStepType == "log") {
1318  double lambdaLogMin = _policy.getDouble("lambdaLogMin");
1319  double lambdaLogMax = _policy.getDouble("lambdaLogMax");
1320  double lambdaLogStep = _policy.getDouble("lambdaLogStep");
1321  for (double l = lambdaLogMin; l <= lambdaLogMax; l += lambdaLogStep) {
1322  lambdas.push_back(pow(10, l));
1323  }
1324  }
1325  else {
1326  throw LSST_EXCEPT(pexExcept::Exception, "lambdaStepType in Policy not recognized");
1327  }
1328  return lambdas;
1329  }
1330 
1331  /*******************************************************************************************************/
1332 
1334  lsst::afw::math::KernelList const& basisList,
1335  lsst::afw::math::Kernel::SpatialFunctionPtr spatialKernelFunction,
1338  ) :
1339  KernelSolution(),
1340  _spatialKernelFunction(spatialKernelFunction),
1341  _constantFirstTerm(false),
1342  _kernel(),
1343  _background(background),
1344  _kSum(0.0),
1345  _policy(policy),
1346  _nbases(0),
1347  _nkt(0),
1348  _nbt(0),
1349  _nt(0) {
1350 
1351  bool isAlardLupton = _policy.getString("kernelBasisSet") == "alard-lupton";
1352  bool usePca = _policy.getBool("usePcaForSpatialKernel");
1353  if (isAlardLupton || usePca) {
1354  _constantFirstTerm = true;
1355  }
1356  this->_fitForBackground = _policy.getBool("fitForBackground");
1357 
1358  _nbases = basisList.size();
1359  _nkt = _spatialKernelFunction->getParameters().size();
1360  _nbt = _fitForBackground ? _background->getParameters().size() : 0;
1361  _nt = 0;
1362  if (_constantFirstTerm) {
1363  _nt = (_nbases - 1) * _nkt + 1 + _nbt;
1364  } else {
1365  _nt = _nbases * _nkt + _nbt;
1366  }
1367 
1368  std::shared_ptr<Eigen::MatrixXd> mMat (new Eigen::MatrixXd(_nt, _nt));
1369  std::shared_ptr<Eigen::VectorXd> bVec (new Eigen::VectorXd(_nt));
1370  (*mMat).setZero();
1371  (*bVec).setZero();
1372 
1373  this->_mMat = mMat;
1374  this->_bVec = bVec;
1375 
1378  );
1379 
1380  LOGL_DEBUG("TRACE3.ip.diffim.SpatialKernelSolution",
1381  "Initializing with size %d %d %d and constant first term = %s",
1382  _nkt, _nbt, _nt,
1383  _constantFirstTerm ? "true" : "false");
1384 
1385  }
1386 
1387  void SpatialKernelSolution::addConstraint(float xCenter, float yCenter,
1388  std::shared_ptr<Eigen::MatrixXd> qMat,
1389  std::shared_ptr<Eigen::VectorXd> wVec) {
1390 
1391  LOGL_DEBUG("TRACE5.ip.diffim.SpatialKernelSolution.addConstraint",
1392  "Adding candidate at %f, %f", xCenter, yCenter);
1393 
1394  /* Calculate P matrices */
1395  /* Pure kernel terms */
1396  Eigen::VectorXd pK(_nkt);
1397  std::vector<double> paramsK = _spatialKernelFunction->getParameters();
1398  for (int idx = 0; idx < _nkt; idx++) { paramsK[idx] = 0.0; }
1399  for (int idx = 0; idx < _nkt; idx++) {
1400  paramsK[idx] = 1.0;
1401  _spatialKernelFunction->setParameters(paramsK);
1402  pK(idx) = (*_spatialKernelFunction)(xCenter, yCenter); /* Assume things don't vary over stamp */
1403  paramsK[idx] = 0.0;
1404  }
1405  Eigen::MatrixXd pKpKt = (pK * pK.transpose());
1406 
1407  Eigen::VectorXd pB;
1408  Eigen::MatrixXd pBpBt;
1409  Eigen::MatrixXd pKpBt;
1410  if (_fitForBackground) {
1411  pB = Eigen::VectorXd(_nbt);
1412 
1413  /* Pure background terms */
1414  std::vector<double> paramsB = _background->getParameters();
1415  for (int idx = 0; idx < _nbt; idx++) { paramsB[idx] = 0.0; }
1416  for (int idx = 0; idx < _nbt; idx++) {
1417  paramsB[idx] = 1.0;
1418  _background->setParameters(paramsB);
1419  pB(idx) = (*_background)(xCenter, yCenter); /* Assume things don't vary over stamp */
1420  paramsB[idx] = 0.0;
1421  }
1422  pBpBt = (pB * pB.transpose());
1423 
1424  /* Cross terms */
1425  pKpBt = (pK * pB.transpose());
1426  }
1427 
1428  if (DEBUG_MATRIX) {
1429  std::cout << "Spatial weights" << std::endl;
1430  std::cout << "pKpKt " << pKpKt << std::endl;
1431  if (_fitForBackground) {
1432  std::cout << "pBpBt " << pBpBt << std::endl;
1433  std::cout << "pKpBt " << pKpBt << std::endl;
1434  }
1435  }
1436 
1437  if (DEBUG_MATRIX) {
1438  std::cout << "Spatial matrix inputs" << std::endl;
1439  std::cout << "M " << (*qMat) << std::endl;
1440  std::cout << "B " << (*wVec) << std::endl;
1441  }
1442 
1443  /* first index to start the spatial blocks; default=0 for non-constant first term */
1444  int m0 = 0;
1445  /* how many rows/cols to adjust the matrices/vectors; default=0 for non-constant first term */
1446  int dm = 0;
1447  /* where to start the background terms; this is always true */
1448  int mb = _nt - _nbt;
1449 
1450  if (_constantFirstTerm) {
1451  m0 = 1; /* we need to manually fill in the first (non-spatial) terms below */
1452  dm = _nkt-1; /* need to shift terms due to lack of spatial variation in first term */
1453 
1454  (*_mMat)(0, 0) += (*qMat)(0,0);
1455  for(int m2 = 1; m2 < _nbases; m2++) {
1456  (*_mMat).block(0, m2*_nkt-dm, 1, _nkt) += (*qMat)(0,m2) * pK.transpose();
1457  }
1458  (*_bVec)(0) += (*wVec)(0);
1459 
1460  if (_fitForBackground) {
1461  (*_mMat).block(0, mb, 1, _nbt) += (*qMat)(0,_nbases) * pB.transpose();
1462  }
1463  }
1464 
1465  /* Fill in the spatial blocks */
1466  for(int m1 = m0; m1 < _nbases; m1++) {
1467  /* Diagonal kernel-kernel term; only use upper triangular part of pKpKt */
1468  (*_mMat).block(m1*_nkt-dm, m1*_nkt-dm, _nkt, _nkt) +=
1469  (pKpKt * (*qMat)(m1,m1)).triangularView<Eigen::Upper>();
1470 
1471  /* Kernel-kernel terms */
1472  for(int m2 = m1+1; m2 < _nbases; m2++) {
1473  (*_mMat).block(m1*_nkt-dm, m2*_nkt-dm, _nkt, _nkt) += (*qMat)(m1,m2) * pKpKt;
1474  }
1475 
1476  if (_fitForBackground) {
1477  /* Kernel cross terms with background */
1478  (*_mMat).block(m1*_nkt-dm, mb, _nkt, _nbt) += (*qMat)(m1,_nbases) * pKpBt;
1479  }
1480 
1481  /* B vector */
1482  (*_bVec).segment(m1*_nkt-dm, _nkt) += (*wVec)(m1) * pK;
1483  }
1484 
1485  if (_fitForBackground) {
1486  /* Background-background terms only */
1487  (*_mMat).block(mb, mb, _nbt, _nbt) +=
1488  (pBpBt * (*qMat)(_nbases,_nbases)).triangularView<Eigen::Upper>();
1489  (*_bVec).segment(mb, _nbt) += (*wVec)(_nbases) * pB;
1490  }
1491 
1492  if (DEBUG_MATRIX) {
1493  std::cout << "Spatial matrix outputs" << std::endl;
1494  std::cout << "mMat " << (*_mMat) << std::endl;
1495  std::cout << "bVec " << (*_bVec) << std::endl;
1496  }
1497 
1498  }
1499 
1502  throw LSST_EXCEPT(pexExcept::Exception, "Kernel not solved; cannot return image");
1503  }
1505  new afwImage::Image<afwMath::Kernel::Pixel>(_kernel->getDimensions())
1506  );
1507  (void)_kernel->computeImage(*image, false, pos[0], pos[1]);
1508  return image;
1509  }
1510 
1512  /* Fill in the other half of mMat */
1513  for (int i = 0; i < _nt; i++) {
1514  for (int j = i+1; j < _nt; j++) {
1515  (*_mMat)(j,i) = (*_mMat)(i,j);
1516  }
1517  }
1518 
1519  try {
1521  } catch (pexExcept::Exception &e) {
1522  LSST_EXCEPT_ADD(e, "Unable to solve spatial kernel matrix");
1523  throw e;
1524  }
1525  /* Turn matrices into _kernel and _background */
1526  _setKernel();
1527  }
1528 
1532  throw LSST_EXCEPT(pexExcept::Exception, "Kernel not solved; cannot return solution");
1533  }
1534 
1535  return std::make_pair(_kernel, _background);
1536  }
1537 
1539  /* Report on condition number */
1540  double cNumber = this->getConditionNumber(EIGENVALUE);
1541 
1542  if (_nkt == 1) {
1543  /* Not spatially varying; this fork is a specialization for convolution speed--up */
1544 
1545  /* Set the basis coefficients */
1546  std::vector<double> kCoeffs(_nbases);
1547  for (int i = 0; i < _nbases; i++) {
1548  if (std::isnan((*_aVec)(i))) {
1549  throw LSST_EXCEPT(
1551  str(boost::format(
1552  "I. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % i % cNumber));
1553  }
1554  kCoeffs[i] = (*_aVec)(i);
1555  }
1556  lsst::afw::math::KernelList basisList =
1557  std::dynamic_pointer_cast<afwMath::LinearCombinationKernel>(_kernel)->getKernelList();
1558  _kernel.reset(
1559  new afwMath::LinearCombinationKernel(basisList, kCoeffs)
1560  );
1561  }
1562  else {
1563 
1564  /* Set the kernel coefficients */
1565  std::vector<std::vector<double> > kCoeffs;
1566  kCoeffs.reserve(_nbases);
1567  for (int i = 0, idx = 0; i < _nbases; i++) {
1568  kCoeffs.push_back(std::vector<double>(_nkt));
1569 
1570  /* Deal with the possibility the first term doesn't vary spatially */
1571  if ((i == 0) && (_constantFirstTerm)) {
1572  if (std::isnan((*_aVec)(idx))) {
1573  throw LSST_EXCEPT(
1575  str(boost::format(
1576  "II. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1577  }
1578  kCoeffs[i][0] = (*_aVec)(idx++);
1579  }
1580  else {
1581  for (int j = 0; j < _nkt; j++) {
1582  if (std::isnan((*_aVec)(idx))) {
1583  throw LSST_EXCEPT(
1585  str(boost::format(
1586  "III. Unable to determine spatial kernel solution %d (nan). Condition number = %.3e") % idx % cNumber));
1587  }
1588  kCoeffs[i][j] = (*_aVec)(idx++);
1589  }
1590  }
1591  }
1592  _kernel->setSpatialParameters(kCoeffs);
1593  }
1594 
1595  /* Set kernel Sum */
1596  ImageT::Ptr image (new ImageT(_kernel->getDimensions()));
1597  _kSum = _kernel->computeImage(*image, false);
1598 
1599  /* Set the background coefficients */
1600  std::vector<double> bgCoeffs(_fitForBackground ? _nbt : 1);
1601  if (_fitForBackground) {
1602  for (int i = 0; i < _nbt; i++) {
1603  int idx = _nt - _nbt + i;
1604  if (std::isnan((*_aVec)(idx))) {
1606  str(boost::format(
1607  "Unable to determine spatial background solution %d (nan)") % (idx)));
1608  }
1609  bgCoeffs[i] = (*_aVec)(idx);
1610  }
1611  }
1612  else {
1613  bgCoeffs[0] = 0.;
1614  }
1615  _background->setParameters(bgCoeffs);
1616  }
1617 
1618 /***********************************************************************************************************/
1619 //
1620 // Explicit instantiations
1621 //
1622  typedef float InputT;
1623 
1624  template class StaticKernelSolution<InputT>;
1625  template class MaskedKernelSolution<InputT>;
1626  template class RegularizedKernelSolution<InputT>;
1627 
1628 }}} // end of namespace lsst::ip::diffim
An include file to include the public header files for lsst::afw::math.
void _setKernel()
Set kernel after solution.
iterator end() const
Return an STL compliant iterator to the end of the image.
Definition: Image.cc:355
std::uint16_t MaskPixel
void flattenArray(Footprint const &fp, ndarray::Array< T, N, C > const &src, ndarray::Array< U, N-1, D > const &dest, lsst::afw::geom::Point2I const &xy0=lsst::afw::geom::Point2I())
Flatten the first two dimensions of an array.
boost::shared_ptr< lsst::afw::math::Function2< double > > SpatialFunctionPtr
Definition: Kernel.h:140
An include file to include the header files for lsst::afw::geom.
std::shared_ptr< Eigen::MatrixXd > getM()
geom::Extent2I const getDimensions() const
Return the Kernel&#39;s dimensions (width, height)
Definition: Kernel.h:223
int getMinY() const
Definition: Box.h:125
Eigen::MatrixXi maskToEigenMatrix(lsst::afw::image::Mask< lsst::afw::image::MaskPixel > const &mask)
void writeFits(std::string const &fileName, boost::shared_ptr< lsst::daf::base::PropertySet const > metadata=boost::shared_ptr< lsst::daf::base::PropertySet >(), std::string const &mode="w") const
Write a mask to a regular FITS file.
estimate sample minimum
Definition: Statistics.h:76
virtual lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel >::Ptr makeKernelImage()
boost::shared_ptr< FootprintList > getFootprints()
: Return the Footprints of detected objects
Definition: FootprintSet.h:148
bool getBool(const std::string &name) const
return a boolean value associated with the given name.
Definition: Policy.h:589
a container for holding hierarchical configuration data in memory.
Definition: Policy.h:169
void setKernelParameters(std::vector< double > const &params)
Set the kernel parameters of a spatially invariant kernel.
Definition: Kernel.h:409
virtual std::pair< std::shared_ptr< lsst::afw::math::Kernel >, double > getSolutionPair()
const std::string getString(const std::string &name) const
return a string value associated with the given name .
Definition: Policy.h:631
SpatialKernelSolution(lsst::afw::math::KernelList const &basisList, lsst::afw::math::Kernel::SpatialFunctionPtr spatialKernelFunction, lsst::afw::math::Kernel::SpatialFunctionPtr background, lsst::pex::policy::Policy policy)
RegularizedKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground, std::shared_ptr< Eigen::MatrixXd > hMat, lsst::pex::policy::Policy policy)
void addConstraint(float xCenter, float yCenter, std::shared_ptr< Eigen::MatrixXd > qMat, std::shared_ptr< Eigen::VectorXd > wVec)
boost::shared_ptr< LinearCombinationKernel > Ptr
Definition: Kernel.h:815
std::shared_ptr< Footprint > Ptr
Definition: Footprint.h:67
lsst::afw::math::Kernel::Ptr _kernel
Derived single-object convolution kernel.
Use (pixels &amp; (given mask))
Definition: Threshold.h:49
A Threshold is used to pass a threshold value to detection algorithms.
Definition: Threshold.h:44
virtual lsst::afw::math::Kernel::Ptr getKernel()
geom::Box2I getBBox(ImageOrigin origin=PARENT) const
Definition: Image.h:378
KernelSolvedBy _solvedBy
Type of algorithm used to make solution.
StaticKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground)
def trace
Definition: log.py:87
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:513
A class to evaluate image statistics.
Definition: Statistics.h:212
An integer coordinate rectangle.
Definition: Box.h:53
Declaration of classes to store the solution for convolution kernels.
int getMinX() const
Definition: Box.h:124
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
LSST DM logging module built on log4cxx.
double getValue(Property const prop=NOTHING) const
Return the value of the desired property (if specified in the constructor)
Definition: Statistics.cc:1034
An include file to include the header files for lsst::afw::image.
geom::Point2I getXY0() const
Return the image&#39;s origin.
Definition: Image.h:265
boost::shared_ptr< Kernel > Ptr
Definition: Kernel.h:138
int getMaxX() const
Definition: Box.h:128
virtual void build(lsst::afw::image::Image< InputT > const &templateImage, lsst::afw::image::Image< InputT > const &scienceImage, lsst::afw::image::Image< lsst::afw::image::VariancePixel > const &varianceEstimate)
int getWidth() const
Definition: Box.h:154
void _setKernel()
Set kernel after solution.
double _kSum
Derived kernel sum.
static int _SolutionId
Unique identifier for solution.
void _setKernelUncertainty()
Not implemented.
bool _fitForBackground
Background terms included in fit.
geom::Extent2I getDimensions() const
Return the image&#39;s size; useful for passing to constructors.
Definition: Image.h:299
An include file to include the header files for lsst::afw::detection.
lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel > ImageT
afwMath::LinearCombinationKernel const & _kernel
virtual double getConditionNumber(ConditionNumberType conditionType)
int _id
Definition: Mask.cc:679
lsst::afw::image::Image< lsst::afw::math::Kernel::Pixel >::Ptr makeKernelImage(lsst::afw::geom::Point2D const &pos)
double computeImage(lsst::afw::image::Image< Pixel > &image, bool doNormalize, double x=0.0, double y=0.0) const
Compute an image (pixellized representation of the kernel) in place.
Definition: Kernel.cc:94
A kernel that is a linear combination of fixed basis kernels.
Definition: Kernel.h:811
std::shared_ptr< Image< PixelT > > Ptr
Definition: Image.h:419
virtual void buildOrig(lsst::afw::image::Image< InputT > const &templateImage, lsst::afw::image::Image< InputT > const &scienceImage, lsst::afw::image::Image< lsst::afw::image::VariancePixel > const &varianceEstimate, lsst::afw::image::Mask< lsst::afw::image::MaskPixel > pixelMask)
lsst::afw::math::Kernel::SpatialFunctionPtr _spatialKernelFunction
Spatial function for Kernel.
static MaskPixelT getPlaneBitMask(const std::vector< std::string > &names)
Return the bitmask corresponding to a vector of plane names OR&#39;d together.
Definition: Mask.cc:860
A set of pixels in an Image.
Definition: Footprint.h:62
int _nbt
Number of background terms.
bool _constantFirstTerm
Is the first term constant.
lsst::pex::policy::Policy _policy
Policy to control processing.
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
A set of Footprints, associated with a MaskedImage.
Definition: FootprintSet.h:55
lsst::afw::math::LinearCombinationKernel::Ptr _kernel
Spatial convolution kernel.
MaskedKernelSolution(lsst::afw::math::KernelList const &basisList, bool fitForBackground)
lsst::afw::math::Kernel::SpatialFunctionPtr _background
Spatial background model.
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, ConvolutionControl const &convolutionControl=ConvolutionControl())
Convolve an Image or MaskedImage with a Kernel, setting pixels of an existing output image...
int _nkt
Number of kernel terms.
int getHeight() const
Definition: Box.h:155
std::pair< lsst::afw::math::LinearCombinationKernel::Ptr, lsst::afw::math::Kernel::SpatialFunctionPtr > getSolutionPair()
MaskT setMaskFromFootprint(lsst::afw::image::Mask< MaskT > *mask, Footprint const &footprint, MaskT const bitmask)
OR bitmask into all the Mask&#39;s pixels that are in the Footprint.
int _nbases
Number of basis functions.
std::shared_ptr< Eigen::VectorXd > _aVec
Derived least squares solution matrix.
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Definition: Statistics.cc:1107
virtual void buildSingleMaskOrig(lsst::afw::image::Image< InputT > const &templateImage, lsst::afw::image::Image< InputT > const &scienceImage, lsst::afw::image::Image< lsst::afw::image::VariancePixel > const &varianceEstimate, lsst::afw::geom::Box2I maskBox)
virtual void buildWithMask(lsst::afw::image::Image< InputT > const &templateImage, lsst::afw::image::Image< InputT > const &scienceImage, lsst::afw::image::Image< lsst::afw::image::VariancePixel > const &varianceEstimate, lsst::afw::image::Mask< lsst::afw::image::MaskPixel > const &pixelMask)
iterator begin() const
Return an STL compliant iterator to the start of the image.
Definition: Image.cc:349
int getMaxY() const
Definition: Box.h:129
std::shared_ptr< Eigen::VectorXd > _bVec
Derived least squares B vector.
#define LSST_EXCEPT_ADD(e, m)
Add the current location and a message to an existing exception before rethrowing it...
Definition: Exception.h:51
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:416
#define DEBUG_MATRIX
#define DEBUG_MATRIX2
Image Subtraction helper functions.
std::shared_ptr< Eigen::MatrixXd > _mMat
Derived least squares M matrix.
MaskT setMaskFromFootprintList(lsst::afw::image::Mask< MaskT > *mask, std::vector< boost::shared_ptr< Footprint >> const &footprints, MaskT const bitmask)
OR bitmask into all the Mask&#39;s pixels which are in the set of Footprints.
Eigen::MatrixXd imageToEigenMatrix(lsst::afw::image::Image< PixelT > const &img)
Turns Image into a 2-D Eigen Matrix.
std::vector< boost::shared_ptr< Kernel > > KernelList
Definition: Kernel.h:539