IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 23573


Ignore:
Timestamp:
Mar 27, 2009, 11:49:17 AM (17 years ago)
Author:
Paul Price
Message:

Allow convolution of images to be optional when stacking.

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/ippconfig/recipes/ppStack.config

    r23498 r23573  
    11# Recipe configuration for ppStack (image combination)
    22
     3CONVOLVE        BOOL    TRUE            # Convolve images when stacking?
    34ITER            S32     1               # Number of rejection iterations
    45COMBINE.REJ     F32     3.0             # Rejection threshold in combination (sigma)
  • trunk/ppStack/src/ppStack.h

    r23341 r23573  
    77#include <pslib.h>
    88#include <psmodules.h>
     9
     10#include "ppStackOptions.h"
    911
    1012// Mask values for inputs
     
    106108/// Convolve image to match specified seeing
    107109bool ppStackMatch(pmReadout *readout,   // Readout to be convolved; replaced with output
    108                   psArray **regions,    // Array of regions used in each PSF matching, returned
    109                   psArray **kernels,    // Array of kernels used in each PSF matching, returned
    110                   float *chi2,          // Chi^2 from the stamps
    111                   float *weighting,     // Stack weighting (1/noise^2)
    112                   psArray *sources,     // Array of sources
    113                   const pmPSF *psf,     // Target PSF
    114                   psRandom *rng,        // Random number generator
     110                  ppStackOptions *options, // Options for stacking
     111                  int index,            // Index of image to match
    115112                  const pmConfig *config // Configuration
    116113    );
     
    120117///
    121118/// Corrects the source PSF photometry to a common system.  Return the sum of the exposure times.
    122 float ppStackSourcesTransparency(const psArray *sourceLists, // Sources for each input
    123                                  psVector *inputMask, // Indicates bad input
    124                                  const pmFPAview *view, // View to readout
    125                                  const pmConfig *config // Configuration
     119bool ppStackSourcesTransparency(ppStackOptions *options, // Stacking options
     120                                const pmFPAview *view, // View to readout
     121                                const pmConfig *config // Configuration
    126122    );
    127123
  • trunk/ppStack/src/ppStackCombineInitial.c

    r23341 r23573  
    1616    psAssert(config, "Require configuration");
    1717
    18     psTimerStart("PPSTACK_FINAL");
     18    if (!options->convolve) {
     19        // No need to do initial combination when we haven't convolved
     20        return true;
     21    }
     22
     23    psTimerStart("PPSTACK_INITIAL");
    1924
    2025    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
     
    6974        }
    7075
    71         // call: ppStackReadoutInitial(config, outRO, readouts, subRegions, subKernels)
    7276        psThreadJob *job = psThreadJobAlloc("PPSTACK_INITIAL_COMBINE"); // Job to start
    7377        psArrayAdd(job->args, 1, thread);
     
    128132
    129133    if (options->stats) {
    130         psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_FINAL", 0,
    131                          "Time to make final stack", psTimerMark("PPSTACK_FINAL"));
     134        psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_INITIAL", 0,
     135                         "Time to make final stack", psTimerMark("PPSTACK_INITIAL"));
    132136    }
    133137
  • trunk/ppStack/src/ppStackConvolve.c

    r23341 r23573  
    3030    int num = options->num;             // Number of inputs
    3131    options->cells = psArrayAlloc(num); // Cells for convolved images --- a handle for reading again
    32     options->subKernels = psArrayAlloc(num); // Subtraction kernels --- required in the stacking
    33     options->subRegions = psArrayAlloc(num); // Subtraction regions --- required in the stacking
     32    options->kernels = psArrayAlloc(num); // PSF-matching kernels --- required in the stacking
     33    options->regions = psArrayAlloc(num); // PSF-matching regions --- required in the stacking
    3434    int numGood = 0;                    // Number of good frames
    3535    options->numCols = 0;
     
    3838    psVectorInit(options->matchChi2, NAN);
    3939    options->weightings = psVectorAlloc(num, PS_TYPE_F32); // Combination weightings for images (1/noise^2)
    40     psVectorInit(options->weightings, NAN);
     40    psVectorInit(options->weightings, 0.0);
    4141    options->covariances = psArrayAlloc(num); // Covariance matrices
    4242
     
    7878
    7979        // Background subtraction, scaling and normalisation is performed automatically by the image matching
    80         psArray *regions = NULL, *kernels = NULL; // Regions and kernels used in subtraction
    8180        psTimerStart("PPSTACK_MATCH");
    82 
    83         if (!ppStackMatch(readout, &regions, &kernels, &options->matchChi2->data.F32[i],
    84                           &options->weightings->data.F32[i], options->sourceLists->data[i],
    85                           options->psf, rng, config)) {
     81        if (!ppStackMatch(readout, options, i, config)) {
    8682            psErrorStackPrint(stderr, "Unable to match image %d --- ignoring.", i);
    87             options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PPSTACK_MASK_MATCH;
     83            options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_MATCH;
    8884            psErrorClear();
    8985            continue;
     
    9288
    9389        if (options->stats) {
    94             pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, readout->analysis,
    95                                                                 PM_SUBTRACTION_ANALYSIS_KERNEL);// Conv kernel
    9690            psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_MATCH", PS_META_DUPLICATE_OK,
    9791                             "Time to match PSF", psTimerMark("PPSTACK_MATCH"));
    98             psMetadataAddF32(options->stats, PS_LIST_TAIL, "STAMP.MEAN", PS_META_DUPLICATE_OK,
    99                              "Mean deviation for stamps", kernels->mean);
    100             psMetadataAddF32(options->stats, PS_LIST_TAIL, "STAMP.RMS", PS_META_DUPLICATE_OK,
    101                              "RMS deviation for stamps", kernels->rms);
    102             psMetadataAddF32(options->stats, PS_LIST_TAIL, "STAMP.NUM", PS_META_DUPLICATE_OK,
    103                              "Number of stamps", kernels->numStamps);
    104             float deconv = psMetadataLookupF32(NULL, readout->analysis,
    105                                                PM_SUBTRACTION_ANALYSIS_DECONV_MAX); // Deconvolution fraction
    106             psMetadataAddF32(options->stats, PS_LIST_TAIL, "KERNEL.DECONV", PS_META_DUPLICATE_OK,
    107                              "Deconvolution fraction for kernel", deconv);
    10892            psMetadataAddF32(options->stats, PS_LIST_TAIL, "PPSTACK.WEIGHTING", PS_META_DUPLICATE_OK,
    10993                             "Weighting for image", options->weightings->data.F32[i]);
     94
     95            if (options->convolve) {
     96                // Pull parameters out of convolution kernel
     97                pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, readout->analysis,
     98                                                                    PM_SUBTRACTION_ANALYSIS_KERNEL);
     99                psMetadataAddF32(options->stats, PS_LIST_TAIL, "STAMP.MEAN", PS_META_DUPLICATE_OK,
     100                                 "Mean deviation for stamps", kernels->mean);
     101                psMetadataAddF32(options->stats, PS_LIST_TAIL, "STAMP.RMS", PS_META_DUPLICATE_OK,
     102                                 "RMS deviation for stamps", kernels->rms);
     103                psMetadataAddF32(options->stats, PS_LIST_TAIL, "STAMP.NUM", PS_META_DUPLICATE_OK,
     104                                 "Number of stamps", kernels->numStamps);
     105                float deconv = psMetadataLookupF32(NULL, readout->analysis,
     106                                                   PM_SUBTRACTION_ANALYSIS_DECONV_MAX);
     107                psMetadataAddF32(options->stats, PS_LIST_TAIL, "KERNEL.DECONV", PS_META_DUPLICATE_OK,
     108                                 "Deconvolution fraction for kernel", deconv);
     109            }
    110110        }
    111111        psLogMsg("ppStack", PS_LOG_INFO, "Time to match image %d: %f sec", i, psTimerClear("PPSTACK_MATCH"));
    112112
    113         options->subRegions->data[i] = regions;
    114         options->subKernels->data[i] = kernels;
    115 
    116113        // Write the temporary convolved files
    117         pmHDU *hdu = readout->parent->parent->parent->hdu; // HDU for convolved image
    118         assert(hdu);
    119         ppStackWriteImage(options->imageNames->data[i], hdu->header, readout->image, config);
    120         psMetadata *maskHeader = psMetadataCopy(NULL, hdu->header); // Copy of header, for mask
    121         pmConfigMaskWriteHeader(config, maskHeader);
    122         ppStackWriteImage(options->maskNames->data[i], maskHeader, readout->mask, config);
    123         psFree(maskHeader);
    124         psImageCovarianceTransfer(readout->variance, readout->covariance);
    125         ppStackWriteImage(options->varianceNames->data[i], hdu->header, readout->variance, config);
     114        if (options->convolve) {
     115            pmHDU *hdu = readout->parent->parent->parent->hdu; // HDU for convolved image
     116            assert(hdu);
     117            ppStackWriteImage(options->imageNames->data[i], hdu->header, readout->image, config);
     118            psMetadata *maskHeader = psMetadataCopy(NULL, hdu->header); // Copy of header, for mask
     119            pmConfigMaskWriteHeader(config, maskHeader);
     120            ppStackWriteImage(options->maskNames->data[i], maskHeader, readout->mask, config);
     121            psFree(maskHeader);
     122            psImageCovarianceTransfer(readout->variance, readout->covariance);
     123            ppStackWriteImage(options->varianceNames->data[i], hdu->header, readout->variance, config);
    126124#ifdef TESTING
    127         {
    128             psString name = NULL;
    129             psStringAppend(&name, "covariance_%d.fits", i);
    130             ppStackWriteImage(name, hdu->header, readout->covariance->image, config);
    131             pmStackVisualPlotTestImage(readout->covariance->image, name);
    132             psFree(name);
    133         }
     125            {
     126                psString name = NULL;
     127                psStringAppend(&name, "covariance_%d.fits", i);
     128                ppStackWriteImage(name, hdu->header, readout->covariance->image, config);
     129                pmStackVisualPlotTestImage(readout->covariance->image, name);
     130                psFree(name);
     131            }
    134132#endif
     133        }
    135134
    136135        pmCell *inCell = readout->parent; // Input cell
     
    152151    psFree(rng);
    153152
     153    psFree(options->norm); options->norm = NULL;
    154154    psFree(options->sourceLists); options->sourceLists = NULL;
    155155    psFree(options->psf); options->psf = NULL;
  • trunk/ppStack/src/ppStackMatch.c

    r23379 r23573  
    163163
    164164
    165 bool ppStackMatch(pmReadout *readout, psArray **regions, psArray **kernels, float *chi2, float *weighting,
    166                   psArray *sources, const pmPSF *psf, psRandom *rng, const pmConfig *config)
     165bool ppStackMatch(pmReadout *readout, ppStackOptions *options, int index, const pmConfig *config)
    167166{
    168167    assert(readout);
    169     assert(regions && !*regions);
    170     assert(kernels && !*kernels);
     168    assert(options);
    171169    assert(config);
    172     *weighting = 0.0;
    173170
    174171    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
     
    197194    }
    198195
    199     pmReadout *output = pmReadoutAlloc(NULL); // Output readout, for holding results temporarily
    200 
    201     static int numInput = -1;            // Index of input file
    202     numInput++;
     196    // Match the PSF
     197    if (options->convolve) {
     198        pmReadout *conv = pmReadoutAlloc(NULL); // Conv readout, for holding results temporarily
    203199#ifdef TESTING
    204     // Read previously produced kernel
    205     if (psMetadataLookupBool(NULL, config->arguments, "PPSTACK.DEBUG.STACK")) {
    206         const char *outName = psMetadataLookupStr(NULL, config->arguments, "OUTPUT"); // Output root
    207         assert(outName);
    208         // Read convolution kernel
    209         psString filename = NULL;   // Output filename
    210         psStringAppend(&filename, "%s.%d.kernel", outName, numInput);
    211         psString resolved = pmConfigConvertFilename(filename, config, false, false); // Resolved filename
    212         psFree(filename);
    213         psFits *fits = psFitsOpen(resolved, "r"); // FITS file for subtraction kernel
    214         psFree(resolved);
    215         if (!fits || !pmReadoutReadSubtractionKernels(output, fits)) {
    216             psError(PS_ERR_IO, false, "Unable to read previously produced kernel");
     200        // This is a hack to use the temporary convolved images and kernel generated previously.
     201        // This makes the 'matching' operation much faster, allowing debugging of the stack process easier.
     202        // It implicitly assumes the output root name is the same between invocations.
     203
     204        // Read previously produced kernel
     205        if (psMetadataLookupBool(NULL, config->arguments, "PPSTACK.DEBUG.STACK")) {
     206            pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.CONV.KERNEL", index);
     207            psAssert(file, "Require file");
     208
     209            pmFPAview *view = pmFPAviewAlloc(0); // View to readout of interest
     210            view->chip = view->cell = view->readout = 0;
     211            psString filename = pmFPAfileNameFromRule(filerule->rule, file, view); // Filename of interest
     212
     213            // Read convolution kernel
     214            psString resolved = pmConfigConvertFilename(filename, config, false, false); // Resolved filename
     215            psFree(filename);
     216            psFits *fits = psFitsOpen(resolved, "r"); // FITS file for subtraction kernel
     217            psFree(resolved);
     218            if (!fits || !pmReadoutReadSubtractionKernels(conv, fits)) {
     219                psError(PS_ERR_IO, false, "Unable to read previously produced kernel");
     220                psFitsClose(fits);
     221                return false;
     222            }
    217223            psFitsClose(fits);
    218             return false;
    219         }
    220         psFitsClose(fits);
    221 
    222         // Add in variance factor
    223         pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, output->analysis,
    224                                                             PM_SUBTRACTION_ANALYSIS_KERNEL); // Kernels
    225         float vf = pmSubtractionVarianceFactor(kernels, 0.0, 0.0, false); // Variance factor
    226         psMetadataItem *vfItem = psMetadataLookup(readout->parent->concepts, "CELL.VARFACTOR");
    227         if (!isfinite(vf)) {
    228             vf = 1.0;
    229         }
    230         if (isfinite(vfItem->data.F32)) {
    231             vfItem->data.F32 *= vf;
    232         } else {
    233             vfItem->data.F32 = vf;
    234         }
    235 
    236         // Read image, mask, variance
    237         const char *tempImage = psMetadataLookupStr(NULL, recipe, "TEMP.IMAGE"); // Suffix for image
    238         const char *tempMask = psMetadataLookupStr(NULL, recipe, "TEMP.MASK"); // Suffix for mask
    239         const char *tempVariance = psMetadataLookupStr(NULL, recipe, "TEMP.VARIANCE"); // Suffix for variance map
    240         psString imageName = NULL, maskName = NULL, varianceName = NULL; // Names for convolved images
    241         psStringAppend(&imageName, "%s.%d.%s", outName, numInput, tempImage);
    242         psStringAppend(&maskName, "%s.%d.%s", outName, numInput, tempMask);
    243         psStringAppend(&varianceName, "%s.%d.%s", outName, numInput, tempVariance);
    244 
    245         if (!readImage(&readout->image, imageName, config) || !readImage(&readout->mask, maskName, config) ||
    246             !readImage(&readout->variance, varianceName, config)) {
    247             psError(PS_ERR_IO, false, "Unable to read previously produced image.");
     224
     225            // Add in variance factor
     226            pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, conv->analysis,
     227                                                                PM_SUBTRACTION_ANALYSIS_KERNEL); // Kernels
     228            float vf = pmSubtractionVarianceFactor(kernels, 0.0, 0.0, false); // Variance factor
     229            psMetadataItem *vfItem = psMetadataLookup(readout->parent->concepts, "CELL.VARFACTOR");
     230            if (!isfinite(vf)) {
     231                vf = 1.0;
     232            }
     233            if (isfinite(vfItem->data.F32)) {
     234                vfItem->data.F32 *= vf;
     235            } else {
     236                vfItem->data.F32 = vf;
     237            }
     238
     239            if (!readImage(&readout->image, options->imageNames->data[index], config) ||
     240                !readImage(&readout->mask, options->maskNames->data[index], config) ||
     241                !readImage(&readout->variance, options->varianceNames->data[index], config)) {
     242                psError(PS_ERR_IO, false, "Unable to read previously produced image.");
     243                psFree(imageName);
     244                psFree(maskName);
     245                psFree(varianceName);
     246                return false;
     247            }
    248248            psFree(imageName);
    249249            psFree(maskName);
    250250            psFree(varianceName);
    251             return false;
    252         }
    253         psFree(imageName);
    254         psFree(maskName);
    255         psFree(varianceName);
    256 
    257         psRegion *region = psMetadataLookupPtr(NULL, output->analysis,
    258                                                PM_SUBTRACTION_ANALYSIS_REGION); // Convolution region
    259 
    260         pmSubtractionAnalysis(readout->analysis, kernels, region,
    261                               readout->image->numCols, readout->image->numRows);
    262 
    263         psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel
    264         psKernel *covar = psImageCovarianceCalculate(kernel, readout->covariance); // New covariance matrix
    265         psFree(readout->covariance);
    266         readout->covariance = covar;
    267         psFree(kernel);
    268 
    269     } else {
    270 #endif
    271 
    272         // Normal operations here
    273         if (psMetadataLookupBool(&mdok, config->arguments, "HAVE.PSF")) {
    274             assert(psf);
    275             assert(sources);
     251
     252            psRegion *region = psMetadataLookupPtr(NULL, conv->analysis,
     253                                                   PM_SUBTRACTION_ANALYSIS_REGION); // Convolution region
     254
     255            pmSubtractionAnalysis(readout->analysis, kernels, region,
     256                                  readout->image->numCols, readout->image->numRows);
     257
     258            psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel
     259            psKernel *covar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix
     260            psFree(readout->covariance);
     261            readout->covariance = covar;
     262            psFree(kernel);
     263        } else {
     264#endif
     265
     266            // Normal operations here
     267            psAssert(options->psf, "Require target PSF");
     268            psAssert(options->sourceLists && options->sourceLists->data[index], "Require source list");
    276269
    277270            int order = psMetadataLookupS32(NULL, ppsub, "SPATIAL.ORDER"); // Spatial polynomial order
     
    284277            float rej = psMetadataLookupF32(NULL, ppsub, "REJ"); // Rejection threshold
    285278            float sysError = psMetadataLookupF32(NULL, ppsub, "SYS"); // Relative systematic error in kernel
    286             pmSubtractionKernelsType type = pmSubtractionKernelsTypeFromString(
    287                 psMetadataLookupStr(NULL, ppsub, "KERNEL.TYPE")); // Kernel type
     279            const char *typeStr = psMetadataLookupStr(NULL, ppsub, "KERNEL.TYPE"); // Kernel type
     280            pmSubtractionKernelsType type = pmSubtractionKernelsTypeFromString(typeStr); // Kernel type
    288281            psVector *widths = psMetadataLookupPtr(NULL, ppsub, "ISIS.WIDTHS"); // ISIS Gaussian widths
    289282            psVector *orders = psMetadataLookupPtr(NULL, ppsub, "ISIS.ORDERS"); // ISIS Polynomial orders
     
    308301            }
    309302
    310 #if 0
    311             // Testing the normalisation of the fake image
    312             {
    313                 pmReadout *test = pmReadoutAlloc(NULL); // Test readout
    314                 psArray *sources = psArrayAlloc(1);     // Array of sources
    315                 pmSource *source = pmSourceAlloc();     // Source
    316                 sources->data[0] = source;
    317                 source->peak = pmPeakAlloc(500, 500, 10000, PM_PEAK_LONE);
    318                 source->psfMag = -13.0;
    319                 pmReadoutFakeFromSources(test, 1000, 1000, sources, NULL, NULL, psf, 0.1, 0, false, true);
    320                 float sum = 0.0;
    321                 for (int y = 0; y < test->image->numRows; y++) {
    322                     for (int x = 0; x < test->image->numCols; x++) {
    323                         sum += test->image->data.F32[y][x];
    324                     }
    325                 }
    326                 fprintf(stderr, "Photometry: %f --> %f = -13.0 ???\n", sum, -2.5*log10(sum));
    327 
    328                 psFits *fits = psFitsOpen("testphot.fits", "w");
    329                 psFitsWriteImage(fits, NULL, test->image, 0, NULL);
    330                 psFitsClose(fits);
    331                 exit(0);
    332             }
    333 #endif
    334 
    335303            pmReadout *fake = pmReadoutAlloc(NULL); // Fake readout with target PSF
    336304
    337305            // For the sake of stamps, remove nearby sources
    338             psArray *stampSources = stackSourcesFilter(sources, footprint); // Filtered list of sources
     306            psArray *stampSources = stackSourcesFilter(options->sourceLists->data[index],
     307                                                       footprint); // Filtered list of sources
    339308
    340309            if (!pmReadoutFakeFromSources(fake, readout->image->numCols, readout->image->numRows,
    341                                           stampSources, NULL, NULL, psf, NAN, footprint + size,
     310                                          stampSources, NULL, NULL, options->psf, NAN, footprint + size,
    342311                                          false, true)) {
    343312                psError(PS_ERR_UNKNOWN, false, "Unable to generate fake image with target PSF.");
    344313                psFree(fake);
    345314                psFree(optWidths);
    346                 psFree(output);
     315                psFree(conv);
    347316                return false;
    348317            }
     
    357326                pmHDU *hdu = pmHDUFromCell(readout->parent);
    358327                psString name = NULL;
    359                 psStringAppend(&name, "fake_%03d.fits", numInput);
     328                psStringAppend(&name, "fake_%03d.fits", index);
    360329                pmStackVisualPlotTestImage(fake->image, name);
    361330                psFits *fits = psFitsOpen(name, "w");
     
    367336                pmHDU *hdu = pmHDUFromCell(readout->parent);
    368337                psString name = NULL;
    369                 psStringAppend(&name, "real_%03d.fits", numInput);
     338                psStringAppend(&name, "real_%03d.fits", index);
    370339                pmStackVisualPlotTestImage(readout->image, name);
    371340                psFits *fits = psFitsOpen(name, "w");
     
    384353                                                               PM_SUBTRACTION_ANALYSIS_KERNEL); // Conv kernel
    385354            if (kernel) {
    386                 if (!pmSubtractionMatchPrecalc(output, NULL, readout, fake, readout->analysis,
     355                if (!pmSubtractionMatchPrecalc(conv, NULL, readout, fake, readout->analysis,
    387356                                               stride, sysError, maskVal, maskBad, maskPoor,
    388357                                               poorFrac, badFrac)) {
     
    391360                    psFree(optWidths);
    392361                    psFree(stampSources);
    393                     psFree(output);
     362                    psFree(conv);
    394363                    return false;
    395364                }
    396365            } else {
    397                 if (!pmSubtractionMatch(output, NULL, readout, fake, footprint, stride, regionSize, spacing,
     366                if (!pmSubtractionMatch(conv, NULL, readout, fake, footprint, stride, regionSize, spacing,
    398367                                        threshold, stampSources, stampsName, type, size, order, widths,
    399368                                        orders, inner, ringsOrder, binning, penalty,
     
    405374                    psFree(optWidths);
    406375                    psFree(stampSources);
    407                     psFree(output);
     376                    psFree(conv);
    408377                    return false;
    409378                }
     
    414383                pmHDU *hdu = pmHDUFromCell(readout->parent);
    415384                psString name = NULL;
    416                 psStringAppend(&name, "conv_%03d.fits", numInput);
    417                 pmStackVisualPlotTestImage(output->image, name);
     385                psStringAppend(&name, "conv_%03d.fits", index);
     386                pmStackVisualPlotTestImage(conv->image, name);
    418387                psFits *fits = psFitsOpen(name, "w");
    419388                psFree(name);
    420                 psFitsWriteImage(fits, hdu->header, output->image, 0, NULL);
     389                psFitsWriteImage(fits, hdu->header, conv->image, 0, NULL);
    421390                psFitsClose(fits);
    422391            }
     
    424393                pmHDU *hdu = pmHDUFromCell(readout->parent);
    425394                psString name = NULL;
    426                 psStringAppend(&name, "diff_%03d.fits", numInput);
     395                psStringAppend(&name, "diff_%03d.fits", index);
    427396                pmStackVisualPlotTestImage(fake->image, name);
    428397                psFits *fits = psFitsOpen(name, "w");
    429398                psFree(name);
    430                 psBinaryOp(fake->image, output->image, "-", fake->image);
     399                psBinaryOp(fake->image, conv->image, "-", fake->image);
    431400                psFitsWriteImage(fits, hdu->header, fake->image, 0, NULL);
    432401                psFitsClose(fits);
     
    444413            // Set the variance factor
    445414            psMetadataItem *vfItem = psMetadataLookup(readout->parent->concepts, "CELL.VARFACTOR");
    446             float vf = psMetadataLookupF32(NULL, output->analysis, PM_SUBTRACTION_ANALYSIS_VARFACTOR_1);
     415            float vf = psMetadataLookupF32(NULL, conv->analysis, PM_SUBTRACTION_ANALYSIS_VARFACTOR_1);
    447416            if (!isfinite(vf)) {
    448417                vf = 1.0;
     
    459428            psFree(readout->variance);
    460429            psFree(readout->covariance);
    461             readout->image  = psMemIncrRefCounter(output->image);
    462             readout->mask   = psMemIncrRefCounter(output->mask);
    463             readout->variance = psMemIncrRefCounter(output->variance);
    464             readout->covariance = psImageCovarianceTruncate(output->covariance, COVAR_FRAC);
    465         } else {
    466             // Fake the convolution
    467             psRegion *region = psRegionAlloc(0, readout->image->numCols - 1, 0, readout->image->numRows - 1);
    468             psMetadataAddPtr(output->analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_REGION,
    469                              PS_DATA_REGION | PS_META_DUPLICATE_OK, "Fake subtraction region", region);
    470             psFree(region);
    471             pmSubtractionKernels *kernels = pmSubtractionKernelsPOIS(FAKE_SIZE, 0, penalty,
    472                                                                      PM_SUBTRACTION_MODE_1);
    473             // Set solution to delta function
    474             kernels->solution1 = psVectorAlloc(kernels->num + 2, PS_TYPE_F64);
    475             psVectorInit(kernels->solution1, 0.0);
    476             int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation
    477             kernels->solution1->data.F64[normIndex] = 1.0;
    478             psMetadataAddPtr(output->analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_KERNEL,
    479                              PS_DATA_UNKNOWN | PS_META_DUPLICATE_OK, "Fake subtraction kernel", kernels);
    480             psFree(kernels);
    481         }
    482 
     430            readout->image  = psMemIncrRefCounter(conv->image);
     431            readout->mask   = psMemIncrRefCounter(conv->mask);
     432            readout->variance = psMemIncrRefCounter(conv->variance);
     433            readout->covariance = psImageCovarianceTruncate(conv->covariance, COVAR_FRAC);
    483434#ifdef TESTING
    484         // Write convolution kernel
     435        }
     436#endif
     437
     438        // Extract the regions and solutions used in the image matching
     439        // This stops them from being freed when we iterate back up the FPA
     440        psArray *regions = options->regions->data[index] = psArrayAllocEmpty(ARRAY_BUFFER); // Match regions
    485441        {
    486             const char *outName = psMetadataLookupStr(NULL, config->arguments, "OUTPUT"); // Output root
    487             assert(outName);
    488 
    489             psString filename = NULL;   // Output filename
    490             psStringAppend(&filename, "%s.%d.kernel", outName, numInput);
    491             psString resolved = pmConfigConvertFilename(filename, config, true, false); // Resolved filename
    492             psFree(filename);
    493             psFits *fits = psFitsOpen(resolved, "w"); // FITS file for subtraction kernel
    494             psFree(resolved);
    495             pmReadoutWriteSubtractionKernels(output, fits);
    496             psFitsClose(fits);
    497         }
    498     }
    499 #endif
    500 
    501     readout->analysis = psMetadataCopy(readout->analysis, output->analysis);
    502 
    503 // Extract the regions and solutions used in the image matching
    504 // This stops them from being freed when we iterate back up the FPA
    505     *regions = psArrayAllocEmpty(ARRAY_BUFFER); // Array of regions
    506     {
    507         psString regex = NULL;          // Regular expression
    508         psStringAppend(&regex, "^%s$", PM_SUBTRACTION_ANALYSIS_REGION);
    509         psMetadataIterator *iter = psMetadataIteratorAlloc(output->analysis, PS_LIST_HEAD, regex); // Iterator
    510         psFree(regex);
    511         psMetadataItem *item = NULL;// Item from iteration
    512         while ((item = psMetadataGetAndIncrement(iter))) {
    513             assert(item->type == PS_DATA_REGION);
    514             *regions = psArrayAdd(*regions, ARRAY_BUFFER, item->data.V);
    515         }
    516         psFree(iter);
    517     }
    518     *kernels = psArrayAllocEmpty(ARRAY_BUFFER); // Array of kernels
    519     {
    520         psString regex = NULL;          // Regular expression
    521         psStringAppend(&regex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL);
    522         psMetadataIterator *iter = psMetadataIteratorAlloc(output->analysis, PS_LIST_HEAD, regex); // Iterator
    523         psFree(regex);
    524         psMetadataItem *item = NULL;// Item from iteration
    525         while ((item = psMetadataGetAndIncrement(iter))) {
    526             assert(item->type == PS_DATA_UNKNOWN);
    527             // Set the normalisation dimensions, since these will be otherwise unavailable when reading the
    528             // images by scans.
    529             pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction
    530             kernel->numCols = readout->image->numCols;
    531             kernel->numRows = readout->image->numRows;
    532 
    533             *kernels = psArrayAdd(*kernels, ARRAY_BUFFER, kernel);
    534         }
    535         psFree(iter);
    536     }
    537     assert((*regions)->n == (*kernels)->n);
    538 
    539     // Record chi^2
    540     {
    541         *chi2 = 0.0;
    542         int num = 0;                    // Number of measurements of chi^2
    543         psString regex = NULL;          // Regular expression
    544         psStringAppend(&regex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL);
    545         psMetadataIterator *iter = psMetadataIteratorAlloc(output->analysis, PS_LIST_HEAD, regex); // Iterator
    546         psFree(regex);
    547         psMetadataItem *item = NULL;// Item from iteration
    548         while ((item = psMetadataGetAndIncrement(iter))) {
    549             assert(item->type == PS_DATA_UNKNOWN);
    550             pmSubtractionKernels *kernels = item->data.V; // Convolution kernels
    551             *chi2 += kernels->mean;
    552             num++;
    553         }
    554         psFree(iter);
    555         *chi2 /= psImageCovarianceFactor(readout->covariance) * num;
    556     }
    557 
    558     // Reject image completely if the maximum deconvolution fraction exceeds the limit
    559     float deconv = psMetadataLookupF32(NULL, output->analysis,
    560                                        PM_SUBTRACTION_ANALYSIS_DECONV_MAX); // Maximum deconvolution fraction
    561     if (deconv > deconvLimit) {
    562         psWarning("Maximum deconvolution fraction (%f) exceeds limit (%f) --- rejecting\n",
    563                   deconv, deconvLimit);
    564         psFree(output);
    565         return NULL;
     442            psString regex = NULL;          // Regular expression
     443            psStringAppend(&regex, "^%s$", PM_SUBTRACTION_ANALYSIS_REGION);
     444            psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex);
     445            psFree(regex);
     446            psMetadataItem *item = NULL;// Item from iteration
     447            while ((item = psMetadataGetAndIncrement(iter))) {
     448                assert(item->type == PS_DATA_REGION);
     449                regions = psArrayAdd(regions, ARRAY_BUFFER, item->data.V);
     450            }
     451            psFree(iter);
     452        }
     453        psArray *kernels = options->kernels->data[index] = psArrayAllocEmpty(ARRAY_BUFFER); // Match kernels
     454        {
     455            psString regex = NULL;          // Regular expression
     456            psStringAppend(&regex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL);
     457            psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex);
     458            psFree(regex);
     459            psMetadataItem *item = NULL;// Item from iteration
     460            while ((item = psMetadataGetAndIncrement(iter))) {
     461                assert(item->type == PS_DATA_UNKNOWN);
     462                // Set the normalisation dimensions, since these will be otherwise unavailable when reading
     463                // the images by scans.
     464                pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction
     465                kernel->numCols = readout->image->numCols;
     466                kernel->numRows = readout->image->numRows;
     467
     468                kernels = psArrayAdd(kernels, ARRAY_BUFFER, kernel);
     469            }
     470            psFree(iter);
     471        }
     472        psAssert((regions)->n == (kernels)->n, "Number of match regions and kernels should match");
     473
     474        // Record chi^2
     475        {
     476            double sum = 0.0;           // Sum of chi^2
     477            int num = 0;                // Number of measurements of chi^2
     478            psString regex = NULL;      // Regular expression
     479            psStringAppend(&regex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL);
     480            psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex);
     481            psFree(regex);
     482            psMetadataItem *item = NULL;// Item from iteration
     483            while ((item = psMetadataGetAndIncrement(iter))) {
     484                assert(item->type == PS_DATA_UNKNOWN);
     485                pmSubtractionKernels *kernels = item->data.V; // Convolution kernels
     486                sum += kernels->mean;
     487                num++;
     488            }
     489            psFree(iter);
     490            options->matchChi2->data.F32[index] = sum / (psImageCovarianceFactor(readout->covariance) * num);
     491        }
     492
     493        // Reject image completely if the maximum deconvolution fraction exceeds the limit
     494        float deconv = psMetadataLookupF32(NULL, conv->analysis,
     495                                           PM_SUBTRACTION_ANALYSIS_DECONV_MAX); // Max deconvolution fraction
     496        if (deconv > deconvLimit) {
     497            psWarning("Maximum deconvolution fraction (%f) exceeds limit (%f) --- rejecting\n",
     498                      deconv, deconvLimit);
     499            psFree(conv);
     500            return NULL;
     501        }
     502
     503        readout->analysis = psMetadataCopy(readout->analysis, conv->analysis);
     504
     505        psFree(conv);
     506    } else {
     507        // Match the normalisation
     508        float norm = powf(10.0, -0.4 * options->norm->data.F32[index]); // Normalisation
     509        psBinaryOp(readout->image, readout->image, "*", psScalarAlloc(norm, PS_TYPE_F32));
     510        psBinaryOp(readout->variance, readout->variance, "*", psScalarAlloc(PS_SQR(norm), PS_TYPE_F32));
    566511    }
    567512
    568513    // Ensure the background value is zero
    569514    psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for background
     515    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
    570516    if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) {
    571517        psWarning("Can't measure background for image.");
     
    581527    if (!psImageBackground(bg, NULL, readout->variance, readout->mask, maskVal | maskBad, rng)) {
    582528        psError(PS_ERR_UNKNOWN, false, "Can't measure mean variance for image.");
    583         psFree(output);
     529        psFree(rng);
     530        psFree(bg);
    584531        return false;
    585532    }
    586     *weighting = 1.0 / (psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN) *
    587                         psImageCovarianceFactor(readout->covariance));
     533    options->weightings->data.F32[index] = 1.0 / (psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN) *
     534                                                  psImageCovarianceFactor(readout->covariance));
    588535    psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "PPSTACK.WEIGHTING", 0,
    589                      "Weighting by 1/noise^2 for stack", *weighting);
    590 
     536                     "Weighting by 1/noise^2 for stack", options->weightings->data.F32[index]);
     537
     538    psFree(rng);
    591539    psFree(bg);
    592 
    593 #if 0
    594 #define RADIUS 10                       // Radius of photometry
    595 #define MIN_ERR 0.05                    // Minimum photometric error, mag
    596 #define MAX_MAG -13                     // Maximum magnitude for source
    597 
    598     // Ensure the normalisation is correct
    599     // XXX Ideally, would like to do proper PSF-fit photometry, but will settle for aperture photometry
    600     int numSources = sources->n;        // Number of sources
    601     psVector *ratio = psVectorAlloc(numSources, PS_TYPE_F32); // Flux ratios for sources
    602     psVector *ratioMask = psVectorAlloc(numSources, PS_TYPE_MASK); // Mask for flux ratios
    603     psVectorInit(ratioMask, 0xFF);
    604     psImage *image = readout->image;    // Image of interest
    605     psImage *mask = readout->mask;      // Mask of interest
    606     int numCols = image->numCols, numRows = image->numRows; // Size of image
    607     for (int i = 0; i < numSources; i++) {
    608         pmSource *source = sources->data[i]; // Source of interest
    609         if (!source || source->mode & SOURCE_MASK || !isfinite(source->psfMag) || !isfinite(source->errMag) ||
    610             source->errMag > MIN_ERR || source->psfMag > MAX_MAG) {
    611             continue;
    612         }
    613 
    614         float xSrc, ySrc;              // Source coordinates
    615         coordsFromSource(&xSrc, &ySrc, source);
    616         int xMin = PS_MAX(0, xSrc - RADIUS), xMax = PS_MIN(numCols - 1, xSrc + RADIUS); // Bounds in x
    617         int yMin = PS_MAX(0, ySrc - RADIUS), yMax = PS_MIN(numRows - 1, ySrc + RADIUS); // Bounds in y
    618         int numPix = 0;                 // Number of pixels
    619         float sum = 0.0;                // Sum of pixels
    620         for (int y = yMin; y <= yMax; y++) {
    621             for (int x = xMin; x <= xMax; x++) {
    622                 if (mask->data.PS_TYPE_MASK_DATA[y][x] & maskBad) {
    623                     continue;
    624                 }
    625                 sum += image->data.F32[y][x];
    626                 numPix++;
    627             }
    628         }
    629         if (sum >= 0 && numPix > 0) {
    630             float mag = -2.5 * log10(sum * M_PI * PS_SQR(RADIUS) / numPix); // Instrumental magnitude
    631             ratio->data.F32[i] = mag - source->psfMag;
    632             ratioMask->data.PS_TYPE_MASK_DATA[i] = 0;
    633         }
    634     }
    635 
    636     psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics
    637     if (!psVectorStats(stats, ratio, NULL, ratioMask, 0xFF)) {
    638         psWarning("Unable to measure normalisation --- assuming correct.");
    639     } else {
    640         psLogMsg("ppStack", PS_LOG_INFO, "Renormalising image by %f (+/- %f) mag\n",
    641                  stats->robustMedian, stats->robustStdev);
    642         float norm = powf(10.0, -0.4 * stats->robustMedian); // Normalisation to apply
    643         psBinaryOp(image, image, "*", psScalarAlloc(norm, PS_TYPE_F32));
    644     }
    645     psFree(stats);
    646     psFree(ratio);
    647     psFree(ratioMask);
    648 #endif
    649540
    650541#ifdef TESTING
     
    652543        pmHDU *hdu = pmHDUFromCell(readout->parent);
    653544        psString name = NULL;
    654         psStringAppend(&name, "convolved_%03d.fits", numInput);
    655         pmStackVisualPlotTestImage(output->image, name);
     545        psStringAppend(&name, "convolved_%03d.fits", index);
     546        pmStackVisualPlotTestImage(readout->image, name);
    656547        psFits *fits = psFitsOpen(name, "w");
    657548        psFree(name);
    658         psFitsWriteImage(fits, hdu->header, output->image, 0, NULL);
     549        psFitsWriteImage(fits, hdu->header, readout->image, 0, NULL);
    659550        psFitsClose(fits);
    660551    }
    661552#endif
    662 
    663     psFree(output);
    664553
    665554    return true;
  • trunk/ppStack/src/ppStackOptions.c

    r23341 r23573  
    1818    psFree(options->inputMask);
    1919    psFree(options->sourceLists);
     20    psFree(options->norm);
    2021    psFree(options->cells);
    21     psFree(options->subKernels);
    22     psFree(options->subRegions);
     22    psFree(options->kernels);
     23    psFree(options->regions);
    2324    psFree(options->matchChi2);
    2425    psFree(options->weightings);
     
    3536    psMemSetDeallocator(options, (psFreeFunc)stackOptionsFree);
    3637
     38    options->convolve = true;
    3739    options->stats = NULL;
    3840    options->statsFile = NULL;
     
    4446    options->inputMask = NULL;
    4547    options->sourceLists = NULL;
     48    options->norm = NULL;
    4649    options->cells = NULL;
    47     options->subKernels = NULL;
    48     options->subRegions = NULL;
     50    options->kernels = NULL;
     51    options->regions = NULL;
    4952    options->numCols = 0;
    5053    options->numRows = 0;
  • trunk/ppStack/src/ppStackOptions.h

    r23341 r23573  
    88typedef struct {
    99    // Setup
     10    bool convolve;                      // Convolve images?
    1011    psMetadata *stats;                  // Statistics for output
    1112    FILE *statsFile;                    // File to which to write statistics
     
    1718    psVector *inputMask;                // Mask for inputs
    1819    psArray *sourceLists;               // Individual lists of sources for matching
     20    psVector *norm;                     // Normalisation for each image
    1921    // Convolve
    2022    psArray *cells;                     // Cells for convolved images --- a handle for reading again
    21     psArray *subKernels;                // Subtraction kernels --- required in the stacking
    22     psArray *subRegions;                // Subtraction regions --- required in the stacking
     23    psArray *kernels;                   // PSF-matching kernels --- required in the stacking
     24    psArray *regions;                   // PSF-matching regions --- required in the stacking
    2325    int numCols, numRows;               // Size of image
    2426    psVector *matchChi2;                // chi^2 for stamps from matching
  • trunk/ppStack/src/ppStackPrepare.c

    r23341 r23573  
    127127    psVectorInit(options->inputMask, 0);
    128128
    129     if (psMetadataLookupBool(NULL, config->arguments, "HAVE.PSF")) {
    130         pmFPAfileActivate(config->files, false, NULL);
    131         ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
    132         pmFPAview *view = ppStackFilesIterateDown(config);
    133         if (!view) {
    134             return false;
    135         }
    136 
    137         // Generate list of PSFs
    138         psMetadataIterator *fileIter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD,
    139                                                                "^PPSTACK.INPUT$"); // Iterator
    140         psMetadataItem *fileItem; // Item from iteration
    141         psArray *psfs = psArrayAlloc(num); // PSFs for PSF envelope
    142         int numCols = 0, numRows = 0;   // Size of image
    143         int index = 0;                  // Index for file
    144         while ((fileItem = psMetadataGetAndIncrement(fileIter))) {
    145             assert(fileItem->type == PS_DATA_UNKNOWN);
    146             pmFPAfile *inputFile = fileItem->data.V; // An input file
     129    pmFPAfileActivate(config->files, false, NULL);
     130    ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
     131    pmFPAview *view = ppStackFilesIterateDown(config);
     132    if (!view) {
     133        return false;
     134    }
     135
     136    psMetadataIterator *fileIter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD, "^PPSTACK.INPUT$");
     137    psMetadataItem *fileItem; // Item from iteration
     138    psArray *psfs = psArrayAlloc(num); // PSFs for PSF envelope
     139    int numCols = 0, numRows = 0;   // Size of image
     140    int index = 0;                  // Index for file
     141    while ((fileItem = psMetadataGetAndIncrement(fileIter))) {
     142        assert(fileItem->type == PS_DATA_UNKNOWN);
     143        pmFPAfile *inputFile = fileItem->data.V; // An input file
     144
     145        // Get list of PSFs, to determine target PSF
     146        if (options->convolve) {
    147147            pmChip *chip = pmFPAviewThisChip(view, inputFile->fpa); // The chip: holds the PSF
    148148            pmPSF *psf = psMetadataLookupPtr(NULL, chip->analysis, "PSPHOT.PSF"); // PSF
     
    173173                numRows = naxis2;
    174174            }
    175 
    176             pmReadout *ro = pmFPAviewThisReadout(view, inputFile->fpa); // Readout with sources
    177             psArray *sources = psMetadataLookupPtr(NULL, ro->analysis, "PSPHOT.SOURCES"); // Sources
    178             if (!sources) {
    179                 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find sources in readout.");
    180                 return NULL;
    181             }
    182             options->sourceLists->data[index] = psMemIncrRefCounter(sources);
    183 
    184             // Re-do photometry if we don't trust the source lists
    185             if (psMetadataLookupBool(NULL, recipe, "PHOT")) {
    186                 psTrace("ppStack", 2, "Photometering input %d of %d....\n", index, num);
    187                 pmFPAfileActivate(config->files, false, NULL);
    188                 ppStackFileActivationSingle(config, PPSTACK_FILES_CONVOLVE, true, index);
    189                 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", index); // File
    190                 pmFPAview *photView = ppStackFilesIterateDown(config);
    191                 if (!photView) {
    192                     psFree(view);
    193                     return false;
    194                 }
    195 
    196                 pmReadout *ro = pmFPAviewThisReadout(view, file->fpa); // Readout of interest
    197 
    198                 if (!ppStackInputPhotometer(ro, sources, config)) {
    199                     psError(PS_ERR_UNKNOWN, false, "Unable to do photometry on input sources");
    200                     psFree(view);
    201                     psFree(photView);
    202                     return false;
    203                 }
    204 
     175        }
     176
     177
     178        pmReadout *ro = pmFPAviewThisReadout(view, inputFile->fpa); // Readout with sources
     179        psArray *sources = psMetadataLookupPtr(NULL, ro->analysis, "PSPHOT.SOURCES"); // Sources
     180        if (!sources) {
     181            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find sources in readout.");
     182            return NULL;
     183        }
     184        options->sourceLists->data[index] = psMemIncrRefCounter(sources);
     185
     186        // Re-do photometry if we don't trust the source lists
     187        if (psMetadataLookupBool(NULL, recipe, "PHOT")) {
     188            psTrace("ppStack", 2, "Photometering input %d of %d....\n", index, num);
     189            pmFPAfileActivate(config->files, false, NULL);
     190            ppStackFileActivationSingle(config, PPSTACK_FILES_CONVOLVE, true, index);
     191            pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", index); // File
     192            pmFPAview *photView = ppStackFilesIterateDown(config);
     193            if (!photView) {
     194                psFree(view);
     195                return false;
     196            }
     197
     198            pmReadout *ro = pmFPAviewThisReadout(view, file->fpa); // Readout of interest
     199
     200            if (!ppStackInputPhotometer(ro, sources, config)) {
     201                psError(PS_ERR_UNKNOWN, false, "Unable to do photometry on input sources");
     202                psFree(view);
    205203                psFree(photView);
    206                 if (!ppStackFilesIterateUp(config)) {
    207                     psFree(view);
    208                     return false;
    209                 }
    210                 pmFPAfileActivate(config->files, false, NULL);
    211                 ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
    212             }
    213 
    214             index++;
    215         }
    216         psFree(fileIter);
    217 
    218         // Zero point calibration
    219         options->sumExposure = ppStackSourcesTransparency(options->sourceLists, options->inputMask,
    220                                                           view, config);
    221         if (!isfinite(options->sumExposure) || options->sumExposure <= 0) {
    222             psError(PS_ERR_UNKNOWN, false, "Unable to calculate transparency differences");
    223             psFree(view);
    224             return false;
    225         }
    226 
    227         // Generate target PSF
     204                return false;
     205            }
     206
     207            psFree(photView);
     208            if (!ppStackFilesIterateUp(config)) {
     209                psFree(view);
     210                return false;
     211            }
     212            pmFPAfileActivate(config->files, false, NULL);
     213            ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
     214        }
     215
     216        index++;
     217    }
     218    psFree(fileIter);
     219
     220    // Generate target PSF
     221    if (options->convolve) {
    228222        options->psf = ppStackPSF(config, numCols, numRows, psfs, options->inputMask);
    229223        psFree(psfs);
     
    240234                         "Target PSF", options->psf);
    241235        outChip->data_exists = true;
    242 
     236    }
     237
     238    // Zero point calibration
     239    if (!ppStackSourcesTransparency(options, view, config)) {
     240        psError(PS_ERR_UNKNOWN, false, "Unable to calculate transparency differences");
    243241        psFree(view);
    244 
    245         if (!ppStackFilesIterateUp(config)) {
    246             return false;
    247         }
     242        return false;
     243    }
     244    psFree(view);
     245
     246    if (!ppStackFilesIterateUp(config)) {
     247        return false;
    248248    }
    249249
  • trunk/ppStack/src/ppStackReject.c

    r23341 r23573  
    1414    psAssert(options, "Require options");
    1515    psAssert(config, "Require configuration");
     16
     17    if (!options->convolve) {
     18        // No need to do complicated rejection when we haven't convolved
     19        return true;
     20    }
    1621
    1722    int num = options->num;             // Number of inputs
     
    8691
    8792        psPixels *reject = pmStackReject(options->inspect->data[i], options->numCols, options->numRows,
    88                                          threshold, poorFrac, stride, options->subRegions->data[i],
    89                                          options->subKernels->data[i]); // Rejected pixels
     93                                         threshold, poorFrac, stride, options->regions->data[i],
     94                                         options->kernels->data[i]); // Rejected pixels
    9095
    9196#ifdef TESTING
     
    141146
    142147    psFree(options->inspect); options->inspect = NULL;
    143     psFree(options->subKernels); options->subKernels = NULL;
    144     psFree(options->subRegions); options->subRegions = NULL;
     148    psFree(options->kernels); options->kernels = NULL;
     149    psFree(options->regions); options->regions = NULL;
    145150
    146151    if (numRejected >= num - 1) {
  • trunk/ppStack/src/ppStackSetup.c

    r23341 r23573  
    1111#include "ppStackLoop.h"
    1212
     13#define BUFFER 16                       // Buffer for name array
     14
     15// Generate an array of input filenames
     16static psArray *stackNameArray(pmConfig *config, // Configuration
     17                               const char *name // Name of file
     18    )
     19{
     20    psAssert(config, "Require configuration");
     21    psAssert(config, "Require file name");
     22
     23    psString regex = NULL;             // Regular expression for selecting file
     24    psStringAppend(&regex, "^%s$", name);
     25    psMetadataIterator *iter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD, regex); // Iterator
     26    psFree(regex);
     27    psMetadataItem *item;               // Item from iteration
     28    psArray *array = psArrayAlloc(BUFFER); // Array of file names
     29    while ((item = psMetadataGetAndIncrement(iter))) {
     30        psAssert(item->type == PS_DATA_UNKNOWN, "Should be this type");
     31        pmFPAfile *file = item->data.V; // An input file
     32
     33        psString filename = psStringCopy(file->filename); // Filename of interest
     34        psArrayAdd(array, array->n, filename);
     35        psFree(filename);               // Drop reference
     36    }
     37    psFree(iter);
     38
     39    return array;
     40}
     41
     42
    1343bool ppStackSetup(ppStackOptions *options, pmConfig *config)
    1444{
     
    1848    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
    1949    psAssert(recipe, "We've thrown an error on this before.");
     50
     51    options->convolve = psMetadataLookupBool(NULL, config->arguments, "CONVOLVE"); // Convolve images?
     52    if (!psMetadataLookupBool(NULL, config->arguments, "HAVE.PSF")) {
     53        psWarning("No PSFs provided --- unable to convolve to common PSF.");
     54        options->convolve = false;
     55    }
    2056
    2157    int num = psMetadataLookupS32(NULL, config->arguments, "INPUTS.NUM"); // Number of inputs
     
    3672    }
    3773
    38     const char *tempDir = psMetadataLookupStr(NULL, recipe, "TEMP.DIR"); // Directory for temporary images
    39     if (!tempDir) {
    40         psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find TEMP.DIR in recipe");
    41         return false;
     74    // Generate temporary names for convolved images
     75    if (options->convolve) {
     76        const char *tempDir = psMetadataLookupStr(NULL, recipe, "TEMP.DIR"); // Directory for temporary images
     77        if (!tempDir) {
     78            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find TEMP.DIR in recipe");
     79            return false;
     80        }
     81
     82        psString outputName = psStringCopy(psMetadataLookupStr(NULL, config->arguments,
     83                                                               "OUTPUT")); // Name for temporary files
     84        const char *tempName = basename(outputName);
     85        if (!tempName) {
     86            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to construct basename for temporary files.");
     87            psFree(outputName);
     88            return false;
     89        }
     90
     91        const char *tempImage = psMetadataLookupStr(NULL, recipe, "TEMP.IMAGE"); // Suffix for images
     92        const char *tempMask = psMetadataLookupStr(NULL, recipe, "TEMP.MASK"); // Suffix for masks
     93        const char *tempVariance = psMetadataLookupStr(NULL, recipe, "TEMP.VARIANCE"); // Suffix for var maps
     94        if (!tempImage || !tempMask || !tempVariance) {
     95            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     96                    "Unable to find TEMP.IMAGE, TEMP.MASK and TEMP.VARIANCE in recipe");
     97            psFree(outputName);
     98            return false;
     99        }
     100
     101        options->imageNames = psArrayAlloc(num);
     102        options->maskNames = psArrayAlloc(num);
     103        options->varianceNames = psArrayAlloc(num);
     104        for (int i = 0; i < num; i++) {
     105            psString imageName = NULL, maskName = NULL, varianceName = NULL; // Names for convolved images
     106            psStringAppend(&imageName, "%s/%s.%d.%s", tempDir, tempName, i, tempImage);
     107            psStringAppend(&maskName, "%s/%s.%d.%s", tempDir, tempName, i, tempMask);
     108            psStringAppend(&varianceName, "%s/%s.%d.%s", tempDir, tempName, i, tempVariance);
     109            psTrace("ppStack", 5, "Temporary files: %s %s %s\n", imageName, maskName, varianceName);
     110            options->imageNames->data[i] = imageName;
     111            options->maskNames->data[i] = maskName;
     112            options->varianceNames->data[i] = varianceName;
     113        }
     114        psFree(outputName);
     115    } else {
     116        options->imageNames = stackNameArray(config, "PPSTACK.INPUT");
     117        options->maskNames = stackNameArray(config, "PPSTACK.INPUT.MASK");
     118        options->varianceNames = stackNameArray(config, "PPSTACK.INPUT.VARIANCE");
    42119    }
    43 
    44     psString outputName = psStringCopy(psMetadataLookupStr(NULL, config->arguments,
    45                                                            "OUTPUT")); // Name for temporary files
    46     const char *tempName = basename(outputName);
    47     if (!tempName) {
    48         psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to construct basename for temporary files.");
    49         psFree(outputName);
    50         return false;
    51     }
    52 
    53     const char *tempImage = psMetadataLookupStr(NULL, recipe, "TEMP.IMAGE"); // Suffix for temporary images
    54     const char *tempMask = psMetadataLookupStr(NULL, recipe, "TEMP.MASK"); // Suffix for temporary masks
    55     const char *tempVariance = psMetadataLookupStr(NULL, recipe, "TEMP.VARIANCE"); // Suffix for temp var maps
    56     if (!tempImage || !tempMask || !tempVariance) {
    57         psError(PS_ERR_BAD_PARAMETER_VALUE, false,
    58                 "Unable to find TEMP.IMAGE, TEMP.MASK and TEMP.VARIANCE in recipe");
    59         psFree(outputName);
    60         return false;
    61     }
    62 
    63     options->imageNames = psArrayAlloc(num);
    64     options->maskNames = psArrayAlloc(num);
    65     options->varianceNames = psArrayAlloc(num);
    66     for (int i = 0; i < num; i++) {
    67         psString imageName = NULL, maskName = NULL, varianceName = NULL; // Names for convolved images
    68         psStringAppend(&imageName, "%s/%s.%d.%s", tempDir, tempName, i, tempImage);
    69         psStringAppend(&maskName, "%s/%s.%d.%s", tempDir, tempName, i, tempMask);
    70         psStringAppend(&varianceName, "%s/%s.%d.%s", tempDir, tempName, i, tempVariance);
    71         psTrace("ppStack", 5, "Temporary files: %s %s %s\n", imageName, maskName, varianceName);
    72         options->imageNames->data[i] = imageName;
    73         options->maskNames->data[i] = maskName;
    74         options->varianceNames->data[i] = varianceName;
    75     }
    76     psFree(outputName);
    77120
    78121    if (!pmConfigMaskSetBits(NULL, NULL, config)) {
  • trunk/ppStack/src/ppStackSources.c

    r23242 r23573  
    99//#define TESTING                         // Enable debugging output
    1010
     11#ifdef TESTING
    1112// Size of fake image; set by hand because it's trouble to get it from other places
    1213#define FAKE_COLS 4861
    1314#define FAKE_ROWS 4913
     15#endif
    1416
    1517#ifdef TESTING
     
    5355
    5456
    55 float ppStackSourcesTransparency(const psArray *sourceLists, psVector *inputMask,
    56                                  const pmFPAview *view, const pmConfig *config)
     57bool ppStackSourcesTransparency(ppStackOptions *options, const pmFPAview *view, const pmConfig *config)
    5758{
    58     PS_ASSERT_ARRAY_NON_NULL(sourceLists, NAN);
    59     PS_ASSERT_VECTOR_NON_NULL(inputMask, NAN);
    60     PS_ASSERT_VECTOR_TYPE(inputMask, PS_TYPE_U8, NAN);
    61     PS_ASSERT_VECTOR_SIZE(inputMask, sourceLists->n, NAN);
    62     PS_ASSERT_PTR_NON_NULL(view, NAN);
    63     PS_ASSERT_PTR_NON_NULL(config, NAN);
     59    PS_ASSERT_PTR_NON_NULL(options, false);
     60    PS_ASSERT_PTR_NON_NULL(view, false);
     61    PS_ASSERT_PTR_NON_NULL(config, false);
     62
     63    psArray *sourceLists = options->sourceLists; // Source lists for each input
     64    psVector *inputMask = options->inputMask; // Mask for inputs
     65
     66    PS_ASSERT_ARRAY_NON_NULL(sourceLists, false);
     67    PS_ASSERT_VECTOR_NON_NULL(inputMask, false);
     68    PS_ASSERT_VECTOR_TYPE(inputMask, PS_TYPE_U8, false);
     69    PS_ASSERT_VECTOR_SIZE(inputMask, sourceLists->n, false);
    6470
    6571#if defined(TESTING) && 0
     
    100106    if (!airmassZP) {
    101107        psError(PS_ERR_UNKNOWN, false, "Unable to find ZP.AIRMASS in recipe.");
    102         return NAN;
     108        return false;
    103109    }
    104110
     
    139145                    exptime, airmass, expFilter);
    140146            psFree(zp);
    141             return NAN;
     147            return false;
    142148        }
    143149
     
    149155                        "Unable to find airmass term (ZP.AIRMASS) for filter %s", filter);
    150156                psFree(zp);
    151                 return NAN;
     157                return false;
    152158            }
    153159        } else if (strcmp(filter, expFilter) != 0) {
    154160            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Filters don't match: %s vs %s", filter, expFilter);
    155161            psFree(zp);
    156             return NAN;
     162            return false;
    157163        }
    158164
     
    160166        sumExpTime += exptime;
    161167    }
     168
     169    options->sumExposure = sumExpTime;
    162170
    163171    psArray *matches = pmSourceMatchSources(sourceLists, radius, true); // List of matches
     
    165173        psError(PS_ERR_UNKNOWN, false, "Unable to match sources");
    166174        psFree(zp);
    167         return NAN;
     175        return false;
    168176    }
    169177
     
    177185    if (!trans) {
    178186        psError(PS_ERR_UNKNOWN, false, "Unable to measure transparencies");
    179         return NAN;
     187        return false;
    180188    }
    181189
     
    186194    for (int i = 0; i < trans->n; i++) {
    187195        if (!isfinite(trans->data.F32[i])) {
    188             inputMask->data.U8[i] = PPSTACK_MASK_CAL;
     196            inputMask->data.U8[i] |= PPSTACK_MASK_CAL;
    189197        }
    190198    }
     
    223231    // m_0 = m_1 + zp_1 + trans_1 - c1 * airmass_0 - 2.5log(t_0)
    224232    // We don't need to know the magnitude zero point for the filter, since it cancels out
     233    options->norm = psVectorAlloc(num, PS_TYPE_F32);
    225234    for (int i = 0; i < num; i++) {
    226235        if (!isfinite(trans->data.F32[i])) {
     
    229238        psArray *sources = sourceLists->data[i]; // Sources of interest
    230239        float magCorr = airmassTerm - 2.5*log10(sumExpTime) - zp->data.F32[i] - trans->data.F32[i];
     240        options->norm->data.F32[i] = magCorr;
    231241        psLogMsg("ppStack", PS_LOG_INFO, "Applying magnitude correction to image %d: %f\n", i, magCorr);
    232242
     
    248258            psError(PS_ERR_UNKNOWN, false, "Unable to match sources");
    249259            psFree(zp);
    250             return NAN;
     260            return false;
    251261        }
    252262        psVector *trans = pmSourceMatchRelphot(matches, zp, iter, tol, starLimit, transIter, transRej,
     
    259269#endif
    260270
    261     return sumExpTime;
     271    return true;
    262272}
Note: See TracChangeset for help on using the changeset viewer.