IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:50:52 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/simtest_nebulous_branches
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/simtest_nebulous_branches

  • branches/simtest_nebulous_branches/psphot

  • branches/simtest_nebulous_branches/psphot/src

    • Property svn:ignore
      •  

        old new  
        1818psphotVersionDefinitions.h
        1919psphotMomentsStudy
         20psphotPetrosianStudy
         21psphotForced
         22psphotMakePSF
         23psphotStack
  • branches/simtest_nebulous_branches/psphot/src/psphotApResid.c

    r24878 r27840  
    44// measure the aperture residual statistics and 2D variations
    55
    6 bool psphotApResid (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf)
     6// for now, let's store the detections on the readout->analysis for each readout
     7bool psphotApResid (pmConfig *config, const pmFPAview *view)
     8{
     9    bool status = true;
     10
     11    // select the appropriate recipe information
     12    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
     13    psAssert (recipe, "missing recipe?");
     14
     15    int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
     16    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
     17
     18    // skip the chisq image (optionally?)
     19    int chisqNum = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.CHISQ.NUM");
     20    if (!status) chisqNum = -1;
     21
     22    // loop over the available readouts
     23    for (int i = 0; i < num; i++) {
     24        if (i == chisqNum) continue; // skip chisq image
     25        if (!psphotApResidReadout (config, view, "PSPHOT.INPUT", i, recipe)) {
     26            psError (PSPHOT_ERR_CONFIG, false, "failed to measure aperture residual for PSPHOT.INPUT entry %d", i);
     27            return false;
     28        }
     29    }
     30    return true;
     31}
     32
     33bool psphotApResidReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe)
    734{
    835    int Nfail = 0;
     
    1340    pmSource *source;
    1441
    15     PS_ASSERT_PTR_NON_NULL(config, false);
    16     PS_ASSERT_PTR_NON_NULL(readout, false);
    17     PS_ASSERT_PTR_NON_NULL(sources, false);
    18     PS_ASSERT_PTR_NON_NULL(psf, false);
    19 
    2042    psTimerStart ("psphot.apresid");
    2143
    22     // select the appropriate recipe information
    23     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
    24     assert (recipe);
     44    // find the currently selected readout
     45    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
     46    psAssert (file, "missing file?");
     47
     48    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
     49    psAssert (readout, "missing readout?");
     50
     51    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
     52    psAssert (detections, "missing detections?");
     53
     54    psArray *sources = detections->allSources;
     55    psAssert (sources, "missing sources?");
     56
     57    if (!sources->n) {
     58        psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping ap resid");
     59        return true;
     60    }
     61
     62    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
     63    psAssert (psf, "missing psf?");
    2564
    2665    // determine the number of allowed threads
     
    3372    if (!measureAptrend) {
    3473        // save nan values since these were not calculated
    35         psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
    36         psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
    37         psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    38         psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
    39         psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    40         psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     74        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
     75        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
     76        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     77        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    4178        return true;
    4279    }
     
    5390    maskVal |= markVal;
    5491
    55     // S/N limit to perform full non-linear fits
     92    // clipping for extreme outliers
     93    // XXX this is not currently defined in the recipe
    5694    float MAX_AP_OFFSET = psMetadataLookupF32 (&status, recipe, "MAX_AP_OFFSET");
    5795
    58     // this is the smallest radius allowed: need to at least extend growth curve down to this...
     96    // options for how the photometry is calculated
     97    // XXX are these sensible?
    5998    bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");
    6099    bool INTERPOLATE_AP = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP");
     
    100139            PS_ARRAY_ADD_SCALAR(job->args, photMode, PS_TYPE_S32);
    101140            PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
     141            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
    102142
    103143            PS_ARRAY_ADD_SCALAR(job->args, 0,        PS_TYPE_S32); // this is used as a return value for Nskip
     
    110150            }
    111151            psFree(job);
    112 
    113 # if (0)
    114                 int nskip = 0;
    115                 int nfail = 0;
    116 
    117                 if (!psphotApResidMags_Unthreaded (&nskip, &nfail, sources, psf, photMode, maskVal)) {
    118                     psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
    119                     return false;
    120                 }
    121                 Nskip += nskip;
    122                 Nfail += nfail;
    123 # endif
    124 
    125152        }
    126153
     
    138165            } else {
    139166                psScalar *scalar = NULL;
    140                 scalar = job->args->data[4];
     167                scalar = job->args->data[5];
    141168                Nskip += scalar->data.S32;
    142                 scalar = job->args->data[5];
     169                scalar = job->args->data[6];
    143170                Nfail += scalar->data.S32;
    144171            }
     
    150177
    151178    // gather the stats to assess the aperture residuals
    152     psVector *mask    = psVectorAllocEmpty (300, PS_TYPE_VECTOR_MASK);
    153179    psVector *mag     = psVectorAllocEmpty (300, PS_TYPE_F32);
    154180    psVector *xPos    = psVectorAllocEmpty (300, PS_TYPE_F32);
     
    158184    Npsf = 0;
    159185
     186# ifdef DEBUG   
     187    FILE *f = fopen ("apresid.dat", "w");
     188    psAssert (f, "failed open");
     189# endif
     190
    160191    for (int i = 0; i < sources->n; i++) {
    161192        source = sources->data[i];
     
    170201        if (source->mode &  PM_SOURCE_MODE_EXT_LIMIT) SKIPSTAR ("EXTENDED");
    171202        if (source->mode &  PM_SOURCE_MODE_CR_LIMIT) SKIPSTAR ("COSMIC RAY");
     203        if (source->mode &  PM_SOURCE_MODE_DEFECT) SKIPSTAR ("DEFECT");
    172204           
    173205        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    174206            continue;
    175207        }
     208
     209        // XXX make this user-configurable?
     210        if (source->errMag > 0.01) continue;
    176211
    177212        // aperture residual for this source
     
    185220        }
    186221
    187         mag->data.F32[Npsf]     = source->psfMag;
    188         apResid->data.F32[Npsf] = dap;
    189         xPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_XPOS];
    190         yPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_YPOS];
    191 
    192         mask->data.PS_TYPE_VECTOR_MASK_DATA[Npsf] = 0;
    193 
    194         dMag->data.F32[Npsf] = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
    195 
    196         psVectorExtend (mag,     100, 1);
    197         psVectorExtend (mask,    100, 1);
    198         psVectorExtend (xPos,    100, 1);
    199         psVectorExtend (yPos,    100, 1);
    200         psVectorExtend (dMag,    100, 1);
    201         psVectorExtend (apResid, 100, 1);
     222# ifdef DEBUG
     223        fprintf (f, "%6.1f %6.1f : %6.1f %6.1f : %8.3f %8.3f %8.3f : %f : %f %f %f : %f\n",
     224                 source->peak->xf, source->peak->yf,
     225                 source->modelPSF->params->data.F32[PM_PAR_XPOS], source->modelPSF->params->data.F32[PM_PAR_YPOS],
     226                 source->psfMag, source->apMag, source->errMag,
     227                 source->modelPSF->params->data.F32[PM_PAR_I0],
     228                 source->modelPSF->params->data.F32[PM_PAR_SXX], source->modelPSF->params->data.F32[PM_PAR_SXY], source->modelPSF->params->data.F32[PM_PAR_SYY],
     229                 source->modelPSF->params->data.F32[PM_PAR_7]);
     230# endif
     231        if (!isfinite(source->psfMag)) psAbort ("nan in psfMag");
     232        if (!isfinite(source->errMag)) psAbort ("nan in errMag");
     233        if (!isfinite(source->apMag)) psAbort ("nan in apMag");
     234        if (!isfinite(model->params->data.F32[PM_PAR_XPOS])) psAbort ("nan in xPos");
     235        if (!isfinite(model->params->data.F32[PM_PAR_YPOS])) psAbort ("nan in yPos");
     236
     237        psVectorAppend (mag, source->psfMag);
     238        psVectorAppend (dMag,source->errMag);
     239        psVectorAppend (apResid, dap);
     240        psVectorAppend (xPos, model->params->data.F32[PM_PAR_XPOS]);
     241        psVectorAppend (yPos, model->params->data.F32[PM_PAR_YPOS]);
    202242        Npsf ++;
    203243    }
     
    205245    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "measure aperture residuals for %d objects (%d skipped, %d failed, %ld invalid)\n",
    206246              Npsf, Nskip, Nfail, sources->n - Npsf - Nskip - Nfail);
     247
     248# ifdef DEBUG
     249    fclose (f);
     250# endif
    207251
    208252    // XXX choose a better value here?
     
    212256    }
    213257
    214     // XXX deprecating the old code which allowed the ApResid to be fitted as a function of flux and r^2/flux
    215     // XXX is this asymmetric clipping still needed?  this analysis should come after neighbors are subtracted...
    216     // 3hi/1lo sigma clipping on the rflux vs metric fit
    217     // systematic error information
    218     float errorScale = 0.0;
    219     float errorFloor = 0.0;
    220 
     258    // this is a bit tricky, because we have two cases (MAP vs POLY), and they have a different
     259    // definition for 'order' (order_MAP = order_POLY + 1).  in addition, we have a
     260    // user-specified MAX order, which we should respect, regardless of the mode
     261
     262    // set the max order (0 = constant) which the number of psf stars can support:
     263    // rule of thumb: require 3 stars per 'cell' (order+1)^2
     264    int MaxOrderForStars = 0;
     265    if (Npsf >= 12) MaxOrderForStars = 1; // 4 cells
     266    if (Npsf >= 27) MaxOrderForStars = 2; // 9 cells
     267    if (Npsf >= 48) MaxOrderForStars = 3; // 16 cells
     268    if (Npsf >  75) MaxOrderForStars = 4; // 25 cells
     269
     270    pmTrend2DMode mode = PM_TREND_MAP;
     271    if (mode == PM_TREND_MAP) {
     272        MaxOrderForStars ++;
     273    }
     274    APTREND_ORDER_MAX = PS_MIN (APTREND_ORDER_MAX, MaxOrderForStars);
     275
     276    psFree (psf->ApTrend);
     277    psf->ApTrend = NULL;
    221278    float errorFloorMin = FLT_MAX;
    222     int entryMin = -1;
    223 
    224     // Fit out the dap vs mag trend, iterate over spatial scale until error Floor increases.
    225     // Stop if Npsf / (Nx * Ny) < 3
     279
     280    // as we loop over orders, we need to refer to the initial selection, but we modify the
     281    // option values to match the current guess: save the max values here:
     282    int NX = readout->image->numCols;
     283    int NY = readout->image->numRows;
    226284    for (int i = 1; i <= APTREND_ORDER_MAX; i++) {
    227 
    228         if (!psphotApResidTrend (readout, psf, Npsf, i, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag)) {
    229             break;
    230         }
    231 
    232         // store the resulting errorFloor values and the scales, redo the best
     285       
     286        int Nx, Ny;
     287        if (NX > NY) {
     288            Nx = i;
     289            Ny = PS_MAX (1, (int)(i * (NY / (float)(NX)) + 0.5));
     290        } else {
     291            Ny = i;
     292            Nx = PS_MAX (1, (int)(i * (NX / (float)(NY)) + 0.5));
     293        }
     294
     295        float errorFloor;
     296        pmTrend2D *apTrend = psphotApResidTrend (&errorFloor, readout, Nx, Ny, xPos, yPos, apResid, dMag);
     297        if (!apTrend) {
     298            continue;
     299        }
     300
     301        // apply ApTrend results
     302        // float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
     303        // float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
     304        // float ApResid = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
     305        // if (!isfinite(ApResid)) psAbort("nan apresid @ center");
     306
     307        // store the minimum errorFloor and best ApTrend to keep
    233308        if (errorFloor < errorFloorMin) {
    234309            errorFloorMin = errorFloor;
    235             entryMin = i;
     310            psFree (psf->ApTrend);
     311            psf->ApTrend = psMemIncrRefCounter(apTrend);
    236312        }
    237     }
    238     if (entryMin == -1) {
     313        psFree (apTrend);
     314    }
     315    if (psf->ApTrend == NULL) {
    239316        psWarning("Failed to find a valid aperture residual value");
    240317        goto escape;
    241318    }
    242319
    243     // XXX catch error condition
    244     psphotApResidTrend (readout, psf, Npsf, entryMin, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag);
     320    // apply ApTrend results
     321    float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
     322    float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
     323
     324    psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
     325    psf->dApResid = errorFloorMin;
     326    psf->nApResid = Npsf;
     327
     328    // save results for later output
     329    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
     330    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
     331    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
     332    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
     333
     334    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
     335    psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
     336
     337    psFree (xPos);
     338    psFree (yPos);
     339    psFree (apResid);
     340    psFree (mag);
     341    psFree (dMag);
     342
     343    psphotVisualPlotApResid (sources, psf->ApResid, psf->dApResid);
     344
     345    return true;
     346
     347escape:
     348    // save nan values since these were not calculated
     349    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
     350    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
     351    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
     352    psMetadataAdd (readout->analysis, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
     353
     354    psFree (xPos);
     355    psFree (yPos);
     356    psFree (apResid);
     357    psFree (mag);
     358    psFree (dMag);
     359    return true;
     360    // this is a quality error, not a programming error
     361}
     362
     363pmTrend2D *psphotApResidTrend (float *apResidSysErr, pmReadout *readout, int Nx, int Ny, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
     364
     365    // the mask marks the values not used to calculate the ApTrend
     366    psVector *mask = psVectorAlloc(xPos->n, PS_TYPE_VECTOR_MASK);
     367    psVectorInit (mask, 0);
     368
     369    // XXX allow user to set this optionally?
     370    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
     371
     372    // measure Trend2D for the current spatial scale
     373    pmTrend2D *apTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
     374
     375    // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
     376    // XXX use this or not?  probably not, since this is the point of the systematic error analysis
     377    psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
     378    for (int i = 0; i < dMag->n; i++) {
     379        dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.005);
     380    }
     381
     382    // XXX test for errors here
     383    if (!pmTrend2DFit (apTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft)) {
     384        psWarning("Failed to fit trend for %d x %d map", Nx, Ny);
     385        psFree (apTrend);
     386        return NULL;
     387    }
     388    if (apTrend->mode == PM_TREND_MAP) {
     389        // p_psImagePrint (2, apTrend->map->map, "ApTrend Before"); // XXX TEST:
     390        psImageMapRepair (apTrend->map->map);
     391        // p_psImagePrint (2, apTrend->map->map, "ApTrend After"); // XXX TEST:
     392    }
    245393
    246394    // construct the fitted values and the residuals
    247     psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
     395    psVector *apResidFit = pmTrend2DEvalVector (apTrend, mask, 0xff, xPos, yPos);
    248396    psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
    249     psVector *dMagSys = (psVector *) psBinaryOp (NULL, (void *) dMag, "*", (void *) psScalarAlloc(errorScale, PS_TYPE_F32));
    250 
    251     if (psTraceGetLevel("psphot") >= 2) {
    252         FILE *dumpFile = fopen ("apresid.dat", "w");
     397
     398    // measure systematic error
     399    *apResidSysErr = psVectorSystematicError (apResidRes, dMag, 0.10);
     400    if (!isfinite(*apResidSysErr)) {
     401        psWarning("Failed to find systematic error for %d x %d map", Nx, Ny);
     402        psFree (apTrend);
     403        return NULL;
     404    }
     405
     406    psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid\n", Nx, Ny);
     407    psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *apResidSysErr);
     408
     409    if (psTraceGetLevel("psphot") >= 4) {
     410        char filename[64];
     411        snprintf (filename, 64, "apresid.%dx%d.dat", Nx, Ny);
     412        FILE *dumpFile = fopen (filename, "w");
    253413        for (int i = 0; i < xPos->n; i++) {
    254             fprintf (dumpFile, "%f %f  %f %f %f %f %f  %x\n",
     414            fprintf (dumpFile, "%f %f  %f %f %f %f  %x\n",
    255415                     xPos->data.F32[i], yPos->data.F32[i],
    256                      mag->data.F32[i], dMag->data.F32[i], dMagSys->data.F32[i],
     416                     dMag->data.F32[i], hypot(dMag->data.F32[i], *apResidSysErr),
    257417                     apResid->data.F32[i], apResidRes->data.F32[i],
    258418                     mask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
     
    261421    }
    262422
    263     // apply ApTrend results
    264     float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
    265     float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
    266 
    267     psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
    268     psf->dApResid = errorFloor;
    269     psf->nApResid = Npsf;
    270 
    271     // save results for later output
    272     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   0.0);
    273     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   0.0);
    274     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
    275     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
    276     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
    277     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
    278 
    279     psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
    280     psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
    281 
    282     psFree (mag);
    283423    psFree (mask);
    284     psFree (xPos);
    285     psFree (yPos);
    286 
    287     psFree (apResid);
    288     psFree (apResidFit);
    289     psFree (apResidRes);
    290 
    291     psFree (dMagSys);
    292     psFree (dMag);
    293 
    294     psphotVisualPlotApResid (sources);
    295 
    296     return true;
    297 
    298 escape:
    299     // save nan values since these were not calculated
    300     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
    301     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
    302     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    303     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
    304     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    305     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
    306 
    307     psFree (mag);
    308     psFree (mask);
    309     psFree (xPos);
    310     psFree (yPos);
    311     psFree (apResid);
    312     psFree (dMag);
    313     return false;
    314 }
    315 
    316 /*
    317   (aprMag' - fitMag) = rflux*skyBias + ApTrend(x,y)
    318   (aprMag - rflux*skyBias) - fitMag = ApTrend(x,y)
    319   (aprMag - rflux*skyBias) = fitMag + ApTrend(x,y)
    320 */
    321 
    322 // XXX this still sucks...  need a better way to estimate the error floor...
    323 bool psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, psVector *mask, int nGroup) {
    324 
    325     psStats *statsS = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    326     psStats *statsM = psStatsAlloc (PS_STAT_SAMPLE_MEAN);
    327 
    328     // measure the trend in bins with 10 values each; if < 10 total, use them all
    329     int nBin = PS_MAX (dMag->n / nGroup, 1);
    330 
    331     // output vectors for ApResid trend
    332     psVector *dSo = psVectorAlloc (nBin, PS_TYPE_F32);
    333     psVector *dMo = psVectorAlloc (nBin, PS_TYPE_F32);
    334     psVector *dRo = psVectorAlloc (nBin, PS_TYPE_F32);
    335 
    336     // use dMag to group the dMag and dap vectors
    337     psVector *index = psVectorSortIndex (NULL, dMag);
    338 
    339     // subset vectors for dMag and dap values within the given range
    340     psVector *dMSubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
    341     psVector *dASubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
    342     psVector *mkSubset = psVectorAllocEmpty (nGroup, PS_TYPE_VECTOR_MASK);
    343 
    344     int n = 0;
    345     for (int i = 0; i < dMo->n; i++) {
    346         int j;
    347         for (j = 0; (j < nGroup) && (n < dMag->n); j++, n++) {
    348             int N = index->data.U32[n];
    349             dMSubset->data.F32[j] = dMag->data.F32[N];
    350             dASubset->data.F32[j] = dap->data.F32[N];
    351             mkSubset->data.PS_TYPE_VECTOR_MASK_DATA[j] = mask->data.PS_TYPE_VECTOR_MASK_DATA[N];
    352         }
    353         dMSubset->n = j;
    354         dASubset->n = j;
    355         mkSubset->n = j;
    356 
    357         psStatsInit (statsS);
    358         psStatsInit (statsM);
    359 
    360         if (j > 2) {
    361             if (!psVectorStats (statsS, dASubset, NULL, mkSubset, 0xff)) {
    362                 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    363                 return false;
    364             }
    365             if (!psVectorStats (statsM, dMSubset, NULL, mkSubset, 0xff)) {
    366                 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    367                 return false;
    368             }
    369             dSo->data.F32[i] = statsS->robustStdev;
    370             dMo->data.F32[i] = statsM->sampleMean;
    371             dRo->data.F32[i] = statsS->robustStdev / statsM->sampleMean;
    372         } else {
    373             dSo->data.F32[i] = NAN;
    374             dMo->data.F32[i] = NAN;
    375             dRo->data.F32[i] = NAN;
    376         }
    377     }
    378     psFree (dMSubset);
    379     psFree (dASubset);
    380     psFree (mkSubset);
    381 
    382     psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
    383     if (!psVectorStats (stats, dRo, NULL, NULL, 0)) {
    384         psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    385         return false;
    386     }
    387 
    388     *errorScale = stats->sampleMedian;
    389     for (int i = 0; i < dSo->n; i++) {
    390         *errorFloor = dSo->data.F32[i];
    391         if (fabs(*errorFloor) <= FLT_EPSILON) continue;
    392         if (isfinite(*errorFloor)) break;
    393     }
    394 
    395     psFree (stats);
    396     psFree (index);
    397 
    398     psFree (dRo);
    399     psFree (dMo);
    400     psFree (dSo);
    401 
    402     psFree (statsS);
    403     psFree (statsM);
    404 
    405     return true;
    406 }
    407 
    408 bool psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
    409 
    410     int Nx, Ny;
    411 
    412     if (readout->image->numCols > readout->image->numRows) {
    413         Nx = scale;
    414         float AR = readout->image->numRows / (float) readout->image->numCols;
    415         Ny = (int) (Nx * AR + 0.5);
    416         Ny = PS_MAX (1, Ny);
    417     } else {
    418         Ny = scale;
    419         float AR = readout->image->numRows / (float) readout->image->numCols;
    420         Nx = (int) (Ny * AR + 0.5);
    421         Nx = PS_MAX (1, Nx);
    422     }
    423 
    424     // require at least 10 stars per spatial bin
    425     if (Npsf < 10*Nx*Ny) {
    426         return false;
    427     }
    428 
    429     // the mask marks the values not used to calculate the ApTrend
    430     psVectorInit (mask, 0);
    431 
    432     // XXX stats structure for use by ApTrend : make parameters user setable
    433     psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    434     stats->min = 2.0;
    435     stats->max = 3.0;
    436 
    437     // measure Trend2D for the current spatial scale
    438     psFree (psf->ApTrend);
    439     psf->ApTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
    440 
    441     // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
    442     psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
    443     for (int i = 0; i < dMag->n; i++) {
    444         dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.01);
    445     }
    446 
    447     // XXX test for errors here
    448     pmTrend2DFit (psf->ApTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft);
    449 
    450     // construct the fitted values and the residuals
    451     psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
    452     psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
    453 
    454     // measure systematic errorFloor & systematic / photon scale factor
    455     // XXX this is a bit arbitrary, but it forces ~3 stars from the bright bin per spatial bin
    456     int nGroup = PS_MAX (3*Nx*Ny, 10);
    457     psphotMagErrorScale (errorScale, errorFloor, dMag, apResidRes, mask, nGroup);
    458 
    459     psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid (%d stars per bin)\n", Nx, Ny, nGroup);
    460     psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic error / photon error: %f\n", *errorScale);
    461     psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *errorFloor);
    462 
    463424    psFree (stats);
    464425    psFree (dMagSoft);
     
    466427    psFree (apResidRes);
    467428
    468     return true;
     429    return apTrend;
    469430}
    470431
     
    480441    pmSourcePhotometryMode photMode = PS_SCALAR_VALUE(job->args->data[2],S32);
    481442    psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[3],PS_TYPE_IMAGE_MASK_DATA);
     443    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
    482444
    483445    for (int i = 0; i < sources->n; i++) {
     
    490452        if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    491453
    492         if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
    493             Nskip ++;
    494             psTrace ("psphot", 3, "skip : bad source mag");
    495             continue;
     454        // replace object in image
     455        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     456            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    496457        }
    497458
    498         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    499             Nfail ++;
    500             psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
    501             continue;
    502         }
    503         source->mode |= PM_SOURCE_MODE_AP_MAGS;
     459        // clear the mask bit and set the circular mask pixels
     460        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     461        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
     462
     463        bool status = pmSourceMagnitudes (source, psf, photMode, maskVal);
     464
     465        // clear the mask bit
     466        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     467
     468        // re-subtract the object, leave local sky
     469        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     470
     471        if (!status) {
     472            Nskip ++;
     473            psTrace ("psphot", 3, "skip : bad source mag");
     474            continue;
     475        }
     476   
     477        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
     478            Nfail ++;
     479            psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
     480            continue;
     481        }
     482        source->mode |= PM_SOURCE_MODE_AP_MAGS;
    504483    }
    505484
    506485    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    507     scalar = job->args->data[4];
     486    scalar = job->args->data[5];
    508487    scalar->data.S32 = Nskip;
    509488
    510     scalar = job->args->data[5];
     489    scalar = job->args->data[6];
    511490    scalar->data.S32 = Nfail;
    512491
    513492    return true;
    514493}
    515 
    516 # if (0)
    517 bool psphotApResidMags_Unthreaded (int *nskip, int *nfail, psArray *sources, pmPSF *psf, pmSourcePhotometryMode photMode, psImageMaskType maskVal) {
    518 
    519     int Nskip = 0;
    520     int Nfail = 0;
    521 
    522     for (int i = 0; i < sources->n; i++) {
    523         pmSource *source = (pmSource *) sources->data[i];
    524 
    525         if (source->type != PM_SOURCE_TYPE_STAR) SKIPSTAR ("NOT STAR");
    526         if (source->mode &  PM_SOURCE_MODE_SATSTAR) SKIPSTAR ("SATSTAR");
    527         if (source->mode &  PM_SOURCE_MODE_BLEND) SKIPSTAR ("BLEND");
    528         if (source->mode &  PM_SOURCE_MODE_FAIL) SKIPSTAR ("FAIL STAR");
    529         if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    530 
    531         if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
    532             Nskip ++;
    533             psTrace ("psphot", 3, "skip : bad source mag");
    534             continue;
    535         }
    536 
    537         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    538             Nfail ++;
    539             psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
    540             continue;
    541         }
    542     }
    543 
    544     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    545     *nskip = Nskip;
    546     *nfail = Nfail;
    547 
    548     return true;
    549 }
    550 # endif
Note: See TracChangeset for help on using the changeset viewer.