IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 25906


Ignore:
Timestamp:
Oct 21, 2009, 12:42:17 PM (17 years ago)
Author:
eugene
Message:

add alternative zero point analysis methods: per-exposure vs per-chip statistics and clipped mean vs blue edge statistic

Location:
trunk/psastro/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/psastro/src/psastro.h

    r24653 r25906  
    146146
    147147bool              psastroZeroPoint (pmConfig *config);
    148 bool              psastroZeroPointReadout(pmReadout *readout, float zeropt, float exptime);
     148psVector         *psastroZeroPointReadoutAccum(psVector *dMag, pmReadout *readout, float exptime);
     149bool              psastroZeroPointAnalysis (psMetadata *header, psVector *dMag, float zeropt, float edgeFraction, bool useMean);
    149150bool              psastroZeroPointFromRecipe (float *zeropt, float *exptime, float *ghostMaxMag, pmFPA *fpa, psMetadata *recipe);
     151
     152psStats          *psastroStatsPercentile (psVector *myVector, float flimit);
    150153
    151154// masking functions
  • trunk/psastro/src/psastroZeroPoint.c

    r24649 r25906  
    1515bool psastroZeroPoint (pmConfig *config) {
    1616
     17    bool status;
    1718    float zeropt, exptime;
    1819    pmChip *chip = NULL;
     
    2728    }
    2829
     30    // recipe options
     31    bool byExposure = psMetadataLookupBool (&status, recipe, "ZERO.POINT.BY.EXPOSURE");
     32    bool useMean    = psMetadataLookupBool (&status, recipe, "ZERO.POINT.USE.MEAN");
     33    float edgeFraction = psMetadataLookupF32 (&status, recipe, "ZERO.POINT.EDGE.FRACTION");
     34
    2935    // select the input data sources
    3036    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSASTRO.INPUT");
     
    5561    }
    5662
     63    // if we measure the zero point by exposure, accumulate the dMag values here:
     64    psVector *dMag = NULL;
     65
    5766    // this loop selects the matched stars for all chips
     67    // XXX optionally measure zero point for entire exposure in a single statistic
    5868    while ((chip = pmFPAviewNextChip (view, fpa, 1)) != NULL) {
    5969        psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
     
    7181
    7282                // calculate dMag for the matched stars
    73                 psastroZeroPointReadout (readout, zeropt, exptime);
    74 
     83                dMag = psastroZeroPointReadoutAccum (dMag, readout, exptime);
     84
     85                if (!byExposure) {
     86                    // calculate dMag for the matched stars just for this readout (well, chip)
     87                    psMetadata *header = psMetadataLookupMetadata (&status, readout->analysis, "PSASTRO.HEADER");
     88                    psastroZeroPointAnalysis (header, dMag, zeropt, edgeFraction, useMean);
     89                    psFree (dMag);
     90                    dMag = NULL;
     91                }
    7592            }
    7693        }
     94    }
     95
     96    if (byExposure) {
     97        psMetadata *header = psMetadataLookupMetadata (&status, fpa->analysis, "PSASTRO.HEADER");
     98        psastroZeroPointAnalysis (header, dMag, zeropt, edgeFraction, useMean);
     99        psFree (dMag);
     100        dMag = NULL;
    77101    }
    78102
     
    82106
    83107/**
    84  * we measure <dMag> and \sigma_dMag and write them to the header
     108 * accumulate the dMag values from this readout
    85109 */
    86 bool psastroZeroPointReadout(pmReadout *readout, float zeropt, float exptime) {
     110psVector *psastroZeroPointReadoutAccum(psVector *dMag, pmReadout *readout, float exptime) {
    87111
    88112    bool status;
     
    90114    // select the raw objects for this readout
    91115    psArray *rawstars = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.RAWSTARS");
    92     if (rawstars == NULL) return false;
     116    if (rawstars == NULL) return dMag;
    93117
    94118    // select the raw objects for this readout
    95119    psArray *refstars = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.REFSTARS");
    96     if (refstars == NULL) return false;
     120    if (refstars == NULL) return dMag;
    97121
    98122    psArray *matches = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.MATCH");
    99     if (matches == NULL) return false;
    100 
    101     psVector *dMag  = psVectorAllocEmpty (100, PS_TYPE_F32);
    102 
    103     int Npts = 0;
     123    if (matches == NULL) return dMag;
     124
     125    if (!dMag) {
     126        dMag  = psVectorAllocEmpty (100, PS_TYPE_F32);
     127    }
     128
    104129    for (int i = 0; i < matches->n; i++) {
    105130
     
    110135      pmAstromObj *ref = refstars->data[match->ref];
    111136
    112       dMag->data.F32[Npts] = ref->Mag - raw->Mag - 2.5*log10(exptime);
    113       psVectorExtend (dMag, 100, 1);
    114       Npts++;
    115     }
    116 
    117     psTrace ("psModules.astrom", 4, "Npts: %d\n", Npts);
    118 
    119     if (Npts < 3) {
     137      float value = ref->Mag - raw->Mag - 2.5*log10(exptime);
     138      psVectorAppend (dMag, value);
     139    }
     140    return dMag;
     141}
     142
     143bool psastroZeroPointAnalysis (psMetadata *header, psVector *dMag, float zeropt, float edgeFraction, bool useMean) {
     144
     145    // XXX make this depend on the mode?
     146    if (dMag->n < 3) {
    120147      fprintf (stderr, "zero point NaN +/- NaN\n");
    121       psFree (dMag);
    122148      return false;
    123149    }
    124150
    125     // stats structure and mask for use in measuring the clipping statistic
    126     // this analysis has too few data points to use the robust median method
    127     psStats *stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV);
    128     if (!psVectorStats (stats, dMag, NULL, NULL, 0)) {
    129         psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
    130         return false;
    131     }
    132     fprintf (stderr, "zero point %f +/- %f using %d stars; transparency %f\n", stats->clippedMean, stats->clippedStdev, Npts, zeropt - stats->clippedMean);
    133 
    134     psMetadata *header = psMetadataLookupMetadata (&status, readout->analysis, "PSASTRO.HEADER");
     151    // the zero point analysis depends on the type of desired statistic.  For comparisons
     152    // against a high-quality reference catalog with a good match to the actual filter used, it
     153    // is best to use a standard clipped mean or global mean statistic.  If the reference
     154    // catalog has some unmodeled extra parameter, as is the case for the synthetic grizy
     155    // database vs PS1, then it is best to use some consistent feature in the color
     156    // distribution.
     157
     158    psStats *stats = NULL;
     159    if (useMean) {
     160        // stats structure and mask for use in measuring the clipping statistic
     161        // this analysis has too few data points to use the robust median method
     162        stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV);
     163        if (!psVectorStats (stats, dMag, NULL, NULL, 0)) {
     164            psError(PS_ERR_UNKNOWN, false, "failure to measure zero point by mean");
     165            return false;
     166        }
     167    } else {
     168        stats = psastroStatsPercentile (dMag, edgeFraction);
     169        if (!stats) {
     170            psError(PS_ERR_UNKNOWN, false, "failure to measure zero point by edge");
     171            return false;
     172        }
     173    }
     174    fprintf (stderr, "zero point %f +/- %f using %ld stars; transparency %f\n", stats->clippedMean, stats->clippedStdev, dMag->n, zeropt - stats->clippedMean);
    135175
    136176    psMetadataAddF32 (header, PS_LIST_TAIL, "ZPT_OBS", PS_META_REPLACE, "measured zero point", stats->clippedMean);
     
    139179    psMetadataAddF32 (header, PS_LIST_TAIL, "ZPT_OFF", PS_META_REPLACE, "measured zero point", zeropt - stats->clippedMean);
    140180
    141     psFree (dMag);
    142181    psFree (stats);
    143182    return true;
    144183}
     184
     185#define MAG_RESOLUTION 0.001
     186
     187// set the bin closest to the corresponding value.  if USE_END is +/- 1,
     188// out-of-range saturates on lower/upper bin REGARDLESS of actual value
     189#define PS_BIN_FOR_VALUE(RESULT, VECTOR, VALUE, USE_END) { \
     190        psVectorBinaryDisectResult result; \
     191        psScalar tmpScalar; \
     192        tmpScalar.type.type = PS_TYPE_F32; \
     193        tmpScalar.data.F32 = (VALUE); \
     194        RESULT = psVectorBinaryDisect (&result, VECTOR, &tmpScalar); \
     195        switch (result) { \
     196          case PS_BINARY_DISECT_PASS: \
     197            break; \
     198          case PS_BINARY_DISECT_OUTSIDE_RANGE: \
     199            psTrace("psastro", 6, "selected bin outside range"); \
     200            if (USE_END == -1) { RESULT = 0; } \
     201            if (USE_END == +1) { RESULT = VECTOR->n - 1; } \
     202            break; \
     203          case PS_BINARY_DISECT_INVALID_INPUT: \
     204          case PS_BINARY_DISECT_INVALID_TYPE: \
     205            psAbort ("programming error"); \
     206            break; \
     207        } }
     208
     209# define PS_BIN_INTERPOLATE(RESULT, VECTOR, BOUNDS, BIN, VALUE) { \
     210        float dX, dY, Xo, Yo, Xt; \
     211        if (BIN == BOUNDS->n - 1) { \
     212            dX = 0.5*(BOUNDS->data.F32[BIN+1] - BOUNDS->data.F32[BIN-1]); \
     213            dY = VECTOR->data.F32[BIN] - VECTOR->data.F32[BIN-1]; \
     214            Xo = 0.5*(BOUNDS->data.F32[BIN+1] + BOUNDS->data.F32[BIN]); \
     215            Yo = VECTOR->data.F32[BIN]; \
     216        } else { \
     217            dX = 0.5*(BOUNDS->data.F32[BIN+2] - BOUNDS->data.F32[BIN]); \
     218            dY = VECTOR->data.F32[BIN+1] - VECTOR->data.F32[BIN]; \
     219            Xo = 0.5*(BOUNDS->data.F32[BIN+1] + BOUNDS->data.F32[BIN]); \
     220            Yo = VECTOR->data.F32[BIN]; \
     221        } \
     222        if (dY != 0) { \
     223            Xt = (VALUE - Yo)*dX/dY + Xo; \
     224        } else { \
     225            Xt = Xo; \
     226        } \
     227        Xt = PS_MIN (BOUNDS->data.F32[BIN+1], PS_MAX(BOUNDS->data.F32[BIN], Xt)); \
     228        psTrace("psastro", 6, "(Xo, Yo, dX, dY, Xt, Yt) is (%.2f %.2f %.2f %.2f %.2f %.2f)\n", \
     229                Xo, Yo, dX, dY, Xt, VALUE); \
     230        RESULT = Xt; }
     231
     232// measure the edge of the sample at flimit
     233// return results in stats->sampleMean, sampleStdev
     234// XXX this is a misuse of psStats -- make our own structure?
     235psStats *psastroStatsPercentile (psVector *myVector, float flimit) {
     236
     237    // search for the 'blue' edge of the dMag distribution:
     238    // the distribution is not a normal population, but instead has a broad range with fairly hard edges.
     239    // construct a histogram and look for the
     240
     241    // stats is first used to find the data range
     242    psStats *stats = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX); // Statistics for min and max
     243    psHistogram *histogram = NULL;      // Histogram of the data
     244    psHistogram *cumulative = NULL;     // Cumulative histogram of the data
     245    float min = NAN, max = NAN;         // Mimimum and maximum values
     246
     247    // Get the minimum and maximum values
     248    if (!psVectorStats(stats, myVector, NULL, NULL, 0)) goto escape;
     249    min = stats->min;
     250    max = stats->max;
     251    if (isnan(min) || isnan(max)) goto escape;
     252    psTrace("psastro", 6, "Data min/max is (%.2f, %.2f)\n", min, max);
     253
     254    // If all data points have the same value, then we set the appropriate members of stats and return.
     255    if (fabs(max - min) <= FLT_EPSILON) {
     256        stats->clippedMean = min;
     257        stats->clippedStdev = NAN;
     258        stats->results |= PS_STAT_CLIPPED_MEAN;
     259        stats->results |= PS_STAT_CLIPPED_STDEV;
     260        return stats;
     261    }
     262   
     263    // Define the histogram bin size. 
     264    float binSize = MAG_RESOLUTION;
     265    long numBins = (max - min) / binSize; // Number of bins
     266    psTrace("psastro", 6, "Numbins is %ld\n", numBins);
     267    psTrace("psastro", 6, "Creating a robust histogram from data range (%.2f - %.2f)\n", min, max);
     268
     269    // Generate the histogram
     270    histogram = psHistogramAlloc(min, max, numBins);
     271    if (!psVectorHistogram(histogram, myVector, NULL, NULL, 0)) {
     272      // if psVectorHistogram returns false, we have a programming error
     273      psError(PS_ERR_UNKNOWN, false, "Unable to generate histogram for psastroZeroPointAnalysis\n");
     274      psFree(histogram);
     275      psFree(stats);
     276      return NULL;
     277    }
     278    if (psTraceGetLevel("psastro") >= 8) {
     279      PS_VECTOR_PRINT_F32(histogram->bounds);
     280      PS_VECTOR_PRINT_F32(histogram->nums);
     281    }
     282
     283    // Convert the specific histogram to a cumulative histogram
     284    // The cumulative histogram data points correspond to the UPPER bound value (N < Bin[i+1])
     285    cumulative = psHistogramAlloc(min, max, numBins);
     286    cumulative->nums->data.F32[0] = histogram->nums->data.F32[0];
     287    for (long i = 1; i < histogram->nums->n; i++) {
     288      cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i];
     289      cumulative->bounds->data.F32[i-1] = histogram->bounds->data.F32[i];
     290    }
     291    if (psTraceGetLevel("psastro") >= 8) {
     292      PS_VECTOR_PRINT_F32(cumulative->bounds);
     293      PS_VECTOR_PRINT_F32(cumulative->nums);
     294    }
     295
     296    // Find the bin which contains the first data point above the limit
     297    long totalDataPoints = cumulative->nums->data.F32[numBins - 1];
     298    psTrace("psastro", 6, "Total data points is %ld\n", totalDataPoints);
     299
     300    // find bin which is the lower bound of the limit value (value[bin] < f < value[bin+1]
     301    long bin;
     302    PS_BIN_FOR_VALUE(bin, cumulative->nums, flimit * totalDataPoints, 0);
     303    psTrace("psastro", 6, "The bin is %ld (%.2f to %.2f)\n", bin, cumulative->bounds->data.F32[bin], cumulative->bounds->data.F32[bin+1]);
     304
     305    // Linear interpolation to the limit value in bin units
     306    float value;
     307    PS_BIN_INTERPOLATE (value, cumulative->nums, cumulative->bounds, bin, totalDataPoints * flimit);
     308    psTrace("psastro", 6, "limit value is %f\n", value);
     309
     310    stats->clippedMean = value;
     311    stats->clippedStdev = 0.0; // XXX derive correct error value
     312    stats->results |= PS_STAT_CLIPPED_MEAN;
     313    stats->results |= PS_STAT_CLIPPED_STDEV;
     314    stats->options = PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV;
     315
     316    // Clean up
     317    psFree(histogram);
     318    psFree(cumulative);
     319    return stats;
     320
     321escape:
     322    stats->clippedMean = NAN;
     323    stats->clippedStdev = NAN;
     324    stats->results |= PS_STAT_CLIPPED_MEAN;
     325    stats->results |= PS_STAT_CLIPPED_STDEV;
     326    stats->options = PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV;
     327
     328    psFree(histogram);
     329    psFree(cumulative);
     330
     331    return stats;
     332}
     333
    145334
    146335# define ESCAPE(MSG) { \
Note: See TracChangeset for help on using the changeset viewer.