IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Feb 14, 2011, 1:05:28 PM (15 years ago)
Author:
watersc1
Message:

Merge of trunk back into branch.

Location:
branches/czw_branch/20101203
Files:
55 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/czw_branch/20101203

  • branches/czw_branch/20101203/psModules/src/extras/pmVisual.c

    r29545 r30631  
    1616#include <pslib.h>
    1717
    18 #include "pmHDU.h"
    19 #include "pmFPA.h"
    20 #include "pmFPAfile.h"
    21 #include "pmAstrometryObjects.h"
    22 #include "pmSubtractionStamps.h"
    23 
    24 #include "pmTrend2D.h"
    25 #include "pmResiduals.h"
    26 #include "pmGrowthCurve.h"
    27 #include "pmSpan.h"
    28 #include "pmFootprintSpans.h"
    29 #include "pmFootprint.h"
    30 #include "pmPeaks.h"
    31 #include "pmMoments.h"
    32 #include "pmModelFuncs.h"
    33 #include "pmModel.h"
    34 #include "pmSourceMasks.h"
    35 #include "pmSourceExtendedPars.h"
    36 #include "pmSourceDiffStats.h"
    37 #include "pmSource.h"
    38 #include "pmSourceFitModel.h"
    39 #include "pmPSF.h"
    40 #include "pmPSFtry.h"
    41 
    42 #include "pmFPAExtent.h"
    43 
    44 #include "pmAstrometryVisual.h"
    45 #include "pmSubtractionVisual.h"
    46 #include "pmStackVisual.h"
    47 #include "pmSourceVisual.h"
     18bool pmSubtractionVisualClose(void);
     19bool pmAstromVisualClose(void);
     20bool pmSubtractionVisualClose(void);
     21bool pmStackVisualClose(void);
     22bool pmSourceVisualClose(void);
     23
     24// #include "pmHDU.h"
     25// #include "pmFPA.h"
     26// #include "pmFPAfile.h"
     27// #include "pmAstrometryObjects.h"
     28// #include "pmSubtractionStamps.h"
     29// #include "pmTrend2D.h"
     30// #include "pmResiduals.h"
     31// #include "pmGrowthCurve.h"
     32// #include "pmSpan.h"
     33// #include "pmFootprintSpans.h"
     34// #include "pmFootprint.h"
     35// #include "pmPeaks.h"
     36// #include "pmMoments.h"
     37// #include "pmModelFuncs.h"
     38// #include "pmModel.h"
     39// #include "pmSourceMasks.h"
     40// #include "pmSourceExtendedPars.h"
     41// #include "pmSourceDiffStats.h"
     42// #include "pmSource.h"
     43// #include "pmSourceFitModel.h"
     44// #include "pmPSF.h"
     45// #include "pmPSFtry.h"
     46// #include "pmFPAExtent.h"
     47// #include "pmAstrometryVisual.h"
     48// #include "pmSubtractionVisual.h"
     49// #include "pmStackVisual.h"
     50// #include "pmSourceVisual.h"
    4851
    4952# if (HAVE_KAPA)
     
    306309}
    307310
     311bool pmVisualRangeImage (int kapaFD, psImage *inImage, const char *name, int channel, float min, float max) {
     312
     313    KiiImage image;
     314    KapaImageData data;
     315    Coords coords;
     316
     317    strcpy (coords.ctype, "RA---TAN");
     318
     319    image.data2d = inImage->data.F32;
     320    image.Nx = inImage->numCols;
     321    image.Ny = inImage->numRows;
     322
     323    strcpy (data.name, name);
     324    strcpy (data.file, name);
     325    data.zero = min;
     326    data.range = max - min;
     327    data.logflux = 0;
     328
     329    KiiSetChannel (kapaFD, channel);
     330    KiiNewPicture2D (kapaFD, &image, &data, &coords);
     331
     332    return true;
     333}
    308334
    309335psImage* pmVisualImageToFloat(psImage *image) {
  • branches/czw_branch/20101203/psModules/src/extras/pmVisual.h

    r23242 r30631  
    6464                        const char *name, int channel, bool clip);
    6565
     66bool pmVisualRangeImage (int kapaFD, psImage *inImage, const char *name, int channel, float min, float max);
    6667
    6768/** Calculate statistics on an image.
  • branches/czw_branch/20101203/psModules/src/imcombine/Makefile.am

    r26893 r30631  
    3030        pmStackReject.h         \
    3131        pmSubtraction.h         \
     32        pmSubtractionTypes.h            \
    3233        pmSubtractionAnalysis.h \
    3334        pmSubtractionEquation.h \
  • branches/czw_branch/20101203/psModules/src/imcombine/pmReadoutCombine.c

    r24907 r30631  
    3333    params->blank = 0;
    3434    params->nKeep = 0;
    35     params->fracHigh = 0.0;
     35    params->fracLow = 0.0;
    3636    params->fracHigh = 0.0;
    3737    params->iter = 1;
  • branches/czw_branch/20101203/psModules/src/imcombine/pmStackReject.c

    r28405 r30631  
    77#include <pslib.h>
    88
     9#include "pmFPA.h"
     10#include "pmSubtractionTypes.h"
    911#include "pmSubtraction.h"
    1012#include "pmSubtractionThreads.h"
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtraction.c

    r29777 r30631  
    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}
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtraction.h

    r29601 r30631  
    1414#define PM_SUBTRACTION_H
    1515
    16 #include <pslib.h>
    17 
    18 #include <pmHDU.h>
    19 #include <pmFPA.h>
    20 #include <pmSubtractionKernels.h>
    21 #include <pmSubtractionStamps.h>
     16// #include <pslib.h>
     17// #include <pmHDU.h>
     18// #include <pmFPA.h>
     19// #include <pmSubtractionKernels.h>
     20// #include <pmSubtractionStamps.h>
    2221
    2322// if we use the original ppSub implementation, we subtract a central delta-function for all
     
    3029/// @addtogroup imcombine Image Combinations
    3130/// @{
    32 
    33 /// Mask values for the subtraction mask
    34 typedef enum {
    35     PM_SUBTRACTION_MASK_CLEAR          = 0x00, // No masking
    36     PM_SUBTRACTION_MASK_BAD_1          = 0x01, // Image 1 is bad
    37     PM_SUBTRACTION_MASK_BAD_2          = 0x02, // Image 2 is bad
    38     PM_SUBTRACTION_MASK_CONVOLVE_1     = 0x04, // If image 1 is convolved, would be poor or bad
    39     PM_SUBTRACTION_MASK_CONVOLVE_2     = 0x08, // If image 2 is convolved, would be poor or bad
    40     PM_SUBTRACTION_MASK_CONVOLVE_BAD_1 = 0x10, // If image 1 is convolved, would be bad
    41     PM_SUBTRACTION_MASK_CONVOLVE_BAD_2 = 0x20, // If image 2 is convolved, would be bad
    42     PM_SUBTRACTION_MASK_BORDER         = 0x40, // Image border
    43     PM_SUBTRACTION_MASK_REJ            = 0x80, // Previously tried as a stamp, and rejected
    44 } pmSubtractionMasks;
    45 
    4631
    4732/// Number of terms in a polynomial
     
    7055    );
    7156
     57bool pmSubtractionConvolveStamps(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels);
     58
     59bool pmSubtractionConvolveStampThread(psThreadJob *job);
     60
    7261/// Reject stamps
    7362int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, ///< Kernel parameters to update
    7463                              pmSubtractionStampList *stamps, ///< Stamps
    75                               const psVector *deviations, ///< Deviations for each stamp
     64                              pmSubtractionQuality *match, ///< data on the subtraction quality
    7665                              psImage *subMask, ///< Subtraction mask
    7766                              float sigmaRej ///< Number of RMS deviations above zero at which to reject
     
    167156bool pmSubtractionSetFWHMs(float fwhm1, float fwhm2);
    168157
     158pmSubtractionQuality *pmSubtractionQualityAlloc();
     159
    169160/// @}
    170161#endif
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionAnalysis.c

    r29595 r30631  
    77
    88#include "pmFPA.h"
     9#include "pmSubtractionTypes.h"
    910#include "pmSubtraction.h"
    1011#include "pmSubtractionKernels.h"
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionDeconvolve.c

    r26893 r30631  
    1010
    1111#include "pmFPA.h"
     12#include "pmSubtractionTypes.h"
    1213#include "pmSubtractionKernels.h"
    1314#include "pmSubtractionDeconvolve.h"
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionEquation.c

    r29598 r30631  
    88
    99#include "pmErrorCodes.h"
     10#include "pmVisual.h"
     11#include "pmFPA.h"
     12#include "pmSubtractionTypes.h"
    1013#include "pmSubtraction.h"
    1114#include "pmSubtractionKernels.h"
     
    1619#include "pmSubtractionVisual.h"
    1720
    18 //#define TESTING                         // TESTING output for debugging; may not work with threads!
    19 
    20 //#define USE_WEIGHT                      // Include weight (1/variance) in equation?
    21 
    22 // XXX TEST:
    23 //# define USE_WINDOW                      // window to avoid neighbor contamination
     21//# define TESTING                         // TESTING output for debugging; may not work with threads!
     22# define USE_WEIGHT                      // Include weight (1/variance) in equation?
     23# define USE_WINDOW                      // window to avoid neighbor contamination
     24
     25/* I believe we want to apply the WEIGHT to the chisq portions of the calculation (but not the WINDOW),
     26 * and the WINDOW to the moments portiosn of the calculations (but not the WEIGHT)
     27 *
     28 */
    2429
    2530# define PENALTY false
    2631# define MOMENTS (!PENALTY)
    27 # define MOMENTS_PENALTY_SCALE 2e-5 // XXX this value is not completely arbitrary, but I don't understand why it needs to be this value...
     32# define MOMENTS_PENALTY_SCALE 20 // up-weight the moments somewhat
    2833
    2934//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     
    107112                        cc *= weight->kernel[y][x];
    108113                    }
    109                     if (window) {
     114                    // XXX NOTE: do NOT apply the window to the chisq portions of the calculation
     115                    if (false && window) {
    110116                        cc *= window->kernel[y][x];
    111117                    }
     
    138144                    rc *= wtVal;
    139145                }
    140                 if (window) {
     146                // XXX NOTE: do NOT apply the window to the chisq portions of the calculation
     147                if (false && window) {
    141148                    float winVal = window->kernel[y][x];
    142149                    ic *= winVal;
     
    173180}
    174181
     182# define RENORM_BY_FLUX 0
    175183
    176184// Calculate the least-squares matrix and vector for dual convolution
     
    268276            for (int y = - footprint; y <= footprint; y++) {
    269277                for (int x = - footprint; x <= footprint; x++) {
     278
     279                    // XXX NOTE: clipping low S/N pixels does not seem to work very well
     280                    if (false && weight) {
     281                        float i1 = image1->kernel[y][x];
     282                        float i2 = image2->kernel[y][x];
     283                        float sn = (i1 + i2) / sqrt (weight->kernel[y][x]);
     284                        if (sn < 0.5) continue;
     285                    }
     286
    270287                    double aa = iConv1->kernel[y][x] * jConv1->kernel[y][x] * PS_SQR(normValue);
    271288                    double bb = iConv2->kernel[y][x] * jConv2->kernel[y][x];
    272289                    double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x] * normValue;
    273                     if (weight) {
    274                         float wtVal = weight->kernel[y][x];
    275                         aa *= wtVal;
    276                         bb *= wtVal;
    277                         ab *= wtVal;
    278                     }
    279                     if (window) {
    280                         float wtVal = window->kernel[y][x];
    281                         aa *= wtVal;
    282                         bb *= wtVal;
    283                         ab *= wtVal;
    284                     }
    285                     sumAA += aa;
    286                     sumBB += bb;
    287                     sumAB += ab;
     290
     291                    float wtVal = (weight) ? weight->kernel[y][x] : 1.0;
     292                    sumAA += wtVal*aa;
     293                    sumBB += wtVal*bb;
     294                    sumAB += wtVal*ab;
    288295
    289296                    if (MOMENTS) {
    290                         MxxAA += x*x*aa;
    291                         MyyAA += y*y*aa;
    292                         MxxBB += x*x*bb;
    293                         MyyBB += y*y*bb;
     297                        float winVal = (window) ? window->kernel[y][x] : 1.0;
     298                        MxxAA += winVal*x*x*aa;
     299                        MyyAA += winVal*y*y*aa;
     300                        MxxBB += winVal*x*x*bb;
     301                        MyyBB += winVal*y*y*bb;
    294302                    }
    295303                }
    296304            }
    297305
     306            // XXX does normSquare1,2 mess up the relative scaling?
     307            // XXX no: normSquare1,2 is the sum of the flux^2 for the source
    298308            if (MOMENTS) {
    299309                MxxAA /= stamp->normSquare1 * PS_SQR(normValue);
     
    305315            // XXX this makes the Chisq portion independent of the normalization and star flux
    306316            // but may be mis-scaling between stars of different fluxes
     317# if (RENORM_BY_FLUX)       
    307318            sumAA /= PS_SQR(stamp->normI2);
    308319            sumAB /= PS_SQR(stamp->normI2);
    309320            sumBB /= PS_SQR(stamp->normI2);
     321# endif
    310322
    311323            // fprintf (stderr, "i,j : %d %d : M(xx,yy)(AA,BB) : %f %f %f %f\n", i, j, MxxAA, MyyAA, MxxBB, MyyBB);
     
    328340                        matrix->data.F64[iIndex][jIndex] += kernels->penalty * MxxAA * MOMENTS_PENALTY_SCALE;
    329341                        matrix->data.F64[iIndex][jIndex] += kernels->penalty * MyyAA * MOMENTS_PENALTY_SCALE;
    330 
    331342                        matrix->data.F64[jIndex][iIndex] += kernels->penalty * MxxAA * MOMENTS_PENALTY_SCALE;
    332343                        matrix->data.F64[jIndex][iIndex] += kernels->penalty * MyyAA * MOMENTS_PENALTY_SCALE;
     
    334345                        matrix->data.F64[iIndex + numParams][jIndex + numParams] += kernels->penalty * MxxBB * MOMENTS_PENALTY_SCALE;
    335346                        matrix->data.F64[iIndex + numParams][jIndex + numParams] += kernels->penalty * MyyBB * MOMENTS_PENALTY_SCALE;
    336 
    337347                        matrix->data.F64[jIndex + numParams][iIndex + numParams] += kernels->penalty * MxxBB * MOMENTS_PENALTY_SCALE;
    338348                        matrix->data.F64[jIndex + numParams][iIndex + numParams] += kernels->penalty * MyyBB * MOMENTS_PENALTY_SCALE;
     
    354364                        ab *= weight->kernel[y][x];
    355365                    }
    356                     if (window) {
     366                    // XXX NOTE: do NOT apply the window to the chisq portions of the calculation
     367                    if (false && window) {
    357368                        ab *= window->kernel[y][x];
    358369                    }
     
    363374            // XXX this makes the Chisq portion independent of the normalization and star flux
    364375            // but may be mis-scaling between stars of different fluxes
     376# if (RENORM_BY_FLUX)
    365377            sumAB /= PS_SQR(stamp->normI2);
     378# endif
    366379
    367380            // Spatial variation of kernel coeffs
     
    391404                float i2 = image2->kernel[y][x];
    392405
     406                // XXX NOTE: clipping low S/N pixels does not seem to work very well
     407                if (false && weight) {
     408                    float sn = (i1 + i2) / sqrt (weight->kernel[y][x]);
     409                    if (sn < 0.5) continue;
     410                }
     411
    393412                double ai2 = a * i2 * normValue;
    394413                double bi2 = b * i2;
     
    396415                double bi1 = b * i1 * normValue;
    397416
    398                 if (weight) {
    399                     float wtVal = weight->kernel[y][x];
    400                     ai2 *= wtVal;
    401                     bi2 *= wtVal;
    402                     ai1 *= wtVal;
    403                     bi1 *= wtVal;
    404                 }
    405                 if (window) {
    406                     float wtVal = window->kernel[y][x];
    407                     ai2 *= wtVal;
    408                     bi2 *= wtVal;
    409                     ai1 *= wtVal;
    410                     bi1 *= wtVal;
    411                 }
    412                 sumAI2 += ai2;
    413                 sumBI2 += bi2;
    414                 sumAI1 += ai1;
    415                 sumBI1 += bi1;
     417                float wtVal = (weight) ? weight->kernel[y][x] : 1.0;
     418                sumAI2 += wtVal*ai2;
     419                sumBI2 += wtVal*bi2;
     420                sumAI1 += wtVal*ai1;
     421                sumBI1 += wtVal*bi1;
    416422
    417423                if (MOMENTS) {
    418                     MxxAI1 += x*x*ai1;
    419                     MyyAI1 += y*y*ai1;
    420                     MxxBI2 += x*x*bi2;
    421                     MyyBI2 += y*y*bi2;
     424                    float winVal = (window) ? window->kernel[y][x] : 1.0;
     425                    MxxAI1 += winVal*x*x*ai1;
     426                    MyyAI1 += winVal*y*y*ai1;
     427                    MxxBI2 += winVal*x*x*bi2;
     428                    MyyBI2 += winVal*y*y*bi2;
    422429                }
    423430            }
     
    435442        // XXX this makes the Chisq portion independent of the normalization and star flux
    436443        // but may be mis-scaling between stars of different fluxes
     444# if (RENORM_BY_FLUX)
    437445        sumAI1 /= PS_SQR(stamp->normI2);
    438446        sumBI1 /= PS_SQR(stamp->normI2);
    439447        sumAI2 /= PS_SQR(stamp->normI2);
    440448        sumBI2 /= PS_SQR(stamp->normI2);
     449# endif
    441450
    442451        // Spatial variation
     
    788797    stamp->normSquare2 = normSquare2;
    789798
    790     psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "normValue: %f %f %f  (%f %f)\n", normI1, normI2, stamp->norm, normSquare1, normSquare2);
     799    // psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "normValue: %f %f %f  (%f %f)\n", normI1, normI2, stamp->norm, normSquare1, normSquare2);
    791800
    792801    return true;
     
    800809    pmSubtractionKernels *kernels = job->args->data[1]; // Kernels
    801810    int index = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index
    802     pmSubtractionEquationCalculationMode mode  = PS_SCALAR_VALUE(job->args->data[3], S32); // calculation model
    803 
    804     return pmSubtractionCalculateEquationStamp(stamps, kernels, index, mode);
    805 }
    806 
    807 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels,
    808                                          int index, const pmSubtractionEquationCalculationMode mode)
     811
     812    return pmSubtractionCalculateEquationStamp(stamps, kernels, index);
     813}
     814
     815bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels, int index)
    809816{
    810817    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
     
    833840    psAssert(stamp->status == PM_SUBTRACTION_STAMP_CALCULATE, "We only operate on stamps with this state.");
    834841
    835     // Generate convolutions: these are generated once and saved
    836     if (!pmSubtractionConvolveStamp(stamp, kernels, footprint)) {
    837         psError(psErrorCodeLast(), false, "Unable to convolve stamp %d.", index);
    838         return NULL;
    839     }
    840 
    841 #ifdef TESTING
    842     for (int j = 0; j < numKernels; j++) {
    843         if (stamp->convolutions1) {
    844             psString convName = NULL;
    845             psStringAppend(&convName, "conv1_%03d_%03d.fits", index, j);
    846             psFits *fits = psFitsOpen(convName, "w");
    847             psFree(convName);
    848             psKernel *conv = stamp->convolutions1->data[j];
    849             psFitsWriteImage(fits, NULL, conv->image, 0, NULL);
    850             psFitsClose(fits);
    851         }
    852 
    853         if (stamp->convolutions2) {
    854             psString convName = NULL;
    855             psStringAppend(&convName, "conv2_%03d_%03d.fits", index, j);
    856             psFits *fits = psFitsOpen(convName, "w");
    857             psFree(convName);
    858             psKernel *conv = stamp->convolutions2->data[j];
    859             psFitsWriteImage(fits, NULL, conv->image, 0, NULL);
    860             psFitsClose(fits);
    861         }
    862     }
    863 #endif
    864 
    865     // XXX visualize the set of convolved stamps
    866 
    867     psImage *polyValues = p_pmSubtractionPolynomial(NULL, spatialOrder,
    868                                                     stamp->xNorm, stamp->yNorm); // Polynomial terms
    869 
    870     bool new = stamp->vector ? false : true; // Is this a new run?
     842    psImage *polyValues = p_pmSubtractionPolynomial(NULL, spatialOrder, stamp->xNorm, stamp->yNorm); // Polynomial terms
     843
     844    // Is this a new run? Have we allocated the correct sized vector/matrix?
     845    bool new = stamp->vector ? false : true;
     846    if (!new && (stamp->vector->n != numParams)) {
     847        psFree (stamp->vector);
     848        psFree (stamp->matrix);
     849        new = true;
     850    }
     851
    871852    if (new) {
    872853        stamp->matrix = psImageAlloc(numParams, numParams, PS_TYPE_F64);
     
    941922}
    942923
    943 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels,
    944                                     const pmSubtractionEquationCalculationMode mode)
     924bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels)
    945925{
    946926    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
     
    953933    for (int i = 0; i < stamps->num; i++) {
    954934        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
     935
    955936        if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE) {
    956937            continue;
     
    969950            psArrayAdd(job->args, 1, (pmSubtractionKernels*)kernels); // Casting away const to put on array
    970951            PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32);
    971             PS_ARRAY_ADD_SCALAR(job->args, mode, PS_TYPE_S32);
    972952            if (!psThreadJobAddPending(job)) {
    973953                return false;
    974954            }
    975955        } else {
    976             pmSubtractionCalculateEquationStamp(stamps, kernels, i, mode);
     956            pmSubtractionCalculateEquationStamp(stamps, kernels, i);
    977957        }
    978958    }
     
    983963    }
    984964
    985     pmSubtractionVisualPlotLeastSquares(stamps);
    986965    pmSubtractionVisualShowKernels((pmSubtractionKernels  *)kernels);
    987966    pmSubtractionVisualShowBasis(stamps);
    988 
    989     psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate equation: %f sec",
    990              psTimerClear("pmSubtractionCalculateEquation"));
    991 
     967    pmSubtractionVisualPlotLeastSquares(stamps);
     968
     969    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate equation: %f sec", psTimerClear("pmSubtractionCalculateEquation"));
    992970
    993971    return true;
     
    998976bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header);
    999977
    1000 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U);
    1001 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt);
    1002 
    1003 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask);
    1004 
    1005 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B);
    1006 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB);
    1007 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB);
    1008 
    1009 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x);
    1010 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y);
    1011 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps);
    1012 
    1013 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w);
    1014 
    1015 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps);
    1016 
    1017 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels,
    1018                                 const pmSubtractionStampList *stamps,
    1019                                 const pmSubtractionEquationCalculationMode mode)
     978bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps)
    1020979{
    1021980    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false);
    1022981    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
     982
     983    psTimerStart("pmSubtractionSolveEquation");
    1023984
    1024985    // Check inputs
     
    10421003        }
    10431004
     1005        if (stamp->vector->n != numParams) {
     1006            fprintf (stderr, "mismatch length\n");
     1007        }
    10441008        PS_ASSERT_VECTOR_NON_NULL(stamp->vector, false);
    10451009        PS_ASSERT_VECTOR_SIZE(stamp->vector, (long)numParams, false);
     
    10801044        }
    10811045
     1046        pmSubtractionVisualPlotLeastSquaresResid(stamps, sumMatrix, numStamps);
     1047
    10821048#if 0
    10831049        psImage *save = psImageCopy(NULL, sumMatrix, PS_TYPE_F32);
     
    10871053#endif
    10881054
     1055        // XXX TEST : print the matrix & vector
     1056        if (0) {
     1057            for (int iy = 0; iy < sumMatrix->numRows; iy++) {
     1058                for (int ix = 0; ix < sumMatrix->numCols; ix++) {
     1059                    fprintf (stderr, "%e  ", sumMatrix->data.F64[iy][ix]);
     1060                }
     1061                fprintf (stderr, " : %e\n", sumVector->data.F64[iy]);
     1062            }
     1063        }
     1064
     1065        psImage *invMatrix = NULL;
    10891066        psVector *solution = NULL;                       // Solution to equation!
    10901067        solution = psVectorAlloc(numParams, PS_TYPE_F64);
     
    10941071        // solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN);
    10951072        // SINGLE solution
    1096         if (1) {
    1097             solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN);
    1098         } else {
    1099             psVector *PERM = NULL;
    1100             psImage *LU = psMatrixLUDecomposition(NULL, &PERM, sumMatrix);
    1101             solution = psMatrixLUSolution(solution, LU, sumVector, PERM);
    1102             psFree (LU);
    1103             psFree (PERM);
    1104         }
     1073# if (1)
     1074        solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, 1e-10);
     1075        invMatrix = psMatrixInvert(NULL, sumMatrix, NULL);
     1076# endif
     1077# if (0)
     1078        psMatrixLUSolve(sumMatrixLU, sumVector);
     1079        solution = psMemIncrRefCounter(sumVector);
     1080        invMatrix = psMemIncrRefCounter(sumMatrix);
     1081# endif
     1082# if (0)
     1083        psMatrixGJSolve(sumMatrix, sumVector);
     1084        invMatrix = psMemIncrRefCounter(sumMatrix);
     1085        solution = psMemIncrRefCounter(sumVector);
     1086# endif
    11051087
    11061088# if (0)
    11071089        for (int i = 0; i < solution->n; i++) {
    1108             psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Single solution %d: %lf\n", i, solution->data.F64[i]);
     1090            psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Single solution %d: %lf +/- %lf\n", i, solution->data.F64[i], sqrt(fabs(invMatrix->data.F64[i][i])));
    11091091        }
    11101092# endif
    11111093
    1112         if (!kernels->solution1) {
    1113             kernels->solution1 = psVectorAlloc(sumVector->n + 2, PS_TYPE_F64); // 1 for norm, 1 for bg
    1114             psVectorInit(kernels->solution1, 0.0);
    1115         }
     1094        // ensure we have a solution vector of the right size
     1095        kernels->solution1    = psVectorRecycle(kernels->solution1,    sumVector->n + 2, PS_TYPE_F64); // 1 for norm, 1 for bg
     1096        kernels->solution1err = psVectorRecycle(kernels->solution1err, sumVector->n + 2, PS_TYPE_F64); // 1 for norm, 1 for bg
     1097        psVectorInit(kernels->solution1, 0.0);
     1098        psVectorInit(kernels->solution1err, 0.0);
    11161099
    11171100        int numKernels = kernels->num;
    11181101        int spatialOrder = kernels->spatialOrder;       // Order of spatial variation
    11191102        int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms
     1103
    11201104        for (int i = 0; i < numKernels * numPoly; i++) {
    11211105            kernels->solution1->data.F64[i] = solution->data.F64[i];
     1106            kernels->solution1err->data.F64[i] = sqrt(invMatrix->data.F64[i][i]);
    11221107        }
    11231108
     
    11311116        psFree(sumVector);
    11321117        psFree(sumMatrix);
     1118        psFree(invMatrix);
    11331119
    11341120    } else {
     
    11601146        }
    11611147
     1148        pmSubtractionVisualPlotLeastSquaresResid(stamps, sumMatrix, numStamps);
     1149
    11621150#if 0
    11631151        psImage *save = psImageCopy(NULL, sumMatrix, PS_TYPE_F32);
     
    11711159        }
    11721160
     1161        // XXX TEST : print the matrix & vector
     1162        if (0) {
     1163            for (int iy = 0; iy < sumMatrix->numRows; iy++) {
     1164                for (int ix = 0; ix < sumMatrix->numCols; ix++) {
     1165                    fprintf (stderr, "%e  ", sumMatrix->data.F64[iy][ix]);
     1166                }
     1167                fprintf (stderr, " : %e\n", sumVector->data.F64[iy]);
     1168            }
     1169        }
     1170
     1171        psImage *invMatrix = NULL;
    11731172        psVector *solution = NULL;                       // Solution to equation!
    11741173        solution = psVectorAlloc(numParams, PS_TYPE_F64);
     
    11761175
    11771176        // DUAL solution
    1178         solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN);
     1177# if (1)
     1178        solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, 1e-10);
     1179        invMatrix = psMatrixInvert(NULL, sumMatrix, NULL);
     1180# endif
     1181# if (0)
     1182        psMatrixLUSolve(sumMatrix, sumVector);
     1183        solution = psMemIncrRefCounter(sumVector);
     1184        invMatrix = psMemIncrRefCounter(sumMatrix);
     1185# endif
    11791186
    11801187#if (0)
    11811188        for (int i = 0; i < solution->n; i++) {
    1182             fprintf(stderr, "Dual solution %d: %lf\n", i, solution->data.F64[i]);
     1189            fprintf(stderr, "Dual solution %d: %lf +/- %lf\n", i, solution->data.F64[i], sqrt(invMatrix->data.F64[i][i]));
    11831190        }
    11841191#endif
    11851192
    1186         if (!kernels->solution1) {
    1187             kernels->solution1 = psVectorAlloc(numSolution1 + 2, PS_TYPE_F64);
    1188             psVectorInit (kernels->solution1, 0.0);
    1189         }
    1190         if (!kernels->solution2) {
    1191             kernels->solution2 = psVectorAlloc(numSolution2, PS_TYPE_F64);
    1192             psVectorInit (kernels->solution2, 0.0);
    1193         }
     1193        // XXX TEST: manually set the coeffs to a desired solution
     1194        // solution->data.F64[0] = +1.826;
     1195        // solution->data.F64[1] = -0.115;
     1196        // solution->data.F64[2] =  0.0;
     1197        // solution->data.F64[3] =  0.0;
     1198
     1199        // ensure we have solution vectors of the right size
     1200        kernels->solution1    = psVectorRecycle(kernels->solution1,    numSolution1 + 2, PS_TYPE_F64); // 1 for norm, 1 for bg
     1201        kernels->solution1err = psVectorRecycle(kernels->solution1err, numSolution1 + 2, PS_TYPE_F64); // 1 for norm, 1 for bg
     1202        kernels->solution2    = psVectorRecycle(kernels->solution2,    numSolution2,     PS_TYPE_F64); // 1 for norm, 1 for bg
     1203        kernels->solution2err = psVectorRecycle(kernels->solution2err, numSolution2,     PS_TYPE_F64); // 1 for norm, 1 for bg
     1204
     1205        psVectorInit(kernels->solution1, 0.0);
     1206        psVectorInit(kernels->solution1err, 0.0);
     1207        psVectorInit(kernels->solution2, 0.0);
     1208        psVectorInit(kernels->solution2err, 0.0);
    11941209
    11951210        // for DUAL convolution analysis, we apply the normalization to I1 as follows:
     
    12051220            kernels->solution1->data.F64[i] = solution->data.F64[i] * stamps->normValue;
    12061221            kernels->solution2->data.F64[i] = solution->data.F64[i + numSolution1];
     1222
     1223            kernels->solution1err->data.F64[i] = sqrt(invMatrix->data.F64[i][i]) * stamps->normValue;
     1224            int i2 = i + numSolution1;
     1225            kernels->solution2err->data.F64[i] = sqrt(invMatrix->data.F64[i2][i2]);
    12071226        }
    12081227
     
    12131232        kernels->solution1->data.F64[bgIndex] = 0.0;
    12141233
     1234        psFree(solution);
     1235        psFree(sumVector);
    12151236        psFree(sumMatrix);
    1216         psFree(sumVector);
    1217         psFree(solution);
     1237        psFree(invMatrix);
    12181238    }
    12191239
     
    12241244    if (psTraceGetLevel("psModules.imcombine") >= 7) {
    12251245        for (int i = 0; i < kernels->solution1->n; i++) {
    1226             psTrace("psModules.imcombine", 7, "Solution 1 %d: %f\n", i, kernels->solution1->data.F64[i]);
     1246            psTrace("psModules.imcombine", 7, "Solution 1 %d: %f +/- %f\n", i, kernels->solution1->data.F64[i], kernels->solution1err->data.F64[i]);
    12271247        }
    12281248        if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
    12291249            for (int i = 0; i < kernels->solution2->n; i++) {
    1230                 psTrace("psModules.imcombine", 7, "Solution 2 %d: %f\n", i, kernels->solution2->data.F64[i]);
     1250                psTrace("psModules.imcombine", 7, "Solution 2 %d: %f +/- %f\n", i, kernels->solution2->data.F64[i], kernels->solution2err->data.F64[i]);
    12311251            }
    12321252        }
    12331253     }
     1254
     1255    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Solve equation: %f sec", psTimerClear("pmSubtractionSolveEquation"));
    12341256
    12351257    // pmSubtractionVisualPlotLeastSquares((pmSubtractionStampList *) stamps); //casting away const
     
    12831305}
    12841306
    1285 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps,
    1286                                            pmSubtractionKernels *kernels)
     1307// given the convolved image(s) and the residual image, calculate the second moment(s) and the chisq
     1308bool pmSubtractionChisqStats(psVector *fluxesVector, psVector *chisqDVector, psVector *chisqRVector, psVector *momentVector, psVector *stampMask, psKernel *convolved1, psKernel *convolved2, psKernel *difference, psKernel *residual, psKernel *weight, psKernel *window) {
     1309
     1310# ifndef USE_WEIGHT
     1311    psAssert(weight == NULL, "impossible!");
     1312# endif
     1313# ifndef USE_WINDOW
     1314    psAssert(window == NULL, "impossible!");
     1315# endif
     1316
     1317    int npix = 0;
     1318    float chisqR = 0;
     1319    float chisqD = 0;
     1320
     1321    // get the chisq
     1322    for (int y = residual->yMin; y <= residual->yMax; y++) {
     1323        for (int x = residual->xMin; x <= residual->xMax; x++) {
     1324            float valueR = PS_SQR(residual->kernel[y][x]);
     1325            if (weight) {
     1326                valueR *= weight->kernel[y][x];
     1327            }
     1328            // XXX NOTE: do NOT apply the window to the chisq portions of the calculation (that would bias the chisq)
     1329            chisqR += valueR;
     1330
     1331            float valueD = PS_SQR(difference->kernel[y][x]);
     1332            if (weight) {
     1333                valueD *= weight->kernel[y][x];
     1334            }
     1335            chisqD += valueD;
     1336            npix ++;
     1337        }
     1338    }
     1339    psVectorAppend(chisqRVector, chisqR / npix);
     1340    psVectorAppend(chisqDVector, chisqD / npix);
     1341
     1342    float value1 = 0;
     1343    float value2 = 0;
     1344    float flux2 = 0;
     1345    float fluxX = 0;
     1346    float fluxY = 0;
     1347    float fluxX2 = 0;
     1348    float fluxY2 = 0;
     1349
     1350    float fluxC1 = 0;
     1351    float fluxC2 = 0;
     1352
     1353    float moment = 0;
     1354
     1355    // get the moments from convolved1
     1356    if (convolved1) {
     1357        for (int y = residual->yMin; y <= residual->yMax; y++) {
     1358            for (int x = residual->xMin; x <= residual->xMax; x++) {
     1359                value1  = convolved1->kernel[y][x];
     1360                value2  = PS_SQR(value1);
     1361
     1362                if (window) {
     1363                    value1 *= window->kernel[y][x];
     1364                    value2 *= window->kernel[y][x];
     1365                }
     1366
     1367                fluxC1 += value1;
     1368                flux2  += value2;
     1369                fluxX  += x * value2;
     1370                fluxY  += y * value2;
     1371                // fluxX2 += PS_SQR(x) * value2;
     1372                // fluxY2 += PS_SQR(y) * value2;
     1373                fluxX2 += PS_SQR(x) * value1;
     1374                fluxY2 += PS_SQR(y) * value1;
     1375            }
     1376        }
     1377        // float Mx = fluxX / flux2;
     1378        // float My = fluxY / flux2;
     1379        // float Mxx = fluxX2 / flux2;
     1380        // float Myy = fluxY2 / flux2;
     1381        float Mxx = fluxX2 / fluxC1;
     1382        float Myy = fluxY2 / fluxC1;
     1383
     1384        // fprintf (stderr, "conv1, flux2: %f, Mx: %f, My: %f, Mxx: %f, Myy: %f, chisq: %f, npix: %d\n", flux2, Mx, My, Mxx, Myy, chisq, npix);
     1385        moment += Mxx + Myy;
     1386    }
     1387
     1388    // get the moments from convolved1
     1389    if (convolved2) {
     1390        for (int y = residual->yMin; y <= residual->yMax; y++) {
     1391            for (int x = residual->xMin; x <= residual->xMax; x++) {
     1392                value1  = convolved2->kernel[y][x];
     1393                value2  = PS_SQR(value1);
     1394
     1395                // XXX NOTE: do NOT apply the weight to the moments calculation
     1396                if (false && weight) {
     1397                    value2 *= weight->kernel[y][x];
     1398                }
     1399                if (window) {
     1400                    value1 *= window->kernel[y][x];
     1401                    value2 *= window->kernel[y][x];
     1402                }
     1403
     1404                fluxC2 += value1;
     1405                flux2  += value2;
     1406                fluxX  += x * value2;
     1407                fluxY  += y * value2;
     1408                // fluxX2 += PS_SQR(x) * value2;
     1409                // fluxY2 += PS_SQR(y) * value2;
     1410                fluxX2 += PS_SQR(x) * value1;
     1411                fluxY2 += PS_SQR(y) * value1;
     1412            }
     1413        }
     1414        // float Mx = fluxX / flux2;
     1415        // float My = fluxY / flux2;
     1416        // float Mxx = fluxX2 / flux2;
     1417        // float Myy = fluxY2 / flux2;
     1418        float Mxx = fluxX2 / fluxC2;
     1419        float Myy = fluxY2 / fluxC2;
     1420
     1421        // fprintf (stderr, "conv2, flux2: %f, Mx: %f, My: %f, Mxx: %f, Myy: %f, chisq: %f, npix: %d\n", flux2, Mx, My, Mxx, Myy, chisq, npix);
     1422        moment += Mxx + Myy;
     1423    }
     1424
     1425    float flux = fluxC1 + fluxC2;
     1426   
     1427    if (convolved1 && convolved2) {
     1428        moment *= 0.5;
     1429        flux *= 0.5;
     1430    }
     1431    psVectorAppend(momentVector, moment);
     1432    psVectorAppend(fluxesVector, flux);
     1433
     1434    // check that the last appended values are ok:
     1435    int Nelem = fluxesVector->n - 1;
     1436    bool valid = true;
     1437    valid &= isfinite(chisqRVector->data.F32[Nelem]);
     1438    valid &= isfinite(fluxesVector->data.F32[Nelem]);
     1439    valid &= isfinite(momentVector->data.F32[Nelem]);
     1440    if (valid) {
     1441      psVectorAppend(stampMask, 0);
     1442    } else {
     1443      psVectorAppend(stampMask, 0x02);
     1444    }
     1445    return true;
     1446}
     1447
     1448bool pmSubtractionCalculateChisqAndMoments(pmSubtractionQuality **bestMatch,
     1449                                           pmSubtractionStampList *stamps,
     1450                                           pmSubtractionKernels *kernels)
    12871451{
    12881452    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL);
    12891453    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, NULL);
    12901454    PM_ASSERT_SUBTRACTION_KERNELS_SOLUTION(kernels, NULL);
     1455
     1456    psTimerStart("pmSubtractionCalculateChisqAndMoments");
     1457
     1458    // XXX need to save these somewhere
     1459    psVector *fluxes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32);
     1460    psVector *chisqD = psVectorAllocEmpty(stamps->num, PS_TYPE_F32);
     1461    psVector *chisqR = psVectorAllocEmpty(stamps->num, PS_TYPE_F32);
     1462    psVector *moments = psVectorAllocEmpty(stamps->num, PS_TYPE_F32);
     1463    psVector *stampMask = psVectorAllocEmpty(stamps->num, PS_TYPE_VECTOR_MASK);
     1464
     1465    int footprint = stamps->footprint; // Half-size of stamps
     1466    int numKernels = kernels->num;      // Number of kernels
     1467
     1468    psImage *polyValues = NULL;         // Polynomial values
     1469
     1470    // storage for the image (convolved2 is not used in SINGLE mode)
     1471    psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image
     1472    psKernel *difference = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image
     1473    psKernel *convolved1 = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image
     1474    psKernel *convolved2 = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image
     1475
     1476    int nGood = 0;
     1477    for (int i = 0; i < stamps->num; i++) {
     1478        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest
     1479        if (stamp->status != PM_SUBTRACTION_STAMP_USED) {
     1480            // mark this stamp as unused (note that we have to append NANs to the other vectors to keep the lengths in sync)
     1481            psVectorAppend(moments, NAN);
     1482            psVectorAppend(fluxes, NAN);
     1483            psVectorAppend(chisqD, NAN);
     1484            psVectorAppend(chisqR, NAN);
     1485            psVectorAppend(stampMask, 0x01);
     1486            continue;
     1487        }
     1488        nGood ++;
     1489
     1490        // Calculate coefficients of the kernel basis functions
     1491        polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm);
     1492        double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation
     1493        double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background
     1494
     1495        // Calculate residuals
     1496        psImageInit(residual->image, 0.0);
     1497        psImageInit(difference->image, 0.0);
     1498
     1499        psKernel *weight = NULL;
     1500        psKernel *window = NULL;
     1501   
     1502#ifdef USE_WEIGHT
     1503    weight = stamp->weight;
     1504#endif
     1505#ifdef USE_WINDOW
     1506    window = stamps->window;
     1507#endif
     1508
     1509        if (kernels->mode != PM_SUBTRACTION_MODE_DUAL) {
     1510
     1511            // the single-direction psf match code attempts to find the kernel such that:
     1512            // source * kernel = target.  we need to assign 'source' and 'target' correctly
     1513            // depending on which of image1 or image2 we asked to be convolved.
     1514
     1515            psKernel *target;           // Target postage stamp (convolve source to match the target)
     1516            psKernel *source;           // Source postage stamp (convolve source to match the target)
     1517            psArray *convolutions;      // Convolution postage stamps for each kernel basis function
     1518
     1519            // init the accumulation image
     1520            psImageInit(convolved1->image, 0.0);
     1521
     1522            switch (kernels->mode) {
     1523              case PM_SUBTRACTION_MODE_1:
     1524                target = stamp->image2;
     1525                source = stamp->image1;
     1526                convolutions = stamp->convolutions1;
     1527                break;
     1528              case PM_SUBTRACTION_MODE_2:
     1529                target = stamp->image1;
     1530                source = stamp->image2;
     1531                convolutions = stamp->convolutions2;
     1532                break;
     1533              default:
     1534                psAbort("Unsupported subtraction mode: %x", kernels->mode);
     1535            }
     1536
     1537            // generate the convolved source image (sum over kernels)
     1538            for (int j = 0; j < numKernels; j++) {
     1539                psKernel *convolution = convolutions->data[j]; // Convolution
     1540                double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient
     1541                for (int y = - footprint; y <= footprint; y++) {
     1542                    for (int x = - footprint; x <= footprint; x++) {
     1543                        convolved1->kernel[y][x] += convolution->kernel[y][x] * coefficient;
     1544                    }
     1545                }
     1546            }
     1547
     1548            // Generate the difference, residual, and convolved source images.  Note the we
     1549            // accumulate the convolution of (A-B), so we need to replace it to generate the
     1550            // images of the convolved source image.
     1551            for (int y = - footprint; y <= footprint; y++) {
     1552                for (int x = - footprint; x <= footprint; x++) {
     1553                    difference->kernel[y][x] = target->kernel[y][x] - source->kernel[y][x] * norm - background;
     1554                    residual->kernel[y][x] = difference->kernel[y][x] - convolved1->kernel[y][x];
     1555                    convolved1->kernel[y][x] += source->kernel[y][x] * norm;
     1556                }
     1557            }
     1558
     1559            // XXX if we want to have a weight and window, we'll need to pass through to here
     1560            pmSubtractionChisqStats(fluxes, chisqD, chisqR, moments, stampMask, convolved1, NULL, difference, residual, weight, window);
     1561
     1562        } else {
     1563
     1564            // Dual convolution
     1565            psArray *convolutions1 = stamp->convolutions1; // Convolutions of the first image
     1566            psArray *convolutions2 = stamp->convolutions2; // Convolutions of the second image
     1567            psKernel *image1 = stamp->image1; // The first image
     1568            psKernel *image2 = stamp->image2; // The second image
     1569
     1570            // init the accumulation images
     1571            psImageInit(convolved1->image, 0.0);
     1572            psImageInit(convolved2->image, 0.0);
     1573
     1574            for (int j = 0; j < numKernels; j++) {
     1575                psKernel *conv1 = convolutions1->data[j]; // Convolution of first image
     1576                psKernel *conv2 = convolutions2->data[j]; // Convolution of second image
     1577                double coeff1 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1
     1578                double coeff2 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, true); // Coefficient 2
     1579
     1580                for (int y = - footprint; y <= footprint; y++) {
     1581                    for (int x = - footprint; x <= footprint; x++) {
     1582                        // NOTE sign for coeff2
     1583                        convolved1->kernel[y][x] += +conv1->kernel[y][x] * coeff1;
     1584                        convolved2->kernel[y][x] += -conv2->kernel[y][x] * coeff2;
     1585                    }
     1586                }
     1587            }
     1588
     1589            // Generate the difference, residual, and convolved source images.  Note the we
     1590            // accumulate the convolutions of (A-B), so we need to replace (A or B) to generate
     1591            // the images of the convolved source images.
     1592            for (int y = - footprint; y <= footprint; y++) {
     1593                for (int x = - footprint; x <= footprint; x++) {
     1594                    difference->kernel[y][x] = image2->kernel[y][x] - image1->kernel[y][x] * norm - background;
     1595                    residual->kernel[y][x] = difference->kernel[y][x] + convolved2->kernel[y][x] - convolved1->kernel[y][x];
     1596                    convolved1->kernel[y][x] += image1->kernel[y][x] * norm;
     1597                    convolved2->kernel[y][x] += image2->kernel[y][x];
     1598                }
     1599            }
     1600
     1601            if (0) {
     1602                psFitsWriteImageSimple("conv1.fits", convolved1->image, NULL);
     1603                psFitsWriteImageSimple("conv2.fits", convolved2->image, NULL);
     1604                psFitsWriteImageSimple("resid.fits", residual->image,   NULL);
     1605                pmVisualAskUser(NULL);
     1606            }
     1607
     1608            pmSubtractionChisqStats(fluxes, chisqD, chisqR, moments, stampMask, convolved1, convolved2, difference, residual, weight, window);
     1609        }
     1610    }
     1611
     1612    // find the mean chisq and mean moment
     1613    psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
     1614    psVectorStats (stats, chisqD, NULL, stampMask, 0xff);
     1615    float chisqDValue = stats->sampleMean;
     1616
     1617    psStatsInit(stats);
     1618    psVectorStats (stats, chisqR, NULL, stampMask, 0xff);
     1619    float chisqRValue = stats->sampleMean;
     1620
     1621    psStatsInit(stats);
     1622    psVectorStats (stats, moments, NULL, stampMask, 0xff);
     1623    float momentValue = stats->sampleMean;
     1624
     1625    double sumKernel1 = 0.0, sumKernel2 = 0.0; // Sum of the kernel
     1626
     1627    // calculate the variance contribution from this smoothing kernel
     1628    psKernel *modelKernel = pmSubtractionKernel(kernels, 0.0, 0.0, false);
     1629    for (int y = modelKernel->yMin; y <= modelKernel->yMax; y++) {
     1630        for (int x = modelKernel->xMin; x <= modelKernel->xMax; x++) {
     1631            if (!isfinite(modelKernel->kernel[y][x])) {
     1632                psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Non-finite covariance matrix element in kernel at %d,%d", x, y);
     1633                return NULL;
     1634            }
     1635            sumKernel1 += PS_SQR(modelKernel->kernel[y][x]);
     1636        }
     1637    }
     1638    psFree (modelKernel);
     1639
     1640    if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
     1641        psKernel *modelKernel = pmSubtractionKernel(kernels, 0.0, 0.0, true);
     1642        for (int y = modelKernel->yMin; y <= modelKernel->yMax; y++) {
     1643            for (int x = modelKernel->xMin; x <= modelKernel->xMax; x++) {
     1644                if (!isfinite(modelKernel->kernel[y][x])) {
     1645                    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Non-finite covariance matrix element in kernel at %d,%d", x, y);
     1646                    return NULL;
     1647                }
     1648                sumKernel2 += PS_SQR(modelKernel->kernel[y][x]);
     1649            }
     1650        }
     1651        psFree (modelKernel);
     1652    } else {
     1653        sumKernel2 = 1.0;
     1654    }
     1655
     1656    // if we modify the chisq value by the (sumKernel1 + sumKernel2), we account for the
     1657    // smoothing coming from larger kernels adding additional spatial fit terms should be
     1658    // penalized by increasing the score somewhat.  the 0.01 value is not well-chosen.
     1659    float orderFactor = 0.01 * kernels->spatialOrder;
     1660    float score = 2.0 * chisqRValue / (sumKernel1 + sumKernel2) + orderFactor;
     1661    psLogMsg("psModules.imcombine", PS_LOG_INFO, "chisq: %6.3f, chisqD: %6.3f, moment: %6.3f, sumKernel_1: %6.3f, sumKernel_2, score: %6.3f: %6.3f\n", chisqRValue, chisqDValue, momentValue, sumKernel1, sumKernel2, score);
     1662
     1663    // save this result if it is the first or the best (skip if bestMatch is NULL)
     1664    if (bestMatch) {
     1665        pmSubtractionQuality *match = *bestMatch;
     1666        bool keep = false;
     1667        if (match == NULL) {
     1668            *bestMatch = match = pmSubtractionQualityAlloc();
     1669            keep = true;
     1670        } else {
     1671            if (score < match->score) {
     1672                psFree(match->fluxes);
     1673                psFree(match->chisq);
     1674                psFree(match->moments);
     1675                psFree(match->stampMask);
     1676                keep = true;
     1677            }
     1678        }
     1679        if (keep) {
     1680            psLogMsg("psModules.imcombine", PS_LOG_INFO, "keeping order: %d, mode: %d, score: %f\n", kernels->spatialOrder, kernels->mode, score);
     1681            match->score        = score;
     1682            match->spatialOrder = kernels->spatialOrder;
     1683            match->mode         = kernels->mode;
     1684            match->nGood        = nGood;
     1685            match->fluxes       = psMemIncrRefCounter(fluxes);
     1686            match->chisq        = psMemIncrRefCounter(chisqR);
     1687            match->moments      = psMemIncrRefCounter(moments);
     1688            match->stampMask    = psMemIncrRefCounter(stampMask);
     1689        }           
     1690    }
     1691
     1692    pmSubtractionVisualPlotChisqAndMoments(fluxes, chisqR, moments);
     1693
     1694    psFree(stats);
     1695    psFree(chisqR);
     1696    psFree(chisqD);
     1697    psFree(fluxes);
     1698    psFree(moments);
     1699    psFree(stampMask);
     1700
     1701    psFree(residual);
     1702    psFree(difference);
     1703    psFree(convolved1);
     1704    psFree(convolved2);
     1705    psFree(polyValues);
     1706
     1707    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate Chisq and Moments: %f sec", psTimerClear("pmSubtractionCalculateChisqAndMoments"));
     1708
     1709    return true;
     1710}
     1711
     1712// XXX for now, let's not use this, and let's instead just use values from pmSubtractionCalculateChisqAndMoments
     1713psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels)
     1714{
     1715    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL);
     1716    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, NULL);
     1717    PM_ASSERT_SUBTRACTION_KERNELS_SOLUTION(kernels, NULL);
     1718
     1719    psTimerStart("pmSubtractionCalculateDeviations");
    12911720
    12921721    psVector *deviations = psVectorAlloc(stamps->num, PS_TYPE_F32); // Mean deviation for stamps
     
    12981727    psImage *polyValues = NULL;         // Polynomial values
    12991728    psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image
    1300 
    1301     // set up holding images for the visualization
    1302     pmSubtractionVisualShowFitInit (stamps);
    13031729
    13041730    psVector *fResSigma = psVectorAllocEmpty(stamps->num, PS_TYPE_F32);
     
    14011827            }
    14021828
    1403             // XXX visualize the target, source, convolution and residual
    1404             pmSubtractionVisualShowFitAddStamp (target, source, residual, background, norm, i);
    1405 
    14061829            for (int y = - footprint; y <= footprint; y++) {
    14071830                for (int x = - footprint; x <= footprint; x++) {
     
    14381861            }
    14391862
    1440             // XXX visualize the target, source, convolution and residual
    1441             pmSubtractionVisualShowFitAddStamp (image2, image1, residual, background, norm, i);
    1442 
    14431863            for (int y = - footprint; y <= footprint; y++) {
    14441864                for (int x = - footprint; x <= footprint; x++) {
     
    14551875        }
    14561876
     1877        double flux = 0.0;
    14571878        double deviation = 0.0;         // Sum of differences
    14581879        for (int y = - footprint; y <= footprint; y++) {
     
    14601881                double dev = PS_SQR(residual->kernel[y][x]) * weight->kernel[y][x];
    14611882                deviation += dev;
    1462 #ifdef TESTING
    1463                 residual->kernel[y][x] = dev;
    1464 #endif
     1883                flux += stamp->image1->kernel[y][x] + stamp->image2->kernel[y][x];
    14651884            }
    14661885        }
    14671886        deviations->data.F32[i] = devNorm * deviation;
    1468         psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n",
    1469                 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]);
     1887        psTrace("psModules.imcombine", 5, "Deviation and Flux for stamp %d (%d,%d): %f %f\n",
     1888                i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i], flux);
    14701889        psStringAppend(&log, "Stamp %d (%d,%d): %f\n",
    14711890                       i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]);
    14721891        if (!isfinite(deviations->data.F32[i])) {
    14731892            stamp->status = PM_SUBTRACTION_STAMP_REJECTED;
    1474             psTrace("psModules.imcombine", 5,
    1475                     "Rejecting stamp %d (%d,%d) because of non-finite deviation\n",
    1476                     i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5));
     1893            psTrace("psModules.imcombine", 5, "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5));
    14771894            continue;
    14781895        }
    1479 
    1480 #ifdef TESTING
    1481         {
    1482             psString filename = NULL;
    1483             psStringAppend(&filename, "resid_%03d.fits", i);
    1484             psFits *fits = psFitsOpen(filename, "w");
    1485             psFree(filename);
    1486             psFitsWriteImage(fits, NULL, residual->image, 0, NULL);
    1487             psFitsClose(fits);
    1488         }
    1489         if (stamp->image1) {
    1490             psString filename = NULL;
    1491             psStringAppend(&filename, "stamp_image1_%03d.fits", i);
    1492             psFits *fits = psFitsOpen(filename, "w");
    1493             psFree(filename);
    1494             psFitsWriteImage(fits, NULL, stamp->image1->image, 0, NULL);
    1495             psFitsClose(fits);
    1496         }
    1497         if (stamp->image2) {
    1498             psString filename = NULL;
    1499             psStringAppend(&filename, "stamp_image2_%03d.fits", i);
    1500             psFits *fits = psFitsOpen(filename, "w");
    1501             psFree(filename);
    1502             psFitsWriteImage(fits, NULL, stamp->image2->image, 0, NULL);
    1503             psFitsClose(fits);
    1504         }
    1505         if (stamp->weight) {
    1506             psString filename = NULL;
    1507             psStringAppend(&filename, "stamp_weight_%03d.fits", i);
    1508             psFits *fits = psFitsOpen(filename, "w");
    1509             psFree(filename);
    1510             psFitsWriteImage(fits, NULL, stamp->weight->image, 0, NULL);
    1511             psFitsClose(fits);
    1512         }
    1513 #endif
    1514 
    15151896    }
    15161897
    15171898    psFree(keepStamps);
    15181899
    1519     psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "%s", log);
     1900    psLogMsg("psModules.imcombine", PS_LOG_MINUTIA, "%s", log);
    15201901    psFree(log);
    15211902
     
    15271908        psLogMsg("psModules.imcombine", PS_LOG_INFO, "normalization: %f, background: %f", norm, background);
    15281909
    1529         pmSubtractionVisualShowFit(norm);
    1530         pmSubtractionVisualPlotFit(kernels);
    1531 
    15321910        psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
    15331911        psVectorStats (stats, fResSigma, NULL, NULL, 0);
     
    15601938    psFree(polyValues);
    15611939
     1940    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate Deviations: %f sec", psTimerClear("pmSubtractionCalculateDeviations"));
     1941
    15621942    return deviations;
    1563 }
    1564 
    1565 // we are supplied U, not Ut; w represents a diagonal matrix (also, we apply 1/w instead of w)
    1566 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U) {
    1567 
    1568     psAssert (w->n == U->numCols, "w and U dimensions do not match");
    1569 
    1570     // wUt has dimensions transposed relative to Ut.
    1571     psImage *wUt = psImageAlloc (U->numRows, U->numCols, PS_TYPE_F64);
    1572     psImageInit (wUt, 0.0);
    1573 
    1574     for (int i = 0; i < wUt->numCols; i++) {
    1575         for (int j = 0; j < wUt->numRows; j++) {
    1576             if (!isfinite(w->data.F64[j])) continue;
    1577             if (w->data.F64[j] == 0.0) continue;
    1578             wUt->data.F64[j][i] = U->data.F64[i][j] / w->data.F64[j];
    1579         }
    1580     }
    1581     return wUt;
    1582 }
    1583 
    1584 // XXX this is just standard matrix multiplication: use psMatrixMultiply?
    1585 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt) {
    1586 
    1587     psAssert (V->numCols == wUt->numRows, "matrix dimensions do not match");
    1588 
    1589     psImage *Ainv = psImageAlloc (wUt->numCols, V->numRows, PS_TYPE_F64);
    1590 
    1591     for (int i = 0; i < Ainv->numCols; i++) {
    1592         for (int j = 0; j < Ainv->numRows; j++) {
    1593             double sum = 0.0;
    1594             for (int k = 0; k < V->numCols; k++) {
    1595                 sum += V->data.F64[j][k] * wUt->data.F64[k][i];
    1596             }
    1597             Ainv->data.F64[j][i] = sum;
    1598         }
    1599     }
    1600     return Ainv;
    1601 }
    1602 
    1603 // we are supplied U, not Ut
    1604 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B) {
    1605 
    1606     psAssert (U->numRows == B->n, "U and B dimensions do not match");
    1607 
    1608     UtB[0] = psVectorRecycle (UtB[0], U->numCols, PS_TYPE_F64);
    1609 
    1610     for (int i = 0; i < U->numCols; i++) {
    1611         double sum = 0.0;
    1612         for (int j = 0; j < U->numRows; j++) {
    1613             sum += B->data.F64[j] * U->data.F64[j][i];
    1614         }
    1615         UtB[0]->data.F64[i] = sum;
    1616     }
    1617     return true;
    1618 }
    1619 
    1620 // w is diagonal
    1621 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB) {
    1622 
    1623     psAssert (w->n == UtB->n, "w and UtB dimensions do not match");
    1624 
    1625     // wUt has dimensions transposed relative to Ut.
    1626     wUtB[0] = psVectorRecycle (wUtB[0], w->n, PS_TYPE_F64);
    1627     psVectorInit (wUtB[0], 0.0);
    1628 
    1629     for (int i = 0; i < w->n; i++) {
    1630         if (!isfinite(w->data.F64[i])) continue;
    1631         if (w->data.F64[i] == 0.0) continue;
    1632         wUtB[0]->data.F64[i] = UtB->data.F64[i] / w->data.F64[i];
    1633     }
    1634     return true;
    1635 }
    1636 
    1637 // this is basically matrix * vector
    1638 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB) {
    1639 
    1640     psAssert (V->numCols == wUtB->n, "V and wUtB dimensions do not match");
    1641 
    1642     VwUtB[0] = psVectorRecycle (*VwUtB, V->numRows, PS_TYPE_F64);
    1643 
    1644     for (int j = 0; j < V->numRows; j++) {
    1645         double sum = 0.0;
    1646         for (int i = 0; i < V->numCols; i++) {
    1647             sum += V->data.F64[j][i] * wUtB->data.F64[i];
    1648         }
    1649         VwUtB[0]->data.F64[j] = sum;
    1650     }
    1651     return true;
    1652 }
    1653 
    1654 // this is basically matrix * vector
    1655 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x) {
    1656 
    1657     psAssert (A->numCols == x->n, "A and x dimensions do not match");
    1658 
    1659     B[0] = psVectorRecycle (*B, A->numRows, PS_TYPE_F64);
    1660 
    1661     for (int j = 0; j < A->numRows; j++) {
    1662         double sum = 0.0;
    1663         for (int i = 0; i < A->numCols; i++) {
    1664             sum += A->data.F64[j][i] * x->data.F64[i];
    1665         }
    1666         B[0]->data.F64[j] = sum;
    1667     }
    1668     return true;
    1669 }
    1670 
    1671 // this is basically Vector * vector
    1672 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y) {
    1673 
    1674     psAssert (x->n == y->n, "x and y dimensions do not match");
    1675 
    1676     double sum = 0.0;
    1677     for (int i = 0; i < x->n; i++) {
    1678         sum += x->data.F64[i] * y->data.F64[i];
    1679     }
    1680     *value = sum;
    1681     return true;
    1682 }
    1683 
    1684 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) {
    1685 
    1686     int footprint = stamps->footprint; // Half-size of stamps
    1687 
    1688     double sum = 0.0;
    1689     for (int i = 0; i < stamps->num; i++) {
    1690 
    1691         pmSubtractionStamp *stamp = stamps->stamps->data[i];
    1692         if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue;
    1693 
    1694         psKernel *weight = NULL;
    1695         psKernel *window = NULL;
    1696         psKernel *input = NULL;
    1697 
    1698 #ifdef USE_WEIGHT
    1699         weight = stamp->weight;
    1700 #endif
    1701 #ifdef USE_WINDOW
    1702         window = stamps->window;
    1703 #endif
    1704 
    1705         switch (kernels->mode) {
    1706             // MODE_1 : convolve image 1 to match image 2 (and vice versa)
    1707           case PM_SUBTRACTION_MODE_1:
    1708             input = stamp->image2;
    1709             break;
    1710           case PM_SUBTRACTION_MODE_2:
    1711             input = stamp->image1;
    1712             break;
    1713           default:
    1714             psAbort ("programming error");
    1715         }
    1716 
    1717         for (int y = - footprint; y <= footprint; y++) {
    1718             for (int x = - footprint; x <= footprint; x++) {
    1719                 double in = input->kernel[y][x];
    1720                 double value = in*in;
    1721                 if (weight) {
    1722                     float wtVal = weight->kernel[y][x];
    1723                     value *= wtVal;
    1724                 }
    1725                 if (window) {
    1726                     float  winVal = window->kernel[y][x];
    1727                     value *= winVal;
    1728                 }
    1729                 sum += value;
    1730             }
    1731         }
    1732     }
    1733     *y2 = sum;
    1734     return true;
    1735 }
    1736 
    1737 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) {
    1738 
    1739     int footprint = stamps->footprint; // Half-size of stamps
    1740     int numKernels = kernels->num;      // Number of kernels
    1741 
    1742     double sum = 0.0;
    1743 
    1744     psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image
    1745     psImageInit(residual->image, 0.0);
    1746 
    1747     psImage *polyValues = NULL;         // Polynomial values
    1748 
    1749     for (int i = 0; i < stamps->num; i++) {
    1750 
    1751         pmSubtractionStamp *stamp = stamps->stamps->data[i];
    1752         if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue;
    1753 
    1754         psKernel *weight = NULL;
    1755         psKernel *window = NULL;
    1756         psKernel *target = NULL;
    1757         psKernel *source = NULL;
    1758 
    1759         psArray *convolutions = NULL;
    1760 
    1761 #ifdef USE_WEIGHT
    1762         weight = stamp->weight;
    1763 #endif
    1764 #ifdef USE_WINDOW
    1765         window = stamps->window;
    1766 #endif
    1767 
    1768         switch (kernels->mode) {
    1769             // MODE_1 : convolve image 1 to match image 2 (and vice versa)
    1770           case PM_SUBTRACTION_MODE_1:
    1771             target = stamp->image2;
    1772             source = stamp->image1;
    1773             convolutions = stamp->convolutions1;
    1774             break;
    1775           case PM_SUBTRACTION_MODE_2:
    1776             target = stamp->image1;
    1777             source = stamp->image2;
    1778             convolutions = stamp->convolutions2;
    1779             break;
    1780           default:
    1781             psAbort ("programming error");
    1782         }
    1783 
    1784         // Calculate coefficients of the kernel basis functions
    1785         polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm);
    1786         double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation
    1787         double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background
    1788 
    1789         psImageInit(residual->image, 0.0);
    1790         for (int j = 0; j < numKernels; j++) {
    1791             psKernel *convolution = convolutions->data[j]; // Convolution
    1792             double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient
    1793             for (int y = - footprint; y <= footprint; y++) {
    1794                 for (int x = - footprint; x <= footprint; x++) {
    1795                     residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient;
    1796                 }
    1797             }
    1798         }
    1799 
    1800         for (int y = - footprint; y <= footprint; y++) {
    1801             for (int x = - footprint; x <= footprint; x++) {
    1802                 double resid = target->kernel[y][x] - background - source->kernel[y][x] * norm + residual->kernel[y][x];
    1803                 double value = PS_SQR(resid);
    1804                 if (weight) {
    1805                     float wtVal = weight->kernel[y][x];
    1806                     value *= wtVal;
    1807                 }
    1808                 if (window) {
    1809                     float  winVal = window->kernel[y][x];
    1810                     value *= winVal;
    1811                 }
    1812                 sum += value;
    1813             }
    1814         }
    1815     }
    1816     psFree (polyValues);
    1817     psFree (residual);
    1818 
    1819     return sum;
    1820 }
    1821 
    1822 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask) {
    1823 
    1824     for (int i = 0; i < w->n; i++) {
    1825         wApply->data.F64[i] = wMask->data.U8[i] ? 0.0 : w->data.F64[i];
    1826     }
    1827     return true;
    1828 }
    1829 
    1830 // we are supplied V and w; w represents a diagonal matrix (also, we apply 1/w instead of w)
    1831 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w) {
    1832 
    1833     psAssert (w->n == V->numCols, "w and U dimensions do not match");
    1834 
    1835     psImage *Vn = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64);
    1836     psImageInit (Vn, 0.0);
    1837 
    1838     // generate Vn = V * w^{-1}
    1839     for (int j = 0; j < Vn->numRows; j++) {
    1840         for (int i = 0; i < Vn->numCols; i++) {
    1841             if (!isfinite(w->data.F64[i])) continue;
    1842             if (w->data.F64[i] == 0.0) continue;
    1843             Vn->data.F64[j][i] = V->data.F64[j][i] / w->data.F64[i];
    1844         }
    1845     }
    1846 
    1847     psImage *Xvar = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64);
    1848     psImageInit (Xvar, 0.0);
    1849 
    1850     // generate Xvar = Vn * Vn^T
    1851     for (int j = 0; j < Vn->numRows; j++) {
    1852         for (int i = 0; i < Vn->numCols; i++) {
    1853             double sum = 0.0;
    1854             for (int k = 0; k < Vn->numCols; k++) {
    1855                 sum += Vn->data.F64[k][i]*Vn->data.F64[k][j];
    1856             }
    1857             Xvar->data.F64[j][i] = sum;
    1858         }
    1859     }
    1860     return Xvar;
    18611943}
    18621944
     
    18641946// of the elements of an image A(x,y) = A->data.F64[y][x] = A_x,y, a matrix
    18651947// multiplication is: A_k,j * B_i,k = C_i,j
    1866 
    18671948
    18681949bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header) {
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionEquation.h

    r29543 r30631  
    44#include "pmSubtractionStamps.h"
    55#include "pmSubtractionKernels.h"
    6 
    7 typedef enum {
    8     PM_SUBTRACTION_EQUATION_NONE    = 0x00,
    9     PM_SUBTRACTION_EQUATION_NORM    = 0x01,
    10     PM_SUBTRACTION_EQUATION_BG      = 0x02,
    11     PM_SUBTRACTION_EQUATION_KERNELS = 0x04,
    12     PM_SUBTRACTION_EQUATION_ALL     = 0x07, // value should be NORM | BG | KERNELS
    13 } pmSubtractionEquationCalculationMode;
     6#include "pmSubtraction.h"
    147
    158/// Execute a thread job to calculate the least-squares equation for a stamp
     
    2013bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, ///< Stamps
    2114                                         pmSubtractionKernels *kernels, ///< Kernel parameters
    22                                          int index, ///< Index of stamp
    23                                          const pmSubtractionEquationCalculationMode mode
     15                                         int index ///< Index of stamp
    2416    );
    2517
    2618/// Calculate the least-squares equation to match the image quality
    2719bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, ///< Stamps
    28                                     pmSubtractionKernels *kernels, ///< Kernel parameters
    29                                     const pmSubtractionEquationCalculationMode mode
     20                                    pmSubtractionKernels *kernels ///< Kernel parameters
    3021    );
    3122
    3223/// Solve the least-squares equation to match the image quality
    3324bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, ///< Kernel parameters
    34                                 const pmSubtractionStampList *stamps, ///< Stamps
    35                                 const pmSubtractionEquationCalculationMode mode
     25                                const pmSubtractionStampList *stamps ///< Stamps
    3626    );
    3727
     
    9282bool pmSubtractionCalculateMomentsKernel(double *Mxx, double *Myy, psKernel *image, int footprint, int window);
    9383
     84bool pmSubtractionChisqStats(psVector *fluxesVector, psVector *chisqDVector, psVector *chisqRVector, psVector *momentVector, psVector *stampMask, psKernel *convolved1, psKernel *convolved2, psKernel *difference, psKernel *residual, psKernel *weight, psKernel *window);
     85
     86bool pmSubtractionCalculateChisqAndMoments(pmSubtractionQuality **bestMatch, pmSubtractionStampList *stamps, pmSubtractionKernels *kernels);
    9487#endif
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionEquation.v0.c

    r29543 r30631  
    99#include "pmErrorCodes.h"
    1010#include "pmSubtraction.h"
     11#include "pmSubtractionTypes.h"
    1112#include "pmSubtractionKernels.h"
    1213#include "pmSubtractionStamps.h"
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionHermitian.c

    r26893 r30631  
    88#include <pslib.h>
    99
     10#include "pmSubtractionTypes.h"
    1011#include "pmSubtractionHermitian.h"
    1112
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionIO.c

    r27321 r30631  
    1212#include "pmConceptsRead.h"
    1313
     14#include "pmSubtractionTypes.h"
    1415#include "pmSubtraction.h"
    1516#include "pmSubtractionKernels.h"
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionKernels.c

    r29597 r30631  
    88#include <pslib.h>
    99
     10#include "pmFPA.h"
     11#include "pmSubtractionTypes.h"
    1012#include "pmSubtraction.h"
    1113#include "pmSubtractionKernels.h"
     
    2022{
    2123    psFree(kernels->description);
     24    psFree(kernels->fwhms);
     25    psFree(kernels->orders);
    2226    psFree(kernels->u);
    2327    psFree(kernels->v);
     
    3034    psFree(kernels->solution1);
    3135    psFree(kernels->solution2);
     36    psFree(kernels->solution1err);
     37    psFree(kernels->solution2err);
    3238    psFree(kernels->sampleStamps);
    3339}
     
    419425
    420426    int num = 0;                        // Number of basis functions
    421     psString params = NULL;             // List of parameters
    422427    for (int i = 0; i < numGaussians; i++) {
    423428        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
    424         psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
    425429        num += (gaussOrder + 1) * (gaussOrder + 2) / 2;
    426430    }
    427431
    428     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size,
    429                                                               spatialOrder, penalty, bounds, mode); // Kernels
    430     psStringAppend(&kernels->description, "ISIS(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
    431 
    432     psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS kernel: %s,%d --> %d elements",
    433              params, spatialOrder, num);
    434     psFree(params);
     432    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size, fwhms, orders, spatialOrder, penalty, bounds, mode); // Kernels
     433    pmSubtractionKernelsMakeDescription(kernels);
     434    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num);
    435435
    436436# if (!CENTRAL_DELTA && !ZERO_KERNEL_ZERO_FLUX)
     
    503503
    504504    int num = 0;                        // Number of basis functions
    505     psString params = NULL;             // List of parameters
    506505    for (int i = 0; i < numGaussians; i++) {
    507506        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
    508         psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
    509507        num += (gaussOrder + 1) * (gaussOrder + 2) / 2;
    510508        num += (11 - gaussOrder - 1);   // include all higher order radial terms
    511509    }
    512510
    513     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size,
    514                                                               spatialOrder, penalty, bounds, mode); // Kernels
    515     psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
    516 
    517     psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS_RADIAL kernel: %s,%d --> %d elements", params, spatialOrder, num);
    518     psFree(params);
     511    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size, fwhms, orders, spatialOrder, penalty, bounds, mode); // Kernels
     512    pmSubtractionKernelsMakeDescription(kernels);
     513    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num);
    519514
    520515    // Set the kernel parameters
     
    569564
    570565    int num = 0;                        // Number of basis functions
    571     psString params = NULL;             // List of parameters
    572566    for (int i = 0; i < numGaussians; i++) {
    573567        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
    574         psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
    575568        num += (gaussOrder + 1) * (gaussOrder + 2) / 2;
    576569    }
    577570
    578     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size,
    579                                                               spatialOrder, penalty, bounds, mode); // Kernels
    580     psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
    581 
    582     psLogMsg("psModules.imcombine", PS_LOG_INFO, "HERM kernel: %s,%d --> %d elements",
    583              params, spatialOrder, num);
    584     psFree(params);
     571    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size, fwhms, orders, spatialOrder, penalty, bounds, mode); // Kernels
     572    pmSubtractionKernelsMakeDescription(kernels);
     573    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num);
    585574
    586575    // Set the kernel parameters
     
    627616
    628617    int num = 0;                        // Number of basis functions
    629     psString params = NULL;             // List of parameters
    630618    for (int i = 0; i < numGaussians; i++) {
    631619        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
    632         psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
    633620        num += PS_SQR(gaussOrder + 1);
    634621    }
    635622
    636     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size,
    637                                                               spatialOrder, penalty, bounds, mode); // Kernels
    638     psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty);
    639 
    640     psLogMsg("psModules.imcombine", PS_LOG_INFO, "DECONVOLVED HERM kernel: %s,%d --> %d elements", params, spatialOrder, num);
    641     psFree(params);
     623    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size, fwhms, orders, spatialOrder, penalty, bounds, mode); // Kernels
     624    pmSubtractionKernelsMakeDescription(kernels);
     625    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num);
    642626
    643627    // XXXXX hard-wired reference sigma for now of 1.7 pix (== 4.0 pix fwhm == 1.0 arcsec in simtest)
     
    713697
    714698pmSubtractionKernels *pmSubtractionKernelsAlloc(int numBasisFunctions, pmSubtractionKernelsType type,
    715                                                 int size, int spatialOrder, float penalty, psRegion bounds,
     699                                                int size, psVector *fwhms, psVector *orders, int spatialOrder, float penalty, psRegion bounds,
    716700                                                pmSubtractionMode mode)
    717701{
     
    722706    kernels->description = NULL;
    723707    kernels->num = numBasisFunctions;
     708    kernels->fwhms = psMemIncrRefCounter(fwhms);
     709    kernels->orders = psMemIncrRefCounter(orders);
    724710    kernels->u = psVectorAlloc(numBasisFunctions, PS_TYPE_S32);
    725711    kernels->v = psVectorAlloc(numBasisFunctions, PS_TYPE_S32);
     
    740726    kernels->size = size;
    741727    kernels->inner = 0;
     728    kernels->binning = 0;
     729    kernels->ringsOrder = 0;
    742730    kernels->spatialOrder = spatialOrder;
    743731    kernels->bgOrder = 0;
     
    745733    kernels->solution1 = NULL;
    746734    kernels->solution2 = NULL;
     735    kernels->solution1err = NULL;
     736    kernels->solution2err = NULL;
    747737    kernels->mean = NAN;
    748738    kernels->rms = NAN;
     
    823813    int num = PS_SQR(2 * size + 1) - 1; // Number of basis functions
    824814
    825     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size,
    826                                                               spatialOrder, penalty, bounds, mode); // Kernels
    827     psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", size, spatialOrder, penalty);
    828     psLogMsg("psModules.imcombine", PS_LOG_INFO, "POIS kernel: %d,%d --> %d elements",
    829              size, spatialOrder, num);
     815    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size, NULL, NULL, spatialOrder, penalty, bounds, mode); // Kernels
     816    pmSubtractionKernelsMakeDescription(kernels);
     817    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num);
    830818
    831819    if (!p_pmSubtractionKernelsAddGrid(kernels, 0, size)) {
     
    871859    psTrace("psModules.imcombine", 3, "Number of basis functions: %d\n", num);
    872860
    873     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size,
    874                                                               spatialOrder, penalty, bounds, mode); // Kernels
     861    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size, NULL, NULL, spatialOrder, penalty, bounds, mode); // Kernels
    875862    kernels->inner = inner;
    876     psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", size, inner, binning, spatialOrder,
    877                    penalty);
    878 
    879     psLogMsg("psModules.imcombine", PS_LOG_INFO, "SPAM kernel: %d,%d,%d,%d --> %d elements",
    880              size, inner, binning, spatialOrder, num);
     863    kernels->binning = binning;
     864    pmSubtractionKernelsMakeDescription(kernels);
     865    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num);
    881866
    882867    kernels->uStop = psVectorAlloc(num, PS_TYPE_S32);
     
    970955    psTrace("psModules.imcombine", 3, "Number of basis functions: %d\n", num);
    971956
    972     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size,
    973                                                               spatialOrder, penalty, bounds, mode); // Kernels
     957    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size, NULL, NULL, spatialOrder, penalty, bounds, mode); // Kernels
    974958    kernels->inner = inner;
    975     psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", size, inner, spatialOrder, penalty);
    976 
    977     psLogMsg("psModules.imcombine", PS_LOG_INFO, "FRIES kernel: %d,%d,%d --> %d elements",
    978              size, inner, spatialOrder, num);
     959    pmSubtractionKernelsMakeDescription(kernels);
     960    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num);
    979961
    980962    kernels->uStop = psVectorAlloc(num, PS_TYPE_S32);
     
    10531035    PS_ASSERT_INT_LESS_THAN(inner, size, NULL);
    10541036
    1055     pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders,
    1056                                                                   penalty, bounds, mode); // Kernels
     1037    pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, penalty, bounds, mode); // Kernels
    10571038    kernels->type = PM_SUBTRACTION_KERNEL_GUNK;
    1058     psStringPrepend(&kernels->description, "GUNK=");
    1059     psStringAppend(&kernels->description, "+POIS(%d,%d)", inner, spatialOrder);
     1039    kernels->inner = inner;
     1040    pmSubtractionKernelsMakeDescription(kernels);
     1041    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, (int) kernels->num);
    10601042
    10611043    int numISIS = kernels->num;         // Number of ISIS kernels
     
    11001082    int num = numRings * numPoly; // Total number of basis functions
    11011083
    1102     pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size,
    1103                                                               spatialOrder, penalty, bounds, mode); // Kernels
     1084    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size, NULL, NULL, spatialOrder, penalty, bounds, mode); // Kernels
    11041085    kernels->inner = inner;
    1105     psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", size, inner, ringsOrder, spatialOrder,
    1106                    penalty);
    1107 
    1108     psLogMsg("psModules.imcombine", PS_LOG_INFO, "RINGS kernel: %d,%d,%d,%d --> %d elements",
    1109              size, inner, ringsOrder, spatialOrder, num);
     1086    kernels->ringsOrder = ringsOrder;
     1087    pmSubtractionKernelsMakeDescription(kernels);
     1088    psLogMsg("psModules.imcombine", PS_LOG_INFO, "kernel: %s --> %d elements", kernels->description, num);
    11101089
    11111090    // Set the Gaussian kernel parameters
     
    14051384}
    14061385
     1386bool pmSubtractionKernelsMakeDescription(pmSubtractionKernels *kernels) {
     1387
     1388    // free if it exists
     1389    psFree (kernels->description);
     1390
     1391    // generate the description parameter string
     1392    psString params = NULL;
     1393    if (kernels->fwhms) {
     1394        for (int i = 0; i < kernels->fwhms->n; i++) {
     1395            psStringAppend(&params, "(%.1f,%d)", kernels->fwhms->data.F32[i], kernels->orders->data.S32[i]);
     1396        }
     1397    }
     1398
     1399    switch (kernels->type) {
     1400      case PM_SUBTRACTION_KERNEL_ISIS:
     1401        psStringAppend (&kernels->description, "ISIS(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty);
     1402        break;
     1403
     1404      case PM_SUBTRACTION_KERNEL_ISIS_RADIAL:
     1405        psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty);
     1406        break;
     1407
     1408      case PM_SUBTRACTION_KERNEL_HERM:
     1409        psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty);
     1410        break;
     1411
     1412      case PM_SUBTRACTION_KERNEL_DECONV_HERM:
     1413        psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty);
     1414        break;
     1415
     1416      case PM_SUBTRACTION_KERNEL_POIS:
     1417        psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", kernels->size, kernels->spatialOrder, kernels->penalty);
     1418        break;
     1419
     1420      case PM_SUBTRACTION_KERNEL_SPAM:
     1421        psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", kernels->size, kernels->inner, kernels->binning, kernels->spatialOrder, kernels->penalty);
     1422        break;
     1423
     1424      case PM_SUBTRACTION_KERNEL_FRIES:
     1425        psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", kernels->size, kernels->inner, kernels->spatialOrder, kernels->penalty);
     1426        break;
     1427
     1428        // Grid United with Normal Kernel [description: GUNK=ISIS(...)+POIS(...)]
     1429      case PM_SUBTRACTION_KERNEL_GUNK:
     1430        psStringAppend(&kernels->description, "GUNK=ISIS(%d,%s,%d,%.2e)", kernels->size, params, kernels->spatialOrder, kernels->penalty);
     1431        psStringAppend(&kernels->description, "+POIS(%d,%d)", kernels->inner, kernels->spatialOrder);
     1432        break;
     1433       
     1434      case PM_SUBTRACTION_KERNEL_RINGS:
     1435        psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", kernels->size, kernels->inner, kernels->ringsOrder, kernels->spatialOrder, kernels->penalty);
     1436        break;
     1437
     1438      default:
     1439        psAbort("unknown kernel");
     1440    }
     1441    psFree (params);
     1442    return true;
     1443}
     1444
    14071445pmSubtractionKernels *pmSubtractionKernelsCopy(const pmSubtractionKernels *in)
    14081446{
     
    14351473    out->solution1 = in->solution1 ? psVectorCopy(NULL, in->solution1, PS_TYPE_F64) : NULL;
    14361474    out->solution2 = in->solution2 ? psVectorCopy(NULL, in->solution2, PS_TYPE_F64) : NULL;
     1475    out->solution1err = in->solution1err ? psVectorCopy(NULL, in->solution1err, PS_TYPE_F64) : NULL;
     1476    out->solution2err = in->solution2err ? psVectorCopy(NULL, in->solution2err, PS_TYPE_F64) : NULL;
    14371477    out->sampleStamps = psMemIncrRefCounter(in->sampleStamps);
    14381478
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionKernels.h

    r29601 r30631  
    22#define PM_SUBTRACTION_KERNELS_H
    33
    4 #include <string.h>
    5 #include <pslib.h>
    6 
    7 /// Type of subtraction kernel
    8 typedef enum {
    9     PM_SUBTRACTION_KERNEL_NONE,         ///< Nothing --- an error
    10     PM_SUBTRACTION_KERNEL_POIS,         ///< Pan-STARRS Optimal Image Subtraction --- delta functions
    11     PM_SUBTRACTION_KERNEL_ISIS,         ///< Traditional kernel --- gaussians modified by polynomials
    12     PM_SUBTRACTION_KERNEL_ISIS_RADIAL,  ///< ISIS + higher-order radial Hermitians
    13     PM_SUBTRACTION_KERNEL_HERM,         ///< Hermitian polynomial kernels
    14     PM_SUBTRACTION_KERNEL_DECONV_HERM,  ///< Deconvolved Hermitian polynomial kernels
    15     PM_SUBTRACTION_KERNEL_SPAM,         ///< Summed Pixels for Advanced Matching --- summed delta functions
    16     PM_SUBTRACTION_KERNEL_FRIES,        ///< Fibonacci Radius Increases Excellence of Subtraction
    17     PM_SUBTRACTION_KERNEL_GUNK,         ///< Grid United with Normal Kernel --- POIS and ISIS hybrid
    18     PM_SUBTRACTION_KERNEL_RINGS,        ///< Rings Instead of the Normal Gaussian Subtraction
    19 } pmSubtractionKernelsType;
    20 
    21 /// Modes --- specifies which image to convolve
    22 typedef enum {
    23     PM_SUBTRACTION_MODE_ERR,            // Error in the mode
    24     PM_SUBTRACTION_MODE_1,              // Convolve image 1
    25     PM_SUBTRACTION_MODE_2,              // Convolve image 2
    26     PM_SUBTRACTION_MODE_UNSURE,         // Not sure yet which image to convolve so try to satisfy both
    27     PM_SUBTRACTION_MODE_DUAL,           // Dual convolution
    28 } pmSubtractionMode;
    29 
    30 /// Kernels specification
    31 typedef struct {
    32     pmSubtractionKernelsType type;      ///< Type of kernels --- allowing the use of multiple kernels
    33     psString description;               ///< Description of the kernel parameters
    34     int xMin, xMax, yMin, yMax;         ///< Bounds of image (for normalisation)
    35     long num;                           ///< Number of kernel components (not including the spatial ones)
    36     psVector *u, *v;                    ///< Offset (for POIS) or polynomial order (for ISIS, HERM or DECONV_HERM)
    37     psVector *widths;                   ///< Gaussian FWHMs (ISIS, HERM or DECONV_HERM)
    38     psVector *uStop, *vStop;            ///< Width of kernel element (SPAM,FRIES only)
    39     psArray *preCalc;                   ///< Array of images containing pre-calculated kernel (for ISIS, HERM or DECONV_HERM)
    40     float penalty;                      ///< Penalty for wideness
    41     psVector *penalties1;               ///< Penalty for each kernel component
    42     psVector *penalties2;               ///< Penalty for each kernel component
    43     bool havePenalties;                 ///< flag to test if we have already calculated the penalties or not.
    44     int size;                           ///< The half-size of the kernel
    45     int inner;                          ///< The size of an inner region
    46     int spatialOrder;                   ///< The spatial order of the kernels
    47     int bgOrder;                        ///< The order for the background fitting
    48     pmSubtractionMode mode;             ///< Mode for subtraction
    49     psVector *solution1, *solution2;    ///< Solution for the PSF matching
    50     // Quality information
    51     float mean, rms;                    ///< Mean and RMS of chi^2 from stamps
    52     int numStamps;                      ///< Number of good stamps
    53     float fResSigmaMean;                ///< mean fractional stdev of residuals
    54     float fResSigmaStdev;               ///< stdev of fractional stdev of residuals
    55     float fResOuterMean;                ///< mean fractional positive swing in residuals
    56     float fResOuterStdev;               ///< stdev of fractional positive swing in residuals
    57     float fResTotalMean;                ///< mean fractional negative swing in residuals
    58     float fResTotalStdev;               ///< stdev of fractional negative swing in residuals
    59     psArray *sampleStamps;              ///< array of brightest set of stamps for output visualizations
    60 } pmSubtractionKernels;
    61 
    62 // pmSubtractionKernels->preCalc is an array of pmSubtractionKernelPreCalc structures
    63 typedef struct {
    64     psVector *uCoords;                  // used by RINGS
    65     psVector *vCoords;                  // used by RINGS
    66     psVector *poly;                     // used by RINGS
    67 
    68     psVector *xKernel;                  // used by ISIS, HERM, DECONV_HERM
    69     psVector *yKernel;                  // used by ISIS, HERM, DECONV_HERM
    70     psKernel *kernel;                   // used by ISIS, HERM, DECONV_HERM
    71 } pmSubtractionKernelPreCalc;
     4// #include <string.h>
     5// #include <pslib.h>
    726
    737// Assertion to check pmSubtractionKernels
     
    16296                                                pmSubtractionKernelsType type, ///< Kernel type
    16397                                                int size, ///< Half-size of kernel
     98                                                psVector *fwhms, ///< requested kernel basis function
     99                                                psVector *orders,
    164100                                                int spatialOrder, ///< Order of spatial variations
    165101                                                float penalty, ///< Penalty for wideness
     
    303239    );
    304240
     241bool pmSubtractionKernelsMakeDescription(pmSubtractionKernels *kernels);
     242
     243
    305244/// Copy kernels
    306245///
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionMask.c

    r27402 r30631  
    77
    88#include "pmErrorCodes.h"
     9#include "pmFPA.h"
     10#include "pmSubtractionTypes.h"
    911#include "pmSubtraction.h"
    1012#include "pmSubtractionKernels.h"
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionMatch.c

    r29596 r30631  
    1111#include "pmFPA.h"
    1212#include "pmHDUUtils.h"
     13#include "pmSubtractionTypes.h"
     14#include "pmSubtraction.h"
    1315#include "pmSubtractionParams.h"
    1416#include "pmSubtractionKernels.h"
    1517#include "pmSubtractionStamps.h"
    1618#include "pmSubtractionEquation.h"
    17 #include "pmSubtraction.h"
    1819#include "pmSubtractionAnalysis.h"
    1920#include "pmSubtractionMask.h"
     
    2728
    2829static bool useFFT = true;              // Do convolutions using FFT
    29 
    30 # define SUBMODE PM_SUBTRACTION_EQUATION_ALL
    3130
    3231//#define TESTING
     
    5958}
    6059
    61 
    62 static bool subtractionGetStamps(pmSubtractionStampList **stamps, // Stamps to read
    63                                  const pmReadout *ro1, // Readout 1
    64                                  const pmReadout *ro2, // Readout 2
    65                                  const psImage *subMask, // Mask for subtraction, or NULL
    66                                  psImage *variance,  // Variance map
    67                                  const psRegion *region, // Region of interest
    68                                  float thresh1,  // Threshold for stamp finding on readout 1
    69                                  float thresh2,  // Threshold for stamp finding on readout 2
    70                                  float stampSpacing, // Spacing between stamps
    71                                  float normFrac,     // Fraction of flux in window for normalisation window
    72                                  float sysError,     // Relative systematic error in images
    73                                  float skyError,     // Relative systematic error in images
    74                                  int size,         // Kernel half-size
    75                                  int footprint,     // Convolution footprint for stamps
    76                                  pmSubtractionMode mode // Mode for subtraction
    77     )
    78 {
    79     PS_ASSERT_PTR_NON_NULL(stamps, false);
    80     PM_ASSERT_READOUT_NON_NULL(ro1, false);
    81     PM_ASSERT_READOUT_NON_NULL(ro2, false);
    82     PS_ASSERT_IMAGE_NON_NULL(subMask, false);
    83     PS_ASSERT_IMAGE_NON_NULL(variance, false);
    84     PS_ASSERT_PTR_NON_NULL(region, false);
    85 
    86     psTrace("psModules.imcombine", 3, "Finding stamps...\n");
    87 
    88     psImage *image1 = ro1 ? ro1->image : NULL, *image2 = ro2 ? ro2->image : NULL; // Images of interest
    89 
    90     *stamps = pmSubtractionStampsFind(*stamps, image1, image2, subMask, region, thresh1, thresh2,
    91                                       size, footprint, stampSpacing, normFrac, sysError, skyError, mode);
    92     if (!*stamps) {
    93         psError(psErrorCodeLast(), false, "Unable to find stamps.");
    94         return false;
    95     }
    96 
    97     memCheck("  find stamps");
    98 
    99     psTrace("psModules.imcombine", 3, "Extracting stamps...\n");
    100     if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2->image, variance, size, *region)) {
    101         psError(psErrorCodeLast(), false, "Unable to extract stamps.");
    102         return false;
    103     }
    104 
    105     memCheck("   extract stamps");
    106     pmSubtractionVisualPlotStamps(*stamps, (pmReadout *) ro1);
    107     return true;
    108 }
    109 
    11060// Check input arguments
    11161static bool subtractionMatchCheck(pmReadout *conv1, pmReadout *conv2, // Convolved images
     
    12373                                  float badFrac,   // Maximum fraction of bad input pixels to accept
    12474                                  pmSubtractionMode subMode // Mode of subtraction
    125                                   )
     75    )
    12676{
    12777    if (subMode != PM_SUBTRACTION_MODE_2) {
     
    473423}
    474424
     425bool pmSubtractionMatchAttempt(pmSubtractionQuality **bestMatch, pmSubtractionKernels *kernels, pmSubtractionStampList *stamps, pmSubtractionMode mode, int spatialOrder, bool final) {
     426
     427    pmSubtractionMode nativeMode = kernels->mode;
     428    pmSubtractionMode nativeOrder = kernels->spatialOrder;
     429
     430    kernels->mode = mode;
     431    kernels->spatialOrder = spatialOrder;
     432
     433    // we always need to recalculate the matrix equation elements...
     434    pmSubtractionStampsResetStatus(stamps);
     435
     436    psTrace("psModules.imcombine", 3, "Convolving stamps as needed...\n");
     437    if (!pmSubtractionConvolveStamps(stamps, kernels)) {
     438        psError(psErrorCodeLast(), false, "Unable to convolve stamps.");
     439        return false;
     440    }
     441
     442    // step 1: generate the elements of the matrix equation Ax = B
     443    psTrace("psModules.imcombine", 3, "Calculating kernel equations...\n");
     444    if (!pmSubtractionCalculateEquation(stamps, kernels)) {
     445        psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     446        return false;
     447    }
     448                   
     449    // step 2: solve the matrix equation Ax = B
     450    psTrace("psModules.imcombine", 3, "Solving kernel equations...\n");
     451    if (!pmSubtractionSolveEquation(kernels, stamps)) {
     452        psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     453        return false;
     454    }
     455    memCheck("  solve equation");
     456
     457    // calculate the score for this model fit attempt
     458    // XXX store the chisq, flux and moments for stamp rejection
     459    pmSubtractionCalculateChisqAndMoments(bestMatch, stamps, kernels); // Stamp deviations
     460
     461    // display the input and model stamps
     462    pmSubtractionVisualShowFit(stamps, kernels);
     463    pmSubtractionVisualPlotFit(kernels);
     464    pmSubtractionVisualPlotConvKernels(kernels);
     465
     466    // reset the kernel if desired (on final pass, do not reset)
     467    if (!final) {
     468        kernels->mode = nativeMode;
     469        kernels->spatialOrder = nativeOrder;
     470    } else {
     471      pmSubtractionKernelsMakeDescription(kernels);
     472      psLogMsg("psModules.imcombine", PS_LOG_INFO, "final kernel: %s", kernels->description);
     473    }
     474    return true;
     475}
    475476
    476477bool pmSubtractionMatch(pmReadout *conv1, pmReadout *conv2, const pmReadout *ro1, const pmReadout *ro2,
     
    478479                        const psArray *sources, const char *stampsName,
    479480                        pmSubtractionKernelsType type, int size, int spatialOrder,
    480                         const psVector *isisWidths, const psVector *isisOrders,
     481                        psVector *isisWidths, const psVector *isisOrders,
    481482                        int inner, int ringsOrder, int binning, float penalty,
    482483                        bool optimum, const psVector *optFWHMs, int optOrder, float optThreshold,
     
    559560    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
    560561
     562    pmSubtractionQuality *bestMatch = NULL;
     563
     564    int N_TEST_MODES;
     565    int N_TEST_ORDER = spatialOrder;
     566
     567    pmSubtractionMode TestModes[3];
     568    switch (subMode) {
     569      case PM_SUBTRACTION_MODE_1:
     570        N_TEST_MODES = 1;
     571        TestModes[0] = PM_SUBTRACTION_MODE_1;
     572        break;
     573      case PM_SUBTRACTION_MODE_2:
     574        N_TEST_MODES = 1;
     575        TestModes[0] = PM_SUBTRACTION_MODE_2;
     576        break;
     577      case PM_SUBTRACTION_MODE_DUAL:
     578        N_TEST_MODES = 3;
     579        TestModes[0] = PM_SUBTRACTION_MODE_1;
     580        TestModes[1] = PM_SUBTRACTION_MODE_2;
     581        TestModes[2] = PM_SUBTRACTION_MODE_DUAL;
     582        break;
     583      default:
     584        psError(psErrorCodeLast(), false, "For now, only modes 1, 2, and DUAL are supported.");
     585        goto MATCH_ERROR;
     586    }
     587   
    561588    memCheck("start");
    562589
     
    628655            regionString = psRegionToString(*region);
    629656            psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Iso-kernel region: %s out of %d,%d\n",
    630                     regionString, numCols, numRows);
     657                     regionString, numCols, numRows);
    631658
    632659            if (stampsName && strlen(stampsName) > 0) {
     
    640667            }
    641668
    642             // We get the stamps here; we will also attempt to get stamps at the first iteration, but it
    643             // doesn't matter.
    644             if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2,
    645                                       stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) {
    646                 goto MATCH_ERROR;
    647             }
    648 
    649 
    650             // generate the window function from the set of stamps
    651             if (!pmSubtractionStampsGetWindow(stamps, size)) {
    652                 psError(psErrorCodeLast(), false, "Unable to get stamp window.");
    653                 goto MATCH_ERROR;
    654             }
    655 
    656             // Define kernel basis functions
    657             if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) {
    658                 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder,
    659                                                           optFWHMs, optOrder, stamps, footprint,
    660                                                           optThreshold, penalty, bounds, subMode);
    661                 if (!kernels) {
    662                     psErrorClear();
    663                     psWarning("Unable to derive optimum ISIS kernel --- switching to default.");
    664                 }
    665             }
    666             if (kernels == NULL) {
    667                 // Not an ISIS/GUNK kernel, or the optimum kernel search failed
    668                 kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders,
    669                                                        inner, binning, ringsOrder, penalty, bounds, subMode);
    670             }
    671 
    672             memCheck("kernels");
    673 
    674             if (subMode == PM_SUBTRACTION_MODE_UNSURE) {
    675                 pmSubtractionMode newMode = pmSubtractionBestMode(&stamps, &kernels, subMask, rej);
    676                 switch (newMode) {
    677                   case PM_SUBTRACTION_MODE_1:
    678                     psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 1 to match image 2.");
    679                     break;
    680                   case PM_SUBTRACTION_MODE_2:
    681                     psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 2 to match image 1.");
    682                     break;
    683                   default:
    684                     psError(psErrorCodeLast(), false, "Unable to determine subtraction order.");
    685                     goto MATCH_ERROR;
    686                 }
    687                 subMode = newMode;
    688             }
    689 
    690             int numRejected = -1;       // Number of rejected stamps in each iteration
    691             for (int k = 0; k < iter && numRejected != 0; k++) {
    692                 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Iteration %d.", k);
    693 
    694                 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region,
    695                                           stampThresh1, stampThresh2, stampSpacing, normFrac,
    696                                           sysError, skyError, size, footprint, subMode)) {
    697                     goto MATCH_ERROR;
    698                 }
    699 
    700                 // generate the window function from the set of stamps
    701                 if (!pmSubtractionStampsGetWindow(stamps, size)) {
    702                     psError(psErrorCodeLast(), false, "Unable to get stamps window.");
    703                     goto MATCH_ERROR;
    704                 }
     669            bool tryAgain = true;
     670            while (tryAgain) {
     671                // We get the stamps here; we will also attempt to get stamps at the first iteration, but it
     672                // doesn't matter.
     673                if (!pmSubtractionStampsSelect(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2,
     674                                               stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) {
     675                    goto MATCH_ERROR;
     676                }
     677
     678                // generate the window function from the set of stamps
     679                if (!pmSubtractionStampsGetWindow(&tryAgain, stamps, size)) {
     680                    // if we failed, it might be due to the desired normWindow being larger than the current footprint.
     681                    // in this case, just adjust the footprint and try again.
     682                    if (tryAgain) {
     683                        // keep the border constant
     684                        int border = footprint - size;
     685                        size = PS_MAX(stamps->normWindow1, stamps->normWindow2) + 2;
     686                        footprint = size + border;
     687
     688                        // we need to reconstruct everything, so just free the stamps here and retry
     689                        psFree(stamps);
     690                    } else {
     691                        // unrecoverable error
     692                        psError(psErrorCodeLast(), false, "Unable to get stamp window.");
     693                        goto MATCH_ERROR;
     694                    }
     695                }
     696            }
     697
     698            // check on the kernel scaling -- if the kron-based radial moments are very different, adjust to match them
     699            {
     700                // float fwhm1;
     701                // float fwhm2;
     702                // pmSubtractionGetFWHMs(&fwhm1, &fwhm2);
     703                // psAssert(isfinite(fwhm1), "fwhm 1 not set");
     704                // psAssert(isfinite(fwhm2), "fwhm 2 not set");
     705
     706                // XXX this is BAD: depends on the relationship below:
     707                // stamps->normWindow1 = 2.75*R1;
     708                // stamps->normWindow2 = 2.75*R2;
     709                float radMoment1 = stamps->normWindow1 / 2.75;
     710                float radMoment2 = stamps->normWindow2 / 2.75;
     711                pmSubtractionParamsScale(NULL, NULL, isisWidths, radMoment1, radMoment2);
     712
     713                // float maxFWHM = PS_MAX(fwhm1, fwhm2);
     714                // float maxRadial = PS_MAX(radMoment1, radMoment2);
     715               
     716                // if (fabs(2.0*(maxFWHM - maxRadial)/(maxFWHM + maxRadial)) > 0.25) {
     717                // if (1) {
     718                //
     719                //     float scale = maxRadial / maxFWHM;
     720                //     psLogMsg ("psModules.imcombine", PS_LOG_INFO, "Kron and FWHM scales are quite different, re-scale by %f to use Kron", scale);
     721                //     
     722                //     for (int i = 0; i < isisWidths->n; i++) {
     723                //      isisWidths->data.F32[i] *= scale;
     724                //     }
     725                // }
     726            }
     727
     728            // Define kernel basis functions
     729            if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) {
     730                kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder,
     731                                                          optFWHMs, optOrder, stamps, footprint,
     732                                                          optThreshold, penalty, bounds, subMode);
     733                if (!kernels) {
     734                    psErrorClear();
     735                    psWarning("Unable to derive optimum ISIS kernel --- switching to default.");
     736                }
     737            }
     738            if (kernels == NULL) {
     739                // Not an ISIS/GUNK kernel, or the optimum kernel search failed
     740                kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders,
     741                                                       inner, binning, ringsOrder, penalty, bounds, subMode);
     742            }
     743
     744            memCheck("kernels");
     745
     746            if (subMode == PM_SUBTRACTION_MODE_UNSURE) {
     747                pmSubtractionMode newMode = pmSubtractionBestMode(&stamps, &kernels, subMask, rej);
     748                switch (newMode) {
     749                  case PM_SUBTRACTION_MODE_1:
     750                    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 1 to match image 2.");
     751                    break;
     752                  case PM_SUBTRACTION_MODE_2:
     753                    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolving image 2 to match image 1.");
     754                    break;
     755                  default:
     756                    psError(psErrorCodeLast(), false, "Unable to determine subtraction order.");
     757                    goto MATCH_ERROR;
     758                }
     759                subMode = newMode;
     760            }
     761
     762            int numRejected = -1;       // Number of rejected stamps in each iteration
     763            for (int k = 0; (k < iter) && (numRejected != 0); k++) {
     764                psLogMsg("psModules.imcombine", PS_LOG_INFO, "Iteration %d.", k);
     765
     766                bool tryAgain = true;
     767                while (tryAgain) {
     768                    // We get the stamps here; we will also attempt to get stamps at the first iteration, but it
     769                    // doesn't matter.
     770                    if (!pmSubtractionStampsSelect(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2,
     771                                                   stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) {
     772                        goto MATCH_ERROR;
     773                    }
     774
     775                    // generate the window function from the set of stamps
     776                    if (!pmSubtractionStampsGetWindow(&tryAgain, stamps, size)) {
     777                        // if we failed, it might be due to the desired normWindow being larger than the current footprint.
     778                        // in this case, just adjust the footprint and try again.
     779                        if (tryAgain) {
     780                            footprint = PS_MAX(stamps->normWindow1, stamps->normWindow2) + 2;
     781
     782                            // we need to reconstruct everything, so just free the stamps here and retry
     783                            psFree(stamps);
     784                        } else {
     785                            // unrecoverable error
     786                            psError(psErrorCodeLast(), false, "Unable to get stamp window.");
     787                            goto MATCH_ERROR;
     788                        }
     789                    }
     790                }
    705791
    706792                // step 0 : calculate the normalizations, pass along to the next steps via stamps->normValue
    707                 psTrace("psModules.imcombine", 3, "Calculating normalization...\n");
    708                 if (!pmSubtractionCalculateNormalization(stamps, kernels->mode)) {
    709                     psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    710                     goto MATCH_ERROR;
    711                 }
    712 
    713                 // step 0b : calculate the moments, pass along to the next steps via stamps->normValue
    714                 // XXX this step is now skipped -- delete
    715                 psTrace("psModules.imcombine", 3, "Calculating normalization...\n");
    716                 if (!pmSubtractionCalculateMoments(kernels, stamps)) {
    717                     psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    718                     goto MATCH_ERROR;
    719                 }
    720 
    721                 // step 1: generate the elements of the matrix equation Ax = B
    722                 psTrace("psModules.imcombine", 3, "Calculating kernel equations...\n");
    723                 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) {
    724                     psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    725                     goto MATCH_ERROR;
    726                 }
    727 
    728                 // step 2: solve the matrix equation Ax = B
    729                 psTrace("psModules.imcombine", 3, "Solving kernel equations...\n");
    730                 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) {
    731                     psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    732                     goto MATCH_ERROR;
    733                 }
    734                 memCheck("  solve equation");
    735 
    736                 pmSubtractionVisualPlotConvKernels(kernels);
    737 
    738                 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
    739                 if (!deviations) {
    740                     psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
    741                     goto MATCH_ERROR;
    742                 }
    743                 memCheck("   calculate deviations");
    744 
    745                 psTrace("psModules.imcombine", 3, "Rejecting stamps...\n");
    746                 numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej);
    747                 if (numRejected < 0) {
    748                     psError(psErrorCodeLast(), false, "Unable to reject stamps.");
    749                     psFree(deviations);
    750                     goto MATCH_ERROR;
    751                 }
    752                 psFree(deviations);
    753 
    754                 memCheck("  reject stamps");
    755             }
    756 
    757             // if we hit the max number of iterations and we have rejected stamps, re-solve
    758             if (numRejected > 0) {
    759 
    760                 // step 1: generate the elements of the matrix equation Ax = B
    761                 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n");
    762                 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) {
    763                     psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    764                     goto MATCH_ERROR;
    765                 }
    766 
    767                 // step 2: solve the matrix equation Ax = B
    768                 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n");
    769                 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) {
    770                     psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    771                     goto MATCH_ERROR;
    772                 }
    773 
    774                 pmSubtractionVisualPlotConvKernels(kernels);
    775 
    776                 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
    777                 if (!deviations) {
    778                     psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
    779                     goto MATCH_ERROR;
    780                 }
    781                 pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN);
    782                 psFree(deviations);
    783             }
    784             psFree(stamps);
    785             stamps = NULL;
    786 
    787             memCheck("solution");
    788 
    789             if (!pmSubtractionAnalysis(analysis, header, kernels, region, numCols, numRows)) {
    790                 psError(psErrorCodeLast(), false, "Unable to generate QA data");
    791                 goto MATCH_ERROR;
    792             }
    793             memCheck("diag outputs");
    794 
    795             psTrace("psModules.imcombine", 2, "Convolving...\n");
    796             if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac,
    797                                        kernelError, covarFrac, region, kernels, true, useFFT)) {
    798                 psError(psErrorCodeLast(), false, "Unable to convolve image.");
    799                 goto MATCH_ERROR;
    800             }
    801 
    802             psFree(kernels);
    803             kernels = NULL;
    804         }
     793                psTrace("psModules.imcombine", 3, "Calculating normalization...\n");
     794                if (!pmSubtractionCalculateNormalization(stamps, kernels->mode)) {
     795                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     796                    goto MATCH_ERROR;
     797                }
     798
     799                // on each iteration, we start from scratch
     800                psFree(bestMatch);
     801
     802                // choose the spatial order and subtraction direction (1, 2, dual)
     803                // XXX need to make these respect recipe somewhat
     804                for (int order = 0; order <= N_TEST_ORDER; order++) {
     805                    for (int j = 0; j < N_TEST_MODES; j++) {
     806                        if (!pmSubtractionMatchAttempt(&bestMatch, kernels, stamps, TestModes[j], order, false)) {
     807                            goto MATCH_ERROR;
     808                        }
     809                    }
     810                }
     811               
     812                // reject the deviant stamps based on the stats of the best match
     813                psTrace("psModules.imcombine", 3, "Rejecting stamps...\n");
     814                numRejected = pmSubtractionRejectStamps(kernels, stamps, bestMatch, subMask, rej);
     815                if (numRejected < 0) {
     816                    psError(psErrorCodeLast(), false, "Unable to reject stamps.");
     817                    goto MATCH_ERROR;
     818                }
     819                memCheck("  reject stamps");
     820            }
     821
     822            // apply the best fit so we are ready to roll
     823            psLogMsg("psModules.imcombine", PS_LOG_INFO, "applying order: %d, mode: %d\n", bestMatch->spatialOrder, bestMatch->mode);
     824            if (!pmSubtractionMatchAttempt(NULL, kernels, stamps, bestMatch->mode, bestMatch->spatialOrder, true)) {
     825                goto MATCH_ERROR;
     826            }
     827            psFree(stamps);
     828            psFree(bestMatch);
     829            memCheck("solution");
     830
     831            if (!pmSubtractionAnalysis(analysis, header, kernels, region, numCols, numRows)) {
     832                psError(psErrorCodeLast(), false, "Unable to generate QA data");
     833                goto MATCH_ERROR;
     834            }
     835            memCheck("diag outputs");
     836
     837            psTrace("psModules.imcombine", 2, "Convolving...\n");
     838            if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac,
     839                                       kernelError, covarFrac, region, kernels, true, useFFT)) {
     840                psError(psErrorCodeLast(), false, "Unable to convolve image.");
     841                goto MATCH_ERROR;
     842            }
     843
     844            psFree(kernels);
     845            kernels = NULL;
     846        }
    805847    }
    806848    psFree(rng);
     
    816858
    817859    if (conv1 && !pmSubtractionBorder(conv1->image, conv1->variance, conv1->mask, size, maskBad)) {
    818         psError(psErrorCodeLast(), false, "Unable to set border of convolved image.");
    819         goto MATCH_ERROR;
     860        psError(psErrorCodeLast(), false, "Unable to set border of convolved image.");
     861        goto MATCH_ERROR;
    820862    }
    821863    if (conv2 && !pmSubtractionBorder(conv2->image, conv2->variance, conv2->mask, size, maskBad)) {
    822         psError(psErrorCodeLast(), false, "Unable to set border of convolved image.");
    823         goto MATCH_ERROR;
     864        psError(psErrorCodeLast(), false, "Unable to set border of convolved image.");
     865        goto MATCH_ERROR;
    824866    }
    825867
     
    832874#ifdef TESTING
    833875    {
    834         if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_DUAL) {
    835             psFits *fits = psFitsOpen("convolved1.fits", "w");
    836             psFitsWriteImage(fits, NULL, conv1->image, 0, NULL);
    837             psFitsClose(fits);
    838         }
    839 
    840         if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_DUAL) {
    841             psFits *fits = psFitsOpen("convolved2.fits", "w");
    842             psFitsWriteImage(fits, NULL, conv2->image, 0, NULL);
    843             psFitsClose(fits);
    844         }
     876        if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_DUAL) {
     877            psFits *fits = psFitsOpen("convolved1.fits", "w");
     878            psFitsWriteImage(fits, NULL, conv1->image, 0, NULL);
     879            psFitsClose(fits);
     880        }
     881
     882        if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_DUAL) {
     883            psFits *fits = psFitsOpen("convolved2.fits", "w");
     884            psFitsWriteImage(fits, NULL, conv2->image, 0, NULL);
     885            psFitsClose(fits);
     886        }
    845887    }
    846888#endif
     
    858900    psFree(variance);
    859901    psFree(rng);
     902    psFree(bestMatch);
    860903    return false;
    861904}
     
    866909// increment).
    867910static int subtractionOrderWidth(const psKernel *kernel, // Image
    868                                 float bg, // Background in image
    869                                 int size, // Maximum size
    870                                 const psArray *models, // Buffer of models
    871                                 const psVector *modelSums // Buffer of model sums
     911                                float bg, // Background in image
     912                                int size, // Maximum size
     913                                const psArray *models, // Buffer of models
     914                                const psVector *modelSums // Buffer of model sums
    872915    )
    873916{
     
    882925    psVector *chi2 = psVectorAlloc(size, PS_TYPE_F32); // chi^2 as a function of radius
    883926    for (int sigma = 0; sigma < size; sigma++) {
    884         double sumFG = 0.0; // Sum for calculating the normalisation of the Gaussian
    885         psKernel *model = models->data[sigma]; // Model of interest
    886         for (int y = yMin; y <= yMax; y++) {
    887             for (int x = xMin; x <= xMax; x++) {
    888                 sumFG += model->kernel[y][x] * (kernel->kernel[y][x] - bg);
    889             }
    890         }
    891         float norm = sumFG * modelSums->data.F64[sigma]; // Normalisation for Gaussian
    892         double sumDev2 = 0.0;           // Sum of square deviations
    893         for (int y = yMin; y <= yMax; y++) {
    894             for (int x = xMin; x <= xMax; x++) {
    895                 float dev = kernel->kernel[y][x] - bg - norm * model->kernel[y][x]; // Deviation
    896                 sumDev2 += PS_SQR(dev);
    897             }
    898         }
    899         chi2->data.F32[sigma] = sumDev2;
     927        double sumFG = 0.0; // Sum for calculating the normalisation of the Gaussian
     928        psKernel *model = models->data[sigma]; // Model of interest
     929        for (int y = yMin; y <= yMax; y++) {
     930            for (int x = xMin; x <= xMax; x++) {
     931                sumFG += model->kernel[y][x] * (kernel->kernel[y][x] - bg);
     932            }
     933        }
     934        float norm = sumFG * modelSums->data.F64[sigma]; // Normalisation for Gaussian
     935        double sumDev2 = 0.0;           // Sum of square deviations
     936        for (int y = yMin; y <= yMax; y++) {
     937            for (int x = xMin; x <= xMax; x++) {
     938                float dev = kernel->kernel[y][x] - bg - norm * model->kernel[y][x]; // Deviation
     939                sumDev2 += PS_SQR(dev);
     940            }
     941        }
     942        chi2->data.F32[sigma] = sumDev2;
    900943    }
    901944
     
    904947    float bestChi2 = INFINITY;          // Best chi^2
    905948    for (int i = 0; i < size; i++) {
    906         if (chi2->data.F32[i] < bestChi2) {
    907             bestChi2 = chi2->data.F32[i];
    908             bestIndex = i;
    909         }
     949        if (chi2->data.F32[i] < bestChi2) {
     950            bestChi2 = chi2->data.F32[i];
     951            bestIndex = i;
     952        }
    910953    }
    911954    psFree(chi2);
     
    916959
    917960bool pmSubtractionOrderStamp(psVector *ratios, psVector *mask, const pmSubtractionStampList *stamps,
    918                              const psArray *models, const psVector *modelSums,
    919                              int index, float bg1, float bg2)
     961                             const psArray *models, const psVector *modelSums,
     962                             int index, float bg1, float bg2)
    920963{
    921964    PS_ASSERT_VECTOR_NON_NULL(ratios, false);
     
    931974    pmSubtractionStamp *stamp = stamps->stamps->data[index]; // Stamp of interest
    932975    psAssert(stamp->status == PM_SUBTRACTION_STAMP_CALCULATE || stamp->status == PM_SUBTRACTION_STAMP_USED,
    933              "We checked this earlier.");
     976             "We checked this earlier.");
    934977
    935978    // Widths of stars
     
    938981
    939982    if (width1 == 0 || width2 == 0) {
    940         ratios->data.F32[index] = NAN;
    941         mask->data.PS_TYPE_VECTOR_MASK_DATA[index] = 0xff;
     983        ratios->data.F32[index] = NAN;
     984        mask->data.PS_TYPE_VECTOR_MASK_DATA[index] = 0xff;
    942985    } else {
    943         ratios->data.F32[index] = (float)width1 / (float)width2;
    944         mask->data.PS_TYPE_VECTOR_MASK_DATA[index] = 0;
    945         psTrace("psModules.imcombine", 3, "Stamp %d (%.1f,%.1f) widths: %d, %d --> %f\n",
    946                 index, stamp->x, stamp->y, width1, width2, ratios->data.F32[index]);
     986        ratios->data.F32[index] = (float)width1 / (float)width2;
     987        mask->data.PS_TYPE_VECTOR_MASK_DATA[index] = 0;
     988        psTrace("psModules.imcombine", 3, "Stamp %d (%.1f,%.1f) widths: %d, %d --> %f\n",
     989                index, stamp->x, stamp->y, width1, width2, ratios->data.F32[index]);
    947990    }
    948991
     
    9781021    psVector *modelSums = psVectorAlloc(size, PS_TYPE_F64); // Gaussian model sums
    9791022    for (int sigma = 0; sigma < size; sigma++) {
    980         psKernel *model = psKernelAlloc(-size, size, -size, size); // Gaussian model
    981         float invSigma2 = 1.0 / (float)PS_SQR(1 + sigma); // Inverse sigma squared
    982         double sumGG = 0.0;         // Sum of square of Gaussian
    983         for (int y = -size; y <= size; y++) {
    984             int y2 = PS_SQR(y);     // y squared
    985             for (int x = -size; x <= size; x++) {
    986                 float rad2 = PS_SQR(x) + y2; // Radius squared
    987                 float value = expf(-rad2 * invSigma2); // Model value
    988                 model->kernel[y][x] = value;
    989                 sumGG += PS_SQR(value);
    990             }
    991         }
    992         models->data[sigma] = model;
    993         modelSums->data.F64[sigma] = 1.0 / sumGG;
     1023        psKernel *model = psKernelAlloc(-size, size, -size, size); // Gaussian model
     1024        float invSigma2 = 1.0 / (float)PS_SQR(1 + sigma); // Inverse sigma squared
     1025        double sumGG = 0.0;         // Sum of square of Gaussian
     1026        for (int y = -size; y <= size; y++) {
     1027            int y2 = PS_SQR(y);     // y squared
     1028            for (int x = -size; x <= size; x++) {
     1029                float rad2 = PS_SQR(x) + y2; // Radius squared
     1030                float value = expf(-rad2 * invSigma2); // Model value
     1031                model->kernel[y][x] = value;
     1032                sumGG += PS_SQR(value);
     1033            }
     1034        }
     1035        models->data[sigma] = model;
     1036        modelSums->data.F64[sigma] = 1.0 / sumGG;
    9941037    }
    9951038
    9961039    // Fit models to stamps
    9971040    for (int i = 0; i < stamps->num; i++) {
    998         pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
    999         if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE && stamp->status != PM_SUBTRACTION_STAMP_USED) {
    1000             mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff;
    1001             continue;
    1002         }
    1003 
    1004         if (pmSubtractionThreaded()) {
    1005             psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_ORDER");
    1006             psArrayAdd(job->args, 1, ratios);
    1007             psArrayAdd(job->args, 1, mask);
    1008             psArrayAdd(job->args, 1, stamps);
    1009             psArrayAdd(job->args, 1, models);
    1010             psArrayAdd(job->args, 1, modelSums);
    1011             PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32);
    1012             PS_ARRAY_ADD_SCALAR(job->args, bg1, PS_TYPE_F32);
    1013             PS_ARRAY_ADD_SCALAR(job->args, bg2, PS_TYPE_F32);
    1014             if (!psThreadJobAddPending(job)) {
    1015                 return false;
    1016             }
    1017         } else {
    1018             if (!pmSubtractionOrderStamp(ratios, mask, stamps, models, modelSums, i, bg1, bg2)) {
    1019                 psError(psErrorCodeLast(), false, "Unable to measure PSF width for stamp %d", i);
    1020                 psFree(models);
    1021                 psFree(modelSums);
    1022                 psFree(ratios);
    1023                 psFree(mask);
    1024                 return false;
    1025             }
    1026         }
     1041        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
     1042        if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE && stamp->status != PM_SUBTRACTION_STAMP_USED) {
     1043            mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff;
     1044            continue;
     1045        }
     1046
     1047        if (pmSubtractionThreaded()) {
     1048            psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_ORDER");
     1049            psArrayAdd(job->args, 1, ratios);
     1050            psArrayAdd(job->args, 1, mask);
     1051            psArrayAdd(job->args, 1, stamps);
     1052            psArrayAdd(job->args, 1, models);
     1053            psArrayAdd(job->args, 1, modelSums);
     1054            PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32);
     1055            PS_ARRAY_ADD_SCALAR(job->args, bg1, PS_TYPE_F32);
     1056            PS_ARRAY_ADD_SCALAR(job->args, bg2, PS_TYPE_F32);
     1057            if (!psThreadJobAddPending(job)) {
     1058                return false;
     1059            }
     1060        } else {
     1061            if (!pmSubtractionOrderStamp(ratios, mask, stamps, models, modelSums, i, bg1, bg2)) {
     1062                psError(psErrorCodeLast(), false, "Unable to measure PSF width for stamp %d", i);
     1063                psFree(models);
     1064                psFree(modelSums);
     1065                psFree(ratios);
     1066                psFree(mask);
     1067                return false;
     1068            }
     1069        }
    10271070    }
    10281071
    10291072    if (!psThreadPoolWait(true)) {
    1030         psError(psErrorCodeLast(), false, "Error waiting for threads.");
    1031         psFree(models);
    1032         psFree(modelSums);
    1033         psFree(ratios);
    1034         psFree(mask);
    1035             return false;
     1073        psError(psErrorCodeLast(), false, "Error waiting for threads.");
     1074        psFree(models);
     1075        psFree(modelSums);
     1076        psFree(ratios);
     1077        psFree(mask);
     1078        return false;
    10361079    }
    10371080
     
    10411084    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
    10421085    if (!psVectorStats(stats, ratios, NULL, mask, 0xff)) {
    1043         psError(psErrorCodeLast(), false, "Unable to calculate statistics for moments ratio.");
    1044         psFree(mask);
    1045         psFree(ratios);
    1046         psFree(stats);
    1047         return PM_SUBTRACTION_MODE_ERR;
     1086        psError(psErrorCodeLast(), false, "Unable to calculate statistics for moments ratio.");
     1087        psFree(mask);
     1088        psFree(ratios);
     1089        psFree(stats);
     1090        return PM_SUBTRACTION_MODE_ERR;
    10481091    }
    10491092    psFree(ratios);
     
    10521095    // XXX raise an error here or not?
    10531096    if (isnan(stats->robustMedian)) {
    1054         psFree(stats);
    1055         return PM_SUBTRACTION_MODE_ERR;
     1097        psFree(stats);
     1098        return PM_SUBTRACTION_MODE_ERR;
    10561099    }
    10571100
     
    10661109// Test a subtraction mode by performing a single iteration
    10671110static bool subtractionModeTest(pmSubtractionStampList *stamps, // Stamps to use to find best mode
    1068                                 pmSubtractionKernels *kernels, // Kernel description
    1069                                 const char *description, // Description for trace
    1070                                 psImage *subMask,  // Subtraction mask
    1071                                 float rej               // Rejection threshold
    1072                                 )
     1111                                pmSubtractionKernels *kernels, // Kernel description
     1112                                const char *description, // Description for trace
     1113                                psImage *subMask,  // Subtraction mask
     1114                                float rej               // Rejection threshold
     1115    )
    10731116{
    10741117    assert(stamps);
    10751118    assert(kernels);
    10761119
     1120    psAbort("this function is not working");
     1121# if (0)
     1122    psTrace("psModules.imcombine", 3, "Convolving stamps as needed...\n");
     1123    if (!pmSubtractionConvolveStamps(stamps, kernels)) {
     1124        psError(psErrorCodeLast(), false, "Unable to convolve stamps.");
     1125        return false;
     1126    }
     1127
    10771128    psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description);
    1078     if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) {
    1079         psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    1080         return false;
     1129    if (!pmSubtractionCalculateEquation(stamps, kernels)) {
     1130        psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1131        return false;
    10811132    }
    10821133
    10831134    psTrace("psModules.imcombine", 3, "Solving %s normalization equation...\n", description);
    1084     if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) {
    1085         psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    1086         return false;
     1135    if (!pmSubtractionSolveEquation(kernels, stamps)) {
     1136        psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1137        return false;
    10871138    }
    10881139
     
    10901141    psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
    10911142    if (!deviations) {
    1092         psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
    1093         return false;
    1094     }
    1095 
     1143        psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
     1144        return false;
     1145    }
     1146
     1147    // XXX this needs to be made consistent with the modified 'reject stamps' function
    10961148    psTrace("psModules.imcombine", 3, "Rejecting %s stamps...\n", description);
    10971149    long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej);
    10981150    if (numRejected < 0) {
    1099         psError(psErrorCodeLast(), false, "Unable to reject stamps.");
    1100         psFree(deviations);
    1101         return false;
     1151        psError(psErrorCodeLast(), false, "Unable to reject stamps.");
     1152        psFree(deviations);
     1153        return false;
    11021154    }
    11031155    psFree(deviations);
    11041156
    11051157    if (numRejected > 0) {
    1106         // Allow re-fit with reduced stamps set
    1107         psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description);
    1108         if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_ALL)) {
    1109             psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    1110             return false;
    1111         }
    1112 
    1113         psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description);
    1114         if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_ALL)) {
    1115             psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
    1116             return false;
    1117         }
    1118         psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description);
    1119 
    1120         psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
    1121         if (!deviations) {
    1122             psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
    1123             return false;
    1124         }
    1125         psTrace("psModules.imcombine", 3, "Measuring %s quality...\n", description);
    1126         long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN);
    1127         if (numRejected < 0) {
    1128             psError(psErrorCodeLast(), false, "Unable to reject stamps.");
    1129             psFree(deviations);
    1130             return false;
    1131         }
    1132         psFree(deviations);
    1133     }
    1134 
     1158        // Allow re-fit with reduced stamps set
     1159        psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description);
     1160        if (!pmSubtractionCalculateEquation(stamps, kernels)) {
     1161            psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1162            return false;
     1163        }
     1164
     1165        psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description);
     1166        if (!pmSubtractionSolveEquation(kernels, stamps)) {
     1167            psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1168            return false;
     1169        }
     1170        psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description);
     1171
     1172        psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
     1173        if (!deviations) {
     1174            psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
     1175            return false;
     1176        }
     1177        psTrace("psModules.imcombine", 3, "Measuring %s quality...\n", description);
     1178        long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN);
     1179        if (numRejected < 0) {
     1180            psError(psErrorCodeLast(), false, "Unable to reject stamps.");
     1181            psFree(deviations);
     1182            return false;
     1183        }
     1184        psFree(deviations);
     1185    }
     1186# endif
    11351187    return true;
    11361188}
     
    11381190
    11391191pmSubtractionMode pmSubtractionBestMode(pmSubtractionStampList **stamps, pmSubtractionKernels **kernels,
    1140                                         const psImage *subMask, float rej)
     1192                                        const psImage *subMask, float rej)
    11411193{
    11421194    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(*stamps, PM_SUBTRACTION_MODE_ERR);
     
    11501202
    11511203    if (!subtractionModeTest(stamps1, kernels1, "convolve 1", subMask1, rej)) {
    1152         psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 1");
    1153         psFree(stamps1);
    1154         psFree(kernels1);
    1155         psFree(subMask1);
    1156         return PM_SUBTRACTION_MODE_ERR;
     1204        psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 1");
     1205        psFree(stamps1);
     1206        psFree(kernels1);
     1207        psFree(subMask1);
     1208        return PM_SUBTRACTION_MODE_ERR;
    11571209    }
    11581210    psFree(subMask1);
     
    11651217
    11661218    if (!subtractionModeTest(stamps2, kernels2, "convolve 2", subMask2, rej)) {
    1167         psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 2");
    1168         psFree(stamps2);
    1169         psFree(kernels2);
    1170         psFree(subMask2);
    1171         psFree(stamps1);
    1172         psFree(kernels1);
    1173         return PM_SUBTRACTION_MODE_ERR;
     1219        psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 2");
     1220        psFree(stamps2);
     1221        psFree(kernels2);
     1222        psFree(subMask2);
     1223        psFree(stamps1);
     1224        psFree(kernels1);
     1225        return PM_SUBTRACTION_MODE_ERR;
    11741226    }
    11751227    psFree(subMask2);
     
    11791231    pmSubtractionKernels *bestKernels = NULL; // Best choice for kernels
    11801232    psLogMsg("psModules.imcombine", PS_LOG_INFO,
    1181              "Image 1: %f +/- %f from %d stamps\nImage 2: %f +/- %f from %d stamps\n",
    1182              kernels1->mean, kernels1->rms, kernels1->numStamps,
    1183              kernels2->mean, kernels2->rms, kernels2->numStamps);
     1233             "Image 1: %f +/- %f from %d stamps\nImage 2: %f +/- %f from %d stamps\n",
     1234             kernels1->mean, kernels1->rms, kernels1->numStamps,
     1235             kernels2->mean, kernels2->rms, kernels2->numStamps);
    11841236
    11851237    if (kernels1->mean < kernels2->mean) {
    1186         bestStamps = stamps1;
    1187         bestKernels = kernels1;
     1238        bestStamps = stamps1;
     1239        bestKernels = kernels1;
    11881240    } else {
    1189         bestStamps = stamps2;
    1190         bestKernels = kernels2;
     1241        bestStamps = stamps2;
     1242        bestKernels = kernels2;
    11911243    }
    11921244
     
    12041256}
    12051257
    1206 
    1207 bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths,
    1208                               float scaleRef, float scaleMin, float scaleMax)
     1258static float scaleRefOption = NAN;
     1259static float scaleMinOption = NAN;
     1260static float scaleMaxOption = NAN;
     1261static bool  scaleOption = false;
     1262
     1263bool pmSubtractionParamScaleOptions(bool scale, float scaleRef, float scaleMin, float scaleMax) {
     1264
     1265    if (scale) {
     1266        PS_ASSERT_FLOAT_LARGER_THAN(scaleRef, 0.0, false);
     1267        PS_ASSERT_FLOAT_LARGER_THAN(scaleMin, 0.0, false);
     1268        PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, 0.0, false);
     1269        PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, scaleMin, false);
     1270    }
     1271
     1272    scaleRefOption = scaleRef;
     1273    scaleMinOption = scaleMin;
     1274    scaleMaxOption = scaleMax;
     1275    scaleOption = scale;
     1276   
     1277    return true;
     1278}
     1279
     1280bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths, float fwhm1, float fwhm2)
    12091281{
    1210     PS_ASSERT_PTR_NON_NULL(kernelSize, false);
    1211     PS_ASSERT_PTR_NON_NULL(stampSize, false);
     1282    // PS_ASSERT_PTR_NON_NULL(kernelSize, false);
     1283    // PS_ASSERT_PTR_NON_NULL(stampSize, false);
    12121284    PS_ASSERT_VECTOR_NON_NULL(widths, false);
    12131285    PS_ASSERT_VECTOR_TYPE(widths, PS_TYPE_F32, false);
    1214     PS_ASSERT_FLOAT_LARGER_THAN(scaleRef, 0.0, false);
    1215     PS_ASSERT_FLOAT_LARGER_THAN(scaleMin, 0.0, false);
    1216     PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, 0.0, false);
    1217     PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, scaleMin, false);
    1218 
    1219     float fwhm1;
    1220     float fwhm2;
    1221 
    1222     pmSubtractionGetFWHMs(&fwhm1, &fwhm2);
    1223     psAssert(isfinite(fwhm1), "fwhm 1 not set");
    1224     psAssert(isfinite(fwhm2), "fwhm 2 not set");
     1286
     1287    if (!scaleOption) return true;
     1288
     1289    // pmSubtractionGetFWHMs(&fwhm1, &fwhm2);
     1290    // psAssert(isfinite(fwhm1), "fwhm 1 not set");
     1291    // psAssert(isfinite(fwhm2), "fwhm 2 not set");
    12251292   
    12261293    // float diff = sqrtf(PS_SQR(PS_MAX(fwhm1, fwhm2)) - PS_SQR(PS_MIN(fwhm1, fwhm2))); // Difference
    1227     float scale = PS_MAX(fwhm1, fwhm2) / scaleRef;      // Scaling factor
    1228 
    1229     if (isfinite(scaleMin) && scale < scaleMin) {
    1230         scale = scaleMin;
    1231     }
    1232     if (isfinite(scaleMax) && scale > scaleMax) {
    1233         scale = scaleMax;
     1294    float scale = PS_MAX(fwhm1, fwhm2) / scaleRefOption;      // Scaling factor
     1295
     1296    if (isfinite(scaleMinOption) && scale < scaleMinOption) {
     1297        scale = scaleMinOption;
     1298    }
     1299    if (isfinite(scaleMaxOption) && scale > scaleMaxOption) {
     1300        scale = scaleMaxOption;
    12341301    }
    12351302
    12361303    for (int i = 0; i < widths->n; i++) {
    1237         widths->data.F32[i] *= scale;
    1238     }
    1239     *kernelSize = *kernelSize * scale + 0.5;
    1240     *stampSize = *stampSize * scale + 0.5;
    1241 
    1242     psLogMsg("psModules.imcombine", PS_LOG_INFO,
    1243              "Scaling kernel parameters by %f: %d %d", scale, *kernelSize, *stampSize);
     1304        widths->data.F32[i] *= scale;
     1305    }
     1306    if (kernelSize) {
     1307        *kernelSize = *kernelSize * scale + 0.5;
     1308    }
     1309    if (stampSize) {
     1310        *stampSize = *stampSize * scale + 0.5;
     1311    }
     1312
     1313    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Scaling kernel parameters by %f", scale);
     1314    if (kernelSize) psLogMsg("psModules.imcombine", PS_LOG_INFO, " modified kernel size %d", *kernelSize);
     1315    if (stampSize) psLogMsg("psModules.imcombine", PS_LOG_INFO, " modified stamp size %d", *stampSize);
    12441316
    12451317    return true;
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionMatch.h

    r29543 r30631  
    88#include <pmSubtractionKernels.h>
    99#include <pmSubtractionStamps.h>
     10#include <pmSubtraction.h>
    1011
    1112/// Match two images
     
    2627                        int size,       ///< Kernel half-size
    2728                        int order,      ///< Spatial polynomial order
    28                         const psVector *widths, ///< ISIS Gaussian widths
     29                        psVector *widths, ///< ISIS Gaussian widths
    2930                        const psVector *orders, ///< ISIS Polynomial orders
    3031                        int inner,      ///< Inner radius for various kernel types
     
    100101
    101102/// Scale subtraction parameters according to the FWHMs of the inputs
    102 bool pmSubtractionParamsScale(
    103     int *kernelSize,                    ///< Half-size of the kernel
    104     int *stampSize,                     ///< Half-size of the stamp (footprint)
    105     psVector *widths,                   ///< ISIS widths
    106     float scaleRef,                     ///< Reference width for scaling
    107     float scaleMin,                     ///< Minimum scaling ratio, or NAN
    108     float scaleMax                      ///< Maximum scaling ratio, or NAN
     103// bool pmSubtractionParamsScale(
     104//     int *kernelSize,                    ///< Half-size of the kernel
     105//     int *stampSize,                     ///< Half-size of the stamp (footprint)
     106//     psVector *widths,                   ///< ISIS widths
     107//     float scaleRef,                     ///< Reference width for scaling
     108//     float scaleMin,                     ///< Minimum scaling ratio, or NAN
     109//     float scaleMax                      ///< Maximum scaling ratio, or NAN
     110//     );
     111
     112bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths, float fwhm1, float fwhm2);
     113
     114bool pmSubtractionParamScaleOptions(bool scale, float scaleRef, float scaleMin, float scaleMax);
     115
     116bool pmSubtractionMatchAttempt(
     117    pmSubtractionQuality **bestMatch,
     118    pmSubtractionKernels *kernels,
     119    pmSubtractionStampList *stamps,
     120    pmSubtractionMode mode,
     121    int spatialOrder,
     122    bool final
    109123    );
    110124
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionParams.c

    r27086 r30631  
    99
    1010#include "pmErrorCodes.h"
     11#include "pmFPA.h"
     12#include "pmSubtractionTypes.h"
     13#include "pmSubtraction.h"
    1114#include "pmSubtractionStamps.h"
    12 #include "pmSubtraction.h"
    1315#include "pmSubtractionParams.h"
    1416
     
    1618
    1719#if 0
     20// XXX this was moved to pmSubtraction.c in r15443 -- delete
    1821// Convolve the reference stamp by the kernel
    1922static psKernel *convolveStamp(const pmSubtractionStamp *stamp, // Stamp to be convolved
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionStamps.c

    r29543 r30631  
    2727#include "pmSource.h"
    2828
     29#include "pmSubtractionTypes.h"
    2930#include "pmSubtraction.h"
    3031#include "pmSubtractionStamps.h"
     32#include "pmSubtractionVisual.h"
    3133
    3234#define STAMP_LIST_BUFFER 20            // Number of stamps to add to list at a time
     
    122124            if ((image1 && image1->data.F32[y][x] < thresh1) ||
    123125                (image2 && image2->data.F32[y][x] < thresh2)) {
     126                // fprintf (stderr, "%f,%f : thresh\n", xRaw, yRaw);
    124127                continue;
    125128            }
     
    366369}
    367370
    368 
    369 pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps, const psImage *image1,
    370                                                 const psImage *image2, const psImage *subMask,
    371                                                 const psRegion *region, float thresh1, float thresh2,
    372                                                 int size, int footprint, float spacing, float normFrac,
    373                                                 float sysErr, float skyErr, pmSubtractionMode mode)
     371bool pmSubtractionStampsSelect(pmSubtractionStampList **stamps, // Stamps to read
     372                               const pmReadout *ro1, // Readout 1
     373                               const pmReadout *ro2, // Readout 2
     374                               const psImage *subMask, // Mask for subtraction, or NULL
     375                               psImage *variance,  // Variance map
     376                               const psRegion *region, // Region of interest
     377                               float thresh1,  // Threshold for stamp finding on readout 1
     378                               float thresh2,  // Threshold for stamp finding on readout 2
     379                               float stampSpacing, // Spacing between stamps
     380                               float normFrac,     // Fraction of flux in window for normalisation window
     381                               float sysError,     // Relative systematic error in images
     382                               float skyError,     // Relative systematic error in images
     383                               int size,         // Kernel half-size
     384                               int footprint,     // Convolution footprint for stamps
     385                               pmSubtractionMode mode // Mode for subtraction
     386    )
     387{
     388    PS_ASSERT_PTR_NON_NULL(stamps, false);
     389    PM_ASSERT_READOUT_NON_NULL(ro1, false);
     390    PM_ASSERT_READOUT_NON_NULL(ro2, false);
     391    PS_ASSERT_IMAGE_NON_NULL(subMask, false);
     392    PS_ASSERT_IMAGE_NON_NULL(variance, false);
     393    PS_ASSERT_PTR_NON_NULL(region, false);
     394
     395    psTrace("psModules.imcombine", 3, "Finding stamps...\n");
     396
     397    psImage *image1 = ro1 ? ro1->image : NULL, *image2 = ro2 ? ro2->image : NULL; // Images of interest
     398
     399    *stamps = pmSubtractionStampsFind(*stamps, image1, image2, subMask, region, thresh1, thresh2,
     400                                      size, footprint, stampSpacing, normFrac, sysError, skyError, mode);
     401    if (!*stamps) {
     402        psError(psErrorCodeLast(), false, "Unable to find stamps.");
     403        return false;
     404    }
     405
     406    psTrace("psModules.imcombine", 3, "Extracting stamps...\n");
     407    if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2->image, variance, size, *region)) {
     408        psError(psErrorCodeLast(), false, "Unable to extract stamps.");
     409        return false;
     410    }
     411
     412    pmSubtractionVisualPlotStamps(*stamps, (pmReadout *) ro1);
     413    return true;
     414}
     415
     416pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps,
     417                                                const psImage *image1,
     418                                                const psImage *image2,
     419                                                const psImage *subMask,
     420                                                const psRegion *region,
     421                                                float thresh1,
     422                                                float thresh2,
     423                                                int size,
     424                                                int footprint,
     425                                                float spacing,
     426                                                float normFrac,
     427                                                float sysErr,
     428                                                float skyErr,
     429                                                pmSubtractionMode mode)
    374430{
    375431    if (!image1 && !image2) {
     
    429485        stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing,
    430486                                             normFrac, sysErr, skyErr);
     487    }
     488
     489    // XXX TEST : dump all stars in the stamps here
     490    if (0) {
     491        FILE *f = fopen ("stamp.dat", "w");
     492        for (int i = 0; i < stamps->num; i++) {
     493            psVector *xList = stamps->x->data[i];
     494            psVector *yList = stamps->y->data[i]; // Coordinate lists
     495            psVector *fluxList = stamps->flux->data[i]; // List of stamp fluxes
     496
     497            for (int j = 0; j < xList->n; j++) {
     498                fprintf (f, "%d %d  %f %f  %f\n", i, j, xList->data.F32[j], yList->data.F32[j], fluxList->data.F32[j]);
     499            }
     500        }
     501        fclose (f);
    431502    }
    432503
     
    636707    }
    637708
     709    int nTotal = 0;
     710
    638711    // Sort the list by flux, with the brightest last
    639712    for (int i = 0; i < numStamps; i++) {
     
    662735        stamps->y->data[i] = ySorted;
    663736        stamps->flux->data[i] = fluxSorted;
    664     }
    665 
     737        nTotal += num;
     738    }
     739    // fprintf (stderr, "nTotal %d\n", nTotal);
     740   
    666741    return stamps;
    667742}
    668743
    669 
    670 bool pmSubtractionStampsGetWindow(pmSubtractionStampList *stamps, int kernelSize)
     744// we are essentially using aperture photometry to determine the photometric match between the
     745// images.  we need to choose an appropriate-sized aperture for this analysis.  If it is too
     746// large, the measurement will be noisy (and possibly biased) due to the sky noise.  If it is
     747// too small, or inconsistent, the measurement will be biased.  We use Kron-mag like aperture
     748// scaled by the first radial moment.
     749bool pmSubtractionStampsGetWindow(bool *tryAgain, pmSubtractionStampList *stamps, int kernelSize)
    671750{
    672751    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
    673752    PS_ASSERT_INT_NONNEGATIVE(kernelSize, false);
    674753
     754    // if we succeed, or fail with an unrecoverable error, do not try again
     755    if (tryAgain) {
     756        *tryAgain = false;
     757    }
     758
    675759    int size = stamps->footprint; // Size of postage stamps
    676760
     761    // window for moments calculations downstream
     762    psFree (stamps->window);
     763    stamps->window = psKernelAlloc(-size, size, -size, size);
     764    psImageInit(stamps->window->image, 0.0);
     765
     766    // window1 and window2 are mean stamp images used here to measure the
     767    // first radial moment, and thus the normalization window
    677768    psFree (stamps->window1);
    678769    stamps->window1 = psKernelAlloc(-size, size, -size, size);
     
    683774    psImageInit(stamps->window2->image, 0.0);
    684775
    685     // Generate a weighting window based on the fwhms (20% larger than the largest)
    686     {
    687         float fwhm1, fwhm2;
    688 
    689         // XXX this is annoyingly hack-ish
    690         pmSubtractionGetFWHMs(&fwhm1, &fwhm2);
    691 
    692         float sigma = 1.5 * PS_MAX(fwhm1, fwhm2) / 2.35;
    693 
    694         psFree (stamps->window);
    695         stamps->window = psKernelAlloc(-size, size, -size, size);
    696         psImageInit(stamps->window->image, 0.0);
    697 
    698         for (int y = -size; y <= size; y++) {
    699             for (int x = -size; x <= size; x++) {
    700                 stamps->window->kernel[y][x] = exp(-0.5*(x*x + y*y)/(sigma*sigma));
    701             }
    702         }
     776    // Generate an initial weighting window based on the fwhms (50% larger than the largest)
     777    float fwhm1, fwhm2;
     778
     779    // XXX this is annoyingly hack-ish
     780    pmSubtractionGetFWHMs(&fwhm1, &fwhm2);
     781   
     782    float sigma = 1.5 * PS_MAX(fwhm1, fwhm2) / 2.35;
     783   
     784    for (int y = -size; y <= size; y++) {
     785        for (int x = -size; x <= size; x++) {
     786            stamps->window->kernel[y][x] = exp(-0.5*(x*x + y*y)/(sigma*sigma));
     787        }
    703788    }
    704789
     
    790875    psTrace("psModules.imcombine", 3, "Window total (2): %f, threshold: %f\n", sum2, (1.0 - stamps->normFrac) * sum2);
    791876
    792 # if (1)
    793     // this block attempts to calculate the radius based on the first radial moment
     877    // attempt to calculate the normalization window based on the first radial moment
    794878    double Sr1 = 0.0;
    795879    double Sr2 = 0.0;
     
    809893    float R2 = Sr2 / Sf2;
    810894
    811     stamps->normWindow1 = 2.0*R1;
    812     stamps->normWindow2 = 2.0*R2;
    813     psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Kron Radii: %f for 1, %f for 2\n", stamps->normWindow1, stamps->normWindow2);
    814 
    815 # else
    816     // XXX : this block attempts to calculate the radius by looking at the curve of growth (or something vaguely equivalent).
    817     // It did not do very well (though a true curve-of-growth analysis might be better...)
    818     bool done1 = false;
    819     bool done2 = false;
    820     double prior1 = 0.0;
    821     double prior2 = 0.0;
    822     double delta1o = 1.0;
    823     double delta2o = 1.0;
    824     for (int radius = 1; radius <= size && !(done1 && done2); radius++) {
    825         double within1 = 0.0;
    826         double within2 = 0.0;
    827         for (int y = -radius; y <= radius; y++) {
    828             for (int x = -radius; x <= radius; x++) {
    829                 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) {
    830                     within1 += stamps->window1->kernel[y][x];
    831                 }
    832                 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) {
    833                     within2 += stamps->window2->kernel[y][x];
    834                 }
    835             }
    836         }
    837         double delta1 = (within1 - prior1) / within1;
    838         if (!done1 && (fabs(delta1) < stamps->normFrac)) {
    839             // interpolate to the radius at which delta2 is normFrac:
    840             stamps->normWindow1 = radius - (stamps->normFrac - delta1) / (delta1o - delta1);
    841             psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "choosing %f (%d) for 1 (%f : %f)\n", stamps->normWindow1, radius, within1, delta1);
    842             done1 = true;
    843         }
    844         double delta2 = (within2 - prior2) / within2;
    845         if (!done2 && (fabs(delta2) < stamps->normFrac)) {
    846             // interpolate to the radius at which delta2 is normFrac:
    847             stamps->normWindow2 = radius - (stamps->normFrac - delta2) / (delta2o - delta2);
    848             psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "choosing %f (%d) for 2 (%f : %f)\n", stamps->normWindow2, radius, within2, delta2);
    849             done2 = true;
    850         }
    851         psTrace("psModules.imcombine", 5, "Radius %d: %f (%f) and %f (%f)\n", radius, within1, delta1, within2, delta2);
    852 
    853         prior1 = within1;
    854         prior2 = within2;
    855         delta1o = delta1;
    856         delta2o = delta2;
    857 
    858         // if (!done1 && (within1 > (1.0 - stamps->normFrac) * sum1)) {
    859         //     stamps->normWindow1 = radius;
    860         //     done1 = true;
    861         // }
    862         // if (!done2 && (within2 > (1.0 - stamps->normFrac) * sum2)) {
    863         //     stamps->normWindow2 = radius;
    864         //     done2 = true;
    865         // }
    866 
    867     }
    868 # endif
    869 
    870     psTrace("psModules.imcombine", 3, "Normalisation window radii set to %f and %f\n", stamps->normWindow1, stamps->normWindow2);
    871     if (stamps->normWindow1 == 0 || stamps->normWindow1 >= size) {
     895    // Compare the Kron Radii (R1 & R2) to above to the FWHMs : if they are too discrepant, we will need to rescale
     896    psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Kron Radii vs FWHMs 1: fwhm: %f, kron %f\n", fwhm1, R1);
     897    psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Kron Radii vs FWHMs 2: fwhm: %f, kron %f\n", fwhm2, R2);
     898
     899    // XXX CAREFUL : in pmSubtractionMatch.c:703, we rely on this factor of 2.75..
     900    stamps->normWindow1 = 2.75*R1;
     901    stamps->normWindow2 = 2.75*R2;
     902    psLogMsg ("psModules.imcombine", PS_LOG_DETAIL, "Windows from Kron Radii: %f for 1, %f for 2\n", stamps->normWindow1, stamps->normWindow2);
     903
     904    // if the calculated normWindows are too large, we will fall off the stamps.  In this case, we need to try again.
     905    if ((stamps->normWindow1 > size) || (stamps->normWindow2 > size)) {
     906        if (tryAgain) {
     907            *tryAgain = true;
     908        }
     909        psFree (stats);
     910        psFree (flux1);
     911        psFree (flux2);
     912        psFree (norm1);
     913        psFree (norm2);
     914        return false;
     915    }
     916
     917    // this is an unrecoverable error : something really bogus in the data
     918    if (stamps->normWindow1 == 0) {
    872919        psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size (1).");
     920        psFree (stats);
     921        psFree (flux1);
     922        psFree (flux2);
     923        psFree (norm1);
     924        psFree (norm2);
    873925        return false;
    874926    }
    875     if (stamps->normWindow2 == 0 || stamps->normWindow2 >= size) {
     927    if (stamps->normWindow2 == 0) {
    876928        psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size (2).");
     929        psFree (stats);
     930        psFree (flux1);
     931        psFree (flux2);
     932        psFree (norm1);
     933        psFree (norm2);
    877934        return false;
     935    }
     936
     937    // Generate a weighting window based on the kron radii
     938    float radius = 2.0 * PS_MAX(R1, R2);
     939    psImageInit(stamps->window->image, 0.0);
     940
     941    // we use a top-hat window for the moments analysis
     942    for (int y = -size; y <= size; y++) {
     943        for (int x = -size; x <= size; x++) {
     944            if (hypot(x,y) > radius) continue;
     945            stamps->window->kernel[y][x] = 1.0;
     946        }
    878947    }
    879948
     
    890959        }
    891960    }
    892 
    893 #if 0
    894     {
    895         psFits *fits = NULL;
    896         fits = psFitsOpen ("window1.norm.fits", "w");
    897         psFitsWriteImage (fits, NULL, stamps->window1->image, 0, NULL);
    898         psFitsClose (fits);
    899         fits = psFitsOpen ("window2.norm.fits", "w");
    900         psFitsWriteImage (fits, NULL, stamps->window2->image, 0, NULL);
    901         psFitsClose (fits);
    902     }
    903 #endif
    904961
    905962    psFree (stats);
     
    11281185            continue;
    11291186        }
     1187       
     1188        // XXX this is somewhat arbitrary...
     1189        if (source->errMag > 0.05) continue;
     1190        if (fabs(source->psfMag - source->apMag) > 0.5) continue;
     1191
    11301192        if (source->modelPSF) {
    11311193            x->data.F32[numOut] = source->modelPSF->params->data.F32[PM_PAR_XPOS];
     
    11351197            y->data.F32[numOut] = source->peak->yf;
    11361198        }
    1137         // fprintf (stderr, "stamp: %5.1f %5.1f\n", x->data.F32[numOut], y->data.F32[numOut]);
    11381199        numOut++;
    11391200    }
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionStamps.h

    r29543 r30631  
    11#ifndef PM_SUBTRACTION_STAMPS_H
    22#define PM_SUBTRACTION_STAMPS_H
    3 
    4 #include <pslib.h>
    5 
    6 #include "pmSubtractionKernels.h"
    7 
    8 /// Status of stamp
    9 typedef enum {
    10     PM_SUBTRACTION_STAMP_INIT,          ///< Initial state
    11     PM_SUBTRACTION_STAMP_FOUND,         ///< Found a suitable source for this stamp
    12     PM_SUBTRACTION_STAMP_CALCULATE,     ///< Calculate matrix and vector values for this stamp
    13     PM_SUBTRACTION_STAMP_USED,          ///< Use this stamp
    14     PM_SUBTRACTION_STAMP_REJECTED,      ///< This stamp has been rejected
    15     PM_SUBTRACTION_STAMP_NONE           ///< No stamp in this region
    16 } pmSubtractionStampStatus;
    17 
    18 /// A list of stamps
    19 typedef struct {
    20     long num;                           ///< Number of stamps
    21     psArray *stamps;                    ///< The stamps
    22     psArray *regions;                   ///< Regions for each stamp
    23     psArray *x, *y;                     ///< Coordinates for possible stamps (or NULL)
    24     psArray *flux;                      ///< Fluxes for possible stamps (or NULL)
    25     int footprint;                      ///< Half-size of stamps
    26     float normFrac;                     ///< Fraction of flux in window for normalisation window
    27     float normValue;                    ///< calculated normalization
    28     float normValue2;                   ///< calculated normalization
    29     psKernel *window1;                  ///< window function generated from ensemble of stamps (input 1)
    30     psKernel *window2;                  ///< window function generated from ensemble of stamps (input 2)
    31     psKernel *window;                   ///< weighting window function (sigma = 1.1 * MAX(fwhm))
    32     float normWindow1;                  ///< Size of window for measuring normalisation
    33     float normWindow2;                  ///< Size of window for measuring normalisation
    34     float sysErr;                       ///< Systematic error
    35     float skyErr;                       ///< increase effective readnoise
    36 } pmSubtractionStampList;
    373
    384/// Allocate a list of stamps
     
    7440    );
    7541
    76 
    77 /// A stamp for image subtraction
    78 typedef struct {
    79     float x, y;                         ///< Position
    80     float flux;                         ///< Flux
    81     float xNorm, yNorm;                 ///< Normalised position
    82     psKernel *image1;                   ///< Reference image postage stamp
    83     psKernel *image2;                   ///< Input image postage stamp
    84     psKernel *weight;                   ///< Weight image (1/variance) postage stamp, or NULL
    85     psArray *convolutions1;             ///< Convolutions of image 1 for each kernel component, or NULL
    86     psArray *convolutions2;             ///< Convolutions of image 2 for each kernel component, or NULL
    87     psImage *matrix;                    ///< Least-squares matrix, or NULL
    88     psVector *vector;                   ///< Least-squares vector, or NULL
    89     double norm;                        ///< Normalisation difference
    90     double normI1;                       ///< Sum(flux) for image 1
    91     double normI2;                       ///< Sum(flux) for image 2
    92     double normSquare1;                 ///< Sum(flux^2) for image 1 (used for penalty)
    93     double normSquare2;                 ///< Sum(flux^2) for image 2 (used for penalty)
    94     pmSubtractionStampStatus status;    ///< Status of stamp
    95     psVector *MxxI1;                    ///< second moments of convolution images
    96     psVector *MyyI1;                    ///< second moments of convolution images
    97     psVector *MxxI2;                    ///< second moments of convolution images
    98     psVector *MyyI2;                    ///< second moments of convolution images
    99     double MxxI1raw;
    100     double MyyI1raw;
    101     double MxxI2raw;
    102     double MyyI2raw;
    103 } pmSubtractionStamp;
    104 
    10542/// Allocate a stamp
    10643pmSubtractionStamp *pmSubtractionStampAlloc(void);
     44
     45// find and extract the stamps
     46bool pmSubtractionStampsSelect(pmSubtractionStampList **stamps, // Stamps to read
     47                               const pmReadout *ro1, // Readout 1
     48                               const pmReadout *ro2, // Readout 2
     49                               const psImage *subMask, // Mask for subtraction, or NULL
     50                               psImage *variance,  // Variance map
     51                               const psRegion *region, // Region of interest
     52                               float thresh1,  // Threshold for stamp finding on readout 1
     53                               float thresh2,  // Threshold for stamp finding on readout 2
     54                               float stampSpacing, // Spacing between stamps
     55                               float normFrac,     // Fraction of flux in window for normalisation window
     56                               float sysError,     // Relative systematic error in images
     57                               float skyError,     // Relative systematic error in images
     58                               int size,         // Kernel half-size
     59                               int footprint,     // Convolution footprint for stamps
     60                               pmSubtractionMode mode // Mode for subtraction
     61    );
     62
    10763
    10864/// Find stamps on an image
     
    172128/// Calculate the window and normalisation window from the stamps
    173129bool pmSubtractionStampsGetWindow(
     130    bool *tryAgain,                     ///< re-try with new stamp size?
    174131    pmSubtractionStampList *stamps,     ///< List of stamps
    175132    int kernelSize                      ///< Half-size of kernel
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionThreads.c

    r27365 r30631  
    66#include <pslib.h>
    77
     8#include "pmSubtractionTypes.h"
    89#include "pmSubtractionMatch.h"
    910#include "pmSubtractionEquation.h"
     
    3334
    3435    {
    35         psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 4);
     36        psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 3);
    3637        task->function = &pmSubtractionCalculateEquationThread;
     38        psThreadTaskAdd(task);
     39        psFree(task);
     40    }
     41
     42    {
     43        psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CONVOLVE_STAMP", 3);
     44        task->function = &pmSubtractionConvolveStampThread;
    3745        psThreadTaskAdd(task);
    3846        psFree(task);
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionVisual.c

    r29600 r30631  
    1616
    1717#include "pmKapaPlots.h"
     18#include "pmFPA.h"
     19#include "pmSubtractionTypes.h"
    1820#include "pmSubtraction.h"
    1921#include "pmSubtractionStamps.h"
    2022#include "pmSubtractionEquation.h"
    2123#include "pmSubtractionKernels.h"
     24#include "pmSubtractionVisual.h"
    2225
    2326#include "pmVisual.h"
     
    210213        psImageOverlaySection(canvas, im, x0, y0, "=");
    211214        stampNum++;
     215
     216        // renormalize the section
     217        float maxValue = 0;
     218        for (int iy = 0; iy < im->numRows; iy++) {
     219            for (int ix = 0; ix < im->numCols; ix++) {
     220                maxValue = PS_MAX(maxValue, im->data.F64[iy][ix]);
     221            }
     222        }
     223        if (maxValue == 0.0) continue;
     224        for (int iy = 0; iy < im->numRows; iy++) {
     225            for (int ix = 0; ix < im->numCols; ix++) {
     226                canvas->data.F64[y0 + iy][x0 + ix] /= maxValue;
     227            }
     228        }
    212229    }
    213230
     
    231248}
    232249
     250/** Plot the least-squares matrix of each stamp */
     251bool pmSubtractionVisualPlotLeastSquaresResid (const pmSubtractionStampList *stamps, psImage *matrixIn, int nUsed) {
     252
     253    if (!pmVisualTestLevel("ppsub.chisq", 1)) return true;
     254
     255    if (!plotLeastSquares) return true;
     256
     257    if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) {
     258        return false;
     259    }
     260
     261    psImage *matrixNorm = psImageCopy(NULL, matrixIn, PS_TYPE_F64);
     262    {
     263        // renormalize the matrix
     264        float maxValue = 0;
     265        for (int iy = 0; iy < matrixNorm->numRows; iy++) {
     266            for (int ix = 0; ix < matrixNorm->numCols; ix++) {
     267                maxValue = PS_MAX(maxValue, matrixNorm->data.F64[iy][ix]);
     268            }
     269        }
     270        for (int iy = 0; iy < matrixNorm->numRows; iy++) {
     271            for (int ix = 0; ix < matrixNorm->numCols; ix++) {
     272                matrixNorm->data.F64[iy][ix] /= maxValue;
     273            }
     274        }
     275    }
     276
     277    // Find the stamp size
     278    int imageMax = -1;
     279    int numStamps = 0;
     280    psElemType type = PS_TYPE_F64;
     281
     282    for(int i = 0; i < stamps->num; i++) {
     283        pmSubtractionStamp *stamp = stamps->stamps->data[i];
     284        if (stamp == NULL) continue;
     285
     286        psImage *im = stamp->matrix;
     287        if (im == NULL) continue;
     288
     289        imageMax = PS_MAX(imageMax, im->numCols);
     290        imageMax = PS_MAX(imageMax, im->numRows);
     291        numStamps++;
     292        type = im->type.type;
     293    }
     294    if (imageMax == -1) return false;
     295
     296    int border = 15;
     297    imageMax += border;
     298    int tileRowCount = (int) ceil(sqrt(numStamps));
     299    int canvasX = tileRowCount * (imageMax);
     300    int canvasY = tileRowCount * (imageMax);
     301    psImage *canvas = psImageAlloc (canvasX, canvasY, type);
     302    psImageInit (canvas, NAN);
     303
     304    // overlay the images
     305    int stampNum = 0;
     306    int stampListNum = 0;
     307    while (stampNum < numStamps) {
     308        int x0 = (imageMax) * (stampNum % tileRowCount);
     309        int y0 = (imageMax) * (stampNum / tileRowCount);
     310
     311        pmSubtractionStamp *stamp = stamps->stamps->data[stampListNum++];
     312        if (stamp == NULL) continue;
     313
     314        psImage *im = stamp->matrix;
     315        if (im == NULL) continue;
     316
     317        stampNum++;
     318
     319        if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue;
     320
     321        // renormalize the section
     322        float maxValue = 0;
     323        for (int iy = 0; iy < im->numRows; iy++) {
     324            for (int ix = 0; ix < im->numCols; ix++) {
     325                maxValue = PS_MAX(maxValue, im->data.F64[iy][ix]);
     326            }
     327        }
     328        if (maxValue == 0.0) continue;
     329        for (int iy = 0; iy < im->numRows; iy++) {
     330            for (int ix = 0; ix < im->numCols; ix++) {
     331                canvas->data.F64[y0 + iy][x0 + ix] = (im->data.F64[iy][ix] / maxValue - matrixNorm->data.F64[iy][ix]) / matrixNorm->data.F64[iy][ix];
     332            }
     333        }
     334    }
     335
     336    psImage *canvas32 = pmVisualImageToFloat(canvas);
     337    pmVisualRangeImage(kapa2, canvas32, "Least_Squares", 0, -100.0, 100.0);
     338
     339    if (0) {
     340        static int count = 0;
     341        char filename[64];
     342        sprintf (filename, "chisq.%02d.fits", count);
     343        count ++;
     344        psFits *fits = psFitsOpen (filename, "w");
     345        psFitsWriteImage (fits, NULL, canvas32, 0, NULL);
     346        psFitsClose (fits);
     347    }
     348
     349    pmVisualAskUser(&plotLeastSquares);
     350    psFree(canvas);
     351    psFree(canvas32);
     352    return true;
     353}
     354
    233355bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) {
    234356
     
    304426    }
    305427
    306     // XXX clear the overlay(s) (red at least!)
     428    // clear the overlay (red at least!)
     429    KiiEraseOverlay (kapa2, "red");
    307430
    308431    // get the kernel sizes
     
    337460    int nKernels = 0;
    338461
     462    // paste in the kernel images, scaled by sum2
    339463    if (maxStamp->convolutions1) {
    340464        // output image is a grid of NXsub by NYsub sub-images
     
    359483            int yPix = ySub * (2*footprint + 1 + 3) + footprint;
    360484           
    361             double sum = 0.0;
    362485            double sum2 = 0.0;
    363486            for (int y = -footprint; y <= footprint; y++) {
    364487                for (int x = -footprint; x <= footprint; x++) {
    365                     output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x];
    366                     sum += kernel->kernel[y][x];
    367488                    sum2 += PS_SQR(kernel->kernel[y][x]);
    368489                }
    369490            }
    370             // fprintf (stderr, "kernel %d, sum %f, sum2: %e\n", i, sum, sum2);
     491            float scale = sqrt(sum2) / PS_SQR(2*footprint + 1);
     492            for (int y = -footprint; y <= footprint; y++) {
     493                for (int x = -footprint; x <= footprint; x++) {
     494                    output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x] / scale;
     495                }
     496            }
    371497        }               
    372498        pmVisualScaleImage(kapa2, output, "Image", 0, true);
     
    401527            int yPix = ySub * (2*footprint + 1 + 3) + footprint;
    402528           
    403             double sum = 0.0;
    404529            double sum2 = 0.0;
    405530            for (int y = -footprint; y <= footprint; y++) {
    406531                for (int x = -footprint; x <= footprint; x++) {
    407                     output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x];
    408                     sum += kernel->kernel[y][x];
    409532                    sum2 += PS_SQR(kernel->kernel[y][x]);
    410533                }
    411534            }
    412             // fprintf (stderr, "kernel %d, sum %f, sum2: %e\n", i, sum, sum2);
     535            float scale = sqrt(sum2) / PS_SQR(2*footprint + 1);
     536            for (int y = -footprint; y <= footprint; y++) {
     537                for (int x = -footprint; x <= footprint; x++) {
     538                    output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x] / scale;
     539                }
     540            }
    413541        }               
    414542        pmVisualScaleImage(kapa2, output, "Image", 1, true);
     
    468596    KiiLoadOverlay (kapa2, overlay, Noverlay, "red");
    469597    FREE (overlay);
    470     return true;
    471 }
    472 
    473 static int footprint = 0;
    474 static int NX = 0;
    475 static int NY = 0;
    476 static psImage *sourceImage      = NULL;
    477 static psImage *targetImage      = NULL;
    478 static psImage *residualImage    = NULL;
    479 static psImage *fresidualImage   = NULL;
    480 static psImage *differenceImage  = NULL;
    481 static psImage *convolutionImage = NULL;
    482 
    483 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) {
    484 
    485     if (!pmVisualTestLevel("ppsub.fit", 1)) return true;
    486 
    487     // generate 4 storage images large enough to hold the N stamps:
    488 
    489     footprint = stamps->footprint;
    490 
    491     float NXf = sqrt(stamps->num);
    492     NX = (int) NXf == NXf ? NXf : NXf + 1.0;
    493    
    494     float NYf = stamps->num / NX;
    495     NY = (int) NYf == NY ? NYf : NYf + 1.0;
    496 
    497     int NXpix = (2*footprint + 1) * NX;
    498     NXpix += (NX > 1) ? 3 * NX : 0;
    499 
    500     int NYpix = (2*footprint + 1) * NY;
    501     NYpix += (NY > 1) ? 3 * NY : 0;
    502 
    503     sourceImage      = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
    504     targetImage      = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
    505     residualImage    = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
    506     fresidualImage   = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
    507     differenceImage  = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
    508     convolutionImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
    509    
    510     psImageInit (sourceImage,      0.0);
    511     psImageInit (targetImage,      0.0);
    512     psImageInit (residualImage,    0.0);
    513     psImageInit (fresidualImage,   0.0);
    514     psImageInit (differenceImage,  0.0);
    515     psImageInit (convolutionImage, 0.0);
    516 
    517     return true;
    518 }
    519 
    520 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) {
    521 
    522     if (!pmVisualTestLevel("ppsub.stamp", 1)) return true;
    523 
    524     double sum;
    525 
    526     int NXoff = index % NX;
    527     int NYoff = index / NX;
    528 
    529     int NXpix = NXoff * (2*footprint + 1 + 3) + footprint;
    530     int NYpix = NYoff * (2*footprint + 1 + 3) + footprint;
    531 
    532     // insert the (target) kernel into the (target) image:
    533     sum = 0.0;
    534     for (int y = -footprint; y <= footprint; y++) {
    535         for (int x = -footprint; x <= footprint; x++) {
    536             targetImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x];
    537             sum += targetImage->data.F32[y + NYpix][x + NXpix];
    538         }
    539     }
    540     targetImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
    541 
    542     // insert the (source) kernel into the (source) image:
    543     sum = 0.0;
    544     for (int y = -footprint; y <= footprint; y++) {
    545         for (int x = -footprint; x <= footprint; x++) {
    546             sourceImage->data.F32[y + NYpix][x + NXpix] = source->kernel[y][x];
    547             sum += sourceImage->data.F32[y + NYpix][x + NXpix];
    548         }
    549     }
    550     sourceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
    551 
    552     // insert the (convolution) kernel into the (convolution) image:
    553     sum = 0.0;
    554     for (int y = -footprint; y <= footprint; y++) {
    555         for (int x = -footprint; x <= footprint; x++) {
    556             convolutionImage->data.F32[y + NYpix][x + NXpix] = convolution->kernel[y][x];
    557             sum += convolutionImage->data.F32[y + NYpix][x + NXpix];
    558         }
    559     }
    560     convolutionImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
    561    
    562     // insert the (difference) kernel into the (difference) image:
    563     sum = 0.0;
    564     for (int y = -footprint; y <= footprint; y++) {
    565         for (int x = -footprint; x <= footprint; x++) {
    566             differenceImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm;
    567             sum += differenceImage->data.F32[y + NYpix][x + NXpix];
    568         }
    569     }
    570     differenceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
    571 
    572     // insert the (residual) kernel into the (residual) image:
    573     sum = 0.0;
    574     for (int y = -footprint; y <= footprint; y++) {
    575         for (int x = -footprint; x <= footprint; x++) {
    576             residualImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm - convolution->kernel[y][x];
    577             sum += residualImage->data.F32[y + NYpix][x + NXpix];
    578         }
    579     }
    580     residualImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
    581 
    582     // insert the (fresidual) kernel into the (fresidual) image:
    583     for (int y = -footprint; y <= footprint; y++) {
    584         for (int x = -footprint; x <= footprint; x++) {
    585             fresidualImage->data.F32[y + NYpix][x + NXpix] = residualImage->data.F32[y + NYpix][x + NXpix] / sqrt(PS_MAX(target->kernel[y][x], 100.0));
    586         }
    587     }
    588598    return true;
    589599}
     
    611621}
    612622
    613 bool pmSubtractionVisualShowFit(double norm) {
    614 
    615     // for testing, dump the residual image and exit
    616     if (0) {
    617         psMetadata *header = psMetadataAlloc();
    618         psMetadataAddF32 (header, PS_LIST_TAIL, "NORM", 0, "Normalization", norm);
    619         psFits *fits = psFitsOpen("resid.fits", "w");
    620         psFitsWriteImage(fits, header, residualImage, 0, NULL);
    621         psFitsClose(fits);
    622         // exit (0);
    623     }
     623static int footprint = 0;
     624static int NX = 0;
     625static int NY = 0;
     626static psImage *sourceImage      = NULL;
     627static psImage *targetImage      = NULL;
     628static psImage *residualImage    = NULL;
     629static psImage *fresidualImage   = NULL;
     630static psImage *differenceImage  = NULL;
     631static psImage *convolutionImage = NULL;
     632
     633bool pmSubtractionVisualShowFit(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels) {
    624634
    625635    if (!pmVisualTestLevel("ppsub.fit", 1)) return true;
     
    627637    if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) return false;
    628638    if (!pmVisualInitWindow(&kapa2, "ppSub:Misc")) return false;
     639
     640    // set up holding images for the visualization
     641    pmSubtractionVisualShowFitInit (stamps);
     642
     643    int numKernels = kernels->num;      // Number of kernels
     644
     645    psImage *polyValues = NULL;         // Polynomial values
     646    psKernel *residual = psKernelAlloc(-stamps->footprint, stamps->footprint, -stamps->footprint, stamps->footprint); // Residual image
     647
     648    double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation
     649
     650    for (int i = 0; i < stamps->num; i++) {
     651        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest
     652        if (stamp->status != PM_SUBTRACTION_STAMP_USED) { continue; }
     653
     654        // Calculate coefficients of the kernel basis functions
     655        polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm);
     656        double background = p_pmSubtractionSolutionBackground(kernels, polyValues); // Difference in background
     657
     658        psImageInit(residual->image, 0.0);
     659
     660        if (kernels->mode != PM_SUBTRACTION_MODE_DUAL) {
     661            psKernel *target;           // Target postage stamp
     662            psKernel *source;           // Source postage stamp
     663            psArray *convolutions;      // Convolution postage stamps for each kernel basis function
     664            switch (kernels->mode) {
     665              case PM_SUBTRACTION_MODE_1:
     666                target = stamp->image2;
     667                source = stamp->image1;
     668                convolutions = stamp->convolutions1;
     669                break;
     670              case PM_SUBTRACTION_MODE_2:
     671                target = stamp->image1;
     672                source = stamp->image2;
     673                convolutions = stamp->convolutions2;
     674                break;
     675              default:
     676                psAbort("Unsupported subtraction mode: %x", kernels->mode);
     677            }
     678
     679            for (int j = 0; j < numKernels; j++) {
     680                psKernel *convolution = convolutions->data[j]; // Convolution
     681                double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient
     682                for (int y = - footprint; y <= footprint; y++) {
     683                    for (int x = - footprint; x <= footprint; x++) {
     684                        residual->kernel[y][x] += convolution->kernel[y][x] * coefficient;
     685                    }
     686                }
     687            }
     688            // visualize the target, source, convolution and residual
     689            pmSubtractionVisualShowFitAddStamp (target, source, residual, background, norm, i);
     690        } else {
     691            // Dual convolution
     692            psArray *convolutions1 = stamp->convolutions1; // Convolutions of the first image
     693            psArray *convolutions2 = stamp->convolutions2; // Convolutions of the second image
     694            psKernel *image1 = stamp->image1; // The first image
     695            psKernel *image2 = stamp->image2; // The second image
     696
     697            for (int j = 0; j < numKernels; j++) {
     698                psKernel *conv1 = convolutions1->data[j]; // Convolution of first image
     699                psKernel *conv2 = convolutions2->data[j]; // Convolution of second image
     700                double coeff1 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1
     701                double coeff2 = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, true); // Coefficient 2
     702
     703                for (int y = - footprint; y <= footprint; y++) {
     704                    for (int x = - footprint; x <= footprint; x++) {
     705                        residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 + conv1->kernel[y][x] * coeff1;
     706                    }
     707                }
     708            }
     709            // visualize the target, source, convolution and residual
     710            pmSubtractionVisualShowFitAddStamp (image2, image1, residual, background, norm, i);
     711        }
     712    }
     713    pmSubtractionVisualShowFitImage(norm);
     714
     715    return true;
     716}
     717
     718// generate 4 storage images large enough to hold the stamps:
     719bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) {
     720
     721    footprint = stamps->footprint;
     722
     723    float NXf = sqrt(stamps->num);
     724    NX = (int) NXf == NXf ? NXf : NXf + 1.0;
     725   
     726    float NYf = stamps->num / NX;
     727    NY = (int) NYf == NY ? NYf : NYf + 1.0;
     728
     729    int NXpix = (2*footprint + 1) * NX;
     730    NXpix += (NX > 1) ? 3 * NX : 0;
     731
     732    int NYpix = (2*footprint + 1) * NY;
     733    NYpix += (NY > 1) ? 3 * NY : 0;
     734
     735    sourceImage      = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
     736    targetImage      = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
     737    residualImage    = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
     738    fresidualImage   = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
     739    differenceImage  = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
     740    convolutionImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32);
     741   
     742    psImageInit (sourceImage,      0.0);
     743    psImageInit (targetImage,      0.0);
     744    psImageInit (residualImage,    0.0);
     745    psImageInit (fresidualImage,   0.0);
     746    psImageInit (differenceImage,  0.0);
     747    psImageInit (convolutionImage, 0.0);
     748
     749    return true;
     750}
     751
     752bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) {
     753
     754    double sum;
     755
     756    int NXoff = index % NX;
     757    int NYoff = index / NX;
     758
     759    int NXpix = NXoff * (2*footprint + 1 + 3) + footprint;
     760    int NYpix = NYoff * (2*footprint + 1 + 3) + footprint;
     761
     762    // insert the (target) kernel into the (target) image:
     763    sum = 0.0;
     764    for (int y = -footprint; y <= footprint; y++) {
     765        for (int x = -footprint; x <= footprint; x++) {
     766            targetImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x];
     767            sum += targetImage->data.F32[y + NYpix][x + NXpix];
     768        }
     769    }
     770    targetImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
     771
     772    // insert the (source) kernel into the (source) image:
     773    sum = 0.0;
     774    for (int y = -footprint; y <= footprint; y++) {
     775        for (int x = -footprint; x <= footprint; x++) {
     776            sourceImage->data.F32[y + NYpix][x + NXpix] = source->kernel[y][x];
     777            sum += sourceImage->data.F32[y + NYpix][x + NXpix];
     778        }
     779    }
     780    sourceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
     781
     782    // insert the (convolution) kernel into the (convolution) image:
     783    sum = 0.0;
     784    for (int y = -footprint; y <= footprint; y++) {
     785        for (int x = -footprint; x <= footprint; x++) {
     786            convolutionImage->data.F32[y + NYpix][x + NXpix] = convolution->kernel[y][x];
     787            sum += convolutionImage->data.F32[y + NYpix][x + NXpix];
     788        }
     789    }
     790    convolutionImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
     791   
     792    // insert the (difference) kernel into the (difference) image:
     793    sum = 0.0;
     794    for (int y = -footprint; y <= footprint; y++) {
     795        for (int x = -footprint; x <= footprint; x++) {
     796            differenceImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm;
     797            sum += differenceImage->data.F32[y + NYpix][x + NXpix];
     798        }
     799    }
     800    differenceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
     801
     802    // insert the (residual) kernel into the (residual) image:
     803    sum = 0.0;
     804    for (int y = -footprint; y <= footprint; y++) {
     805        for (int x = -footprint; x <= footprint; x++) {
     806            residualImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm - convolution->kernel[y][x];
     807            sum += residualImage->data.F32[y + NYpix][x + NXpix];
     808        }
     809    }
     810    residualImage->data.F32[footprint + 1 + NYpix][NXpix] = sum;
     811
     812    // insert the (fresidual) kernel into the (fresidual) image:
     813    for (int y = -footprint; y <= footprint; y++) {
     814        for (int x = -footprint; x <= footprint; x++) {
     815            fresidualImage->data.F32[y + NYpix][x + NXpix] = residualImage->data.F32[y + NYpix][x + NXpix] / sqrt(PS_MAX(target->kernel[y][x], 100.0));
     816        }
     817    }
     818    return true;
     819}
     820
     821bool pmSubtractionVisualShowFitImage(double norm) {
    629822
    630823    KiiEraseOverlay (kapa1, "red");
     
    673866    psVector *x = psVectorAllocEmpty (kernels->num, PS_TYPE_F32);
    674867    psVector *y = psVectorAllocEmpty (kernels->num, PS_TYPE_F32);
     868    psVector *dy = psVectorAllocEmpty (kernels->num, PS_TYPE_F32);
    675869
    676870    graphdata.xmin = -1.0;
     
    685879        x->data.F32[i] = i;
    686880        y->data.F32[i] = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, false);
     881        dy->data.F32[i] = kernels->solution1err->data.F64[i];
    687882        graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[i]);
    688883        graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[i]);
    689884    }
    690     x->n = y->n = kernels->num;
     885    x->n = y->n = dy->n = kernels->num;
    691886
    692887    float range;
     
    709904    graphdata.size = 0.5;
    710905    graphdata.style = 2;
     906    graphdata.etype |= 0x01;
    711907
    712908    KapaPrepPlot   (kapa3, x->n, &graphdata);
    713909    KapaPlotVector (kapa3, x->n, x->data.F32, "x");
    714910    KapaPlotVector (kapa3, x->n, y->data.F32, "y");
     911    KapaPlotVector (kapa3, x->n, dy->data.F32, "dym");
     912    KapaPlotVector (kapa3, x->n, dy->data.F32, "dyp");
    715913
    716914    psFree (x);
    717915    psFree (y);
     916    psFree (dy);
    718917    psFree (polyValues);
     918
     919    pmVisualAskUser(NULL);
     920    return true;
     921}
     922
     923// plot log(flux) vs log(chisq), log(flux) vs log(moments), log(chisq) vs log(moments)
     924bool pmSubtractionVisualPlotChisqAndMoments(psVector *fluxes, psVector *chisq, psVector *moments) {
     925
     926    Graphdata graphdata;
     927    KapaSection section;
     928
     929    if (!pmVisualTestLevel("ppsub.fit", 1)) return true;
     930
     931    if (!pmVisualInitWindow(&kapa3, "ppSub:plots")) return false;
     932
     933    KapaClearSections (kapa3);
     934    KapaInitGraph (&graphdata);
     935    KiiResize(kapa3, 1500, 500);
     936
     937    psVector *lchi = psVectorAlloc (fluxes->n, PS_TYPE_F32);
     938    psVector *lflx = psVectorAlloc (fluxes->n, PS_TYPE_F32);
     939    psVector *lMxx = psVectorAlloc (fluxes->n, PS_TYPE_F32);
     940
     941    // construct the plot vectors
     942    for (int i = 0; i < fluxes->n; i++) {
     943        lchi->data.F32[i] = log10(chisq->data.F32[i]);
     944        lflx->data.F32[i] = log10(fluxes->data.F32[i]);
     945        lMxx->data.F32[i] = log10(moments->data.F32[i]);
     946    }
     947
     948    section.bg = KapaColorByName ("none"); // XXX probably should be 'none'
     949
     950    // section 1: lflux vs lchi
     951    section.dx = 0.33;
     952    section.dy = 1.00;
     953    section.x  = 0.00;
     954    section.y  = 0.00;
     955    section.name = psStringCopy ("flux.v.chi");
     956    KapaSetSection (kapa3, &section);
     957    psFree (section.name);
     958
     959    graphdata.color = KapaColorByName ("black");
     960    pmVisualScaleGraphdata(&graphdata, lflx, lchi, false);
     961    KapaSetLimits (kapa3, &graphdata);
     962
     963    KapaSetFont (kapa3, "helvetica", 14);
     964    KapaBox (kapa3, &graphdata);
     965    KapaSendLabel (kapa3, "log(flux)", KAPA_LABEL_XM);
     966    KapaSendLabel (kapa3, "log(chisq)", KAPA_LABEL_YM);
     967
     968    graphdata.color = KapaColorByName ("black");
     969    graphdata.ptype = 2;
     970    graphdata.size = 0.5;
     971    graphdata.style = 2;
     972
     973    KapaPrepPlot   (kapa3, lflx->n, &graphdata);
     974    KapaPlotVector (kapa3, lflx->n, lflx->data.F32, "x");
     975    KapaPlotVector (kapa3, lflx->n, lchi->data.F32, "y");
     976
     977    // section 2: lflux vs lMxx
     978    section.dx = 0.33;
     979    section.dy = 1.00;
     980    section.x  = 0.33;
     981    section.y  = 0.00;
     982    section.name = psStringCopy ("flux.v.mom");
     983    KapaSetSection (kapa3, &section);
     984    psFree (section.name);
     985
     986    graphdata.color = KapaColorByName ("black");
     987    pmVisualScaleGraphdata(&graphdata, lflx, lMxx, false);
     988    KapaSetLimits (kapa3, &graphdata);
     989
     990    KapaSetFont (kapa3, "helvetica", 14);
     991    KapaBox (kapa3, &graphdata);
     992    KapaSendLabel (kapa3, "log(flux)", KAPA_LABEL_XM);
     993    KapaSendLabel (kapa3, "log(moments)", KAPA_LABEL_YM);
     994
     995    graphdata.color = KapaColorByName ("black");
     996    graphdata.ptype = 2;
     997    graphdata.size = 0.5;
     998    graphdata.style = 2;
     999
     1000    KapaPrepPlot   (kapa3, lflx->n, &graphdata);
     1001    KapaPlotVector (kapa3, lflx->n, lflx->data.F32, "x");
     1002    KapaPlotVector (kapa3, lflx->n, lMxx->data.F32, "y");
     1003
     1004    // section 1: lflux vs lchi
     1005    section.dx = 0.33;
     1006    section.dy = 1.00;
     1007    section.x  = 0.66;
     1008    section.y  = 0.00;
     1009    section.name = psStringCopy ("chi.v.mom");
     1010    KapaSetSection (kapa3, &section);
     1011    psFree (section.name);
     1012
     1013    graphdata.color = KapaColorByName ("black");
     1014    pmVisualScaleGraphdata(&graphdata, lchi, lMxx, false);
     1015    KapaSetLimits (kapa3, &graphdata);
     1016
     1017    KapaSetFont (kapa3, "helvetica", 14);
     1018    KapaBox (kapa3, &graphdata);
     1019    KapaSendLabel (kapa3, "log(chisq)", KAPA_LABEL_XM);
     1020    KapaSendLabel (kapa3, "log(moments)", KAPA_LABEL_YM);
     1021
     1022    graphdata.color = KapaColorByName ("black");
     1023    graphdata.ptype = 2;
     1024    graphdata.size = 0.5;
     1025    graphdata.style = 2;
     1026
     1027    KapaPrepPlot   (kapa3, lflx->n, &graphdata);
     1028    KapaPlotVector (kapa3, lflx->n, lchi->data.F32, "x");
     1029    KapaPlotVector (kapa3, lflx->n, lMxx->data.F32, "y");
    7191030
    7201031    pmVisualAskUser(NULL);
  • branches/czw_branch/20101203/psModules/src/imcombine/pmSubtractionVisual.h

    r29601 r30631  
    66bool pmSubtractionVisualPlotStamps(pmSubtractionStampList *stamps, pmReadout *ro);
    77bool pmSubtractionVisualPlotLeastSquares(pmSubtractionStampList *stamps);
     8bool pmSubtractionVisualPlotLeastSquaresResid (const pmSubtractionStampList *stamps, psImage *matrixIn, int nUsed);
    89bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub);
     10
     11bool pmSubtractionVisualShowFit(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels);
    912bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps);
    1013bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index);
    11 bool pmSubtractionVisualShowFit(double norm);
     14bool pmSubtractionVisualShowFitImage(double norm);
     15
    1216bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels);
    1317bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels);
    1418bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps);
     19bool pmSubtractionVisualPlotChisqAndMoments(psVector *fluxes, psVector *chisq, psVector *moments);
    1520
    1621#endif
  • branches/czw_branch/20101203/psModules/src/objects

    • Property svn:mergeinfo deleted
  • branches/czw_branch/20101203/psModules/src/objects/pmFootprint.c

    r29004 r30631  
    255255}
    256256
     257// create a new footprint with the same span set as the input footprint
     258pmFootprint *pmFootprintCopyData(pmFootprint *inFoot, psImage *image) {
     259
     260    pmFootprint *outFoot = pmFootprintAlloc(inFoot->nspans, image);
     261    for (int i = 0; i < inFoot->nspans; i++) {
     262        pmSpan *span = inFoot->spans->data[i];
     263        pmFootprintAddSpan(outFoot, span->y, span->x0, span->x1);
     264    }
     265    return outFoot;
     266}
     267
    257268/************************************************************************************************************/
  • branches/czw_branch/20101203/psModules/src/objects/pmFootprint.h

    r29004 r30631  
    2727
    2828bool pmFootprintAllocEmptySpans (pmFootprint *footprint, int nSpans);
     29
     30pmFootprint *pmFootprintCopyData(pmFootprint *inFoot, psImage *image);
    2931
    3032pmFootprint *pmFootprintNormalize(pmFootprint *fp);
  • branches/czw_branch/20101203/psModules/src/objects/pmFootprintAssignPeaks.c

    r29004 r30631  
    2424/*
    2525 * Given a psArray of pmFootprints and another of pmPeaks, assign the peaks to the
    26  * footprints in which that fall; if they _don't_ fall in a footprint, add a suitable
     26 * footprints in which they fall; if they _don't_ fall in a footprint, add a suitable
    2727 * one to the list.
    2828 */
     
    8383
    8484        // XXX are we allowed to have peak-less footprints??
    85         if (!fp->peaks->n) continue;
     85        if (fp->peaks->n == 0) continue;
     86        if (fp->peaks->n == 1) continue;
    8687
    8788        fp->peaks = psArraySort(fp->peaks, pmPeakSortBySN);
    8889
     90        // XXX check for an assert on duplicates (I don't think they can happen, but
     91        // let's double check for now)
     92
     93        for (int j = 1; j < fp->peaks->n; j++) {
     94            psAssert (fp->peaks->data[j] != fp->peaks->data[j-1], "duplicate peak!");
     95        }
     96        continue;
     97
     98        // XXX WHY am I culling duplicates?  how can there be duplicates?
    8999        // XXX EAM : the algorithm below should be much faster than using psArrayRemove if
    90100        // the number of peaks in the footprint is large, or if there are no duplicates.
     
    93103
    94104        // track the number of good peaks in the footprint
    95         int nGood = 1;
     105        int lastGood = 0;
    96106
    97107        // check for duplicates
     
    100110        // (if sorted list has A, B, A, B ...)
    101111        for (int j = 1; j < fp->peaks->n; j++) {
    102             if (fp->peaks->data[j] == fp->peaks->data[nGood]) {
     112            if (fp->peaks->data[j] == fp->peaks->data[lastGood]) {
    103113                // everything on the array has its own mem reference; free and drop this one
    104114                psFree (fp->peaks->data[j]);
    105115                fp->peaks->data[j] = NULL;
    106116            } else {
    107                 nGood ++;
     117                lastGood ++;
    108118            }
    109119        }
     120        int nGood = lastGood + 1;
    110121
    111122        // no deleted peaks, go to next footprint
  • branches/czw_branch/20101203/psModules/src/objects/pmFootprintCullPeaks.c

    r29004 r30631  
    2828  * Examine the peaks in a pmFootprint, and throw away the ones that are not sufficiently
    2929  * isolated.  More precisely, for each peak find the highest coll that you'd have to traverse
    30   * to reach a still higher peak --- and if that coll's more than nsigma DN below your
     30  * to reach a still higher peak --- and if that coll's more (less?) than nsigma DN below your
    3131  * starting point, discard the peak.
    3232  */
     
    9999        float threshold = flux - nsigma_delta*stdev_pad;
    100100
    101         if (isnan(threshold) || threshold < min_threshold) {
     101        if (isnan(threshold)) {
    102102            // min_threshold is assumed to be below the detection threshold,
    103103            // so all the peaks are pmFootprint, and this isn't the brightest
     
    109109            threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON;
    110110        }
     111
     112        if (threshold < min_threshold) {
     113            threshold = min_threshold;
     114        }
    111115
    112116        // init peakFootprint here?
  • branches/czw_branch/20101203/psModules/src/objects/pmModel.c

    r29004 r30631  
    7070    tmp->fitRadius = 0;
    7171    tmp->flags = PM_MODEL_STATUS_NONE;
    72     tmp->residuals = NULL;              // XXX should the model own this memory?
     72    tmp->residuals = NULL;              // do not free: the model does not own this memory
     73    tmp->isPCM = false;
    7374
    7475    psS32 Nparams = pmModelClassParameterCount(type);
     
    108109pmModel *pmModelCopy (pmModel *model)
    109110{
    110     PS_ASSERT_PTR_NON_NULL(model, NULL);
    111 
     111    if (model == NULL) {
     112        return NULL;
     113    }
    112114    pmModel *new = pmModelAlloc (model->type);
    113115
  • branches/czw_branch/20101203/psModules/src/objects/pmModel.h

    r29004 r30631  
    4343    float fitRadius;                    ///< fit radius actually used
    4444    pmResiduals *residuals;             ///< normalized PSF residuals
     45    bool isPCM;                         ///< is this model fitted with PSF-convolution?
    4546
    4647    // functions for this model which depend on the model class
  • branches/czw_branch/20101203/psModules/src/objects/pmPCMdata.h

    r29004 r30631  
    8383    pmPCMdata *pcm);
    8484
     85psKernel *pmPCMkernelFromPSF (pmSource *source, int nPix);
     86
    8587bool pmSourceModelGuessPCM (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal);
    8688
  • branches/czw_branch/20101203/psModules/src/objects/pmPSFtry.c

    r29004 r30631  
    8484
    8585    for (int i = 0; i < sources->n; i++) {
    86         test->sources->data[i] = pmSourceCopy (sources->data[i]);
     86        pmSource *sourceOld = sources->data[i];
     87        pmSource *sourceNew = pmSourceCopy (sourceOld);
     88
     89        // save a reference so we can get back to the original
     90        // this is specifically used in psphotChooosePSF to unflag the candidate PSF sources
     91        // which were not actually used to generate a PSF model
     92        sourceNew->parent = sourceOld;
     93
     94        test->sources->data[i] = sourceNew;
    8795    }
    8896
  • branches/czw_branch/20101203/psModules/src/objects/pmPSFtryFitEXT.c

    r29004 r30631  
    6565        if (!source->moments) {
    6666            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
     67            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : no moments\n", i, source->peak->x, source->peak->y);
    6768            continue;
    6869        }
    6970        if (!source->moments->nPixels) {
     71            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : no pixels\n", i, source->peak->x, source->peak->y);
    7072            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
    7173            continue;
     
    7476        source->modelEXT = pmSourceModelGuess (source, options->type);
    7577        if (source->modelEXT == NULL) {
     78            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y);
    7679            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
    77             psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y);
    7880            continue;
    7981        }
     
    9193        // exclude the poor fits
    9294        if (!status) {
     95            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y);
    9396            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
    94             psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y);
    9597            continue;
    9698        }
  • branches/czw_branch/20101203/psModules/src/objects/pmPSFtryFitPSF.c

    r29004 r30631  
    8181        if (source->modelPSF == NULL) {
    8282            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_BAD_MODEL;
     83            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : bad PSF fit\n", i, source->peak->x, source->peak->y);
    8384            continue;
    8485        }
  • branches/czw_branch/20101203/psModules/src/objects/pmPSFtryModel.c

    r30118 r30631  
    5252// mask values indicate the reason the source was rejected:
    5353
     54// XXX some test code (delete eventually)
     55// bool countMaskedSources(pmPSFtry *try, char *msg) {
     56//
     57//     int N1 = 0;
     58//     int N2 = 0;
     59//     for (int i = 0; i < try->sources->n; i++) {
     60//         pmSource *source = try->sources->data[i];
     61//      // fprintf (stderr, "%llx : %d\n", (long long int) source, (source->mode & PM_SOURCE_MODE_PSFSTAR));
     62//      if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
     63//          N1 ++;
     64//         }
     65//      if (try->mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
     66//          N2 ++;
     67//         }
     68//     }
     69//     fprintf (stderr, "%s : masked: %d or %d of %ld\n", msg, N1, N2, try->sources->n);
     70//     return true;
     71// }
     72
    5473// generate a pmPSFtry with a copy of the test PSF sources
    5574pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal)
     
    203222            chisq->data.F32[i] = 0.0;
    204223            mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff;
     224            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : no PSF model\n", i, source->peak->x, source->peak->y);
    205225        } else {
    206226            flux->data.F32[i] = source->modelPSF->params->data.F32[PM_PAR_I0];
  • branches/czw_branch/20101203/psModules/src/objects/pmSource.c

    r30118 r30631  
    6161    psFree(tmp->moments);
    6262    psFree(tmp->diffStats);
    63     psFree(tmp->radial);
     63    psFree(tmp->radialAper);
    6464    psFree(tmp->blends);
    6565    psTrace("psModules.objects", 10, "---- end ----\n");
     
    126126    source->extpars = NULL;
    127127    source->diffStats = NULL;
    128     source->radial = NULL;
     128    source->radialAper = NULL;
     129    source->parent = NULL;
    129130
    130131    source->region = psRegionSet(NAN, NAN, NAN, NAN);
     
    159160affecting the original.  This Copy can be used to allow multiple fit attempts on the same
    160161object.  The pixels, variance, and mask arrays all point to the same original subarrays.  The
    161 peak and moments point at the original values.
     162peak and moments point at the original values.  The models, blends, and XXX are NOT copied
    162163*****************************************************************************/
    163164pmSource *pmSourceCopy(pmSource *in)
     
    167168    }
    168169    pmSource *source = pmSourceAlloc ();
    169 
    170     // keep the original ID so we can find map back to the original
    171     P_PM_SOURCE_SET_ID(source, in->id);
    172170
    173171    // peak has the same values as the original
     
    203201}
    204202
    205 /******************************************************************************
    206 pmSourceCopyData(): this creates a new, duplicate source with the same parameters as the
    207 original (but is actually a new source at the same location)
    208 *****************************************************************************/
    209 pmSource *pmSourceCopyData(pmSource *in)
    210 {
    211     if (in == NULL) {
    212         return(NULL);
    213     }
    214     // this copy is used to allow multiple fit attempts on the
    215     // same object.  the pixels, variance, and mask arrays all point to
    216     // the same original subarrays.  the peak and moments point at
    217     // the original values.
    218     pmSource *source = pmSourceAlloc ();
    219 
    220     // this is actually the same peak as the original, is this the correct way to handle this?
    221     if (in->peak != NULL) {
    222         source->peak = pmPeakAlloc (in->peak->x, in->peak->y, in->peak->value, in->peak->type);
    223         source->peak->xf = in->peak->xf;
    224         source->peak->yf = in->peak->yf;
    225         source->peak->flux = in->peak->flux;
    226         source->peak->SN = in->peak->SN;
    227     }
    228 
    229     // copy the values in the moments structure
    230     if (in->moments != NULL) {
    231         source->moments  =  pmMomentsAlloc();
    232         *source->moments = *in->moments;
    233     }
    234 
    235     // These images are all views to the parent.
    236     // We want a new view, but pointing at the same pixels.
    237     source->pixels   = psImageCopyView(NULL, in->pixels);
    238     source->variance   = psImageCopyView(NULL, in->variance);
    239     source->maskView = in->maskView ? psImageCopyView(NULL, in->maskView) : NULL;
    240 
    241     // the maskObj is a unique mask array; create a new mask image
    242     source->maskObj = in->maskObj ? psImageCopy (NULL, in->maskObj, PS_TYPE_IMAGE_MASK) : NULL;
    243 
    244     source->type = in->type;
    245     source->mode = in->mode;
    246     source->imageID = in->imageID;
    247 
    248     return(source);
    249 }
    250 
    251203// x,y are defined in the parent image coords of readout->image
    252204bool pmSourceDefinePixels(pmSource *mySource,
     
    300252    newRegion = psRegionForImage (readout->image, newRegion);
    301253
     254    // re-define if required by region or absence of pixels
    302255    extend = false;
    303256    extend |= (int)(newRegion.x0) < (int)(mySource->region.x0);
     
    335288    }
    336289    return extend;
     290}
     291
     292bool pmSourceRedefinePixelsByRegion(pmSource *mySource,
     293                                    const pmReadout *readout,
     294                                    psRegion newRegion)
     295{
     296    PS_ASSERT_PTR_NON_NULL(mySource, false);
     297    PS_ASSERT_PTR_NON_NULL(readout, false);
     298    PS_ASSERT_PTR_NON_NULL(readout->image, false);
     299
     300    // re-create the subimage
     301    psFree (mySource->pixels);
     302    psFree (mySource->variance);
     303    psFree (mySource->maskView);
     304       
     305    mySource->pixels   = psImageSubset(readout->image,    newRegion);
     306    mySource->variance = psImageSubset(readout->variance, newRegion);
     307    mySource->maskView = psImageSubset(readout->mask,     newRegion);
     308    mySource->region   = newRegion;
     309
     310    // re-copy the main mask pixels.  NOTE: the user will need to reset the object mask
     311    // pixels (eg, with psImageKeepCircle)
     312    mySource->maskObj = psImageCopy (mySource->maskObj, mySource->maskView, PS_TYPE_IMAGE_MASK);
     313
     314    // drop the old modelFlux pixels and force the user to re-create
     315    psFree (mySource->modelFlux);
     316    mySource->modelFlux = NULL;
     317
     318    // drop the old psfImage pixels and force the user to re-create
     319    psFree (mySource->psfImage);
     320    mySource->psfImage = NULL;
     321
     322    return true;
    337323}
    338324
     
    675661            if ((source->moments->SN > PSF_SN_LIM) && (radius < PSF_CLUMP_NSIGMA)) {
    676662                source->type = PM_SOURCE_TYPE_STAR;
    677                 source->mode |= PM_SOURCE_MODE_PSFSTAR;
     663                source->tmpFlags |= PM_SOURCE_TMPF_CANDIDATE_PSFSTAR;
    678664                Npsf ++;
    679665                continue;
     
    934920}
    935921
    936 // construct a realization of the source model
    937 // XXX this function should optionally save an existing psf image from modelFlux
     922// construct a realization of the PSF model at the location of this source
    938923bool pmSourceCachePSF (pmSource *source, psImageMaskType maskVal) {
    939924    PS_ASSERT_PTR_NON_NULL(source, false);
     
    10201005    }
    10211006
    1022     if (!addNoise) {
    1023         if (add) {
    1024             status = pmModelAddWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
    1025             source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
    1026         } else {
    1027             status = pmModelSubWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
    1028             source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    1029         }
     1007    if (add) {
     1008        status = pmModelAddWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
     1009        source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
     1010    } else {
     1011        status = pmModelSubWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
     1012        source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
    10301013    }
    10311014
  • branches/czw_branch/20101203/psModules/src/objects/pmSource.h

    r29546 r30631  
    3535    PM_SOURCE_TMPF_SIZE_CR_CANDIDATE = 0x0008,
    3636    PM_SOURCE_TMPF_MOMENTS_MEASURED  = 0x0010,
     37    PM_SOURCE_TMPF_CANDIDATE_PSFSTAR = 0x0020,
    3738} pmSourceTmpF;
    3839
     
    4243 *  simplest measurement of a source is the location and flux of the peak pixel
    4344 *  associated with the source:
     45 *
     46 * a pmSource is the information about a (possible) blob of flux in a specific image.  A source
     47 * may represent an insignificant or undetected source.  There may be multiple representations
     48 * of an image (eg, alternate smoothed copies); sources on alternate images may have a pointer
     49 * to the version on the primary image (source->parent).  A set of sources on different, but
     50 * related images (eg, multiple exposures or different filters) which (may) represent the same
     51 * astronomical object are grouped together with the pmPhotObj type (set pmPhotObj.h).
     52 *
     53 * A single source may be fitted with multiple models (not at the same time!).  The PSF model
     54 * fit is a fit of the position (optionally) and the flux to the PSF model at the location of
     55 * the source.  Alternate model fits are extended source models. The best model fit is used to
     56 * subtract the object from the image.
    4457 *
    4558 *  XXX do I have to re-organize this (again!) to allow an arbitrary set of extended model fits??
     
    5467    pmPeak  *peak;                      ///< Description of peak pixel.
    5568    psImage *pixels;                    ///< Rectangular region including object pixels.
    56     psImage *variance;                    ///< Image variance.
     69    psImage *variance;                  ///< Image variance.
    5770    psImage *maskObj;                   ///< unique mask for this object which marks included pixels associated with objects.
    5871    psImage *maskView;                  ///< view into global image mask for this object region
    5972    psImage *modelFlux;                 ///< cached copy of the best model for this source
    60     psImage *psfImage;                   ///< cached copy of the psf model for this source
     73    psImage *psfImage;                  ///< cached copy of the psf model for this source
    6174    pmMoments *moments;                 ///< Basic moments measured for the object.
    6275    pmModel *modelPSF;                  ///< PSF Model fit (parameters and type)
     
    89102    pmSourceExtendedPars *extpars;      ///< extended source parameters
    90103    pmSourceDiffStats *diffStats;       ///< extra parameters for difference detections
    91     pmSourceRadialApertures *radial;    ///< radial flux in circular apertures
     104    psArray *radialAper;                ///< radial flux in circular apertures
     105    pmSource *parent;                   ///< reference to the master source from which this is derived
    92106    int imageID;
    93107};
     
    162176);
    163177
     178bool pmSourceRedefinePixelsByRegion (
     179    pmSource *mySource,   ///< source to be re-defined
     180    const pmReadout *readout,   ///< base the source on this readout
     181    psRegion newRegion ///< region for source pixel definition
     182);
     183
    164184/** pmSourcePSFClump()
    165185 *
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceExtendedPars.c

    r28013 r30631  
    1717#endif
    1818
    19 // #include <stdio.h>
    20 // #include <math.h>
    21 // #include <string.h>
    2219#include <pslib.h>
    23 // #include "pmHDU.h"
    24 // #include "pmFPA.h"
    25 // #include "pmFPAMaskWeight.h"
    26 // #include "pmSpan.h"
    27 // #include "pmFootprint.h"
    28 // #include "pmPeaks.h"
    29 // #include "pmMoments.h"
    30 // #include "pmResiduals.h"
    31 // #include "pmGrowthCurve.h"
    32 // #include "pmTrend2D.h"
    33 // #include "pmPSF.h"
    34 // #include "pmModel.h"
    35 // #include "pmSource.h"
    3620#include "pmSourceExtendedPars.h"
    3721
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceFitPCM.c

    r29004 r30631  
    8989    if (!fitStatus) pcm->modelConv->flags |= PM_MODEL_STATUS_NONCONVERGE;
    9090
     91    // once we have fitted a model, we need to record that this model is a PCM model:
     92    pcm->modelConv->isPCM = true;
     93
    9194    // models can go insane: reject these
    9295    bool onPic = true;
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO.c

    r29546 r30631  
    5959
    6060// lookup the EXTNAME values used for table data and image header segments
    61 static bool sourceExtensions(psString *headname, // Extension name for header
    62                              psString *dataname, // Extension name for data
    63                              psString *deteffname, // Extension name for detection efficiency
    64                              psString *xsrcname, // Extension name for extended sources
    65                              psString *xfitname, // Extension name for extended fits
    66                              const pmFPAfile *file, // File of interest
    67                              const pmFPAview *view // View to level of interest
    68                              )
     61bool pmSourceIOextnames(psString *headname,    // Extension name for image header
     62                        psString *dataname,    // Extension name for PSF table data
     63                        psString *deteffname,  // Extension name for detection efficiency
     64                        psString *xsrcname,    // Extension name for extended non-parametric measurements
     65                        psString *xfitname,    // Extension name for extended fitted measurements
     66                        psString *xradname,    // Extension name for radial apertures
     67                        const pmFPAfile *file, // File of interest
     68                        const pmFPAview *view  // View to level of interest
     69    )
    6970{
    7071    bool status;                        // Status of MD lookup
     
    8788    }
    8889
    89     // EXTNAME for table data
     90    // EXTNAME for PSF table data
    9091    if (dataname) {
    9192        const char *rule = psMetadataLookupStr(&status, menu, "CMF.DATA");
     
    107108    }
    108109
    109     // EXTNAME for extended source data table
     110    // EXTNAME for extended source non-parametric measurements
    110111    if (xsrcname) {
    111112        const char *rule = psMetadataLookupStr(&status, menu, "CMF.XSRC");
     
    117118    }
    118119
     120    // EXTNAME for extended source fitted measurements
    119121    if (xfitname) {
    120         // EXTNAME for extended source data table
    121122        const char *rule = psMetadataLookupStr(&status, menu, "CMF.XFIT");
    122123        if (!rule) {
     
    125126        }
    126127        *xfitname = pmFPAfileNameFromRule (rule, file, view);
     128    }
     129
     130    // EXTNAME for radial apertures
     131    if (xradname) {
     132        const char *rule = psMetadataLookupStr(&status, menu, "CMF.XRAD");
     133        if (!rule) {
     134            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XRAD in EXTNAME.RULES in camera.config");
     135            return false;
     136        }
     137        *xradname = pmFPAfileNameFromRule (rule, file, view);
    127138    }
    128139
     
    344355            status &= pmSourcesWrite_##TYPE##_XFIT (file->fits, readout, sources, file->header, xfitname); \
    345356        }                                                               \
     357        if (xradname) {                                                 \
     358            status &= pmSourcesWrite_##TYPE##_XRAD (file->fits, readout, sources, file->header, xradname, recipe); \
     359        }                                                               \
    346360    }
    347361
     
    449463        bool XSRC_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_ANALYSIS");
    450464        bool XFIT_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_FITS");
     465        bool XRAD_OUTPUT = psMetadataLookupBool(&status, recipe, "RADIAL_APERTURES");
    451466
    452467        // define the EXTNAME values for the different data segments:
     
    456471        psString xsrcname = NULL;
    457472        psString xfitname = NULL;
    458         if (!sourceExtensions(&headname, &dataname, &deteffname,
    459                               XSRC_OUTPUT ? &xsrcname : NULL,
    460                               XFIT_OUTPUT ? &xfitname : NULL,
    461                               file, view)) {
     473        psString xradname = NULL;
     474        if (!pmSourceIOextnames(&headname, &dataname, &deteffname,
     475                                XSRC_OUTPUT ? &xsrcname : NULL,
     476                                XFIT_OUTPUT ? &xfitname : NULL,
     477                                XRAD_OUTPUT ? &xradname : NULL,
     478                                file, view)) {
    462479            return false;
    463480        }
     
    539556                psMetadataAddStr (outhead, PS_LIST_TAIL, "XFITNAME", PS_META_REPLACE, "name of XFIT table extension", xfitname);
    540557            }
    541    
     558            if (xradname) {
     559                psMetadataAddStr (outhead, PS_LIST_TAIL, "XRADNAME", PS_META_REPLACE, "name of XRAD table extension", xradname);
     560            }
    542561
    543562            // these are case-sensitive since the EXTYPE is case-sensitive
     
    563582        }
    564583
    565 
    566584        // write out the detection efficiency TABLE segments
    567585        if (deteffname) {
     
    583601        psFree (xsrcname);
    584602        psFree (xfitname);
     603        psFree (xradname);
    585604        psFree (deteffname);
    586605
     
    593612        psFree (xsrcname);
    594613        psFree (xfitname);
     614        psFree (xradname);
    595615        psFree (deteffname);
    596616        return false;
     
    939959        psString dataname = NULL;
    940960        psString deteffname = NULL;
    941         if (!sourceExtensions(&headname, &dataname, &deteffname, NULL, NULL, file, view)) {
     961        if (!pmSourceIOextnames(&headname, &dataname, &deteffname, NULL, NULL, NULL, file, view)) {
    942962            return false;
    943963        }
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO.h

    r29546 r30631  
    3030bool pmSourcesWrite_SMPDATA_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    3131bool pmSourcesWrite_SMPDATA_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     32bool pmSourcesWrite_SMPDATA_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    3233
    3334bool pmSourcesWrite_PS1_DEV_0(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    3435bool pmSourcesWrite_PS1_DEV_0_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    3536bool pmSourcesWrite_PS1_DEV_0_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     37bool pmSourcesWrite_PS1_DEV_0_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    3638
    3739bool pmSourcesWrite_PS1_DEV_1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    3840bool pmSourcesWrite_PS1_DEV_1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    3941bool pmSourcesWrite_PS1_DEV_1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     42bool pmSourcesWrite_PS1_DEV_1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    4043
    4144bool pmSourcesWrite_PS1_CAL_0(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    4245bool pmSourcesWrite_PS1_CAL_0_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    4346bool pmSourcesWrite_PS1_CAL_0_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     47bool pmSourcesWrite_PS1_CAL_0_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    4448
    4549bool pmSourcesWrite_CMF_PS1_V1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    4650bool pmSourcesWrite_CMF_PS1_V1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    4751bool pmSourcesWrite_CMF_PS1_V1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     52bool pmSourcesWrite_CMF_PS1_V1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    4853
    4954bool pmSourcesWrite_CMF_PS1_V2(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    5055bool pmSourcesWrite_CMF_PS1_V2_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    5156bool pmSourcesWrite_CMF_PS1_V2_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     57bool pmSourcesWrite_CMF_PS1_V2_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    5258
    5359bool pmSourcesWrite_CMF_PS1_V3(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    5460bool pmSourcesWrite_CMF_PS1_V3_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    5561bool pmSourcesWrite_CMF_PS1_V3_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     62bool pmSourcesWrite_CMF_PS1_V3_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    5663
    5764bool pmSourcesWrite_CMF_PS1_SV1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    5865bool pmSourcesWrite_CMF_PS1_SV1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    5966bool pmSourcesWrite_CMF_PS1_SV1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     67bool pmSourcesWrite_CMF_PS1_SV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    6068
    6169bool pmSourcesWrite_CMF_PS1_DV1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    6270bool pmSourcesWrite_CMF_PS1_DV1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    6371bool pmSourcesWrite_CMF_PS1_DV1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     72bool pmSourcesWrite_CMF_PS1_DV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    6473
    6574bool pmSourcesWrite_CMF_PS1_DV2(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
    6675bool pmSourcesWrite_CMF_PS1_DV2_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    6776bool pmSourcesWrite_CMF_PS1_DV2_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
     77bool pmSourcesWrite_CMF_PS1_DV2_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
    6878
    6979psArray *pmSourcesReadCMP (char *filename, psMetadata *header);
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c

    r29004 r30631  
    676676    return true;
    677677}
     678
     679bool pmSourcesWrite_CMF_PS1_DV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     680{
     681    return true;
     682}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c

    r29620 r30631  
    737737    return true;
    738738}
     739
     740bool pmSourcesWrite_CMF_PS1_DV2_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     741{
     742    return true;
     743}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c

    r29019 r30631  
    2020
    2121#include "pmConfig.h"
     22#include "pmErrorCodes.h"
    2223#include "pmDetrendDB.h"
    2324
     
    7172    psF32 errMag, chisq, apRadius;
    7273    psS32 nPix, nDOF;
    73     char keyword1[80], keyword2[80];
    7474
    7575    pmChip *chip = readout->parent->parent;
     
    103103    table = psArrayAllocEmpty (sources->n);
    104104
     105# if (0)
    105106    // we use this just to define the output vectors (which must be present for all objects)
    106107    bool status = false;
     
    118119      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
    119120    }
    120 
     121# endif
    121122
    122123    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
     
    258259        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                     source->mode2);
    259260
     261# if (0)
     262        // XXX if we have raw radial apertures, write them out here
    260263        psVector *radFlux    = psVectorAlloc(radMax->n, PS_TYPE_F32);
    261264        psVector *radFluxErr = psVectorAlloc(radMax->n, PS_TYPE_F32);
     
    284287        psFree (radFluxErr);
    285288        psFree (radFill);
     289# endif
    286290
    287291        // XXX not sure how to get this : need to load Nimages with weight?
     
    781785    return true;
    782786}
     787
     788// **** write out the radial flux values for the sources for a given matched-PSF image
     789// **** how do we distinguish the matched-PSF images from the non-matched version
     790bool pmSourcesWrite_CMF_PS1_SV1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     791{
     792
     793    psArray *table;
     794    psMetadata *row;
     795    psF32 xPos, yPos;
     796    char keyword1[80], keyword2[80];
     797
     798    // create a header to hold the output data
     799    psMetadata *outhead = psMetadataAlloc ();
     800
     801    // write the links to the image header
     802    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTNAME", PS_META_REPLACE, "radial flux table extension", extname);
     803
     804    // we use this just to define the output vectors (which must be present for all objects)
     805    bool status = false;
     806    psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
     807    psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
     808    psAssert (radMax, "this must have been defined and tested earlier!");
     809    psAssert (radMax->n, "this must have been defined and tested earlier!");
     810    psAssert (radMin->n == radMax->n, "inconsistent annular bins");
     811
     812    // write the radial profile apertures to header
     813    for (int i = 0; i < radMax->n; i++) {
     814      sprintf (keyword1, "RMIN_%02d", i);
     815      sprintf (keyword2, "RMAX_%02d", i);
     816      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);
     817      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
     818    }
     819
     820    psVector *fwhmValues = psMetadataLookupVector(&status, readout->analysis, "STACK.PSF.FWHM.VALUES");
     821    if (!fwhmValues) {
     822        psError (PM_ERR_CONFIG, true, "convolved or measured FWHM is not defined for this readout");
     823        return false;
     824    }
     825
     826    // let's write these out in S/N order
     827    sources = psArraySort (sources, pmSourceSortBySN);
     828
     829    table = psArrayAllocEmpty (sources->n);
     830
     831    // we write out all sources, regardless of quality.  the source flags tell us the state
     832    for (int i = 0; i < sources->n; i++) {
     833
     834        pmSource *source = sources->data[i];
     835
     836        // skip sources without radial aper measurements (or insufficient)
     837        if (source->radialAper == NULL) continue;
     838        psAssert (source->radialAper->n == fwhmValues->n, "inconsistent radial aperture set");
     839
     840        for (int entry = 0; entry < fwhmValues->n; entry++) {
     841
     842            // choose the convolved EXT model, if available, otherwise the simple one
     843            pmSourceRadialApertures *radialAper = source->radialAper->data[entry];
     844            assert (radialAper);
     845
     846            bool useMoments = true;
     847            useMoments = (useMoments && source->moments);          // can't if there are no moments
     848            useMoments = (useMoments && source->moments->nPixels); // can't if the moments were not measured
     849            useMoments = (useMoments && !(source->mode && PM_SOURCE_MODE_MOMENTS_FAILURE)); // can't if the moments failed...
     850
     851            if (useMoments) {
     852                xPos = source->moments->Mx;
     853                yPos = source->moments->My;
     854            } else {
     855                xPos = source->peak->xf;
     856                yPos = source->peak->yf;
     857            }
     858
     859            row = psMetadataAlloc ();
     860
     861            // XXX we are not writing out the mode (flags) or the type (psf, ext, etc)
     862            psMetadataAddU32 (row, PS_LIST_TAIL, "IPP_IDET",         0, "IPP detection identifier index",             source->seq);
     863            psMetadataAddF32 (row, PS_LIST_TAIL, "X_APER",           0, "Center of aperture measurements",            xPos);
     864            psMetadataAddF32 (row, PS_LIST_TAIL, "Y_APER",           0, "Center of aperture measurements",            yPos);
     865            psMetadataAddF32 (row, PS_LIST_TAIL, "PSF_FWHM",         0, "FWHM of matched PSF",                        fwhmValues->data.F32[entry]);
     866
     867            // XXX if we have raw radial apertures, write them out here
     868            psVector *radFlux    = psVectorAlloc(radMax->n, PS_TYPE_F32);
     869            psVector *radFluxErr = psVectorAlloc(radMax->n, PS_TYPE_F32);
     870            psVector *radFill    = psVectorAlloc(radMax->n, PS_TYPE_F32);
     871            psVectorInit (radFlux,    NAN);
     872            psVectorInit (radFluxErr, NAN);
     873            psVectorInit (radFill,    NAN);
     874            if (!radialAper->flux) goto write_annuli;
     875            if (!radialAper->fill) goto write_annuli;
     876            psAssert (radialAper->flux->n <= radFlux->n, "inconsistent vector lengths");
     877            psAssert (radialAper->fill->n <= radFlux->n, "inconsistent vector lengths");
     878
     879            // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux
     880            for (int j = 0; j < radialAper->flux->n; j++) {
     881                radFlux->data.F32[j]    = radialAper->flux->data.F32[j];
     882                radFluxErr->data.F32[j] = radialAper->fluxErr->data.F32[j];
     883                radFill->data.F32[j]    = radialAper->fill->data.F32[j];
     884            }
     885
     886        write_annuli:
     887            psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX",     PS_DATA_VECTOR, "flux within annuli",    radFlux);
     888            psMetadataAdd (row, PS_LIST_TAIL, "APER_FLUX_ERR", PS_DATA_VECTOR, "flux error in annuli",  radFluxErr);
     889            psMetadataAdd (row, PS_LIST_TAIL, "APER_FILL",     PS_DATA_VECTOR, "fill factor of annuli", radFill);
     890            psFree (radFlux);
     891            psFree (radFluxErr);
     892            psFree (radFill);
     893
     894            psArrayAdd (table, 100, row);
     895            psFree (row);
     896        }
     897    }
     898
     899    if (table->n == 0) {
     900        if (!psFitsWriteBlank (fits, outhead, extname)) {
     901            psError(psErrorCodeLast(), false, "Unable to write empty sources file.");
     902            psFree(outhead);
     903            psFree(table);
     904            return false;
     905        }
     906        psFree (outhead);
     907        psFree (table);
     908        return true;
     909    }
     910
     911    psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname);
     912    if (!psFitsWriteTable (fits, outhead, table, extname)) {
     913        psError(psErrorCodeLast(), false, "writing ext data %s\n", extname);
     914        psFree (outhead);
     915        psFree(table);
     916        return false;
     917    }
     918    psFree (outhead);
     919    psFree (table);
     920    return true;
     921}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c

    r29004 r30631  
    721721    return false;
    722722}
     723
     724bool pmSourcesWrite_CMF_PS1_V1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     725{
     726    return true;
     727}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c

    r29004 r30631  
    724724    return true;
    725725}
     726
     727bool pmSourcesWrite_CMF_PS1_V2_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     728{
     729    return true;
     730}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c

    r29620 r30631  
    762762    return true;
    763763}
     764
     765bool pmSourcesWrite_CMF_PS1_V3_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     766{
     767    return true;
     768}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_PS1_CAL_0.c

    r29004 r30631  
    702702    return true;
    703703}
     704
     705bool pmSourcesWrite_PS1_CAL_0_XRAD (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     706{
     707    return true;
     708}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_PS1_DEV_0.c

    r29004 r30631  
    248248    return true;
    249249}
     250
     251bool pmSourcesWrite_PS1_DEV_0_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     252{
     253    return true;
     254}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_PS1_DEV_1.c

    r29004 r30631  
    588588    return true;
    589589}
     590
     591bool pmSourcesWrite_PS1_DEV_1_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     592{
     593    return true;
     594}
  • branches/czw_branch/20101203/psModules/src/objects/pmSourceIO_SMPDATA.c

    r29004 r30631  
    222222    return true;
    223223}
     224
     225bool pmSourcesWrite_SMPDATA_XRAD(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
     226{
     227    return true;
     228}
  • branches/czw_branch/20101203/psModules/src/psmodules.h

    r29388 r30631  
    9898// the following headers are from psModule:imcombine
    9999#include <pmStack.h>
     100#include <pmSubtractionTypes.h>
    100101#include <pmStackReject.h>
    101102#include <pmSubtraction.h>
Note: See TracChangeset for help on using the changeset viewer.