IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Feb 13, 2011, 12:19:53 PM (15 years ago)
Author:
eugene
Message:

some code reorganzation (move all types into pmSubtractionTypes.h); add stage to check on different mode and order options, choosing best based on chisq of subtraction; careful with the window and the kernel sizes: if the measured kron radius is too large, allow the window to grow as needed; use the 1st radial moment measured on the stamps to set the kernel scaling; remove some cruft from the code; calling program now passes in kernel scaling options to be used when 1st radial moment is measured; new function to update the kernel description string used for kernel I/O; update the kernel description after the spatial order and direction is chosen; need to carry the kernel fwhms and spatial order to allow for update; calculate the psf-match solution errors; psf solution now uses the weights to get sensible chisq values, window is used to calculate the moments; penalty scale is now adjusted to be consistent with sensible reduced chisq; improved visualizations; use range-limiter in SVD of 1e-10; calculate chisq and moments for the solution and use in the evaluation; split out the stamp selection / convolution steps; reject sources after fitting a model to the chisq assuming non-zero systematic error

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/imcombine/pmSubtraction.c

    r29777 r30622  
    2020#include "pmHDU.h"                      // Required for pmFPA.h
    2121#include "pmFPA.h"
     22#include "pmSubtractionTypes.h"
    2223#include "pmSubtractionStamps.h"
    2324#include "pmSubtractionEquation.h"
    2425#include "pmSubtractionVisual.h"
    2526#include "pmSubtractionThreads.h"
     27
     28bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header);
    2629
    2730#include "pmSubtraction.h"
     
    773776
    774777    if (convolutions) {
    775         // Already done
    776778        return convolutions;
    777779    }
     
    787789}
    788790
     791
     792bool pmSubtractionConvolveStampThread(psThreadJob *job)
     793{
     794    PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
     795
     796    pmSubtractionStamp *stamp = job->args->data[0]; // List of stamps
     797    pmSubtractionKernels *kernels = job->args->data[1]; // Kernels
     798    int footprint = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index
     799
     800    return pmSubtractionConvolveStamp(stamp, kernels, footprint);
     801}
    789802
    790803bool pmSubtractionConvolveStamp (pmSubtractionStamp *stamp, pmSubtractionKernels *kernels, int footprint)
     
    818831    }
    819832
     833#ifdef TESTING
     834    for (int j = 0; j < kernels->num; j++) {
     835        if (stamp->convolutions1) {
     836            psString convName = NULL;
     837            psStringAppend(&convName, "conv1_%03d_%03d.fits", index, j);
     838            psFits *fits = psFitsOpen(convName, "w");
     839            psFree(convName);
     840            psKernel *conv = stamp->convolutions1->data[j];
     841            psFitsWriteImage(fits, NULL, conv->image, 0, NULL);
     842            psFitsClose(fits);
     843        }
     844
     845        if (stamp->convolutions2) {
     846            psString convName = NULL;
     847            psStringAppend(&convName, "conv2_%03d_%03d.fits", index, j);
     848            psFits *fits = psFitsOpen(convName, "w");
     849            psFree(convName);
     850            psKernel *conv = stamp->convolutions2->data[j];
     851            psFitsWriteImage(fits, NULL, conv->image, 0, NULL);
     852            psFitsClose(fits);
     853        }
     854    }
     855#endif
     856
    820857    return true;
    821858}
    822859
     860bool pmSubtractionConvolveStamps(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels)
     861{
     862    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
     863    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false);
     864
     865    psTimerStart("pmSubtractionConvolveStamps");
     866
     867    int footprint = stamps->footprint;  // Half-size of stamps
     868
     869    // We iterate over each stamp and generate the convolution if needed.  We do NOT need the
     870    // convolution if (a) it has already been calculated or (b) the stamp is not available for
     871    // use (available = USED or CALCULATE)
     872   
     873    for (int i = 0; i < stamps->num; i++) {
     874        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
     875
     876        bool keep = false;
     877        keep |= (stamp->status == PM_SUBTRACTION_STAMP_USED);
     878        keep |= (stamp->status == PM_SUBTRACTION_STAMP_CALCULATE);
     879        if (!keep) continue;
     880
     881        bool haveConvolutions = false;
     882        if (kernels->mode == PM_SUBTRACTION_MODE_1) {
     883            haveConvolutions = (stamp->convolutions1 != NULL);
     884        }
     885        if (kernels->mode == PM_SUBTRACTION_MODE_2) {
     886            haveConvolutions = (stamp->convolutions2 != NULL);
     887        }
     888        if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
     889            haveConvolutions = (stamp->convolutions1 != NULL) && (stamp->convolutions2 != NULL);
     890        }
     891        if (haveConvolutions) {
     892            continue;
     893        }
     894
     895        if (pmSubtractionThreaded()) {
     896            psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_CONVOLVE_STAMP");
     897            psArrayAdd(job->args, 1, stamp);
     898            psArrayAdd(job->args, 1, kernels);
     899            PS_ARRAY_ADD_SCALAR(job->args, footprint, PS_TYPE_S32);
     900            if (!psThreadJobAddPending(job)) {
     901                return false;
     902            }
     903        } else {
     904            pmSubtractionConvolveStamp(stamp, kernels, footprint);
     905        }
     906    }
     907    if (!psThreadPoolWait(true)) {
     908        psError(psErrorCodeLast(), false, "Error waiting for threads.");
     909        return false;
     910    }
     911    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolve stamps: %f sec", psTimerClear("pmSubtractionConvolveStamps"));
     912    return true;
     913}
    823914
    824915int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, pmSubtractionStampList *stamps,
    825                               const psVector *deviations, psImage *subMask, float sigmaRej)
     916                              pmSubtractionQuality *match, psImage *subMask, float sigmaRej)
    826917{
    827918    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false);
    828919    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, -1);
    829     PS_ASSERT_VECTOR_NON_NULL(deviations, -1);
    830     PS_ASSERT_VECTOR_TYPE(deviations, PS_TYPE_F32, -1);
    831920    PS_ASSERT_IMAGE_NON_EMPTY(subMask, -1);
    832921    PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_IMAGE_MASK, -1);
    833922
    834     // I used to measure the rms deviation about zero, and use that as the sigma against which to clip, but
    835     // the distribution is actually something like a chi^2 or Student's t, both of which become Gaussian-like
    836     // with large N.  Therefore, let's just treat this as a Gaussian distribution.
     923    // Comment from PAP (r18287): I used to measure the rms deviation about zero, and use that as the
     924    // sigma against which to clip, but the distribution is actually something like a chi^2 or
     925    // Student's t, both of which become Gaussian-like with large N.  Therefore, let's just
     926    // treat this as a Gaussian distribution.
     927
     928    // Comment from EAM (r29777): The residual distribution is only chisq-like if the model is
     929    // a good fit to the data.  In the (likely) case that there is a systematic difference
     930    // between the model and the data, the squared-residual distribution grows quadratically
     931    // with increasing flux: the systematic residual flux is a constant factor times the source
     932    // flux; the squared-residual is then of the form (k0 + k1*flux)^2, where k0 comes from the
     933    // Gaussian distributed residual and k1*flux is the systematic residual error.
     934
     935    // By rejecting sources with the largest squared-residuals, the rejection biases against
     936    // the brighter sources; in severe cases, this pushes the measurement to the weakest
     937    // sources with the most noise.  To account for this, let's fit a 2nd order polynomial to
     938    // the distribution of flux vs squared-residual, subtract that fit, and reject sources
     939    // which are significantly deviant from that distribution.
    837940
    838941    kernels->mean = NAN;
     
    840943    kernels->numStamps = -1;
    841944
    842     int numStamps = 0;                  // Number of used stamps
    843     psVector *mask = psVectorAlloc(stamps->num, PS_TYPE_VECTOR_MASK); // Mask, for statistics
    844     psVectorInit(mask, 0);
    845     for (int i = 0; i < stamps->num; i++) {
    846         pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
    847         if (stamp->status != PM_SUBTRACTION_STAMP_USED) {
    848             mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff;
    849             continue;
    850         }
    851         numStamps++;
    852     }
    853     psTrace("psModules.imcombine", 1, "Number of good stamps: %d\n", numStamps);
    854 
    855     if (numStamps == 0) {
    856         psError(PM_ERR_STAMPS, true, "No good stamps found.");
    857         psFree(mask);
    858         return -1;
    859     }
    860 
    861     psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV |
    862                                   PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_QUARTILE); // Statistics for deviatns
    863     if (!psVectorStats(stats, deviations, NULL, mask, 0xff)) {
    864         psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations.");
     945    psTrace("psModules.imcombine", 1, "Number of good stamps: %d\n", match->nGood);
     946
     947    // the chisq & flux vectors are calculated by pmSubtractionCalculateChisqAndMoments
     948
     949    // use 3hi/3lo sigma clipping on the chisq fit
     950    psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV);
     951    stats->clipSigma = 5.0;
     952    stats->clipIter = 2;
     953    psPolynomial1D *model = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 2);
     954
     955    bool result = psVectorClipFitPolynomial1D(model, stats, match->stampMask, 0xff, match->chisq, NULL, match->fluxes);
     956    if (!result) {
     957        psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations.");
     958        psFree(model);
    865959        psFree(stats);
    866         psFree(mask);
    867         return -1;
    868     }
    869     psFree(mask);
    870 
    871     // XXX raise an error?
     960        return -1;
     961    }
    872962    if (isnan(stats->sampleMean)) {
     963        psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations.");
     964        psFree(model);
    873965        psFree(stats);
    874966        return -1;
    875967    }
    876968
    877     double mean, rms;                 // Mean and RMS of deviations
    878     if (numStamps < MIN_SAMPLE_STATS) {
    879         mean = stats->sampleMean;
    880         rms = stats->sampleStdev;
    881     } else {
    882         mean = stats->sampleMedian;
    883         rms = 0.74 * (stats->sampleUQ - stats->sampleLQ);
    884     }
    885     psFree(stats);
    886 
    887     psTrace("psModules.imcombine", 1, "Mean: %f\n", mean);
    888     psTrace("psModules.imcombine", 1, "RMS deviation: %f\n", rms);
    889 
    890     kernels->mean = mean;
    891     kernels->rms = rms;
    892     kernels->numStamps = numStamps;
    893 
    894     psLogMsg("psModules.imcombine", PS_LOG_INFO, "Mean deviation from %d stamps: %lf +/- %lf",
    895              numStamps, mean, rms);
    896 
    897     if (!isfinite(sigmaRej) || sigmaRej <= 0.0) {
    898         // User just wanted to calculate and record the deviation for posterity
    899         return 0;
    900     }
    901 
    902     float limit = sigmaRej * rms; // Limit on maximum deviation
    903     psTrace("psModules.imcombine", 1, "Deviation limit: %f\n", limit);
    904 
     969    kernels->mean = stats->sampleMean;
     970    kernels->rms = stats->sampleStdev;
     971    kernels->numStamps = stats->clippedNvalues;
     972
     973    psLogMsg ("pmPSFtry", 4, "chisq vs flux model: %e + %e flux + %e flux^2\n", model->coeff[0], model->coeff[1], model->coeff[2]);
     974    psLogMsg ("pmPSFtry", 4, "chisq vs flux resid: %f +/- %f\n", stats->sampleMean, stats->sampleStdev);
     975    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Mean deviation from %d stamps: %lf +/- %lf",  kernels->numStamps, kernels->mean, kernels->rms);
    905976
    906977    psString ds9name = NULL;            // Filename for ds9 region file
     
    914985    int numRejected = 0;                // Number of stamps rejected
    915986    int numGood = 0;                    // Number of good stamps
    916     double newMean = 0.0;               // New mean
    917987    psString log = NULL;                // Log message
    918     psStringAppend(&log, "Rejecting stamps, mean = %f, threshold = %f\n", mean, limit);
     988
     989    // save DS9 region files for the stamps and mark for rejection and replacement
    919990    for (int i = 0; i < stamps->num; i++) {
    920991        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
    921         if (stamp->status == PM_SUBTRACTION_STAMP_USED) {
     992        if (stamp->status  != PM_SUBTRACTION_STAMP_USED) { continue; }
     993        if (match->stampMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
    922994            // Should we reject stars with low deviation?  Well, if this is really a Gaussian-like
    923995            // distribution and they're low, then we have the right to ask why.  Isn't it suspicious that
     
    926998            // subtract well, in which case very few (if any) stars will be legitimately rejected for being
    927999            // low.
    928             if (fabsf(deviations->data.F32[i] - mean) > limit) {
    929                 // Mask out the stamp in the image so you it's not found again
    930                 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i,
    931                         (int)(stamp->x - 0.5), (int)(stamp->y - 0.5));
    932                 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", i,
    933                                (int)(stamp->x - 0.5), (int)(stamp->y - 0.5),
    934                                fabsf(deviations->data.F32[i] - mean));
    935                 numRejected++;
    936                 for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) {
    937                     for (int x = stamp->x - footprint; x <= stamp->x + footprint; x++) {
    938                         subMask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= PM_SUBTRACTION_MASK_REJ;
    939                     }
    940                 }
    941                 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "red");
    942 
    943                 // Set stamp for replacement
    944                 stamp->x = 0;
    945                 stamp->y = 0;
    946                 stamp->xNorm = NAN;
    947                 stamp->yNorm = NAN;
    948                 stamp->status = PM_SUBTRACTION_STAMP_REJECTED;
    949                 // Recalculate convolutions
    950                 psFree(stamp->convolutions1);
    951                 psFree(stamp->convolutions2);
    952                 stamp->convolutions1 = stamp->convolutions2 = NULL;
    953                 psFree(stamp->image1);
    954                 psFree(stamp->image2);
    955                 psFree(stamp->weight);
    956                 stamp->image1 = stamp->image2 = stamp->weight = NULL;
    957                 psFree(stamp->matrix);
    958                 stamp->matrix = NULL;
    959                 psFree(stamp->vector);
    960                 stamp->vector = NULL;
    961             } else {
    962                 numGood++;
    963                 newMean += deviations->data.F32[i];
    964                 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green");
    965             }
    966         }
    967     }
    968     newMean /= numGood;
     1000            psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i,
     1001                    (int)(stamp->x - 0.5), (int)(stamp->y - 0.5));
     1002            psStringAppend(&log, "Stamp %d (%d,%d): %f : %f : %f\n",
     1003                           i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5),
     1004                           match->chisq->data.F32[i], match->fluxes->data.F32[i], match->chisq->data.F32[i] - psPolynomial1DEval(model, match->fluxes->data.F32[i]));
     1005            numRejected++;
     1006            for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) {
     1007                for (int x = stamp->x - footprint; x <= stamp->x + footprint; x++) {
     1008                    subMask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= PM_SUBTRACTION_MASK_REJ;
     1009                }
     1010            }
     1011            pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "red");
     1012
     1013            // Set stamp for replacement
     1014            stamp->x = 0;
     1015            stamp->y = 0;
     1016            stamp->xNorm = NAN;
     1017            stamp->yNorm = NAN;
     1018            stamp->status = PM_SUBTRACTION_STAMP_REJECTED;
     1019            // Recalculate convolutions
     1020            psFree(stamp->convolutions1);
     1021            psFree(stamp->convolutions2);
     1022            stamp->convolutions1 = stamp->convolutions2 = NULL;
     1023            psFree(stamp->image1);
     1024            psFree(stamp->image2);
     1025            psFree(stamp->weight);
     1026            stamp->image1 = stamp->image2 = stamp->weight = NULL;
     1027            psFree(stamp->matrix);
     1028            stamp->matrix = NULL;
     1029            psFree(stamp->vector);
     1030            stamp->vector = NULL;
     1031        } else {
     1032            numGood++;
     1033            pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green");
     1034        }
     1035    }
    9691036
    9701037    if (numRejected == 0) {
     
    9781045    }
    9791046
     1047    psFree(model);
     1048    psFree(stats);
     1049
    9801050    if (numRejected > 0) {
    981         psLogMsg("psModules.imcombine", PS_LOG_INFO,
    982                  "%d good stamps; %d rejected.\nMean deviation: %lf --> %lf\n",
    983                  numGood, numRejected, mean, newMean);
     1051        psLogMsg("psModules.imcombine", PS_LOG_INFO, "%d good stamps; %d rejected.\n", numGood, numRejected);
    9841052    } else {
    985         psLogMsg("psModules.imcombine", PS_LOG_INFO,
    986                  "%d good stamps; 0 rejected.\nMean deviation: %lf\n",
    987                  numGood, mean);
     1053        psLogMsg("psModules.imcombine", PS_LOG_INFO, "%d good stamps; 0 rejected.\n", numGood);
    9881054    }
    9891055
     
    13731439    psFree(kernelErr2);
    13741440
     1441    static int nOut1 = 0;
     1442    static int nOut2 = 0;
     1443
    13751444    // Calculate covariances
    13761445    // This can be fairly involved, so we only do it for a small number of instances
     
    13861455                psKernelTruncate(kernel, covarFrac);
    13871456                covars->data[i] = psImageCovarianceCalculate(kernel, ro1->covariance);
     1457                if (0) {
     1458                    char name[128];
     1459                    snprintf (name, 128, "covar.sample1.%03d.fits", nOut1);
     1460                    psKernel *cov = covars->data[i];
     1461                    psFitsWriteImageSimple (name, cov->image, NULL);
     1462
     1463                    snprintf (name, 128, "incovar.sample1.%03d.fits", nOut1);
     1464                    psFitsWriteImageSimple (name, ro1->covariance->image, NULL);
     1465
     1466                    snprintf (name, 128, "conv.sample1.%03d.fits", nOut1);
     1467                    psFitsWriteImageSimple (name, kernel->image, NULL);
     1468
     1469                    fprintf (stderr, "incov: %d,%d; kern: %d,%d, outcov: %d,%d\n",
     1470                             ro1->covariance->image->numCols, ro1->covariance->image->numRows,
     1471                             kernel->image->numCols, kernel->image->numRows,
     1472                             cov->image->numCols, cov->image->numRows);
     1473
     1474                    nOut1 ++;
     1475                }
    13881476                psFree(kernel);
    13891477            }
     
    14071495                psKernelTruncate(kernel, covarFrac);
    14081496                covars->data[i] = psImageCovarianceCalculate(kernel, ro2->covariance);
     1497                if (0) {
     1498                    char name[128];
     1499                    snprintf (name, 128, "covar.sample2.%03d.fits", nOut2);
     1500                    psKernel *cov = covars->data[i];
     1501                    psFitsWriteImageSimple (name, cov->image, NULL);
     1502
     1503                    snprintf (name, 128, "incovar.sample2.%03d.fits", nOut2);
     1504                    psFitsWriteImageSimple (name, ro2->covariance->image, NULL);
     1505
     1506                    snprintf (name, 128, "conv.sample2.%03d.fits", nOut2);
     1507                    psFitsWriteImageSimple (name, kernel->image, NULL);
     1508
     1509                    fprintf (stderr, "incov: %d,%d; kern: %d,%d, outcov: %d,%d\n",
     1510                             ro2->covariance->image->numCols, ro2->covariance->image->numRows,
     1511                             kernel->image->numCols, kernel->image->numRows,
     1512                             cov->image->numCols, cov->image->numRows);
     1513
     1514                    nOut2 ++;
     1515                }
    14091516                psFree(kernel);
    14101517            }
     
    14221529    psImageCovarianceSetThreads(oldThreads);
    14231530
    1424     // Copy anything that wasn't convolved
     1531    // Copy anything that wasn't convolved (they may have been allocated though, so free them)
    14251532    switch (kernels->mode) {
    14261533      case PM_SUBTRACTION_MODE_1:
    14271534        if (out2) {
     1535            psFree(out2->image);
     1536            psFree(out2->variance);
     1537            psFree(out2->mask);
     1538            psFree(out2->covariance);
    14281539            out2->image = psMemIncrRefCounter(ro2->image);
    14291540            out2->variance = psMemIncrRefCounter(ro2->variance);
     
    14341545      case PM_SUBTRACTION_MODE_2:
    14351546        if (out1) {
     1547            psFree(out1->image);
     1548            psFree(out1->variance);
     1549            psFree(out1->mask);
     1550            psFree(out1->covariance);
    14361551            out1->image = psMemIncrRefCounter(ro1->image);
    14371552            out1->variance = psMemIncrRefCounter(ro1->variance);
     
    14791594  return true;
    14801595}
     1596
     1597static void pmSubtractionQualityFree(pmSubtractionQuality *quality) {
     1598
     1599    psFree (quality->fluxes);
     1600    psFree (quality->chisq);
     1601    psFree (quality->moments);
     1602    psFree (quality->stampMask);
     1603}   
     1604
     1605pmSubtractionQuality *pmSubtractionQualityAlloc() {
     1606
     1607    pmSubtractionQuality *quality = psAlloc(sizeof(pmSubtractionQuality)); // Stamp list to return
     1608    psMemSetDeallocator(quality, (psFreeFunc)pmSubtractionQualityFree);
     1609
     1610    quality->fluxes = NULL;
     1611    quality->chisq = NULL;
     1612    quality->moments = NULL;
     1613    quality->stampMask = NULL;
     1614
     1615    quality->score = NAN;
     1616    quality->mode = PM_SUBTRACTION_MODE_ERR;
     1617    quality->spatialOrder = -1;
     1618    quality->nGood = 0;
     1619   
     1620    return quality;
     1621}
Note: See TracChangeset for help on using the changeset viewer.