27 #include "boost/tuple/tuple.hpp"
29 #include "lsst/afw/image.h"
30 #include "lsst/afw/detection/Psf.h"
31 #include "lsst/afw/geom/Angle.h"
32 #include "lsst/afw/geom/ellipses.h"
33 #include "lsst/afw/table/Source.h"
38 namespace pexPolicy = lsst::pex::policy;
39 namespace pexExceptions = lsst::pex::exceptions;
40 namespace afwDet = lsst::afw::detection;
41 namespace afwImage = lsst::afw::image;
42 namespace afwGeom = lsst::afw::geom;
43 namespace afwTable = lsst::afw::table;
45 namespace lsst {
namespace meas {
namespace base {
47 FlagDefinitionList flagDefinitions;
52 FlagDefinition
const SdssShapeAlgorithm::UNWEIGHTED = flagDefinitions.add(
"flag_unweighted",
"Weighted moments converged to an invalid value; using unweighted moments");
53 FlagDefinition
const SdssShapeAlgorithm::SHIFT = flagDefinitions.add(
"flag_shift",
"centroid shifted by more than the maximum allowed amount");
58 return flagDefinitions;
64 typedef Eigen::Matrix<double,4,4,Eigen::DontAlign> Matrix4d;
74 double const Mxx = result.
xx;
75 double const Mxy = result.
xy;
76 double const Myy = result.
yy;
78 double const Muu_p_Mvv = Mxx + Myy;
79 double const Muu_m_Mvv = ::sqrt(::pow(Mxx - Myy, 2) + 4*::pow(Mxy, 2));
80 double const Muu = 0.5*(Muu_p_Mvv + Muu_m_Mvv);
81 double const Mvv = 0.5*(Muu_p_Mvv - Muu_m_Mvv);
83 return lsst::afw::geom::TWOPI * ::sqrt(Muu*Mvv);
99 calc_fisher(SdssShapeResult
const& shape,
102 float const A = shape.flux;
103 float const sigma11W = shape.xx;
104 float const sigma12W = shape.xy;
105 float const sigma22W = shape.yy;
107 double const D = sigma11W*sigma22W - sigma12W*sigma12W;
109 if (D <= std::numeric_limits<double>::epsilon()) {
110 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
111 "Determinant is too small calculating Fisher matrix");
116 if (bkgd_var <= 0.0) {
117 throw LSST_EXCEPT(lsst::pex::exceptions::DomainError,
118 (boost::format(
"Background variance must be positive (saw %g)") % bkgd_var).str());
120 double const F = afwGeom::PI*sqrt(D)/bkgd_var;
126 double fac = F*A/(4.0*D);
128 fisher(0, 1) = fac*sigma22W;
129 fisher(1, 0) = fisher(0, 1);
130 fisher(0, 2) = fac*sigma11W;
131 fisher(2, 0) = fisher(0, 2);
132 fisher(0, 3) = -fac*2*sigma12W;
133 fisher(3, 0) = fisher(0, 3);
135 fac = 3.0*F*A*A/(16.0*D*D);
136 fisher(1, 1) = fac*sigma22W*sigma22W;
137 fisher(2, 2) = fac*sigma11W*sigma11W;
138 fisher(3, 3) = fac*4.0*(sigma12W*sigma12W + D/3.0);
140 fisher(1, 2) = fisher(3, 3)/4.0;
141 fisher(2, 1) = fisher(1, 2);
142 fisher(1, 3) = fac*(-2*sigma22W*sigma12W);
143 fisher(3, 1) = fisher(1, 3);
144 fisher(2, 3) = fac*(-2*sigma11W*sigma12W);
145 fisher(3, 2) = fisher(2, 3);
152 template<
typename ImageT>
153 struct ImageAdaptor {
154 typedef ImageT Image;
156 static bool const hasVariance =
false;
158 Image
const& getImage(ImageT
const& image)
const {
162 double getVariance(ImageT
const&,
int,
int) {
163 return std::numeric_limits<double>::quiet_NaN();
168 struct ImageAdaptor<afwImage::MaskedImage<T> > {
169 typedef typename afwImage::MaskedImage<T>::Image Image;
171 static bool const hasVariance =
true;
173 Image
const& getImage(afwImage::MaskedImage<T>
const& mimage)
const {
174 return *mimage.getImage();
177 double getVariance(afwImage::MaskedImage<T>
const& mimage,
int ix,
int iy) {
178 return mimage.at(ix, iy).variance();
183 std::tuple<std::pair<bool, double>, double, double,
double>
184 getWeights(
double sigma11,
double sigma12,
double sigma22) {
185 double const NaN = std::numeric_limits<double>::quiet_NaN();
186 if (std::isnan(sigma11) || std::isnan(sigma12) || std::isnan(sigma22)) {
187 return std::make_tuple(std::make_pair(
false, NaN), NaN, NaN, NaN);
189 double const det = sigma11*sigma22 - sigma12*sigma12;
190 if (std::isnan(det) || det < std::numeric_limits<float>::epsilon()) {
191 return std::make_tuple(std::make_pair(
false, det), NaN, NaN, NaN);
193 return std::make_tuple(std::make_pair(
true, det), sigma22/det, -sigma12/det, sigma11/det);
197 bool shouldInterp(
double sigma11,
double sigma22,
double det) {
198 float const xinterp = 0.25;
199 return (sigma11 < xinterp || sigma22 < xinterp || det < xinterp*xinterp);
205 afw::geom::Box2I computeAdaptiveMomentsBBox(
206 afw::geom::Box2I
const & bbox,
207 afw::geom::Point2D
const & center,
211 double maxRadius = 1000
213 double radius = std::min(4*std::sqrt(std::max(sigma11_w, sigma22_w)), maxRadius);
214 afw::geom::Extent2D offset(radius, radius);
215 afw::geom::Box2I result(afw::geom::Box2D(center - offset, center + offset));
224 template<
bool fluxOnly,
typename ImageT>
226 calcmom(ImageT
const& image,
227 float xcen,
float ycen,
228 lsst::afw::geom::BoxI bbox,
231 double w11,
double w12,
double w22,
234 double *psumx,
double *psumy,
235 double *psumxx,
double *psumxy,
double *psumyy,
237 bool negative =
false
245 double sum, sumx, sumy, sumxx, sumyy, sumxy, sums4;
246 #define RECALC_W 0 // estimate sigmaXX_w within BBox?
248 double wsum, wsumxx, wsumxy, wsumyy;
250 wsum = wsumxx = wsumxy = wsumyy = 0;
254 if (fabs(w11) > 1e6 || fabs(w12) > 1e6 || fabs(w22) > 1e6) {
258 sum = sumx = sumy = sumxx = sumxy = sumyy = sums4 = 0;
260 int const ix0 = bbox.getMinX();
261 int const ix1 = bbox.getMaxX();
262 int const iy0 = bbox.getMinY();
263 int const iy1 = bbox.getMaxY();
265 if (ix0 < 0 || ix1 >= image.getWidth() || iy0 < 0 || iy1 >= image.getHeight()) {
269 for (
int i = iy0; i <= iy1; ++i) {
270 typename ImageT::x_iterator ptr = image.x_at(ix0, i);
271 float const y = i - ycen;
272 float const y2 = y*
y;
273 float const yl = y - 0.375;
274 float const yh = y + 0.375;
275 for (
int j = ix0; j <= ix1; ++j, ++ptr) {
278 float const xl = x - 0.375;
279 float const xh = x + 0.375;
281 float expon = xl*xl*w11 + yl*yl*w22 + 2.0*xl*yl*w12;
282 tmp = xh*xh*w11 + yh*yh*w22 + 2.0*xh*yh*w12;
283 expon = (expon > tmp) ? expon : tmp;
284 tmp = xl*xl*w11 + yh*yh*w22 + 2.0*xl*yh*w12;
285 expon = (expon > tmp) ? expon : tmp;
286 tmp = xh*xh*w11 + yl*yl*w22 + 2.0*xh*yl*w12;
287 expon = (expon > tmp) ? expon : tmp;
291 for (Y = yl; Y <= yh; Y += 0.25) {
292 double const interpY2 = Y*Y;
293 for (X = xl; X <= xh; X += 0.25) {
294 double const interpX2 = X*X;
295 double const interpXy = X*Y;
296 expon = interpX2*w11 + 2*interpXy*w12 + interpY2*w22;
297 weight = std::exp(-0.5*expon);
302 sumx += ymod*(X + xcen);
303 sumy += ymod*(Y + ycen);
307 tmp = interpX2*weight;
311 tmp = interpXy*weight;
315 tmp = interpY2*weight;
319 sumxx += interpX2*ymod;
320 sumxy += interpXy*ymod;
321 sumyy += interpY2*ymod;
323 sums4 += expon*expon*ymod;
331 float expon = x2*w11 + 2*xy*w12 + y2*w22;
334 weight = std::exp(-0.5*expon);
360 sums4 += expon*expon*ymod;
368 std::tuple<std::pair<bool, double>, double, double,
double>
const weights = getWeights(w11, w12, w22);
369 double const detW = std::get<1>(weights)*std::get<3>(weights) - std::pow(std::get<2>(weights), 2);
370 *pI0 = sum/(afwGeom::PI*sqrt(detW));
380 if (psums4 != NULL) {
386 if (wsum > 0 && !fluxOnly) {
387 double det = w11*w22 - w12*w12;
391 printf(
"%g %g %g %g %g %g\n", w22/det, -w12/det, w11/det, wsumxx, wsumxy, wsumyy);
396 return (fluxOnly || (sum < 0 && sumxx < 0 && sumyy < 0)) ? 0 : -1;
398 return (fluxOnly || (sum > 0 && sumxx > 0 && sumyy > 0)) ? 0 : -1;
407 template<
typename ImageT>
408 bool getAdaptiveMoments(ImageT
const& mimage,
double bkgd,
double xcen,
double ycen,
double shiftmax,
409 SdssShapeResult *shape,
int maxIter,
float tol1,
float tol2,
bool negative)
414 double sumxx, sumxy, sumyy;
416 float const xcen0 = xcen;
417 float const ycen0 = ycen;
419 double sigma11W = 1.5;
420 double sigma12W = 0.0;
421 double sigma22W = 1.5;
423 double w11 = -1, w12 = -1, w22 = -1;
424 float e1_old = 1e6, e2_old = 1e6;
425 float sigma11_ow_old = 1e6;
427 typename ImageAdaptor<ImageT>::Image
const &image = ImageAdaptor<ImageT>().getImage(mimage);
429 if (std::isnan(xcen) || std::isnan(ycen)) {
435 bool interpflag =
false;
436 lsst::afw::geom::BoxI bbox;
438 for (; iter < maxIter; iter++) {
439 bbox = computeAdaptiveMomentsBBox(image.getBBox(afw::image::LOCAL), afw::geom::Point2D(xcen, ycen),
440 sigma11W, sigma12W, sigma22W);
441 std::tuple<std::pair<bool, double>, double, double,
double> weights =
442 getWeights(sigma11W, sigma12W, sigma22W);
443 if (!std::get<0>(weights).first) {
448 double const detW = std::get<0>(weights).second;
450 #if 0 // this form was numerically unstable on my G4 powerbook
453 assert(sigma11W*sigma22W >= sigma12W*sigma12W - std::numeric_limits<float>::epsilon());
457 const double ow11 = w11;
458 const double ow12 = w12;
459 const double ow22 = w22;
461 w11 = std::get<1>(weights);
462 w12 = std::get<2>(weights);
463 w22 = std::get<3>(weights);
465 if (shouldInterp(sigma11W, sigma22W, detW)) {
469 sigma11_ow_old = 1.e6;
479 if (calcmom<false>(image, xcen, ycen, bbox, bkgd, interpflag, w11, w12, w22,
480 &I0, &sum, &sumx, &sumy, &sumxx, &sumxy, &sumyy, &sums4, negative) < 0) {
497 if (fabs(shape->x - xcen0) > shiftmax || fabs(shape->y - ycen0) > shiftmax) {
503 float const sigma11_ow = sumxx/sum;
504 float const sigma22_ow = sumyy/sum;
505 float const sigma12_ow = sumxy/sum;
507 if (sigma11_ow <= 0 || sigma22_ow <= 0) {
512 float const d = sigma11_ow + sigma22_ow;
513 float const e1 = (sigma11_ow - sigma22_ow)/d;
514 float const e2 = 2.0*sigma12_ow/d;
519 fabs(e1 - e1_old) < tol1 && fabs(e2 - e2_old) < tol1 &&
520 fabs(sigma11_ow/sigma11_ow_old - 1.0) < tol2 ) {
526 sigma11_ow_old = sigma11_ow;
551 float ow11, ow12, ow22;
553 std::tuple<std::pair<bool, double>, double, double,
double> weights =
554 getWeights(sigma11_ow, sigma12_ow, sigma22_ow);
555 if (!std::get<0>(weights).first) {
560 ow11 = std::get<1>(weights);
561 ow12 = std::get<2>(weights);
562 ow22 = std::get<3>(weights);
568 weights = getWeights(n11, n12, n22);
569 if (!std::get<0>(weights).first) {
575 sigma11W = std::get<1>(weights);
576 sigma12W = std::get<2>(weights);
577 sigma22W = std::get<3>(weights);
580 if (sigma11W <= 0 || sigma22W <= 0) {
586 if (iter == maxIter) {
591 if (sumxx + sumyy == 0.0) {
599 if (calcmom<false>(image, xcen, ycen, bbox, bkgd, interpflag, w11, w12, w22,
600 &I0, &sum, &sumx, &sumy, &sumxx, &sumxy, &sumyy, NULL, negative) < 0 ||
601 (!negative && sum <= 0) || (negative && sum >= 0)) {
614 sigma11W = sumxx/sum;
615 sigma12W = sumxy/sum;
616 sigma22W = sumyy/sum;
620 shape->xx = sigma11W;
621 shape->xy = sigma12W;
622 shape->yy = sigma22W;
624 if (shape->xx + shape->yy != 0.0) {
625 int const ix = lsst::afw::image::positionToIndex(xcen);
626 int const iy = lsst::afw::image::positionToIndex(ycen);
628 if (ix >= 0 && ix < mimage.getWidth() && iy >= 0 && iy < mimage.getHeight()) {
629 float const bkgd_var =
630 ImageAdaptor<ImageT>().getVariance(mimage, ix, iy);
632 if (bkgd_var > 0.0) {
634 Matrix4d fisher = calc_fisher(*shape, bkgd_var);
635 Matrix4d cov = fisher.inverse();
639 shape->fluxSigma = std::sqrt(cov(0, 0));
640 shape->xxSigma = std::sqrt(cov(1, 1));
641 shape->xySigma = std::sqrt(cov(2, 2));
642 shape->yySigma = std::sqrt(cov(3, 3));
643 shape->flux_xx_Cov = cov(0, 1);
644 shape->flux_xy_Cov = cov(0, 2);
645 shape->flux_yy_Cov = cov(0, 3);
646 shape->xx_yy_Cov = cov(1, 3);
647 shape->xx_xy_Cov = cov(1, 2);
648 shape->yy_xy_Cov = cov(2, 3);
661 flux_xx_Cov(std::numeric_limits<
ErrElement>::quiet_NaN()),
662 flux_yy_Cov(std::numeric_limits<
ErrElement>::quiet_NaN()),
663 flux_xy_Cov(std::numeric_limits<
ErrElement>::quiet_NaN())
668 afw::table::Schema & schema,
669 std::string
const & name,
682 r._includePsf =
true;
683 r._psfShapeResult = afwTable::QuadrupoleKey::addFields(
684 schema, schema.join(name,
"psf"),
"adaptive moments of the PSF model at the object position");
686 r._includePsf =
false;
690 schema.join(name,
"flux",
"xx",
"Cov"),
691 (boost::format(
"uncertainty covariance between %s and %s")
692 % schema.join(name,
"flux") % schema.join(name,
"xx")).str(),
696 schema.join(name,
"flux",
"yy",
"Cov"),
697 (boost::format(
"uncertainty covariance between %s and %s")
698 % schema.join(name,
"flux") % schema.join(name,
"yy")).str(),
702 schema.join(name,
"flux",
"xy",
"Cov"),
703 (boost::format(
"uncertainty covariance between %s and %s")
704 % schema.join(name,
"flux") % schema.join(name,
"xy")).str(),
723 _flux_xx_Cov(s[
"flux"][
"xx"][
"Cov"]),
724 _flux_yy_Cov(s[
"flux"][
"yy"][
"Cov"]),
725 _flux_xy_Cov(s[
"flux"][
"xy"][
"Cov"])
729 _psfShapeResult = afwTable::QuadrupoleKey(s[
"psf"]);
732 }
catch (pex::exceptions::NotFoundError& e) {
740 static_cast<ShapeResult&
>(result) = record.get(_shapeResult);
741 static_cast<CentroidResult&
>(result) = record.get(_centroidResult);
742 static_cast<FluxResult&
>(result) = record.get(_fluxResult);
754 return record.get(_psfShapeResult);
758 record.set(_shapeResult, value);
759 record.set(_centroidResult, value);
760 record.set(_fluxResult, value);
771 afwGeom::ellipses::Quadrupole
const & value)
const {
772 record.set(_psfShapeResult, value);
776 return _shapeResult == other._shapeResult &&
777 _centroidResult == other._centroidResult &&
778 _fluxResult == other._fluxResult &&
779 _psfShapeResult == other._psfShapeResult &&
780 _flux_xx_Cov == other._flux_xx_Cov &&
781 _flux_yy_Cov == other._flux_yy_Cov &&
782 _flux_xy_Cov == other._flux_xy_Cov;
787 return _shapeResult.
isValid() &&
790 _psfShapeResult.isValid() &&
791 _flux_xx_Cov.isValid() &&
792 _flux_yy_Cov.isValid() &&
793 _flux_xy_Cov.isValid();
799 std::string
const & name,
800 afw::table::Schema & schema
803 _resultKey(
ResultKey::addFields(schema, name, ctrl.doMeasurePsf)),
807 template <
typename ImageT>
809 ImageT
const & image,
810 afw::geom::Point2D
const & center,
814 double xcen = center.getX();
815 double ycen = center.getY();
817 xcen -= image.getX0();
818 ycen -= image.getY0();
823 }
else if (shiftmax > 10) {
830 image, control.
background, xcen, ycen, shiftmax, &result,
833 }
catch (pex::exceptions::Exception & err) {
849 pex::exceptions::LogicError,
850 "Should not get singular moments unless a flag is set");
857 double fluxScale = computeFluxScale(result);
859 result.
flux *= fluxScale;
861 result.
x += image.getX0();
862 result.
y += image.getY0();
864 if (ImageAdaptor<ImageT>::hasVariance) {
873 template <
typename ImageT>
875 ImageT
const & image,
876 afw::geom::ellipses::Quadrupole
const & shape,
877 afw::geom::Point2D
const & center
880 afw::geom::Point2D localCenter = center - afw::geom::Extent2D(image.getXY0());
882 afwGeom::BoxI
const bbox = computeAdaptiveMomentsBBox(image.getBBox(afw::image::LOCAL),
884 shape.getIxx(), shape.getIxy(), shape.getIyy());
886 std::tuple<std::pair<bool, double>, double, double,
double> weights =
887 getWeights(shape.getIxx(), shape.getIxy(), shape.getIyy());
891 if (!std::get<0>(weights).first) {
892 throw pex::exceptions::InvalidParameterError(
"Input shape is singular");
895 double const w11 = std::get<1>(weights);
896 double const w12 = std::get<2>(weights);
897 double const w22 = std::get<3>(weights);
898 bool const interp = shouldInterp(shape.getIxx(), shape.getIyy(), std::get<0>(weights).second);
901 if (calcmom<true>(ImageAdaptor<ImageT>().getImage(image), localCenter.getX(), localCenter.getY(),
902 bbox, 0.0, interp, w11, w12, w22, &i0, NULL, NULL, NULL, NULL, NULL, NULL, NULL)< 0) {
903 throw LSST_EXCEPT(pex::exceptions::RuntimeError,
"Error from calcmom");
906 double const wArea = afw::geom::PI*std::sqrt(shape.getDeterminant());
908 result.flux = i0*2*wArea;
910 if (ImageAdaptor<ImageT>::hasVariance) {
911 int ix =
static_cast<int>(center.getX() - image.getX0());
912 int iy =
static_cast<int>(center.getY() - image.getY0());
913 if (!image.getBBox(afw::image::LOCAL).contains(afw::geom::Point2I(ix, iy))) {
914 throw LSST_EXCEPT(pex::exceptions::RuntimeError,
915 (boost::format(
"Center (%d,%d) not in image (%dx%d)") %
916 ix % iy % image.getWidth() % image.getHeight()).str());
918 double var = ImageAdaptor<ImageT>().getVariance(image, ix, iy);
919 double i0Err = std::sqrt(var/wArea);
920 result.fluxSigma = i0Err*2*wArea;
927 afw::table::SourceRecord & measRecord,
928 afw::image::Exposure<float>
const & exposure
930 bool negative =
false;
933 negative = measRecord.get(measRecord.getSchema().find<afw::table::Flag>(
"flags_negative").key);
934 }
catch(pexExcept::Exception &e) {
937 exposure.getMaskedImage(),
952 PTR(afw::detection::Psf
const) psf = exposure.getPsf();
956 _resultKey.
setPsfShape(measRecord, psf->computeShape(afw::geom::Point2D(result.
x, result.
y)));
958 }
catch (pex::exceptions::Exception & err) {
963 measRecord.set(_resultKey, result);
967 afw::table::SourceRecord & measRecord,
973 #define INSTANTIATE_IMAGE(IMAGE) \
974 template SdssShapeResult SdssShapeAlgorithm::computeAdaptiveMoments( \
976 afw::geom::Point2D const &, \
980 template FluxResult SdssShapeAlgorithm::computeFixedMomentsFlux( \
982 afw::geom::ellipses::Quadrupole const &, \
983 afw::geom::Point2D const & \
986 #define INSTANTIATE_PIXEL(PIXEL) \
987 INSTANTIATE_IMAGE(lsst::afw::image::Image<PIXEL>); \
988 INSTANTIATE_IMAGE(lsst::afw::image::MaskedImage<PIXEL>);
996 std::string
const & name,
997 afw::table::SchemaMapper & mapper
1000 _fluxTransform{name, mapper},
1001 _centroidTransform{name, mapper}
1004 _transformPsf = mapper.getInputSchema().getNames().count(
"sdssShape_flag_psf") ?
true :
false;
1010 if (mapper.getInputSchema().getNames().count(
1011 mapper.getInputSchema().join(name, flag.name)) == 0)
continue;
1012 afw::table::Key<afw::table::Flag> key = mapper.getInputSchema().find<afw::table::Flag>(
1013 name +
"_" + flag.name).key;
1014 mapper.addMapping(key);
1019 if (_transformPsf) {
1020 _outPsfShapeKey = afwTable::QuadrupoleKey::addFields(mapper.editOutputSchema(), name +
"_psf",
1021 "PSF shape in celestial moments",
1022 afw::table::CoordinateType::CELESTIAL);
1027 afw::table::SourceCatalog
const & inputCatalog,
1028 afw::table::BaseCatalog & outputCatalog,
1029 afw::image::Wcs
const & wcs,
1030 afw::image::Calib
const & calib
1034 _fluxTransform(inputCatalog, outputCatalog, wcs, calib);
1035 _centroidTransform(inputCatalog, outputCatalog, wcs, calib);
1039 afwTable::QuadrupoleKey inPsfShapeKey;
1040 if (_transformPsf) {
1041 inPsfShapeKey = afwTable::QuadrupoleKey(
1042 inputCatalog.getSchema()[inputCatalog.getSchema().join(
_name,
"psf")]);
1045 afw::table::SourceCatalog::const_iterator inSrc = inputCatalog.begin();
1046 afw::table::BaseCatalog::iterator outSrc = outputCatalog.begin();
1047 for (; inSrc != inputCatalog.end(); ++inSrc, ++outSrc) {
1052 afw::geom::AffineTransform crdTr = wcs.linearizePixelToSky(centroidKey.get(*inSrc).getCentroid(),
1053 afw::geom::radians);
1060 _outShapeKey.
set(*outSrc, outShape);
1062 if (_transformPsf) {
1063 _outPsfShapeKey.set(*outSrc, inPsfShapeKey.get(*inSrc).transform(crdTr.getLinear()));
#define INSTANTIATE_PIXEL(PIXEL)
bool doMeasurePsf
"Whether to also compute the shape of the PSF model" ;
static Result computeAdaptiveMoments(ImageT const &image, afw::geom::Point2D const &position, bool negative=false, Control const &ctrl=Control())
Compute the adaptive Gaussian-weighted moments of an image.
ShapeTrMatrix makeShapeTransformMatrix(afw::geom::LinearTransform const &xform)
Construct a matrix suitable for transforming second moments.
static FlagDefinitionList const & getFlagDefinitions()
virtual void setPsfShape(afw::table::BaseRecord &record, afw::geom::ellipses::Quadrupole const &value) const
Set a Quadrupole for the Psf at the position of the given record.
static FluxResult computeFixedMomentsFlux(ImageT const &image, afw::geom::ellipses::Quadrupole const &shape, afw::geom::Point2D const &position)
Compute the flux within a fixed Gaussian aperture.
float tol2
"Convergence tolerance for FWHM" ;
FlagHandler const & getFlagHandler() const
static FlagDefinition const SHIFT
bool getValue(afw::table::BaseRecord const &record, std::size_t i) const
Return the value of the flag field corresponding to the given flag index.
Only the diagonal elements of the covariance matrix are provided.
A reusable struct for centroid measurements.
afw::geom::ellipses::Quadrupole getQuadrupole()
double background
"Additional value to add to background" ;
The full covariance matrix is provided.
CentroidElement x
x (column) coordinate of the measured position
int maxIter
"Maximum number of iterations" ;
bool isValid() const
Return True if the centroid key is valid.
virtual void fail(afw::table::SourceRecord &measRecord, MeasurementError *error=nullptr) const
Handle an exception thrown by the current algorithm by setting flags in the given record...
Exception to be thrown when a measurement algorithm experiences a known failure mode.
static FlagDefinition const UNWEIGHTED
static FluxResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc)
Add a pair of _flux, _fluxSigma fields to a Schema, and return a FluxResultKey that points to them...
float tol1
"Convergence tolerance for e1,e2" ;
static FlagDefinition const UNWEIGHTED_BAD
double maxShift
"Maximum centroid shift, limited to 2-10" ;
bool isValid() const
Return True if the key is valid.
ErrElement flux_yy_Cov
flux, yy term in the uncertainty covariance matrix
bool operator==(SdssShapeResultKey const &other) const
Compare the FunctorKey for equality with another, using the underlying Keys.
Shape const getShape() const
Return an afw::geom::ellipses object corresponding to xx, yy, xy.
A FunctorKey for ShapeResult.
virtual void measure(afw::table::SourceRecord &measRecord, afw::image::Exposure< float > const &exposure) const
Called to measure a single child source in an image.
void setShapeErr(ShapeCov const &matrix)
Set the struct uncertainty elements from the given matrix, with rows and columns ordered (xx...
Utility class for handling flag fields that indicate the failure modes of an algorithm.
A reusable struct for moments-based shape measurements.
static unsigned int const N_FLAGS
virtual void set(afw::table::BaseRecord &record, ShapeResult const &value) const
Set a ShapeResult in the given record.
Result object SdssShapeAlgorithm.
SdssShapeResult()
Constructor; initializes everything to NaN.
bool isValid() const
Return True if both the flux and fluxSigma Keys are valid.
SdssShapeAlgorithm(Control const &ctrl, std::string const &name, afw::table::Schema &schema)
bool isValid() const
Return True if the shape key is valid.
virtual afw::geom::ellipses::Quadrupole getPsfShape(afw::table::BaseRecord const &record) const
Get a Quadrupole for the Psf from the given record.
_centroidExtractor(schema, name)
Flux flux
Measured flux in DN.
static CentroidResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc, UncertaintyEnum uncertainty)
Add the appropriate fields to a Schema, and return a CentroidResultKey that manages them...
A C++ control class to handle SdssShapeAlgorithm's configuration.
void setValue(afw::table::BaseRecord &record, std::size_t i, bool value) const
Set the flag field corresponding to the given flag index.
void handleFailure(afw::table::BaseRecord &record, MeasurementError const *error=nullptr) const
Handle an expected or unexpected Exception thrown by a measurement algorithm.
virtual void set(afw::table::BaseRecord &record, SdssShapeResult const &value) const
Set an SdssShapeResult in the given record.
static FlagHandler addFields(afw::table::Schema &schema, std::string const &prefix, FlagDefinitionList const &flagDefs, FlagDefinitionList const &exclDefs=FlagDefinitionList::getEmptyList())
Add Flag fields to a schema, creating a FlagHandler object to manage them.
std::bitset< SdssShapeAlgorithm::N_FLAGS > flags
Status flags (see SdssShapeAlgorithm).
virtual SdssShapeResult get(afw::table::BaseRecord const &record) const
Get an SdssShapeResult from the given record.
static FlagDefinition const MAXITER
static FlagDefinition const PSF_SHAPE_BAD
A FunctorKey that maps SdssShapeResult to afw::table Records.
Algorithm provides no uncertainy information at all.
static FlagDefinition const FAILURE
A FunctorKey for CentroidResult.
CentroidElement y
y (row) coordinate of the measured position
SdssShapeResultKey()
Default constructor; instance will not be usuable unless subsequently assigned to.
vector-type utility class to build a collection of FlagDefinitions
ErrElement flux_xx_Cov
flux, xx term in the uncertainty covariance matrix
void setShape(Shape const &shape)
Set struct elements from the given Quadrupole object.
FluxErrElement fluxSigma
1-Sigma error (sqrt of variance) on flux in DN.
std::size_t size() const
return the current size (number of defined elements) of the collection
Eigen::Matrix< ShapeElement, 3, 3, Eigen::DontAlign > ShapeTrMatrix
static SdssShapeResultKey addFields(afw::table::Schema &schema, std::string const &name, bool doMeasurePsf)
Add the appropriate fields to a Schema, and return a SdssShapeResultKey that manages them...
ShapeCov const getShapeErr() const
Return the 3x3 symmetric covariance matrix, with rows and columns ordered (xx, yy, xy)
A reusable result struct for flux measurements.
ErrElement flux_xy_Cov
flux, xy term in the uncertainty covariance matrix
static ShapeResultKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc, UncertaintyEnum uncertainty, afw::table::CoordinateType coordType=afw::table::CoordinateType::PIXEL)
Add the appropriate fields to a Schema, and return a ShapeResultKey that manages them.