LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
SpatialModelPsf.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 
32 #include <numeric>
33 
34 #if !defined(DOXYGEN)
35 # include "Minuit2/FCNBase.h"
36 # include "Minuit2/FunctionMinimum.h"
37 # include "Minuit2/MnMigrad.h"
38 # include "Minuit2/MnMinos.h"
39 # include "Minuit2/MnPrint.h"
40 #endif
41 
42 #include "Eigen/Core"
43 #include "Eigen/Cholesky"
44 #include "Eigen/SVD"
45 
49 #include "lsst/afw/geom/Point.h"
50 #include "lsst/afw/geom/Box.h"
54 
55 namespace afwDetection = lsst::afw::detection;
56 namespace afwGeom = lsst::afw::geom;
57 namespace afwImage = lsst::afw::image;
58 namespace afwMath = lsst::afw::math;
59 
60 namespace lsst {
61 namespace meas {
62 namespace algorithms {
63 
64 namespace {
65 
66 int const WARP_BUFFER(1); // Buffer (border) around kernel to prevent warp issues
67 std::string const WARP_ALGORITHM("lanczos5"); // Name of warping algorithm to use
68 
69 
70 // A class to pass around to all our PsfCandidates which builds the PcaImageSet
71 template<typename PixelT>
72 class SetPcaImageVisitor : public afwMath::CandidateVisitor {
73  typedef afwImage::Image<PixelT> ImageT;
74  typedef afwImage::MaskedImage<PixelT> MaskedImageT;
75  typedef afwImage::Exposure<PixelT> ExposureT;
76 public:
77  explicit SetPcaImageVisitor(
78  PsfImagePca<MaskedImageT> *imagePca, // Set of Images to initialise
79  unsigned int const mask=0x0 // Ignore pixels with any of these bits set
80  ) :
81  afwMath::CandidateVisitor(),
82  _imagePca(imagePca)
83  {
84  ;
85  }
86 
87  // Called by SpatialCellSet::visitCandidates for each Candidate
88  void processCandidate(afwMath::SpatialCellCandidate *candidate) {
89  PsfCandidate<PixelT> *imCandidate = dynamic_cast<PsfCandidate<PixelT> *>(candidate);
90  if (imCandidate == NULL) {
91  throw LSST_EXCEPT(lsst::pex::exceptions::LogicError,
92  "Failed to cast SpatialCellCandidate to PsfCandidate");
93  }
94 
95  try {
96  typename MaskedImageT::Ptr im = imCandidate->getOffsetImage(WARP_ALGORITHM,
97  WARP_BUFFER);
98 
99 
100  //static int count = 0;
101  //im->writeFits(str(boost::format("cand%03d.fits") % count));
102  //count += 1;
103 
105  sctrl.setNanSafe(false);
106 
107  if (!lsst::utils::isfinite(afwMath::makeStatistics(*im->getImage(),
108  afwMath::MAX, sctrl).getValue())) {
109  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
110  str(boost::format("Image at %d, %d contains NaN")
111  % imCandidate->getXCenter() % imCandidate->getYCenter()));
112 
113  }
114  if (!lsst::utils::isfinite(afwMath::makeStatistics(*im->getVariance(),
115  afwMath::MAX, sctrl).getValue())) {
116  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
117  str(boost::format("Variance of Image at %d, %d contains NaN")
118  % imCandidate->getXCenter() % imCandidate->getYCenter()));
119  }
120 
121  _imagePca->addImage(im, imCandidate->getSource()->getPsfFlux());
122  } catch(lsst::pex::exceptions::LengthError &) {
123  return;
124  }
125  }
126 private:
127  PsfImagePca<MaskedImageT> *_imagePca; // the ImagePca we're building
128 };
129 
130 /************************************************************************************************************/
132 template<typename PixelT>
133 class countVisitor : public afwMath::CandidateVisitor {
134  typedef afwImage::MaskedImage<PixelT> MaskedImage;
135  typedef afwImage::Exposure<PixelT> Exposure;
136 public:
137  explicit countVisitor() : afwMath::CandidateVisitor(), _n(0) {}
138 
139  void reset() {
140  _n = 0;
141  }
142 
143  // Called by SpatialCellSet::visitCandidates for each Candidate
144  void processCandidate(afwMath::SpatialCellCandidate *candidate) {
145  PsfCandidate<PixelT> *imCandidate = dynamic_cast<PsfCandidate<PixelT> *>(candidate);
146  if (imCandidate == NULL) {
147  throw LSST_EXCEPT(lsst::pex::exceptions::LogicError,
148  "Failed to cast SpatialCellCandidate to PsfCandidate");
149  }
150 
151  try {
152  imCandidate->getMaskedImage();
153  } catch(lsst::pex::exceptions::LengthError &) {
154  return;
155  }
156 
157  ++_n;
158  }
159 
160  // Return the number
161  double getN() const { return _n; }
162 
163 private:
164  int mutable _n; // the desired number
165 };
166 
167 
172 template<typename ImageT>
173 std::vector<typename ImageT::Ptr> offsetKernel(
174  afwMath::LinearCombinationKernel const& kernel,
175  float dx, float dy
176  )
177 {
178  afwMath::KernelList kernels = kernel.getKernelList(); // The Kernels that kernel adds together
179  unsigned int const nKernel = kernels.size(); // Number of kernel components
180  std::vector<typename ImageT::Ptr> kernelImages(nKernel); // Images of each Kernel in kernels
181  if (nKernel == 0) {
182  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
183  "Kernel has no components");
184  }
185 
186  ImageT scratch(kernel.getDimensions()); // Buffered scratch space
187  for (unsigned int i = 0; i != nKernel; ++i) {
188  kernels[i]->computeImage(scratch, false);
189  kernelImages[i] = afwMath::offsetImage(scratch, dx, dy, WARP_ALGORITHM, WARP_BUFFER);
190  }
191 
192  return kernelImages;
193 }
194 
195 } // Anonymous namespace
196 
197 /************************************************************************************************************/
205 template<typename PixelT>
206 std::pair<afwMath::LinearCombinationKernel::Ptr, std::vector<double> > createKernelFromPsfCandidates(
207  afwMath::SpatialCellSet const& psfCells,
208  lsst::afw::geom::Extent2I const& dims,
209  lsst::afw::geom::Point2I const& xy0,
210  int const nEigenComponents,
211  int const spatialOrder,
212  int const ksize,
213  int const nStarPerCell,
214  bool const constantWeight,
215  int const border
216  )
217 {
218  typedef typename afwImage::Image<PixelT> ImageT;
219  typedef typename afwImage::MaskedImage<PixelT> MaskedImageT;
220  typedef typename afwImage::Exposure<PixelT> ExposureT;
221 
222  //
223  // Set the sizes for PsfCandidates made from either Images or MaskedImages
224  //
225  //lsst::meas::algorithms::PsfCandidate<ImageT>::setWidth(ksize);
226  //lsst::meas::algorithms::PsfCandidate<ImageT>::setHeight(ksize);
227  //lsst::meas::algorithms::PsfCandidate<MaskedImageT>::setWidth(ksize);
228  //lsst::meas::algorithms::PsfCandidate<MaskedImageT>::setHeight(ksize);
231 
232 
233  PsfImagePca<MaskedImageT> imagePca(constantWeight, border); // Here's the set of images we'll analyze
234 
235  {
236  SetPcaImageVisitor<PixelT> importStarVisitor(&imagePca);
237  bool const ignoreExceptions = true;
238  psfCells.visitCandidates(&importStarVisitor, nStarPerCell, ignoreExceptions);
239  }
240 
241  //
242  // Do a PCA decomposition of those PSF candidates.
243  //
244  // We have "gappy" data; in other words we don't want to include any pixels with INTRP set
245  //
246  int niter = 10; // number of iterations of updateBadPixels
247  double deltaLim = 10.0; // acceptable value of delta, the max change due to updateBadPixels
251 
252  for (int i = 0; i != niter; ++i) {
253  int const ncomp = (i == 0) ? 0 :
254  ((nEigenComponents == 0) ? imagePca.getEigenImages().size() : nEigenComponents);
255  double delta = imagePca.updateBadPixels(BAD | CR | INTRP, ncomp);
256  if (i > 0 && delta < deltaLim) {
257  break;
258  }
259 
260  imagePca.analyze();
261  }
262 
263  std::vector<typename MaskedImageT::Ptr> eigenImages = imagePca.getEigenImages();
264  std::vector<double> eigenValues = imagePca.getEigenValues();
265  int const nEigen = static_cast<int>(eigenValues.size());
266 
267  int const ncomp = (nEigenComponents <= 0 || nEigen < nEigenComponents) ? nEigen : nEigenComponents;
268  //
269  // Set the background level of the components to 0.0 to avoid coupling variable background
270  // levels to the form of the Psf. More precisely, we calculate the mean of an outer "annulus"
271  // of width bkg_border
272  //
273  for (int k = 0; k != ncomp; ++k) {
274  ImageT const& im = *eigenImages[k]->getImage();
275 
276  int bkg_border = 2;
277  if (bkg_border > im.getWidth()) {
278  bkg_border = im.getWidth() / 2;
279  }
280  if (bkg_border > im.getHeight()) {
281  bkg_border = im.getHeight() / 2;
282  }
283 
284  double sum = 0;
285  // Bottom and Top borders
286  for (int i = 0; i != bkg_border; ++i) {
287  typename ImageT::const_x_iterator
288  ptrB = im.row_begin(i), ptrT = im.row_begin(im.getHeight() - i - 1);
289  for (int j = 0; j != im.getWidth(); ++j, ++ptrB, ++ptrT) {
290  sum += *ptrB + *ptrT;
291  }
292  }
293  for (int i = bkg_border; i < im.getHeight() - bkg_border; ++i) {
294  // Left and Right borders
295  typename ImageT::const_x_iterator
296  ptrL = im.row_begin(i), ptrR = im.row_begin(i) + im.getWidth() - bkg_border;
297  for (int j = 0; j != bkg_border; ++j, ++ptrL, ++ptrR) {
298  sum += *ptrL + *ptrR;
299  }
300  }
301  sum /= 2*(bkg_border*im.getWidth() + bkg_border*(im.getHeight() - 2*bkg_border));
302 
303  *eigenImages[k] -= sum;
304  }
305  //
306  // Now build our LinearCombinationKernel; build the lists of basis functions
307  // and spatial variation, then assemble the Kernel
308  //
309  afwMath::KernelList kernelList;
310  std::vector<afwMath::Kernel::SpatialFunctionPtr> spatialFunctionList;
312 
313  for (int i = 0; i != ncomp; ++i) {
314  {
315  // Enforce unit sum for kernel by construction
316  // Zeroth component has unit sum
317  // Other components have zero sum by normalising and then subtracting the zeroth component
318  ImageT& image = *eigenImages[i]->getImage();
319  double sum = std::accumulate(image.begin(true), image.end(true), 0.0);
320  if (i == 0) {
321  image /= sum;
322  } else {
323  for (typename ImageT::fast_iterator ptr0 = eigenImages[0]->getImage()->begin(true),
324  ptr1 = image.begin(true), end = image.end(true); ptr1 != end; ++ptr0, ++ptr1) {
325  *ptr1 = *ptr1 / sum - *ptr0;
326  }
327  }
328  }
329 
330  kernelList.push_back(afwMath::Kernel::Ptr(new afwMath::FixedKernel(
331  afwImage::Image<afwMath::Kernel::Pixel>(*eigenImages[i]->getImage(),true)
332  )));
333 
335 // spatialFunction(new afwMath::PolynomialFunction2<double>(spatialOrder));
336  spatialFunction(new afwMath::Chebyshev1Function2<double>(spatialOrder, range));
337  spatialFunction->setParameter(0, 1.0); // the constant term; all others are 0
338  spatialFunctionList.push_back(spatialFunction);
339  }
340 
342  psf(new afwMath::LinearCombinationKernel(kernelList, spatialFunctionList));
343 
344  return std::make_pair(psf, eigenValues);
345 }
346 
347 /************************************************************************************************************/
351 template<typename PixelT>
353  int const nStarPerCell)
354 {
355  countVisitor<PixelT> counter;
356  psfCells.visitCandidates(&counter, nStarPerCell);
357 
358  return counter.getN();
359 }
360 
361 /************************************************************************************************************/
362 namespace {
368 template<typename ModelImageT, typename DataImageT>
369 std::pair<double, double>
370 fitKernel(ModelImageT const& mImage, // The model image at this point
371  DataImageT const& data, // the data to fit
372  double lambda = 0.0, // floor for variance is lambda*data
373  bool detected = true, // only fit DETECTED pixels?
374  int const id=-1 // ID for this object; useful in debugging
375  ) {
376  assert(data.getDimensions() == mImage.getDimensions());
377  assert(id == id);
378  int const DETECTED = afwImage::Mask<>::getPlaneBitMask("DETECTED");
380 
381  double sumMM = 0.0, sumMD = 0.0, sumDD = 0.0; // sums of model*model/variance etc.
382  int npix = 0; // number of pixels used to evaluate chi^2
383  for (int y = 0; y != data.getHeight(); ++y) {
384  typename ModelImageT::x_iterator mptr = mImage.row_begin(y);
385  for (typename DataImageT::x_iterator ptr = data.row_begin(y), end = data.row_end(y);
386  ptr != end; ++ptr, ++mptr) {
387  double const m = (*mptr)[0]; // value of model
388  double const d = ptr.image(); // value of data
389  double const var = ptr.variance() + lambda*d; // data's variance
390  if (detected && !(ptr.mask() & DETECTED)) {
391  continue;
392  }
393  if (ptr.mask() & BAD) {
394  continue;
395  }
396  if (var != 0.0) { // assume variance == 0 => infinity XXX
397  double const iVar = 1.0/var;
398  npix++;
399  sumMM += m*m*iVar;
400  sumMD += m*d*iVar;
401  sumDD += d*d*iVar;
402  }
403  }
404  }
405 
406  if (npix == 0) {
407  throw LSST_EXCEPT(lsst::pex::exceptions::RangeError, "No good pixels");
408  }
409  if (sumMM == 0.0) {
410  throw LSST_EXCEPT(lsst::pex::exceptions::RangeError, "sum(data*data)/var == 0");
411  }
412 
413  double const amp = sumMD/sumMM; // estimate of amplitude of model at this point
414  double const chi2 = (sumDD - 2*amp*sumMD + amp*amp*sumMM)/(npix - 1);
415 
416 #if 0
417  bool show = false; // Display the centre of the image; set from gdb
418 
419  if (show) {
420  show = true; // you can jump here in gdb to set show if direct attempts fail
421  int y = data.getHeight()/2;
422  int x = data.getWidth()/2;
423  int hsize = 2;
424  printf("\ndata ");
425  for (int ii = -hsize; ii <= hsize; ++ii) {
426  for (int jj = -hsize; jj <= hsize; ++jj) {
427  printf("%7.1f ", data.at(x + jj, y - ii).image());
428  }
429  printf(" model ");
430  for (int jj = -hsize; jj <= hsize; ++jj) {
431  printf("%7.1f ", amp*(*(mImage.at(x + jj, y - ii)))[0]);
432  }
433  printf("\n ");
434  }
435  printf("%g %.1f\n", amp, chi2);
436  }
437 #endif
438 
439  return std::make_pair(chi2, amp);
440 }
441 }
442 
443 /************************************************************************************************************/
444 /*
445  * Fit for the spatial variation of the PSF parameters over the field
446  */
448 template<typename PixelT>
453 
455 public:
456  explicit evalChi2Visitor(afwMath::Kernel const& kernel,
457  double lambda
458  ) :
459  afwMath::CandidateVisitor(),
460  _chi2(0.0), _kernel(kernel), _lambda(lambda),
461  _kImage(KImage::Ptr(new KImage(kernel.getDimensions()))) {
462  }
463 
464  void reset() {
465  _chi2 = 0.0;
466  }
467 
468  // Called by SpatialCellSet::visitCandidates for each Candidate
470  PsfCandidate<PixelT> *imCandidate = dynamic_cast<PsfCandidate<PixelT> *>(candidate);
471  if (imCandidate == NULL) {
472  throw LSST_EXCEPT(lsst::pex::exceptions::LogicError,
473  "Failed to cast SpatialCellCandidate to PsfCandidate");
474  }
475 
476  double const xcen = imCandidate->getSource()->getX();
477  double const ycen = imCandidate->getSource()->getY();
478 
479  _kernel.computeImage(*_kImage, true, xcen, ycen);
480  typename MaskedImage::ConstPtr data;
481  try {
482  data = imCandidate->getOffsetImage(WARP_ALGORITHM, WARP_BUFFER);
483  } catch(lsst::pex::exceptions::LengthError &) {
484  return;
485  }
486 
487  try {
488  std::pair<double, double> result = fitKernel(*_kImage, *data, _lambda, false,
489  imCandidate->getSource()->getId());
490 
491  double dchi2 = result.first; // chi^2 from this object
492  double const amp = result.second; // estimate of amplitude of model at this point
493 
494  imCandidate->setChi2(dchi2);
495  imCandidate->setAmplitude(amp);
496 
497  _chi2 += dchi2;
498  } catch(lsst::pex::exceptions::RangeError &e) {
500  imCandidate->setChi2(std::numeric_limits<double>::quiet_NaN());
501  imCandidate->setAmplitude(std::numeric_limits<double>::quiet_NaN());
502  }
503  }
504 
505  // Return the computed chi^2
506  double getValue() const { return _chi2; }
507 
508 private:
509  double mutable _chi2; // the desired chi^2
510  afwMath::Kernel const& _kernel; // the kernel
511  double _lambda; // floor for variance is _lambda*data
512  typename KImage::Ptr mutable _kImage; // The Kernel at this point; a scratch copy
513 };
514 
515 /********************************************************************************************************/
519 // Set the Kernel's spatial parameters from a vector
521  std::vector<double> const& coeffs
522  )
523 {
524  int const nComponents = kernel->getNKernelParameters();
525  int const nSpatialParams = kernel->getNSpatialParameters();
526 
527  assert (nComponents*nSpatialParams == static_cast<long>(coeffs.size()));
528 
529  std::vector<std::vector<double> > kCoeffs; // coefficients rearranged for Kernel
530  kCoeffs.reserve(nComponents);
531  for (int i = 0; i != nComponents; ++i) {
532  kCoeffs.push_back(std::vector<double>(nSpatialParams));
533  std::copy(coeffs.begin() + i*nSpatialParams,
534  coeffs.begin() + (i + 1)*nSpatialParams, kCoeffs[i].begin());
535  }
536 
537  kernel->setSpatialParameters(kCoeffs);
538 }
539 
543 // Set the Kernel's spatial parameters from an Eigen::VectorXd
545  Eigen::VectorXd const& vec
546  )
547 {
548  int const nComponents = kernel->getNKernelParameters();
549  int const nSpatialParams = kernel->getNSpatialParameters();
550 
551  assert (nComponents*nSpatialParams == vec.size());
552 
553  std::vector<std::vector<double> > kCoeffs; // coefficients rearranged for Kernel
554  kCoeffs.reserve(nComponents);
555  for (int i = 0; i != nComponents; ++i) {
556  std::vector<double> spatialCoeffs(nSpatialParams);
557  for (int j = 0; j != nSpatialParams; ++j) {
558  spatialCoeffs[j] = vec[i*nSpatialParams + j];
559  }
560  kCoeffs.push_back(spatialCoeffs);
561  }
562 
563  kernel->setSpatialParameters(kCoeffs);
564 }
565 
566 //
567 // The object that minuit minimises
568 //
569 template<typename PixelT>
570 class MinimizeChi2 : public ROOT::Minuit2::FCNBase {
571 public:
572  explicit MinimizeChi2(evalChi2Visitor<PixelT> & chi2Visitor,
573  afwMath::Kernel *kernel,
574  afwMath::SpatialCellSet const& psfCells,
575  int nStarPerCell,
576  int nComponents,
577  int nSpatialParams
578  ) : _errorDef(1.0),
579  _chi2Visitor(chi2Visitor),
580  _kernel(kernel),
581  _psfCells(psfCells),
582  _nStarPerCell(nStarPerCell),
583  _nComponents(nComponents),
584  _nSpatialParams(nSpatialParams) {}
585 
592  double Up() const { return _errorDef; }
593 
594  // Evaluate our cost function (in this case chi^2)
595  double operator()(const std::vector<double>& coeffs) const {
596  setSpatialParameters(_kernel, coeffs);
597 
599 
600  return _chi2Visitor.getValue();
601  }
602 
603  void setErrorDef(double def) { _errorDef = def; }
604 private:
605  double _errorDef; // how much cost function has changed at the +- 1 error points
606 
613 };
614 
615 /************************************************************************************************************/
619 template<typename PixelT>
620 std::pair<bool, double>
622  afwMath::Kernel *kernel,
623  afwMath::SpatialCellSet const& psfCells,
624  int const nStarPerCell,
625  double const tolerance,
626  double const lambda
627  ) {
628  typedef typename afwImage::Image<PixelT> Image;
629 
630  int const nComponents = kernel->getNKernelParameters();
631  int const nSpatialParams = kernel->getNSpatialParameters();
632  //
633  // visitor that evaluates the chi^2 of the current fit
634  //
635  evalChi2Visitor<PixelT> getChi2(*kernel, lambda);
636  //
637  // We have to unpack the Kernel coefficients into a linear array, coeffs
638  //
639  std::vector<double> coeffs; // The coefficients we want to fit
640  coeffs.assign(nComponents*nSpatialParams, 0.0);
641 
642  std::vector<double> stepSize; // step sizes
643  stepSize.assign(nComponents*nSpatialParams, 100);
644  //
645  // Translate that into minuit's language
646  //
647  ROOT::Minuit2::MnUserParameters fitPar;
648  std::vector<std::string> paramNames;
649  paramNames.reserve(nComponents*nSpatialParams);
650 
651  for (int i = 0, c = 0; c != nComponents; ++c) {
652  coeffs[i] = 1; // the constant part of each spatial order
653  for (int s = 0; s != nSpatialParams; ++s, ++i) {
654  paramNames.push_back((boost::format("C%d:%d") % c % s).str());
655  fitPar.Add(paramNames[i].c_str(), coeffs[i], stepSize[i]);
656  }
657  }
658  fitPar.Fix("C0:0");
659  //
660  // Create the minuit object that knows how to minimise our functor
661  //
662  MinimizeChi2<PixelT> minimizerFunc(getChi2, kernel, psfCells, nStarPerCell, nComponents, nSpatialParams);
663 
664  double const errorDef = 1.0; // use +- 1sigma errors
665  minimizerFunc.setErrorDef(errorDef);
666  //
667  // tell minuit about it
668  //
669  ROOT::Minuit2::MnMigrad migrad(minimizerFunc, fitPar);
670  //
671  // And let it loose
672  //
673  int maxFnCalls = 0; // i.e. unlimited
674  ROOT::Minuit2::FunctionMinimum min =
675  migrad(maxFnCalls, tolerance/(1e-4*errorDef)); // minuit uses 0.1*1e-3*tolerance*errorDef
676 
677  float minChi2 = min.Fval();
678  bool const isValid = min.IsValid() && std::isfinite(minChi2);
679 
680  if (true || isValid) { // calculate coeffs even in minuit is unhappy
681  for (int i = 0; i != nComponents*nSpatialParams; ++i) {
682  coeffs[i] = min.UserState().Value(i);
683  }
684 
685  setSpatialParameters(kernel, coeffs);
686  }
687 
688 #if 0 // Estimate errors; we don't really need this
689  ROOT::Minuit2::MnMinos minos(minimizerFunc, min);
690  for (int i = 0, c = 0; c != nComponents; ++c) {
691  for (int s = 0; s != nSpatialParams; ++s, ++i) {
692  char const *name = paramNames[i].c_str();
693  printf("%s %g", name, min.UserState().Value(name));
694  if (isValid && !fitPar.Parameter(fitPar.Index(name)).IsFixed()) {
695  printf(" (%g+%g)\n", minos(i).first, minos(i).second);
696  }
697  printf("\n");
698  }
699  }
700 #endif
701  //
702  // One time more through the Candidates setting their chi^2 values. We'll
703  // do all the candidates this time, not just the first nStarPerCell
704  //
705  psfCells.visitAllCandidates(&getChi2, true);
706 
707  return std::make_pair(isValid, minChi2);
708 }
709 
710 /************************************************************************************************************/
714 namespace {
751 template<typename PixelT>
752 class FillABVisitor : public afwMath::CandidateVisitor {
753  typedef afwImage::Image<PixelT> Image;
754  typedef afwImage::MaskedImage<PixelT> MaskedImage;
755  typedef afwImage::Exposure<PixelT> Exposure;
756 
758 public:
759  explicit FillABVisitor(afwMath::LinearCombinationKernel const& kernel, // the Kernel we're fitting
760  double tau2=0.0 // floor to the per-candidate variance
761  ) :
762  afwMath::CandidateVisitor(),
763  _kernel(kernel),
764  _tau2(tau2),
765  _nSpatialParams(_kernel.getNSpatialParameters()),
766  _nComponents(_kernel.getNKernelParameters()),
767  _basisImgs(),
771  {
772  _basisImgs.resize(_nComponents);
773 
774  _A.setZero();
775  _b.setZero();
776  //
777  // Get all the Kernel's components as Images
778  //
779  afwMath::KernelList const& kernels = _kernel.getKernelList(); // Kernel's components
780  for (int i = 0; i != _nComponents; ++i) {
781  _basisImgs[i] = typename KImage::Ptr(new KImage(kernels[i]->getDimensions()));
782  kernels[i]->computeImage(*_basisImgs[i], false);
783  }
784 
785  //
786  // Calculate the inner products of the Kernel components once and for all
787  //
788  for (int i = 1; i != _nComponents; ++i) { // Don't need 0th component
789  for (int j = i; j != _nComponents; ++j) {
790  _basisDotBasis(i, j) = _basisDotBasis(j, i) =
792  PsfCandidate<PixelT>::getBorderWidth());
793  }
794  }
795  }
796 
797  void reset() {}
798 
799  // Called by SpatialCellSet::visitCandidates for each Candidate
800  void processCandidate(afwMath::SpatialCellCandidate *candidate) {
801  PsfCandidate<PixelT> *imCandidate = dynamic_cast<PsfCandidate<PixelT> *>(candidate);
802  if (imCandidate == NULL) {
803  throw LSST_EXCEPT(lsst::pex::exceptions::LogicError,
804  "Failed to cast SpatialCellCandidate to PsfCandidate");
805  }
806 
807  CONST_PTR(MaskedImage) data;
808  try {
809  data = imCandidate->getMaskedImage(_kernel.getWidth(), _kernel.getHeight());
810  } catch(lsst::pex::exceptions::LengthError &) {
811  return;
812  }
813  double const xcen = imCandidate->getXCenter();
814  double const ycen = imCandidate->getYCenter();
815  double const dx = afwImage::positionToIndex(xcen, true).second;
816  double const dy = afwImage::positionToIndex(ycen, true).second;
817 
818 #if 0
819  double const amp = imCandidate->getAmplitude();
820 #else
821  /*
822  * Estimate the amplitude based on the current basis functions.
823  *
824  * N.b. you have to be a little careful here. Consider a PSF that is phi == (N0 + b*y*N1)/(1 + b*y)
825  * where the amplitude of N0 and N1 is 1.0, so a star has profile I = A*(N0 + b*y*N1)/(1 + b*y)
826  *
827  * If we set the amplitude to be A = I(0)/phi(0) (i.e. the central value of the data and best-fit phi)
828  * then the coefficient of N0 becomes 1/(1 + b*y) which makes the model non-linear in y.
829  */
830  std::pair<afwMath::Kernel::Ptr, std::pair<double, double> > ret =
831  fitKernelToImage(_kernel, *data, afwGeom::Point2D(xcen, ycen));
832  double const amp = ret.second.first;
833 #endif
834 
835  double const var = imCandidate->getVar();
836  double const ivar = 1/(var + _tau2); // Allow for floor on variance
837 
838  // Spatial params of all the components
839  std::vector<std::vector<double> > params(_nComponents);
840  for (int ic = 1; ic != _nComponents; ++ic) { // Don't need params[0]
841  params[ic] = _kernel.getSpatialFunction(ic)->getDFuncDParameters(xcen, ycen);
842  }
843 
844  std::vector<typename KImage::Ptr> basisImages = offsetKernel<KImage>(_kernel, dx, dy);
845 
846  // Prepare values for basis dot data
847  // Scale data and subtract 0th component as part of unit kernel sum construction
848  typename Image::Ptr dataImage(new Image(*data->getImage(), true));
849  typename KImage::fast_iterator bPtr = basisImages[0]->begin(true);
850  for (typename Image::fast_iterator dPtr = dataImage->begin(true), end = dataImage->end(true);
851  dPtr != end; ++dPtr, ++bPtr) {
852  *dPtr = *dPtr / amp - *bPtr;
853  }
854 
855  for (int i = 0, ic = 1; ic != _nComponents; ++ic) { // Don't need 0th component now
856  double const basisDotData = afwImage::innerProduct(*basisImages[ic], *dataImage,
857  PsfCandidate<PixelT>::getBorderWidth());
858  for (int is = 0; is != _nSpatialParams; ++is, ++i) {
859  _b(i) += ivar*params[ic][is]*basisDotData;
860 
861  for (int j = i, jc = ic; jc != _nComponents; ++jc) {
862  for (int js = (i == j) ? is : 0; js != _nSpatialParams; ++js, ++j) {
863  _A(i, j) += ivar*params[ic][is]*params[jc][js]*_basisDotBasis(ic, jc);
864  _A(j, i) = _A(i, j); // could do this after _A is fully calculated
865  }
866  }
867  }
868  }
869  }
870 
871  Eigen::MatrixXd const& getA() const { return _A; }
872  Eigen::VectorXd const& getB() const { return _b; }
873 
874 private:
876  double _tau2; // variance floor added in quadrature to true candidate variance
877  int const _nSpatialParams; // number of spatial parameters
878  int const _nComponents; // number of basis functions
879  std::vector<typename KImage::Ptr> _basisImgs; // basis function images from _kernel
880  Eigen::MatrixXd _A; // We'll solve the matrix equation A x = b for the Kernel's coefficients
881  Eigen::VectorXd _b;
882  Eigen::MatrixXd _basisDotBasis; // the inner products of the Kernel components
883 };
884 
885 
887 template<typename PixelT>
888 class setAmplitudeVisitor : public afwMath::CandidateVisitor {
889  typedef afwImage::MaskedImage<PixelT> MaskedImage;
890  typedef afwImage::Exposure<PixelT> Exposure;
891 public:
892  // Called by SpatialCellSet::visitCandidates for each Candidate
893  void processCandidate(afwMath::SpatialCellCandidate *candidate) {
894  PsfCandidate<PixelT> *imCandidate = dynamic_cast<PsfCandidate<PixelT> *>(candidate);
895  if (imCandidate == NULL) {
896  throw LSST_EXCEPT(lsst::pex::exceptions::LogicError,
897  "Failed to cast SpatialCellCandidate to PsfCandidate");
898  }
899  imCandidate->setAmplitude(afwMath::makeStatistics(*imCandidate->getMaskedImage()->getImage(),
900  afwMath::MAX).getValue());
901  }
902 };
903 
904 }
905 
906 
907 template<typename PixelT>
908 std::pair<bool, double>
910  afwMath::Kernel *kernel,
911  afwMath::SpatialCellSet const& psfCells,
912  bool const doNonLinearFit,
913  int const nStarPerCell,
914  double const tolerance,
915  double const lambda
916  )
917 {
918  if (doNonLinearFit) {
919  return fitSpatialKernelFromPsfCandidates<PixelT>(kernel, psfCells, nStarPerCell, tolerance);
920  }
921 
922  double const tau = 0; // softening for errors
923 
924  afwMath::LinearCombinationKernel const* lcKernel =
925  dynamic_cast<afwMath::LinearCombinationKernel const*>(kernel);
926  if (!lcKernel) {
927  throw LSST_EXCEPT(lsst::pex::exceptions::LogicError,
928  "Failed to cast Kernel to LinearCombinationKernel while building spatial PSF model");
929  }
930 #if 1
931  //
932  // Set the initial amplitudes of all our candidates
933  //
934  setAmplitudeVisitor<PixelT> setAmplitude;
935  psfCells.visitAllCandidates(&setAmplitude, true);
936 #endif
937  //
938  // visitor that fills out the A and b matrices (we'll solve A x = b for the coeffs, x)
939  //
940  FillABVisitor<PixelT> getAB(*lcKernel, tau);
941  //
942  // Actually visit all our candidates
943  //
944  psfCells.visitCandidates(&getAB, nStarPerCell, true);
945  //
946  // Extract A and b, and solve Ax = b
947  //
948  Eigen::MatrixXd const& A = getAB.getA();
949  Eigen::VectorXd const& b = getAB.getB();
950  Eigen::VectorXd x0(b.size()); // Solution to matrix problem
951  x0 = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
952 #if 0
953  std::cout << "A " << A << std::endl;
954  std::cout << "b " << b.transpose() << std::endl;
955  std::cout << "x " << x.transpose() << std::endl;
956 
957  afwImage::Image<double> img(b.size(), b.size());
958  for (int j = 0; j < b.size(); ++j) {
959  for (int i = 0; i < b.size(); ++i) {
960  img(i, j) = A(i, j);
961  }
962  }
963  img.writeFits("a.fits");
964 
965  if (x.cols() >= 6) {
966  for (int i = 0; i != 6; ++i) {
967  double xcen = 25; double ycen = 35 + 35*i;
968  std::cout << "x, y " << xcen << " , " << ycen << " b "
969  << (x[3] + xcen*x[4] + ycen*x[5])/(x[0] + xcen*x[1] + ycen*x[2]) << std::endl;
970  }
971  }
972 #endif
973 
974  // Generate kernel parameters (including 0th component) from matrix solution
975  Eigen::VectorXd x(kernel->getNKernelParameters() * kernel->getNSpatialParameters()); // Kernel parameters
976  x(0) = 1.0;
977  std::fill(x.data() + 1, x.data() + kernel->getNSpatialParameters(), 0.0);
978  std::copy(x0.data(), x0.data() + x0.size(), x.data() + kernel->getNSpatialParameters());
979 
980  setSpatialParameters(kernel, x);
981  //
982  // One time more through the Candidates setting their chi^2 values. We'll
983  // do all the candidates this time, not just the first nStarPerCell
984  //
985  // visitor that evaluates the chi^2 of the current fit
986  //
987  evalChi2Visitor<PixelT> getChi2(*kernel, lambda);
988 
989  psfCells.visitAllCandidates(&getChi2, true);
990 
991  return std::make_pair(true, getChi2.getValue());
992 }
993 
994 /************************************************************************************************************/
998 template<typename MaskedImageT>
999 double subtractPsf(afwDetection::Psf const& psf,
1000  MaskedImageT *data,
1001  double x,
1002  double y,
1003  double psfFlux
1004  )
1005 {
1006  if (lsst::utils::isnan(x + y)) {
1007  return std::numeric_limits<double>::quiet_NaN();
1008  }
1009 
1010  //
1011  // Get Psf candidate
1012  //
1013  afwDetection::Psf::Image::Ptr kImage = psf.computeImage(afwGeom::PointD(x, y));
1014 
1015  //
1016  // Now find the proper sub-Image
1017  //
1018  afwGeom::BoxI bbox = kImage->getBBox();
1019 
1020  typename MaskedImageT::Ptr subData(new MaskedImageT(*data, bbox, afwImage::PARENT, false)); // shallow copy
1021  //
1022  // Now we've got both; find the PSF's amplitude
1023  //
1024  double lambda = 0.0; // floor for variance is lambda*data
1025  try {
1026  double chi2; // chi^2 for fit
1027  double amp; // estimate of amplitude of model at this point
1028 
1029  if (lsst::utils::isnan(psfFlux)) {
1030  std::pair<double, double> result = fitKernel(*kImage, *subData, lambda, true);
1031  chi2 = result.first; // chi^2 for fit
1032  amp = result.second; // estimate of amplitude of model at this point
1033  } else {
1034  chi2 = std::numeric_limits<double>::quiet_NaN();
1035  amp = psfFlux/afwMath::makeStatistics(*kImage, afwMath::SUM).getValue();
1036  }
1037  //
1038  // Convert kImage to the proper type so that I can subtract it.
1039  //
1040  typename MaskedImageT::Image::Ptr
1041  kImageF(new typename MaskedImageT::Image(*kImage, true)); // of data's type
1042 
1043  *kImageF *= amp;
1044  *subData->getImage() -= *kImageF;
1045 
1046  return chi2;
1047  } catch(lsst::pex::exceptions::RangeError &e) {
1048  LSST_EXCEPT_ADD(e, (boost::format("Object at (%.2f, %.2f)") % x % y).str());
1049  throw e;
1050  }
1051 }
1052 
1053 /************************************************************************************************************/
1059 template<typename Image>
1060 std::pair<std::vector<double>, afwMath::KernelList>
1062  afwMath::LinearCombinationKernel const& kernel,
1063  Image const& image,
1064  afwGeom::Point2D const& pos
1065  )
1066 {
1068 
1069  afwMath::KernelList kernels = kernel.getKernelList(); // the Kernels that kernel adds together
1070  int const nKernel = kernels.size();
1071 
1072  if (nKernel == 0) {
1073  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
1074  "Your kernel must have at least one component");
1075  }
1076 
1077  /*
1078  * Go through all the kernels, get a copy centered at the desired sub-pixel position, and then
1079  * extract a subImage from the parent image at the same place
1080  */
1081  std::vector<KernelT::Ptr> kernelImages = offsetKernel<KernelT>(kernel, pos[0], pos[1]);
1082  afwGeom::BoxI bbox(kernelImages[0]->getBBox());
1083  Image const& subImage(Image(image, bbox, afwImage::PARENT, false)); // shallow copy
1084 
1085  /*
1086  * Solve the linear problem subImage = sum x_i K_i + epsilon; we solve this for x_i by constructing the
1087  * normal equations, A x = b
1088  */
1089  Eigen::MatrixXd A(nKernel, nKernel);
1090  Eigen::VectorXd b(nKernel);
1091 
1092  for (int i = 0; i != nKernel; ++i) {
1093  b(i) = afwImage::innerProduct(*kernelImages[i], *subImage.getImage());
1094 
1095  for (int j = i; j != nKernel; ++j) {
1096  A(i, j) = A(j, i) = afwImage::innerProduct(*kernelImages[i], *kernelImages[j]);
1097  }
1098  }
1099  Eigen::VectorXd x(nKernel);
1100 
1101  if (nKernel == 1) {
1102  x(0) = b(0)/A(0, 0);
1103  } else {
1104  x = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
1105  }
1106 
1107  // the XY0() point of the shifted Kernel basis functions
1108  int const x0 = kernelImages[0]->getX0(), y0 = kernelImages[0]->getY0();
1109 
1110  afwMath::KernelList newKernels(nKernel);
1111  std::vector<double> params(nKernel);
1112  for (int i = 0; i != nKernel; ++i) {
1113  afwMath::Kernel::Ptr newKernel(new afwMath::FixedKernel(*kernelImages[i]));
1114  newKernel->setCtrX(x0 + static_cast<int>(newKernel->getWidth()/2));
1115  newKernel->setCtrY(y0 + static_cast<int>(newKernel->getHeight()/2));
1116 
1117  params[i] = x[i];
1118  newKernels[i] = newKernel;
1119  }
1120 
1121  return std::make_pair(params, newKernels);
1122 }
1123 
1124 
1125 /************************************************************************************************************/
1131 template<typename Image>
1132 std::pair<afwMath::Kernel::Ptr, std::pair<double, double> >
1134  afwMath::LinearCombinationKernel const& kernel,
1135  Image const& image,
1136  afwGeom::Point2D const& pos
1137  )
1138 {
1139  std::pair<std::vector<double>, afwMath::KernelList> const fit =
1140  fitKernelParamsToImage(kernel, image, pos);
1141  std::vector<double> params = fit.first;
1142  afwMath::KernelList kernels = fit.second;
1143  int const nKernel = params.size();
1144  assert(kernels.size() == static_cast<unsigned int>(nKernel));
1145 
1146  double amp = 0.0;
1147  for (int i = 0; i != nKernel; ++i) {
1148  afwMath::Kernel::Ptr base = kernels[i];
1149  afwMath::FixedKernel::Ptr k = boost::static_pointer_cast<afwMath::FixedKernel>(base);
1150  amp += params[i] * k->getSum();
1151  }
1152 
1153  afwMath::Kernel::Ptr outputKernel(new afwMath::LinearCombinationKernel(kernels, params));
1154  double chisq = 0.0;
1155  outputKernel->setCtrX(kernels[0]->getCtrX());
1156  outputKernel->setCtrY(kernels[0]->getCtrY());
1157 
1158  return std::make_pair(outputKernel, std::make_pair(amp, chisq));
1159 }
1160 
1161 
1162 /************************************************************************************************************/
1163 //
1164 // Explicit instantiations
1165 //
1167  typedef float Pixel;
1168 
1169  template
1170  std::pair<afwMath::LinearCombinationKernel::Ptr, std::vector<double> >
1171  createKernelFromPsfCandidates<Pixel>(afwMath::SpatialCellSet const&, afwGeom::Extent2I const&,
1172  afwGeom::Point2I const&, int const, int const, int const,
1173  int const, bool const, int const);
1174  template
1175  int countPsfCandidates<Pixel>(afwMath::SpatialCellSet const&, int const);
1176 
1177  template
1178  std::pair<bool, double>
1179  fitSpatialKernelFromPsfCandidates<Pixel>(afwMath::Kernel *, afwMath::SpatialCellSet const&,
1180  int const, double const, double const);
1181  template
1182  std::pair<bool, double>
1183  fitSpatialKernelFromPsfCandidates<Pixel>(afwMath::Kernel *, afwMath::SpatialCellSet const&, bool const,
1184  int const, double const, double const);
1185 
1186  template
1187  double subtractPsf(afwDetection::Psf const&, afwImage::MaskedImage<float> *, double, double, double);
1188 
1189  template
1190  std::pair<std::vector<double>, afwMath::KernelList>
1193 
1194  template
1195  std::pair<afwMath::Kernel::Ptr, std::pair<double, double> >
1199 }}}
int y
afwImage::MaskedImage< PixelT > MaskedImage
2-dimensional weighted sum of Chebyshev polynomials of the first kind.
Class for doing PCA on PSF stars.
boost::shared_ptr< lsst::afw::math::Function2< double > > SpatialFunctionPtr
Definition: Kernel.h:143
Class used by SpatialCell for spatial PSF fittig.
void setStatus(Status status)
Set the candidate&#39;s status.
Definition: SpatialCell.cc:61
A coordinate class intended to represent absolute positions.
void setAmplitude(double amplitude)
Set the best-fit amplitude.
Definition: PsfCandidate.h:122
geom::Extent2I const getDimensions() const
Return the Kernel&#39;s dimensions (width, height)
Definition: Kernel.h:226
x_iterator fast_iterator
Definition: Image.h:154
std::vector< double > const & getEigenValues() const
Return Eigen values.
Definition: ImagePca.h:68
Represent a set of pixels of an arbitrary shape and size.
afwImage::Exposure< PixelT > Exposure
table::Key< std::string > name
Definition: ApCorrMap.cc:71
afwImage::Image< afwMath::Kernel::Pixel > KImage
int positionToIndex(double pos)
Convert image position to nearest integer index.
Definition: ImageUtils.h:69
std::vector< typename KImage::Ptr > _basisImgs
void processCandidate(afwMath::SpatialCellCandidate *candidate)
int countPsfCandidates(lsst::afw::math::SpatialCellSet const &psfCells, int const nStarPerCell=-1)
boost::shared_ptr< afw::table::SourceRecord > getSource() const
Return the original Source.
Definition: PsfCandidate.h:116
A class to contain the data, WCS, and other information needed to describe an image of the sky...
Definition: Exposure.h:48
A coordinate class intended to represent offsets and dimensions.
boost::uint16_t MaskPixel
double innerProduct(Image1T const &lhs, Image2T const &rhs, int const border=0)
Definition: ImagePca.cc:454
double subtractPsf(lsst::afw::detection::Psf const &psf, ImageT *data, double x, double y, double psfFlux=std::numeric_limits< double >::quiet_NaN())
MinimizeChi2(evalChi2Visitor< PixelT > &chi2Visitor, afwMath::Kernel *kernel, afwMath::SpatialCellSet const &psfCells, int nStarPerCell, int nComponents, int nSpatialParams)
boost::shared_ptr< Image > computeImage(geom::Point2D position=makeNullPoint(), image::Color color=image::Color(), ImageOwnerEnum owner=COPY) const
Return an Image of the PSF, in a form that can be compared directly with star images.
SelectEigenView< T >::Type copy(Eigen::EigenBase< T > const &other)
Copy an arbitrary Eigen expression into a new EigenView.
Definition: eigen.h:390
int getNSpatialParameters() const
Return the number of spatial parameters (0 if not spatially varying)
Definition: Kernel.h:296
boost::shared_ptr< LinearCombinationKernel > Ptr
Definition: Kernel.h:818
Define a collection of useful Functions.
boost::shared_ptr< const MaskedImage > ConstPtr
Definition: MaskedImage.h:88
estimate sample maximum
Definition: Statistics.h:77
evalChi2Visitor(afwMath::Kernel const &kernel, double lambda)
int isnan(T t)
Definition: ieee.h:110
unsigned long _n
Definition: RandomImage.cc:68
std::pair< std::vector< double >, lsst::afw::math::KernelList > fitKernelParamsToImage(lsst::afw::math::LinearCombinationKernel const &kernel, Image const &image, lsst::afw::geom::Point2D const &pos)
int const x0
Definition: saturated.cc:45
boost::enable_if< typename ExpressionTraits< Scalar >::IsScalar, Scalar >::type sum(Scalar const &scalar)
Definition: operators.h:1250
An integer coordinate rectangle.
Definition: Box.h:53
int getHeight() const
Return the Kernel&#39;s height.
Definition: Kernel.h:247
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
int const _nSpatialParams
int getWidth() const
Return the Kernel&#39;s width.
Definition: Kernel.h:240
double getValue(Property const prop=NOTHING) const
Return the value of the desired property (if specified in the constructor)
Definition: Statistics.cc:1009
Eigen::MatrixXd _basisDotBasis
boost::shared_ptr< Kernel > Ptr
Definition: Kernel.h:141
A collection of SpatialCells covering an entire image.
Definition: SpatialCell.h:378
ImageList const & getEigenImages() const
Return Eigen images.
Definition: ImagePca.h:70
Pass parameters to a Statistics objectA class to pass parameters which control how the stats are calc...
Definition: Statistics.h:92
A class to pass around to all our PsfCandidates to evaluate the PSF fit&#39;s X^2.
Class used by SpatialCell for spatial PSF fittig.
unsigned int getNKernelParameters() const
Return the number of kernel parameters (0 if none)
Definition: Kernel.h:289
afwMath::LinearCombinationKernel const & _kernel
virtual KernelList const & getKernelList() const
Get the fixed basis kernels.
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
double _tau2
A kernel that is a linear combination of fixed basis kernels.
Definition: Kernel.h:814
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:77
boost::shared_ptr< MaskedImage > Ptr
shared pointer to a MaskedImage
Definition: MaskedImage.h:87
evalChi2Visitor< PixelT > & _chi2Visitor
boost::shared_ptr< Image< PixelT > > Ptr
Definition: Image.h:418
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
double x
int isfinite(T t)
Definition: ieee.h:100
int const _nComponents
void setSpatialParameters(const std::vector< std::vector< double > > params)
Set the parameters of all spatial functions.
Definition: Kernel.cc:139
void setSpatialParameters(afwMath::Kernel *kernel, std::vector< double > const &coeffs)
double chisq
ImageT::Ptr offsetImage(ImageT const &image, float dx, float dy, std::string const &algorithmName="lanczos5", unsigned int buffer=0)
Return an image offset by (dx, dy) using the specified algorithm.
Definition: offsetImage.cc:55
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
tuple m
Definition: lsstimport.py:48
void setNanSafe(bool isNanSafe)
Definition: Statistics.h:148
SpatialFunctionPtr getSpatialFunction(unsigned int index) const
Return a clone of the specified spatial function (one component of the spatial model) ...
Definition: Kernel.cc:171
boost::shared_ptr< FixedKernel > Ptr
Definition: Kernel.h:553
static void setWidth(int width)
Set the width of the image that getImage should return.
Definition: SpatialCell.h:210
afwMath::SpatialCellSet const & _psfCells
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Definition: Statistics.cc:1082
double const _b
Definition: RandomImage.cc:78
#define CONST_PTR(...)
Definition: base.h:47
Class to ensure constraints for spatial modeling.
afw::table::Key< double > b
std::pair< lsst::afw::math::Kernel::Ptr, std::pair< double, double > > fitKernelToImage(lsst::afw::math::LinearCombinationKernel const &kernel, Image const &image, lsst::afw::geom::Point2D const &pos)
static void setHeight(int height)
Set the height of the image that getImage should return.
Definition: SpatialCell.h:217
void visitAllCandidates(CandidateVisitor *visitor, bool const ignoreExceptions=false)
Definition: SpatialCell.cc:546
double operator()(const std::vector< double > &coeffs) const
boost::shared_ptr< afw::image::MaskedImage< PixelT > > getOffsetImage(std::string const algorithm, unsigned int buffer) const
Return an offset version of the image of the source. The returned image has been offset to put the ce...
void setChi2(double chi2)
Set the candidate&#39;s chi^2.
Definition: SpatialCell.h:224
find sum of pixels in the image
Definition: Statistics.h:78
A floating-point coordinate rectangle geometry.
Definition: Box.h:271
A polymorphic base class for representing an image&#39;s Point Spread Function.
Definition: Psf.h:68
int const y0
Definition: saturated.cc:45
std::pair< lsst::afw::math::LinearCombinationKernel::Ptr, std::vector< double > > createKernelFromPsfCandidates(lsst::afw::math::SpatialCellSet const &psfCells, lsst::afw::geom::Extent2I const &dims, lsst::afw::geom::Point2I const &xy0, int const nEigenComponents, int const spatialOrder, int const ksize, int const nStarPerCell=-1, bool const constantWeight=true, int const border=3)
#define LSST_EXCEPT_ADD(e, m)
Definition: Exception.h:51
Kernels are used for convolution with MaskedImages and (eventually) Images.
Definition: Kernel.h:134
void visitCandidates(CandidateVisitor *visitor, int const nMaxPerCell=-1, bool const ignoreExceptions=false)
Definition: SpatialCell.cc:510
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:415
Class stored in SpatialCells for spatial Psf fitting.
Definition: PsfCandidate.h:57
virtual double updateBadPixels(unsigned long mask, int const ncomp)
Definition: ImagePca.cc:417
Eigen::MatrixXd _A
PsfImagePca< MaskedImageT > * _imagePca
std::pair< bool, double > fitSpatialKernelFromPsfCandidates(lsst::afw::math::Kernel *kernel, lsst::afw::math::SpatialCellSet const &psfCells, int const nStarPerCell=-1, double const tolerance=1e-5, double const lambda=0.0)
A kernel created from an Image.
Definition: Kernel.h:551
std::vector< boost::shared_ptr< Kernel > > KernelList
Definition: Kernel.h:542