IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Dec 10, 2008, 5:24:56 PM (17 years ago)
Author:
Paul Price
Message:

Added photometric determination and measurement clipping for relphot. Seems to work.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/objects/pmSourceMatch.c

    r20949 r20953  
    6363        pmSource *source = sources->data[i]; // Source of interest
    6464        if (!source || (source->mode & SOURCE_MASK) || !isfinite(source->psfMag) ||
    65             source->psfMag > SOURCE_FAINTEST) {
     65            !isfinite(source->errMag) || source->psfMag > SOURCE_FAINTEST) {
    6666            continue;
    6767        }
     
    122122    match->image = psVectorAllocEmpty(num, PS_TYPE_U32);
    123123    match->index = psVectorAllocEmpty(num, PS_TYPE_U32);
     124    match->mask = psVectorAllocEmpty(num, PS_TYPE_MASK);
    124125
    125126    return match;
     
    142143    match->image->data.S32[num] = image;
    143144    match->index->data.S32[num] = index;
     145    match->index->data.PS_TYPE_MASK_DATA[num] = 0;
    144146    match->num++;
    145147
    146     match->mag->n = match->magErr->n = match->image->n = match->index->n = match->num;
     148    match->mag->n = match->magErr->n = match->image->n = match->index->n = match->mask->n = match->num;
    147149}
    148150
     
    287289                                psVector *stars, // Star magnitudes
    288290                                const psArray *matches, // Array of matches
    289                                 const psVector *zp // Zero points for each image (including airmass term)
     291                                const psVector *zp, // Zero points for each image (including airmass term)
     292                                const psVector *photo // Photometric image?
    290293                                )
    291294{
     295    psAssert(zp && zp->type.type == PS_TYPE_F32, "Need zero points");
     296    psAssert(matches, "Need list of matches");
     297
    292298    int numImages = zp->n;              // Number of images
    293299    int numStars = matches->n;          // Number of stars
     
    297303    psAssert(stars && stars->type.type == PS_TYPE_F32, "Need star magnitudes");
    298304    psAssert(stars->n == numStars, "Not enough stars: %ld\n", stars->n);
    299     psAssert(matches, "Need list of matches");
    300     psAssert(zp && zp->type.type == PS_TYPE_F32, "Need zero points");
    301305    psAssert(zp->n == numImages, "Not enough ZPs: %ld", zp->n);
    302 
    303     psVector *transErr = psVectorAlloc(numImages, PS_TYPE_F32); // Errors in the transparency
    304     psVector *starsErr = psVectorAlloc(numStars, PS_TYPE_F32); // Errors in the star magnitudes
     306    psAssert(!photo || photo->type.type == PS_TYPE_U8, "Photometric determination is wrong type");
     307    psAssert(!photo || photo->n == numImages, "Not enough photometric determinations: %ld", photo->n);
    305308
    306309    // Solve the star magnitudes
    307310    psVectorInit(stars, 0.0);
    308     psVectorInit(starsErr, 0.0);
     311    int numGoodStars = 0;               // Number of stars with good measurements
     312    for (int i = 0; i < numStars; i++) {
     313        pmSourceMatch *match = matches->data[i]; // Matched stars
     314        int numMeasurements = 0;        // Number of unmasked measurements for star
     315        double star = 0.0, starErr = 0.0; // Accumulators for star
     316        for (int j = 0; j < match->num; j++) {
     317            if (match->mask->data.PS_TYPE_MASK_DATA[j]) {
     318                continue;
     319            }
     320            numMeasurements++;
     321            int index = match->image->data.U32[j]; // Image index
     322            float mag = match->mag->data.F32[j]; // Measured magnitude
     323            double magErr = match->magErr->data.F32[j]; // Error in measured magnitude
     324            double invErr2 = 1.0 / PS_SQR(magErr); // Inverse square error
     325            float cal = zp->data.F32[index]; // Calibration to apply to image
     326            if (!photo || !photo->data.U8[index]) {
     327                cal -= trans->data.F32[index];
     328            }
     329            star += (mag + cal) * invErr2;
     330            starErr += invErr2;
     331        }
     332        if (numMeasurements > 1) {
     333            // It's only a good star (contributing to the chi^2) if there's more than 1 measurement
     334            numGoodStars++;
     335        }
     336        stars->data.F32[i] = star / starErr;
     337    }
     338
     339    // Solve for the transparencies
     340    // We solve even for the "photometric" images since they may jump out of that status upon iteration
     341    psVector *accum = psVectorAlloc(numImages, PS_TYPE_F64); // Transparency accumulator
     342    psVector *accumErr = psVectorAlloc(numImages, PS_TYPE_F64); // Transparency accumulator
     343    psVectorInit(accum, 0.0);
     344    psVectorInit(accumErr, 0.0);
    309345    for (int i = 0; i < numStars; i++) {
    310346        pmSourceMatch *match = matches->data[i]; // Matched stars
    311347        for (int j = 0; j < match->num; j++) {
     348            if (match->mask->data.PS_TYPE_MASK_DATA[j]) {
     349                continue;
     350            }
     351            int index = match->image->data.U32[j]; // Image index
     352            float mag = match->mag->data.F32[j]; // Measured magnitude
     353            double magErr = match->magErr->data.F32[j]; // Error in measured magnitude
     354            double invErr2 = 1.0 / PS_SQR(magErr); // Inverse square error
     355            float cal = zp->data.F32[index]; // Calibration to apply to image
     356            accum->data.F64[index] += (mag + cal - stars->data.F32[i]) * invErr2;
     357            accumErr->data.F64[index] += invErr2;
     358        }
     359    }
     360    for (int i = 0; i < numImages; i++) {
     361        trans->data.F32[i] = accum->data.F64[i] / accumErr->data.F64[i];
     362
     363        psTrace("psModules.objects", 3, "Transparency for image %d: %f\n", i, trans->data.F32[i]);
     364    }
     365    psFree(accum);
     366    psFree(accumErr);
     367
     368    // Once more through to evaluate chi^2
     369    float chi2 = 0.0;                   // chi^2 for iteration
     370    int dof = 0;                        // Degrees of freedom
     371    for (int i = 0; i < numStars; i++) {
     372        pmSourceMatch *match = matches->data[i]; // Matched stars
     373        for (int j = 0; j < match->num; j++) {
     374            if (match->mask->data.PS_TYPE_MASK_DATA[j]) {
     375                continue;
     376            }
    312377            int index = match->image->data.U32[j]; // Image index
    313378            float mag = match->mag->data.F32[j]; // Measured magnitude
    314379            float magErr = match->magErr->data.F32[j]; // Error in measured magnitude
    315             float invErr2 = 1.0 / PS_SQR(magErr); // Inverse square error
    316             stars->data.F32[i] += (mag + zp->data.F32[index] - trans->data.F32[index]) * invErr2;
    317             starsErr->data.F32[i] += invErr2;
    318         }
    319     }
    320     for (int i = 0; i < numStars; i++) {
    321         float inverse = 1.0 / starsErr->data.F32[i]; // Inverse error
    322         stars->data.F32[i] *= inverse;
    323         starsErr->data.F32[i] = sqrtf(inverse);
    324     }
    325 
    326     // Solve for the transparencies
    327     psVectorInit(trans, 0.0);
    328     psVectorInit(transErr, 0.0);
     380            float cal = zp->data.F32[index]; // Calibration to apply to image
     381            if (!photo || !photo->data.U8[index]) {
     382                cal -= trans->data.F32[index];
     383            }
     384            float dev = (mag + cal - stars->data.F32[index]) / magErr; // Deviation from fit
     385            if (isfinite(dev)) {
     386                chi2 += PS_SQR(dev);
     387                dof++;
     388            }
     389        }
     390    }
     391    dof -= numGoodStars + numImages;
     392    chi2 /= dof;
     393
     394    return chi2;
     395}
     396
     397// Determine which images are photometric, based on estimated transparencies
     398// Returns number of photometric images, or -1 on error
     399static int sourceMatchRelphotPhotometric(psVector *photo, // Photometric determination
     400                                         const psVector *trans, // Estimated transparencies
     401                                         int transIter, // Iterations for transparency
     402                                         float transClip, // Clipping level for transparency
     403                                         float photoLevel // Level below which we declare photometric
     404                                         )
     405{
     406    psAssert(photo && photo->type.type == PS_TYPE_U8, "Need photometric determination");
     407    psAssert(trans && trans->type.type == PS_TYPE_F32, "Need transparencies");
     408
     409    int numImages = photo->n;              // Number of images
     410
     411    psAssert(trans->n == numImages, "Not enough transparencies: %ld", trans->n);
     412    psAssert(transIter >= 0, "Iterations for transparency must be non-negative: %d", transIter);
     413    psAssert(transClip > 0, "Clipping level for transparency must be positive: %f", transClip);
     414    psAssert(photoLevel > 0, "Photometric level must be positive: %f", photoLevel);
     415
     416    psStats *stats = psStatsAlloc(PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV); // Statistics
     417    stats->clipIter = transIter;
     418    stats->clipSigma = transClip;
     419
     420    if (!psVectorStats(stats, trans, NULL, NULL, 0)) {
     421        psError(PS_ERR_UNKNOWN, false, "Unable to perform statistics on transparencies.");
     422        psFree(stats);
     423        return -1;
     424    }
     425
     426    float thresh = stats->clippedMean + photoLevel * stats->clippedStdev; // Threshold for clouds
     427    psFree(stats);
     428
     429    int numPhoto = 0;                   // Number of photometric images
     430    for (int i = 0; i < numImages; i++) {
     431        if (trans->data.F32[i] < thresh) {
     432            photo->data.U8[i] = 0xFF;
     433            numPhoto++;
     434        } else {
     435            photo->data.U8[i] = 0;
     436        }
     437    }
     438
     439    return numPhoto;
     440}
     441
     442
     443// Reject star measurements
     444// Returns the fraction of measurements that were rejected
     445static float sourceMatchRelphotReject(psVector *trans, // Transparencies
     446                                      psVector *stars, // Star magnitudes
     447                                      const psArray *matches, // Array of matches
     448                                      const psVector *zp, // Zero points for each image
     449                                      const psVector *photo, // Photometric image?
     450                                      float starClip, // Clipping for stars
     451                                      float sysErr // Systematic error
     452                                )
     453{
     454    psAssert(zp && zp->type.type == PS_TYPE_F32, "Need zero points");
     455    psAssert(matches, "Need list of matches");
     456
     457    int numImages = zp->n;              // Number of images
     458    int numStars = matches->n;          // Number of stars
     459
     460    psAssert(trans && trans->type.type == PS_TYPE_F32, "Need transparencies");
     461    psAssert(trans->n == numImages, "Not enough transparencies: %ld\n", trans->n);
     462    psAssert(stars && stars->type.type == PS_TYPE_F32, "Need star magnitudes");
     463    psAssert(stars->n == numStars, "Not enough stars: %ld\n", stars->n);
     464    psAssert(zp->n == numImages, "Not enough ZPs: %ld", zp->n);
     465    psAssert(!photo || photo->type.type == PS_TYPE_U8, "Photometric determination is wrong type");
     466    psAssert(!photo || photo->n == numImages, "Not enough photometric determinations: %ld", photo->n);
     467
     468    starClip = PS_SQR(starClip);
     469    sysErr = PS_SQR(sysErr);
     470
     471    int numRejected = 0;                // Number rejected
     472    int numMeasurements = 0;            // Number of measurements
    329473    for (int i = 0; i < numStars; i++) {
    330474        pmSourceMatch *match = matches->data[i]; // Matched stars
    331475        for (int j = 0; j < match->num; j++) {
     476            if (match->mask->data.PS_TYPE_MASK_DATA[j]) {
     477                continue;
     478            }
     479            numMeasurements++;
    332480            int index = match->image->data.U32[j]; // Image index
    333481            float mag = match->mag->data.F32[j]; // Measured magnitude
    334482            float magErr = match->magErr->data.F32[j]; // Error in measured magnitude
    335             float invErr2 = 1.0 / PS_SQR(magErr); // Inverse square error
    336             trans->data.F32[index] += (mag - stars->data.F32[i]) * invErr2;
    337             transErr->data.F32[index] += invErr2;
    338         }
    339     }
    340     for (int i = 0; i < numImages; i++) {
    341         float inverse = 1.0 / transErr->data.F32[i]; // Inverse error
    342         trans->data.F32[i] *= inverse;
    343         transErr->data.F32[i] = sqrtf(inverse);
    344 
    345         psTrace("psModules.objects", 3, "Transparency for image %d: %f +/- %f\n",
    346                 i, trans->data.F32[i], transErr->data.F32[i]);
    347     }
    348 
    349     // Once more through to evaluate chi^2
    350     float chi2 = 0.0;                   // chi^2 for iteration
    351     for (int i = 0; i < numStars; i++) {
    352         pmSourceMatch *match = matches->data[i]; // Matched stars
    353         for (int j = 0; j < match->num; j++) {
    354             int index = match->image->data.U32[j]; // Image index
    355             float mag = match->mag->data.F32[j]; // Measured magnitude
    356             float magErr = match->magErr->data.F32[j]; // Error in measured magnitude
    357             chi2 += PS_SQR(mag - stars->data.F32[index] - trans->data.F32[index] + zp->data.F32[index]) /
    358                 PS_SQR(magErr);
    359         }
    360     }
    361     chi2 /= numStars + numImages;
    362 
    363     psFree(transErr);
    364     psFree(starsErr);
    365 
    366     return chi2;
     483            float cal = zp->data.F32[index]; // Calibration to apply to image
     484            if (!photo || !photo->data.U8[index]) {
     485                cal -= trans->data.F32[index];
     486            }
     487            float dev = mag + cal - stars->data.F32[i]; // Deviation
     488            if (PS_SQR(dev) > starClip * (PS_SQR(magErr) + sysErr)) {
     489                numRejected++;
     490                match->mask->data.PS_TYPE_MASK_DATA[j] = 0xFF;
     491            }
     492        }
     493    }
     494
     495    return (float)numRejected / (float)numMeasurements;
    367496}
    368497
     
    372501                               int maxIter, // Maximum number of iterations
    373502                               float tol, // Relative tolerance for convergence
    374                                float cloudClip, // Clipping for clouds
    375                                float starClip // Clipping for stars
     503                               float rejLimit, // Limit on rejection between iterations
     504                               int transIter, // Clipping iterations for transparency
     505                               float transClip, // Clipping level for transparency
     506                               float photoLevel, // Level at which we declare image is photometric
     507                               float starClip, // Clipping for stars
     508                               float sysErr // Systematic error in measurements
    376509                               )
    377510{
     
    379512    PS_ASSERT_VECTOR_NON_NULL(zp, NULL);
    380513    PS_ASSERT_VECTOR_TYPE(zp, PS_TYPE_F32, NULL);
    381     PS_ASSERT_FLOAT_LARGER_THAN(cloudClip, 0.0, NULL);
     514    PS_ASSERT_FLOAT_LARGER_THAN(transClip, 0.0, NULL);
    382515
    383516    int numImages = zp->n;              // Number of images
     
    385518    psVector *trans = psVectorAlloc(numImages, PS_TYPE_F32); // Transparencies for each image, magnitudes
    386519    psVectorInit(trans, 0.0);
     520    psVector *photo = psVectorAlloc(numImages, PS_TYPE_U8); // Photometric determination for each image
     521    psVectorInit(photo, 0);
    387522    psVector *stars = psVectorAlloc(numStars, PS_TYPE_F32); // Magnitudes for each star
    388523
    389     float chi2 = sourceMatchRelphotIterate(trans, stars, matches, zp); // chi^2 for solution
     524    float chi2 = sourceMatchRelphotIterate(trans, stars, matches, zp, photo); // chi^2 for solution
    390525    psTrace("psModules.objects", 1, "Initial: chi^2 = %f\n", chi2);
    391526    float lastChi2 = INFINITY;          // chi^2 on last iteration
    392     for (int i = 0; i < maxIter && (lastChi2 - chi2) / chi2 > tol; i++) {
     527    float fracRej = INFINITY;        // Fraction of measurements rejected
     528    for (int i = 0; i < maxIter && (fabsf(lastChi2 - chi2) > tol * chi2 || fracRej > rejLimit); i++) {
    393529        lastChi2 = chi2;
    394         chi2 = sourceMatchRelphotIterate(trans, stars, matches, zp); // chi^2 for solution
    395         psTrace("psModules.objects", 1, "iter = %d: chi^2 = %f\n", i, chi2);
     530
     531        // Identify photometric nights
     532        int numPhoto = sourceMatchRelphotPhotometric(photo, trans, transIter, transClip,
     533                                                     photoLevel); // Number of photometric images
     534        if (numPhoto < 0) {
     535            psError(PS_ERR_UNKNOWN, false, "Unable to perform photometric determination");
     536            psFree(trans);
     537            psFree(photo);
     538            psFree(stars);
     539            return NULL;
     540        }
     541        psTrace("psModules.objects", 3, "Determined %d/%d are photometric", numPhoto, numImages);
     542
     543        fracRej = sourceMatchRelphotReject(trans, stars, matches, zp, photo, starClip, sysErr);
     544        psTrace("psModules.objects", 3, "%f%% of measurements rejected", fracRej * 100);
     545
     546        chi2 = sourceMatchRelphotIterate(trans, stars, matches, zp, photo); // chi^2 for solution
     547        psTrace("psModules.objects", 1, "iter = %d: chi^2 = %f rejected = %f\n", i, chi2, fracRej);
     548    }
     549
     550    psFree(photo);
     551    psFree(stars);
     552
     553    if (fabsf(lastChi2 - chi2) > tol * chi2 || fracRej > rejLimit) {
     554        psWarning("Unable to converge to relphot solution (%f,%f)", (lastChi2 - chi2) / chi2, fracRej);
    396555    }
    397556
Note: See TracChangeset for help on using the changeset viewer.