IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 25228


Ignore:
Timestamp:
Sep 1, 2009, 4:30:19 PM (17 years ago)
Author:
Paul Price
Message:

First cut at fake insertion and recovery.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/pap/psphot/src/psphotFake.c

    r25062 r25228  
    1313// We limit ourselves to calculating the peak flux in the smoothed image, which should be close (modulo
    1414// non-Gaussian PSF) to the limiting flux in the un-smoothed original image.
    15 static float fakeLimit(const pmReadout *ro,     // Readout of interest
    16                        const psMetadata *recipe // psphot recipe
    17                        );
     15static bool fakeLimit(float *magLim,           // Limiting magntiude, to return
     16                      float *minFlux,          // Minimum flux, to return
     17                      const pmReadout *ro,     // Readout of interest
     18                      float thresh,            // Threshold for source identification
     19                      float xFWHM, float yFWHM, // Size of PSF
     20                      float smoothNsigma,       // Smoothing limit
     21                      psImageMaskType maskVal   // Value to mask
     22                      );
    1823{
    19     PM_ASSERT_READOUT_NON_NULL(ro, NAN);
    20     PM_ASSERT_READOUT_VARIANCE(ro, NAN);
    21     PS_ASSERT_METADATA_NON_NULL(recipe, NAN);
    22 
    23     float xFWHM = psMetadataLookupF32(NULL, recipe, "FWHM_X");
    24     float yFWHM = psMetadataLookupF32(NULL, recipe, "FWHM_Y");
    25     if (!isfinite(xFWHM) || !isfinite(yFWHM)) {
    26         psError(PSPHOT_ERR_CONFIG, false, "Unable to find FWHM_X and FWHM_Y");
    27         return NAN;
    28     }
     24    PM_ASSERT_READOUT_NON_NULL(ro, false);
     25    PM_ASSERT_READOUT_VARIANCE(ro, false);
     26    PS_ASSERT_METADATA_NON_NULL(recipe, false);
    2927
    3028    float smoothSigma  = 0.5*(FWHM_X + FWHM_Y) / (2.0*sqrtf(2.0*log(2.0)));
    31     float smoothNsigma = psMetadataLookupF32(NULL, recipe, "PEAKS_SMOOTH_NSIGMA");
    32     if (!isfinite(smoothSigma) || !isfinite(smoothNsigma)) {
    33         psError(PSPHOT_ERR_CONFIG, false, "Unable to set smoothing parameters");
    34         return NAN;
    35     }
    36 
    3729    psKernel *kernel = psImageSmoothKernel(smoothSigma, smoothNsigma); // Kernel used for smoothing
    3830    psKernel *newCovar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix
     
    4032    float factor = psImageCovarianceFactor(newCovar); // Variance factor
    4133    psFree(newCovar);
    42 
    43     psImageMaskType maskVal = psMetadataLookupImageMask(NULL, recipe, "MASK.PSPHOT"); // Value to mask
    4434
    4535    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for variance
     
    5040        psFree(stats);
    5141        psFree(rng);
    52         return NAN;
     42        return false;
    5343    }
    5444    psFree(rng);
     
    5646    psFree(stats);
    5747
    58     float thresh = psMetadataLookupF32(NULL, recipe, "PEAKS_NSIGMA_LIMIT_2");
    59     if (!isfinite(thresh)) {
    60         psError(PSPHOT_ERR_CONFIG, false, "Unable to find threshold");
    61         return NAN;
    62     }
    63 
    64     return -2.5 * log10(thresh * sqrtf(meanVar * factor));
     48    if (magLim) {
     49        *magLim = -2.5 * log10(thresh * sqrtf(meanVar * factor));
     50    }
     51    if (minFlux) {
     52        int fudge = psMetadataLookupF32(NULL, recipe, "FAKE.MINFLUX"); // Fudge factor for minimum flux
     53        *minFlux = sqrtf(meanVar) * fudge;
     54    }
     55
     56    return true;
    6557}
    6658
     59/// Generate a fake image and add it in to the existing readout
    6760static bool fakeGenerate(psImage **xSrc, psImage **ySrc, // Positions of sources
    6861                         const pmReadout *ro,            // Readout of interest
    69                          const psMetadata *recipe, // psphot recipe
    70                          float refMag              // Reference magnitude
     62                         const psVector *magOffsets,     // Magnitude offsets for fake sources
     63                         int numSources,                 // Number of fake sources for each bin
     64                         float refMag,                   // Reference magnitude
     65                         float minFlux                   // Minimum flux level for fake image
    7166                         )
    7267{
    73     PM_ASSERT_READOUT_NON_NULL(ro, NULL);
    74     PM_ASSERT_READOUT_IMAGE(ro, NULL);
    75     PS_ASSERT_METADATA_NON_NULL(recipe, NULL);
    76 
    77     psMetadata *fake = psMetadataLookupMetadata(NULL, recipe, "FAKE"); // Fake information
    78     if (!fake) {
    79         psError(PSPHOT_ERR_CONFIG, false, "Unable to find FAKE information in recipe");
    80         return NULL;
    81     }
    82 
    83     psVector *magOffsets = psMetadataLookupVector(NULL, recipe, "FAKE.MAG"); // Magnitude offsets
    84     if (!magOffset || magOffset->type.type != PS_TYPE_F32) {
    85         psError(PSPHOT_ERR_CONFIG, false, "Unable to find FAKE.MAG F32 vector in recipe");
    86         return NULL;
    87     }
     68    PM_ASSERT_READOUT_NON_NULL(ro, false);
     69    PM_ASSERT_READOUT_IMAGE(ro, false);
     70    PS_ASSERT_METADATA_NON_NULL(recipe, false);
     71    PS_ASSERT_VECTOR_NON_NULL(magOffsets, false);
     72    PS_ASSERT_VECTOR_TYPE(magOffsets, PS_TYPE_F32, false);
     73
    8874    int numBins = magOffset->n;                                     // Number of bins
    89     int numSources = psMetadataLookupS32(NULL, recipe, "FAKE.NUM"); // Number of sources for each bin
    90 
    9175    int numCols = ro->image->numCols, numRows = ro->image->numRows; // Size of image
    92 
    93 
    9476
    9577    *xSrc = psImageRecycle(*xSrc, numSources, numBins, PS_TYPE_F32);
     
    123105
    124106    pmReadout *fakeRO = pmReadoutAlloc(); // Fake readout
    125     pmReadoutFakeFromVectors(fakeRO, xAll, yAll, mag,
    126 
     107    if (!pmReadoutFakeFromVectors(fakeRO, xAll, yAll, mag, NULL, NULL, psf, minFlux, NAN, false, false)) {
     108        psError(PS_ERR_UNKNOWN, false, "Unable to generate fake image");
     109        psFree(fakeRO);
     110        psFree(xAll);
     111        psFree(yAll);
     112        psFree(magAll);
     113        return false;
     114    }
     115    psFree(xAll);
     116    psFree(yAll);
     117    psFree(magAll);
     118
     119    psBinaryOp(ro->image, ro->image, "+", fakeRO->image);
     120    psFree(fakeRO);
     121
     122    return true;
     123}
    127124
    128125
     
    138135    PS_ASSERT_ARRAY_NON_NULL(realSources, false);
    139136
    140     psTimerStart("psphotFake");
    141 
    142     // Generate array of fake sources and define the pixels with pmSourceDefinePixels
    143     psArray *fakeOrig = fakeGenerate(config, readout, recipe);
    144 
    145     psArray *fakeMeasured = psArrayAlloc(fakeOrig->n); // Measured values for the sources in fakeOrig
    146     for (int i = 0; i < fakeOrig->n; i++) {
    147         fakeMeasured->data[i] = pmSourceCopy(fakeOrig->data[i]);
    148     }
    149 
    150     int numCols = readout->image->numCols, numRows = readout->image->numRows; // Size of image
    151 
    152     pmReadout *fakeRO = pmReadoutAlloc(NULL); // Readout with fake sources
    153 
    154     if (!pmReadoutFakeFromSources(fakeRO, numCols, numRows, fakeOrig, NULL, NULL,
    155                                   psf, MIN_FLUX, 0, false, false)) {
    156         psError(psErrorCodeLast(), false, "Unable to generate fake readout");
    157         psFree(fakeRO);
    158         psFree(fakeMeasured);
    159         psFree(fakeOrig);
    160         return false;
    161     }
    162 
    163 
    164 bool pmReadoutFakeFromSources(pmReadout *readout, ///< Output readout, or NULL
    165                               int numCols, int numRows, ///< Dimension of image
    166                               const psArray *sources, ///< Array of pmSource
    167                               const psVector *xOffset, ///< x offsets for sources (source -> img), or NULL
    168                               const psVector *yOffset, ///< y offsets for sources (source -> img), or NULL
    169                               const pmPSF *psf, ///< PSF for sources
    170                               float minFlux, ///< Minimum flux to bother about; for setting source radius
    171                               int radius, ///< Fixed radius for sources
    172                               bool circularise, ///< Circularise PSF model?
    173                               bool normalise ///< Normalise the peak value?
    174     );
    175 
    176 
    177 
    178 
    179     // remove all sources
     137    psTimerStart("psphot.fake");
     138
     139    // Collect recipe information
     140    float xFWHM = psMetadataLookupF32(NULL, recipe, "FWHM_X"); // PSF size in x
     141    float yFWHM = psMetadataLookupF32(NULL, recipe, "FWHM_Y"); // PSF size in y
     142    if (!isfinite(xFWHM) || !isfinite(yFWHM)) {
     143        psError(PSPHOT_ERR_CONFIG, false, "Unable to find FWHM_X and FWHM_Y in recipe");
     144        return false;
     145    }
     146    float smoothNsigma = psMetadataLookupF32(NULL, recipe, "PEAKS_SMOOTH_NSIGMA"); // Smoothing limit
     147    if (!isfinite(smoothNsigma)) {
     148        psError(PSPHOT_ERR_CONFIG, false, "Unable to find PEAKS_SMOOTH_NSIGMA in recipe");
     149        return false;
     150    }
     151    float thresh = psMetadataLookupF32(NULL, recipe, "PEAKS_NSIGMA_LIMIT_2");
     152    if (!isfinite(thresh)) {
     153        psError(PSPHOT_ERR_CONFIG, false, "Unable to find PEAKS_NSIGMA_LIMIT_2 in recipe");
     154        return false;
     155    }
     156    psVector *magOffsets = psMetadataLookupVector(NULL, recipe, "FAKE.MAG"); // Magnitude offsets
     157    if (!magOffset || magOffset->type.type != PS_TYPE_F32) {
     158        psError(PSPHOT_ERR_CONFIG, false, "Unable to find FAKE.MAG F32 vector in recipe");
     159        return NULL;
     160    }
     161    int numSources = psMetadataLookupS32(NULL, recipe, "FAKE.NUM"); // Number of sources for each bin
     162    if (numSources == 0) {
     163        psError(PSPHOT_ERR_CONFIG, false, "Unable to find FAKE.NUM in recipe");
     164        return NULL;
     165    }
     166    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Value to mask
     167
     168
     169    // remove all sources, adding noise for subtracted sources
    180170    psphotRemoveAllSources(realSources, recipe);
    181 
    182     // add noise for real (subtracted) objects
    183     psphotAddNoise (readout, realSources, recipe);
    184 
    185     // XXX fake sources should measure peak->x,y, force sources should not
    186     psImageMaskType maskVal = 0xff;
    187     psImage *significance = psphotSignificanceImage(readout, recipe, 1, maskVal);
    188     ppSimDetections (significance, recipe, fakeSources);
    189     psFree (significance);
    190 
    191     // remove noise for subtracted objects (ie, return to normal noise level)
    192     psphotSubNoise (readout, realSources, recipe);
    193 
    194     // replace all sources
    195     psphotReplaceAllSources (realSources, recipe);
    196 
    197     // construct an initial model for each object
    198     psphotGuessModels (config, readout, realSources, psf);
    199     psphotGuessModels (config, readout, fakeSources, psf);
    200 
    201     // linear fit to real + fake sources
    202     psArray *sources = ppSimMergeSources (realSources, fakeSources);
    203     psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE); // XXX option to NOT subtract
    204     psphotReplaceAllSources (sources, recipe);
    205     psFree (sources); // only frees the merged references
    206 
    207     // calculate source magnitudes (for which set??)
    208     psphotMagnitudes(config, readout, view, fakeSources, psf);
    209 
    210     // drop the references to the image pixels held by each source
    211     psphotSourceFreePixels (realSources);
    212     psphotSourceFreePixels (fakeSources);
    213 
    214     // create the exported-metadata and free local data
    215     // XXX this places the sources on readout->analysis as PSPHOT.SOURCES.  modify?
    216     // (or don't supply the sources, and do this with a different function)
    217     psphotReadoutCleanup(config, readout, recipe, NULL, psf, NULL);
    218 
    219     pmCell    *fakeCell    = pmFPAfileThisCell (config->files, view, "PPSIM.FAKE.SOURCES"); psAssert (fakeCell, "no cell?");
    220     pmChip    *fakeChip    = pmFPAfileThisChip (config->files, view, "PPSIM.FAKE.SOURCES"); psAssert (fakeChip, "no chip?");
    221     pmReadout *fakeReadout = pmFPAfileThisReadout (config->files, view, "PPSIM.FAKE.SOURCES");
    222     if (!fakeReadout) {
    223         fakeReadout = pmReadoutAlloc (fakeCell);
    224         psFree (fakeReadout); // there is a copy on 'cell' as well
    225     }
    226     psAssert (fakeReadout, "no fakeReadout?");
    227     pmChipSetDataStatus (fakeChip, true);
    228     psMetadataAddArray (fakeReadout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_META_REPLACE, "fake photometry ", fakeSources);
     171    psphotAddNoise(readout, realSources, recipe);
     172
     173    float magLim;                       // Guess at limiting magnitude
     174    float minFlux;                      // Minimum flux for fake image
     175    if (!fakeLimit(&magLim, &minFlux, readout, thresh, xFWHM, yFWHM, smoothNsigma, maskVal)) {
     176        psError(PS_ERR_UNKNOWN, false, "Unable to determine limits for image");
     177        return false;
     178    }
     179
     180    psImage *xFake = NULL, *yFake = NULL; // Coordinates of sources, each bin in a row
     181    if (!fakeGenerate(&xFake, &yFake, readout, magOffsets, numSources, magLim, minFlux)) {
     182        psError(PS_ERR_UNKNOWN, false, "Unable to generate fake sources");
     183        psFree(xFake);
     184        psFree(yFake);
     185        return false;
     186    }
     187
     188    psImage *significance = psphotSignificanceImage(readout, recipe, 2, maskVal);
     189    if (!significance) {
     190        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate significance image");
     191        psFree(xFake);
     192        psFree(yFake);
     193        return false;
     194    }
     195
     196    int numBins = magOffsets->n;                          // Number of bins
     197    psVector *frac = psVectorAlloc(numBins, PS_TYPE_S32); // Fraction of sources in each bin
     198    for (int i = 0; i < numBins; i++) {
     199        int numFound = 0;               // Number found
     200        for (int j = 0; j < numSources; j++) {
     201            float x = xFake->data.F32[i][j], y = yFake->data.F32[i][j]; // Coordinates of interest
     202            int xPix = x, yPix = y;                                     // Pixel coordinates
     203            if (significance->data.F32[yPix][xPix] > thresh) {
     204                numFound++;
     205            }
     206        }
     207        frac->data.S32[i] = (float)numFound / (float)numSources;
     208    }
     209
     210    psFree(xFake);
     211    psFree(yFake);
     212    psFree(significance);
     213
     214    // Putting results on recipe because that appears to be the psphot standard, but it's not a good idea
     215    psMetadataAddVector(recipe, PS_LIST_TAIL, "FAKE.EFF", PS_META_REPLACE,
     216                        "Efficiency fractions", frac);
     217    psMetadataAddVector(recipe, PS_LIST_TAIL, "FAKE.MAG", PS_META_REPLACE,
     218                        "Efficiency magnitudes", magOffsets);
     219    psMetadataAddF32(recipe, PS_LIST_TAIL, "FAKE.REF", PS_META_REPLACE,
     220                     "Efficiency reference magnitude", magLim);
     221
     222    psFree(frac);
    229223
    230224    return true;
Note: See TracChangeset for help on using the changeset viewer.