IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Apr 4, 2011, 1:04:41 PM (15 years ago)
Author:
eugene
Message:

updates to pmPeak to better distinguish peak flux versions; updates to visualization; add bits for substantial suspect masking; consolidate assignment of source position and flux based on peak, moments, etc; improve footprint culling process; fix PSF_QF and PSF_QF_PERFECT calculations; fix source model chisq values

Location:
trunk/psModules
Files:
54 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/psModules

    • Property svn:ignore
      •  

        old new  
        2828ChangeLog
        2929psmodules-*.tar.*
         30a.out.dSYM
  • trunk/psModules/src/objects/Makefile.am

    r29004 r31153  
    3232        pmSourceFitSet.c \
    3333        pmSourcePhotometry.c \
     34        pmSourceOutputs.c \
    3435        pmSourceIO.c \
    3536        pmSourceIO_RAW.c \
     
    102103        pmSourceFitSet.h \
    103104        pmSourcePhotometry.h \
     105        pmSourceOutputs.h \
    104106        pmSourceIO.h \
    105107        pmSourcePlots.h \
  • trunk/psModules/src/objects/models/pmModel_DEV.c

    r29004 r31153  
    217217bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
    218218{
    219     pmMoments *moments = source->moments;
    220     pmPeak    *peak    = source->peak;
    221     psF32     *PAR  = model->params->data.F32;
    222 
    223     psEllipseMoments emoments;
    224     emoments.x2 = moments->Mxx;
    225     emoments.xy = moments->Mxy;
    226     emoments.y2 = moments->Myy;
    227 
    228     // force the axis ratio to be < 20.0
    229     psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
    230 
    231     if (!isfinite(axes.major)) return false;
    232     if (!isfinite(axes.minor)) return false;
    233     if (!isfinite(axes.theta)) return false;
    234 
    235     psEllipseShape shape = psEllipseAxesToShape (axes);
    236 
    237     if (!isfinite(shape.sx))  return false;
    238     if (!isfinite(shape.sy))  return false;
    239     if (!isfinite(shape.sxy)) return false;
    240 
    241     // the other parameters depend on the guess for PAR_7
     219    psF32 *PAR  = model->params->data.F32;
     220
     221    // sky is set to 0.0
     222    PAR[PM_PAR_SKY]  = 0.0;
     223
     224    // set the shape parameters
     225    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
     226      return false;
     227    }
     228
     229    // the normalization is modified by the slope
    242230    float index = 0.5 / ALPHA;
    243231    float bn = 1.9992*index - 0.3271;
    244     // float fR = 1.0 / (sqrt(2.0) * pow (bn, index));
    245232    float Io = exp(0.5*bn);
    246233
    247     float Sxx = PS_MAX(0.5, shape.sx);
    248     float Syy = PS_MAX(0.5, shape.sy);
    249 
    250     PAR[PM_PAR_SKY]  = 0.0;
    251     PAR[PM_PAR_I0]   = peak->flux / Io;
    252     PAR[PM_PAR_XPOS] = peak->xf;
    253     PAR[PM_PAR_YPOS] = peak->yf;
    254     // PAR[PM_PAR_SXX]  = Sxx * fR;
    255     // PAR[PM_PAR_SYY]  = Syy * fR;
    256     PAR[PM_PAR_SXX]  = Sxx;
    257     PAR[PM_PAR_SYY]  = Syy;
    258     PAR[PM_PAR_SXY]  = shape.sxy;
     234    // set the model normalization
     235    if (!pmModelSetNorm(&PAR[PM_PAR_I0], source)) {
     236      return false;
     237    }
     238    PAR[PM_PAR_I0] /= Io;
     239
     240    // set the model position
     241    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     242      return false;
     243    }
    259244
    260245    return(true);
     
    322307    psF64 radius = axes.major * sqrt (2.0) * pow(zn, 0.5 / ALPHA);
    323308
    324     psAssert (isfinite(radius), "fix this code: z should not be nan");
     309    psAssert (isfinite(radius), "fix this code: radius should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f)",
     310              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY]);
     311
    325312    return (radius);
    326313}
  • trunk/psModules/src/objects/models/pmModel_EXP.c

    r29004 r31153  
    210210bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
    211211{
    212     pmMoments *moments = source->moments;
    213     pmPeak    *peak    = source->peak;
    214     psF32     *PAR  = model->params->data.F32;
    215 
    216     psEllipseMoments emoments;
    217     emoments.x2 = moments->Mxx;
    218     emoments.xy = moments->Mxy;
    219     emoments.y2 = moments->Myy;
    220 
    221     // force the axis ratio to be < 20.0
    222     psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
    223 
    224     if (!isfinite(axes.major)) return false;
    225     if (!isfinite(axes.minor)) return false;
    226     if (!isfinite(axes.theta)) return false;
    227 
    228     psEllipseShape shape = psEllipseAxesToShape (axes);
    229 
    230     if (!isfinite(shape.sx))  return false;
    231     if (!isfinite(shape.sy))  return false;
    232     if (!isfinite(shape.sxy)) return false;
    233 
     212    psF32 *PAR  = model->params->data.F32;
     213
     214    // sky is set to 0.0
    234215    PAR[PM_PAR_SKY]  = 0.0;
    235     PAR[PM_PAR_I0]   = peak->flux;
    236     PAR[PM_PAR_XPOS] = peak->xf;
    237     PAR[PM_PAR_YPOS] = peak->yf;
    238     PAR[PM_PAR_SXX]  = PS_MAX(0.5, M_SQRT2*shape.sx);
    239     PAR[PM_PAR_SYY]  = PS_MAX(0.5, M_SQRT2*shape.sy);
    240     PAR[PM_PAR_SXY]  = shape.sxy;
     216
     217    // set the shape parameters
     218    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
     219      return false;
     220    }
     221
     222    // set the model normalization
     223    if (!pmModelSetNorm(&PAR[PM_PAR_I0], source)) {
     224      return false;
     225    }
     226
     227    // set the model position
     228    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     229      return false;
     230    }
     231
    241232    return(true);
    242233}
     
    303294    psF64 radius = axes.major * sqrt (2.0) * zn;
    304295
    305     psAssert (isfinite(radius), "fix this code: z should not be nan for %f", PAR[PM_PAR_7]);
     296    psAssert (isfinite(radius), "fix this code: radius should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f)",
     297              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY]);
    306298    return (radius);
    307299}
  • trunk/psModules/src/objects/models/pmModel_GAUSS.c

    r29004 r31153  
    193193bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
    194194{
    195     pmMoments *moments = source->moments;
    196     pmPeak    *peak    = source->peak;
    197     psF32     *PAR  = model->params->data.F32;
    198 
    199     psEllipseMoments emoments;
    200     emoments.x2 = moments->Mxx;
    201     emoments.y2 = moments->Myy;
    202     emoments.xy = moments->Mxy;
    203 
    204     // force the axis ratio to be < 20.0
    205     psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
    206     psEllipseShape shape = psEllipseAxesToShape (axes);
    207 
     195    psF32 *PAR  = model->params->data.F32;
     196
     197    // sky is set to 0.0
    208198    PAR[PM_PAR_SKY]  = 0.0;
    209     PAR[PM_PAR_I0]   = peak->flux;
    210     PAR[PM_PAR_XPOS] = peak->xf;
    211     PAR[PM_PAR_YPOS] = peak->yf;
    212     PAR[PM_PAR_SXX] = PS_MAX(0.5, M_SQRT2*shape.sx);
    213     PAR[PM_PAR_SYY] = PS_MAX(0.5, M_SQRT2*shape.sy);
    214     PAR[PM_PAR_SXY] = shape.sxy;
     199
     200    // set the shape parameters
     201    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
     202      return false;
     203    }
     204
     205    // set the model normalization
     206    if (!pmModelSetNorm(&PAR[PM_PAR_I0], source)) {
     207      return false;
     208    }
     209
     210    // set the model position
     211    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     212      return false;
     213    }
     214
    215215    return(true);
    216216}
     
    258258    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
    259259    psF64 radius = axes.major * sqrt (2.0 * log(PAR[PM_PAR_I0] / flux));
    260     psAssert (isfinite(radius), "fix this code: radius should not be nan for %f", PAR[PM_PAR_I0]);
     260    psAssert (isfinite(radius), "fix this code: radius should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f)",
     261              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY]);
    261262
    262263    return (radius);
  • trunk/psModules/src/objects/models/pmModel_PGAUSS.c

    r29004 r31153  
    194194bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
    195195{
    196     pmMoments *moments = source->moments;
    197     pmPeak    *peak    = source->peak;
    198     psF32     *PAR     = model->params->data.F32;
    199 
    200     psEllipseMoments emoments;
    201     emoments.x2 = moments->Mxx;
    202     emoments.xy = moments->Mxy;
    203     emoments.y2 = moments->Myy;
    204 
    205     psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
    206     psEllipseShape shape = psEllipseAxesToShape (axes);
    207 
     196    psF32 *PAR  = model->params->data.F32;
     197
     198    // sky is set to 0.0
    208199    PAR[PM_PAR_SKY]  = 0.0;
    209     PAR[PM_PAR_I0]   = peak->flux;
    210     PAR[PM_PAR_XPOS] = peak->xf;
    211     PAR[PM_PAR_YPOS] = peak->yf;
    212     PAR[PM_PAR_SXX] = PS_MAX(0.5, M_SQRT2*shape.sx);
    213     PAR[PM_PAR_SYY] = PS_MAX(0.5, M_SQRT2*shape.sy);
    214     PAR[PM_PAR_SXY] = shape.sxy;
     200
     201    // set the shape parameters
     202    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
     203      return false;
     204    }
     205
     206    // set the model normalization
     207    if (!pmModelSetNorm(&PAR[PM_PAR_I0], source)) {
     208      return false;
     209    }
     210
     211    // set the model position
     212    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     213      return false;
     214    }
     215
    215216    return(true);
    216217}
     
    285286    // choose a z value guaranteed to be beyond our limit
    286287    float z0 = pow((1.0 / limit), (1.0 / 3.0));
    287     psAssert (isfinite(z0), "fix this code: z0 should not be nan for %f", PAR[PM_PAR_I0]);
     288    psAssert (isfinite(z0), "fix this code: z0 should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f)",
     289              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY]);
     290
    288291    float z1 = (1.0 / limit);
    289     psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_I0]);
     292    psAssert (isfinite(z1), "fix this code: z1 should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f)",
     293              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY]);
     294
    290295    z1 = PS_MAX (z0, z1);
    291296    z0 = 0.0;
  • trunk/psModules/src/objects/models/pmModel_PS1_V1.c

    r29004 r31153  
    213213bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
    214214{
    215     pmMoments *moments = source->moments;
    216     pmPeak    *peak    = source->peak;
    217     psF32     *PAR  = model->params->data.F32;
    218 
    219     psEllipseMoments emoments;
    220     emoments.x2 = moments->Mxx;
    221     emoments.xy = moments->Mxy;
    222     emoments.y2 = moments->Myy;
    223 
    224     // force the axis ratio to be < 20.0
    225     psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
    226 
    227     if (!isfinite(axes.major)) return false;
    228     if (!isfinite(axes.minor)) return false;
    229     if (!isfinite(axes.theta)) return false;
    230 
    231     psEllipseShape shape = psEllipseAxesToShape (axes);
    232 
    233     if (!isfinite(shape.sx))  return false;
    234     if (!isfinite(shape.sy))  return false;
    235     if (!isfinite(shape.sxy)) return false;
    236 
     215    psF32 *PAR  = model->params->data.F32;
     216
     217    // sky is set to 0.0
    237218    PAR[PM_PAR_SKY]  = 0.0;
    238     PAR[PM_PAR_I0]   = peak->flux;
    239     PAR[PM_PAR_XPOS] = peak->xf;
    240     PAR[PM_PAR_YPOS] = peak->yf;
    241     PAR[PM_PAR_SXX]  = PS_MAX(0.5, M_SQRT2*shape.sx);
    242     PAR[PM_PAR_SYY]  = PS_MAX(0.5, M_SQRT2*shape.sy);
    243     PAR[PM_PAR_SXY]  = shape.sxy;
     219
     220    // set the shape parameters
     221    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
     222      return false;
     223    }
     224
     225    // set the model normalization
     226    if (!pmModelSetNorm(&PAR[PM_PAR_I0], source)) {
     227      return false;
     228    }
     229
     230    // set the model position
     231    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     232      return false;
     233    }
     234
     235    // extra parameter
    244236    PAR[PM_PAR_7]    = 0.5;
    245237
     
    314306    float z0 = 0.0;
    315307    float z1 = pow((1.0 / limit), (1.0 / ALPHA));
    316     psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]);
     308    psAssert (isfinite(z1), "fix this code: z1 should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f)",
     309              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY]);
    317310    if (PAR[PM_PAR_7] < 0.0) z1 *= 2.0;
    318311
  • trunk/psModules/src/objects/models/pmModel_QGAUSS.c

    r29004 r31153  
    214214bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
    215215{
    216     pmMoments *moments = source->moments;
    217     pmPeak    *peak    = source->peak;
    218     psF32     *PAR  = model->params->data.F32;
    219 
    220     psEllipseMoments emoments;
    221     emoments.x2 = moments->Mxx;
    222     emoments.xy = moments->Mxy;
    223     emoments.y2 = moments->Myy;
    224 
    225     // force the axis ratio to be < 20.0
    226     psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
    227 
    228     if (!isfinite(axes.major)) return false;
    229     if (!isfinite(axes.minor)) return false;
    230     if (!isfinite(axes.theta)) return false;
    231 
    232     psEllipseShape shape = psEllipseAxesToShape (axes);
    233 
    234     if (!isfinite(shape.sx))  return false;
    235     if (!isfinite(shape.sy))  return false;
    236     if (!isfinite(shape.sxy)) return false;
    237 
     216    psF32 *PAR  = model->params->data.F32;
     217
     218    // sky is set to 0.0
    238219    PAR[PM_PAR_SKY]  = 0.0;
    239     PAR[PM_PAR_I0]   = peak->flux;
    240     PAR[PM_PAR_XPOS] = peak->xf;
    241     PAR[PM_PAR_YPOS] = peak->yf;
    242     PAR[PM_PAR_SXX]  = PS_MAX(0.5, M_SQRT2*shape.sx);
    243     PAR[PM_PAR_SYY]  = PS_MAX(0.5, M_SQRT2*shape.sy);
    244     PAR[PM_PAR_SXY]  = shape.sxy;
     220
     221    // set the shape parameters
     222    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
     223      return false;
     224    }
     225
     226    // set the model normalization
     227    if (!pmModelSetNorm(&PAR[PM_PAR_I0], source)) {
     228      return false;
     229    }
     230
     231    // set the model position
     232    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     233      return false;
     234    }
     235
     236    // extra parameter
    245237    PAR[PM_PAR_7]    = 1.0;
    246238
     
    315307    float z0 = 0.0;
    316308    float z1 = pow((1.0 / limit), (1.0 / ALPHA));
    317     psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]);
     309    psAssert (isfinite(z1), "fix this code: z1 should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f)",
     310              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY]);
    318311    if (PAR[PM_PAR_7] < 0.0) z1 *= 2.0;
    319312
  • trunk/psModules/src/objects/models/pmModel_RGAUSS.c

    r29004 r31153  
    203203bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
    204204{
    205     pmMoments *moments = source->moments;
    206     pmPeak    *peak    = source->peak;
    207     psF32     *PAR  = model->params->data.F32;
    208 
    209     psEllipseMoments emoments;
    210     emoments.x2 = moments->Mxx;
    211     emoments.xy = moments->Mxy;
    212     emoments.y2 = moments->Myy;
    213 
    214     // force the axis ratio to be < 20.0
    215     psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
    216 
    217     if (!isfinite(axes.major)) return false;
    218     if (!isfinite(axes.minor)) return false;
    219     if (!isfinite(axes.theta)) return false;
    220 
    221     psEllipseShape shape = psEllipseAxesToShape (axes);
    222 
    223     if (!isfinite(shape.sx))  return false;
    224     if (!isfinite(shape.sy))  return false;
    225     if (!isfinite(shape.sxy)) return false;
    226 
     205    psF32 *PAR  = model->params->data.F32;
     206
     207    // sky is set to 0.0
    227208    PAR[PM_PAR_SKY]  = 0.0;
    228     PAR[PM_PAR_I0]   = peak->flux;
    229     PAR[PM_PAR_XPOS] = peak->xf;
    230     PAR[PM_PAR_YPOS] = peak->yf;
    231     PAR[PM_PAR_SXX]  = PS_MAX(0.5, shape.sx);
    232     PAR[PM_PAR_SYY]  = PS_MAX(0.5, shape.sy);
    233     PAR[PM_PAR_SXY]  = shape.sxy;
     209
     210    // set the shape parameters
     211    if (!pmModelSetShape(&PAR[PM_PAR_SXX], &PAR[PM_PAR_SXY], &PAR[PM_PAR_SYY], source->moments)) {
     212      return false;
     213    }
     214
     215    // set the model normalization
     216    if (!pmModelSetNorm(&PAR[PM_PAR_I0], source)) {
     217      return false;
     218    }
     219
     220    // set the model position
     221    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     222      return false;
     223    }
     224
     225    // extra parameter
    234226    PAR[PM_PAR_7]    = 1.5;
    235227
     
    305297    // choose a z value guaranteed to be beyond our limit
    306298    float z0 = pow((1.0 / limit), (1.0 / PAR[PM_PAR_7]));
    307     psAssert (isfinite(z0), "fix this code: z0 should not be nan for %f", PAR[PM_PAR_7]);
     299    psAssert (isfinite(z0), "fix this code: z0 should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f), par 7 = %f",
     300              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], PAR[PM_PAR_7]);
     301
    308302    float z1 = (1.0 / limit);
    309     psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]);
     303    psAssert (isfinite(z1), "fix this code: z1 should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f), par 7 = %f",
     304              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], PAR[PM_PAR_7]);
     305
    310306    z1 = PS_MAX (z0, z1);
    311307    z0 = 0.0;
  • trunk/psModules/src/objects/models/pmModel_SERSIC.c

    r29028 r31153  
    222222{
    223223    pmMoments *moments = source->moments;
    224     pmPeak    *peak    = source->peak;
    225224    psF32     *PAR  = model->params->data.F32;
     225
     226    // sky is set to 0.0
     227    PAR[PM_PAR_SKY]  = 0.0;
    226228
    227229    // the other parameters depend on the guess for PAR_7
     
    236238    float Zero  = 1.16 - 0.615 * PAR[PM_PAR_7];
    237239
     240    // Sersic shape is a bit special
    238241    psEllipseMoments emoments;
    239242    emoments.x2 = moments->Mxx;
     
    273276    float Syy = PS_MAX(0.5, shape.sy);
    274277
    275     PAR[PM_PAR_SKY]  = 0.0;
    276     PAR[PM_PAR_I0]   = peak->flux / Io;
    277     PAR[PM_PAR_XPOS] = peak->xf;
    278     PAR[PM_PAR_YPOS] = peak->yf;
    279278    PAR[PM_PAR_SXX]  = Sxx;
    280279    PAR[PM_PAR_SYY]  = Syy;
    281280    PAR[PM_PAR_SXY]  = shape.sxy;
     281
     282    // set the model normalization (adjust for Sersic best guess)
     283    if (!pmModelSetNorm(&PAR[PM_PAR_I0], source)) {
     284      return false;
     285    }
     286    PAR[PM_PAR_I0] /= Io;
     287
     288    // set the model position
     289    if (!pmModelSetPosition(&PAR[PM_PAR_XPOS], &PAR[PM_PAR_YPOS], source)) {
     290      return false;
     291    }
    282292
    283293    return(true);
     
    346356    psF64 radius = axes.major * sqrt (2.0) * pow(zn, 0.5 / PAR[PM_PAR_7]);
    347357
    348     // fprintf (stderr, "sersic model %f %f, n %f, radius: %f, zn: %f, f/Io: %f, major: %f\n", PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], PAR[PM_PAR_7], radius, zn, flux/PAR[PM_PAR_I0], axes.major);
    349 
    350     psAssert (isfinite(radius), "fix this code: z should not be nan for %f", PAR[PM_PAR_7]);
     358    psAssert (isfinite(radius), "fix this code: radius should not be nan for Io = %f, flux = %f, major = %f (%f, %f, %f), par 7 = %f",
     359              PAR[PM_PAR_I0], flux, axes.major, PAR[PM_PAR_SXX], PAR[PM_PAR_SXY], PAR[PM_PAR_SYY], PAR[PM_PAR_7]);
    351360    return (radius);
    352361}
  • trunk/psModules/src/objects/pmFootprint.c

    r30621 r31153  
    9898}
    9999
     100// XXX not actually used anywhere
    100101pmFootprint *pmFootprintNormalize(pmFootprint *fp) {
    101102    if (fp != NULL && !fp->normalized) {
    102         fp->peaks = psArraySort(fp->peaks, pmPeakSortBySN);
     103        if (PM_PEAKS_CULL_WITH_SMOOTHED_IMAGE) {
     104            fp->peaks = psArraySort(fp->peaks, pmPeaksSortBySmoothFluxDescend);
     105        } else {
     106            fp->peaks = psArraySort(fp->peaks, pmPeaksSortByRawFluxDescend);
     107        }
    103108        fp->normalized = true;
    104109    }
  • trunk/psModules/src/objects/pmFootprint.h

    r30621 r31153  
    1010#ifndef PM_FOOTPRINT_H
    1111#define PM_FOOTPRINT_H
     12
     13// We need to choose up front if the culling algorithm uses the raw or smoothed image.
     14// depending on which we choose, we should produce sorted peaks based on peak->rawFlux or
     15// peak->smoothFlux
     16
     17# define PM_PEAKS_CULL_WITH_SMOOTHED_IMAGE 1
    1218
    1319typedef struct {
     
    8490                                 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive
    8591                                 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance
    86                                  const float min_threshold // minimum permitted coll height
     92                                 const float min_threshold, // minimum permitted coll height
     93                                 const float max_threshold,// maximum permitted coll height
     94                                 const bool isWeightVar // the input weight may be variance (sigma^2) or S/N (1/sigma)
    8795    );
    8896
  • trunk/psModules/src/objects/pmFootprintAssignPeaks.c

    r30621 r31153  
    4646     */
    4747    psImage *ids = pmSetFootprintArrayIDs(footprints, true);
    48     assert (ids != NULL);
    49     assert (ids->type.type == PS_TYPE_S32);
    50     const int row0 = ids->row0;
    51     const int col0 = ids->col0;
    52     const int numRows = ids->numRows;
    53     const int numCols = ids->numCols;
     48    if (ids) { assert (ids->type.type == PS_TYPE_S32); }
     49   
     50    const int row0 = ids ? ids->row0 : 0;
     51    const int col0 = ids ? ids->col0 : 0;
     52    const int numRows = ids ? ids->numRows : -1;
     53    const int numCols = ids ? ids->numCols : -1;
    5454
    5555    for (int i = 0; i < peaks->n; i++) {
     
    5858        const int y = peak->y - row0;
    5959       
    60         assert (x >= 0 && x < numCols && y >= 0 && y < numRows);
    61         int id = ids->data.S32[y][x - col0];
     60        if (ids) { assert (x >= 0 && x < numCols && y >= 0 && y < numRows);}
     61        int id = ids ? ids->data.S32[y][x - col0] : 0;
     62        // XXX I think the '[x - col0]' above is just wrong (should be [x], but never gets triggerd.
    6263
    6364        if (id == 0) {                  // peak isn't in a footprint, so make one for it
     
    8687        if (fp->peaks->n == 1) continue;
    8788
    88         fp->peaks = psArraySort(fp->peaks, pmPeakSortBySN);
     89        // make sure the peaks are sorted in a way consistent with our cull process
     90        if (PM_PEAKS_CULL_WITH_SMOOTHED_IMAGE) {
     91            fp->peaks = psArraySort(fp->peaks, pmPeaksSortBySmoothFluxDescend);
     92        } else {
     93            fp->peaks = psArraySort(fp->peaks, pmPeaksSortByRawFluxDescend);
     94        }
    8995
    9096        // XXX check for an assert on duplicates (I don't think they can happen, but
  • trunk/psModules/src/objects/pmFootprintCullPeaks.c

    r30621 r31153  
    3838                                 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive
    3939                                 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance
    40                                  const float min_threshold) { // minimum permitted coll height
     40                                 const float min_threshold, // minimum permitted coll height
     41                                 const float max_threshold,
     42                                 const bool useSmoothedImage
     43    ) { // maximum permitted coll height
    4144    assert (img != NULL); assert (img->type.type == PS_TYPE_F32);
    4245    assert (weight != NULL); assert (weight->type.type == PS_TYPE_F32);
     
    4447    assert (fp != NULL);
    4548
    46     if (fp->peaks == NULL || fp->peaks->n == 0) { // nothing to do
     49    if (fp->peaks == NULL || fp->peaks->n < 2) { // nothing to do
    4750        return PS_ERR_NONE;
    4851    }
     
    5356
    5457    psImage *subImg = psImageSubset((psImage *)img, subRegion);
    55     psImage *subWt = psImageSubset((psImage *)weight, subRegion);
    56     assert (subImg != NULL && subWt != NULL);
     58    psAssert (subImg, "trouble making local subimage");
    5759
    5860    psImage *idImg = psImageAlloc(subImg->numCols, subImg->numRows, PS_TYPE_S32);
     
    6870    psArrayAdd (brightPeaks, 128, fp->peaks->data[0]);
    6971
     72    // XXX test point
     73    // pmPeak *myPeak = fp->peaks->data[0];
     74    // if ((fabs(myPeak->x - 205) < 100) && (fabs(myPeak->y - 806) < 100)) {
     75    //  fprintf (stderr, "test peak\n");
     76    // }
     77
    7078    // allocate the peakFootprint and peakFPSpans containers -- these are re-used by pmFootprintsFindAtPoint to minimize allocs in this function
    7179    pmFootprint *peakFootprint = pmFootprintAlloc(fp->nspans, subImg);
     
    7785    psImage *subMask = psImageCopy(NULL, subImg, PS_TYPE_IMAGE_MASK);
    7886
    79     // The brightest peak is always safe; go through other peaks trying to cull them
    80     for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop
    81         const pmPeak *peak = fp->peaks->data[i];
    82         int x = peak->x - subImg->col0;
    83         int y = peak->y - subImg->row0;
    84         //
    85         // Find the level nsigma below the peak that must separate the peak
    86         // from any of its friends
    87         //
    88         assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows);
    89 
    90         // const float stdev = sqrt(subWt->data.F32[y][x]);
    91         // float threshold = subImg->data.F32[y][x] - nsigma_delta*stdev;
    92 
    93         const float stdev = sqrt(subWt->data.F32[y][x]);
    94         const float flux = subImg->data.F32[y][x];
    95         const float fStdev = fabs(stdev/flux);
    96         const float stdev_pad = fabs(flux * hypot(fStdev, fPadding));
    97         // if flux is negative, careful with fStdev
    98 
    99         float threshold = flux - nsigma_delta*stdev_pad;
    100 
    101         if (isnan(threshold)) {
    102             // min_threshold is assumed to be below the detection threshold,
    103             // so all the peaks are pmFootprint, and this isn't the brightest
    104             continue;
    105         }
    106 
    107         // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true?
    108         if (threshold > subImg->data.F32[y][x]) {
    109             threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON;
    110         }
    111 
    112         if (threshold < min_threshold) {
    113             threshold = min_threshold;
    114         }
    115 
    116         // init peakFootprint here?
    117         pmFootprintsFindAtPoint(peakFootprint, peakFPSpans, subImg, subMask, threshold, brightPeaks, peak->y, peak->x);
    118         if (peakFPSpans->nStartSpans > 2000) {
    119             // dumpfootprints(peakFootprint, peakFPSpans);
    120             // fprintf (stderr, "big footprint %d : %d\n", peakFootprint->nspans, peakFPSpans->nStartSpans);
    121             fprintf (stderr, "big test footprint: %f %f to %f %f (%d pix)\n", peakFootprint->bbox.x0, peakFootprint->bbox.y0, peakFootprint->bbox.x1, peakFootprint->bbox.y1, peakFootprint->npix);
    122         }
    123 
    124         // at this point brightPeaks only has the peaks brighter than the current
    125 
    126         // we set the IDs to either 1 (in peak) or 0 (not in peak)
    127         pmSetFootprintID (idImg, peakFootprint, IN_PEAK);
    128 
    129         // If this peak has not already been assigned to a source, then we can look for any
    130         // brighter peaks within its footprint. Check if any of the previous (brighter) peaks
    131         // are within the footprint of this peak If so, the current peak is bogus; drop it.
    132         bool keep = true;
    133         for (int j = 0; keep && !peak->assigned && (j < brightPeaks->n); j++) {
    134             const pmPeak *peak2 = fp->peaks->data[j];
    135             int x2 = peak2->x - subImg->col0;
    136             int y2 = peak2->y - subImg->row0;
    137             if (idImg->data.S32[y2][x2] == IN_PEAK) {
    138                 // There's a brighter peak within the footprint above threshold; so cull our initial peak
    139                 keep = false;
    140             }
    141         }
    142         if (!keep) {
    143             psAssert (!peak->assigned, "logic error: trying to drop a previously-assigned peak");  // we should not drop any already assigned peaks.
    144             continue;
    145         }
    146 
    147         psArrayAdd (brightPeaks, 128, fp->peaks->data[i]);
     87    // if we have many peaks in a large footprint, we waste a lot of time generating nearly identical footprints
     88    // here we attempt to cull peaks drawing a single footprint for all peaks in some threshold range
     89    // fprintf (stderr, "footprint: %d x %d : %d pix, %d peaks\n", subImg->numCols, subImg->numRows, fp->npix, (int) fp->peaks->n);
     90    if ((fp->npix > 30000) && (fp->peaks->n > 10)) {
     91
     92        // max flux is above threshold for brightest peak
     93        pmPeak *maxPeak = fp->peaks->data[0];
     94        float maxFlux = useSmoothedImage ? maxPeak->smoothFlux : maxPeak->rawFlux;
     95
     96        // we have a relationship between the bin and the threshold of:
     97        // threshold = 0.25 beta^2 bin^2 + minThreshold
     98        // thus, the max bin is: sqrt(4.0*(maxThreshold - minThreshold)/ALPHA^2)
     99
     100# define ALPHA 0.1
     101       
     102        float beta = nsigma_delta * ALPHA;
     103        float beta2 = PS_SQR(beta);
     104        int nBins = sqrt(4.0*(maxFlux - min_threshold)/beta2) + 10; // let's be extra generous
     105
     106        // create a vector to store the threshold bins used for each peak
     107        psVector *threshbins = psVectorAlloc(fp->peaks->n, PS_TYPE_S32);
     108        threshbins->data.S32[0] = -1; // we skip the first peak
     109
     110        /// create a vector to track if a peak has been tried or not:
     111        psVector *peaktried = psVectorAlloc(fp->peaks->n, PS_TYPE_U8);
     112        psVectorInit(peaktried, 0);
     113        peaktried->data.U8[0] = true; // we skip the first peak
     114
     115        psVector *threshbounds = psVectorAlloc(nBins, PS_TYPE_F32);
     116        for (int i = 0; i < nBins; i++) {
     117            threshbounds->data.F32[i] = 0.25*beta2*PS_SQR(i) + min_threshold;       
     118        }
     119        psAssert(threshbounds->data.F32[threshbounds->n-1] > maxFlux, "upper limit does not include max flux");
     120
     121        psHistogram *threshist = psHistogramAllocGeneric(threshbounds);
     122
     123        // assign the peaks to the histogram bins based on their nominal thresholsd
     124        for (int i = 1; i < fp->peaks->n; i++) {
     125            const pmPeak *peak = fp->peaks->data[i];
     126            float flux = useSmoothedImage ? peak->smoothFlux : peak->rawFlux;
     127            float stdev = useSmoothedImage ? peak->smoothFluxStdev : peak->rawFluxStdev;
     128
     129            // if flux is negative, careful with fStdev
     130            const float fStdev = fabs(stdev/flux);
     131            const float stdev_pad = fabs(flux * hypot(fStdev, fPadding));
     132
     133            float threshold = flux - nsigma_delta*stdev_pad;
     134            psAssert(!isnan(threshold), "impossible");
     135
     136            if (threshold <= min_threshold) {
     137                threshist->nums->data.F32[0] += 1.0;
     138                threshbins->data.S32[i] = 0;
     139                continue;
     140            }
     141            int bin = sqrt(4.0*(threshold - min_threshold)/beta2);
     142            psAssert(bin >= 0, "impossible bin");
     143
     144            bin = PS_MIN(bin, threshist->nums->n - 1);
     145            threshist->nums->data.F32[bin] += 1.0;
     146           
     147            // record the bin selected for this peak
     148            threshbins->data.S32[i] = bin;
     149        }
     150
     151        // XXX TEST: did we assign correctly
     152# if (0)
     153        int nPeaks = 1; // we don't put the brightest in the histogram
     154        for (int i = 0; i < threshist->nums->n; i++) {
     155            if (threshist->nums->data.F32[i] > 0) {
     156                fprintf (stderr, "%f : %f : %d\n", threshist->bounds->data.F32[i], threshist->bounds->data.F32[i+1], (int)threshist->nums->data.F32[i]);
     157                nPeaks += threshist->nums->data.F32[i];
     158            }
     159        }
     160        fprintf (stderr, "%d peaks vs %d in histogram\n", (int) fp->peaks->n, nPeaks);
     161# endif
     162
     163        // XXX for the moment, we will use the alternate cull for all peaks -- it might be
     164        // faster to use the standard process for the peaks for which the threshold bin
     165        // contains < N sources (N ~ 5-10?)
     166
     167        // loop over the threshold bins from brightest to faintest
     168        for (int i = threshist->nums->n - 1; i >= 0; i--) {
     169            if (threshist->nums->data.F32[i] == 0) continue;
     170
     171            // we are going to examine the footprints at this threshold
     172            float threshold = 0.5*(threshist->bounds->data.F32[i] + threshist->bounds->data.F32[i+1]);
     173                   
     174            // generate all footprints corresponding to this threshold
     175            psArray *myFP = pmFootprintsFind(subImg, threshold, 5);
     176            if (!myFP) {
     177                psWarning ("missing footprint?");
     178                continue;
     179            }
     180            if (!myFP->n) {
     181                psWarning ("empty footprint?");
     182                continue;
     183            }
     184
     185            // an array to track if the footprint has a brighter peak or not
     186            psVector *found = psVectorAlloc(myFP->n + 1, PS_TYPE_U8);
     187            psVectorInit(found, 0);
     188            int nFound = 0;
     189
     190            // set IDs to distinguish the footprints
     191            psImageInit(idImg, 0);
     192            pmSetFootprintArrayIDsForImage(idImg, myFP, true);
     193       
     194            // check which footprints contain already-accepted (brighter) peaks
     195            // (we can give up if/when we found a peak for all footprints)
     196            for (int j = 0; (j < brightPeaks->n) && (nFound < found->n); j++) {
     197                const pmPeak *peak = brightPeaks->data[j];
     198                int x = peak->x - subImg->col0;
     199                int y = peak->y - subImg->row0;
     200                int myID = idImg->data.S32[y][x];
     201                psAssert(myID >= 0, "impossible");
     202                psAssert(myID < found->n, "impossible");
     203
     204                if (myID == 0) continue; // bright peak is not in a footprint
     205                if (found->data.U8[myID]) continue; // we already know this footprint contains a peak
     206                found->data.U8[myID] = true;
     207                nFound ++;
     208            }
     209       
     210            // check the peaks from this threshold bin: if they land in a footprint which has
     211            // been found, we should drop that peak.  otherwise, keep it
     212            for (int j = 0; j < fp->peaks->n; j++) {
     213                pmPeak *peak = fp->peaks->data[j];
     214                if (peak->assigned) continue; // peak is already claimed by a source -- don't cull
     215
     216                // skip peaks if we've already tried them
     217                if (peaktried->data.U8[j]) continue;
     218
     219                // is this peak in the threshold bin of interest?
     220                if (threshbins->data.S32[j] != i) continue;
     221               
     222                // do not try this peak again
     223                peaktried->data.U8[j] = true;
     224
     225                int x = peak->x - subImg->col0;
     226                int y = peak->y - subImg->row0;
     227                int myID = idImg->data.S32[y][x];
     228                psAssert(myID < found->n, "impossible");
     229
     230                // a peak in this threshold bin without a valid footprint comes from a region
     231                // with only a handful of pixels (1 or more from the peak itself).  It probably
     232                // cannot be joined to a neighbor
     233                if (myID == 0) {
     234                    psArrayAdd (brightPeaks, 128, peak);
     235                    continue;
     236                }
     237
     238                // keep this peak if found->data.U8[myID] == false (no brighter peak in the footprint)
     239                if (!found->data.U8[myID]) {
     240                    // fprintf (stderr, "keeping %d: %d,%d\n", j, peak->x, peak->y);
     241                    psArrayAdd (brightPeaks, 128, peak);
     242                    continue;
     243                }
     244                // fprintf (stderr, "skipping %d: %d,%d\n", j, peak->x, peak->y);
     245            }
     246            psFree (myFP);
     247            psFree (found);
     248        }
     249        psFree (threshist);
     250        psFree (threshbounds);
     251        psFree (threshbins);
     252        psFree (peaktried);
     253
     254    } else {
     255
     256        // The brightest peak is always safe; go through other peaks trying to cull them
     257        for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop
     258            const pmPeak *peak = fp->peaks->data[i];
     259
     260            float flux  = useSmoothedImage ? peak->smoothFlux      : peak->rawFlux;
     261            float stdev = useSmoothedImage ? peak->smoothFluxStdev : peak->rawFluxStdev;
     262
     263            // if flux is negative, careful with fStdev
     264            const float fStdev = fabs(stdev/flux);
     265            const float stdev_pad = fabs(flux * hypot(fStdev, fPadding));
     266
     267            float threshold = flux - nsigma_delta*stdev_pad;
     268
     269            if (isnan(threshold)) {
     270                // min_threshold is assumed to be below the detection threshold,
     271                // so all the peaks are pmFootprint, and this isn't the brightest
     272                continue;
     273            }
     274
     275            // just in case, force the threshold below the peak source flux
     276            if (threshold > flux) {
     277                threshold = flux - 10*FLT_EPSILON;
     278            }
     279
     280            if (threshold < min_threshold) {
     281                threshold = min_threshold;
     282            }
     283            if (threshold > max_threshold) {
     284                threshold = max_threshold;
     285            }
     286
     287            pmFootprintsFindAtPoint(peakFootprint, peakFPSpans, subImg, subMask, threshold, brightPeaks, peak->y, peak->x);
     288            // if (peakFPSpans->nStartSpans > 2000) {
     289            //  // dumpfootprints(peakFootprint, peakFPSpans);
     290            //  // fprintf (stderr, "big footprint %d : %d\n", peakFootprint->nspans, peakFPSpans->nStartSpans);
     291            //  // fprintf (stderr, "big test footprint: %f %f to %f %f (%d pix)\n", peakFootprint->bbox.x0, peakFootprint->bbox.y0, peakFootprint->bbox.x1, peakFootprint->bbox.y1, peakFootprint->npix);
     292            // }
     293
     294            // at this point brightPeaks only has the peaks brighter than the current
     295
     296            // we set the IDs to either 1 (in peak) or 0 (not in peak)
     297            pmSetFootprintID (idImg, peakFootprint, IN_PEAK);
     298
     299            // If this peak has not already been assigned to a source, then we can look for any
     300            // brighter peaks within its footprint. Check if any of the previous (brighter) peaks
     301            // are within the footprint of this peak If so, the current peak is bogus; drop it.
     302            bool keep = true;
     303            for (int j = 0; keep && !peak->assigned && (j < brightPeaks->n); j++) {
     304                // const pmPeak *peak2 = fp->peaks->data[j]; XXX isn't this an error?  we only care about the kept brighter peak, right?
     305                const pmPeak *peak2 = brightPeaks->data[j];
     306                int x2 = peak2->x - subImg->col0;
     307                int y2 = peak2->y - subImg->row0;
     308                if (idImg->data.S32[y2][x2] == IN_PEAK) {
     309                    // There's a brighter peak within the footprint above threshold; so cull our initial peak
     310                    keep = false;
     311                }
     312            }
     313            if (!keep) {
     314                psAssert (!peak->assigned, "logic error: trying to drop a previously-assigned peak");  // we should not drop any already assigned peaks.
     315                continue;
     316            }
     317            psArrayAdd (brightPeaks, 128, fp->peaks->data[i]);
     318        }
    148319    }
    149320
     
    153324    psFree(idImg);
    154325    psFree(subImg);
    155     psFree(subWt);
    156326    psFree(subMask);
    157327    psFree(peakFootprint);
  • trunk/psModules/src/objects/pmFootprintFindAtPoint.c

    r29004 r31153  
    3131 *
    3232 * This is the guts of pmFootprintsFindAtPoint
     33 *
     34 * This function is/was ill-defined if pixel values are NAN.  we should either treat NAN as >
     35 * threshold or < threshold, but the current (r29004) code is ambiguous.
     36 * EAM : change code so NAN is always > threshold
    3337 */
    3438bool pmFootprintSpansBuild(pmFootprint *fp, // the footprint that we're building
     
    103107        for (int j = x0 - 1; j >= -1; j--) {
    104108            double pixVal = (j < 0) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    105             if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) {
     109            bool belowThreshold = (pixVal < threshold) && isfinite(pixVal);
     110            if ((maskRow[j] & PM_STARTSPAN_DETECTED) || belowThreshold)  {
    106111                if (j < x0 - 1) {       // we found some pixels above threshold
    107112                    nx0 = j + 1;
     
    119124            for (int j = nx0 + 1; j <= numCols; j++) {
    120125                double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    121                 if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) {
     126                bool belowThreshold = (pixVal < threshold) && isfinite(pixVal);
     127                if ((maskRow[j] & PM_STARTSPAN_DETECTED) || belowThreshold) {
    122128                    nx1 = j - 1;
    123129                    break;
     
    146152        for (int j = nx1 + 1; j <= x1 + 1; j++) {
    147153            double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    148             if (!(maskRow[j] & PM_STARTSPAN_DETECTED) && pixVal >= threshold) {
     154            bool aboveThreshold = (pixVal >= threshold) || !isfinite(pixVal);
     155            if (!(maskRow[j] & PM_STARTSPAN_DETECTED) && aboveThreshold) {
    149156                int sx0 = j++;          // span that we're working on is sx0:sx1
    150157                int sx1 = -1;           // We know that if we got here, we'll also set sx1
    151158                for (; j <= numCols; j++) {
    152159                    double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    153                     if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) { // end of span
     160                    bool belowThreshold = (pixVal < threshold) && isfinite(pixVal);
     161                    if ((maskRow[j] & PM_STARTSPAN_DETECTED) || belowThreshold) { // end of span
    154162                        sx1 = j;
    155163                        break;
     
    306314        for (i = col; i >= 0; i--) {
    307315            pixVal = F32 ? imgRowF32[i] : imgRowS32[i];
    308             if ((maskRow[i] & PM_STARTSPAN_DETECTED) || pixVal < threshold) {
     316            bool belowThreshold = (pixVal < threshold) && isfinite(pixVal);
     317            if ((maskRow[i] & PM_STARTSPAN_DETECTED) || belowThreshold) {
    309318                break;
    310319            }
     
    313322        for (i = col; i < numCols; i++) {
    314323            pixVal = F32 ? imgRowF32[i] : imgRowS32[i];
    315             if ((maskRow[i] & PM_STARTSPAN_DETECTED) || pixVal < threshold) {
     324            bool belowThreshold = (pixVal < threshold) && isfinite(pixVal);
     325            if ((maskRow[i] & PM_STARTSPAN_DETECTED) || belowThreshold) {
    316326                break;
    317327            }
  • trunk/psModules/src/objects/pmFootprintIDs.c

    r29004 r31153  
    6666
    6767   if (footprints->n == 0) {
    68        psError(PS_ERR_BAD_PARAMETER_SIZE, true, "You didn't provide any footprints");
     68       // XXX this was an error, but is an allowed condition -- NULL returned image means no footprints for any peaks
     69       // psError(PS_ERR_BAD_PARAMETER_SIZE, true, "You didn't provide any footprints");
    6970       return NULL;
    7071   }
  • trunk/psModules/src/objects/pmModel.c

    r30621 r31153  
    4141    psFree(tmp->params);
    4242    psFree(tmp->dparams);
     43    psFree(tmp->covar);
    4344    psTrace("psModules.objects", 10, "---- %s() end ----\n", __func__);
    4445}
     
    6667    tmp->chisqNorm = NAN;
    6768    tmp->nDOF  = 0;
     69    tmp->nPar  = 0;
    6870    tmp->nPix  = 0;
    6971    tmp->nIter = 0;
     
    7173    tmp->flags = PM_MODEL_STATUS_NONE;
    7274    tmp->residuals = NULL;              // do not free: the model does not own this memory
     75    tmp->covar = NULL;
    7376    tmp->isPCM = false;
    7477
  • trunk/psModules/src/objects/pmModel.h

    r30621 r31153  
    3333    psVector *params;                   ///< Paramater values.
    3434    psVector *dparams;                  ///< Parameter errors.
     35    psImage *covar;                     ///< Optional covariance matrix
    3536    float chisq;                        ///< Fit chi-squared.
    3637    float chisqNorm;                    ///< re-normalized fit chi-squared.
     
    3839    float magErr;                       ///< integrated model magnitude error
    3940    int nPix;                           ///< number of pixels used for fit
    40     int nDOF;                           ///< number of degrees of freedom
     41    int nPar;                           ///< number of parameters in fit
     42    int nDOF;                           ///< number of degrees of freedom (nDOF = nPix - nPar)
    4143    int nIter;                          ///< number of iterations to reach min
    4244    pmModelStatus flags;                ///< model status flags
  • trunk/psModules/src/objects/pmModelUtils.c

    r29004 r31153  
    107107    return true;
    108108}
     109
     110bool pmModelSetShape (float *Sxx, float *Sxy, float *Syy, pmMoments *moments) {
     111
     112    psEllipseMoments emoments;
     113    emoments.x2 = moments->Mxx;
     114    emoments.xy = moments->Mxy;
     115    emoments.y2 = moments->Myy;
     116
     117    // force the axis ratio to be < 20.0
     118    psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
     119
     120    if (!isfinite(axes.major)) return false;
     121    if (!isfinite(axes.minor)) return false;
     122    if (!isfinite(axes.theta)) return false;
     123
     124    psEllipseShape shape = psEllipseAxesToShape (axes);
     125
     126    if (!isfinite(shape.sx))  return false;
     127    if (!isfinite(shape.sy))  return false;
     128    if (!isfinite(shape.sxy)) return false;
     129
     130    // set the shape parameters
     131    *Sxx  = PS_MAX(0.5, M_SQRT2*shape.sx);
     132    *Syy  = PS_MAX(0.5, M_SQRT2*shape.sy);
     133    *Sxy  = shape.sxy;
     134
     135    return true;
     136}
     137
     138bool pmModelSetNorm (float *Io, pmSource *source) {
     139
     140    *Io = source->peak->rawFlux;
     141    if (!isfinite(*Io) && !source->moments) return false;
     142
     143    *Io = source->moments->Peak;
     144    if (!isfinite(*Io)) return false;
     145
     146    return true;
     147}
     148
     149bool pmModelSetPosition (float *Xo, float *Yo, pmSource *source) {
     150
     151    bool useMoments = pmSourcePositionUseMoments(source);
     152   
     153    if (useMoments) {
     154        *Xo = source->moments->Mx;
     155        *Yo = source->moments->My;
     156    } else {
     157        *Xo = source->peak->xf;
     158        *Yo = source->peak->yf;
     159    }
     160
     161    return true;
     162}
  • trunk/psModules/src/objects/pmModelUtils.h

    r15843 r31153  
    4242    );
    4343
    44 
     44bool pmModelSetPosition (float *Xo, float *Yo, pmSource *source);
     45bool pmModelSetNorm (float *Io, pmSource *source);
     46bool pmModelSetShape (float *Sxx, float *Sxy, float *Syy, pmMoments *moments);
    4547
    4648/// @}
  • trunk/psModules/src/objects/pmMoments.h

    r29004 r31153  
    5151    int nPixels;  ///< Number of pixels used.
    5252
    53     float KronFlux;    ///< Kron flux (flux in 2.5*Mrf)
     53    float KronCore;    ///< flux in r < 1.0*Mrf
     54    float KronCoreErr;    ///< error on flux in r < 1.0*Mrf
     55
     56    float KronFlux;    ///< Kron flux (flux in r < 2.5*Mrf)
    5457    float KronFluxErr; ///< Kron flux error
    5558
    56     float KronFinner;    ///< Kron flux (flux in 2.5*Mrf)
    57     float KronFouter;    ///< Kron flux (flux in 2.5*Mrf)
    58 
     59    float KronFinner;    ///< Kron flux (flux in 1.0*Mrf < r < 2.5*Mrf)
     60    float KronFouter;    ///< Kron flux (flux in 2.5*Mrf < r < 4.0*Mrf)
    5961}
    6062pmMoments;
  • trunk/psModules/src/objects/pmPCMdata.c

    r29546 r31153  
    254254
    255255    pcm->nPix = nPix;
    256     pcm->nDOF = nPix - nParams - 1;
     256    pcm->nPar = nParams;
     257    pcm->nDOF = nPix - nParams;
    257258
    258259    return pcm;
     
    341342        return false;
    342343    }
    343     pcm->nDOF = pcm->nPix - nParams - 1;
     344    pcm->nPar = nParams;
     345    pcm->nDOF = pcm->nPix - nParams;
    344346
    345347    // has the source pixel window changed?
  • trunk/psModules/src/objects/pmPCMdata.h

    r30621 r31153  
    3333    psMinConstraint *constraint;
    3434    int nPix;
     35    int nPar;
    3536    int nDOF;
    3637} pmPCMdata;
  • trunk/psModules/src/objects/pmPSF.c

    r29004 r31153  
    430430        return NAN;
    431431    }
     432
     433    // get the model full-width at half-max
     434    float fwhmMajor = 2*model->modelRadius (model->params, 0.5);
     435
     436# if (0)
    432437    psF32 *params = model->params->data.F32; // Model parameters
    433438    psEllipseAxes axes = pmPSF_ModelToAxes(params, MAX_AXIS_RATIO); // Ellipse axes
     
    439444
    440445    return fwhm;
    441 }
     446# else
     447
     448    psFree(model);
     449
     450    return fwhmMajor;
     451# endif
     452}
  • trunk/psModules/src/objects/pmPSFtryFitPSF.c

    r30621 r31153  
    109109
    110110        // This function calculates the psf and aperture magnitudes
    111         status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal, markVal); // raw PSF mag, AP mag
     111        status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal, markVal, options->apRadius); // raw PSF mag, AP mag
    112112        if (!status || isnan(source->apMag)) {
    113113            psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
  • trunk/psModules/src/objects/pmPeaks.c

    r29004 r31153  
    115115XXX: Macro this.
    116116*****************************************************************************/
     117# if (0)
    117118static bool isItInThisRegion(const psRegion valid,
    118119                             psS32 x,
     
    130131    return(false);
    131132}
     133# endif
    132134
    133135/******************************************************************************
     
    148150    tmp->x = x;
    149151    tmp->y = y;
    150     tmp->value = value;
    151     tmp->flux = value;
    152     tmp->SN = 0;
     152    tmp->detValue        = value;
     153    tmp->rawFlux         = value; // set this by default: it is up to the user to supply a better value
     154    tmp->rawFluxStdev    = NAN;
     155    tmp->smoothFlux      = value; // set this by default: it is up to the user to supply a better value
     156    tmp->smoothFluxStdev = NAN;
     157    // tmp->SN = 0;
    153158    tmp->xf = x;
    154159    tmp->yf = y;
     
    170175
    171176
    172 // psSort comparison function for peaks
     177// psSort comparison functions for peaks
    173178// XXX: Add error-checking for NULL args
    174 int pmPeaksCompareAscend (const void **a, const void **b)
    175 {
    176     psTrace("psModules.objects", 10, "---- %s() begin ----\n", __func__);
     179int pmPeaksSortByDetValueAscend (const void **a, const void **b)
     180{
    177181    pmPeak *A = *(pmPeak **)a;
    178182    pmPeak *B = *(pmPeak **)b;
     
    180184    psF32 diff;
    181185
    182     diff = A->value - B->value;
     186    diff = A->detValue - B->detValue;
    183187    if (diff < FLT_EPSILON) {
    184         psTrace("psModules.objects", 10, "---- %s(-1) end ----\n", __func__);
    185188        return (-1);
    186189    } else if (diff > FLT_EPSILON) {
    187         psTrace("psModules.objects", 10, "---- %s(+1) end ----\n", __func__);
    188190        return (+1);
    189191    }
    190     psTrace("psModules.objects", 10, "---- %s(0) end ----\n", __func__);
    191192    return (0);
    192193}
    193 
    194 // psSort comparison function for peaks
    195 // XXX: Add error-checking for NULL args
    196 int pmPeaksCompareDescend (const void **a, const void **b)
    197 {
    198     psTrace("psModules.objects", 10, "---- %s() begin ----\n", __func__);
     194int pmPeaksSortByDetValueDescend (const void **a, const void **b)
     195{
    199196    pmPeak *A = *(pmPeak **)a;
    200197    pmPeak *B = *(pmPeak **)b;
     
    202199    psF32 diff;
    203200
    204     diff = A->value - B->value;
     201    diff = A->detValue - B->detValue;
    205202    if (diff < FLT_EPSILON) {
    206         psTrace("psModules.objects", 10, "---- %s(+1) end ----\n", __func__);
    207203        return (+1);
    208204    } else if (diff > FLT_EPSILON) {
    209         psTrace("psModules.objects", 10, "---- %s(-1) end ----\n", __func__);
    210205        return (-1);
    211206    }
    212     psTrace("psModules.objects", 10, "---- %s(0) end ----\n", __func__);
    213207    return (0);
    214208}
    215 
    216 // sort by SN (descending)
    217 int pmPeakSortBySN (const void **a, const void **b)
     209int pmPeaksSortByRawFluxAscend (const void **a, const void **b)
    218210{
    219211    pmPeak *A = *(pmPeak **)a;
    220212    pmPeak *B = *(pmPeak **)b;
    221213
    222     psF32 fA = A->SN;
    223     psF32 fB = B->SN;
    224     if (isnan (fA)) fA = 0;
    225     if (isnan (fB)) fB = 0;
    226 
    227     psF32 diff = fA - fB;
    228     if (diff > FLT_EPSILON) return (-1);
    229     if (diff < FLT_EPSILON) return (+1);
     214    psF32 diff;
     215
     216    diff = A->rawFlux - B->rawFlux;
     217    if (diff < FLT_EPSILON) {
     218        return (-1);
     219    } else if (diff > FLT_EPSILON) {
     220        return (+1);
     221    }
    230222    return (0);
    231223}
    232 
    233 // sort by Y (ascending)
    234 int pmPeakSortByY (const void **a, const void **b)
     224int pmPeaksSortByRawFluxDescend (const void **a, const void **b)
    235225{
    236226    pmPeak *A = *(pmPeak **)a;
    237227    pmPeak *B = *(pmPeak **)b;
    238228
    239     psF32 fA = A->y;
    240     psF32 fB = B->y;
    241 
    242     psF32 diff = fA - fB;
    243     if (diff > FLT_EPSILON) return (+1);
    244     if (diff < FLT_EPSILON) return (-1);
     229    psF32 diff;
     230
     231    diff = A->rawFlux - B->rawFlux;
     232    if (diff < FLT_EPSILON) {
     233        return (+1);
     234    } else if (diff > FLT_EPSILON) {
     235        return (-1);
     236    }
    245237    return (0);
    246238}
     239int pmPeaksSortBySmoothFluxAscend (const void **a, const void **b)
     240{
     241    pmPeak *A = *(pmPeak **)a;
     242    pmPeak *B = *(pmPeak **)b;
     243
     244    psF32 diff;
     245
     246    diff = A->smoothFlux - B->smoothFlux;
     247    if (diff < FLT_EPSILON) {
     248        return (-1);
     249    } else if (diff > FLT_EPSILON) {
     250        return (+1);
     251    }
     252    return (0);
     253}
     254int pmPeaksSortBySmoothFluxDescend (const void **a, const void **b)
     255{
     256    pmPeak *A = *(pmPeak **)a;
     257    pmPeak *B = *(pmPeak **)b;
     258
     259    psF32 diff;
     260
     261    diff = A->smoothFlux - B->smoothFlux;
     262    if (diff < FLT_EPSILON) {
     263        return (+1);
     264    } else if (diff > FLT_EPSILON) {
     265        return (-1);
     266    }
     267    return (0);
     268}
     269
     270// // sort by SN (descending)
     271// int pmPeakSortBySN (const void **a, const void **b)
     272// {
     273//     pmPeak *A = *(pmPeak **)a;
     274//     pmPeak *B = *(pmPeak **)b;
     275//
     276//     psF32 fA = A->flux;
     277//     psF32 fB = B->flux;
     278//     if (isnan (fA)) fA = 0;
     279//     if (isnan (fB)) fB = 0;
     280//
     281//     psF32 diff = fA - fB;
     282//     if (diff > FLT_EPSILON) return (-1);
     283//     if (diff < FLT_EPSILON) return (+1);
     284//     return (0);
     285// }
     286//
     287// // sort by Y (ascending)
     288// int pmPeakSortByY (const void **a, const void **b)
     289// {
     290//     pmPeak *A = *(pmPeak **)a;
     291//     pmPeak *B = *(pmPeak **)b;
     292//
     293//     psF32 fA = A->y;
     294//     psF32 fB = B->y;
     295//
     296//     psF32 diff = fA - fB;
     297//     if (diff > FLT_EPSILON) return (+1);
     298//     if (diff < FLT_EPSILON) return (-1);
     299//     return (0);
     300// }
    247301
    248302/******************************************************************************
     
    554608    return(list);
    555609}
    556 
    557 // return a new array of peaks which are in the valid region and below threshold
    558 // XXX this function is unused and probably could be dropped
    559 psArray *pmPeaksSubset(
    560     psArray *peaks,
    561     psF32 maxValue,
    562     const psRegion valid)
    563 {
    564     psTrace("psModules.objects", 10, "---- %s() begin ----\n", __func__);
    565     PS_ASSERT_PTR_NON_NULL(peaks, NULL);
    566 
    567     psArray *output = psArrayAllocEmpty (200);
    568 
    569     psTrace ("psModules.objects", 3, "list size is %ld\n", peaks->n);
    570 
    571     for (int i = 0; i < peaks->n; i++) {
    572         pmPeak *tmpPeak = (pmPeak *) peaks->data[i];
    573         if (tmpPeak->value > maxValue)
    574             continue;
    575         if (isItInThisRegion(valid, tmpPeak->x, tmpPeak->y))
    576             continue;
    577         psArrayAdd (output, 200, tmpPeak);
    578     }
    579     psTrace("psModules.objects", 10, "---- %s() end ----\n", __func__);
    580     return(output);
    581 }
  • trunk/psModules/src/objects/pmPeaks.h

    r29004 r31153  
    3535    PM_PEAK_EDGE,                       ///< Peak on edge.
    3636    PM_PEAK_FLAT,                       ///< Peak has equal-value neighbors.
     37    PM_PEAK_SUSPECT_SATURATION,         ///< Peak is probably saturated
    3738    PM_PEAK_UNDEF                       ///< Undefined.
    3839} pmPeakType;
     
    4546 *  associated with the source:
    4647 *
     48 *  There are 3 values which define the amplitude of the peak and which may be used to sort the
     49 *  peaks:
     50 *  * detValue - the peak in the detection image (nominally, the S/N)
     51 *  * rawFlux - the peak in the unsmoothed image
     52 *  * smoothFlux - the peak in the smoothed image
     53 *
     54 *  For a given image, peaks do necesarily not have the same sequence for these three values.
     55 *  Depending on the analysis, it may make sense to sort by one or the other of these values
    4756 */
    4857typedef struct
     
    5564    float dx;                           ///< bicube fit error on peak coord (x)
    5665    float dy;                           ///< bicube fit error on peak coord (y)
    57     float value;                        ///< level in detection image
    58     float flux;                         ///< level in unsmoothed sci image
    59     float SN;                           ///< S/N implied by detection level
     66    float detValue;                     ///< peak flux in detection image (= S/N)
     67    float rawFlux;                      ///< peak flux in unsmoothed signal image
     68    float rawFluxStdev;                 ///< peak stdev in unsmoothed signal image
     69    float smoothFlux;                   ///< peak flux in smoothed signal image
     70    float smoothFluxStdev;              ///< peak stdev in smoothed signal image
     71    // float SNestimated;                  ///< S/N estimated from the detection image
    6072    bool assigned;                      ///< is peak assigned to a source?
    6173    pmPeakType type;                    ///< Description of peak.
     
    136148);
    137149
    138 int pmPeaksCompareAscend (const void **a, const void **b);
    139 int pmPeaksCompareDescend (const void **a, const void **b);
    140 
    141 int pmPeakSortBySN (const void **a, const void **b);
    142 int pmPeakSortByY (const void **a, const void **b);
     150int pmPeaksSortByDetValueAscend (const void **a, const void **b);
     151int pmPeaksSortByDetValueDescend (const void **a, const void **b);
     152int pmPeaksSortByRawFluxAscend (const void **a, const void **b);
     153int pmPeaksSortByRawFluxDescend (const void **a, const void **b);
     154int pmPeaksSortBySmoothFluxAscend (const void **a, const void **b);
     155int pmPeaksSortBySmoothFluxDescend (const void **a, const void **b);
    143156
    144157/// @}
  • trunk/psModules/src/objects/pmPhotObj.c

    r29004 r31153  
    6767        return false;
    6868    }
    69     if (!finite(source->peak->xf)) {
     69    if (!isfinite(source->peak->xf)) {
    7070        psError(PS_ERR_UNKNOWN, true, "NAN peak coordinate");
    7171        return false;
    7272    }
    73     if (!finite(source->peak->yf)) {
     73    if (!isfinite(source->peak->yf)) {
    7474        psError(PS_ERR_UNKNOWN, true, "NAN peak coordinate");
    7575        return false;
     
    8181        object->x  = source->peak->xf;
    8282        object->y  = source->peak->yf;
    83         object->SN = source->peak->SN;
     83        object->flux = source->peak->rawFlux;
    8484    } else {
    85         object->SN = PS_MAX(object->SN, source->peak->SN);
     85        object->flux = PS_MAX(object->flux, source->peak->rawFlux);
    8686    }
    8787    psArrayAdd (object->sources, 1, source);
     
    8989}
    9090
    91 // sort by SN (descending)
    92 int pmPhotObjSortBySN (const void **a, const void **b)
     91// sort by flux (descending)
     92int pmPhotObjSortByFlux (const void **a, const void **b)
    9393{
    9494    pmPhotObj *objA = *(pmPhotObj **)a;
    9595    pmPhotObj *objB = *(pmPhotObj **)b;
    9696
    97     psF32 fA = objA->SN;
    98     psF32 fB = objB->SN;
     97    psF32 fA = objA->flux;
     98    psF32 fB = objB->flux;
    9999
    100100    psF32 diff = fA - fB;
  • trunk/psModules/src/objects/pmPhotObj.h

    r29004 r31153  
    3434    float x;
    3535    float y;
    36     float SN;                           // max of peak->SN for all matched sources
     36    float flux;                         // max of peak->rawFlux for all matched sources
    3737} pmPhotObj;
    3838
     
    4141bool pmPhotObjAddSource(pmPhotObj *object, pmSource *source);
    4242
    43 int pmPhotObjSortBySN (const void **a, const void **b);
     43int pmPhotObjSortByFlux (const void **a, const void **b);
    4444int pmPhotObjSortByX (const void **a, const void **b);
    4545
  • trunk/psModules/src/objects/pmSource.c

    r30621 r31153  
    171171    // peak has the same values as the original
    172172    if (in->peak != NULL) {
    173         source->peak = pmPeakAlloc (in->peak->x, in->peak->y, in->peak->value, in->peak->type);
     173        source->peak = pmPeakAlloc (in->peak->x, in->peak->y, in->peak->detValue, in->peak->type);
    174174        source->peak->xf = in->peak->xf;
    175175        source->peak->yf = in->peak->yf;
    176         source->peak->flux = in->peak->flux;
    177         source->peak->SN = in->peak->SN;
     176        source->peak->rawFlux         = in->peak->rawFlux;
     177        source->peak->rawFluxStdev    = in->peak->rawFluxStdev;
     178        source->peak->smoothFlux      = in->peak->smoothFlux;
     179        source->peak->smoothFluxStdev = in->peak->smoothFluxStdev;
     180        // source->peak->SN = in->peak->SN;
    178181    }
    179182
     
    328331*****************************************************************************/
    329332
    330 // XXX EAM include a S/N cutoff in selecting the sources?
    331 // XXX this function should probably accept the values, not a recipe. wrap with a
    332 // psphot-specific function which applies the recipe values
    333 // only apply selection to sources within specified region
    334333pmPSFClump pmSourcePSFClump(psImage **savedImage, psRegion *region, psArray *sources, float PSF_SN_LIM, float PSF_CLUMP_GRID_SCALE, psF32 SX_MAX, psF32 SY_MAX, psF32 AR_MAX)
    335334{
     
    429428
    430429        psfClump.nSigma = stats->sampleStdev;
     430        psfClump.nTotal = nValid;
    431431
    432432        if (savedImage) {
     
    465465        psStats *stats  = NULL;
    466466
    467         // select the single highest peak
    468         psArraySort (peaks, pmPeaksCompareDescend);
     467        // select the single highest peak (note that we only have detValue, not rawFlux, etc
     468        psArraySort (peaks, pmPeaksSortByDetValueDescend);
    469469        clump = peaks->data[0];
    470         psTrace ("psModules.objects", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->value);
     470        psTrace ("psModules.objects", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->detValue);
    471471
    472472        // XXX store the mean sigma?
    473473        float meanSigma = psfClump.nSigma;
    474         psfClump.nStars = clump->value;
    475         psfClump.nSigma = clump->value / meanSigma;
     474        psfClump.nStars = clump->detValue;
     475        psfClump.nSigma = clump->detValue / meanSigma;
    476476
    477477        // define section window for clump
     
    643643            }
    644644
     645            // check for insignificant sources or excessively low-surface brightness
     646            float coreSN = source->moments->KronCore / source->moments->KronCoreErr;
     647            float coreKR = source->moments->KronCore / source->moments->KronFlux;
     648
     649            // XXX these values need to be in the recipe...
     650            if (false && isfinite(coreSN) && (coreSN < 5.0)) {
     651                source->type = PM_SOURCE_TYPE_DEFECT;
     652                source->mode |= PM_SOURCE_MODE_DEFECT;
     653                Ncr ++;
     654                continue;
     655            }
     656            if (false && isfinite(coreKR) && (coreKR < 0.1)) {
     657                source->type = PM_SOURCE_TYPE_DEFECT;
     658                source->mode |= PM_SOURCE_MODE_DEFECT;
     659                Ncr ++;
     660                continue;
     661            }
     662
    645663            // likely unsaturated extended source (too large to be stellar)
    646664            if (sigX > clump.X + 3*clump.dX || sigY > clump.Y + 3*clump.dY) {
     
    651669
    652670            // the rest are probable stellar objects
     671            // the vectors below are accumulated to give user feedback on the S/N ranges
    653672            starsn_moments->data.F32[starsn_moments->n] = source->moments->SN;
    654673            starsn_moments->n ++;
    655             starsn_peaks->data.F32[starsn_peaks->n] = source->peak->SN;
     674            starsn_peaks->data.F32[starsn_peaks->n] = sqrt(source->peak->detValue);
    656675            starsn_peaks->n ++;
    657676            Nstar ++;
     
    11491168}
    11501169
     1170// this function decides if the source position should be based on the peak or the moments.
     1171// this is only used if we know we should not use a model fit position (eg, no model, or no
     1172// model yet)
     1173bool pmSourcePositionUseMoments(pmSource *source) {
     1174
     1175    if (!source->moments) return false;          // can't if there are no moments
     1176    if (!source->moments->nPixels) return false; // can't if the moments were not measured
     1177    if (source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE) return false; // can't if the moments failed...
     1178
     1179    if (source->mode & PM_SOURCE_MODE_SATSTAR) return true; // moments are best for SATSTARs
     1180
     1181    float dX = source->moments->Mx - source->peak->xf;
     1182    float dY = source->moments->My - source->peak->yf;
     1183    float dR = hypot(dX, dY);
     1184   
     1185    // only use the moments position if the moment-peak offset is small or the star is saturated
     1186    if (dR > 1.5) return false;
     1187
     1188    return true;
     1189}
     1190
    11511191// sort by SN (descending)
    1152 int pmSourceSortBySN (const void **a, const void **b)
     1192int pmSourceSortByFlux (const void **a, const void **b)
    11531193{
    11541194    pmSource *A = *(pmSource **)a;
    11551195    pmSource *B = *(pmSource **)b;
    11561196
    1157     psF32 fA = (A->peak == NULL) ? 0 : A->peak->SN;
    1158     psF32 fB = (B->peak == NULL) ? 0 : B->peak->SN;
     1197    psF32 fA = (A->peak == NULL) ? 0 : A->peak->rawFlux;
     1198    psF32 fB = (B->peak == NULL) ? 0 : B->peak->rawFlux;
    11591199    if (isnan (fA)) fA = 0;
    11601200    if (isnan (fB)) fB = 0;
     
    11661206}
    11671207
     1208// sort by SN (descending)
     1209int pmSourceSortByParentFlux (const void **a, const void **b)
     1210{
     1211    pmSource *Ao = *(pmSource **)a;
     1212    pmSource *Bo = *(pmSource **)b;
     1213    pmSource *A  = Ao->parent;
     1214    pmSource *B  = Bo->parent;
     1215
     1216    psF32 fA = (A->peak == NULL) ? 0 : A->peak->rawFlux;
     1217    psF32 fB = (B->peak == NULL) ? 0 : B->peak->rawFlux;
     1218    if (isnan (fA)) fA = 0;
     1219    if (isnan (fB)) fB = 0;
     1220
     1221    psF32 diff = fA - fB;
     1222    if (diff > FLT_EPSILON) return (-1);
     1223    if (diff < FLT_EPSILON) return (+1);
     1224    return (0);
     1225}
     1226
    11681227// sort by Y (ascending)
    11691228int pmSourceSortByY (const void **a, const void **b)
     
    12011260    pmSource *A = *(pmSource **)a;
    12021261    pmSource *B = *(pmSource **)b;
     1262
     1263    int iA = A->seq;
     1264    int iB = B->seq;
     1265
     1266    int diff = iA - iB;
     1267    if (diff > 0) return (+1);
     1268    if (diff < 0) return (-1);
     1269    return (0);
     1270}
     1271
     1272// sort by Seq (ascending)
     1273int pmSourceSortByParentSeq (const void **a, const void **b)
     1274{
     1275    pmSource *Ao = *(pmSource **)a;
     1276    pmSource *Bo = *(pmSource **)b;
     1277    pmSource *A  = Ao->parent;
     1278    pmSource *B  = Bo->parent;
    12031279
    12041280    int iA = A->seq;
  • trunk/psModules/src/objects/pmSource.h

    r30621 r31153  
    121121    float dY;
    122122    int nStars;
     123    int nTotal;
    123124    float nSigma;
    124125}
     
    286287bool pmSourceCachePSF (pmSource *source, psImageMaskType maskVal);
    287288
    288 int  pmSourceSortBySN (const void **a, const void **b);
     289bool pmSourcePositionUseMoments(pmSource *source);
     290
    289291int  pmSourceSortByY (const void **a, const void **b);
    290292int  pmSourceSortByX (const void **a, const void **b);
    291293int  pmSourceSortBySeq (const void **a, const void **b);
     294int  pmSourceSortByParentSeq (const void **a, const void **b);
     295int  pmSourceSortByFlux (const void **a, const void **b);
     296int  pmSourceSortByParentFlux (const void **a, const void **b);
    292297
    293298pmSourceMode pmSourceModeFromString (const char *name);
  • trunk/psModules/src/objects/pmSourceExtendedPars.c

    r30621 r31153  
    5555    psFree(radial->flux);
    5656    psFree(radial->fluxErr);
     57    psFree(radial->fluxStdev);
    5758    psFree(radial->fill);
    5859}
     
    6566    radial->flux = NULL;
    6667    radial->fluxErr = NULL;
     68    radial->fluxStdev = NULL;
    6769    radial->fill = NULL;
    6870    return radial;
  • trunk/psModules/src/objects/pmSourceExtendedPars.h

    r28013 r31153  
    2323typedef struct {
    2424    psVector *flux;                     // fluxes measured at above radii
     25    psVector *fluxStdev;                // scatter (standard deviation) of flux
    2526    psVector *fluxErr;                  // formal error on the fluxes (sqrt\sum(variance))
    2627    psVector *fill;                     // angles corresponding to above radial profiles
     
    6364    float petrosianR50;
    6465    float petrosianR50Err;
     66    float petrosianFill;
    6567} pmSourceExtendedPars;
    6668
  • trunk/psModules/src/objects/pmSourceFitModel.c

    r29004 r31153  
    4040#include "pmSourceDiffStats.h"
    4141#include "pmSource.h"
     42#include "pmSourcePhotometry.h"
    4243#include "pmSourceFitModel.h"
    4344
     
    5960    opt->maxChisqDOF = NAN;
    6061    opt->poissonErrors = true;
     62    opt->saveCovariance = false;
    6163
    6264    return opt;
     
    231233        psTrace ("psModules.objects", 4, "%f +/- %f", params->data.F32[i], dparams->data.F32[i]);
    232234    }
     235    if (options->saveCovariance) {
     236        model->covar = psMemIncrRefCounter(covar);
     237    }
     238    model->nIter = myMin->iter;
     239    model->nPar = nParams;
     240
    233241    psTrace ("psModules.objects", 4, "niter: %d, chisq: %f", myMin->iter, myMin->value);
    234242
    235243    // save the resulting chisq, nDOF, nIter
    236     model->chisq = myMin->value;
    237     model->nIter = myMin->iter;
    238     model->nPix  = y->n;
    239     model->nDOF  = y->n - nParams;
    240     model->chisqNorm = model->chisq / model->nDOF;
     244    // NOTE: if (!options->poissonErrors) chisq will be wrong : recalculate
     245    if (options->poissonErrors) {
     246        model->chisq = myMin->value;
     247        model->nPix  = y->n;
     248        model->nDOF  = y->n - model->nPar;
     249        model->chisqNorm = model->chisq / model->nDOF;
     250    } else {
     251        pmSourceChisqUnsubtracted (source, model, maskVal);
     252    }
     253
     254    // set the model success or failure status
    241255    model->flags |= PM_MODEL_STATUS_FITTED;
    242256    if (!fitStatus) model->flags |= PM_MODEL_STATUS_NONCONVERGE;
  • trunk/psModules/src/objects/pmSourceFitModel.h

    r29004 r31153  
    3131    float maxChisqDOF;                  ///< convergence criterion
    3232    float weight;                       ///< use this weight for constant-weight fits
     33    float covarFactor;                  ///< covariance factor for calculating the chisq
    3334    bool poissonErrors;                 ///< use poisson errors for fits?
     35    bool saveCovariance;
    3436} pmSourceFitOptions;
    3537
  • trunk/psModules/src/objects/pmSourceFitPCM.c

    r30621 r31153  
    3838#include "pmSourceDiffStats.h"
    3939#include "pmSource.h"
     40#include "pmSourcePhotometry.h"
    4041#include "pmSourceFitModel.h"
    4142#include "pmPCMdata.h"
     
    7071        psTrace ("psModules.objects", 4, "%f +/- %f", params->data.F32[i], dparams->data.F32[i]);
    7172    }
     73    if (fitOptions->saveCovariance) {
     74        psFree(pcm->modelConv->covar);
     75        pcm->modelConv->covar = psMemIncrRefCounter(covar);
     76    }
    7277    psTrace ("psphot", 4, "niter: %d, chisq: %f", myMin->iter, myMin->value);
    7378
     
    7984        }
    8085    }
     86    pcm->modelConv->nIter = myMin->iter;
     87    pcm->modelConv->nPar = pcm->nPar;
    8188
    8289    // save the resulting chisq, nDOF, nIter
    83     pcm->modelConv->chisq = myMin->value;
    84     pcm->modelConv->nIter = myMin->iter;
    85     pcm->modelConv->nPix = pcm->nPix;
    86     pcm->modelConv->nDOF = pcm->nDOF;
    87     pcm->modelConv->chisqNorm = pcm->modelConv->chisq / pcm->modelConv->nDOF;
     90    if (fitOptions->poissonErrors) {
     91        pcm->modelConv->chisq = myMin->value;
     92        pcm->modelConv->nPix = pcm->nPix;
     93        pcm->modelConv->nDOF = pcm->nDOF;
     94        pcm->modelConv->chisqNorm = pcm->modelConv->chisq / pcm->modelConv->nDOF;
     95    } else {
     96        // xxx this is wrong because it does not convolve with the psf
     97        pmSourceChisqUnsubtracted (source, pcm->modelConv, maskVal);
     98    }
     99
     100    // set the model success or failure status
    88101    pcm->modelConv->flags |= PM_MODEL_STATUS_FITTED;
    89102    if (!fitStatus) pcm->modelConv->flags |= PM_MODEL_STATUS_NONCONVERGE;
  • trunk/psModules/src/objects/pmSourceFitSet.c

    r29004 r31153  
    3939#include "pmSourceDiffStats.h"
    4040#include "pmSource.h"
     41#include "pmSourcePhotometry.h"
    4142
    4243#include "pmSourceFitModel.h"
     
    296297
    297298// set the model parameters for this fit set
    298 bool pmSourceFitSetValues (pmSourceFitSetData *set, const psVector *dparam,
    299                            const psVector *param, pmSource *source,
    300                            psMinimization *myMin, int nPix, bool fitStatus)
     299bool pmSourceFitSetValues (pmSourceFitSetData *set,
     300                           const psVector *dparam, const psVector *param, const psImage *covar,
     301                           pmSource *source, psMinimization *myMin, int nPix,
     302                           bool fitStatus, pmSourceFitOptions *options, psImageMaskType maskVal)
    301303{
    302304    PS_ASSERT_PTR_NON_NULL(set, false);
     
    311313
    312314    int n = 0;
     315    int nStart = 0;
    313316    for (int i = 0; i < set->paramSet->n; i++) {
    314317
     
    320323            psTrace ("psModules.objects", 4, "%f +/- %f", param->data.F32[n], dparam->data.F32[n]);
    321324        }
     325        if (options->saveCovariance) {
     326            // we only save the covar matrix for this object with itself (ignore cross terms between objects)
     327            model->covar = psImageAlloc(model->params->n, model->params->n, PS_TYPE_F32);
     328            for (int ix = 0; ix < model->params->n; ix++) {
     329                for (int iy = 0; iy < model->params->n; iy++) {
     330                    model->covar->data.F32[iy][ix] = covar->data.F32[nStart+iy][nStart+ix];
     331                }
     332            }
     333        }
     334        nStart += model->params->n;
    322335        psTrace ("psModules.objects", 4, " src %d", i);
     336
     337        model->nIter = myMin->iter;
     338        // model->nPar is set by pmSourceFitSetMasks
    323339
    324340        // save the resulting chisq, nDOF, nIter
    325341        // these are not unique for any one source
    326         model->chisq = myMin->value;
    327         model->nIter = myMin->iter;
    328         model->nDOF  = nPix - model->params->n;
     342        if (options->poissonErrors) {
     343            model->chisq = myMin->value;
     344            model->nPix  = nPix;
     345            model->nDOF  = nPix - model->nPar;
     346            model->chisqNorm = model->chisq / model->nDOF;
     347        } else {
     348            pmSourceChisqUnsubtracted (source, model, maskVal);
     349        }
    329350
    330351        // set the model success or failure status
     
    380401    for (int i = 0; i < set->paramSet->n; i++) {
    381402        psVector *paramOne = set->paramSet->data[i];
     403        pmModel  *modelOne = set->modelSet->data[i];
    382404
    383405        switch (mode) {
     
    387409                if (j == PM_PAR_I0) continue;
    388410                constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n + j] = 1;
     411                modelOne->nPar = 1;
    389412            }
    390413            break;
     
    396419                if (j == PM_PAR_I0) continue;
    397420                constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n + j] = 1;
     421                modelOne->nPar = 3;
    398422            }
    399423            break;
     
    401425            // EXT model fits all params (except sky)
    402426            constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n + PM_PAR_SKY] = 1;
     427            modelOne->nPar = paramOne->n - 1;
    403428            break;
    404429          default:
     
    550575    }
    551576
    552 // parameter errors from the covariance matrix
     577    // parameter errors from the covariance matrix
    553578    psVector *dparams = psVectorAlloc (thisSet->nParamSet, PS_TYPE_F32);
    554579    for (int i = 0; i < dparams->n; i++) {
     
    558583    }
    559584
    560 // get the Gauss-Newton distance for fixed model parameters
     585    // get the Gauss-Newton distance for fixed model parameters
    561586    if (constraint->paramMask != NULL) {
    562587        psVector *delta = psVectorAlloc (params->n, PS_TYPE_F32);
     
    580605    }
    581606
    582     pmSourceFitSetValues (thisSet, dparams, params, source, myMin, y->n, fitStatus);
     607    pmSourceFitSetValues (thisSet, dparams, params, covar, source, myMin, y->n, fitStatus, options, maskVal);
    583608    psTrace ("psModules.objects", 5, "onPic: %d, fitStatus: %d, nIter: %d, chisq: %f, nPix: %ld\n", onPic, fitStatus, myMin->iter, myMin->value, y->n);
    584609
  • trunk/psModules/src/objects/pmSourceFitSet.h

    r29004 r31153  
    4040bool pmSourceFitSetJoin (psVector *deriv, psVector *param, pmSourceFitSetData *set);
    4141bool pmSourceFitSetSplit (pmSourceFitSetData *set, const psVector *deriv, const psVector *param);
    42 bool pmSourceFitSetValues (pmSourceFitSetData *set, const psVector *dparam, const psVector *param, pmSource *source, psMinimization *myMin, int nPix, bool fitStatus);
     42
     43bool pmSourceFitSetValues (pmSourceFitSetData *set,
     44                           const psVector *dparam, const psVector *param, const psImage *covar,
     45                           pmSource *source, psMinimization *myMin, int nPix,
     46                           bool fitStatus, pmSourceFitOptions *options, psImageMaskType maskVal);
    4347
    4448psF32 pmSourceFitSetFunction(psVector *deriv, const psVector *param, const psVector *x);
     
    5761    psArray *modelSet,                  ///< model to be fitted
    5862    pmSourceFitOptions *options,        ///< define options for fitting process
    59     psImageMaskType maskVal             ///< Vale to mask
     63    psImageMaskType maskVal             ///< Value to mask
    6064
    6165);
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c

    r30621 r31153  
    4949
    5050#include "pmSourceIO.h"
     51#include "pmSourceOutputs.h"
    5152
    5253// panstarrs-style FITS table output (header + table in 1st extension)
     
    6263    PS_ASSERT_PTR_NON_NULL(extname, false);
    6364
    64     int i;
    6565    psArray *table;
    6666    psMetadata *row;
    67     psF32 *PAR, *dPAR;
    68     psEllipseAxes axes;
    69     psF32 xPos, yPos;
    70     psF32 xErr, yErr;
    71     psF32 errMag, chisq, apRadius;
    72     psS32 nPix, nDOF;
    7367
    7468    pmChip *chip = readout->parent->parent;
    75     pmFPA  *fpa  = chip->parent;
    76 
    77     bool status1 = false;
    78     bool status2 = false;
    79     float magOffset = NAN;
    80     float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
    81     float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
    82     if (!isfinite(zeropt)) {
    83         zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
    84     }
    85     if (status1 && status2 && (exptime > 0.0)) {
    86         magOffset = zeropt + 2.5*log10(exptime);
    87     }
    88     float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
     69
    8970
    9071    // if the sequence is defined, write these in seq order; otherwise
     
    9475        if (source->seq == -1) {
    9576          // let's write these out in S/N order
    96           sources = psArraySort (sources, pmSourceSortBySN);
     77          sources = psArraySort (sources, pmSourceSortByFlux);
    9778        } else {
    9879          sources = psArraySort (sources, pmSourceSortBySeq);
     
    10081    }
    10182
     83    short nImageOverlap;
     84    float magOffset;
     85    float zeroptErr;
     86    float fwhmMajor;
     87    float fwhmMinor;
     88    pmSourceOutputsCommonValues (&nImageOverlap, &magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader);
     89
    10290    table = psArrayAllocEmpty (sources->n);
    10391
    10492    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
    10593    // by the time we call this function, all values should be assigned.  let's use asserts to be sure in some cases.
    106     for (i = 0; i < sources->n; i++) {
     94    for (int i = 0; i < sources->n; i++) {
    10795        pmSource *source = (pmSource *) sources->data[i];
    10896
     
    115103        }
    116104
    117         // no difference between PSF and non-PSF model
    118         pmModel *model = source->modelPSF;
    119 
    120         if (model != NULL) {
    121             PAR = model->params->data.F32;
    122             dPAR = model->dparams->data.F32;
    123             xPos = PAR[PM_PAR_XPOS];
    124             yPos = PAR[PM_PAR_YPOS];
    125             if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
    126               xErr = dPAR[PM_PAR_XPOS];
    127               yErr = dPAR[PM_PAR_YPOS];
    128             } else {
    129               // in linear-fit mode, there is no error on the centroid
    130               xErr = source->peak->dx;
    131               yErr = source->peak->dy;
    132             }
    133             if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
    134                 axes = pmPSF_ModelToAxes (PAR, 20.0);
    135             } else {
    136                 axes.major = NAN;
    137                 axes.minor = NAN;
    138                 axes.theta = NAN;
    139             }
    140             chisq = model->chisq;
    141             nDOF = model->nDOF;
    142             nPix = model->nPix;
    143             apRadius = source->apRadius;
    144             errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
    145         } else {
    146             xPos = source->peak->xf;
    147             yPos = source->peak->yf;
    148             xErr = source->peak->dx;
    149             yErr = source->peak->dy;
    150             axes.major = NAN;
    151             axes.minor = NAN;
    152             axes.theta = NAN;
    153             chisq = NAN;
    154             nDOF = 0;
    155             nPix = 0;
    156             apRadius = NAN;
    157             errMag = NAN;
    158         }
    159 
    160         float calMag = isfinite(magOffset) ? source->psfMag + magOffset : NAN;
    161         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
    162         psS16 nImageOverlap = 1;
    163 
    164         psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
    165         float posAngle = 0.0;
    166         float pltScale = 0.0;
    167         pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);
     105        // set the 'best' values for various output fields:
     106        pmSourceOutputs outputs;
     107        pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset);
     108
     109        pmSourceOutputsMoments moments;
     110        pmSourceOutputsSetMoments (&moments, source);
    168111
    169112        pmSourceDiffStats diffStats;
     
    175118        row = psMetadataAlloc ();
    176119        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
    177         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           xPos);
    178         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           yPos);
    179         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  xErr); // XXX this is only measured for non-linear fits
    180         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr); // XXX this is only measured for non-linear fits
    181         psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         posAngle*PS_DEG_RAD);
    182         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       pltScale*PS_DEG_RAD*3600.0);
     120        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           outputs.xPos);
     121        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           outputs.yPos);
     122        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  outputs.xErr); // XXX this is only measured for non-linear fits
     123        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  outputs.yErr); // XXX this is only measured for non-linear fits
     124        psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         outputs.posAngle);
     125        psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
    183126        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
    184         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        errMag);
     127        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
    185128        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfFlux);
    186129        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfFluxErr);
    187130        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
    188         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
    189         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
    190         psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   calMag);
     131        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              outputs.apRadius);
     132        psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           outputs.peakMag);
     133        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   outputs.calMag);
    191134        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);
    192         psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                ptSky.r*PS_DEG_RAD);
    193         psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               ptSky.d*PS_DEG_RAD);
     135        psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                outputs.ra);
     136        psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               outputs.dec);
    194137        psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
    195138        psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",                         source->skyErr);
    196139
    197         psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           chisq);
     140        psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           outputs.chisq);
    198141        psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA",        PS_DATA_F32, "Nsigma deviations from PSF to CF",           source->crNsigma);
    199142        psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA",       PS_DATA_F32, "Nsigma deviations from PSF to EXT",          source->extNsigma);
    200143
    201         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     axes.major);
    202         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
    203         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
     144        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     outputs.psfMajor);
     145        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     outputs.psfMinor);
     146        psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      outputs.psfTheta);
    204147        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
    205         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
    206         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
    207 
    208         // distinguish moments measure from window vs S/N > XX ??
    209         float mxx = source->moments ? source->moments->Mxx : NAN;
    210         float mxy = source->moments ? source->moments->Mxy : NAN;
    211         float myy = source->moments ? source->moments->Myy : NAN;
    212         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      mxx);
    213         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      mxy);
    214         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      myy);
    215 
    216         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NPOS",        PS_DATA_S32, "nPos (n pix > 3 sigma)",                    diffStats.nGood);
    217         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_FRATIO",      PS_DATA_F32, "fPos / (fPos + fNeg)",                      diffStats.fRatio);
    218         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_BAD",  PS_DATA_F32, "nPos / (nPos + nNeg)",                      diffStats.nRatioBad);
    219         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_MASK", PS_DATA_F32, "nPos / (nPos + nMask)",                     diffStats.nRatioMask);
    220         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_ALL",  PS_DATA_F32, "nPos / (nGood + nMask + nBad)",             diffStats.nRatioAll);
     148        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         outputs.nDOF);
     149        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    outputs.nPix);
     150
     151        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                       moments.Mxx);
     152        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                       moments.Mxy);
     153        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                       moments.Myy);
     154
     155        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NPOS",        PS_DATA_S32, "nPos (n pix > 3 sigma)",                     diffStats.nGood);
     156        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_FRATIO",      PS_DATA_F32, "fPos / (fPos + fNeg)",                       diffStats.fRatio);
     157        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_BAD",  PS_DATA_F32, "nPos / (nPos + nNeg)",                       diffStats.nRatioBad);
     158        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_MASK", PS_DATA_F32, "nPos / (nPos + nMask)",                      diffStats.nRatioMask);
     159        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_ALL",  PS_DATA_F32, "nPos / (nGood + nMask + nBad)",              diffStats.nRatioAll);
    221160
    222161        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                      source->mode);
     
    331270        // recreate the peak to match (xPos, yPos) +/- (xErr, yErr)
    332271        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    333         source->peak->flux = peakFlux;
     272        source->peak->rawFlux = peakFlux;
     273        source->peak->smoothFlux = peakFlux;
    334274        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
    335275        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
    336276        source->peak->dx   = dPAR[PM_PAR_XPOS];
    337277        source->peak->dy   = dPAR[PM_PAR_YPOS];
    338         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    339           source->peak->SN = 1.0 / source->errMag;
    340         } else {
    341           source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
    342         }
    343278
    344279        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
     
    353288
    354289        source->moments = pmMomentsAlloc ();
     290        source->moments->Mx = source->peak->xf; // we don't have both Mx,My and xf,yf in the cmf
     291        source->moments->My = source->peak->yf; // we don't have both Mx,My and xf,yf in the cmf
     292
    355293        source->moments->Mxx = psMetadataLookupF32 (&status, row, "MOMENTS_XX");
    356294        source->moments->Mxy = psMetadataLookupF32 (&status, row, "MOMENTS_XY");
     
    395333
    396334    // let's write these out in S/N order
    397     sources = psArraySort (sources, pmSourceSortBySN);
     335    sources = psArraySort (sources, pmSourceSortByFlux);
    398336
    399337    table = psArrayAllocEmpty (sources->n);
     
    568506
    569507    // let's write these out in S/N order
    570     sources = psArraySort (sources, pmSourceSortBySN);
     508    sources = psArraySort (sources, pmSourceSortByFlux);
    571509
    572510    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c

    r30621 r31153  
    4949
    5050#include "pmSourceIO.h"
     51#include "pmSourceOutputs.h"
    5152
    5253// panstarrs-style FITS table output (header + table in 1st extension)
     
    6263    PS_ASSERT_PTR_NON_NULL(extname, false);
    6364
    64     int i;
    6565    psArray *table;
    6666    psMetadata *row;
    67     psF32 *PAR, *dPAR;
    68     psEllipseAxes axes;
    69     psF32 xPos, yPos;
    70     psF32 xErr, yErr;
    71     psF32 chisq, apRadius;
    72     psS32 nPix, nDOF;
    7367
    7468    pmChip *chip = readout->parent->parent;
    75     pmFPA  *fpa  = chip->parent;
    76 
    77     bool status1 = false;
    78     bool status2 = false;
    79     float magOffset = NAN;
    80     float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
    81     float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
    82     if (!isfinite(zeropt)) {
    83         zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
    84     }
    85     if (status1 && status2 && (exptime > 0.0)) {
    86         magOffset = zeropt + 2.5*log10(exptime);
    87     }
    88     float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
    89 
    90     // we need a measure of the image quality (FWHM) for this image, in order to get the positional errors
    91     float fwhmMajor = psMetadataLookupF32(&status1, readout->analysis, "FWHM_MAJ");
    92     if (!status1) {
    93         fwhmMajor = psMetadataLookupF32(&status1, readout->analysis, "IQ_FW1");
    94         if (!status1) {
    95             fwhmMajor = 5.0; // XXX just a guess!
    96         }
    97     }
    98     float fwhmMinor = psMetadataLookupF32(&status1, readout->analysis, "FWHM_MIN");
    99     if (!status1) {
    100         fwhmMinor = psMetadataLookupF32(&status1, readout->analysis, "IQ_FW2");
    101         if (!status1) {
    102             fwhmMinor = 5.0; // XXX just a guess!
    103         }
    104     }
    10569
    10670    // if the sequence is defined, write these in seq order; otherwise
     
    11074        if (source->seq == -1) {
    11175          // let's write these out in S/N order
    112           sources = psArraySort (sources, pmSourceSortBySN);
     76          sources = psArraySort (sources, pmSourceSortByFlux);
    11377        } else {
    11478          sources = psArraySort (sources, pmSourceSortBySeq);
     
    11882    table = psArrayAllocEmpty (sources->n);
    11983
     84    short nImageOverlap;
     85    float magOffset;
     86    float zeroptErr;
     87    float fwhmMajor;
     88    float fwhmMinor;
     89    pmSourceOutputsCommonValues (&nImageOverlap, &magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader);
     90
    12091    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
    12192    // by the time we call this function, all values should be assigned.  let's use asserts to be sure in some cases.
    122     for (i = 0; i < sources->n; i++) {
     93    for (int i = 0; i < sources->n; i++) {
    12394        pmSource *source = (pmSource *) sources->data[i];
    12495
     
    131102        }
    132103
    133         // no difference between PSF and non-PSF model
    134         pmModel *model = source->modelPSF;
    135 
    136         if (model != NULL) {
    137             PAR = model->params->data.F32;
    138             dPAR = model->dparams->data.F32;
    139             xPos = PAR[PM_PAR_XPOS];
    140             yPos = PAR[PM_PAR_YPOS];
    141             if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
    142               xErr = dPAR[PM_PAR_XPOS];
    143               yErr = dPAR[PM_PAR_YPOS];
    144             } else {
    145               // in linear-fit mode, there is no error on the centroid
    146                 xErr = fwhmMajor * source->errMag / 2.35;
    147                 yErr = fwhmMinor * source->errMag / 2.35;
    148             }
    149             if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
    150                 axes = pmPSF_ModelToAxes (PAR, 20.0);
    151             } else {
    152                 axes.major = NAN;
    153                 axes.minor = NAN;
    154                 axes.theta = NAN;
    155             }
    156             chisq = model->chisq;
    157             nDOF = model->nDOF;
    158             nPix = model->nPix;
    159             apRadius = source->apRadius;
    160         } else {
    161             bool useMoments = true;
    162             useMoments = (useMoments && source->moments);          // can't if there are no moments
    163             useMoments = (useMoments && source->moments->nPixels); // can't if the moments were not measured
    164             useMoments = (useMoments && !(source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE)); // can't if the moments failed...
    165 
    166             if (useMoments) {
    167                 xPos = source->moments->Mx;
    168                 yPos = source->moments->My;
    169                 xErr = fwhmMajor * source->errMag / 2.35;
    170                 yErr = fwhmMinor * source->errMag / 2.35;
    171             } else {
    172                 xPos = source->peak->xf;
    173                 yPos = source->peak->yf;
    174                 xErr = source->peak->dx;
    175                 yErr = source->peak->dy;
    176             }
    177             axes.major = NAN;
    178             axes.minor = NAN;
    179             axes.theta = NAN;
    180             chisq = NAN;
    181             nDOF = 0;
    182             nPix = 0;
    183             apRadius = NAN;
    184         }
    185 
    186         float calMag = isfinite(magOffset) ? source->psfMag + magOffset : NAN;
    187         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
    188         psS16 nImageOverlap = 1;
    189 
    190         psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
    191         float posAngle = 0.0;
    192         float pltScale = 0.0;
    193         pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);
     104        // set the 'best' values for various output fields:
     105        pmSourceOutputs outputs;
     106        pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset);
     107
     108        pmSourceOutputsMoments moments;
     109        pmSourceOutputsSetMoments (&moments, source);
    194110
    195111        pmSourceDiffStats diffStats;
     
    201117        row = psMetadataAlloc ();
    202118        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
    203         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           xPos);
    204         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           yPos);
    205         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  xErr); // XXX this is only measured for non-linear fits
    206         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr); // XXX this is only measured for non-linear fits
    207         psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         posAngle*PS_DEG_RAD);
    208         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       pltScale*PS_DEG_RAD*3600.0);
     119        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           outputs.xPos);
     120        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           outputs.yPos);
     121        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  outputs.xErr); // XXX this is only measured for non-linear fits
     122        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  outputs.yErr); // XXX this is only measured for non-linear fits
     123        psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         outputs.posAngle);
     124        psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
    209125        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
    210126        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
     
    214130        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
    215131        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW",       PS_DATA_F32, "magnitude in real aperture",                 source->apMagRaw);
    216         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
     132        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              outputs.apRadius);
    217133        psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX",          PS_DATA_F32, "instrumental flux in standard aperture",     source->apFlux);
    218134        psMetadataAdd (row, PS_LIST_TAIL, "AP_FLUX_SIG",      PS_DATA_F32, "aperture flux error",                        source->apFluxErr);
    219135
    220         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
    221         psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   calMag);
     136        psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           outputs.peakMag);
     137        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   outputs.calMag);
    222138        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);
    223         psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                ptSky.r*PS_DEG_RAD);
    224         psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               ptSky.d*PS_DEG_RAD);
     139        psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                outputs.ra);
     140        psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               outputs.dec);
    225141        psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
    226142        psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",                         source->skyErr);
    227143
    228         psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           chisq);
     144        psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           outputs.chisq);
    229145        psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA",        PS_DATA_F32, "Nsigma deviations from PSF to CF",           source->crNsigma);
    230146        psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA",       PS_DATA_F32, "Nsigma deviations from PSF to EXT",          source->extNsigma);
    231147
    232         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     axes.major);
    233         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
    234         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
     148        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     outputs.psfMajor);
     149        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     outputs.psfMinor);
     150        psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      outputs.psfTheta);
    235151        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor (bad)",          source->pixWeightNotBad);
    236152        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT",   PS_DATA_F32, "PSF coverage/quality factor (poor)",         source->pixWeightNotPoor);
    237         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
    238         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
    239 
    240         // distinguish moments measure from window vs S/N > XX ??
    241         float mxx = source->moments ? source->moments->Mxx : NAN;
    242         float mxy = source->moments ? source->moments->Mxy : NAN;
    243         float myy = source->moments ? source->moments->Myy : NAN;
    244         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      mxx);
    245         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      mxy);
    246         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      myy);
    247 
    248         float Mrf  = source->moments ? source->moments->Mrf : NAN;
    249         float Mrh  = source->moments ? source->moments->Mrh : NAN;
    250         float Krf  = source->moments ? source->moments->KronFlux : NAN;
    251         float dKrf = source->moments ? source->moments->KronFluxErr : NAN;
    252 
    253         float Kinner = source->moments ? source->moments->KronFinner : NAN;
    254         float Kouter = source->moments ? source->moments->KronFouter : NAN;
    255 
    256         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",                       Mrf);
    257         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",                        Mrh);
    258         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Krf);
    259         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",                          dKrf);
    260 
    261         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 1.0 R1)",                     Kinner);
    262         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 4.0 R1)",                     Kouter);
    263 
    264         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NPOS",        PS_DATA_S32, "nPos (n pix > 3 sigma)",                    diffStats.nGood);
    265         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_FRATIO",      PS_DATA_F32, "fPos / (fPos + fNeg)",                      diffStats.fRatio);
    266         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_BAD",  PS_DATA_F32, "nPos / (nPos + nNeg)",                      diffStats.nRatioBad);
    267         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_MASK", PS_DATA_F32, "nPos / (nPos + nMask)",                     diffStats.nRatioMask);
    268         psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_ALL",  PS_DATA_F32, "nPos / (nGood + nMask + nBad)",             diffStats.nRatioAll);
     153        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         outputs.nDOF);
     154        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    outputs.nPix);
     155
     156        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                       moments.Mxx);
     157        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                       moments.Mxy);
     158        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                       moments.Myy);
     159
     160        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",                        moments.Mrf);
     161        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",                         moments.Mrh);
     162        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Krf);
     163        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",                            moments.dKrf);
     164        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 1.0 R1)",                      moments.Kinner);
     165        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 4.0 R1)",                      moments.Kouter);
     166
     167        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NPOS",        PS_DATA_S32, "nPos (n pix > 3 sigma)",                     diffStats.nGood);
     168        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_FRATIO",      PS_DATA_F32, "fPos / (fPos + fNeg)",                       diffStats.fRatio);
     169        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_BAD",  PS_DATA_F32, "nPos / (nPos + nNeg)",                       diffStats.nRatioBad);
     170        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_MASK", PS_DATA_F32, "nPos / (nPos + nMask)",                      diffStats.nRatioMask);
     171        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_ALL",  PS_DATA_F32, "nPos / (nGood + nMask + nBad)",              diffStats.nRatioAll);
    269172
    270173        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_P",         PS_DATA_F32, "distance to positive match source",          diffStats.Rp);
     
    385288        // recreate the peak to match (xPos, yPos) +/- (xErr, yErr)
    386289        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    387         source->peak->flux = peakFlux;
     290        source->peak->rawFlux = peakFlux;
     291        source->peak->smoothFlux = peakFlux;
    388292        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
    389293        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
    390294        source->peak->dx   = dPAR[PM_PAR_XPOS];
    391295        source->peak->dy   = dPAR[PM_PAR_YPOS];
    392         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    393           source->peak->SN = 1.0 / source->errMag;
    394         } else {
    395           source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
    396         }
    397296
    398297        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
     
    408307
    409308        source->moments = pmMomentsAlloc ();
     309        source->moments->Mx = source->peak->xf; // we don't have both Mx,My and xf,yf in the cmf
     310        source->moments->My = source->peak->yf; // we don't have both Mx,My and xf,yf in the cmf
     311
    410312        source->moments->Mxx = psMetadataLookupF32 (&status, row, "MOMENTS_XX");
    411313        source->moments->Mxy = psMetadataLookupF32 (&status, row, "MOMENTS_XY");
     
    456358
    457359    // let's write these out in S/N order
    458     sources = psArraySort (sources, pmSourceSortBySN);
     360    sources = psArraySort (sources, pmSourceSortByFlux);
    459361
    460362    table = psArrayAllocEmpty (sources->n);
     
    629531
    630532    // let's write these out in S/N order
    631     sources = psArraySort (sources, pmSourceSortBySN);
     533    sources = psArraySort (sources, pmSourceSortByFlux);
    632534
    633535    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c

    r30621 r31153  
    5050
    5151#include "pmSourceIO.h"
     52#include "pmSourceOutputs.h"
    5253
    5354// panstarrs-style FITS table output (header + table in 1st extension)
     
    6667    psArray *table;
    6768    psMetadata *row;
    68     psF32 *PAR, *dPAR;
    69     psEllipseAxes axes;
    70     psF32 xPos, yPos;
    71     psF32 xErr, yErr;
    72     psF32 errMag, chisq, apRadius;
    73     psS32 nPix, nDOF;
    7469
    7570    pmChip *chip = readout->parent->parent;
    76     pmFPA  *fpa  = chip->parent;
    77 
    78     bool status1 = false;
    79     bool status2 = false;
    80     float magOffset = NAN;
    81     float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
    82     float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
    83     if (!isfinite(zeropt)) {
    84         zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
    85     }
    86     if (status1 && status2 && (exptime > 0.0)) {
    87         magOffset = zeropt + 2.5*log10(exptime);
    88     }
    89     float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
    90 
    91     // if the sequence is defined, write these in seq order; otherwise
    92     // write them in S/N order:
     71
     72    // if the sequence is defined, write these in seq order; otherwise write them in S/N order.
     73    // Careful: if we are working with child sources, then we need to sort by the parent info,
     74    // not our info
    9375    if (sources->n > 0) {
    94         pmSource *source = (pmSource *) sources->data[0];
     76        pmSource *source = sources->data[0];
    9577        if (source->seq == -1) {
    96             // let's write these out in S/N order
    97             sources = psArraySort (sources, pmSourceSortBySN);
     78            sources = psArraySort (sources, pmSourceSortByFlux);
    9879        } else {
    9980            sources = psArraySort (sources, pmSourceSortBySeq);
     
    10384    table = psArrayAllocEmpty (sources->n);
    10485
    105 # if (0)
    106     // we use this just to define the output vectors (which must be present for all objects)
    107     bool status = false;
    108     psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
    109     psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
    110     psAssert (radMax, "this must have been defined and tested earlier!");
    111     psAssert (radMax->n, "this must have been defined and tested earlier!");
    112     psAssert (radMin->n == radMax->n, "inconsistent annular bins");
    113 
    114     // write the radial profile apertures to header
    115     for (int i = 0; i < radMax->n; i++) {
    116       sprintf (keyword1, "RMIN_%02d", i);
    117       sprintf (keyword2, "RMAX_%02d", i);
    118       psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);
    119       psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
    120     }
    121 # endif
     86    short nImageOverlap;
     87    float magOffset;
     88    float zeroptErr;
     89    float fwhmMajor;
     90    float fwhmMinor;
     91    pmSourceOutputsCommonValues (&nImageOverlap, &magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader);
    12292
    12393    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
    12494    // by the time we call this function, all values should be assigned.  let's use asserts to be sure in some cases.
    12595    for (int i = 0; i < sources->n; i++) {
    126         pmSource *source = (pmSource *) sources->data[i];
    127 
    128         // If source->seq is -1, source was generated in this analysis.  If source->seq is
    129         // not -1, source was read from elsewhere: in the latter case, preserve the source
    130         // ID.  source.seq is used instead of source.id since the latter is a const
    131         // generated on Alloc, and would thus be wrong for read in sources.
     96        // this is the source associated with this image
     97        pmSource *thisSource = sources->data[i];
     98
     99        // this is the "real" version of this source
     100        pmSource *source = thisSource->parent ? thisSource->parent : thisSource;
     101
     102        // If source->seq is -1, source is unique and generated in this analysis.  If
     103        // source->seq is not -1, source was read from elsewhere or tied to other source (eg
     104        // from another image): in the latter case, preserve the source ID.  source.seq is used
     105        // instead of source.id since the latter is a const generated on Alloc, and would thus
     106        // be wrong for read in sources.
    132107        if (source->seq == -1) {
    133108            source->seq = i;
    134109        }
    135110
    136         // no difference between PSF and non-PSF model
    137         pmModel *model = source->modelPSF;
    138 
    139         if (model != NULL) {
    140             PAR = model->params->data.F32;
    141             dPAR = model->dparams->data.F32;
    142             xPos = PAR[PM_PAR_XPOS];
    143             yPos = PAR[PM_PAR_YPOS];
    144             if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
    145                 xErr = dPAR[PM_PAR_XPOS];
    146                 yErr = dPAR[PM_PAR_YPOS];
    147             } else {
    148                 // in linear-fit mode, there is no error on the centroid
    149                 xErr = source->peak->dx;
    150                 yErr = source->peak->dy;
    151             }
    152             if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
    153                 axes = pmPSF_ModelToAxes (PAR, 20.0);
    154             } else {
    155                 axes.major = NAN;
    156                 axes.minor = NAN;
    157                 axes.theta = NAN;
    158             }
    159             chisq = model->chisq;
    160             nDOF = model->nDOF;
    161             nPix = model->nPix;
    162             apRadius = source->apRadius;
    163             errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
    164         } else {
    165             xPos = source->peak->xf;
    166             yPos = source->peak->yf;
    167             xErr = source->peak->dx;
    168             yErr = source->peak->dy;
    169             axes.major = NAN;
    170             axes.minor = NAN;
    171             axes.theta = NAN;
    172             chisq = NAN;
    173             nDOF = 0;
    174             nPix = 0;
    175             apRadius = NAN;
    176             errMag = NAN;
    177         }
    178 
    179         float calMag = isfinite(magOffset) ? source->psfMag + magOffset : NAN;
    180         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
    181         psS16 nImageOverlap = 1;
    182 
    183         psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
    184         float posAngle = 0.0;
    185         float pltScale = 0.0;
    186         pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);
     111        // set the 'best' values for various output fields:
     112        pmSourceOutputs outputs;
     113        pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset);
     114
     115        pmSourceOutputsMoments moments;
     116        pmSourceOutputsSetMoments (&moments, source);
    187117
    188118        row = psMetadataAlloc ();
    189119        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
    190         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           xPos);
    191         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           yPos);
    192         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  xErr); // XXX this is only measured for non-linear fits
    193         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr); // XXX this is only measured for non-linear fits
    194         psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         posAngle*PS_DEG_RAD);
    195         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       pltScale*PS_DEG_RAD*3600.0);
     120        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           outputs.xPos);
     121        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           outputs.yPos);
     122        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  outputs.xErr);
     123        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  outputs.yErr);
     124        psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         outputs.posAngle);
     125        psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
    196126        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
    197         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        errMag);
     127        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
    198128        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental flux (counts)",         source->psfFlux);
    199129        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental flux",             source->psfFluxErr);
    200130        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
    201131        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW",       PS_DATA_F32, "magnitude in reported aperture",             source->apMagRaw);
    202         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
    203         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
    204         psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   calMag);
     132        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              outputs.apRadius);
     133        psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           outputs.peakMag);
     134        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   outputs.calMag);
    205135        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);
    206         psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                ptSky.r*PS_DEG_RAD);
    207         psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               ptSky.d*PS_DEG_RAD);
     136        psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                outputs.ra);
     137        psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               outputs.dec);
    208138        psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
    209139        psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",                         source->skyErr);
    210140
    211         psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           chisq);
     141        psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           outputs.chisq);
    212142        psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA",        PS_DATA_F32, "Nsigma deviations from PSF to CF",           source->crNsigma);
    213143        psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA",       PS_DATA_F32, "Nsigma deviations from PSF to EXT",          source->extNsigma);
    214144
    215         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     axes.major);
    216         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
    217         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
     145        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     outputs.psfMajor);
     146        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     outputs.psfMinor);
     147        psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      outputs.psfTheta);
    218148        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor (bad)",          source->pixWeightNotBad);
    219149        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT",   PS_DATA_F32, "PSF coverage/quality factor (poor)",         source->pixWeightNotPoor);
    220         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
    221         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
    222 
    223         // distinguish moments measure from window vs S/N > XX ??
    224         float Mxx = source->moments ? source->moments->Mxx : NAN;
    225         float Mxy = source->moments ? source->moments->Mxy : NAN;
    226         float Myy = source->moments ? source->moments->Myy : NAN;
    227 
    228         float Mrf  = source->moments ? source->moments->Mrf : NAN;
    229         float Mrh  = source->moments ? source->moments->Mrh : NAN;
    230         float Krf  = source->moments ? source->moments->KronFlux : NAN;
    231         float dKrf = source->moments ? source->moments->KronFluxErr : NAN;
    232 
    233         float Kinner = source->moments ? source->moments->KronFinner : NAN;
    234         float Kouter = source->moments ? source->moments->KronFouter : NAN;
    235 
    236         float M_c3 = source->moments ? 1.0*source->moments->Mxxx - 3.0*source->moments->Mxyy : NAN;
    237         float M_s3 = source->moments ? 3.0*source->moments->Mxxy - 1.0*source->moments->Myyy : NAN;
    238         float M_c4 = source->moments ? 1.0*source->moments->Mxxxx - 6.0*source->moments->Mxxyy + 1.0*source->moments->Myyyy : NAN;
    239         float M_s4 = source->moments ? 4.0*source->moments->Mxxxy - 4.0*source->moments->Mxyyy : NAN;
    240 
    241         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      Mxx);
    242         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      Mxy);
    243         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      Myy);
    244 
    245         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3C",      PS_DATA_F32, "third momemt cos theta",                    M_c3);
    246         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3S",      PS_DATA_F32, "third momemt sin theta",                    M_s3);
    247         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4C",      PS_DATA_F32, "fourth momemt cos theta",                   M_c4);
    248         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4S",      PS_DATA_F32, "fourth momemt sin theta",                   M_s4);
    249 
    250         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",                       Mrf);
    251         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",                        Mrh);
    252         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Krf);
    253         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",                          dKrf);
    254 
    255         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Kinner);
    256         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Kouter);
     150        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         outputs.nDOF);
     151        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    outputs.nPix);
     152
     153        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                       moments.Mxx);
     154        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                       moments.Mxy);
     155        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                       moments.Myy);
     156
     157        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3C",      PS_DATA_F32, "third momemt cos theta",                     moments.M_c3);
     158        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3S",      PS_DATA_F32, "third momemt sin theta",                     moments.M_s3);
     159        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4C",      PS_DATA_F32, "fourth momemt cos theta",                    moments.M_c4);
     160        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4S",      PS_DATA_F32, "fourth momemt sin theta",                    moments.M_s4);
     161
     162        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",                        moments.Mrf);
     163        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",                         moments.Mrh);
     164        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Krf);
     165        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",                            moments.dKrf);
     166        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Kinner);
     167        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Kouter);
    257168
    258169        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                     source->mode);
    259170        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                     source->mode2);
    260 
    261 # if (0)
    262         // XXX if we have raw radial apertures, write them out here
    263         psVector *radFlux    = psVectorAlloc(radMax->n, PS_TYPE_F32);
    264         psVector *radFluxErr = psVectorAlloc(radMax->n, PS_TYPE_F32);
    265         psVector *radFill    = psVectorAlloc(radMax->n, PS_TYPE_F32);
    266         psVectorInit (radFlux,    NAN);
    267         psVectorInit (radFluxErr, NAN);
    268         psVectorInit (radFill,    NAN);
    269         if (!source->radial) goto empty_annuli;
    270         if (!source->radial->flux) goto empty_annuli;
    271         if (!source->radial->fill) goto empty_annuli;
    272         psAssert (source->radial->flux->n <= radFlux->n, "inconsistent vector lengths");
    273         psAssert (source->radial->fill->n <= radFlux->n, "inconsistent vector lengths");
    274 
    275         // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux
    276         for (int j = 0; j < source->radial->flux->n; j++) {
    277             radFlux->data.F32[j]    = source->radial->flux->data.F32[j];
    278             radFluxErr->data.F32[j] = source->radial->fluxErr->data.F32[j];
    279             radFill->data.F32[j]    = source->radial->fill->data.F32[j];
    280         }
    281 
    282     empty_annuli:
    283         psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX",     PS_DATA_VECTOR, "flux within annuli",    radFlux);
    284         psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX_ERR", PS_DATA_VECTOR, "flux error in annuli",  radFluxErr);
    285         psMetadataAdd (row, PS_LIST_TAIL, "APER_FILL",     PS_DATA_VECTOR, "fill factor of annuli", radFill);
    286         psFree (radFlux);
    287         psFree (radFluxErr);
    288         psFree (radFill);
    289 # endif
    290171
    291172        // XXX not sure how to get this : need to load Nimages with weight?
     
    406287        // recreate the peak to match (xPos, yPos) +/- (xErr, yErr)
    407288        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    408         source->peak->flux = peakFlux;
     289        source->peak->rawFlux = peakFlux;
     290        source->peak->smoothFlux = peakFlux;
    409291        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
    410292        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
    411293        source->peak->dx   = dPAR[PM_PAR_XPOS];
    412294        source->peak->dy   = dPAR[PM_PAR_YPOS];
    413         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    414           source->peak->SN = 1.0 / source->errMag;
    415         } else {
    416           source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
    417         }
    418295
    419296        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
     
    429306
    430307        source->moments = pmMomentsAlloc ();
     308        source->moments->Mx = source->peak->xf; // we don't have both Mx,My and xf,yf in the cmf
     309        source->moments->My = source->peak->yf; // we don't have both Mx,My and xf,yf in the cmf
     310
    431311        source->moments->Mxx = psMetadataLookupF32 (&status, row, "MOMENTS_XX");
    432312        source->moments->Mxy = psMetadataLookupF32 (&status, row, "MOMENTS_XY");
     
    500380
    501381    // let's write these out in S/N order
    502     sources = psArraySort (sources, pmSourceSortBySN);
     382    sources = psArraySort (sources, pmSourceSortByFlux);
    503383
    504384    table = psArrayAllocEmpty (sources->n);
     
    522402    // we write out all sources, regardless of quality.  the source flags tell us the state
    523403    for (int i = 0; i < sources->n; i++) {
    524         pmSource *source = sources->data[i];
     404        // this is the source associated with this image
     405        pmSource *thisSource = sources->data[i];
     406
     407        // this is the "real" version of this source
     408        pmSource *source = thisSource->parent ? thisSource->parent : thisSource;
    525409
    526410        // skip sources without measurements
     
    556440        }
    557441        psMetadataAdd (row, PS_LIST_TAIL, "F25_ARATIO",       PS_DATA_F32, "Axial Ratio of radial profile",              AxialRatio);
    558         psMetadataAdd (row, PS_LIST_TAIL, "F25_THETA",        PS_DATA_F32, "Angle of radial profile ellipse",                  AxialTheta);
     442        psMetadataAdd (row, PS_LIST_TAIL, "F25_THETA",        PS_DATA_F32, "Angle of radial profile ellipse",            AxialTheta);
    559443
    560444        // Petrosian measurements
     
    567451                float mag = (extpars->petrosianFlux > 0.0) ? -2.5*log10(extpars->petrosianFlux) + magOffset : NAN; // XXX zero point
    568452                float magErr = (extpars->petrosianFlux > 0.0) ? extpars->petrosianFlux / extpars->petrosianFluxErr : NAN; // XXX zero point
    569                 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG",        PS_DATA_F32, "Petrosian Magnitude", mag);
    570                 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR",    PS_DATA_F32, "Petrosian Magnitude Error", magErr);
    571                 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS",     PS_DATA_F32, "Petrosian Radius (pix)", extpars->petrosianRadius);
    572                 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error (pix)", extpars->petrosianRadiusErr);
     453                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG",           PS_DATA_F32, "Petrosian Magnitude", mag);
     454                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR",       PS_DATA_F32, "Petrosian Magnitude Error", magErr);
     455                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS",        PS_DATA_F32, "Petrosian Radius (pix)", extpars->petrosianRadius);
     456                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR",    PS_DATA_F32, "Petrosian Radius Error (pix)", extpars->petrosianRadiusErr);
    573457                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50",     PS_DATA_F32, "Petrosian R50 (pix)", extpars->petrosianR50);
    574458                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50_ERR", PS_DATA_F32, "Petrosian R50 Error (pix)", extpars->petrosianR50Err);
    575459                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90",     PS_DATA_F32, "Petrosian R90 (pix)", extpars->petrosianR90);
    576460                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90_ERR", PS_DATA_F32, "Petrosian R90 Error (pix)", extpars->petrosianR90Err);
     461                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_FILL",          PS_DATA_F32, "Petrosian Fill Factor", extpars->petrosianFill);
    577462            } else {
    578                 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG",        PS_DATA_F32, "Petrosian Magnitude",       NAN);
    579                 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR",    PS_DATA_F32, "Petrosian Magnitude Error", NAN);
    580                 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS",     PS_DATA_F32, "Petrosian Radius",          NAN);
    581                 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error",    NAN);
     463                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG",           PS_DATA_F32, "Petrosian Magnitude",       NAN);
     464                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR",       PS_DATA_F32, "Petrosian Magnitude Error", NAN);
     465                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS",        PS_DATA_F32, "Petrosian Radius",          NAN);
     466                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR",    PS_DATA_F32, "Petrosian Radius Error",    NAN);
    582467                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50",     PS_DATA_F32, "Petrosian R50 (pix)", NAN);
    583468                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50_ERR", PS_DATA_F32, "Petrosian R50 Error (pix)",NAN);
    584469                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90",     PS_DATA_F32, "Petrosian R90 (pix)", NAN);
    585470                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90_ERR", PS_DATA_F32, "Petrosian R90 Error (pix)",NAN);
     471                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_FILL",          PS_DATA_F32, "Petrosian Fill Factor", NAN);
    586472            }
    587473        }
     
    672558
    673559    // let's write these out in S/N order
    674     sources = psArraySort (sources, pmSourceSortBySN);
     560    sources = psArraySort (sources, pmSourceSortByFlux);
    675561
    676562    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
    677563    int nParamMax = 0;
    678564    for (int i = 0; i < sources->n; i++) {
    679         pmSource *source = sources->data[i];
     565        // this is the source associated with this image
     566        pmSource *thisSource = sources->data[i];
     567
     568        // this is the "real" version of this source
     569        pmSource *source = thisSource->parent ? thisSource->parent : thisSource;
     570
    680571        if (source->modelFits == NULL) continue;
    681572        for (int j = 0; j < source->modelFits->n; j++) {
     
    691582    for (int i = 0; i < sources->n; i++) {
    692583
    693         pmSource *source = sources->data[i];
     584        pmSource *thisSource = sources->data[i];
     585
     586        // this is the "real" version of this source
     587        pmSource *source = thisSource->parent ? thisSource->parent : thisSource;
    694588
    695589        // XXX if no model fits are saved, write out modelEXT?
     
    747641
    748642                if (k < model->params->n) {
    749                     psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "", model->params->data.F32[k]);
     643                    psMetadataAddF32 (row, PS_LIST_TAIL, name, 0, "", model->params->data.F32[k]);
    750644                } else {
    751                     psMetadataAddF32 (row, PS_LIST_TAIL, name, PS_DATA_F32, "", NAN);
     645                    psMetadataAddF32 (row, PS_LIST_TAIL, name, 0, "", NAN);
    752646                }
    753647            }
    754648
    755             // XXX other parameters which may be set.
    756             // XXX flag / value to define the model
    757             // XXX write out the model type, fit status flags
    758 
     649            // optionally, write out the covariance matrix values
     650            // XXX do I need to pad this to match the biggest covar matrix?
     651            if (model->covar) {
     652                for (int iy = 0; iy < model->covar->numCols; iy++) {
     653                    for (int ix = iy; ix < model->covar->numCols; ix++) {
     654                        snprintf (name, 64, "EXT_COVAR_%02d_%02d", iy, ix);
     655                        psMetadataAddF32 (row, PS_LIST_TAIL, name, 0, "", model->covar->data.F32[iy][ix]);
     656
     657                    }
     658                }                   
     659            }
    759660            psArrayAdd (table, 100, row);
    760661            psFree (row);
     
    790691bool pmSourcesWrite_CMF_PS1_SV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
    791692{
    792 
     693    bool status = false;
    793694    psArray *table;
    794695    psMetadata *row;
     
    796697    char keyword1[80], keyword2[80];
    797698
     699    // perform full non-linear fits / extended source analysis?
     700    if (!psMetadataLookupBool (&status, recipe, "RADIAL_APERTURES")) {
     701        psLogMsg ("psphot", PS_LOG_INFO, "radial apertures were not measured, skipping\n");
     702        return true;
     703    }
     704
    798705    // create a header to hold the output data
    799706    psMetadata *outhead = psMetadataAlloc ();
     
    803710
    804711    // we use this just to define the output vectors (which must be present for all objects)
    805     bool status = false;
    806712    psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
    807713    psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
     
    818724    }
    819725
     726    // the FWHM values are available if we measured a psf-matched convolved set
    820727    psVector *fwhmValues = psMetadataLookupVector(&status, readout->analysis, "STACK.PSF.FWHM.VALUES");
    821     if (!fwhmValues) {
    822         psError (PM_ERR_CONFIG, true, "convolved or measured FWHM is not defined for this readout");
    823         return false;
    824     }
    825728
    826729    // let's write these out in S/N order
    827     sources = psArraySort (sources, pmSourceSortBySN);
     730    sources = psArraySort (sources, pmSourceSortByFlux);
    828731
    829732    table = psArrayAllocEmpty (sources->n);
     
    832735    for (int i = 0; i < sources->n; i++) {
    833736
    834         pmSource *source = sources->data[i];
     737        // this is the source associated with this image
     738        pmSource *thisSource = sources->data[i];
     739
     740        // this is the "real" version of this source
     741        pmSource *source = thisSource->parent ? thisSource->parent : thisSource;
    835742
    836743        // skip sources without radial aper measurements (or insufficient)
    837         if (source->radialAper == NULL) continue;
    838         psAssert (source->radialAper->n == fwhmValues->n, "inconsistent radial aperture set");
    839 
    840         for (int entry = 0; entry < fwhmValues->n; entry++) {
     744        if (source->radialAper == NULL) continue;
     745
     746        // psAssert (source->radialAper->n == fwhmValues->n, "inconsistent radial aperture set");
     747
     748        for (int entry = 0; entry < source->radialAper->n; entry++) {
    841749
    842750            // choose the convolved EXT model, if available, otherwise the simple one
     
    844752            assert (radialAper);
    845753
    846             bool useMoments = true;
    847             useMoments = (useMoments && source->moments);          // can't if there are no moments
    848             useMoments = (useMoments && source->moments->nPixels); // can't if the moments were not measured
    849             useMoments = (useMoments && !(source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE)); // can't if the moments failed...
    850 
    851             if (useMoments) {
     754            if (pmSourcePositionUseMoments(source)) {
    852755                xPos = source->moments->Mx;
    853756                yPos = source->moments->My;
     
    863766            psMetadataAddF32 (row, PS_LIST_TAIL, "X_APER",           0, "Center of aperture measurements",            xPos);
    864767            psMetadataAddF32 (row, PS_LIST_TAIL, "Y_APER",           0, "Center of aperture measurements",            yPos);
    865             psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM",         0, "FWHM of matched PSF",                        fwhmValues->data.F32[entry]);
     768            if (fwhmValues) {
     769                psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM",         0, "FWHM of matched PSF",                    fwhmValues->data.F32[entry]);
     770            } else {
     771                psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM",         0, "image is not FWHM-matched",              NAN);
     772            }
    866773
    867774            // XXX if we have raw radial apertures, write them out here
    868             psVector *radFlux    = psVectorAlloc(radMax->n, PS_TYPE_F32);
    869             psVector *radFluxErr = psVectorAlloc(radMax->n, PS_TYPE_F32);
    870             psVector *radFill    = psVectorAlloc(radMax->n, PS_TYPE_F32);
     775            psVector *radFlux      = psVectorAlloc(radMax->n, PS_TYPE_F32);
     776            psVector *radFluxErr   = psVectorAlloc(radMax->n, PS_TYPE_F32);
     777            psVector *radFill      = psVectorAlloc(radMax->n, PS_TYPE_F32);
     778            psVector *radFluxStdev = psVectorAlloc(radMax->n, PS_TYPE_F32);
    871779            psVectorInit (radFlux,    NAN);
    872780            psVectorInit (radFluxErr, NAN);
     
    879787            // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux
    880788            for (int j = 0; j < radialAper->flux->n; j++) {
    881                 radFlux->data.F32[j]    = radialAper->flux->data.F32[j];
    882                 radFluxErr->data.F32[j] = radialAper->fluxErr->data.F32[j];
    883                 radFill->data.F32[j]    = radialAper->fill->data.F32[j];
     789                radFlux->data.F32[j]      = radialAper->flux->data.F32[j];
     790                radFluxErr->data.F32[j]   = radialAper->fluxErr->data.F32[j];
     791                radFluxStdev->data.F32[j] = radialAper->fluxStdev->data.F32[j];
     792                radFill->data.F32[j]      = radialAper->fill->data.F32[j];
    884793            }
    885794
    886795        write_annuli:
    887             psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX",     PS_DATA_VECTOR, "flux within annuli",    radFlux);
    888             psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX_ERR", PS_DATA_VECTOR, "flux error in annuli",  radFluxErr);
    889             psMetadataAdd (row, PS_LIST_TAIL, "APER_FILL",     PS_DATA_VECTOR, "fill factor of annuli", radFill);
     796            psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX",       PS_DATA_VECTOR, "flux within annuli",       radFlux);
     797            psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX_ERR",   PS_DATA_VECTOR, "flux error in annuli",     radFluxErr);
     798            psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX_STDEV", PS_DATA_VECTOR, "flux standard deviation",  radFluxStdev);
     799            psMetadataAdd (row, PS_LIST_TAIL, "APER_FILL",       PS_DATA_VECTOR, "fill factor of annuli",    radFill);
    890800            psFree (radFlux);
    891801            psFree (radFluxErr);
     802            psFree (radFluxStdev);
    892803            psFree (radFill);
    893804
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c

    r30621 r31153  
    4949
    5050#include "pmSourceIO.h"
     51#include "pmSourceOutputs.h"
    5152
    5253// panstarrs-style FITS table output (header + table in 1st extension)
     
    6263    psArray *table;
    6364    psMetadata *row;
    64     int i;
    65     psF32 *PAR, *dPAR;
    66     psEllipseAxes axes;
    67     psF32 xPos, yPos;
    68     psF32 xErr, yErr;
    69     psF32 errMag, chisq, apRadius;
    70     psS32 nPix, nDOF;
    7165
    7266    pmChip *chip = readout->parent->parent;
    73     pmFPA  *fpa  = chip->parent;
    74 
    75     bool status1 = false;
    76     bool status2 = false;
    77     float magOffset = NAN;
    78     float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
    79     float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
    80     if (!isfinite(zeropt)) {
    81         zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
    82     }
    83     if (status1 && status2 && (exptime > 0.0)) {
    84         magOffset = zeropt + 2.5*log10(exptime);
    85     }
    86     float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
    8767
    8868    // if the sequence is defined, write these in seq order; otherwise
     
    9272        if (source->seq == -1) {
    9373          // let's write these out in S/N order
    94           sources = psArraySort (sources, pmSourceSortBySN);
     74          sources = psArraySort (sources, pmSourceSortByFlux);
    9575        } else {
    9676          sources = psArraySort (sources, pmSourceSortBySeq);
     
    10080    table = psArrayAllocEmpty (sources->n);
    10181
     82    short nImageOverlap;
     83    float magOffset;
     84    float zeroptErr;
     85    float fwhmMajor;
     86    float fwhmMinor;
     87    pmSourceOutputsCommonValues (&nImageOverlap, &magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader);
     88
    10289    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
    10390    // by the time we call this function, all values should be assigned.  let's use asserts to be sure in some cases.
    104     for (i = 0; i < sources->n; i++) {
     91    for (int i = 0; i < sources->n; i++) {
    10592        pmSource *source = (pmSource *) sources->data[i];
    10693
     
    113100        }
    114101
    115         // no difference between PSF and non-PSF model
    116         pmModel *model = source->modelPSF;
    117 
    118         if (model != NULL) {
    119             PAR = model->params->data.F32;
    120             dPAR = model->dparams->data.F32;
    121             xPos = PAR[PM_PAR_XPOS];
    122             yPos = PAR[PM_PAR_YPOS];
    123             if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
    124               xErr = dPAR[PM_PAR_XPOS];
    125               yErr = dPAR[PM_PAR_YPOS];
    126             } else {
    127               // in linear-fit mode, there is no error on the centroid
    128               xErr = source->peak->dx;
    129               yErr = source->peak->dy;
    130             }
    131             if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
    132                 axes = pmPSF_ModelToAxes (PAR, 20.0);
    133             } else {
    134                 axes.major = NAN;
    135                 axes.minor = NAN;
    136                 axes.theta = NAN;
    137             }
    138             chisq = model->chisq;
    139             nDOF = model->nDOF;
    140             nPix = model->nPix;
    141             apRadius = source->apRadius;
    142             errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
    143         } else {
    144             xPos = source->peak->xf;
    145             yPos = source->peak->yf;
    146             xErr = source->peak->dx;
    147             yErr = source->peak->dy;
    148             axes.major = NAN;
    149             axes.minor = NAN;
    150             axes.theta = NAN;
    151             chisq = NAN;
    152             nDOF = 0;
    153             nPix = 0;
    154             apRadius = NAN;
    155             errMag = NAN;
    156         }
    157 
    158         float calMag = isfinite(magOffset) ? source->psfMag + magOffset : NAN;
    159         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
    160         psS16 nImageOverlap = 1;
    161 
    162         psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
    163         float posAngle = 0.0;
    164         float pltScale = 0.0;
    165         pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);
     102        // set the 'best' values for various output fields:
     103        pmSourceOutputs outputs;
     104        pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset);
     105
     106        pmSourceOutputsMoments moments;
     107        pmSourceOutputsSetMoments (&moments, source);
    166108
    167109        row = psMetadataAlloc ();
    168110        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
    169         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           xPos);
    170         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           yPos);
    171         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  xErr); // XXX this is only measured for non-linear fits
    172         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr); // XXX this is only measured for non-linear fits
    173         psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F32, "PSF RA coordinate (degrees)",                ptSky.r*PS_DEG_RAD);
    174         psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F32, "PSF DEC coordinate (degrees)",               ptSky.d*PS_DEG_RAD);
    175         psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         posAngle*PS_DEG_RAD);
    176         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       pltScale*PS_DEG_RAD*3600.0);
     111        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           outputs.xPos);
     112        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           outputs.yPos);
     113        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  outputs.xErr); // XXX this is only measured for non-linear fits
     114        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  outputs.yErr); // XXX this is only measured for non-linear fits
     115        psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F32, "PSF RA coordinate (degrees)",                outputs.ra);
     116        psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F32, "PSF DEC coordinate (degrees)",               outputs.dec);
     117        psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         outputs.posAngle);
     118        psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
    177119        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
    178         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        errMag);
     120        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
    179121        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
    180         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
    181         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
    182         psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   calMag);
     122        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              outputs.apRadius);
     123        psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           outputs.peakMag);
     124        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   outputs.calMag);
    183125        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);
    184126        psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
    185127        psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",                         source->skyErr);
    186128
    187         psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           chisq);
     129        psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           outputs.chisq);
    188130        psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA",        PS_DATA_F32, "Nsigma deviations from PSF to CF",           source->crNsigma);
    189131        psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA",       PS_DATA_F32, "Nsigma deviations from PSF to EXT",          source->extNsigma);
    190132
    191         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     axes.major);
    192         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
    193         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
     133        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     outputs.psfMajor);
     134        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     outputs.psfMinor);
     135        psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      outputs.psfTheta);
    194136        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
    195         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
    196         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
    197 
    198         // distinguish moments measure from window vs S/N > XX ??
    199         float mxx = source->moments ? source->moments->Mxx : NAN;
    200         float mxy = source->moments ? source->moments->Mxy : NAN;
    201         float myy = source->moments ? source->moments->Myy : NAN;
    202         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      mxx);
    203         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      mxy);
    204         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      myy);
     137        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         outputs.nDOF);
     138        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    outputs.nPix);
     139
     140        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                       moments.Mxx);
     141        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                       moments.Mxy);
     142        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                       moments.Myy);
    205143
    206144        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                      source->mode);
     
    317255        // recreate the peak to match (xPos, yPos) +/- (xErr, yErr)
    318256        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    319         source->peak->flux = peakFlux;
     257        source->peak->rawFlux = peakFlux;
     258        source->peak->smoothFlux = peakFlux;
    320259        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
    321260        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
    322261        source->peak->dx   = dPAR[PM_PAR_XPOS];
    323262        source->peak->dy   = dPAR[PM_PAR_YPOS];
    324         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    325           source->peak->SN = 1.0 / source->errMag;
    326         } else {
    327           source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
    328         }
    329263
    330264        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
     
    339273
    340274        source->moments = pmMomentsAlloc ();
     275        source->moments->Mx = source->peak->xf; // we don't have both Mx,My and xf,yf in the cmf
     276        source->moments->My = source->peak->yf; // we don't have both Mx,My and xf,yf in the cmf
     277
    341278        source->moments->Mxx = psMetadataLookupF32 (&status, row, "MOMENTS_XX");
    342279        source->moments->Mxy = psMetadataLookupF32 (&status, row, "MOMENTS_XY");
     
    371308
    372309    // let's write these out in S/N order
    373     sources = psArraySort (sources, pmSourceSortBySN);
     310    sources = psArraySort (sources, pmSourceSortByFlux);
    374311
    375312    table = psArrayAllocEmpty (sources->n);
     
    549486
    550487    // let's write these out in S/N order
    551     sources = psArraySort (sources, pmSourceSortBySN);
     488    sources = psArraySort (sources, pmSourceSortByFlux);
    552489
    553490    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c

    r30621 r31153  
    4949
    5050#include "pmSourceIO.h"
     51#include "pmSourceOutputs.h"
    5152
    5253// panstarrs-style FITS table output (header + table in 1st extension)
     
    6263    psArray *table;
    6364    psMetadata *row;
    64     psF32 *PAR, *dPAR;
    65     psEllipseAxes axes;
    66     psF32 xPos, yPos;
    67     psF32 xErr, yErr;
    68     psF32 errMag, chisq, apRadius;
    69     psS32 nPix, nDOF;
    7065
    7166    pmChip *chip = readout->parent->parent;
    72     pmFPA  *fpa  = chip->parent;
    73 
    74     bool status1 = false;
    75     bool status2 = false;
    76     float magOffset = NAN;
    77     float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
    78     float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
    79     if (!isfinite(zeropt)) {
    80         zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
    81     }
    82     if (status1 && status2 && (exptime > 0.0)) {
    83         magOffset = zeropt + 2.5*log10(exptime);
    84     }
    85     float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
    8667
    8768    // if the sequence is defined, write these in seq order; otherwise
     
    9172        if (source->seq == -1) {
    9273            // let's write these out in S/N order
    93             sources = psArraySort (sources, pmSourceSortBySN);
     74            sources = psArraySort (sources, pmSourceSortByFlux);
    9475        } else {
    9576            sources = psArraySort (sources, pmSourceSortBySeq);
     
    9879
    9980    table = psArrayAllocEmpty (sources->n);
     81
     82    short nImageOverlap;
     83    float magOffset;
     84    float zeroptErr;
     85    float fwhmMajor;
     86    float fwhmMinor;
     87    pmSourceOutputsCommonValues (&nImageOverlap, &magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader);
    10088
    10189    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
     
    112100        }
    113101
    114         // no difference between PSF and non-PSF model
    115         pmModel *model = source->modelPSF;
    116 
    117         if (model != NULL) {
    118             PAR = model->params->data.F32;
    119             dPAR = model->dparams->data.F32;
    120             xPos = PAR[PM_PAR_XPOS];
    121             yPos = PAR[PM_PAR_YPOS];
    122             if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
    123                 xErr = dPAR[PM_PAR_XPOS];
    124                 yErr = dPAR[PM_PAR_YPOS];
    125             } else {
    126                 // in linear-fit mode, there is no error on the centroid
    127                 xErr = source->peak->dx;
    128                 yErr = source->peak->dy;
    129             }
    130             if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
    131                 axes = pmPSF_ModelToAxes (PAR, 20.0);
    132             } else {
    133                 axes.major = NAN;
    134                 axes.minor = NAN;
    135                 axes.theta = NAN;
    136             }
    137             chisq = model->chisq;
    138             nDOF = model->nDOF;
    139             nPix = model->nPix;
    140             apRadius = source->apRadius;
    141             errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
    142         } else {
    143             xPos = source->peak->xf;
    144             yPos = source->peak->yf;
    145             xErr = source->peak->dx;
    146             yErr = source->peak->dy;
    147             axes.major = NAN;
    148             axes.minor = NAN;
    149             axes.theta = NAN;
    150             chisq = NAN;
    151             nDOF = 0;
    152             nPix = 0;
    153             apRadius = NAN;
    154             errMag = NAN;
    155         }
    156 
    157         float calMag = isfinite(magOffset) ? source->psfMag + magOffset : NAN;
    158         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
    159         psS16 nImageOverlap = 1;
    160 
    161         psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
    162         float posAngle = 0.0;
    163         float pltScale = 0.0;
    164         pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);
     102        // set the 'best' values for various output fields:
     103        pmSourceOutputs outputs;
     104        pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset);
     105
     106        pmSourceOutputsMoments moments;
     107        pmSourceOutputsSetMoments (&moments, source);
    165108
    166109        row = psMetadataAlloc ();
    167110        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
    168         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           xPos);
    169         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           yPos);
    170         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  xErr); // XXX this is only measured for non-linear fits
    171         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr); // XXX this is only measured for non-linear fits
    172         psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         posAngle*PS_DEG_RAD);
    173         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       pltScale*PS_DEG_RAD*3600.0);
     111        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           outputs.xPos);
     112        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           outputs.yPos);
     113        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  outputs.xErr); // XXX this is only measured for non-linear fits
     114        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  outputs.yErr); // XXX this is only measured for non-linear fits
     115        psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         outputs.posAngle);
     116        psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
    174117        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
    175         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        errMag);
     118        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
    176119        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
    177         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
    178         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
    179         psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   calMag);
     120        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              outputs.apRadius);
     121        psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           outputs.peakMag);
     122        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   outputs.calMag);
    180123        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);
    181         psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                ptSky.r*PS_DEG_RAD);
    182         psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               ptSky.d*PS_DEG_RAD);
     124        psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                outputs.ra);
     125        psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               outputs.dec);
    183126        psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
    184127        psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",                         source->skyErr);
    185128
    186         psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           chisq);
     129        psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           outputs.chisq);
    187130        psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA",        PS_DATA_F32, "Nsigma deviations from PSF to CF",           source->crNsigma);
    188131        psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA",       PS_DATA_F32, "Nsigma deviations from PSF to EXT",          source->extNsigma);
    189132
    190         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     axes.major);
    191         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
    192         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
     133        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     outputs.psfMajor);
     134        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     outputs.psfMinor);
     135        psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      outputs.psfTheta);
    193136        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
    194         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
    195         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
    196 
    197         // distinguish moments measure from window vs S/N > XX ??
    198         float mxx = source->moments ? source->moments->Mxx : NAN;
    199         float mxy = source->moments ? source->moments->Mxy : NAN;
    200         float myy = source->moments ? source->moments->Myy : NAN;
    201         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      mxx);
    202         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      mxy);
    203         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      myy);
     137        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         outputs.nDOF);
     138        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    outputs.nPix);
     139
     140        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                       moments.Mxx);
     141        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                       moments.Mxy);
     142        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                       moments.Myy);
    204143
    205144        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                      source->mode);
     
    322261        // recreate the peak to match (xPos, yPos) +/- (xErr, yErr)
    323262        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    324         source->peak->flux = peakFlux;
     263        source->peak->rawFlux = peakFlux;
     264        source->peak->smoothFlux = peakFlux;
    325265        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
    326266        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
    327267        source->peak->dx   = dPAR[PM_PAR_XPOS];
    328268        source->peak->dy   = dPAR[PM_PAR_YPOS];
    329         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    330           source->peak->SN = 1.0 / source->errMag;
    331         } else {
    332           source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
    333         }
    334269
    335270        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
     
    344279
    345280        source->moments = pmMomentsAlloc ();
     281        source->moments->Mx = source->peak->xf; // we don't have both Mx,My and xf,yf in the cmf
     282        source->moments->My = source->peak->yf; // we don't have both Mx,My and xf,yf in the cmf
     283
    346284        source->moments->Mxx = psMetadataLookupF32 (&status, row, "MOMENTS_XX");
    347285        source->moments->Mxy = psMetadataLookupF32 (&status, row, "MOMENTS_XY");
     
    392330
    393331    // let's write these out in S/N order
    394     sources = psArraySort (sources, pmSourceSortBySN);
     332    sources = psArraySort (sources, pmSourceSortByFlux);
    395333
    396334    table = psArrayAllocEmpty (sources->n);
     
    611549
    612550    // let's write these out in S/N order
    613     sources = psArraySort (sources, pmSourceSortBySN);
     551    sources = psArraySort (sources, pmSourceSortByFlux);
    614552
    615553    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
  • trunk/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c

    r30621 r31153  
    4949
    5050#include "pmSourceIO.h"
     51#include "pmSourceOutputs.h"
    5152
    5253// panstarrs-style FITS table output (header + table in 1st extension)
     
    6263    psArray *table;
    6364    psMetadata *row;
    64     psF32 *PAR, *dPAR;
    65     psEllipseAxes axes;
    66     psF32 xPos, yPos;
    67     psF32 xErr, yErr;
    68     psF32 chisq, apRadius;
    69     psS32 nPix, nDOF;
    7065
    7166    pmChip *chip = readout->parent->parent;
    72     pmFPA  *fpa  = chip->parent;
    73 
    74     bool status1 = false;
    75     bool status2 = false;
    76     float magOffset = NAN;
    77     float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
    78     float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
    79     if (!isfinite(zeropt)) {
    80         zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
    81     }
    82     if (status1 && status2 && (exptime > 0.0)) {
    83         magOffset = zeropt + 2.5*log10(exptime);
    84     }
    85     float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
    86 
    87     // we need a measure of the image quality (FWHM) for this image, in order to get the positional errors
    88     float fwhmMajor = psMetadataLookupF32(&status1, readout->analysis, "FWHM_MAJ");
    89     if (!status1) {
    90         fwhmMajor = psMetadataLookupF32(&status1, readout->analysis, "IQ_FW1");
    91         if (!status1) {
    92             fwhmMajor = 5.0; // XXX just a guess!
    93         }
    94     }
    95     float fwhmMinor = psMetadataLookupF32(&status1, readout->analysis, "FWHM_MIN");
    96     if (!status1) {
    97         fwhmMinor = psMetadataLookupF32(&status1, readout->analysis, "IQ_FW2");
    98         if (!status1) {
    99             fwhmMinor = 5.0; // XXX just a guess!
    100         }
    101     }
    10267
    10368    // if the sequence is defined, write these in seq order; otherwise
     
    10772        if (source->seq == -1) {
    10873            // let's write these out in S/N order
    109             sources = psArraySort (sources, pmSourceSortBySN);
     74            sources = psArraySort (sources, pmSourceSortByFlux);
    11075        } else {
    11176            sources = psArraySort (sources, pmSourceSortBySeq);
     
    11479
    11580    table = psArrayAllocEmpty (sources->n);
     81
     82    short nImageOverlap;
     83    float magOffset;
     84    float zeroptErr;
     85    float fwhmMajor;
     86    float fwhmMinor;
     87    pmSourceOutputsCommonValues (&nImageOverlap, &magOffset, &zeroptErr, &fwhmMajor, &fwhmMinor, readout, imageHeader);
    11688
    11789    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
     
    128100        }
    129101
    130         // no difference between PSF and non-PSF model
    131         pmModel *model = source->modelPSF;
    132 
    133         if (model != NULL) {
    134             PAR = model->params->data.F32;
    135             dPAR = model->dparams->data.F32;
    136             xPos = PAR[PM_PAR_XPOS];
    137             yPos = PAR[PM_PAR_YPOS];
    138             if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
    139                 xErr = dPAR[PM_PAR_XPOS];
    140                 yErr = dPAR[PM_PAR_YPOS];
    141             } else {
    142                 xErr = fwhmMajor * source->errMag / 2.35;
    143                 yErr = fwhmMinor * source->errMag / 2.35;
    144             }
    145             if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
    146                 axes = pmPSF_ModelToAxes (PAR, 20.0);
    147             } else {
    148                 axes.major = NAN;
    149                 axes.minor = NAN;
    150                 axes.theta = NAN;
    151             }
    152             chisq = model->chisq;
    153             nDOF = model->nDOF;
    154             nPix = model->nPix;
    155             apRadius = source->apRadius;
    156         } else {
    157             bool useMoments = true;
    158             useMoments = (useMoments && source->moments);          // can't if there are no moments
    159             useMoments = (useMoments && source->moments->nPixels); // can't if the moments were not measured
    160             useMoments = (useMoments && !(source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE)); // can't if the moments failed...
    161 
    162             if (useMoments) {
    163                 xPos = source->moments->Mx;
    164                 yPos = source->moments->My;
    165                 xErr = fwhmMajor * source->errMag / 2.35;
    166                 yErr = fwhmMinor * source->errMag / 2.35;
    167             } else {
    168                 xPos = source->peak->xf;
    169                 yPos = source->peak->yf;
    170                 xErr = source->peak->dx;
    171                 yErr = source->peak->dy;
    172             }
    173             axes.major = NAN;
    174             axes.minor = NAN;
    175             axes.theta = NAN;
    176             chisq = NAN;
    177             nDOF = 0;
    178             nPix = 0;
    179             apRadius = NAN;
    180         }
    181 
    182         float calMag = isfinite(magOffset) ? source->psfMag + magOffset : NAN;
    183         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
    184         psS16 nImageOverlap = 1;
    185 
    186         psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
    187         float posAngle = 0.0;
    188         float pltScale = 0.0;
    189         pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);
     102        // set the 'best' values for various output fields:
     103        pmSourceOutputs outputs;
     104        pmSourceOutputsSetValues (&outputs, source, chip, fwhmMajor, fwhmMinor, magOffset);
     105
     106        pmSourceOutputsMoments moments;
     107        pmSourceOutputsSetMoments (&moments, source);
    190108
    191109        row = psMetadataAlloc ();
    192110        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
    193         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           xPos);
    194         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           yPos);
    195         psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  xErr);
    196         psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr);
    197         psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         posAngle*PS_DEG_RAD);
    198         psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       pltScale*PS_DEG_RAD*3600.0);
     111        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           outputs.xPos);
     112        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           outputs.yPos);
     113        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  outputs.xErr);
     114        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  outputs.yErr);
     115        psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         outputs.posAngle);
     116        psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       outputs.pltScale);
    199117        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
    200118        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->errMag);
     
    203121        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
    204122        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW",       PS_DATA_F32, "magnitude in reported aperture",             source->apMagRaw);
    205         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
    206 
    207         psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   calMag);
     123        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              outputs.apRadius);
     124
     125        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   outputs.calMag);
    208126        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);
    209127       
    210128        // NOTE: RA & DEC (both double) need to be on an 8-byte boundary...
    211         psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                ptSky.r*PS_DEG_RAD);
    212         psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               ptSky.d*PS_DEG_RAD);
    213 
    214         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
     129        psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                outputs.ra);
     130        psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               outputs.dec);
     131
     132        psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           outputs.peakMag);
    215133        psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
    216134        psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",                         source->skyErr);
    217135
    218         psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           chisq);
     136        psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           outputs.chisq);
    219137        psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA",        PS_DATA_F32, "Nsigma deviations from PSF to CF",           source->crNsigma);
    220138        psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA",       PS_DATA_F32, "Nsigma deviations from PSF to EXT",          source->extNsigma);
    221139
    222         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     axes.major);
    223         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
    224         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
     140        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     outputs.psfMajor);
     141        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     outputs.psfMinor);
     142        psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      outputs.psfTheta);
    225143        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor (bad)",          source->pixWeightNotBad);
    226144        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT",   PS_DATA_F32, "PSF coverage/quality factor (poor)",         source->pixWeightNotPoor);
    227         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
    228         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
    229 
    230         // distinguish moments measure from window vs S/N > XX ??
    231         float Mxx = source->moments ? source->moments->Mxx : NAN;
    232         float Mxy = source->moments ? source->moments->Mxy : NAN;
    233         float Myy = source->moments ? source->moments->Myy : NAN;
    234 
    235         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      Mxx);
    236         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      Mxy);
    237         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      Myy);
    238 
    239         float M_c3 = source->moments ? 1.0*source->moments->Mxxx - 3.0*source->moments->Mxyy : NAN;
    240         float M_s3 = source->moments ? 3.0*source->moments->Mxxy - 1.0*source->moments->Myyy : NAN;
    241         float M_c4 = source->moments ? 1.0*source->moments->Mxxxx - 6.0*source->moments->Mxxyy + 1.0*source->moments->Myyyy : NAN;
    242         float M_s4 = source->moments ? 4.0*source->moments->Mxxxy - 4.0*source->moments->Mxyyy : NAN;
    243 
    244         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3C",      PS_DATA_F32, "third momemt cos theta",                    M_c3);
    245         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3S",      PS_DATA_F32, "third momemt sin theta",                    M_s3);
    246         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4C",      PS_DATA_F32, "fourth momemt cos theta",                   M_c4);
    247         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4S",      PS_DATA_F32, "fourth momemt sin theta",                   M_s4);
    248 
    249         float Mrf  = source->moments ? source->moments->Mrf : NAN;
    250         float Mrh  = source->moments ? source->moments->Mrh : NAN;
    251         float Krf  = source->moments ? source->moments->KronFlux : NAN;
    252         float dKrf = source->moments ? source->moments->KronFluxErr : NAN;
    253 
    254         float Kinner = source->moments ? source->moments->KronFinner : NAN;
    255         float Kouter = source->moments ? source->moments->KronFouter : NAN;
    256 
    257         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",                       Mrf);
    258         psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",                        Mrh);
    259         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Krf);
    260         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",                          dKrf);
    261 
    262         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Kinner);
    263         psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Kouter);
    264 
    265         psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                     source->mode);
    266         psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                     source->mode2);
     145        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         outputs.nDOF);
     146        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    outputs.nPix);
     147
     148        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                       moments.Mxx);
     149        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                       moments.Mxy);
     150        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                       moments.Myy);
     151
     152        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3C",      PS_DATA_F32, "third momemt cos theta",                     moments.M_c3);
     153        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3S",      PS_DATA_F32, "third momemt sin theta",                     moments.M_s3);
     154        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4C",      PS_DATA_F32, "fourth momemt cos theta",                    moments.M_c4);
     155        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4S",      PS_DATA_F32, "fourth momemt sin theta",                    moments.M_s4);
     156
     157        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",                        moments.Mrf);
     158        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",                         moments.Mrh);
     159        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Krf);
     160        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",                            moments.dKrf);
     161        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Kinner);
     162        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                      moments.Kouter);
     163        // psMetadataAdd (row, PS_LIST_TAIL, "KRON_CORE_FLUX",   PS_DATA_F32, "Kron Flux (in 1.0 R1)",                      moments.KronCore);
     164        // psMetadataAdd (row, PS_LIST_TAIL, "KRON_CORE_ERROR",  PS_DATA_F32, "Kron Error (in 1.0 R1)",                     moments.KronCoreErr);
     165        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                      source->mode);
     166        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                      source->mode2);
    267167        psMetadataAdd (row, PS_LIST_TAIL, "PADDING2",         PS_DATA_S32, "more padding", 0);
    268168
     
    384284        // recreate the peak to match (xPos, yPos) +/- (xErr, yErr)
    385285        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    386         source->peak->flux = peakFlux;
     286        source->peak->rawFlux = peakFlux;
     287        source->peak->smoothFlux = peakFlux;
    387288        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
    388289        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
    389290        source->peak->dx   = dPAR[PM_PAR_XPOS];
    390291        source->peak->dy   = dPAR[PM_PAR_YPOS];
    391         if (isfinite (source->errMag) && (source->errMag > 0.0)) {
    392           source->peak->SN = 1.0 / source->errMag;
    393         } else {
    394           source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
    395         }
     292
     293        // we no longer sort by S/N, only flux
     294        // if (isfinite (source->errMag) && (source->errMag > 0.0)) {
     295        //   source->peak->SN = 1.0 / source->errMag;
     296        // } else {
     297        //   source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
     298        // }
    396299
    397300        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
     
    407310
    408311        source->moments = pmMomentsAlloc ();
     312        source->moments->Mx = source->peak->xf; // we don't have both Mx,My and xf,yf in the cmf
     313        source->moments->My = source->peak->yf; // we don't have both Mx,My and xf,yf in the cmf
     314
    409315        source->moments->Mxx = psMetadataLookupF32 (&status, row, "MOMENTS_XX");
    410316        source->moments->Mxy = psMetadataLookupF32 (&status, row, "MOMENTS_XY");
     
    477383
    478384    // let's write these out in S/N order
    479     sources = psArraySort (sources, pmSourceSortBySN);
     385    sources = psArraySort (sources, pmSourceSortByFlux);
    480386
    481387    table = psArrayAllocEmpty (sources->n);
     
    649555
    650556    // let's write these out in S/N order
    651     sources = psArraySort (sources, pmSourceSortBySN);
     557    sources = psArraySort (sources, pmSourceSortByFlux);
    652558
    653559    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
  • trunk/psModules/src/objects/pmSourceIO_PS1_CAL_0.c

    r30621 r31153  
    9191
    9292    // let's write these out in S/N order
    93     sources = psArraySort (sources, pmSourceSortBySN);
     93    sources = psArraySort (sources, pmSourceSortByFlux);
    9494
    9595    table = psArrayAllocEmpty (sources->n);
     
    136136
    137137        float calMag = source->psfMag + magOffset;
    138         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
     138        float peakMag = (source->peak->rawFlux > 0) ? -2.5*log10(source->peak->rawFlux) : NAN;
    139139        psS16 nImageOverlap = 1;
    140140
     
    294294
    295295        source->peak       = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    296         source->peak->flux = peakFlux;
     296        source->peak->rawFlux = peakFlux;
     297        source->peak->smoothFlux = peakFlux;
    297298        source->peak->dx   = dPAR[PM_PAR_XPOS];
    298299        source->peak->dy   = dPAR[PM_PAR_YPOS];
     
    357358
    358359    // let's write these out in S/N order
    359     sources = psArraySort (sources, pmSourceSortBySN);
     360    sources = psArraySort (sources, pmSourceSortByFlux);
    360361
    361362    table = psArrayAllocEmpty (sources->n);
     
    576577
    577578    // let's write these out in S/N order
    578     sources = psArraySort (sources, pmSourceSortBySN);
     579    sources = psArraySort (sources, pmSourceSortByFlux);
    579580
    580581    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
  • trunk/psModules/src/objects/pmSourceIO_PS1_DEV_0.c

    r30621 r31153  
    101101        }
    102102
    103         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
     103        float peakMag = (source->peak->rawFlux > 0) ? -2.5*log10(source->peak->rawFlux) : NAN;
    104104        psS16 nImageOverlap = 1;
    105105        psS32 ID = 0; // XXX need to figure out how to generate this
     
    220220
    221221        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    222         source->peak->flux = peakFlux;
     222        source->peak->rawFlux = peakFlux;
     223        source->peak->smoothFlux = peakFlux;
    223224        source->peak->dx   = dPAR[PM_PAR_XPOS];
    224225        source->peak->dy   = dPAR[PM_PAR_YPOS];
  • trunk/psModules/src/objects/pmSourceIO_PS1_DEV_1.c

    r30621 r31153  
    7373
    7474    // let's write these out in S/N order
    75     sources = psArraySort (sources, pmSourceSortBySN);
     75    sources = psArraySort (sources, pmSourceSortByFlux);
    7676
    7777    table = psArrayAllocEmpty (sources->n);
     
    117117        }
    118118
    119         float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
     119        float peakMag = (source->peak->rawFlux > 0) ? -2.5*log10(source->peak->rawFlux) : NAN;
    120120        psS16 nImageOverlap = 1;
    121121
     
    263263
    264264        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    265         source->peak->flux = peakFlux;
     265        source->peak->rawFlux = peakFlux;
     266        source->peak->smoothFlux = peakFlux;
    266267        source->peak->dx   = dPAR[PM_PAR_XPOS];
    267268        source->peak->dy   = dPAR[PM_PAR_YPOS];
     
    307308
    308309    // let's write these out in S/N order
    309     sources = psArraySort (sources, pmSourceSortBySN);
     310    sources = psArraySort (sources, pmSourceSortByFlux);
    310311
    311312    table = psArrayAllocEmpty (sources->n);
     
    480481
    481482    // let's write these out in S/N order
    482     sources = psArraySort (sources, pmSourceSortBySN);
     483    sources = psArraySort (sources, pmSourceSortByFlux);
    483484
    484485    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
  • trunk/psModules/src/objects/pmSourceIO_RAW.c

    r29004 r31153  
    126126                 source[0].apMag, source[0].type, source[0].mode,
    127127                 logChi, logChiNorm,
    128                  source[0].peak->SN,
     128                 source[0].peak->rawFlux,
    129129                 source[0].apRadius,
    130130                 source[0].pixWeightNotBad,
     
    188188                 log10(model[0].chisq/model[0].nDOF),
    189189                 log10(model[0].chisqNorm/model[0].nDOF),
    190                  source[0].peak->SN,
     190                 source[0].peak->rawFlux,
    191191                 source[0].apRadius,
    192192                 source[0].pixWeightNotBad,
     
    234234
    235235        fprintf (f, "%5d %5d  %7.1f  %7.1f %7.1f  %6.3f %6.3f  %8.1f %7.1f %7.1f %7.1f  %4d %2d\n",
    236                  source->peak->x, source->peak->y, source->peak->value,
     236                 source->peak->x, source->peak->y, source->peak->detValue,
    237237                 moment->Mx, moment->My,
    238238                 moment->Mxx, moment->Myy,
     
    270270            continue;
    271271        fprintf (f, "%5d %5d  %8.1f  %7.1f %7.1f  %6.3f %6.3f  %10.1f %7.1f %7.1f %7.1f  %4d %2d %#5x\n",
    272                  source->peak->x, source->peak->y, source->peak->value,
     272                 source->peak->x, source->peak->y, source->peak->detValue,
    273273                 source->moments->Mx, source->moments->My,
    274274                 source->moments->Mxx, source->moments->Myy,
     
    299299            continue;
    300300        fprintf (f, "%5d %5d  %7.1f %7.2f %7.2f %7.2f\n",
    301                  peak->x, peak->y, peak->value, peak->SN, peak->xf, peak->yf);
    302     }
    303     fclose (f);
    304     return true;
    305 }
    306 
     301                 peak->x, peak->y, peak->detValue, peak->rawFlux, peak->xf, peak->yf);
     302    }
     303    fclose (f);
     304    return true;
     305}
     306
  • trunk/psModules/src/objects/pmSourceIO_SMPDATA.c

    r30621 r31153  
    205205
    206206        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
    207         source->peak->flux = peakFlux;
    208207
    209208        sources->data[i] = source;
  • trunk/psModules/src/objects/pmSourceMasks.h

    r29546 r31153  
    4646    PM_SOURCE_MODE2_DIFF_WITH_DOUBLE = 0x00000002, ///< diff source matched to positive detections in both images
    4747    PM_SOURCE_MODE2_MATCHED          = 0x00000004, ///< diff source matched to positive detections in both images
     48
     49    PM_SOURCE_MODE2_ON_SPIKE         = 0x00000008, ///< > 25% of (PSF-weighted) pixels land on diffraction spike
     50    PM_SOURCE_MODE2_ON_STARCORE      = 0x00000010, ///< > 25% of (PSF-weighted) pixels land on starcore
     51    PM_SOURCE_MODE2_ON_BURNTOOL      = 0x00000020, ///< > 25% of (PSF-weighted) pixels land on burntool
     52    PM_SOURCE_MODE2_ON_CONVPOOR      = 0x00000040, ///< > 25% of (PSF-weighted) pixels land on convpoor
    4853} pmSourceMode2;
    4954
  • trunk/psModules/src/objects/pmSourceMoments.c

    r29602 r31153  
    8282    psF32 Sum = 0.0;
    8383    psF32 Var = 0.0;
     84    psF32 SumCore = 0.0;
     85    psF32 VarCore = 0.0;
    8486    psF32 R2 = PS_SQR(radius);
    8587    psF32 minSN2 = PS_SQR(minSN);
     
    248250
    249251    int nKronPix = 0;
     252    int nCorePix = 0;
     253    int nInner = 0;
     254    int nOuter = 0;
    250255    Sum = Var = 0.0;
    251256    float SumInner = 0.0;
     
    255260
    256261        psF32 yDiff = row - yCM;
    257         if (fabs(yDiff) > radKron) continue;
     262        if (fabs(yDiff) > radKouter) continue;
    258263
    259264        psF32 *vPix = source->pixels->data.F32[row];
     
    272277
    273278            psF32 xDiff = col - xCM;
    274             if (fabs(xDiff) > radKron) continue;
     279            if (fabs(xDiff) > radKouter) continue;
    275280
    276281            // radKron is just a function of (xDiff, yDiff)
     
    293298            }
    294299
     300            // use sigma (fixed by psf) not a radKron based value
     301            if (r < sigma) {
     302                SumCore += pDiff;
     303                VarCore += wDiff;
     304                nCorePix ++;
     305            }
     306
    295307            if ((r > radKinner) && (r < radKron)) {
    296308                SumInner += pDiff;
     309                nInner ++;
    297310            }
    298311            if ((r > radKron)  && (r < radKouter)) {
    299312                SumOuter += pDiff;
     313                nOuter ++;
    300314            }
    301315        }
    302316    }
    303     source->moments->KronFlux = Sum;
    304     source->moments->KronFinner = SumInner;
    305     source->moments->KronFouter = SumOuter;
    306     source->moments->KronFluxErr = sqrt(Var);
     317    // *** should I rescale these fluxes by pi R^2 / nNpix?
     318    source->moments->KronCore    = SumCore       * M_PI * PS_SQR(sigma) / nCorePix;
     319    source->moments->KronCoreErr = sqrt(VarCore) * M_PI * PS_SQR(sigma) / nCorePix;
     320    source->moments->KronFlux    = Sum       * M_PI * PS_SQR(radKron) / nKronPix;
     321    source->moments->KronFluxErr = sqrt(Var) * M_PI * PS_SQR(radKron) / nKronPix;
     322    source->moments->KronFinner = SumInner * M_PI * (PS_SQR(radKron)   - PS_SQR(radKinner)) / nInner;
     323    source->moments->KronFouter = SumOuter * M_PI * (PS_SQR(radKouter) -   PS_SQR(radKron)) / nOuter;
    307324
    308325    psTrace ("psModules.objects", 4, "Mrf: %f  KronFlux: %f  Mxx: %f  Mxy: %f  Myy: %f  Mxxx: %f  Mxxy: %f  Mxyy: %f  Myyy: %f  Mxxxx: %f  Mxxxy: %f  Mxxyy: %f  Mxyyy: %f  Mxyyy: %f\n",
     
    313330
    314331    psTrace ("psModules.objects", 3, "peak %f %f (%f = %f) Mx: %f  My: %f  Sum: %f  Mxx: %f  Mxy: %f  Myy: %f  sky: %f  Npix: %d\n",
    315              source->peak->xf, source->peak->yf, source->peak->flux, source->peak->SN, source->moments->Mx,   source->moments->My, Sum, source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy, sky, source->moments->nPixels);
     332             source->peak->xf, source->peak->yf, source->peak->rawFlux, sqrt(source->peak->detValue), source->moments->Mx,   source->moments->My, Sum, source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy, sky, source->moments->nPixels);
    316333
    317334    return(true);
  • trunk/psModules/src/objects/pmSourcePhotometry.c

    r29935 r31153  
    2323#include "pmFPAMaskWeight.h"
    2424
     25#include "pmConfigMask.h"
    2526#include "pmTrend2D.h"
    2627#include "pmResiduals.h"
     
    4950static float AP_MIN_SN = 0.0;
    5051
    51 bool pmSourceMagnitudesInit (psMetadata *config)
    52 {
    53     PS_ASSERT_PTR_NON_NULL(config, false);
     52// make this a bit more clever and dynamic
     53static psImageMaskType maskSuspect  = 0;
     54static psImageMaskType maskSpike    = 0;
     55static psImageMaskType maskStarCore = 0;
     56static psImageMaskType maskBurntool = 0;
     57static psImageMaskType maskConvPoor = 0;
     58
     59bool pmSourceMagnitudesInit (pmConfig *config, psMetadata *recipe)
     60{
     61    PS_ASSERT_PTR_NON_NULL(recipe, false);
    5462    bool status;
    5563
    56     float limit = psMetadataLookupF32 (&status, config, "AP_MIN_SN");
     64    // we are going to test specially against these poor values
     65    if (config) {
     66        maskSpike    = pmConfigMaskGet("SPIKE", config);
     67        maskStarCore = pmConfigMaskGet("STARCORE", config);
     68        maskBurntool = pmConfigMaskGet("BURNTOOL", config);
     69        maskConvPoor = pmConfigMaskGet("CONV.POOR", config);
     70        maskSuspect  = maskSpike | maskStarCore | maskBurntool | maskConvPoor;
     71    }
     72
     73    float limit = psMetadataLookupF32 (&status, recipe, "AP_MIN_SN");
    5774    if (status) {
    5875        AP_MIN_SN = limit;
     
    7794// XXX masked region should be (optionally) elliptical
    7895// if mode is PM_SOURCE_PHOT_PSFONLY, we skip all other magnitudes
    79 bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal, psImageMaskType markVal)
     96bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal, psImageMaskType markVal, float radius)
    8097{
    8198    PS_ASSERT_PTR_NON_NULL(source, false);
     
    166183    // measure the contribution of included pixels
    167184    if (mode & PM_SOURCE_PHOT_WEIGHT) {
    168         pmSourcePixelWeight (&source->pixWeightNotBad, &source->pixWeightNotPoor, model, source->maskObj, maskVal, markVal);
     185        pmSourcePixelWeight (source, model, source->maskObj, maskVal, radius);
    169186    }
    170187
     
    342359
    343360// return source aperture magnitude
    344 bool pmSourcePixelWeight (float *pixWeightNotBad, float *pixWeightNotPoor, pmModel *model, psImage *mask, psImageMaskType maskVal, psImageMaskType markVal)
    345 {
    346     PS_ASSERT_PTR_NON_NULL(pixWeightNotBad, false);
    347     PS_ASSERT_PTR_NON_NULL(pixWeightNotPoor, false);
     361bool pmSourcePixelWeight (pmSource *source, pmModel *model, psImage *mask, psImageMaskType maskVal, float radius)
     362{
     363    PS_ASSERT_PTR_NON_NULL(source, false);
     364    source->pixWeightNotBad = NAN;
     365    source->pixWeightNotPoor = NAN;
     366
    348367    PS_ASSERT_PTR_NON_NULL(mask, false);
    349368    PS_ASSERT_PTR_NON_NULL(model, false);
     
    355374    float value;
    356375
     376    float spikeSum = 0;
     377    float starcoreSum = 0;
     378    float burntoolSum = 0;
     379    float convpoorSum = 0;
     380
    357381    int Xo, Yo, dP;
    358382    int dX, DX, NX;
    359383    int dY, DY, NY;
    360384
    361     *pixWeightNotBad = 0.0;
    362     *pixWeightNotPoor = 0.0;
     385    float radius2 = PS_SQR(radius);
    363386
    364387    // we only care about the value of the object model, not the local sky
     
    387410    NY = mask->numRows;
    388411
     412    psImageMaskType maskBad = maskVal;
     413    maskBad &= ~maskSuspect;
     414
    389415    // measure modelSum and validSum.  this function is applied to a sources' subimage.  the
    390416    // value of DX is chosen (see above) to cover the full possible size of the subimage if it
    391417    // were not by an edge; ie, if the source is cut in half by an image edge, we correctly
    392418    // count the virtual pixels off the edge in normalizing the value of the pixWeight
     419
     420    // we skip any pixels [real or virtual] outside of the specified radius (nominally the aperture radius)
    393421    for (int ix = -DX; ix < DX + 1; ix++) {
     422        if (ix > radius) continue;
    394423        int mx = ix + dX;
    395424        for (int iy = -DY; iy < DY + 1; iy++) {
     425            if (iy > radius) continue;
     426            if (ix*ix + iy*iy > radius2) continue;
    396427            int my = iy + dY;
    397428
     
    409440            if (my >= NY) continue;
    410441
    411             if (!(mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskVal)) {
     442            // count pixels which are masked only with bad pixels
     443            if (!(mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskBad)) {
    412444                notBadSum += value;
    413445            }
    414             if (!(mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & ~markVal)) {
     446
     447            // count pixels which are masked with an mask bit (bad or poor)
     448            if (!(mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskVal)) {
    415449                notPoorSum += value;
    416450            }
     451
     452            // count pixels which are masked with an mask bit (bad or poor)
     453            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskSpike) {
     454                spikeSum += value;
     455            }
     456            // count pixels which are masked with an mask bit (bad or poor)
     457            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskStarCore) {
     458                starcoreSum += value;
     459            }
     460            // count pixels which are masked with an mask bit (bad or poor)
     461            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskBurntool) {
     462                burntoolSum += value;
     463            }
     464            // count pixels which are masked with an mask bit (bad or poor)
     465            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskConvPoor) {
     466                convpoorSum += value;
     467            }
    417468        }
    418469    }
    419470    psFree (coord);
    420471
    421     *pixWeightNotBad  = notBadSum  / modelSum;
    422     *pixWeightNotPoor = notPoorSum / modelSum;
     472    source->pixWeightNotBad  = notBadSum  / modelSum;
     473    source->pixWeightNotPoor = notPoorSum / modelSum;
     474
     475    if ((spikeSum/modelSum) > 0.25) {
     476        source->mode2 |= PM_SOURCE_MODE2_ON_SPIKE;
     477    }
     478    if ((starcoreSum/modelSum) > 0.25) {
     479        source->mode2 |= PM_SOURCE_MODE2_ON_STARCORE;
     480    }
     481    if ((burntoolSum/modelSum) > 0.25) {
     482        source->mode2 |= PM_SOURCE_MODE2_ON_BURNTOOL;
     483    }
     484    if ((convpoorSum/modelSum) > 0.25) {
     485        source->mode2 |= PM_SOURCE_MODE2_ON_CONVPOOR;
     486    }
     487
     488    if (isfinite(source->pixWeightNotBad) && isfinite(source->pixWeightNotPoor)) {
     489        psAssert (source->pixWeightNotBad <= source->pixWeightNotPoor, "error: all bad pixels should also be poor");
     490    }
    423491
    424492    return (true);
     
    427495# define FLUX_LIMIT 3.0
    428496
    429 // measure stats that may be using in difference images for distinguishing real sources from bad residuals
     497// measure stats that may be used in difference images for distinguishing real sources from bad residuals
    430498bool pmSourceMeasureDiffStats (pmSource *source, psImageMaskType maskVal, psImageMaskType markVal)
    431499{
     
    673741# endif
    674742
    675 // determine chisq, etc for linear normalization-only fit
    676 bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *variance, psImageMaskType maskVal, const float covarFactor)
     743// determine chisq, nPix, nDOF, chisqNorm : model->nPar must be set
     744bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *variance, psImageMaskType maskVal)
    677745{
    678746    PS_ASSERT_PTR_NON_NULL(model, false);
     
    689757            if (variance->data.F32[j][i] <= 0)
    690758                continue;
    691             dC += PS_SQR (image->data.F32[j][i]) / (covarFactor * variance->data.F32[j][i]);
     759            dC += PS_SQR (image->data.F32[j][i]) / variance->data.F32[j][i];
    692760            Npix ++;
    693761        }
    694762    }
    695763    model->nPix = Npix;
    696     model->nDOF = Npix - 1;
     764    model->nDOF = Npix - model->nPar;
    697765    model->chisq = dC;
     766    model->chisqNorm = dC / model->nDOF;
    698767
    699768    return (true);
    700769}
    701770
     771
     772// return source aperture magnitude
     773bool pmSourceChisqUnsubtracted (pmSource *source, pmModel *model, psImageMaskType maskVal)
     774{
     775    PS_ASSERT_PTR_NON_NULL(source, false);
     776    PS_ASSERT_PTR_NON_NULL(model, false);
     777
     778    float dC = 0.0;
     779    int Npix = 0;
     780
     781    // the model function returns the source flux at a position
     782    psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
     783
     784    psVector *params = model->params;
     785    psImage  *image = source->pixels;
     786    psImage  *mask = source->maskObj;
     787    psImage  *variance = source->variance;
     788
     789    int dX = image->col0;
     790    int dY = image->row0;
     791
     792    for (int iy = 0; iy < image->numRows; iy++) {
     793        for (int ix = 0; ix < image->numCols; ix++) {
     794
     795            // skip pixels which are masked
     796            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal) continue;
     797
     798            if (variance->data.F32[iy][ix] <= 0) continue;
     799
     800            coord->data.F32[0] = (psF32) ix + dX + 0.5;
     801            coord->data.F32[1] = (psF32) iy + dY + 0.5;
     802
     803            // for the full model, add all points
     804            float value = model->modelFunc (NULL, params, coord);
     805
     806            // fprintf (stderr, "%d, %d : %f, %f : %f - %f : %f\n",
     807            // ix, iy, coord->data.F32[0], coord->data.F32[1], image->data.F32[iy][ix], value, dC);
     808
     809            dC += PS_SQR (image->data.F32[iy][ix] - value) / variance->data.F32[iy][ix];
     810            Npix ++;
     811        }
     812    }
     813    model->nPix = Npix;
     814    model->nDOF = Npix - model->nPar;
     815    model->chisq = dC;
     816    model->chisqNorm = dC / model->nDOF;
     817
     818    psFree (coord);
     819    return (true);
     820}
    702821
    703822double pmSourceModelWeight(const pmSource *Mi, int term, const bool unweighted_sum, const float covarFactor, psImageMaskType maskVal)
  • trunk/psModules/src/objects/pmSourcePhotometry.h

    r29546 r31153  
    6464);
    6565
    66 bool pmSourceMagnitudesInit (psMetadata *config);
    67 bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal, psImageMaskType markVal);
     66bool pmSourceMagnitudesInit (pmConfig *config, psMetadata *recipe);
     67bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal, psImageMaskType markVal, float radius);
    6868
    69 bool pmSourcePixelWeight (float *pixWeightNotBad, float *pixWeightNotPoor, pmModel *model, psImage *mask, psImageMaskType maskVal, psImageMaskType markVal);
     69bool pmSourcePixelWeight (pmSource *source, pmModel *model, psImage *mask, psImageMaskType maskVal, float radius);
    7070
    71 bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *weight, psImageMaskType maskVal, const float covarFactor);
     71bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *weight, psImageMaskType maskVal);
     72bool pmSourceChisqUnsubtracted (pmSource *source, pmModel *model, psImageMaskType maskVal);
    7273
    7374bool pmSourceMeasureDiffStats (pmSource *source, psImageMaskType maskVal, psImageMaskType markVal);
  • trunk/psModules/src/objects/pmSourceVisual.c

    r29004 r31153  
    5656
    5757    if (!pmVisualTestLevel("psphot.psf.metric", 2)) return true;
    58 
    59     if (kapa1 == -1) {
    60         kapa1 = KapaOpenNamedSocket ("kapa", "pmSource:plots");
    61         if (kapa1 == -1) {
    62             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    63             pmVisualSetVisual(false);
    64             return false;
    65         }
    66     }
     58    if (!pmVisualInitWindow (&kapa1, "pmSource:plots")) return false;
    6759
    6860    KapaClearSections (kapa1);
     
    140132
    141133    if (!pmVisualTestLevel("psphot.psf.subpix", 3)) return true;
    142 
    143     if (kapa1 == -1) {
    144         kapa1 = KapaOpenNamedSocket ("kapa", "pmSource:plots");
    145         if (kapa1 == -1) {
    146             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    147             pmVisualSetVisual(false);
    148             return false;
    149         }
    150     }
     134    if (!pmVisualInitWindow (&kapa1, "pmSource:plots")) return false;
    151135
    152136    KapaClearSections (kapa1);
    153137    KapaInitGraph (&graphdata);
     138    section.bg = KapaColorByName ("none"); // XXX probably should be 'none'
    154139
    155140    int n;
     
    302287
    303288    if (!pmVisualTestLevel("psphot.psf.fits", 2)) return true;
    304 
    305     if (kapa2 == -1) {
    306         kapa2 = KapaOpenNamedSocket ("kapa", "pmSource:images");
    307         if (kapa2 == -1) {
    308             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    309             pmVisualSetVisual(false);
    310             return false;
    311         }
    312     }
     289    if (!pmVisualInitWindow (&kapa2, "pmSource:images")) return false;
    313290
    314291    // create images 1/10 scale:
     
    385362    if (!source->pixels) return false;
    386363    if (!source->modelFlux) return false;
    387 
    388     if (kapa2 == -1) {
    389         kapa2 = KapaOpenNamedSocket ("kapa", "pmSource:images");
    390         if (kapa2 == -1) {
    391             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    392             pmVisualSetVisual(false);
    393             return false;
    394         }
    395     }
     364    if (!pmVisualInitWindow (&kapa2, "pmSource:images")) return false;
    396365
    397366    // KapaClearSections (kapa2);
     
    428397    if (!plotPSF) return true;
    429398    if (!pmVisualTestLevel("psphot.psf.resid", 2)) return true;
    430 
    431     if (kapa1 == -1) {
    432         kapa1 = KapaOpenNamedSocket ("kapa", "pmSource:plots");
    433         if (kapa1 == -1) {
    434             fprintf (stderr, "failure to open kapa; visual mode disabled\n");
    435             pmVisualSetVisual(false);
    436             return false;
    437         }
    438     }
     399    if (!pmVisualInitWindow (&kapa1, "pmSource:plots")) return false;
    439400
    440401    KapaClearPlots (kapa1);
    441402    KapaInitGraph (&graphdata);
     403    section.bg = KapaColorByName ("none"); // XXX probably should be 'none'
    442404
    443405    float Xmin = +1e32;
Note: See TracChangeset for help on using the changeset viewer.