27 #include "boost/tuple/tuple.hpp" 
   43 FlagDefinitionList flagDefinitions;
 
   48         flagDefinitions.add(
"flag_unweightedBad", 
"Both weighted and unweighted moments were invalid");
 
   50         "flag_unweighted", 
"Weighted moments converged to an invalid value; using unweighted moments");
 
   52         flagDefinitions.add(
"flag_shift", 
"centroid shifted by more than the maximum allowed amount");
 
   54         flagDefinitions.add(
"flag_maxIter", 
"Too many iterations in adaptive moments");
 
   56         flagDefinitions.add(
"flag_psf", 
"Failure in measuring PSF model shape");
 
   62 typedef Eigen::Matrix<double, 4, 4, Eigen::DontAlign> Matrix4d;
 
   72     double const Mxx = 
result.xx;  
 
   73     double const Mxy = 
result.xy;  
 
   74     double const Myy = 
result.yy;  
 
   76     double const Muu_p_Mvv = Mxx + Myy;                                        
 
   77     double const Muu_m_Mvv = ::sqrt(::pow(Mxx - Myy, 2) + 4 * ::pow(Mxy, 2));  
 
   78     double const Muu = 0.5 * (Muu_p_Mvv + Muu_m_Mvv);
 
   79     double const Mvv = 0.5 * (Muu_p_Mvv - Muu_m_Mvv);
 
   96 Matrix4d calc_fisher(SdssShapeResult 
const &shape,  
 
   99     float const A = shape.instFlux;  
 
  100     float const sigma11W = shape.xx;
 
  101     float const sigma12W = shape.xy;
 
  102     float const sigma22W = shape.yy;
 
  104     double const D = sigma11W * sigma22W - sigma12W * sigma12W;
 
  112     if (bkgd_var <= 0.0) {
 
  114                           (
boost::format(
"Background variance must be positive (saw %g)") % bkgd_var).str());
 
  116     double const F = 
geom::PI * sqrt(D) / bkgd_var;
 
  122     double fac = F * A / (4.0 * D);
 
  124     fisher(0, 1) = fac * sigma22W;
 
  125     fisher(1, 0) = fisher(0, 1);
 
  126     fisher(0, 2) = fac * sigma11W;
 
  127     fisher(2, 0) = fisher(0, 2);
 
  128     fisher(0, 3) = -fac * 2 * sigma12W;
 
  129     fisher(3, 0) = fisher(0, 3);
 
  131     fac = 3.0 * F * A * A / (16.0 * D * D);
 
  132     fisher(1, 1) = fac * sigma22W * sigma22W;
 
  133     fisher(2, 2) = fac * sigma11W * sigma11W;
 
  134     fisher(3, 3) = fac * 4.0 * (sigma12W * sigma12W + D / 3.0);
 
  136     fisher(1, 2) = fisher(3, 3) / 4.0;
 
  137     fisher(2, 1) = fisher(1, 2);
 
  138     fisher(1, 3) = fac * (-2 * sigma22W * sigma12W);
 
  139     fisher(3, 1) = fisher(1, 3);
 
  140     fisher(2, 3) = fac * (-2 * sigma11W * sigma12W);
 
  141     fisher(3, 2) = fisher(2, 3);
 
  148 template <
typename ImageT>  
 
  149 struct ImageAdaptor {
 
  150     typedef ImageT Image;
 
  152     static bool const hasVariance = 
false;
 
  154     Image 
const &getImage(ImageT 
const &
image)
 const { 
return image; }
 
  159 template <
typename T>  
 
  163     static bool const hasVariance = 
true;
 
  165     Image 
const &getImage(afw::image::MaskedImage<T> 
const &mimage)
 const { 
return *mimage.getImage(); }
 
  167     double getVariance(afw::image::MaskedImage<T> 
const &mimage, 
int ix, 
int iy) {
 
  168         return mimage.at(ix, iy).variance();
 
  179     double const det = sigma11 * sigma22 - sigma12 * sigma12;              
 
  187 bool shouldInterp(
double sigma11, 
double sigma22, 
double det) {
 
  188     float const xinterp = 0.25;  
 
  189     return (sigma11 < xinterp || sigma22 < xinterp || 
det < xinterp * xinterp);
 
  200                                        double maxRadius = 1000       
 
  213 template <
bool instFluxOnly, 
typename ImageT>
 
  214 static int calcmom(ImageT 
const &
image,                             
 
  215                    float xcen, 
float ycen,                          
 
  219                    double w11, 
double w12, 
double w22,              
 
  222                    double *psumx, 
double *psumy,                    
 
  223                    double *psumxx, 
double *psumxy, 
double *psumyy,  
 
  225                    bool negative = 
false) {
 
  230     double sum, sumx, sumy, sumxx, sumyy, sumxy, sums4;
 
  231 #define RECALC_W 0  // estimate sigmaXX_w within BBox? 
  233     double wsum, wsumxx, wsumxy, wsumyy;
 
  235     wsum = wsumxx = wsumxy = wsumyy = 0;
 
  239     if (
fabs(w11) > 1e6 || 
fabs(w12) > 1e6 || 
fabs(w22) > 1e6) {
 
  243     sum = sumx = sumy = sumxx = sumxy = sumyy = sums4 = 0;
 
  245     int const ix0 = 
bbox.getMinX();  
 
  246     int const ix1 = 
bbox.getMaxX();
 
  247     int const iy0 = 
bbox.getMinY();  
 
  248     int const iy1 = 
bbox.getMaxY();
 
  250     if (ix0 < 0 || ix1 >= 
image.getWidth() || iy0 < 0 || iy1 >= 
image.getHeight()) {
 
  254     for (
int i = iy0; i <= iy1; ++i) {
 
  255         typename ImageT::x_iterator 
ptr = 
image.x_at(ix0, i);
 
  256         float const y = i - ycen;
 
  257         float const y2 = 
y * 
y;
 
  258         float const yl = 
y - 0.375;
 
  259         float const yh = 
y + 0.375;
 
  260         for (
int j = ix0; j <= ix1; ++j, ++
ptr) {
 
  263                 float const xl = 
x - 0.375;
 
  264                 float const xh = 
x + 0.375;
 
  266                 float expon = xl * xl * w11 + yl * yl * w22 + 2.0 * xl * yl * w12;
 
  267                 tmp = xh * xh * w11 + yh * yh * w22 + 2.0 * xh * yh * w12;
 
  268                 expon = (expon > tmp) ? expon : tmp;
 
  269                 tmp = xl * xl * w11 + yh * yh * w22 + 2.0 * xl * yh * w12;
 
  270                 expon = (expon > tmp) ? expon : tmp;
 
  271                 tmp = xh * xh * w11 + yl * yl * w22 + 2.0 * xh * yl * w12;
 
  272                 expon = (expon > tmp) ? expon : tmp;
 
  276                     for (
Y = yl; 
Y <= yh; 
Y += 0.25) {
 
  277                         double const interpY2 = 
Y * 
Y;
 
  278                         for (
X = xl; 
X <= xh; 
X += 0.25) {
 
  279                             double const interpX2 = 
X * 
X;
 
  280                             double const interpXy = 
X * 
Y;
 
  281                             expon = interpX2 * w11 + 2 * interpXy * w12 + interpY2 * w22;
 
  287                                 sumx += ymod * (
X + xcen);
 
  288                                 sumy += ymod * (
Y + ycen);
 
  304                                 sumxx += interpX2 * ymod;
 
  305                                 sumxy += interpXy * ymod;
 
  306                                 sumyy += interpY2 * ymod;
 
  308                                 sums4 += expon * expon * ymod;
 
  316                 float expon = x2 * w11 + 2 * xy * w12 + y2 * w22;
 
  345                         sums4 += expon * expon * ymod;
 
  353     double const detW = std::get<1>(weights) * std::get<3>(weights) - 
std::pow(std::get<2>(weights), 2);
 
  364         if (psums4 != NULL) {
 
  370     if (wsum > 0 && !instFluxOnly) {
 
  371         double det = w11 * w22 - w12 * w12;
 
  375         printf(
"%g %g %g  %g %g %g\n", w22 / 
det, -w12 / 
det, w11 / 
det, wsumxx, wsumxy, wsumyy);
 
  380         return (instFluxOnly || (sum < 0 && sumxx < 0 && sumyy < 0)) ? 0 : -1;
 
  382         return (instFluxOnly || (sum > 0 && sumxx > 0 && sumyy > 0)) ? 0 : -1;
 
  391 template <
typename ImageT>
 
  392 bool getAdaptiveMoments(ImageT 
const &mimage, 
double bkgd, 
double xcen, 
double ycen, 
double shiftmax,
 
  393                         SdssShapeResult *shape, 
int maxIter, 
float tol1, 
float tol2, 
bool negative) {
 
  397     double sumxx, sumxy, sumyy;  
 
  399     float const xcen0 = xcen;    
 
  400     float const ycen0 = ycen;    
 
  402     double sigma11W = 1.5;  
 
  403     double sigma12W = 0.0;  
 
  404     double sigma22W = 1.5;  
 
  406     double w11 = -1, w12 = -1, w22 = -1;  
 
  407     float e1_old = 1e6, e2_old = 1e6;     
 
  408     float sigma11_ow_old = 1e6;           
 
  410     typename ImageAdaptor<ImageT>::Image 
const &
image = ImageAdaptor<ImageT>().getImage(mimage);
 
  418     bool interpflag = 
false;  
 
  423                                           sigma11W, sigma12W, sigma22W);
 
  425                 getWeights(sigma11W, sigma12W, sigma22W);
 
  426         if (!std::get<0>(weights).
first) {
 
  431         double const detW = std::get<0>(weights).second;
 
  433 #if 0  // this form was numerically unstable on my G4 powerbook 
  440             const double ow11 = w11;  
 
  441             const double ow12 = w12;  
 
  442             const double ow22 = w22;  
 
  444             w11 = std::get<1>(weights);
 
  445             w12 = std::get<2>(weights);
 
  446             w22 = std::get<3>(weights);
 
  448             if (shouldInterp(sigma11W, sigma22W, detW)) {
 
  452                         sigma11_ow_old = 1.e6;  
 
  462         if (calcmom<false>(
image, xcen, ycen, 
bbox, bkgd, interpflag, w11, w12, w22, &I0, &sum, &sumx, &sumy,
 
  463                            &sumxx, &sumxy, &sumyy, &sums4, negative) < 0) {
 
  477         shape->x = sumx / sum;  
 
  478         shape->y = sumy / sum;
 
  480         if (
fabs(shape->x - xcen0) > shiftmax || 
fabs(shape->y - ycen0) > shiftmax) {
 
  486         float const sigma11_ow = sumxx / sum;  
 
  487         float const sigma22_ow = sumyy / sum;  
 
  488         float const sigma12_ow = sumxy / sum;  
 
  490         if (sigma11_ow <= 0 || sigma22_ow <= 0) {
 
  495         float const d = sigma11_ow + sigma22_ow;  
 
  496         float const e1 = (sigma11_ow - sigma22_ow) / d;
 
  497         float const e2 = 2.0 * sigma12_ow / d;
 
  501         if (
iter > 0 && 
fabs(e1 - e1_old) < tol1 && 
fabs(e2 - e2_old) < tol1 &&
 
  502             fabs(sigma11_ow / sigma11_ow_old - 1.0) < tol2) {
 
  508         sigma11_ow_old = sigma11_ow;
 
  533             float ow11, ow12, ow22;  
 
  536                     getWeights(sigma11_ow, sigma12_ow, sigma22_ow);
 
  537             if (!std::get<0>(weights).
first) {
 
  542             ow11 = std::get<1>(weights);
 
  543             ow12 = std::get<2>(weights);
 
  544             ow22 = std::get<3>(weights);
 
  550             weights = getWeights(n11, n12, n22);
 
  551             if (!std::get<0>(weights).
first) {
 
  557             sigma11W = std::get<1>(weights);
 
  558             sigma12W = std::get<2>(weights);
 
  559             sigma22W = std::get<3>(weights);
 
  562         if (sigma11W <= 0 || sigma22W <= 0) {
 
  568     if (
iter == maxIter) {
 
  573     if (sumxx + sumyy == 0.0) {
 
  581         if (calcmom<false>(
image, xcen, ycen, 
bbox, bkgd, interpflag, w11, w12, w22, &I0, &sum, &sumx, &sumy,
 
  582                            &sumxx, &sumxy, &sumyy, NULL, negative) < 0 ||
 
  583             (!negative && sum <= 0) || (negative && sum >= 0)) {
 
  588                 shape->xx = 1 / 12.0;  
 
  590                 shape->yy = 1 / 12.0;
 
  596         sigma11W = sumxx / sum;  
 
  597         sigma12W = sumxy / sum;  
 
  598         sigma22W = sumyy / sum;  
 
  601     shape->instFlux = I0;
 
  602     shape->xx = sigma11W;
 
  603     shape->xy = sigma12W;
 
  604     shape->yy = sigma22W;
 
  606     if (shape->xx + shape->yy != 0.0) {
 
  610         if (ix >= 0 && ix < mimage.getWidth() && iy >= 0 && iy < mimage.getHeight()) {
 
  611             float const bkgd_var = ImageAdaptor<ImageT>().getVariance(
 
  614             if (bkgd_var > 0.0) {  
 
  616                     Matrix4d fisher = calc_fisher(*shape, bkgd_var);  
 
  617                     Matrix4d cov = fisher.inverse();
 
  621                     shape->instFluxErr = 
std::sqrt(cov(0, 0));
 
  625                     shape->instFlux_xx_Cov = cov(0, 1);
 
  626                     shape->instFlux_xy_Cov = cov(0, 2);
 
  627                     shape->instFlux_yy_Cov = cov(0, 3);
 
  628                     shape->xx_yy_Cov = cov(1, 3);
 
  629                     shape->xx_xy_Cov = cov(1, 2);
 
  630                     shape->yy_xy_Cov = cov(2, 3);
 
  642         : instFlux_xx_Cov(
std::numeric_limits<
ErrElement>::quiet_NaN()),
 
  643           instFlux_yy_Cov(
std::numeric_limits<
ErrElement>::quiet_NaN()),
 
  644           instFlux_xy_Cov(
std::numeric_limits<
ErrElement>::quiet_NaN()) {}
 
  657         r._includePsf = 
true;
 
  659                 schema, 
schema.join(
name, 
"psf"), 
"adaptive moments of the PSF model at the object position");
 
  661         r._includePsf = 
false;
 
  697           _instFlux_xx_Cov(s[
"instFlux"][
"xx"][
"Cov"]),
 
  698           _instFlux_yy_Cov(s[
"instFlux"][
"yy"][
"Cov"]),
 
  699           _instFlux_xy_Cov(s[
"instFlux"][
"xy"][
"Cov"]) {
 
  717     result.instFlux_xx_Cov = record.
get(_instFlux_xx_Cov);
 
  718     result.instFlux_yy_Cov = record.
get(_instFlux_yy_Cov);
 
  719     result.instFlux_xy_Cov = record.
get(_instFlux_xy_Cov);
 
  728     return record.
get(_psfShapeResult);
 
  732     record.
set(_shapeResult, value);
 
  733     record.
set(_centroidResult, value);
 
  734     record.
set(_instFluxResult, value);
 
  746     record.
set(_psfShapeResult, value);
 
  750     return _shapeResult == 
other._shapeResult && _centroidResult == 
other._centroidResult &&
 
  751            _instFluxResult == 
other._instFluxResult && _psfShapeResult == 
other._psfShapeResult &&
 
  752            _instFlux_xx_Cov == 
other._instFlux_xx_Cov && _instFlux_yy_Cov == 
other._instFlux_yy_Cov &&
 
  753            _instFlux_xy_Cov == 
other._instFlux_xy_Cov;
 
  770 template <
typename ImageT>
 
  772                                                            bool negative, 
Control const &control) {
 
  773     double xcen = center.getX();  
 
  774     double ycen = center.getY();  
 
  776     xcen -= 
image.getX0();  
 
  777     ycen -= 
image.getY0();
 
  782     } 
else if (shiftmax > 10) {
 
  790                                     control.
tol1, control.
tol2, negative);
 
  799     if (
result.getQuadrupole().getIxx() * 
result.getQuadrupole().getIyy() <
 
  800         (1.0 + 1.0e-6) * 
result.getQuadrupole().getIxy() * 
result.getQuadrupole().getIxy())
 
  807                               "Should not get singular moments unless a flag is set");
 
  814     double instFluxScale = computeFluxScale(
result);
 
  816     result.instFlux *= instFluxScale;
 
  817     result.instFluxErr *= instFluxScale;
 
  821     if (ImageAdaptor<ImageT>::hasVariance) {
 
  822         result.instFlux_xx_Cov *= instFluxScale;
 
  823         result.instFlux_yy_Cov *= instFluxScale;
 
  824         result.instFlux_xy_Cov *= instFluxScale;
 
  830 template <
typename ImageT>
 
  845     if (!std::get<0>(weights).
first) {
 
  849     double const w11 = std::get<1>(weights);
 
  850     double const w12 = std::get<2>(weights);
 
  851     double const w22 = std::get<3>(weights);
 
  852     bool const interp = shouldInterp(shape.
getIxx(), shape.
getIyy(), std::get<0>(weights).second);
 
  855     if (calcmom<true>(ImageAdaptor<ImageT>().getImage(
image), localCenter.getX(), localCenter.getY(), 
bbox,
 
  856                       0.0, interp, w11, w12, w22, &i0, NULL, NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
 
  862     result.instFlux = i0 * 2 * wArea;
 
  864     if (ImageAdaptor<ImageT>::hasVariance) {
 
  865         int ix = 
static_cast<int>(center.getX() - 
image.getX0());
 
  866         int iy = 
static_cast<int>(center.getY() - 
image.getY0());
 
  869                               (
boost::format(
"Center (%d,%d) not in image (%dx%d)") % ix % iy %
 
  873         double var = ImageAdaptor<ImageT>().getVariance(
image, ix, iy);
 
  875         result.instFluxErr = i0Err * 2 * wArea;
 
  883     bool negative = 
false;
 
  886         negative = measRecord.
get(measRecord.
getSchema().
find<afw::table::Flag>(
"flags_negative").key);
 
  920 #define INSTANTIATE_IMAGE(IMAGE)                                          \ 
  921     template SdssShapeResult SdssShapeAlgorithm::computeAdaptiveMoments(  \ 
  922             IMAGE const &, geom::Point2D const &, bool, Control const &); \ 
  923     template FluxResult SdssShapeAlgorithm::computeFixedMomentsFlux(      \ 
  924             IMAGE const &, afw::geom::ellipses::Quadrupole const &, geom::Point2D const &) 
  926 #define INSTANTIATE_PIXEL(PIXEL)                 \ 
  927     INSTANTIATE_IMAGE(afw::image::Image<PIXEL>); \ 
  928     INSTANTIATE_IMAGE(afw::image::MaskedImage<PIXEL>); 
  938     _transformPsf = 
mapper.getInputSchema().getNames().count(
"sdssShape_flag_psf") ? true : 
false;
 
  944         if (
mapper.getInputSchema().getNames().count(
mapper.getInputSchema().join(
name, flag.name)) == 0)
 
  947                 mapper.getInputSchema().find<afw::table::Flag>(
name + 
"_" + flag.name).
key;
 
  955                                                                "PSF shape in celestial moments",
 
  965     _instFluxTransform(inputCatalog, outputCatalog, 
wcs, 
photoCalib);
 
  966     _centroidTransform(inputCatalog, outputCatalog, 
wcs, 
photoCalib);
 
  973                 inputCatalog.getSchema()[inputCatalog.getSchema().join(
_name, 
"psf")]);
 
  978     for (; inSrc != inputCatalog.end(); ++inSrc, ++outSrc) {
 
  991         _outShapeKey.
set(*outSrc, outShape);