IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

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

updates from trunk

Location:
branches/simmosaic_branches
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/simmosaic_branches

  • branches/simmosaic_branches/psphot

  • branches/simmosaic_branches/psphot/src

    • Property svn:ignore
      •  

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

    r23989 r27839  
    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];
     
    168199        if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    169200
     201        if (source->mode &  PM_SOURCE_MODE_EXT_LIMIT) SKIPSTAR ("EXTENDED");
     202        if (source->mode &  PM_SOURCE_MODE_CR_LIMIT) SKIPSTAR ("COSMIC RAY");
     203        if (source->mode &  PM_SOURCE_MODE_DEFECT) SKIPSTAR ("DEFECT");
     204           
    170205        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    171206            continue;
    172207        }
     208
     209        // XXX make this user-configurable?
     210        if (source->errMag > 0.01) continue;
    173211
    174212        // aperture residual for this source
     
    182220        }
    183221
    184         mag->data.F32[Npsf]     = source->psfMag;
    185         apResid->data.F32[Npsf] = dap;
    186         xPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_XPOS];
    187         yPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_YPOS];
    188 
    189         mask->data.PS_TYPE_VECTOR_MASK_DATA[Npsf] = 0;
    190 
    191         dMag->data.F32[Npsf] = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
    192 
    193         psVectorExtend (mag,     100, 1);
    194         psVectorExtend (mask,    100, 1);
    195         psVectorExtend (xPos,    100, 1);
    196         psVectorExtend (yPos,    100, 1);
    197         psVectorExtend (dMag,    100, 1);
    198         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]);
    199242        Npsf ++;
    200243    }
     
    202245    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "measure aperture residuals for %d objects (%d skipped, %d failed, %ld invalid)\n",
    203246              Npsf, Nskip, Nfail, sources->n - Npsf - Nskip - Nfail);
     247
     248# ifdef DEBUG
     249    fclose (f);
     250# endif
    204251
    205252    // XXX choose a better value here?
     
    209256    }
    210257
    211     // XXX deprecating the old code which allowed the ApResid to be fitted as a function of flux and r^2/flux
    212     // XXX is this asymmetric clipping still needed?  this analysis should come after neighbors are subtracted...
    213     // 3hi/1lo sigma clipping on the rflux vs metric fit
    214     // systematic error information
    215     float errorScale = 0.0;
    216     float errorFloor = 0.0;
    217 
     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;
    218278    float errorFloorMin = FLT_MAX;
    219     int entryMin = -1;
    220 
    221     // Fit out the dap vs mag trend, iterate over spatial scale until error Floor increases.
    222     // 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;
    223284    for (int i = 1; i <= APTREND_ORDER_MAX; i++) {
    224 
    225         if (!psphotApResidTrend (readout, psf, Npsf, i, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag)) {
    226             break;
    227         }
    228 
    229         // 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
    230308        if (errorFloor < errorFloorMin) {
    231309            errorFloorMin = errorFloor;
    232             entryMin = i;
     310            psFree (psf->ApTrend);
     311            psf->ApTrend = psMemIncrRefCounter(apTrend);
    233312        }
    234     }
    235     if (entryMin == -1) {
     313        psFree (apTrend);
     314    }
     315    if (psf->ApTrend == NULL) {
    236316        psWarning("Failed to find a valid aperture residual value");
    237317        goto escape;
    238318    }
    239319
    240     // XXX catch error condition
    241     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    }
    242393
    243394    // construct the fitted values and the residuals
    244     psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
     395    psVector *apResidFit = pmTrend2DEvalVector (apTrend, mask, 0xff, xPos, yPos);
    245396    psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
    246     psVector *dMagSys = (psVector *) psBinaryOp (NULL, (void *) dMag, "*", (void *) psScalarAlloc(errorScale, PS_TYPE_F32));
    247 
    248     if (psTraceGetLevel("psphot") >= 2) {
    249         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");
    250413        for (int i = 0; i < xPos->n; i++) {
    251             fprintf (dumpFile, "%f %f  %f %f %f %f %f  %x\n",
     414            fprintf (dumpFile, "%f %f  %f %f %f %f  %x\n",
    252415                     xPos->data.F32[i], yPos->data.F32[i],
    253                      mag->data.F32[i], dMag->data.F32[i], dMagSys->data.F32[i],
     416                     dMag->data.F32[i], hypot(dMag->data.F32[i], *apResidSysErr),
    254417                     apResid->data.F32[i], apResidRes->data.F32[i],
    255418                     mask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
     
    258421    }
    259422
    260     // apply ApTrend results
    261     float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
    262     float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
    263 
    264     psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
    265     psf->dApResid = errorFloor;
    266     psf->nApResid = Npsf;
    267 
    268     // save results for later output
    269     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   0.0);
    270     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   0.0);
    271     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
    272     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
    273     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
    274     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
    275 
    276     psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
    277     psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
    278 
    279     psFree (mag);
    280423    psFree (mask);
    281     psFree (xPos);
    282     psFree (yPos);
    283 
    284     psFree (apResid);
    285     psFree (apResidFit);
    286     psFree (apResidRes);
    287 
    288     psFree (dMagSys);
    289     psFree (dMag);
    290 
    291     psphotVisualPlotApResid (sources);
    292 
    293     return true;
    294 
    295 escape:
    296     // save nan values since these were not calculated
    297     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
    298     psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
    299     psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
    300     psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
    301     psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
    302     psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
    303 
    304     psFree (mag);
    305     psFree (mask);
    306     psFree (xPos);
    307     psFree (yPos);
    308     psFree (apResid);
    309     psFree (dMag);
    310     return false;
    311 }
    312 
    313 /*
    314   (aprMag' - fitMag) = rflux*skyBias + ApTrend(x,y)
    315   (aprMag - rflux*skyBias) - fitMag = ApTrend(x,y)
    316   (aprMag - rflux*skyBias) = fitMag + ApTrend(x,y)
    317 */
    318 
    319 bool psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, psVector *mask, int nGroup) {
    320 
    321     psStats *statsS = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    322     psStats *statsM = psStatsAlloc (PS_STAT_SAMPLE_MEAN);
    323 
    324     // measure the trend in bins with 10 values each; if < 10 total, use them all
    325     int nBin = PS_MAX (dMag->n / nGroup, 1);
    326 
    327     // output vectors for ApResid trend
    328     psVector *dSo = psVectorAlloc (nBin, PS_TYPE_F32);
    329     psVector *dMo = psVectorAlloc (nBin, PS_TYPE_F32);
    330     psVector *dRo = psVectorAlloc (nBin, PS_TYPE_F32);
    331 
    332     // use dMag to group the dMag and dap vectors
    333     psVector *index = psVectorSortIndex (NULL, dMag);
    334 
    335     // subset vectors for dMag and dap values within the given range
    336     psVector *dMSubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
    337     psVector *dASubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
    338     psVector *mkSubset = psVectorAllocEmpty (nGroup, PS_TYPE_VECTOR_MASK);
    339 
    340     int n = 0;
    341     for (int i = 0; i < dMo->n; i++) {
    342         int j;
    343         for (j = 0; (j < nGroup) && (n < dMag->n); j++, n++) {
    344             int N = index->data.U32[n];
    345             dMSubset->data.F32[j] = dMag->data.F32[N];
    346             dASubset->data.F32[j] = dap->data.F32[N];
    347             mkSubset->data.PS_TYPE_VECTOR_MASK_DATA[j] = mask->data.PS_TYPE_VECTOR_MASK_DATA[N];
    348         }
    349         dMSubset->n = j;
    350         dASubset->n = j;
    351         mkSubset->n = j;
    352 
    353         psStatsInit (statsS);
    354         psStatsInit (statsM);
    355 
    356         if (j > 2) {
    357             if (!psVectorStats (statsS, dASubset, NULL, mkSubset, 0xff)) {
    358                 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    359                 return false;
    360             }
    361             if (!psVectorStats (statsM, dMSubset, NULL, mkSubset, 0xff)) {
    362                 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    363                 return false;
    364             }
    365             dSo->data.F32[i] = statsS->robustStdev;
    366             dMo->data.F32[i] = statsM->sampleMean;
    367             dRo->data.F32[i] = statsS->robustStdev / statsM->sampleMean;
    368         } else {
    369             dSo->data.F32[i] = NAN;
    370             dMo->data.F32[i] = NAN;
    371             dRo->data.F32[i] = NAN;
    372         }
    373     }
    374     psFree (dMSubset);
    375     psFree (dASubset);
    376     psFree (mkSubset);
    377 
    378     psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
    379     if (!psVectorStats (stats, dRo, NULL, NULL, 0)) {
    380         psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    381         return false;
    382     }
    383 
    384     *errorScale = stats->sampleMedian;
    385     for (int i = 0; i < dSo->n; i++) {
    386         *errorFloor = dSo->data.F32[i];
    387         if (isfinite(*errorFloor)) break;
    388     }
    389 
    390     psFree (stats);
    391     psFree (index);
    392 
    393     psFree (dRo);
    394     psFree (dMo);
    395     psFree (dSo);
    396 
    397     psFree (statsS);
    398     psFree (statsM);
    399 
    400     return true;
    401 }
    402 
    403 bool psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
    404 
    405     int Nx, Ny;
    406 
    407     if (readout->image->numCols > readout->image->numRows) {
    408         Nx = scale;
    409         float AR = readout->image->numRows / (float) readout->image->numCols;
    410         Ny = (int) (Nx * AR + 0.5);
    411         Ny = PS_MAX (1, Ny);
    412     } else {
    413         Ny = scale;
    414         float AR = readout->image->numRows / (float) readout->image->numCols;
    415         Nx = (int) (Ny * AR + 0.5);
    416         Nx = PS_MAX (1, Nx);
    417     }
    418 
    419     // require at least 10 stars per spatial bin
    420     if (Npsf < 10*Nx*Ny) {
    421         return false;
    422     }
    423 
    424     // the mask marks the values not used to calculate the ApTrend
    425     psVectorInit (mask, 0);
    426 
    427     // XXX stats structure for use by ApTrend : make parameters user setable
    428     psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    429     stats->min = 2.0;
    430     stats->max = 3.0;
    431 
    432     // measure Trend2D for the current spatial scale
    433     psFree (psf->ApTrend);
    434     psf->ApTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
    435 
    436     // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
    437     psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
    438     for (int i = 0; i < dMag->n; i++) {
    439         dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.01);
    440     }
    441 
    442     // XXX test for errors here
    443     pmTrend2DFit (psf->ApTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft);
    444 
    445     // construct the fitted values and the residuals
    446     psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
    447     psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
    448 
    449     // measure systematic errorFloor & systematic / photon scale factor
    450     // XXX this is a bit arbitrary, but it forces ~3 stars from the bright bin per spatial bin
    451     int nGroup = PS_MAX (3*Nx*Ny, 10);
    452     psphotMagErrorScale (errorScale, errorFloor, dMag, apResidRes, mask, nGroup);
    453 
    454     psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid (%d stars per bin)\n", Nx, Ny, nGroup);
    455     psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic error / photon error: %f\n", *errorScale);
    456     psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *errorFloor);
    457 
    458424    psFree (stats);
    459425    psFree (dMagSoft);
     
    461427    psFree (apResidRes);
    462428
    463     return true;
     429    return apTrend;
    464430}
    465431
     
    475441    pmSourcePhotometryMode photMode = PS_SCALAR_VALUE(job->args->data[2],S32);
    476442    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);
    477444
    478445    for (int i = 0; i < sources->n; i++) {
     
    485452        if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    486453
    487         if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
    488             Nskip ++;
    489             psTrace ("psphot", 3, "skip : bad source mag");
    490             continue;
     454        // replace object in image
     455        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
     456            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
    491457        }
    492458
    493         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    494             Nfail ++;
    495             psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
    496             continue;
    497         }
    498         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;
    499483    }
    500484
    501485    // change the value of a scalar on the array (wrap this and put it in psArray.h)
    502     scalar = job->args->data[4];
     486    scalar = job->args->data[5];
    503487    scalar->data.S32 = Nskip;
    504488
    505     scalar = job->args->data[5];
     489    scalar = job->args->data[6];
    506490    scalar->data.S32 = Nfail;
    507491
    508492    return true;
    509493}
    510 
    511 # if (0)
    512 bool psphotApResidMags_Unthreaded (int *nskip, int *nfail, psArray *sources, pmPSF *psf, pmSourcePhotometryMode photMode, psImageMaskType maskVal) {
    513 
    514     int Nskip = 0;
    515     int Nfail = 0;
    516 
    517     for (int i = 0; i < sources->n; i++) {
    518         pmSource *source = (pmSource *) sources->data[i];
    519 
    520         if (source->type != PM_SOURCE_TYPE_STAR) SKIPSTAR ("NOT STAR");
    521         if (source->mode &  PM_SOURCE_MODE_SATSTAR) SKIPSTAR ("SATSTAR");
    522         if (source->mode &  PM_SOURCE_MODE_BLEND) SKIPSTAR ("BLEND");
    523         if (source->mode &  PM_SOURCE_MODE_FAIL) SKIPSTAR ("FAIL STAR");
    524         if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
    525 
    526         if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
    527             Nskip ++;
    528             psTrace ("psphot", 3, "skip : bad source mag");
    529             continue;
    530         }
    531 
    532         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
    533             Nfail ++;
    534             psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
    535             continue;
    536         }
    537     }
    538 
    539     // change the value of a scalar on the array (wrap this and put it in psArray.h)
    540     *nskip = Nskip;
    541     *nfail = Nfail;
    542 
    543     return true;
    544 }
    545 # endif
Note: See TracChangeset for help on using the changeset viewer.