IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 26899


Ignore:
Timestamp:
Feb 10, 2010, 7:42:02 PM (16 years ago)
Author:
eugene
Message:

updates from eam_branches/20091201

Location:
trunk/ppSub
Files:
12 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/ppSub/src/ppSub.c

    r25847 r26899  
    2424int main(int argc, char *argv[])
    2525{
     26
     27# if 0
     28    psLibInit(NULL);
     29    pmVisualSetVisual(true);
     30    for (int order = 2; order < 11; order ++) {
     31        pmSubtractionDeconvolutionTest (order);
     32    }
     33    psLibFinalize();
     34    exit (1);
     35# endif
     36
    2637    psExit exitValue = PS_EXIT_SUCCESS; // Exit value
    2738    psTimerStart("ppSub");
  • trunk/ppSub/src/ppSub.h

    r24862 r26899  
    152152    );
    153153
     154/// Generate JPEG images
     155bool ppSubResidualSampleJpeg(pmConfig *config);
     156
    154157/// Generate inverse subtraction
    155158bool ppSubReadoutInverse(pmConfig *config // Configuration
     
    160163bool psMetadataCopySingle(psMetadata *target, psMetadata *source, const char *name);
    161164
     165bool ppSubCopyPSF (pmFPAfile *output, pmFPAfile *input, pmFPAview *view);
     166
    162167///@}
    163168#endif
  • trunk/ppSub/src/ppSubBackground.c

    r23740 r26899  
    4242    if (!modelRO) {
    4343        // Create the background model
    44         if (!psphotModelBackground(config, view, "PPSUB.OUTPUT")) {
     44        if (!psphotModelBackgroundReadoutFileIndex(config, view, "PPSUB.OUTPUT", 0)) {
    4545            psError(PS_ERR_UNKNOWN, false, "Unable to model background");
    4646            psFree(view);
  • trunk/ppSub/src/ppSubCamera.c

    r26571 r26899  
    2323
    2424// Define an input file
    25 static pmFPAfile *defineInputFile(pmConfig *config,// Configuration
     25static pmFPAfile *defineInputFile(bool *success,
     26                                  pmConfig *config,// Configuration
    2627                                  pmFPAfile *bind,    // File to which to bind, or NULL
    2728                                  char *filerule,     // Name of file rule
     
    3233    bool status;
    3334
     35    *success = false;
     36
    3437    pmFPAfile *file = NULL;
     38
    3539    // look for the file on the argument list
    3640    if (bind) {
     
    3943        file = pmFPAfileDefineFromArgs(&status, config, filerule, argname);
    4044    }
     45
    4146    if (!status) {
    4247        psError(PS_ERR_UNKNOWN, false, "Failed to load file definition for %s", filerule);
     
    5358
    5459    if (!file) {
     60        // no file defined
     61        *success = true;
    5562        return NULL;
    5663    }
     
    6168    }
    6269
     70    *success = true;
    6371    return file;
    6472}
     
    137145bool ppSubCamera(ppSubData *data)
    138146{
     147    bool success = true;
     148
    139149    psAssert(data, "Require processing data");
    140150    pmConfig *config = data->config;
     
    142152
    143153    // Input image
    144     pmFPAfile *input = defineInputFile(config, NULL, "PPSUB.INPUT", "INPUT", PM_FPA_FILE_IMAGE);
    145     if (!input) {
     154    pmFPAfile *input = defineInputFile(&success, config, NULL, "PPSUB.INPUT", "INPUT", PM_FPA_FILE_IMAGE);
     155    if (!success) {
    146156        psError(PS_ERR_IO, false, "Failed to build FPA from PPSUB.INPUT");
    147157        return false;
    148158    }
    149     defineInputFile(config, input, "PPSUB.INPUT.MASK", "INPUT.MASK", PM_FPA_FILE_MASK);
    150     pmFPAfile *inVar = defineInputFile(config, input, "PPSUB.INPUT.VARIANCE", "INPUT.VARIANCE",
    151                                        PM_FPA_FILE_VARIANCE);
    152     defineInputFile(config, NULL, "PPSUB.INPUT.SOURCES", "INPUT.SOURCES", PM_FPA_FILE_CMF);
     159
     160    defineInputFile(&success, config, input, "PPSUB.INPUT.MASK", "INPUT.MASK", PM_FPA_FILE_MASK);
     161    if (!success) {
     162        psError(PS_ERR_IO, false, "Failed to build FPA from PPSUB.INPUT.MASK");
     163        return false;
     164    }
     165
     166    pmFPAfile *inVar = defineInputFile(&success, config, input, "PPSUB.INPUT.VARIANCE", "INPUT.VARIANCE", PM_FPA_FILE_VARIANCE);
     167    if (!success) {
     168        psError(PS_ERR_IO, false, "Failed to build FPA from PPSUB.INPUT.VARIANCE");
     169        return false;
     170    }
     171
     172    defineInputFile(&success, config, NULL, "PPSUB.INPUT.SOURCES", "INPUT.SOURCES", PM_FPA_FILE_CMF);
     173    if (!success) {
     174        psError(PS_ERR_IO, false, "Failed to build FPA from PPSUB.INPUT.SOURCES");
     175        return false;
     176    }
    153177
    154178    // Reference image
    155     pmFPAfile *ref = defineInputFile(config, NULL, "PPSUB.REF", "REF", PM_FPA_FILE_IMAGE);
    156     if (!ref) {
     179    pmFPAfile *ref = defineInputFile(&success, config, NULL, "PPSUB.REF", "REF", PM_FPA_FILE_IMAGE);
     180    if (!success) {
    157181        psError(PS_ERR_IO, false, "Failed to build FPA from PPSUB.REF");
    158182        return false;
    159183    }
    160     defineInputFile(config, ref, "PPSUB.REF.MASK", "REF.MASK", PM_FPA_FILE_MASK);
    161     pmFPAfile *refVar = defineInputFile(config, ref, "PPSUB.REF.VARIANCE", "REF.VARIANCE",
    162                                         PM_FPA_FILE_VARIANCE);
    163     defineInputFile(config, NULL, "PPSUB.REF.SOURCES", "REF.SOURCES", PM_FPA_FILE_CMF);
    164 
     184
     185    defineInputFile(&success, config, ref, "PPSUB.REF.MASK", "REF.MASK", PM_FPA_FILE_MASK);
     186    if (!success) {
     187        psError(PS_ERR_IO, false, "Failed to build FPA from PPSUB.REF.MASK");
     188        return false;
     189    }
     190
     191    pmFPAfile *refVar = defineInputFile(&success, config, ref, "PPSUB.REF.VARIANCE", "REF.VARIANCE", PM_FPA_FILE_VARIANCE);
     192    if (!success) {
     193        psError(PS_ERR_IO, false, "Failed to build FPA from PPSUB.REF.VARIANCE");
     194        return false;
     195    }
     196
     197    defineInputFile(&success, config, NULL, "PPSUB.REF.SOURCES", "REF.SOURCES", PM_FPA_FILE_CMF);
     198    if (!success) {
     199        psError(PS_ERR_IO, false, "Failed to build FPA from PPSUB.REF.SOURCES");
     200        return false;
     201    }
    165202
    166203    // Now that the camera has been determined, we can read the recipe
     
    298335    jpeg2->save = true;
    299336
     337    // Output residual JPEG
     338    pmFPAfile *jpeg3 = pmFPAfileDefineOutput(config, NULL, "PPSUB.OUTPUT.RESID.JPEG");
     339    if (!jpeg3) {
     340        psError(PS_ERR_IO, false, _("Unable to generate output file from PPSUB.OUTPUT.RESID.JPEG"));
     341        return false;
     342    }
     343    if (jpeg3->type != PM_FPA_FILE_JPEG) {
     344        psError(PS_ERR_IO, true, "PPSUB.OUTPUT.RESID.JPEG is not of type JPEG");
     345        return false;
     346    }
     347    jpeg3->save = true;
     348
    300349    // Output subtraction kernel
    301350    pmFPAfile *kernel = defineCalcFile(config, NULL, "PPSUB.OUTPUT.KERNELS", PM_FPA_FILE_SUBKERNEL);
     
    306355
    307356    // psPhot input
    308     if (data->photometry) {
     357    if (data->photometry || 1) {
    309358        psphotModelClassInit();        // load implementation-specific models
    310359
     
    318367            return false;
    319368        }
     369        // specify the number of psphot input images
     370        psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);
    320371        pmFPAfileActivate(config->files, false, "PSPHOT.INPUT");
    321372
    322         // Internal-ish file for getting the PSF from the minuend
    323         pmFPAfile *psf = pmFPAfileDefineOutputFromFile(config, psphot, "PSPHOT.PSF.LOAD");
     373        // Internal file for getting the PSF from the minuend
     374        pmFPAfile *psf = pmFPAfileDefineFromFPA(config, output->fpa, 1, 1, "PSPHOT.PSF.LOAD");
    324375        if (!psf) {
    325376            psError(PS_ERR_IO, false, "Failed to build FPA from PSPHOT.PSF.LOAD");
  • trunk/ppSub/src/ppSubDefineOutput.c

    r23740 r26899  
    5151    bool mdok;                          // Status of MD lookup
    5252    psMetadata *analysis = inConv->analysis; // Analysis metadata with kernel information
    53     pmSubtractionKernels *kernels = psMetadataLookupPtr(&mdok, analysis,
    54                                                         PM_SUBTRACTION_ANALYSIS_KERNEL); // Subtraction kernel
     53    pmHDU *hdu = pmHDUFromCell(inConv->parent);
     54    pmSubtractionKernels *kernels = psMetadataLookupPtr(&mdok, analysis, PM_SUBTRACTION_ANALYSIS_KERNEL); // Subtraction kernel
     55
    5556    if (!kernels) {
     57        hdu = pmHDUFromCell(refConv->parent);
    5658        analysis = refConv->analysis;
    5759        kernels = psMetadataLookupPtr(&mdok, analysis, PM_SUBTRACTION_ANALYSIS_KERNEL);
     
    6264        return false;
    6365    }
    64     psMetadataAddStr(outHDU->header, PS_LIST_TAIL, "PPSUB.KERNEL", 0, "Subtraction kernel",
    65                      kernels->description);
     66    psAssert (hdu, "unable to find HDU");
     67    psMetadataAddStr(outHDU->header, PS_LIST_TAIL, "PPSUB.KERNEL", 0, "Subtraction kernel", kernels->description);
     68    outHDU->header = psMetadataCopy(outHDU->header, hdu->header);
    6669
    6770    // Add additional data to the header
  • trunk/ppSub/src/ppSubFiles.c

    r23740 r26899  
    2323// Subtraction files
    2424static const char *subFiles[] = { "PPSUB.OUTPUT", "PPSUB.OUTPUT.MASK", "PPSUB.OUTPUT.VARIANCE",
    25                                   "PPSUB.OUTPUT.JPEG1", "PPSUB.OUTPUT.JPEG2",
     25                                  "PPSUB.OUTPUT.JPEG1", "PPSUB.OUTPUT.JPEG2", "PPSUB.OUTPUT.RESID.JPEG",
    2626                                  NULL };
    2727
  • trunk/ppSub/src/ppSubLoop.c

    r24862 r26899  
    2727
    2828    pmConfigCamerasCull(config, NULL);
    29     pmConfigRecipesCull(config, "PPSUB,PPSTATS,PSPHOT,MASKS,JPEG");
     29    pmConfigRecipesCull(config, "PPSUB,PPSTATS,PSPHOT,PSASTRO,MASKS,JPEG");
    3030
    3131
     
    5454        // Can't do anything at all
    5555        return true;
     56    }
     57    // generate the residual stamp grid for visualization
     58    if (!ppSubResidualSampleJpeg(config)) {
     59        psError(PS_ERR_UNKNOWN, false, "Unable to update.");
     60        return false;
    5661    }
    5762
     
    130135    }
    131136
     137    // generate the binned image used to write the jpeg
    132138    if (!ppSubReadoutJpeg(config)) {
    133139        psError(PS_ERR_UNKNOWN, false, "Unable to update.");
  • trunk/ppSub/src/ppSubMakePSF.c

    r26263 r26899  
    2222#include "ppSub.h"
    2323
     24psArray *ppSubSelectPSFSources(psArray *sources);
     25
    2426bool ppSubMakePSF(ppSubData *data)
    2527{
     
    6163        return false;
    6264    }
     65
    6366    pmReadout *photRO = pmFPAviewThisReadout(view, photFile->fpa); // Readout to photometer
    64     if (psMetadataLookup(photRO->analysis, "PSPHOT.SOURCES")) {
    65         psMetadataRemoveKey(photRO->analysis, "PSPHOT.SOURCES");
    66     }
    67 
    68     // psphotSaveImage (photFile->fpa->hdu->header, photRO->image, "findpsf.im.fits");
    69     // psphotSaveImage (photFile->fpa->hdu->header, photRO->variance, "findpsf.wt.fits");
    70     // psphotSaveImage (photFile->fpa->hdu->header, photRO->mask, "findpsf.mk.fits");
    71 
    72     // XXX for testing, can i dump a complete copy of the psphot sources here? 
    73     // I actually only need the X,Y coordinates to test this.
     67
     68    // we need to remove any existing PSPHOT.DETECTIONS (why not do this in psphot?)
     69    if (psMetadataLookup(photRO->analysis, "PSPHOT.DETECTIONS")) {
     70        psMetadataRemoveKey(photRO->analysis, "PSPHOT.DETECTIONS");
     71    }
     72    if (psMetadataLookup(photRO->parent->parent->analysis, "PSPHOT.PSF")) {
     73        psMetadataRemoveKey(photRO->parent->parent->analysis, "PSPHOT.PSF");
     74    }
     75
     76# ifdef TESTING
     77    // XXX for testing, dump these images:
     78    psphotSaveImage (NULL, photRO->image, "findpsf.im.fits");
     79    psphotSaveImage (NULL, photRO->variance, "findpsf.wt.fits");
     80    psphotSaveImage (NULL, photRO->mask, "findpsf.mk.fits");
     81# endif
    7482
    7583    // Extract the loaded sources from the associated readout, and generate PSF
    7684    // Here, we assume the image is background-subtracted
    77     psArray *sources = psMetadataLookupPtr(&mdok, minuend->analysis, "PSPHOT.SOURCES");
    78     if (!psphotReadoutFindPSF(config, view, sources)) {
     85    pmDetections *detections = psMetadataLookupPtr(&mdok, minuend->analysis, "PSPHOT.DETECTIONS");
     86    psAssert(detections, "missing detections?");
     87    psArray *sources = detections->allSources;
     88    psAssert(sources, "missing sources?");
     89
     90    // XXX filter sources?  limit the total number and return only brighter objects?
     91    // use flags to toss totally bogus entries?
     92    psArray *goodSources = ppSubSelectPSFSources (sources);
     93    if (!psphotReadoutFindPSF(config, view, goodSources)) {
    7994        // This is likely a data quality issue
    8095        // XXX Split into multiple cases using error codes?
     
    8398        ppSubDataQuality(data, PSPHOT_ERR_PSF, PPSUB_FILES_PHOT_SUB | PPSUB_FILES_PHOT_INV);
    8499        psFree(view);
     100        psFree(goodSources);
    85101        return true;
     102    }
     103
     104    // save the resulting PSF information on the pmFPAfile PSPHOT.PSF.LOAD
     105    pmFPAfile *psfFile = psMetadataLookupPtr(&mdok, config->files, "PSPHOT.PSF.LOAD"); // PSF file
     106    if (!ppSubCopyPSF (psfFile, photFile, view)) {
     107        psErrorStackPrint(stderr, "PSF was not generated");
     108        psWarning("PSF was not generated --- suspect bad data quality.");
     109        ppSubDataQuality(data, psErrorCodeLast(), PPSUB_FILES_PHOT_SUB | PPSUB_FILES_PHOT_INV);
    86110    }
    87111
     
    89113    psMetadataRemoveKey(photRO->analysis, "PSPHOT.HEADER");
    90114
    91     if (!data->quality) {
    92         data->psf = psMemIncrRefCounter(psMetadataLookupPtr(NULL, photRO->parent->parent->analysis,
    93                                                             "PSPHOT.PSF"));
    94     }
    95 
     115    psFree(goodSources);
    96116    psFree(view);
    97117
    98118    return true;
    99119}
     120
     121bool ppSubCopyPSF (pmFPAfile *output, pmFPAfile *input, pmFPAview *view) {
     122
     123    bool mdok = false;
     124
     125    pmChip *inputChip   = pmFPAviewThisChip(view, input->fpa); // Chip with PSF info
     126    pmChip *outputChip  = pmFPAviewThisChip(view, output->fpa); // Chip to store PSF info
     127
     128    pmReadout *inputRO  = pmFPAviewThisReadout(view, input->fpa); // Readout with PSF info
     129    pmReadout *outputRO = pmFPAviewThisReadout(view, output->fpa); // Readout to store PSF info
     130
     131    if (!outputRO) {
     132        pmCell *outputCell  = pmFPAviewThisCell(view, output->fpa);
     133        outputRO = pmReadoutAlloc(outputCell);
     134        outputRO->image = psMemIncrRefCounter (inputRO->image);
     135    }
     136
     137    // copy the PSF-related data to PSPHOT.PSF.LOAD for safe-keeping
     138    psMetadata *psfRegions = psMetadataAlloc();
     139
     140    int nRegions = psMetadataLookupS32 (&mdok, inputRO->analysis, "PSF.CLUMP.NREGIONS");
     141    if (!nRegions) {
     142        psErrorStackPrint(stderr, "No PSF available");
     143        return false;
     144    }
     145    psMetadataAddS32 (psfRegions, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", nRegions);
     146
     147    for (int i = 0; i < nRegions; i++) {
     148        char fieldName[80];
     149        snprintf (fieldName, 80, "PSF.CLUMP.REGION.%03d", i);
     150        psMetadata *regionMD = psMetadataLookupPtr (&mdok, inputRO->analysis, fieldName);
     151        if (!regionMD) {
     152            psWarning ("missing psf clump region metadata for entry %d", i);
     153            continue;
     154        }
     155        psMetadataAddMetadata (psfRegions, PS_LIST_TAIL, fieldName, PS_META_REPLACE, "psf clump region", regionMD);
     156    }
     157
     158    // XXX why am I replacing the entire analysis MD?
     159    psFree(outputRO->analysis);
     160    outputRO->analysis = psfRegions;
     161
     162    // copy the PSF model data
     163    pmPSF *psf = psMetadataLookupPtr(NULL, inputChip->analysis, "PSPHOT.PSF"); // PSF for photometry
     164    if (!psf) {
     165        psErrorStackPrint(stderr, "No PSF available");
     166        return false;
     167    }
     168
     169    psMetadataAddPtr(outputChip->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_DATA_UNKNOWN | PS_META_REPLACE, "PSF from ppSubMakePSF", psf);
     170
     171    return true;
     172}
     173
     174
     175// XXX hardwired MAX for now
     176# define MAX_NPSF 500
     177
     178psArray *ppSubSelectPSFSources(psArray *sources){
     179
     180    sources = psArraySort (sources, pmSourceSortBySN);
     181
     182    psArray *subset = psArrayAllocEmpty(MAX_NPSF);
     183
     184    int nPSF = 0;
     185    for (int i = 0; (nPSF < MAX_NPSF) && (i < sources->n); i++) {
     186
     187        pmSource *source = sources->data[i];
     188        if (!source) continue;
     189
     190        // skip non-astronomical objects (very likely defects)
     191        if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
     192        if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
     193        if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
     194
     195        psArrayAdd (subset, 100, source);
     196        nPSF++;
     197    }
     198
     199    return subset;
     200}
  • trunk/ppSub/src/ppSubMatchPSFs.c

    r26036 r26899  
    1818#include <pslib.h>
    1919#include <psmodules.h>
     20#include <psphot.h>
    2021
    2122#include "ppSub.h"
     23
     24#define COVAR_FRAC 0.01                 // Truncation fraction for covariance matrix
    2225
    2326// Normalise a region on an image
     
    3740}
    3841
     42// Measure the PSF for an image
     43static float subImagePSF(ppSubData *data, // Processing data
     44                         const pmReadout *ro, // Readout for which to measure PSF
     45                         psArray *sources     // Sources with positions at which to measure PSF
     46    )
     47{
     48    psAssert(data, "Require processing data");
     49    pmConfig *config = data->config;    // Configuration
     50    psAssert(config, "Require configuration");
     51
     52    psAssert(ro, "Need readout");
     53    psAssert(sources, "Need sources.");
     54
     55    pmFPAfile *photFile = psMetadataLookupPtr(NULL, config->files, "PSPHOT.INPUT"); // Photometry file
     56    psAssert(photFile, "Need photometry file.");
     57    if (!pmFPACopy(photFile->fpa, ro->parent->parent->parent)) {
     58        psError(PS_ERR_UNKNOWN, false, "Unable to copy FPA for photometry");
     59        return false;
     60    }
     61
     62    pmFPAview *view = ppSubViewReadout(); // View to readout
     63    pmReadout *photRO = pmFPAviewThisReadout(view, photFile->fpa); // Readout to photometer
     64
     65    if (psMetadataLookup(photRO->analysis, "PSPHOT.DETECTIONS")) {
     66        psMetadataRemoveKey(photRO->analysis, "PSPHOT.DETECTIONS");
     67    }
     68    if (psMetadataLookup(photRO->parent->parent->analysis, "PSPHOT.PSF")) {
     69        psMetadataRemoveKey(photRO->parent->parent->analysis, "PSPHOT.PSF");
     70    }
     71
     72    // Extract the loaded sources from the associated readout, and generate PSF
     73    // Here, we assume the image is background-subtracted
     74    if (!psphotReadoutFindPSF(config, view, sources)) {
     75        psErrorStackPrint(stderr, "Unable to determine PSF");
     76        psWarning("Unable to determine PSF.");
     77        psFree(view);
     78        return true;
     79    }
     80
     81    psFree(view);
     82
     83    psMetadata *header = psMetadataLookupMetadata(NULL, photRO->analysis, "PSPHOT.HEADER");
     84    psAssert(header, "Require header.");
     85    float fwhm = psMetadataLookupF32(NULL, header, "FWHM_MAJ");
     86
     87    return fwhm;
     88}
     89
     90// Scale the kernel parameters according to the PSFs
     91static bool subScaleKernel(ppSubData *data, // Processing data
     92                           psVector *kernelWidths, // Widths for kernel
     93                           int *kernelSize,        // Size of kernel
     94                           int *stampSize          // Size of stamps (footprint)
     95    )
     96{
     97    psAssert(data, "Require processing data");
     98    pmConfig *config = data->config;    // Configuration
     99    psAssert(config, "Require configuration");
     100
     101    // Nothing to do if pre-calculated kernel exists
     102    pmFPAview *view = ppSubViewReadout(); // View to readout
     103    pmReadout *kernelRO = pmFPAfileThisReadout(config->files, view, "PPSUB.OUTPUT.KERNELS"); // RO with kernel
     104    if (kernelRO) {
     105        psFree(view);
     106        return true;
     107    }
     108
     109    // Look up recipe values
     110    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
     111    psAssert(recipe, "We checked this earlier, so it should be here.");
     112    if (!psMetadataLookupBool(NULL, recipe, "SCALE")) {
     113        // No scaling requested
     114        psFree(view);
     115        return true;
     116    }
     117
     118    // Input images
     119    pmReadout *inRO = pmFPAfileThisReadout(config->files, view, "PPSUB.INPUT"); // Input readout
     120    pmReadout *refRO = pmFPAfileThisReadout(config->files, view, "PPSUB.REF"); // Reference readout
     121
     122    // Input sources
     123    pmReadout *inSourceRO = pmFPAfileThisReadout(config->files, view, "PPSUB.INPUT.SOURCES");
     124    pmReadout *refSourceRO = pmFPAfileThisReadout(config->files, view, "PPSUB.REF.SOURCES");
     125    // XXX assert on inSourcesRO and refSourcesRO?
     126
     127    pmDetections *inDetections = psMetadataLookupPtr(NULL, inSourceRO->analysis, "PSPHOT.DETECTIONS"); // Input sources
     128    pmDetections *refDetections = psMetadataLookupPtr(NULL, refSourceRO->analysis, "PSPHOT.DETECTIONS"); // Ref sources
     129
     130    psFree(view);
     131
     132    if (!inDetections || !refDetections) {
     133        psWarning("Unable to scale kernel, since no sources were provided.");
     134        return true;
     135    }
     136
     137    psArray *inSources = inDetections->allSources;
     138    psAssert (inSources, "missing inSources?");
     139
     140    psArray *refSources = refDetections->allSources;
     141    psAssert (refSources, "missing refSources?");
     142
     143    float inFWHM = subImagePSF(data, inRO, inSources); // FWHM for input
     144    float refFWHM = subImagePSF(data, refRO, refSources); // FWHM for reference
     145
     146    psLogMsg("ppSub", PS_LOG_INFO, "Input FWHM: %f\nReference FWHM: %f\n", inFWHM, refFWHM);
     147    if (!isfinite(inFWHM) || !isfinite(refFWHM)) {
     148        psWarning("Unable to scale kernel, since unable to measure PSFs.");
     149        return true;
     150    }
     151
     152    float scaleRef = psMetadataLookupF32(NULL, recipe, "SCALE.REF"); // Reference for scaling
     153    float scaleMin = psMetadataLookupF32(NULL, recipe, "SCALE.MIN"); // Minimum for scaling
     154    float scaleMax = psMetadataLookupF32(NULL, recipe, "SCALE.MAX"); // Maximum for scaling
     155    if (!isfinite(scaleRef) || !isfinite(scaleMin) || !isfinite(scaleMax)) {
     156        psError(PPSUB_ERR_ARGUMENTS, false,
     157                "Scale parameters (SCALE.REF=%f, SCALE.MIN=%f, SCALE.MAX=%f) not set in recipe.",
     158                scaleRef, scaleMin, scaleMax);
     159        return false;
     160    }
     161
     162    if (!pmSubtractionParamsScale(kernelSize, stampSize, kernelWidths, inFWHM, refFWHM,
     163                                  scaleRef, scaleMin, scaleMax)) {
     164        psError(PS_ERR_UNKNOWN, false, "Unable to scale parameters.");
     165        return false;
     166    }
     167
     168    return true;
     169}
     170
    39171
    40172bool ppSubMatchPSFs(ppSubData *data)
     
    71203    pmReadout *kernelRO = pmFPAfileThisReadout(config->files, view, "PPSUB.OUTPUT.KERNELS"); // RO with kernel
    72204
    73     psFree(view);
    74 
    75205    // Sources in image, used for stamps: these must be loaded from previous analysis stages
    76206    pmReadout *inSourceRO = pmFPAfileThisReadout(config->files, view, "PPSUB.INPUT.SOURCES");
    77207    pmReadout *refSourceRO = pmFPAfileThisReadout(config->files, view, "PPSUB.REF.SOURCES");
    78     psArray *inSources = inSourceRO ? psMetadataLookupPtr(&mdok, inSourceRO->analysis, "PSPHOT.SOURCES") :
    79         NULL; // Source list from input image
    80     psArray *refSources = refSourceRO ? psMetadataLookupPtr(&mdok, refSourceRO->analysis, "PSPHOT.SOURCES") :
    81         NULL ; // Source list from reference image
    82 
    83     psArray *sources = NULL;            // Merged list of sources
    84     if (inSources && refSources) {
     208
     209    pmDetections *inDetections  = inSourceRO  ? psMetadataLookupPtr(&mdok, inSourceRO->analysis,  "PSPHOT.DETECTIONS") : NULL; // Input sources
     210    pmDetections *refDetections = refSourceRO ? psMetadataLookupPtr(&mdok, refSourceRO->analysis, "PSPHOT.DETECTIONS") : NULL; // Ref sources
     211
     212    psFree(view);
     213
     214    pmDetections *detections = NULL;    // Merged detection set
     215    if (inDetections && refDetections) {
     216        psArray *inSources  = inDetections->allSources;
     217        psArray *refSources = refDetections->allSources;
     218
     219        psAssert (inSources, "missing in sources?");
     220        psAssert (refSources, "missing ref sources?");
     221
     222        detections = pmDetectionsAlloc();
    85223        float radius = psMetadataLookupF32(NULL, recipe, "SOURCE.RADIUS"); // Matching radius
    86224        psArray *lists = psArrayAlloc(2); // Source lists
    87225        lists->data[0] = psMemIncrRefCounter(inSources);
    88226        lists->data[1] = psMemIncrRefCounter(refSources);
    89         sources = pmSourceMatchMerge(lists, radius);
     227        detections->allSources = pmSourceMatchMerge(lists, radius);
    90228        psFree(lists);
    91         if (!sources) {
     229        if (!detections->allSources) {
    92230            psError(PS_ERR_UNKNOWN, false, "Unable to merge source lists");
     231            psFree(detections);
    93232            return false;
    94233        }
    95     } else if (inSources) {
    96         sources = psMemIncrRefCounter(inSources);
    97     } else if (refSources) {
    98         sources = psMemIncrRefCounter(refSources);
    99     }
    100 
    101     psMetadataAddArray(inConv->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_META_REPLACE,
    102                        "Merged source list", sources);
    103     psMetadataAddArray(refConv->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_META_REPLACE,
    104                        "Merged source list", sources);
    105     psFree(sources);                    // Drop reference
     234    }
     235    if (!detections && inDetections) {
     236        detections = psMemIncrRefCounter(inDetections);
     237    }
     238    if (!detections && refDetections) {
     239        detections = psMemIncrRefCounter(refDetections);
     240    }
     241
     242    psMetadataAddPtr(inConv->analysis,  PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_META_REPLACE | PS_DATA_UNKNOWN, "Merged source list", detections);
     243    psMetadataAddPtr(refConv->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_META_REPLACE | PS_DATA_UNKNOWN, "Merged source list", detections);
     244    psFree(detections);                    // Drop reference
    106245
    107246    int footprint = psMetadataLookupS32(NULL, recipe, "STAMP.FOOTPRINT"); // Stamp half-size
     
    131270    float rej = psMetadataLookupF32(NULL, recipe, "REJ"); // Rejection threshold
    132271    float kernelErr = psMetadataLookupF32(NULL, recipe, "KERNEL.ERR"); // Relative systematic error in kernel
     272    float normFrac = psMetadataLookupF32(NULL, recipe, "NORM.FRAC"); // Fraction of window for normalisn windw
    133273    float sysErr = psMetadataLookupF32(NULL, recipe, "SYS.ERR"); // Relative systematic error in images
     274    float skyErr = psMetadataLookupF32(NULL, recipe, "SKY.ERR"); // Additional error in sky
     275    float covarFrac = psMetadataLookupF32(NULL, recipe, "COVAR.FRAC"); // Fraction for covariance calculation
    134276
    135277    float badFrac = psMetadataLookupF32(NULL, recipe, "BADFRAC"); // Maximum bad fraction
     
    169311            break;
    170312          default:
    171             psErrorStackPrint(stderr, "Invalid value for -convolve");
     313            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Invalid value for -convolve");
    172314            return false;
    173315        }
     316    }
     317
     318    if (!subScaleKernel(data, widths, &size, &footprint)) {
     319        psError(PS_ERR_UNKNOWN, false, "Unable to scale kernel parameters");
     320        return false;
    174321    }
    175322
     
    177324    if (threads > 0) {
    178325        pmSubtractionThreadsInit(inRO, refRO);
     326    }
     327
     328    if (inRO->covariance) {
     329        psImageCovarianceTruncate(inRO->covariance, COVAR_FRAC);
     330    }
     331    if (refRO->covariance) {
     332        psImageCovarianceTruncate(refRO->covariance, COVAR_FRAC);
    179333    }
    180334
     
    183337    if (kernelRO) {
    184338        success = pmSubtractionMatchPrecalc(inConv, refConv, inRO, refRO, kernelRO->analysis,
    185                                             stride, kernelErr, maskVal, maskBad, maskPoor, poorFrac, badFrac);
     339                                            stride, kernelErr, covarFrac, maskVal, maskBad, maskPoor,
     340                                            poorFrac, badFrac);
    186341    } else {
    187342        success = pmSubtractionMatch(inConv, refConv, inRO, refRO, footprint, stride, regionSize,
    188                                      spacing, threshold, sources, data->stamps, type, size, order,
     343                                     spacing, threshold, detections->allSources, data->stamps, type, size, order,
    189344                                     widths, orders, inner, ringsOrder, binning, penalty, optimum,
    190                                      optWidths, optOrder, optThresh, iter, rej, sysErr, kernelErr, maskVal,
    191                                      maskBad, maskPoor, poorFrac, badFrac, subMode);
    192     }
     345                                     optWidths, optOrder, optThresh, iter, rej, normFrac,
     346                                     sysErr, skyErr, kernelErr, covarFrac, maskVal, maskBad, maskPoor,
     347                                     poorFrac, badFrac, subMode);
     348    }
     349
     350# ifdef TESTING
     351    // XXX for testing
     352    psphotSaveImage (NULL, refRO->image,    "refRO.im.fits");
     353    psphotSaveImage (NULL, refRO->variance, "refRO.wt.fits");
     354    psphotSaveImage (NULL, refRO->mask,     "refRO.mk.fits");
     355
     356    psphotSaveImage (NULL, inRO->image,    "inRO.im.fits");
     357    psphotSaveImage (NULL, inRO->variance, "inRO.wt.fits");
     358    psphotSaveImage (NULL, inRO->mask,     "inRO.mk.fits");
     359
     360    psphotSaveImage (NULL, inConv->image,    "inConv.im.fits");
     361    psphotSaveImage (NULL, inConv->variance, "inConv.wt.fits");
     362    psphotSaveImage (NULL, inConv->mask,     "inConv.mk.fits");
     363
     364    psphotSaveImage (NULL, refConv->image,    "refConv.im.fits");
     365    psphotSaveImage (NULL, refConv->variance, "refConv.wt.fits");
     366    psphotSaveImage (NULL, refConv->mask,     "refConv.mk.fits");
     367# endif
    193368
    194369    psFree(optWidths);
     
    261436    pmConceptsCopyFPA(refConv->parent->parent->parent, refRO->parent->parent->parent, true, true);
    262437
     438    if (inConv->covariance) {
     439        psImageCovarianceTruncate(inConv->covariance, COVAR_FRAC);
     440    }
     441    if (refConv->covariance) {
     442        psImageCovarianceTruncate(refConv->covariance, COVAR_FRAC);
     443    }
     444
    263445    if (inConv->variance) {
    264446        psImageCovarianceTransfer(inConv->variance, inConv->covariance);
  • trunk/ppSub/src/ppSubReadoutJpeg.c

    r23740 r26899  
    4949    return true;
    5050}
     51
     52bool ppSubResidualSampleJpeg(pmConfig *config)
     53{
     54    return true;
     55
     56    pmFPAview *view = ppSubViewReadout(); // View to readout
     57
     58    // we save sample difference stamps on the convolved image readout->analysis metadata
     59    pmReadout *inConv = pmFPAfileThisReadout(config->files, view, "PPSUB.INPUT.CONV"); // Input convolved
     60
     61    psArray *samples = psArrayAllocEmpty(16); // Array of sample stamp images
     62
     63    // we may have multiple entries with the same name; pull them off into a separate array:
     64    psString regex = NULL;          // Regular expression
     65    psStringAppend(&regex, "^%s$", "SUBTRACTION.SAMPLE.STAMP.SET");
     66    psMetadataIterator *iter = psMetadataIteratorAlloc(inConv->analysis, PS_LIST_HEAD, regex); // Iterator
     67    psFree(regex);
     68
     69    psMetadataItem *item = NULL;// Item from iteration
     70    while ((item = psMetadataGetAndIncrement(iter))) {
     71        assert(item->type == PS_DATA_ARRAY);
     72        psArray *sampleStamps = item->data.V;
     73        samples = psArrayAdd(samples, 16, sampleStamps);
     74    }
     75    psFree(iter);
     76    psAssert (samples, "no sample stamps?");
     77    psAssert (samples->n, "no sample stamps?");
     78
     79    // get the kernel sizes
     80    psArray *kernels = samples->data[0];
     81    psAssert (kernels, "no valid kernel?");
     82    psAssert (kernels->n, "no valid kernel?");
     83
     84    psImage *kernel = kernels->data[0];
     85    psAssert (kernel, "missing valid kernel?");
     86
     87    int DX = kernel->numCols;
     88    int DY = kernel->numRows;
     89
     90    // each array contains up to 9 sample stamps.  generate an image mosaicking these together in 3x3 blocks.
     91    int innerBorder = 1;
     92    int outerBorder = 2;
     93    int NXblock = sqrt(samples->n);
     94    int NYblock = samples->n / NXblock;
     95    if (samples->n % NXblock) NYblock ++;
     96
     97    int NXpix = NXblock * (3 * (DX + innerBorder) + outerBorder);
     98    int NYpix = NYblock * (3 * (DY + innerBorder) + outerBorder);
     99
     100    // output cell
     101    pmCell *cell = pmFPAfileThisCell(config->files, view, "PPSUB.OUTPUT.RESID.JPEG");
     102    pmReadout *readout = pmReadoutAlloc(cell);
     103    readout->image = psImageAlloc(NXpix, NYpix, PS_TYPE_F32);
     104
     105    cell->data_exists = true;
     106    cell->parent->data_exists = true;
     107
     108    psImageInit (readout->image, 0.0);
     109
     110    for (int i = 0; i < samples->n; i++) {
     111
     112        int xBlock = i % NXblock;
     113        int yBlock = i / NYblock;
     114
     115        psArray *kernels = samples->data[i];
     116
     117        for (int j = 0; j < kernels->n; j++) {
     118
     119            psImage *kernel = kernels->data[j];
     120
     121            int xSub = j % 3;
     122            int ySub = j / 3;
     123
     124            int xPix = xBlock * (3 * (DX + innerBorder) + outerBorder) + xSub * (DX + innerBorder);
     125            int yPix = yBlock * (3 * (DX + innerBorder) + outerBorder) + ySub * (DY + innerBorder);
     126
     127            for (int y = 0; y < kernel->numRows; y++) {
     128                for (int x = 0; x < kernel->numCols; x++) {
     129                    readout->image->data.F32[y + yPix][x + xPix] = kernel->data.F32[y][x];
     130                }
     131            }
     132        }
     133    }
     134
     135    {
     136        psFits *fits = psFitsOpen ("resid.stamps.fits", "w");
     137        psFitsWriteImage (fits, NULL, readout->image, 0, NULL);
     138        psFitsClose (fits);
     139    }
     140
     141    return true;
     142}
  • trunk/ppSub/src/ppSubReadoutPhotometry.c

    r26264 r26899  
    2424bool ppSubReadoutPhotometry(const char *name, ppSubData *data)
    2525{
     26    bool mdok = false;
     27
    2628    psAssert(data, "Require processing data");
    2729    pmConfig *config = data->config;    // Configuration
     
    4244    }
    4345
    44     // The PSF (measured in ppSubMakePSF) is stored on the chip->analysis of PSPHOT.INPUT
    45     // In order to use an incoming PSF, it must be stored on the chip->analysis of PSPHOT.PSF.LOAD
     46    // select the view of interest
    4647    pmFPAview *view = ppSubViewReadout(); // View to readout
    47     pmChip *psfInputChip = pmFPAfileThisChip(config->files, view, "PSPHOT.INPUT"); // Chip with PSF
    48     psAssert (psfInputChip, "should have been generated for ppSubMakePSF");
    49     pmChip *psfLoadChip = pmFPAfileThisChip(config->files, view, "PSPHOT.PSF.LOAD"); // Chip to have PSF
    50     psAssert (psfLoadChip, "PSPHOT.PSF.LOAD should have been defined in ppSubCamera");
    51     pmPSF *psf = psMetadataLookupPtr(NULL, psfInputChip->analysis, "PSPHOT.PSF"); // PSF for photometry
    52     if (!psf) {
    53         psErrorStackPrint(stderr, "No PSF available");
    54         psWarning("No PSF available --- suspect bad data quality.");
    55         ppSubDataQuality(data, psErrorCodeLast(), PPSUB_FILES_PHOT_SUB | PPSUB_FILES_PHOT_INV);
    56         return true;
    57     }
    58     psMetadataAddPtr(psfLoadChip->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_DATA_UNKNOWN | PS_META_REPLACE,
    59                      "PSF from ppSubMakePSF", psf);
    60 
    61     bool mdok = false;
    6248
    6349    // psphotReadoutMinimal performs the photometry analysis on PSPHOT.INPUT; we need to move
    64     // around the pointers so PSPHOT.INPUT corresponds to the output image; previously, it was
    65     // equivalent to the minuend image.
    66     pmReadout *inRO = pmFPAfileThisReadout(config->files, view, name); // Readout with image and sources
    67     if (psMetadataLookup(inRO->analysis, "PSPHOT.SOURCES")) {
    68         psMetadataRemoveKey(inRO->analysis, "PSPHOT.SOURCES");
    69     }
    70 
     50    // around the pointers so PSPHOT.INPUT corresponds to the output image of interest (on one
     51    // pass this is the subtraction image, in another it is negative of the subtraction
    7152    pmFPAfile *photFile = psMetadataLookupPtr(&mdok, config->files, "PSPHOT.INPUT"); // Photometry file
    7253    pmFPAfile *inFile = psMetadataLookupPtr(&mdok, config->files, name); // Input file
     
    7657        return false;
    7758    }
     59
     60    // drop references to PSPHOT.DETECTIONS on both of these  (why is this needed for both??)
    7861    pmReadout *photRO = pmFPAviewThisReadout(view, photFile->fpa); // Readout to photometer
    79     if (psMetadataLookup(photRO->analysis, "PSPHOT.SOURCES")) {
    80         psMetadataRemoveKey(photRO->analysis, "PSPHOT.SOURCES");
     62    if (psMetadataLookup(photRO->analysis, "PSPHOT.DETECTIONS")) {
     63        psMetadataRemoveKey(photRO->analysis, "PSPHOT.DETECTIONS");
     64    }
     65    pmReadout *inRO = pmFPAfileThisReadout(config->files, view, name); // Readout with image and sources
     66    if (psMetadataLookup(inRO->analysis, "PSPHOT.DETECTIONS")) {
     67        psMetadataRemoveKey(inRO->analysis, "PSPHOT.DETECTIONS");
    8168    }
    8269
    83     psMetadataAddPtr(photRO->parent->parent->analysis, PS_LIST_TAIL, "PSPHOT.PSF",
    84                      PS_META_REPLACE | PS_DATA_UNKNOWN, "Point-spread function", data->psf);
    85 
    86     psFree(photRO->analysis);
    87     photRO->analysis = psMetadataAlloc();
     70    // grab the PSF information from the pmFPAfile PSPHOT.PSF.LOAD
     71    pmFPAfile *psfFile = psMetadataLookupPtr(&mdok, config->files, "PSPHOT.PSF.LOAD"); // PSF file
     72    ppSubCopyPSF (photFile, psfFile, view);
    8873
    8974    // psphotSaveImage (photFile->fpa->hdu->header, photRO->image, "findsrc.im.fits");
    9075    // psphotSaveImage (photFile->fpa->hdu->header, photRO->variance, "findsrc.wt.fits");
    9176    // psphotSaveImage (photFile->fpa->hdu->header, photRO->mask, "findsrc.mk.fits");
     77
     78    // erase the overlays from a previous psphot-related step
     79    if (pmVisualIsVisual()) {
     80        //      psphotVisualEraseOverlays (1, "all");
     81    }
    9282
    9383    if (!psphotReadoutMinimal(config, view)) {
     
    10090
    10191    // If no sources were found, there's no error,  but we want to trigger 'bad quality'
    102     psArray *sources = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.SOURCES"); // Sources
    103     if (!sources) {
     92    pmDetections *detections = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.DETECTIONS"); // Sources
     93    if (!detections) {
    10494        ppSubDataQuality(data, PSPHOT_ERR_DATA, PPSUB_FILES_PHOT_SUB | PPSUB_FILES_PHOT_INV);
    10595    }
     96    psArray *sources = detections->allSources;
     97    psAssert (sources, "missing sources?");
    10698
    10799    if (data->stats) {
     
    118110
    119111    if (!data->quality) {
    120         if (!psMetadataCopySingle(inRO->analysis, photRO->analysis, "PSPHOT.SOURCES")) {
    121             psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to copy PSPHOT.SOURCES");
     112        if (!psMetadataCopySingle(inRO->analysis, photRO->analysis, "PSPHOT.DETECTIONS")) {
     113            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to copy PSPHOT.DETECTIONS");
    122114            return false;
    123115        }
     
    125117            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to copy PSPHOT.HEADER");
    126118            return false;
     119        }
     120        if (!psMetadataCopySingle(inRO->analysis, photRO->analysis, PM_DETEFF_ANALYSIS)) {
     121            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to copy Detection Efficiency");
     122            return false;
     123        }
     124
     125        // Ensure photometry information is put in the header
     126        pmHDU *hdu = pmHDUFromReadout(inRO); // HDU for readout
     127        if (hdu) {
     128            psMetadata *photHeader = psMetadataLookupMetadata(NULL, inRO->analysis, "PSPHOT.HEADER"); // Header
     129            hdu->header = psMetadataCopy(hdu->header, photHeader);
    127130        }
    128131    }
     
    134137}
    135138
    136 
    137 
    138 
    139 
    140139#ifdef TESTING
    141140    // Record data about sources: not everything gets into the output CMF files
    142141    {
    143142        pmReadout *photRO = pmFPAviewThisReadout(view, photFile->fpa); // Readout with the sources
    144         psArray *sources = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.SOURCES"); // Sources
     143        pmDetections *detections = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.DETECTIONS"); // Sources
     144        psArray *sources = detections->allSources;
    145145        FILE *sourceFile = fopen("sources.dat", "w"); // File for sources
    146146        fprintf(sourceFile,
  • trunk/ppSub/src/ppSubThreshold.c

    r24862 r26899  
    2727    psImageMaskType maskIgnore,         // Ignore pixels with this mask
    2828    psImageMaskType maskThresh,         // Give pixels this mask if below threshold
     29    psRegion *region,                   // Region of interest
    2930    const char *description             // Description of image
    3031    )
     
    3738    psImage *image = ro->image;         // Image
    3839    psImage *mask = ro->mask;           // Mask
    39     int numCols = ro->image->numCols, numRows = ro->image->numRows; // Size of image
     40
     41    psImage *subImage = psImageSubset(image, *region); // Image with region of interest
     42    psImage *subMask = psImageSubset(mask, *region);  // Maks with region of interest
    4043
    4144    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics
    4245    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);                               // Random number generator
    43     if (!psImageBackground(stats, NULL, image, mask, maskIgnore, rng)) {
     46    if (!psImageBackground(stats, NULL, subImage, subMask, maskIgnore, rng)) {
    4447        psError(PS_ERR_UNKNOWN, false, "Unable to determine threshold.");
    4548        psFree(rng);
     
    4952    psFree(rng);
    5053
     54    psFree(subImage);
     55    psFree(subMask);
     56
    5157    float threshold = stats->robustMedian - thresh * stats->robustStdev; // Threshold below which to clip
    5258    psFree(stats);
    5359    psLogMsg("ppSub", PS_LOG_INFO, "Masking pixels below %f in %s", threshold, description);
    5460
    55     for (int y = 0; y < numRows; y++) {
    56         for (int x = 0; x < numCols; x++) {
     61    for (int y = region->y0; y < region->y1; y++) {
     62        for (int x = region->x0; x < region->x1; x++) {
    5763            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskIgnore) {
    5864                continue;
     
    94100        return false;
    95101    }
    96     if (!lowThreshold(in, thresh, maskVal, maskThresh, "input convolved image")) {
    97         psError(PS_ERR_UNKNOWN, false, "Unable to threshold input image.");
    98         return false;
    99     }
    100102
    101103    pmReadout *ref = pmFPAfileThisReadout(config->files, view, "PPSUB.REF.CONV"); // Reference image
     
    104106        return false;
    105107    }
    106     if (!lowThreshold(ref, thresh, maskVal, maskThresh, "reference convolved image")) {
    107         psError(PS_ERR_UNKNOWN, false, "Unable to threshold input image.");
    108         return false;
     108
     109    psMetadataIterator *regIter = psMetadataIteratorAlloc(in->analysis, PS_LIST_HEAD,
     110                                                          "^" PM_SUBTRACTION_ANALYSIS_REGION "$");
     111    psMetadataItem *regItem;        // Item with region
     112    while ((regItem = psMetadataGetAndIncrement(regIter))) {
     113        psAssert(regItem->type == PS_DATA_REGION && regItem->data.V, "Expect region type");
     114        psRegion *region = regItem->data.V; // Region of interest
     115        if (!lowThreshold(in, thresh, maskVal, maskThresh, region, "input convolved image")) {
     116            psError(PS_ERR_UNKNOWN, false, "Unable to threshold input image.");
     117            return false;
     118        }
     119        if (!lowThreshold(ref, thresh, maskVal, maskThresh, region, "reference convolved image")) {
     120            psError(PS_ERR_UNKNOWN, false, "Unable to threshold input image.");
     121            return false;
     122        }
    109123    }
     124    psFree(regIter);
    110125
    111126    psFree(view);
Note: See TracChangeset for help on using the changeset viewer.