lsst.ip.diffim  21.0.0-11-ga42c5b2+786b8397db
DipoleAlgorithms.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2008-2015 AURA/LSST
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <http://www.lsstcorp.org/LegalNotices/>.
21  */
22 
26 #include <iostream> // std::cout
27 #include <algorithm> // std::sort
28 #include <functional> // std::binary_function
29 #include <limits> // std::numeric_limits
30 #include <cmath> // std::sqrt
31 
32 #if !defined(DOXYGEN)
33 # include "Minuit2/FCNBase.h"
34 # include "Minuit2/FunctionMinimum.h"
35 # include "Minuit2/MnMigrad.h"
36 # include "Minuit2/MnMinos.h"
37 # include "Minuit2/MnPrint.h"
38 #endif
39 
40 #include <memory>
41 #include "lsst/pex/exceptions.h"
42 #include "lsst/afw/image.h"
43 #include "lsst/afw/detection.h"
44 #include "lsst/afw/table.h"
45 #include "lsst/afw/math.h"
46 #include "lsst/geom.h"
48 #include "ndarray/eigen.h"
49 
51 namespace afwDet = lsst::afw::detection;
52 namespace afwImage = lsst::afw::image;
53 namespace afwMath = lsst::afw::math;
54 namespace geom = lsst::geom;
55 
56 namespace lsst { namespace ip { namespace diffim {
57 
58 namespace {
59 meas::base::FlagDefinitionList dipoleFluxFlagDefinitions;
60 }
61 
62 meas::base::FlagDefinition const DipoleFluxAlgorithm::FAILURE = dipoleFluxFlagDefinitions.addFailureFlag("general failure flag, set if anything went wrong");
63 meas::base::FlagDefinition const DipoleFluxAlgorithm::POS_FLAG = dipoleFluxFlagDefinitions.add("pos_flag", "failure flag for positive, set if anything went wrong");
64 meas::base::FlagDefinition const DipoleFluxAlgorithm::NEG_FLAG = dipoleFluxFlagDefinitions.add("neg_flag", "failure flag for negative, set if anything went wrong");
65 
67  return dipoleFluxFlagDefinitions;
68 }
69 
70 namespace {
71 meas::base::FlagDefinitionList dipoleCentroidFlagDefinitions;
72 }
73 
74 meas::base::FlagDefinition const DipoleCentroidAlgorithm::FAILURE = dipoleCentroidFlagDefinitions.addFailureFlag("general failure flag, set if anything went wrong");
75 meas::base::FlagDefinition const DipoleCentroidAlgorithm::POS_FLAG = dipoleCentroidFlagDefinitions.add("pos_flag", "failure flag for positive, set if anything went wrong");
76 meas::base::FlagDefinition const DipoleCentroidAlgorithm::NEG_FLAG = dipoleCentroidFlagDefinitions.add("neg_flag", "failure flag for negative, set if anything went wrong");
77 
79  return dipoleCentroidFlagDefinitions;
80 }
81 
82  int const NEGCENTXPAR(0); // Parameter for the x-component of the negative lobe centroid
83  int const NEGCENTYPAR(1); // Parameter for the y-component of the negative lobe centroid
84  int const NEGFLUXPAR(2); // Parameter for the flux of the negative lobe
85  int const POSCENTXPAR(3); // Parameter for the x-component of the positive lobe centroid
86  int const POSCENTYPAR(4); // Parameter for the y-component of the positive lobe centroid
87  int const POSFLUXPAR(5); // Parameter for the flux of the positive lobe
88 
89 
90 namespace {
91 
92 void naiveCentroid(
93  afw::table::SourceRecord & source,
94  afw::image::Exposure<float> const& exposure,
95  geom::Point2I const & center,
97  )
98 {
99  typedef afw::image::Image<float> ImageT;
100  ImageT const& image = *exposure.getMaskedImage().getImage();
101  // set to the input centroid, just in case all else fails
102  source.set(keys.getX(), center.getX());
103  source.set(keys.getY(), center.getY());
104 
105  int x = center.getX() - image.getX0();
106  int y = center.getY() - image.getY0();
107 
108  if (x < 1 || x >= image.getWidth() - 1 || y < 1 || y >= image.getHeight() - 1) {
110  (boost::format("Object at (%d, %d) is too close to the edge")
111  % x % y).str());
112  }
113 
114  ImageT::xy_locator im = image.xy_at(x, y);
115 
116  double const sum =
117  (im(-1, 1) + im( 0, 1) + im( 1, 1) +
118  im(-1, 0) + im( 0, 0) + im( 1, 0) +
119  im(-1, -1) + im( 0, -1) + im( 1, -1));
120 
121 
122  if (sum == 0.0) {
124  (boost::format("Object at (%d, %d) has no counts") %
125  x % y).str());
126  }
127 
128  double const sum_x =
129  -im(-1, 1) + im( 1, 1) +
130  -im(-1, 0) + im( 1, 0) +
131  -im(-1, -1) + im( 1, -1);
132  double const sum_y =
133  (im(-1, 1) + im( 0, 1) + im( 1, 1)) -
134  (im(-1, -1) + im( 0, -1) + im( 1, -1));
135 
136  float xx = afw::image::indexToPosition(x + image.getX0()) + sum_x / sum;
137  float yy = afw::image::indexToPosition(y + image.getY0()) + sum_y / sum;
138  source.set(keys.getX(), xx);
139  source.set(keys.getY(), yy);
140 }
141 
142 } // anonymous namespace
143 
144 
146  Control const & ctrl,
147  std::string const & name,
148  afw::table::Schema & schema
149 ) : DipoleCentroidAlgorithm(ctrl, name, schema, "unweighted first moment centroid"),
150  _ctrl(ctrl)
151 { }
152 
157  afw::table::SourceRecord & source,
158  afw::image::Exposure<float> const & exposure
159 ) const {
160  afw::detection::PeakCatalog const& peaks = source.getFootprint()->getPeaks();
161 
162  int posInd = 0;
163  double posValue = peaks[posInd].getPeakValue(), negValue = 0;
164  if (posValue < 0.) { /* All peaks are negative so use the *most* negative value */
165  posInd = peaks.size() - 1;
166  posValue = peaks[posInd].getPeakValue();
167  }
168  naiveCentroid(source, exposure, peaks[posInd].getI(),
169  (posValue >= 0 ? getPositiveKeys() : getNegativeKeys()));
170 
171  if (posValue > 0. && posInd == 0 && peaks.size() > 1) { /* See if there's also a negative peak */
172  int negInd = peaks.size() - 1;
173  negValue = peaks[negInd].getPeakValue();
174  if (posValue > 0. && negValue < 0.) {
175  naiveCentroid(source, exposure, peaks[negInd].getI(),
176  (negValue >= 0 ? getPositiveKeys() : getNegativeKeys()));
177  }
178  }
179 
180  mergeCentroids(source, posValue, negValue);
181 
182 }
183 
185  double posValue, double negValue) const {
186 
187  double pos_x, pos_y, pos_f;
188  double neg_x, neg_y, neg_f;
189 
190  pos_x = source.get(getPositiveKeys().getX());
191  pos_y = source.get(getPositiveKeys().getY());
192  pos_f = posValue;
193 
194  neg_x = source.get(getNegativeKeys().getX());
195  neg_y = source.get(getNegativeKeys().getY());
196  neg_f = -negValue;
197 
198  if(std::isfinite(pos_x) && std::isfinite(pos_y) &&
199  std::isfinite(neg_x) && std::isfinite(neg_y)) {
200  source.set(getCenterKeys().getX(), (pos_x * pos_f + neg_x * neg_f) / (pos_f + neg_f));
201  source.set(getCenterKeys().getY(), (pos_y * pos_f + neg_y * neg_f) / (pos_f + neg_f));
202  } else if (std::isfinite(pos_x) && std::isfinite(pos_y)) {
203  source.set(getCenterKeys().getX(), pos_x);
204  source.set(getCenterKeys().getY(), pos_y);
205  } else {
206  source.set(getCenterKeys().getX(), neg_x);
207  source.set(getCenterKeys().getY(), neg_y);
208  }
209 }
210 
212  meas::base::MeasurementError * error) const {
213  _flagHandler.handleFailure(measRecord, error);
214 }
215 
216 
217 namespace {
218 
219 class NaiveDipoleFootprinter {
220 public:
221  explicit NaiveDipoleFootprinter() : _sumPositive(0.0), _sumNegative(0.0), _numPositive(0),
222  _numNegative(0) {}
223 
225  void reset() {
226  _sumPositive = _sumNegative = 0.0;
227  _numPositive = _numNegative = 0;
228  }
229  void reset(afwDet::Footprint const&) {}
230 
232  void operator() (geom::Point2I const & pos,
235  if (ival >= 0.0) {
236  _sumPositive += ival;
237  _varPositive += vval;
238  ++_numPositive;
239  } else {
240  _sumNegative += ival;
241  _varPositive += vval;
242  ++_numNegative;
243  }
244  }
245 
246  double getSumPositive() const { return _sumPositive; }
247  double getSumNegative() const { return _sumNegative; }
248  double getVarPositive() const { return _sumPositive; }
249  double getVarNegative() const { return _sumNegative; }
250  int getNumPositive() const { return _numPositive; }
251  int getNumNegative() const { return _numNegative; }
252 
253 private:
254  double _sumPositive;
255  double _sumNegative;
256  double _varPositive;
257  double _varNegative;
258  int _numPositive;
259  int _numNegative;
260 };
261 
262 } // anonymous namespace
263 
264 
269  afw::table::SourceRecord & source,
270  afw::image::Exposure<float> const & exposure
271 ) const {
272  typedef afw::image::Exposure<float>::MaskedImageT MaskedImageT;
273 
274  NaiveDipoleFootprinter functor;
275  source.getFootprint()->getSpans()->applyFunctor(functor, *(exposure.getMaskedImage().getImage()),
276  *(exposure.getMaskedImage().getVariance()));
277 
278  source.set(getPositiveKeys().getInstFlux(), functor.getSumPositive());
279  source.set(getPositiveKeys().getInstFluxErr(), ::sqrt(functor.getVarPositive()));
280  source.set(_numPositiveKey, functor.getNumPositive());
281 
282  source.set(getNegativeKeys().getInstFlux(), functor.getSumNegative());
283  source.set(getNegativeKeys().getInstFluxErr(), ::sqrt(functor.getVarNegative()));
284  source.set(_numNegativeKey, functor.getNumNegative());
285  functor.reset();
286 }
287 
289  _flagHandler.handleFailure(measRecord, error);
290 }
291 
292 
296 class MinimizeDipoleChi2 : public ROOT::Minuit2::FCNBase {
297 public:
298  explicit MinimizeDipoleChi2(PsfDipoleFlux const& psfDipoleFlux,
299  afw::table::SourceRecord & source,
300  afw::image::Exposure<float> const& exposure
301  ) : _errorDef(1.0),
302  _nPar(6),
303  _maxPix(1e4),
304  _bigChi2(1e10),
305  _psfDipoleFlux(psfDipoleFlux),
306  _source(source),
307  _exposure(exposure)
308  {}
309  double Up() const { return _errorDef; }
310  void setErrorDef(double def) { _errorDef = def; }
311  int getNpar() const { return _nPar; }
312  int getMaxPix() const { return _maxPix; }
313  void setMaxPix(int maxPix) { _maxPix = maxPix; }
314 
315  // Evaluate our cost function (in this case chi^2)
316  virtual double operator()(std::vector<double> const & params) const {
317  double negCenterX = params[NEGCENTXPAR];
318  double negCenterY = params[NEGCENTYPAR];
319  double negFlux = params[NEGFLUXPAR];
320  double posCenterX = params[POSCENTXPAR];
321  double posCenterY = params[POSCENTYPAR];
322  double posFlux = params[POSFLUXPAR];
323 
324  /* Restrict negative dipole to be negative; positive to be positive */
325  if ((negFlux > 0.0) || (posFlux < 0.0)) {
326  return _bigChi2;
327  }
328 
329  std::pair<double,int> fit = _psfDipoleFlux.chi2(_source, _exposure, negCenterX, negCenterY, negFlux,
330  posCenterX, posCenterY, posFlux);
331  double chi2 = fit.first;
332  int nPix = fit.second;
333  if (nPix > _maxPix) {
334  return _bigChi2;
335  }
336 
337  return chi2;
338  }
339 
340 private:
341  double _errorDef; // how much cost function has changed at the +- 1 error points
342  int _nPar; // number of parameters in the fit; hard coded for MinimizeDipoleChi2
343  int _maxPix; // maximum number of pixels that shoud be in the footprint;
344  // prevents too much centroid wander
345  double _bigChi2; // large value to tell fitter when it has gone into bad region of parameter space
346 
347  PsfDipoleFlux const& _psfDipoleFlux;
348  afw::table::SourceRecord & _source;
349  afw::image::Exposure<float> const& _exposure;
350 };
351 
353  afw::table::SourceRecord & source,
354  afw::image::Exposure<float> const& exposure,
355  double negCenterX, double negCenterY, double negFlux,
356  double posCenterX, double posCenterY, double posFlux
357 ) const {
358 
359  geom::Point2D negCenter(negCenterX, negCenterY);
360  geom::Point2D posCenter(posCenterX, posCenterY);
361 
362  CONST_PTR(afw::detection::Footprint) footprint = source.getFootprint();
363 
364  /*
365  * Fit for the superposition of Psfs at the two centroids.
366  */
367  CONST_PTR(afwDet::Psf) psf = exposure.getPsf();
368  PTR(afwImage::Image<afwMath::Kernel::Pixel>) negPsf = psf->computeImage(negCenter);
369  PTR(afwImage::Image<afwMath::Kernel::Pixel>) posPsf = psf->computeImage(posCenter);
370 
371  afwImage::Image<double> negModel(footprint->getBBox());
372  afwImage::Image<double> posModel(footprint->getBBox());
373  afwImage::Image<float> data(*(exposure.getMaskedImage().getImage()),footprint->getBBox());
375  footprint->getBBox());
376 
377  geom::Box2I negPsfBBox = negPsf->getBBox();
378  geom::Box2I posPsfBBox = posPsf->getBBox();
379  geom::Box2I negModelBBox = negModel.getBBox();
380  geom::Box2I posModelBBox = posModel.getBBox();
381 
382  // Portion of the negative Psf that overlaps the model
383  int negXmin = std::max(negPsfBBox.getMinX(), negModelBBox.getMinX());
384  int negYmin = std::max(negPsfBBox.getMinY(), negModelBBox.getMinY());
385  int negXmax = std::min(negPsfBBox.getMaxX(), negModelBBox.getMaxX());
386  int negYmax = std::min(negPsfBBox.getMaxY(), negModelBBox.getMaxY());
387  geom::Box2I negBBox = geom::Box2I(geom::Point2I(negXmin, negYmin),
388  geom::Point2I(negXmax, negYmax));
389  afwImage::Image<afwMath::Kernel::Pixel> negSubim(*negPsf, negBBox);
390  afwImage::Image<double> negModelSubim(negModel, negBBox);
391  negModelSubim += negSubim;
392 
393  // Portion of the positive Psf that overlaps the model
394  int posXmin = std::max(posPsfBBox.getMinX(), posModelBBox.getMinX());
395  int posYmin = std::max(posPsfBBox.getMinY(), posModelBBox.getMinY());
396  int posXmax = std::min(posPsfBBox.getMaxX(), posModelBBox.getMaxX());
397  int posYmax = std::min(posPsfBBox.getMaxY(), posModelBBox.getMaxY());
398  geom::Box2I posBBox = geom::Box2I(geom::Point2I(posXmin, posYmin),
399  geom::Point2I(posXmax, posYmax));
400  afwImage::Image<afwMath::Kernel::Pixel> posSubim(*posPsf, posBBox);
401  afwImage::Image<double> posModelSubim(posModel, posBBox);
402  posModelSubim += posSubim;
403 
404  negModel *= negFlux; // scale negative model to image
405  posModel *= posFlux; // scale positive model to image
406  afwImage::Image<double> residuals(negModel, true); // full model contains negative lobe...
407  residuals += posModel; // plus positive lobe...
408  residuals -= data; // minus the data...
409  residuals *= residuals; // squared...
410  residuals /= var; // divided by the variance : [(model-data)/sigma]**2
411  afwMath::Statistics stats = afwMath::makeStatistics(residuals, afwMath::SUM | afwMath::NPOINT);
412  double chi2 = stats.getValue(afwMath::SUM);
413  int nPix = stats.getValue(afwMath::NPOINT);
414  return std::pair<double,int>(chi2, nPix);
415 }
416 
418  afw::table::SourceRecord & source,
419  afw::image::Exposure<float> const & exposure
420 ) const {
421 
422  typedef afw::image::Exposure<float>::MaskedImageT MaskedImageT;
423 
424  CONST_PTR(afw::detection::Footprint) footprint = source.getFootprint();
425  if (!footprint) {
427  (boost::format("No footprint for source %d") % source.getId()).str());
428  }
429 
430  afw::detection::PeakCatalog peakCatalog = afw::detection::PeakCatalog(footprint->getPeaks());
431 
432  if (peakCatalog.size() == 0) {
434  (boost::format("No peak for source %d") % source.getId()).str());
435  }
436  else if (peakCatalog.size() == 1) {
437  // No deblending to do
438  return;
439  }
440 
441  // For N>=2, just measure the brightest-positive and brightest-negative
442  // peaks. peakCatalog is automatically ordered by peak flux, with the most
443  // positive one (brightest) being first
444  afw::detection::PeakRecord const& positivePeak = peakCatalog.front();
445  afw::detection::PeakRecord const& negativePeak = peakCatalog.back();
446 
447  // Set up fit parameters and param names
448  ROOT::Minuit2::MnUserParameters fitPar;
449 
450  fitPar.Add((boost::format("P%d")%NEGCENTXPAR).str(), negativePeak.getFx(), _ctrl.stepSizeCoord);
451  fitPar.Add((boost::format("P%d")%NEGCENTYPAR).str(), negativePeak.getFy(), _ctrl.stepSizeCoord);
452  fitPar.Add((boost::format("P%d")%NEGFLUXPAR).str(), negativePeak.getPeakValue(), _ctrl.stepSizeFlux);
453  fitPar.Add((boost::format("P%d")%POSCENTXPAR).str(), positivePeak.getFx(), _ctrl.stepSizeCoord);
454  fitPar.Add((boost::format("P%d")%POSCENTYPAR).str(), positivePeak.getFy(), _ctrl.stepSizeCoord);
455  fitPar.Add((boost::format("P%d")%POSFLUXPAR).str(), positivePeak.getPeakValue(), _ctrl.stepSizeFlux);
456 
457  // Create the minuit object that knows how to minimise our functor
458  //
459  MinimizeDipoleChi2 minimizerFunc(*this, source, exposure);
460  minimizerFunc.setErrorDef(_ctrl.errorDef);
461 
462  //
463  // tell minuit about it
464  //
465  ROOT::Minuit2::MnMigrad migrad(minimizerFunc, fitPar);
466 
467  //
468  // And let it loose
469  //
470  ROOT::Minuit2::FunctionMinimum min = migrad(_ctrl.maxFnCalls);
471 
472  float minChi2 = min.Fval();
473  bool const isValid = min.IsValid() && std::isfinite(minChi2);
474 
475  if (true || isValid) { // calculate coeffs even in minuit is unhappy
476 
477  /* I need to call chi2 one more time to grab nPix to calculate chi2/dof.
478  Turns out that the Minuit operator method has to be const, and the
479  measurement _apply method has to be const, so I can't store nPix as a
480  private member variable anywhere. Consted into a corner.
481  */
482  std::pair<double,int> fit = chi2(source, exposure,
483  min.UserState().Value(NEGCENTXPAR),
484  min.UserState().Value(NEGCENTYPAR),
485  min.UserState().Value(NEGFLUXPAR),
486  min.UserState().Value(POSCENTXPAR),
487  min.UserState().Value(POSCENTYPAR),
488  min.UserState().Value(POSFLUXPAR));
489  double evalChi2 = fit.first;
490  int nPix = fit.second;
491 
492  PTR(geom::Point2D) minNegCentroid(new geom::Point2D(min.UserState().Value(NEGCENTXPAR),
493  min.UserState().Value(NEGCENTYPAR)));
494  source.set(getNegativeKeys().getInstFlux(), min.UserState().Value(NEGFLUXPAR));
495  source.set(getNegativeKeys().getInstFluxErr(), min.UserState().Error(NEGFLUXPAR));
496 
497  PTR(geom::Point2D) minPosCentroid(new geom::Point2D(min.UserState().Value(POSCENTXPAR),
498  min.UserState().Value(POSCENTYPAR)));
499  source.set(getPositiveKeys().getInstFlux(), min.UserState().Value(POSFLUXPAR));
500  source.set(getPositiveKeys().getInstFluxErr(), min.UserState().Error(POSFLUXPAR));
501 
502  source.set(_chi2dofKey, evalChi2 / (nPix - minimizerFunc.getNpar()));
503  source.set(_negCentroid.getX(), minNegCentroid->getX());
504  source.set(_negCentroid.getY(), minNegCentroid->getY());
505  source.set(_posCentroid.getX(), minPosCentroid->getX());
506  source.set(_posCentroid.getY(), minPosCentroid->getY());
507  source.set(_avgCentroid.getX(), 0.5*(minNegCentroid->getX() + minPosCentroid->getX()));
508  source.set(_avgCentroid.getY(), 0.5*(minNegCentroid->getY() + minPosCentroid->getY()));
509 
510  }
511 }
512 
514  _flagHandler.handleFailure(measRecord, error);
515 }
516 }}} // namespace lsst::ip::diffim
table::Key< std::string > name
char * data
int min
double x
#define LSST_EXCEPT(type,...)
afw::table::Key< afw::table::Array< ImagePixelT > > image
int y
#define PTR(...)
#define CONST_PTR(...)
MaskedImageT getMaskedImage()
std::shared_ptr< lsst::afw::detection::Psf const > getPsf() const
lsst::geom::Box2I getBBox(ImageOrigin origin=PARENT) const
VariancePtr getVariance() const
double getValue(Property const prop=NOTHING) const
size_type size() const
reference back() const
reference front() const
int getMinY() const noexcept
int getMinX() const noexcept
int getMaxX() const noexcept
int getMaxY() const noexcept
Intermediate base class for algorithms that compute a centroid.
static meas::base::FlagDefinition const FAILURE
static meas::base::FlagDefinition const POS_FLAG
static meas::base::FlagDefinition const NEG_FLAG
static meas::base::FlagDefinitionList const & getFlagDefinitions()
static meas::base::FlagDefinitionList const & getFlagDefinitions()
static meas::base::FlagDefinition const POS_FLAG
static meas::base::FlagDefinition const NEG_FLAG
ResultKey const & getNegativeKeys() const
static meas::base::FlagDefinition const FAILURE
ResultKey const & getPositiveKeys() const
Return the standard flux keys registered by this algorithm.
Class to minimize PsfDipoleFlux; this is the object that Minuit minimizes.
virtual double operator()(std::vector< double > const &params) const
MinimizeDipoleChi2(PsfDipoleFlux const &psfDipoleFlux, afw::table::SourceRecord &source, afw::image::Exposure< float > const &exposure)
ResultKey const & getNegativeKeys() const
NaiveDipoleCentroid(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
ResultKey const & getCenterKeys() const
Return the standard centroid keys registered by this algorithm.
ResultKey const & getPositiveKeys() const
void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
Given an image and a pixel position, return a Centroid using a naive 3x3 weighted moment.
void mergeCentroids(afw::table::SourceRecord &source, double posValue, double negValue) const
void fail(afw::table::SourceRecord &measRecord, meas::base::MeasurementError *error=NULL) const
void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
Given an image and a pixel position, return a Centroid using a naive 3x3 weighted moment.
void fail(afw::table::SourceRecord &measRecord, meas::base::MeasurementError *error=NULL) const
float stepSizeCoord
"Default initial step size for coordinates in non-linear fitter" ;
double errorDef
"How many sigma the error bars of the non-linear fitter represent" ;
float stepSizeFlux
"Default initial step size for flux in non-linear fitter" ;
int maxFnCalls
"Maximum function calls for non-linear fitter; 0 = unlimited" ;
Implementation of Psf dipole flux.
std::pair< double, int > chi2(afw::table::SourceRecord &source, afw::image::Exposure< float > const &exposure, double negCenterX, double negCenterY, double negFlux, double posCenterX, double poCenterY, double posFlux) const
void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
void fail(afw::table::SourceRecord &measRecord, meas::base::MeasurementError *error=NULL) const
afw::table::Key< CentroidElement > getY() const
afw::table::Key< CentroidElement > getX() const
void handleFailure(afw::table::BaseRecord &record, MeasurementError const *error=nullptr) const
bool isValid
T isfinite(T... args)
T max(T... args)
T min(T... args)
const char * source()
def keys(self)
afw::table::CatalogT< PeakRecord > PeakCatalog
double indexToPosition(double ind)
int const NEGFLUXPAR(2)
int const NEGCENTXPAR(0)
int const NEGCENTYPAR(1)
int const POSFLUXPAR(5)
int const POSCENTXPAR(3)
int const POSCENTYPAR(4)
Key< int > psf
table::Schema schema