IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Oct 20, 2010, 8:55:04 AM (16 years ago)
Author:
eugene
Message:

update the source size analysis : CR now detected using M_minor and Kron mag; EXT now detected using only psf - kron mags; update visualization of source sizes; fix apresid visualization (kron vs apmag options); for stand-alone psphot, do not mask as SAT NAN pixels which are already masked; function for dynamic calculation of CR detection parameters

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-20100823/psphot/src/psphotSourceSize.c

    r29459 r29491  
    11# include "psphotInternal.h"
    22# include <gsl/gsl_sf_gamma.h>
    3 
    4 # define KRON 1
    53
    64typedef struct {
     
    1614    int grow;
    1715    int xtest, ytest;
    18     bool apply; // apply CR mask?
     16    bool applyCRmask; // apply CR mask?
     17    bool dynamicLimitsCR; // apply CR mask?
     18    float sizeLimitCR;
     19    float magLimitCR;
    1920} psphotSourceSizeOptions;
    2021
    2122// local functions:
    22 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf);
     23bool psphotSourceSizePSF (psphotSourceSizeOptions *options, pmReadout *readout, psArray *sources, pmPSF *psf, psMetadata *recipe);
     24bool psphotDynamicLimitsCR (psphotSourceSizeOptions *options, pmReadout *readout, psArray *sources, pmPSF *psf, psMetadata *recipe);
    2325bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
    2426bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
    25 bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options);
     27bool psphotSourceSelectCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options);
    2628bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal);
    2729bool psphotMaskCosmicRayFootprintCheck (psArray *sources);
    2830int  psphotMaskCosmicRayConnected (int xPeak, int yPeak, psImage *mymask, psImage *myvar, psImage *edges, int binning, float sigma_thresh);
     31float psphotSourceSizeFindThreshold (psVector *value, psVector *mask, int maskValue, float minValue, float maxValue, float delta, float guess, float fraction);
    2932
    3033// we need to call this function after sources have been fitted to the PSF model and
     
    111114    assert (status);
    112115
    113     // XXX recipe name is not great
     116    // location of a single test source
    114117    options.xtest = psMetadataLookupS32 (&status, recipe, "PSPHOT.CRMASK.XTEST");
    115118    options.ytest = psMetadataLookupS32 (&status, recipe, "PSPHOT.CRMASK.YTEST");
     
    128131    }
    129132
    130     options.apply = psMetadataLookupBool(&status, recipe, "PSPHOT.CRMASK.APPLY"); // Growth size for CRs
     133    options.applyCRmask = psMetadataLookupBool(&status, recipe, "PSPHOT.CRMASK.APPLY"); // Growth size for CRs
    131134    if (!status) {
    132135        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSPHOT.CRMASK.APPLY is not defined.");
     
    134137    }
    135138
    136     // We are using the value psfMag - 2.5*log10(moment.Sum) as a measure of the extendedness
    137     // of an object.  We need to model this distribution for the PSF stars before we can test
    138     // the significance for a specific object
    139     // XXX move this to the code that generates the PSF?
    140     // XXX store the results on pmPSF?
    141 
    142     // XXX this should only be done on the first pass (ie, if we have newSources or allSources?)
    143     if (getPSFsize) {
    144         psphotSourceSizePSF (&options, sources, psf);
    145     }
    146 
    147     // classify the sources based on ApResid and Moments (extended sources)
     139    // determine the distribution of (PSF_mag - KRON_mag) for the PSF sources (saved on readout->analysis)
     140    psphotSourceSizePSF (&options, readout, sources, psf, recipe);
     141
     142    // adjust the user-supplied limits based on the distribution of CRs in the (Mminor, mKron) space
     143    psphotDynamicLimitsCR(&options, readout, sources, psf, recipe);
     144
     145    // classify the sources based on ApResid and Moments
    148146    // NOTE: only sources not already measured !(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)
    149147    psphotSourceClass(readout, sources, recipe, psf, &options);
    150148
    151     // NOTE: only sources not already measured !(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)
    152     psphotSourceSizeCR (readout, sources, &options);
     149    // attempt to mask the candidate CRs; flag if CR nature is confirmed
     150    psphotSourceSelectCR(readout, sources, &options);
    153151
    154152    // XXX fix this (was source->n  - first)
     
    156154
    157155    psphotVisualPlotSourceSize (recipe, readout->analysis, sources);
     156    psphotVisualPlotSourceSizeAlt (recipe, readout->analysis, sources);
    158157    psphotVisualShowSourceSize (readout, sources);
    159     psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr);
     158    psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr, false);
    160159    psphotVisualShowSatStars (recipe, psf, sources);
    161160
     
    163162}
    164163
     164# define SAVE_PSF_OPTIONS(RO,OPT)                                       \
     165    /* save these on readout->analysis (a) for output to the header and (b) to prevent re-calculating in another pass */ \
     166    psMetadataAddF32(RO->analysis, PS_LIST_TAIL, "PSPHOT.PSF.APRESID", PS_META_REPLACE, "locus of PSF stars in PSF_MAG - KRON_MAG", OPT->ApResid); \
     167    psMetadataAddF32(RO->analysis, PS_LIST_TAIL, "PSPHOT.PSF.APRESID.SYSERR",  PS_META_REPLACE, "systematic error of PSF_MAG - KRON_MAG",  OPT->ApSysErr);
     168
    165169// model the apmifit distribution for the psf stars:
    166 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) {
     170bool psphotSourceSizePSF (psphotSourceSizeOptions *options, pmReadout *readout, psArray *sources, pmPSF *psf, psMetadata *recipe) {
     171
     172    // We are using the value PSF_MAG - KRON_MAG as a measure of the extendedness of an object.
     173    // We need to model this distribution for the PSF stars before we can test the significance
     174    // for a specific object.
     175
     176    // NOTE: we require that objects have had moments measured, and we also require psfMags to
     177    // be calculated.  but, we do not require aperture mags or any other photometry values that
     178    // require pixel analysis.
     179
     180    bool status1 = false;
     181    bool status2 = false;
     182    options->ApResid = psMetadataLookupF32 (&status1, readout->analysis, "PSPHOT.PSF.APRESID");
     183    options->ApSysErr = psMetadataLookupF32 (&status2, readout->analysis, "PSPHOT.PSF.APRESID.SYSERR");
     184    psAssert ((status1 && status2) || (!status1 && !status2), "inconsistent record of PSF ApResid values");
     185
     186    // if they are saved on readout->analysis, we have already calculated these values
     187    if (status1 && status2) {
     188        return true;
     189    }
    167190
    168191    // select stats from the psf stars
    169     psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32);
     192    psVector *ApOff = psVectorAllocEmpty (100, PS_TYPE_F32);
    170193    psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);
    171194
     
    173196    psImageMaskType maskVal = options->maskVal | options->markVal;
    174197
    175     // XXX  why PHOT_WEIGHT??
    176     pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
     198    // with PSFONLY, we do not need modify the pixels
     199    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_PSFONLY;
    177200
    178201    int num = 0;                        // Number of sources measured
     
    182205        num++;
    183206
    184         // replace object in image
    185         if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
    186             pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
    187         }
    188 
    189         // clear the mask bit and set the circular mask pixels
    190         psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
    191         psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
    192 
    193         // XXX can we test if psfMag is set and calculate only if needed?
    194207        pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
    195208
    196         // clear the mask bit
    197         psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
    198 
    199         // re-subtract the object, leave local sky
    200         pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
    201 
    202         // XXX test: switch to kron flux
    203 # if (KRON)
    204         float apMag = -2.5*log10(source->moments->KronFlux);
    205 # else
    206         float apMag = -2.5*log10(source->moments->Sum);
    207 # endif
    208         float dMag = source->psfMag - apMag;
    209 
    210         psVectorAppend (Ap, dMag);
     209        float kMag = -2.5*log10(source->moments->KronFlux);
     210        float dMag = source->psfMag - kMag;
     211
     212        psVectorAppend (ApOff, dMag);
    211213        psVectorAppend (ApErr, source->errMag);
    212214    }
    213215    if (num == 0) {
    214         // Not raising an error, because errors aren't being checked elsewhere in this function
    215         psFree(Ap);
     216        // if we cannot determine the PSF distribution, call all objects PSFs...
     217        options->ApResid = NAN;
     218        options->ApSysErr = NAN;
     219        psFree(ApOff);
    216220        psFree(ApErr);
     221        SAVE_PSF_OPTIONS(readout, options);
    217222        return false;
    218223    }
     
    221226    // psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);   
    222227    psStats *stats = psStatsAlloc(PS_STAT_CLIPPED_MEAN);   
    223     psVectorStats (stats, Ap, NULL, NULL, 0);
    224 
    225     psVector *dAp = psVectorAlloc (Ap->n, PS_TYPE_F32);
    226     for (int i = 0; i < Ap->n; i++) {
    227         dAp->data.F32[i] = Ap->data.F32[i] - stats->clippedMean;
     228    psVectorStats (stats, ApOff, NULL, NULL, 0);
     229
     230    psVector *dAp = psVectorAlloc (ApOff->n, PS_TYPE_F32);
     231    for (int i = 0; i < ApOff->n; i++) {
     232        dAp->data.F32[i] = ApOff->data.F32[i] - stats->clippedMean;
    228233    }
    229234
    230235    options->ApResid = stats->clippedMean;
    231236    options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.1);
    232     // XXX this is quite arbitrary...
    233     if (!isfinite(options->ApSysErr)) options->ApSysErr = 0.01;
     237
     238    // this is quite arbitrary... a large value means fewer things classified as extended.
     239    if (!isfinite(options->ApSysErr)) options->ApSysErr = 0.05;
    234240    psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr);
    235241
    236     psFree (Ap);
     242    psFree (ApOff);
    237243    psFree (ApErr);
    238244    psFree (stats);
    239245    psFree (dAp);
    240246
     247    SAVE_PSF_OPTIONS(readout, options);
    241248    return true;
     249}
     250
     251# define SAVE_CR_OPTIONS(RO,OPT)                                        \
     252    /* save these on readout->analysis (a) for output to the header and (b) to prevent re-calculating in another pass */  \
     253    psMetadataAddF32(RO->analysis, PS_LIST_TAIL, "PSPHOT.CR.MAX.SIZE", PS_META_REPLACE, "dynamically-set minor axis size limit for cosmic rays", OPT->sizeLimitCR); \
     254    psMetadataAddF32(RO->analysis, PS_LIST_TAIL, "PSPHOT.CR.MAX.MAG",  PS_META_REPLACE, "dynamically-set kron magnitude limit for cosmic rays",  OPT->magLimitCR);
     255
     256// model the size and magnitude distribution of the Cosmic Rays
     257// ** CRs are reliably flagged by a combination on Mminor < X && mag (or flux) > Y
     258bool psphotDynamicLimitsCR (psphotSourceSizeOptions *options, pmReadout *readout, psArray *sources, pmPSF *psf, psMetadata *recipe) {
     259
     260    /* attempt to describe the CR sources:
     261       - input parameters are sizeLimit, magLimit
     262       - first try to refine the sizeLimit:
     263       -- select objects which meet the magLimit and exceed the sizeLimit by a factor of 1.5
     264       -- generate the histogram
     265       -- look for a peak in the histogram
     266       -- look for the min between valley and upper limit
     267       -- look for first bin within 5% of the valley floor after peak (new sizeLimit)
     268       
     269       - next try to refine the magLimit
     270       -- select objects which meet the sizeLimit and go fainter than the magLimit by 1.0 mag
     271       -- generate the histogram
     272       -- look for a peak in the histogram
     273       -- look for the min between valley and upper limit
     274       -- look for first bin within 5% of the valley floor after peak (new magLimit)
     275    */
     276
     277    bool status  = false;
     278    bool status1 = false;
     279    bool status2 = false;
     280    options->sizeLimitCR = psMetadataLookupF32 (&status1, readout->analysis, "PSPHOT.CR.MAX.SIZE");
     281    if (!status1) {
     282        options->sizeLimitCR = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.MAX.SIZE");
     283        if (!status) {
     284            options->sizeLimitCR = 1.0;
     285        }
     286    }
     287    options->magLimitCR = psMetadataLookupF32 (&status2, readout->analysis, "PSPHOT.CR.MAX.MAG");
     288    if (!status2) {
     289        options->magLimitCR = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.MAX.MAG");
     290        if (!status) {
     291            options->magLimitCR = -8.0;
     292        }
     293    }
     294    psAssert ((status1 && status2) || (!status1 && !status2), "inconsistent record of dynamic CR limits");
     295
     296    // if they are saved on readout->analysis, we have already calculated these values
     297    if (status1 && status2) {
     298        return true;
     299    }
     300
     301    // if we do not want to dynamically set these, save the user-supplied values and exit
     302    options->dynamicLimitsCR = psMetadataLookupBool (&status, recipe, "PSPHOT.CR.AUTOSCALE");
     303    if (!status) {
     304        options->dynamicLimitsCR = true;
     305    }
     306    if (!options->dynamicLimitsCR) {
     307        SAVE_CR_OPTIONS(readout, options); // macro defined above
     308        return true;
     309    }
     310
     311    psVector *minor = psVectorAllocEmpty (100, PS_TYPE_F32);
     312    psVector *mKron = psVectorAllocEmpty (100, PS_TYPE_F32);
     313    psVector *mask  = NULL;
     314
     315    psImageMaskType markVal = options->markVal;
     316    psImageMaskType maskVal = options->maskVal | options->markVal;
     317
     318    // with PSFONLY, we do not need modify the pixels
     319    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_PSFONLY;
     320
     321    // generate vectors for all the objects of possible interest (so we can just access those
     322    // vectors in the next sections)
     323    for (int i = 0; i < sources->n; i++) {
     324        pmSource *source = sources->data[i];
     325
     326        // XXX can we test if psfMag is set and calculate only if needed?
     327        pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
     328
     329        // convert to Mmaj, Mmin:
     330        psF32 Mxx = source->moments->Mxx;
     331        psF32 Myy = source->moments->Myy;
     332        psF32 Mxy = source->moments->Mxy;
     333
     334        float KronMag = -2.5*log10(source->moments->KronFlux);
     335
     336        float Mminor = 0.5*(Mxx + Myy) - 0.5*sqrt(PS_SQR(Mxx - Myy) + 4.0*PS_SQR(Mxy));
     337
     338        if (Mminor > options->sizeLimitCR * 1.5) continue;
     339        if (KronMag > options->magLimitCR + 2.5) continue;
     340
     341        psVectorAppend (mKron, KronMag);
     342        psVectorAppend (minor, Mminor);
     343    }
     344
     345    // if too few objects meet the criterion, give up..
     346    if (mKron->n < 50) goto escape;
     347
     348    // set distinct masks for (minor > sizeLimit) or (mKron > magLimit)
     349    mask = psVectorAlloc(mKron->n, PS_TYPE_U8);
     350    psVectorInit(mask, 0);
     351    for (int i = 0; i < mKron->n; i++) {
     352        if (mKron->data.F32[i] > options->magLimitCR) {
     353            mask->data.U8[i] |= 0x01;
     354        }
     355        if (minor->data.F32[i] > options->sizeLimitCR) {
     356            mask->data.U8[i] |= 0x02;
     357        }
     358    }
     359       
     360    float delta1 = PS_MAX(0.02, PS_MIN(0.2, 5.0 * 0.5 / minor->n));
     361    float newSizeLimit = psphotSourceSizeFindThreshold(minor, mask, 0x01, 0.0, options->sizeLimitCR * 1.5, delta1, options->sizeLimitCR, 0.05);
     362    if (isfinite(newSizeLimit)) {
     363        options->sizeLimitCR = newSizeLimit;
     364    }
     365
     366    float delta2 = PS_MAX(0.02, PS_MIN(0.2, 5.0 * 2.0 / minor->n));
     367    float newMagLimit = psphotSourceSizeFindThreshold(mKron, mask, 0x02, -15.0, options->magLimitCR + 2.5, delta2, options->magLimitCR, 0.05);
     368    if (isfinite(newMagLimit)) {
     369        options->magLimitCR = newMagLimit;
     370    }
     371
     372    psLogMsg ("psphot", PS_LOG_DETAIL, "CR limits : %f mag | %f pix^2\n", options->magLimitCR, options->sizeLimitCR);
     373
     374    psFree (mKron);
     375    psFree (minor);
     376    psFree (mask);
     377
     378    // save these on readout->analysis (a) for output to the header and (b) to prevent re-calculating in another pass
     379    SAVE_CR_OPTIONS(readout, options); // macro defined above
     380    return true;
     381
     382 escape:
     383    SAVE_CR_OPTIONS(readout, options); // macro defined above
     384    return false;
    242385}
    243386
     
    249392    char regionName[64];
    250393
    251     psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip");
     394    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nskip");
     395
     396    if (!psphotSourceClassRegion (NULL, &psfClump, sources, recipe, psf, options)) {
     397        psLogMsg ("psphot", 4, "Failed to determine source classification for full image\n");
     398    } else {
     399        psLogMsg ("psphot", 4, "source classification for full image\n");
     400    }
     401    return true;
    252402
    253403    int nRegions = psMetadataLookupS32 (&status, readout->analysis, "PSF.CLUMP.NREGIONS");
     
    275425            continue;
    276426        }
     427        psLogMsg ("psphot", 4, "source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
    277428        // psphotVisualPlotSourceSize (recipe, readout->analysis, sources);
    278429    }
     
    281432}
    282433
    283 # define SIZE_SN_LIM 10
    284434bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
    285435
     
    291441    int Npsf  = 0;
    292442    int Ncr   = 0;
    293     int Nmiss = 0;
    294443    int Nskip = 0;
    295444
    296445    pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN;
    297     pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
     446
     447    // request the pixWeight values as well as the magnitudes
     448    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
    298449
    299450    psImageMaskType markVal = options->markVal;
     
    306457        // psfClumps are found for image subregions:
    307458        // skip sources not in this region
    308         if (source->peak->x <  region->x0) continue;
    309         if (source->peak->x >= region->x1) continue;
    310         if (source->peak->y <  region->y0) continue;
    311         if (source->peak->y >= region->y1) continue;
     459        if (region) {
     460            if (source->peak->x <  region->x0) continue;
     461            if (source->peak->x >= region->x1) continue;
     462            if (source->peak->y <  region->y0) continue;
     463            if (source->peak->y >= region->y1) continue;
     464        }
    312465
    313466        // skip source if it was already measured
     
    321474            source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
    322475            psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
    323             continue;
    324         }
    325 
    326         // we are basically classifying by moments
     476            Nskip ++;
     477            continue;
     478        }
     479
     480        // we are classifying by moments and PSF_MAG - KRON_MAG
    327481        psAssert (source->moments, "why is this source missing moments?");
    328482        if (source->mode & noMoments) {
     
    335489        psF32 Myy = source->moments->Myy;
    336490        psF32 Mxy = source->moments->Mxy;
    337 
    338         // replace object in image
     491        float Mminor = 0.5*(Mxx + Myy) - 0.5*sqrt(PS_SQR(Mxx - Myy) + 4.0*PS_SQR(Mxy));
     492
     493        // replace object in image to measure mag & psfWeights
    339494        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
    340495            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
     
    345500        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
    346501
    347         // XXX can we test if psfMag is set and calculate only if needed?
    348502        pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
    349503
     
    354508        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
    355509
    356 # if (KRON)
    357         float apMag = -2.5*log10(source->moments->KronFlux);
    358 # else
    359         float apMag = -2.5*log10(source->moments->Sum);
    360 # endif
    361         float dMag = source->psfMag - apMag;
    362 
    363         // set nSigma to include both systematic and poisson error terms
    364         // XXX need to handle NAN psfMag and apMag (ie, skip?)
    365         // XXX the 'poisson error' contribution for size is probably wrong...
    366         // XXX add in a hard floor on the Ap Sys Err (to be a bit generous)
    367         float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, hypot(options->ApSysErr, 0.025));
    368         float nSigmaMXX = (Mxx - psfClump->X) / hypot(psfClump->dX, psfClump->X*psfClump->X*source->errMag);
    369         float nSigmaMYY = (Myy - psfClump->Y) / hypot(psfClump->dY, psfClump->Y*psfClump->Y*source->errMag);
    370 
    371         // XXX should I change psfClump to use minor, major?
    372 
    373         // fprintf (stderr, "%f %f : Mxx: %f, Myy: %f, dx: %f, dy: %f, psfMag: %f, apMag: %f, dMag: %f, errMag: %f, nSigmaMag: %f, nSigmaMxx: %f, nSigmaMyy: %f\n",
    374         // source->peak->xf, source->peak->yf, Mxx, Myy, source->peak->xf - source->moments->Mx, source->peak->yf - source->moments->My,
    375         // source->psfMag, apMag, dMag, source->errMag, nSigmaMAG, nSigmaMXX, nSigmaMYY);
    376 
    377         // XXX double check on ths stuff!! partially-masked sources are more likely to be mis-measured PSFs
    378         float sizeBias = 1.0;
    379         if (source->pixWeightNotBad < 0.9) {
    380             sizeBias = 3.0;
    381         }
    382         if (source->pixWeightNotPoor < 0.9) {
    383             sizeBias = 3.0;
    384         }
    385 
    386         float minMxx = psfClump->X - sizeBias*options->nSigmaMoments*psfClump->dX;
    387         float minMyy = psfClump->Y - sizeBias*options->nSigmaMoments*psfClump->dY;
    388 
    389         // include MAG, MXX, and MYY?
     510        float kMag = -2.5*log10(source->moments->KronFlux);
     511        float dMag = source->psfMag - kMag;
     512
     513        // sources without a valid magnitudes cannot have their size measured
     514        if (!isfinite(kMag) || !isfinite(source->psfMag)) {
     515            Nskip ++;
     516            continue;
     517        }
     518
     519        // set nSigmaMAG to include both systematic and poisson error terms.  we include a hard
     520        // floor on the Ap Sys Err (to be a bit generous).  XXX put the floor in the recipe...
     521        float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, hypot(options->ApSysErr, 0.02));
    390522        source->extNsigma = nSigmaMAG;
    391523
     
    394526        // * CR & defect should have a faintess limit (min S/N)
    395527        // * SAT stars should not be faint, but defects may?
    396 
    397         // Anything within this region is a probably PSF-like object. Saturated stars may land
    398         // in this region, but are detected elsewhere on the basis of their peak value.
    399         bool isPSF = (fabs(nSigmaMAG) < options->nSigmaApResid) && (fabs(nSigmaMXX) < sizeBias*options->nSigmaMoments) && (fabs(nSigmaMYY) < sizeBias*options->nSigmaMoments);
    400         if (isPSF) {
    401           psTrace("psphotSourceClassRegion.PSF",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g PSF\t%g %g\n",
    402                   source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
    403                   options->nSigmaApResid,sizeBias*options->nSigmaMoments);
    404           source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
    405           Npsf ++;
    406           continue;
    407         }
    408528
    409529        // Defects may not always match CRs from peak curvature analysis
     
    413533        // (nSigmaMAG < -options->nSigmaApResid) ||
    414534
    415         // ** CRs are reliably flagged by a combination on Mminor < X && mag (or flux) > Y
    416 
    417         float Mminor = 0.5*(Mxx + Myy) - 0.5*sqrt(PS_SQR(Mxx - Myy) + 4.0*PS_SQR(Mxy));
    418         if ((Mminor < 1.0) && (apMag < -8.0)) {
    419             fprintf (stderr, "likely CR @ %f,%f\n", source->peak->xf, source->peak->yf);
    420         }
    421 
    422         // XXX do I need to find the Mminor, Mmajor distribution?
    423 
    424         bool isCR = isCR = (source->errMag < 1.0 / SIZE_SN_LIM) && ((Mxx < minMxx) || (Myy < minMyy));
     535        // saturated star (too many saturated pixels or peak above saturation limit).  These
     536        // may also be saturated galaxies, or just large saturated regions.
     537        if (source->mode & PM_SOURCE_MODE_SATSTAR) {
     538            psTrace("psphotSourceClassRegion.SAT",4,"CLASS: %g %g\t%g %g\t%g %g\t%g %g\t%g SAT\n",
     539                    source->peak->xf, source->peak->yf, Mminor, kMag, dMag, nSigmaMAG, options->sizeLimitCR, options->magLimitCR, options->nSigmaApResid);
     540            source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     541            Nsat ++;
     542            continue;
     543        }
     544
     545        // any sources missing a large fraction should just be treated as PSFs
     546        if ((source->pixWeightNotBad < 0.9) || (source->pixWeightNotPoor < 0.9)) {
     547            psTrace("psphotSourceClassRegion.PSF",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g PSF\t%g %g\n",
     548                    source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,kMag,dMag,nSigmaMAG,
     549                    options->nSigmaApResid,options->nSigmaMoments);
     550            source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     551            Npsf ++;
     552            continue;
     553        }
     554
     555        // CRs are flagged by a combination on Mminor < options->sizeLimitCR && kmag < options->magLimitCR
     556        // NOTE: we only flag the CRs here; when we mask them we verify their CR nature (otherwise -> PSF)
     557        // bool isCR = (kMag < options->magLimitCR) && (Mminor < options->sizeLimitCR);
     558        bool isCR = (source->moments->SN > 7.0) && (Mminor < options->sizeLimitCR);
    425559        if (isCR) {
    426             psTrace("psphotSourceClassRegion.CR",4,"CLASS: %g %g %f\t%g %g  %g %g  %g %g\t%g %g\t%g CR\t%g %g\n",
    427                     source->peak->xf,source->peak->yf,source->pixWeightNotBad,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
    428                     options->nSigmaApResid,sizeBias*options->nSigmaMoments);
     560            psTrace("psphotSourceClassRegion.CR",4,"CLASS: %g %g\t%g %g\t%g %g\t%g %g\t%g CR\n",
     561                    source->peak->xf, source->peak->yf, Mminor, kMag, dMag, nSigmaMAG, options->sizeLimitCR, options->magLimitCR, options->nSigmaApResid);
    429562            source->mode |= PM_SOURCE_MODE_DEFECT;
    430563            source->tmpFlags |= PM_SOURCE_TMPF_SIZE_CR_CANDIDATE;
     564            source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
    431565            Ncr ++;
    432566            continue;
    433567        }
    434568
    435         // saturated star (determined in PSF fit).  These may also be saturated galaxies, or
    436         // just large saturated regions.
    437         if (source->mode & PM_SOURCE_MODE_SATSTAR) {
    438             psTrace("psphotSourceClassRegion.SAT",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g SAT\t%g %g\n",
    439                     source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
    440                     options->nSigmaApResid,sizeBias*options->nSigmaMoments);
    441             source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
    442             Nsat ++;
    443             continue;
    444         }
    445 
    446         // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)?
    447         bool isEXT = (nSigmaMAG > options->nSigmaApResid) || (Mxx > minMxx) || (Myy > minMyy);
     569        // Likely extended source (PSF_MAG - KRON_MAG is larger than limit)
     570        bool isEXT = (nSigmaMAG > options->nSigmaApResid);
    448571        if (isEXT) {
    449           psTrace("psphotSourceClassRegion.EXT",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g Ext\t%g %g\n",
    450                   source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
    451                   options->nSigmaApResid,sizeBias*options->nSigmaMoments);
    452 
     572            psTrace("psphotSourceClassRegion.EXT",4,"CLASS: %g %g\t%g %g\t%g %g\t%g %g\t%g EXT\n",
     573                    source->peak->xf, source->peak->yf, Mminor, kMag, dMag, nSigmaMAG, options->sizeLimitCR, options->magLimitCR, options->nSigmaApResid);
    453574            source->mode |= PM_SOURCE_MODE_EXT_LIMIT;
    454575            source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     
    456577            continue;
    457578        }
    458         psTrace("psphotSourceClassRegion.MISS",4,"CLASS: %g %g\t%g %g  %g %g  %g %g\t%g %g\t%g Unk\t%g %g\n",
    459                 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
    460                 options->nSigmaApResid,sizeBias*options->nSigmaMoments);
    461 
    462         // sources that reach here are probably too faint for a reasonable source size measurement
    463         // psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigmaMAG);
    464         source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
    465         Nmiss ++;
    466     }
    467 
    468     psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip);
     579
     580        // Everything else should just be treated as a PSF
     581        psTrace("psphotSourceClassRegion.PSF",4,"CLASS: %g %g\t%g %g\t%g %g\t%g %g\t%g PSF\n",
     582                source->peak->xf, source->peak->yf, Mminor, kMag, dMag, nSigmaMAG, options->sizeLimitCR, options->magLimitCR, options->nSigmaApResid);
     583        source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
     584        Npsf ++;
     585    }
     586
     587    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nskip);
    469588
    470589    return true;
     
    473592// given an object suspected to be a defect, generate a pixel mask using the Lapacian transform
    474593// if enough of the object is detected as 'sharp', consider the object a cosmic ray
    475 bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
     594bool psphotSourceSelectCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
    476595
    477596    psTimerStart ("psphot.cr");
     
    481600        pmSource *source = sources->data[i];
    482601
    483         // skip source if it was already measured
    484         if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
    485             psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
    486             continue;
    487         }
    488 
    489602        // only check candidates marked above
    490603        if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_CR_CANDIDATE)) {
     
    493606        }
    494607
    495         // skip unless this source is thought to be a cosmic ray.  flag the detection and mask the pixels
    496         // XXX this may be degenerate with the above test
    497         if (!(source->mode & PM_SOURCE_MODE_DEFECT)) continue;
     608        // once we are here, remove the temporary flag
     609        source->mode &= ~PM_SOURCE_TMPF_SIZE_CR_CANDIDATE;
    498610
    499611        // Integer position of peak
     
    519631        // XXX this is running slowly and is too agressive, but it more-or-less works
    520632        psTrace("psphot", 6, "mask cosmic ray at %f, %f\n", source->peak->xf, source->peak->yf);
    521         if (options->apply) {
     633        if (options->applyCRmask) {
    522634            psphotMaskCosmicRay(readout, source, options->crMask);
    523635        } else {
     
    546658
    547659    // XXX test : save the mask image
    548     if (0) {
    549         psphotSaveImage (NULL, readout->mask,   "mask.fits");
     660    if (1) {
     661        psphotSaveImage (NULL, readout->mask,   "crmask.fits");
    550662    }
    551663
     
    736848    if (nCRpix > 1) {
    737849        source->mode |= PM_SOURCE_MODE_CR_LIMIT;
    738         source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
    739850    }
    740851    // fprintf (stderr, "CRMASK %d %d %d %d %d\n", peak->x, peak->y, dx, dy, nCRpix);
     
    12311342}
    12321343
     1344float psphotSourceSizeFindThreshold (psVector *value, psVector *mask, int maskValue, float minValue, float maxValue, float delta, float guess, float fraction) {
     1345
     1346    // make a histogram of the sources with mKron < magLimit
     1347    int nValue = (int)((maxValue - minValue) / delta) + 1;
     1348
     1349    psVector *histogram = psVectorAlloc(nValue, PS_TYPE_S32);
     1350    psVectorInit (histogram, 0);
     1351
     1352    for (int i = 0; i < value->n; i++) {
     1353        if (mask->data.U8[i] & maskValue) continue;
     1354        int bin = (value->data.F32[i] - minValue) / delta;
     1355        if (bin < 0.0) continue;
     1356        if (bin > histogram->n - 1) continue;
     1357        histogram->data.S32[bin] ++;
     1358    }
     1359
     1360    // find the peak of this histogram, but stop search at guess
     1361    int last = (guess - minValue) / delta;
     1362    int nPeak = 0;
     1363    int vPeak = histogram->data.S32[0];
     1364    for (int i = 1; (i < last) && (i < histogram->n); i++) {
     1365        if (histogram->data.S32[i] < vPeak) continue;
     1366        nPeak = i;
     1367        vPeak = histogram->data.S32[i];
     1368    }
     1369
     1370    // start at the peak and find the valley between here and the end of the histogram
     1371    int nValley = nPeak;
     1372    int vValley = histogram->data.S32[nPeak];
     1373    for (int i = nPeak + 1; i < histogram->n; i++) {
     1374        if (histogram->data.S32[i] > vValley) continue;
     1375        nValley = i;
     1376        vValley = histogram->data.S32[i];
     1377    }
     1378
     1379    psLogMsg ("psphot", PS_LOG_MINUTIA, "CR limits threshold : peak %d @ %f, valley %d @ %f (%f sigma)\n",
     1380              vPeak, delta * nPeak + minValue, vValley, delta * nValley + minValue, vPeak / PS_MAX(1.0, sqrt(vValley)));
     1381
     1382    if (nValley == nPeak) {
     1383        psFree (histogram);
     1384        return NAN;
     1385    }
     1386
     1387    if (vPeak < 3.0*sqrt(vValley)) {
     1388        psFree (histogram);
     1389        return NAN;
     1390    }
     1391
     1392    /// search for the first bin after the peak with f < vValley + 0.05*(vPeak - vValley)
     1393    float vLimit = vValley + fraction*(vPeak - vValley);
     1394    int nLimit = nValley;
     1395    for (int i = nPeak; i < nValley; i++) {
     1396        if (histogram->data.S32[i] > vLimit) continue;
     1397        nLimit = i;
     1398        break;
     1399    }
     1400    float result = nLimit * delta + minValue;
     1401
     1402    psFree (histogram);
     1403   
     1404    return result;
     1405}
Note: See TracChangeset for help on using the changeset viewer.