IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:41:49 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/tap_branches
Files:
28 edited
3 copied

Legend:

Unmodified
Added
Removed
  • branches/tap_branches

  • branches/tap_branches/ppStack/src

    • Property svn:ignore
      •  

        old new  
        1010stamp-h1
        1111ppStackVersionDefinitions.h
         12ppStackErrorCodes.c
         13ppStackErrorCodes.h
  • branches/tap_branches/ppStack/src/Makefile.am

    r23808 r27838  
    4747        ppStackCleanup.c        \
    4848        ppStackPhotometry.c     \
    49         ppStackFinish.c
     49        ppStackFinish.c         \
     50        ppStackErrorCodes.c
    5051
    5152noinst_HEADERS =                \
     
    5354        ppStackLoop.h           \
    5455        ppStackOptions.h        \
    55         ppStackThread.h
     56        ppStackThread.h         \
     57        ppStackErrorCodes.h
    5658
    57 CLEANFILES = *~
     59### Error codes.
     60BUILT_SOURCES = ppStackErrorCodes.h ppStackErrorCodes.c
     61CLEANFILES = ppStackErrorCodes.h ppStackErrorCodes.c
     62
     63ppStackErrorCodes.h : ppStackErrorCodes.dat ppStackErrorCodes.h.in
     64        $(ERRORCODES) --data=ppStackErrorCodes.dat --outdir=. ppStackErrorCodes.h
     65
     66ppStackErrorCodes.c : ppStackErrorCodes.dat ppStackErrorCodes.c.in ppStackErrorCodes.h
     67        $(ERRORCODES) --data=ppStackErrorCodes.dat --outdir=. ppStackErrorCodes.c
     68
    5869
    5970clean-local:
  • branches/tap_branches/ppStack/src/ppStack.c

    r23341 r27838  
    1515int main(int argc, char *argv[])
    1616{
    17     psExit exitValue = PS_EXIT_SUCCESS; // Exit value
     17    psLibInit(NULL);
    1818    psTimerStart(TIMER_NAME);
    1919    psTimerStart("PPSTACK_STEPS");
    20     psLibInit(NULL);
     20
     21    pmErrorRegister();
     22    ppStackErrorRegister();
     23    psphotErrorRegister();
    2124
    2225    pmConfig *config = pmConfigRead(&argc, argv, PPSTACK_RECIPE); // Configuration
     26    ppStackOptions *options = NULL;                               // Options for stacking
    2327    if (!config) {
    24         psErrorStackPrint(stderr, "Error reading configuration.");
    25         exitValue = PS_EXIT_CONFIG_ERROR;
    26         goto die;
    27     }
    28 
    29     (void) psTraceSetLevel("ppStack", 5);
    30 
    31     if (!ppStackArgumentsSetup(argc, argv, config)) {
    32         psErrorStackPrint(stderr, "Error reading arguments.\n");
    33         exitValue = PS_EXIT_CONFIG_ERROR;
    3428        goto die;
    3529    }
     
    3832
    3933    if (!pmModelClassInit()) {
    40         psErrorStackPrint(stderr, "Error initialising model classes.\n");
    41         exitValue = PS_EXIT_PROG_ERROR;
     34        psError(PPSTACK_ERR_PROG, false, "Unable to initialise model classes.");
    4235        goto die;
    4336    }
    4437
    4538    if (!psphotInit()) {
    46         psErrorStackPrint(stderr, "Error initialising psphot.\n");
    47         exitValue = PS_EXIT_PROG_ERROR;
     39        psError(PPSTACK_ERR_PROG, false, "Error initialising psphot.");
     40        goto die;
     41    }
     42
     43    (void)psTraceSetLevel("ppStack", 5);
     44
     45    if (!ppStackArgumentsSetup(argc, argv, config)) {
    4846        goto die;
    4947    }
    5048
    5149    if (!ppStackCamera(config)) {
    52         psErrorStackPrint(stderr, "Error setting up input files.\n");
    53         exitValue = PS_EXIT_CONFIG_ERROR;
    5450        goto die;
    5551    }
    5652
    5753    if (!ppStackArgumentsParse(config)) {
    58         psErrorStackPrint(stderr, "Error reading arguments.\n");
    59         exitValue = PS_EXIT_CONFIG_ERROR;
    6054        goto die;
    6155    }
    6256
    63     if (!ppStackLoop(config)) {
    64         psErrorStackPrint(stderr, "Error performing combination.\n");
    65         exitValue = PS_EXIT_DATA_ERROR;
     57    options = ppStackOptionsAlloc();
     58    if (!ppStackLoop(config, options)) {
    6659        goto die;
    6760    }
    6861
    6962
    70      // Common code for the death.
    71 die:
    72     psTrace("ppStack", 1, "Finished at %f sec\n", psTimerMark(TIMER_NAME));
    73     psTimerStop();
     63 die:
     64    // Common code for the death.
     65    {
     66        psExit exitValue = ppStackExitCode(PS_EXIT_SUCCESS); // Exit code
    7467
    75     psFree(config);
    76     pmModelClassCleanup();
    77     pmConfigDone();
    78     psLibFinalize();
    79     pmVisualClose();
    80     exit(exitValue);
     68        // Ensure everything closes
     69        if (config) {
     70            ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
     71            ppStackFileActivation(config, PPSTACK_FILES_CONVOLVE, true);
     72            ppStackFileActivation(config, PPSTACK_FILES_STACK, true);
     73            ppStackFileActivation(config, PPSTACK_FILES_UNCONV, true);
     74            ppStackFileActivation(config, PPSTACK_FILES_PHOT, true);
     75            if (!ppStackFilesIterateUp(config)) {
     76                psError(psErrorCodeLast(), false, "Unable to close files.");
     77                exitValue = ppStackExitCode(exitValue);
     78                pmFPAfileFreeSetStrict(false);
     79            }
     80        }
     81
     82        // Write out summary statistics
     83        if (options && options->stats) {
     84
     85            psMetadataAddS32(options->stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE,
     86                             "Bad data quality flag", options->quality);
     87            psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_STACK", 0,
     88                             "Total time", psTimerClear("PPSTACK_TOTAL"));
     89
     90            const char *statsMDC = psMetadataConfigFormat(options->stats);
     91            if (!statsMDC || strlen(statsMDC) == 0) {
     92                psError(PS_ERR_IO, false, "Unable to get statistics MDC file.");
     93                return false;
     94            }
     95            if (fprintf(options->statsFile, "%s", statsMDC) != strlen(statsMDC)) {
     96                psError(PS_ERR_IO, false, "Unable to write statistics MDC file.");
     97                return false;
     98            }
     99            psFree(statsMDC);
     100            if (fclose(options->statsFile) == EOF) {
     101                psError(PS_ERR_IO, false, "Unable to close statistics MDC file.");
     102                return false;
     103            }
     104            options->statsFile = NULL;
     105            pmConfigRunFilenameAddWrite(config, "STATS",
     106                                        psMetadataLookupStr(NULL, config->arguments, "STATS"));
     107        }
     108        psFree(options);
     109
     110        // Dump configuration
     111        bool mdok;                                                                    // Status of MD lookup
     112        psString dump = psMetadataLookupStr(&mdok, config->arguments, "DUMP_CONFIG"); // File for config
     113        if (dump && !pmConfigDump(config, dump)) {
     114            psError(psErrorCodeLast(), false, "Unable to dump configuration.");
     115            exitValue = ppStackExitCode(exitValue);
     116        }
     117
     118        psTrace("ppStack", 1, "Finished at %f sec\n", psTimerMark(TIMER_NAME));
     119        psTimerStop();
     120
     121        psFree(config);
     122        pmModelClassCleanup();
     123        pmConfigDone();
     124        psLibFinalize();
     125        pmVisualClose();
     126
     127        exitValue = ppStackExitCode(exitValue);
     128        exit(exitValue);
     129    }
    81130}
    82131
  • branches/tap_branches/ppStack/src/ppStack.h

    r23573 r27838  
    99
    1010#include "ppStackOptions.h"
     11#include "ppStackErrorCodes.h"
    1112
    1213// Mask values for inputs
    1314typedef enum {
     15    PPSTACK_MASK_NONE   = 0x00,         // Nothing wrong
    1416    PPSTACK_MASK_CAL    = 0x01,         // Photometric calibration failed
    15     PPSTACK_MASK_MATCH  = 0x02,         // PSF-matching failed
    16     PPSTACK_MASK_CHI2   = 0x04,         // Chi^2 too deviant
    17     PPSTACK_MASK_REJECT = 0x08,         // Rejection failed
    18     PPSTACK_MASK_BAD    = 0x10,         // Bad image (too many pixels rejected)
     17    PPSTACK_MASK_PSF    = 0x02,         // PSF measurement failed
     18    PPSTACK_MASK_MATCH  = 0x04,         // PSF-matching failed
     19    PPSTACK_MASK_CHI2   = 0x08,         // Chi^2 too deviant
     20    PPSTACK_MASK_REJECT = 0x10,         // Rejection failed
     21    PPSTACK_MASK_BAD    = 0x20,         // Bad image (too many pixels rejected)
    1922    PPSTACK_MASK_ALL    = 0xff          // All errors
    2023} ppStackMask;
     
    2427    PPSTACK_FILES_PREPARE,              // Files for preparation
    2528    PPSTACK_FILES_CONVOLVE,             // Files for convolution
    26     PPSTACK_FILES_COMBINE,              // Files for combination
     29    PPSTACK_FILES_STACK,                // Stack files
     30    PPSTACK_FILES_UNCONV,               // Unconvolved stack files
    2731    PPSTACK_FILES_PHOT                  // Files for photometry
    2832} ppStackFileList;
     
    5963// Perform stacking on a readout
    6064//
    61 // Returns an array of pixels to inspect for each input image
     65// Returns two arrays: pixels to inspect for each input image, and pixels to reject for each input image.
    6266psArray *ppStackReadoutInitial(const pmConfig *config,   // Configuration
    6367                               pmReadout *outRO,   // Output readout
     
    6569                               const psVector *mask, // Mask for input readouts
    6670                               const psVector *weightings, // Weighting factors for each image
     71                               const psVector *exposures,  // Exposure time for each image
    6772                               const psVector *addVariance // Additional variance for rejection
    6873    );
     
    7984bool ppStackReadoutFinal(const pmConfig *config,   // Configuration
    8085                         pmReadout *outRO,   // Output readout
     86                         pmReadout *expRO,   // Exposure readout
    8187                         const psArray *readouts, // Input readouts
    8288                         const psVector *mask, // Mask for input readouts
    8389                         const psArray *rejected, // Array with pixels rejected in each image
    8490                         const psVector *weightings, // Weighting factors for each image
    85                          const psVector *addVariance // Additional variance for rejection
     91                         const psVector *exposures,  // Exposure times for each image
     92                         const psVector *addVariance, // Additional variance for rejection
     93                         bool safety,                 // Enable safety switch?
     94                         const psVector *norm         // Normalisations to apply
    8695    );
    8796
     
    164173    );
    165174
     175/// Return an appropriate exit code based on the error code
     176psExit ppStackExitCode(psExit exitValue);
    166177
    167178#endif
  • branches/tap_branches/ppStack/src/ppStackArguments.c

    r23841 r27838  
    4343        value = psMetadataLookup##TYPE(&mdok, recipe, RECIPENAME); \
    4444        if (!mdok) { \
    45             psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s", \
     45            psError(PPSTACK_ERR_CONFIG, true, "Unable to find %s in recipe %s", \
    4646                RECIPENAME, PPSTACK_RECIPE); \
    4747            goto ERROR; \
     
    5858        value = psMetadataLookup##TYPE(&mdok, recipe, RECIPENAME); \
    5959        if (!mdok) { \
    60             psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s", \
     60            psError(PPSTACK_ERR_CONFIG, true, "Unable to find %s in recipe %s", \
    6161                RECIPENAME, PPSTACK_RECIPE); \
    6262            goto ERROR; \
     
    7373        name = psMetadataLookupStr(NULL, recipe, RECIPENAME); \
    7474        if (!name) { \
    75             psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s", \
    76                 RECIPENAME, PPSTACK_RECIPE); \
     75            psError(PPSTACK_ERR_CONFIG, true, "Unable to find %s in recipe %s", \
     76                    RECIPENAME, PPSTACK_RECIPE);                        \
    7777            goto ERROR; \
    7878        } \
     
    108108        value = psMetadataLookupStr(NULL, recipe, mdName);
    109109        if (!value) {
    110             psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s",
     110            psError(PPSTACK_ERR_CONFIG, true, "Unable to find %s in recipe %s",
    111111                    mdName, PPSTACK_RECIPE);
    112112            return false;
     
    148148    psMetadataAddStr(arguments, PS_LIST_TAIL, "-stamps", 0, "Stamps file with x,y,flux per line", NULL);
    149149    psMetadataAddStr(arguments, PS_LIST_TAIL, "-stats", 0, "Statistics file", NULL);
    150     psMetadataAddS32(arguments, PS_LIST_TAIL, "-iter", 0, "Number of rejection iterations", 0);
     150    psMetadataAddF32(arguments, PS_LIST_TAIL, "-combine-iter", 0, "Number of rejection iterations per input", NAN);
    151151    psMetadataAddF32(arguments, PS_LIST_TAIL, "-combine-rej", 0,
    152152                     "Combination rejection thresold (sigma)", NAN);
     
    185185    psMetadataAddF32(arguments, PS_LIST_TAIL, "-zp-star-sys-1", 0, "Estimated systematic error; pass 1", NAN);
    186186    psMetadataAddF32(arguments, PS_LIST_TAIL, "-zp-star-sys-2", 0, "Estimated systematic error; pass 2", NAN);
     187    psMetadataAddStr(arguments, PS_LIST_TAIL, "-temp-dir", 0, "Directory for temporary images", NULL);
    187188    psMetadataAddStr(arguments, PS_LIST_TAIL, "-temp-image", 0, "Suffix for temporary images", NULL);
    188189    psMetadataAddStr(arguments, PS_LIST_TAIL, "-temp-mask", 0, "Suffix for temporary masks", NULL);
     
    206207        psMetadata *inputs = psMetadataConfigRead(NULL, &numBad, argv[argNum], false); // Input file info
    207208        if (!inputs || numBad > 0) {
    208             psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to cleanly read MDC file with inputs.");
     209            psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to cleanly read MDC file with inputs.");
    209210            return false;
    210211        }
     
    228229    int numThreads = psMetadataLookupS32(NULL, arguments, "-threads"); // Number of threads
    229230    if (numThreads > 0 && !psThreadPoolInit(numThreads)) {
    230         psError(PS_ERR_UNKNOWN, false, "Unable to setup %d threads", numThreads);
     231        psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to setup %d threads", numThreads);
    231232        return false;
    232233    }
     
    246247    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // Recipe
    247248    if (!recipe) {
    248         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSTACK_RECIPE);
     249        psError(PPSTACK_ERR_CONFIG, false, "Unable to find recipe %s", PPSTACK_RECIPE);
    249250        goto ERROR;
    250251    }
    251252
    252     VALUE_ARG_RECIPE_INT("-iter",              "ITER",            S32, 0);
     253    VALUE_ARG_RECIPE_FLOAT("-combine-iter",    "COMBINE.ITER",    F32);
    253254    VALUE_ARG_RECIPE_FLOAT("-combine-rej",     "COMBINE.REJ",     F32);
    254255    VALUE_ARG_RECIPE_FLOAT("-combine-sys",     "COMBINE.SYS",     F32);
     
    260261    VALUE_ARG_RECIPE_FLOAT("-poor-frac",       "POOR.FRACTION",   F32);
    261262
    262     valueArgRecipeStr(arguments, recipe, "-mask-val",  "MASK.VAL",  recipe);
     263    valueArgRecipeStr(arguments, recipe, "-mask-val",  "MASK.IN",   recipe);
    263264    valueArgRecipeStr(arguments, recipe, "-mask-bad",  "MASK.BAD",  recipe);
    264265    valueArgRecipeStr(arguments, recipe, "-mask-poor", "MASK.POOR", recipe);
     
    316317
    317318    pmConfigCamerasCull(config, NULL);
    318     pmConfigRecipesCull(config, "PPSTACK,PPSUB,PPSTATS,PSPHOT,MASKS,JPEG");
     319    pmConfigRecipesCull(config, "PPSTACK,PPSUB,PPSTATS,PSPHOT,PSASTRO,MASKS,JPEG");
    319320
    320321    return true;
  • branches/tap_branches/ppStack/src/ppStackCamera.c

    r25519 r27838  
    3030        pmFPAfileDefineFromArgs(&found, config, name, "FILENAMES");
    3131    if (!file || !found) {
    32         psError(PS_ERR_UNKNOWN, false, "Unable to define file %s from %s", name, filename);
     32        psError(psErrorCodeLast(), false, "Unable to define file %s from %s", name, filename);
    3333        return NULL;
    3434    }
    3535    if (file->type != type) {
    36         psError(PS_ERR_IO, true, "%s is not of type %s", name, pmFPAfileStringFromType(type));
     36        psError(PS_ERR_IO, PPSTACK_ERR_CONFIG, "%s is not of type %s", name, pmFPAfileStringFromType(type));
    3737        return NULL;
    3838    }
     
    5353    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // Recipe for ppSim
    5454    if (!recipe) {
    55         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSTACK_RECIPE);
     55        psError(PPSTACK_ERR_CONFIG, false, "Unable to find recipe %s", PPSTACK_RECIPE);
    5656        return false;
    5757    }
     
    6767                                                           "PPSTACK.INPUT.MASK"); // Input masks
    6868        if (!status) {
    69             psError(PS_ERR_UNKNOWN, false, "Unable to define input masks from RUN metadata.");
     69            psError(psErrorCodeLast(), false, "Unable to define input masks from RUN metadata.");
    7070            psFree(runImages);
    7171            return false;
     
    7676                                                          "PPSTACK.INPUT.VARIANCE"); // Input variances
    7777        if (!status) {
    78             psError(PS_ERR_UNKNOWN, false, "Unable to define input variances from RUN metadata.");
     78            psError(psErrorCodeLast(), false, "Unable to define input variances from RUN metadata.");
    7979            psFree(runImages);
    8080            return false;
     
    8888                                                         "PPSTACK.INPUT.SOURCES"); // Input sources
    8989        if (!status) {
    90             psError(PS_ERR_UNKNOWN, false, "Unable to define input sources from RUN metadata.");
     90            psError(psErrorCodeLast(), false, "Unable to define input sources from RUN metadata.");
    9191            psFree(runImages);
    9292            return false;
    9393        }
    9494        if (!runSrc) {
    95             psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to define input sources from RUN metadata.");
     95            psError(PPSTACK_ERR_CONFIG, true, "Unable to define input sources from RUN metadata.");
    9696            psFree(runImages);
    9797            return false;
     
    104104                                                         "PPSTACK.INPUT.PSF"); // Input PSFs
    105105                if (!status) {
    106                     psError(PS_ERR_UNKNOWN, false, "Unable to define input PSFs from RUN metadata.");
     106                    psError(psErrorCodeLast(), false, "Unable to define input PSFs from RUN metadata.");
    107107                    psFree(runImages);
    108108                    return false;
     
    118118                                                                    "PPSTACK.CONV.KERNEL"); // Conv'n kernels
    119119                if (!status) {
    120                     psError(PS_ERR_UNKNOWN, false, "Unable to define convolution kernels from RUN metadata.");
     120                    psError(psErrorCodeLast(), false,
     121                            "Unable to define convolution kernels from RUN metadata.");
    121122                    psFree(runImages);
    122123                    return false;
    123124                }
    124125                if (!runKernel) {
    125                     psError(PS_ERR_UNEXPECTED_NULL, true,
     126                    psError(PPSTACK_ERR_CONFIG, true,
    126127                            "Unable to define convolution kernels from RUN metadata.");
    127128                    psFree(runImages);
     
    137138        psMetadata *inputs = psMetadataLookupMetadata(NULL, config->arguments, "INPUTS"); // The inputs info
    138139        if (!inputs) {
    139             psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find inputs.");
     140            psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to find inputs.");
    140141            return false;
    141142        }
     
    145146        while ((item = psMetadataGetAndIncrement(iter))) {
    146147            if (item->type != PS_DATA_METADATA) {
    147                 psError(PS_ERR_BAD_PARAMETER_TYPE, true,
     148                psError(PPSTACK_ERR_ARGUMENTS, true,
    148149                        "Component %s of the input metadata is not of type METADATA", item->name);
    149150                psFree(iter);
     
    155156            psString image = psMetadataLookupStr(NULL, input, "IMAGE"); // Name of image
    156157            if (!image || strlen(image) == 0) {
    157                 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Component %s lacks IMAGE of type STR", item->name);
     158                psError(PPSTACK_ERR_ARGUMENTS, true, "Component %s lacks IMAGE of type STR", item->name);
    158159                psFree(iter);
    159160                return false;
     
    169170                                              image, PM_FPA_FILE_IMAGE); // File for image
    170171            if (!imageFile) {
    171                 psError(PS_ERR_UNKNOWN, false, "Unable to define file from image %d (%s)", i, image);
     172                psError(psErrorCodeLast(), false, "Unable to define file from image %d (%s)", i, image);
    172173                return false;
    173174            }
     
    175176            if (mask && strlen(mask) > 0 &&
    176177                !defineFile(config, imageFile, "PPSTACK.INPUT.MASK", mask, PM_FPA_FILE_MASK)) {
    177                 psError(PS_ERR_UNKNOWN, false, "Unable to define file from mask %d (%s)", i, mask);
     178                psError(psErrorCodeLast(), false, "Unable to define file from mask %d (%s)", i, mask);
    178179                return false;
    179180            }
     
    183184                if (!defineFile(config, imageFile, "PPSTACK.INPUT.VARIANCE", variance,
    184185                                PM_FPA_FILE_VARIANCE)) {
    185                     psError(PS_ERR_UNKNOWN, false,
     186                    psError(psErrorCodeLast(), false,
    186187                            "Unable to define file from variance %d (%s)", i, variance);
    187188                    return false;
     
    195196                    havePSFs = true;
    196197                    if (!defineFile(config, imageFile, "PPSTACK.INPUT.PSF", psf, PM_FPA_FILE_PSF)) {
    197                         psError(PS_ERR_UNKNOWN, false, "Unable to define file from psf %d (%s)", i, psf);
     198                        psError(psErrorCodeLast(), false, "Unable to define file from psf %d (%s)", i, psf);
    198199                        return false;
    199200                    }
    200201                }
    201202            } else if (havePSFs) {
    202                 psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find PSF %d", i);
     203                psError(PPSTACK_ERR_CONFIG, true, "Unable to find PSF %d", i);
    203204                return false;
    204205            }
    205206
    206207            if (!sources || strlen(sources) == 0) {
    207                 psError(PS_ERR_UNEXPECTED_NULL, true, "SOURCES not provided for file %d", i);
     208                psError(PPSTACK_ERR_CONFIG, true, "SOURCES not provided for file %d", i);
    208209                return false;
    209210            }
    210211            if (!defineFile(config, imageFile, "PPSTACK.INPUT.SOURCES", sources, PM_FPA_FILE_CMF)) {
    211                 psError(PS_ERR_UNKNOWN, false, "Unable to define file from sources %d (%s)",
     212                psError(psErrorCodeLast(), false, "Unable to define file from sources %d (%s)",
    212213                        i, sources);
    213214                return false;
     
    217218                pmFPAfile *kernel = pmFPAfileDefineOutput(config, imageFile->fpa, "PPSTACK.CONV.KERNEL");
    218219                if (!kernel) {
    219                     psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.CONV.KERNEL"));
     220                    psError(psErrorCodeLast(), false,
     221                            "Unable to generate output file from PPSTACK.CONV.KERNEL");
    220222                    return false;
    221223                }
     
    233235
    234236    // Output image
    235     pmFPA *fpa = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain the output
    236     if (!fpa) {
    237         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to construct an FPA from camera configuration.");
    238         return false;
    239     }
    240     pmFPAfile *output = pmFPAfileDefineOutput(config, fpa, "PPSTACK.OUTPUT");
    241     psFree(fpa);                        // Drop reference
     237    pmFPA *outFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain the output
     238    if (!outFPA) {
     239        psError(psErrorCodeLast(), false, "Unable to construct an FPA from camera configuration.");
     240        return false;
     241    }
     242    pmFPAfile *output = pmFPAfileDefineOutput(config, outFPA, "PPSTACK.OUTPUT");
     243    psFree(outFPA);                        // Drop reference
    242244    if (!output) {
    243         psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT"));
     245        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT"));
    244246        return false;
    245247    }
    246248    if (output->type != PM_FPA_FILE_IMAGE) {
    247         psError(PS_ERR_IO, true, "PPSTACK.OUTPUT is not of type IMAGE");
     249        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT is not of type IMAGE");
    248250        return false;
    249251    }
    250252    output->save = true;
    251253
    252     if (!pmFPAAddSourceFromFormat(fpa, "Stack", output->format)) {
    253         psError(PS_ERR_UNKNOWN, false, "Unable to generate output FPA.");
    254         psFree(fpa);
     254    if (!pmFPAAddSourceFromFormat(outFPA, "Stack", output->format)) {
     255        psError(psErrorCodeLast(), false, "Unable to generate output FPA.");
    255256        return false;
    256257    }
     
    259260    pmFPAfile *outMask = pmFPAfileDefineOutput(config, output->fpa, "PPSTACK.OUTPUT.MASK");
    260261    if (!outMask) {
    261         psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT.MASK"));
     262        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.MASK"));
    262263        return false;
    263264    }
    264265    if (outMask->type != PM_FPA_FILE_MASK) {
    265         psError(PS_ERR_IO, true, "PPSTACK.OUTPUT.MASK is not of type MASK");
     266        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.MASK is not of type MASK");
    266267        return false;
    267268    }
     
    272273        pmFPAfile *outVariance = pmFPAfileDefineOutput(config, output->fpa, "PPSTACK.OUTPUT.VARIANCE");
    273274        if (!outVariance) {
    274             psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT.VARIANCE"));
     275            psError(psErrorCodeLast(), false, "Unable to generate output file from PPSTACK.OUTPUT.VARIANCE");
    275276            return false;
    276277        }
    277278        if (outVariance->type != PM_FPA_FILE_VARIANCE) {
    278             psError(PS_ERR_IO, true, "PPSTACK.OUTPUT.VARIANCE is not of type VARIANCE");
     279            psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.VARIANCE is not of type VARIANCE");
    279280            return false;
    280281        }
     
    282283    }
    283284
     285
     286    // Exposure image
     287    pmFPA *expFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain the output
     288    if (!expFPA) {
     289        psError(psErrorCodeLast(), false, "Unable to construct an FPA from camera configuration.");
     290        return false;
     291    }
     292    pmFPAfile *exp = pmFPAfileDefineOutput(config, expFPA, "PPSTACK.OUTPUT.EXP");
     293    psFree(expFPA);                        // Drop reference
     294    if (!exp) {
     295        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.EXP"));
     296        return false;
     297    }
     298    if (exp->type != PM_FPA_FILE_IMAGE) {
     299        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.EXP is not of type IMAGE");
     300        return false;
     301    }
     302    exp->save = true;
     303
     304    if (!pmFPAAddSourceFromFormat(expFPA, "Stack", exp->format)) {
     305        psError(psErrorCodeLast(), false, "Unable to generate output FPA.");
     306        return false;
     307    }
     308
     309    // Exposure numbers
     310    pmFPAfile *expNum = pmFPAfileDefineOutput(config, exp->fpa, "PPSTACK.OUTPUT.EXPNUM");
     311    if (!expNum) {
     312        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.EXPNUM"));
     313        return false;
     314    }
     315    if (expNum->type != PM_FPA_FILE_MASK) {
     316        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.EXPNUM is not of type MASK");
     317        return false;
     318    }
     319    expNum->save = true;
     320
     321    // Weighted exposure
     322    pmFPAfile *expWt = pmFPAfileDefineOutput(config, exp->fpa, "PPSTACK.OUTPUT.EXPWT");
     323    if (!expWt) {
     324        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.EXPWT"));
     325        return false;
     326    }
     327    if (expWt->type != PM_FPA_FILE_VARIANCE) {
     328        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.EXPWT is not of type VARIANCE");
     329        return false;
     330    }
     331    expWt->save = true;
     332
     333
    284334    if (havePSFs) {
    285         pmFPAfile *targetPSF = pmFPAfileDefineOutput(config, output->fpa, "PPSTACK.TARGET.PSF");
     335        pmFPA *psfFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain PSF
     336        if (!psfFPA) {
     337            psError(psErrorCodeLast(), false, "Unable to construct an FPA from camera configuration.");
     338            return false;
     339        }
     340        pmFPAfile *targetPSF = pmFPAfileDefineOutput(config, psfFPA, "PPSTACK.TARGET.PSF");
    286341        if (!targetPSF) {
    287             psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.TARGET.PSF"));
    288             return false;
    289         }
     342            psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.TARGET.PSF"));
     343            return false;
     344        }
     345        psFree(psfFPA);
    290346        if (targetPSF->type != PM_FPA_FILE_PSF) {
    291             psError(PS_ERR_IO, true, "PPSTACK.TARGET.PSF is not of type PSF");
     347            psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.TARGET.PSF is not of type PSF");
    292348            return false;
    293349        }
    294350        targetPSF->save = true;
    295351    }
     352
     353    // Unconvolved stack
     354    pmFPA *unconvFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain unconvolved output
     355    if (!unconvFPA) {
     356        psError(psErrorCodeLast(), false, "Unable to construct an FPA from camera configuration.");
     357        return false;
     358    }
     359    pmFPAfile *unConv = pmFPAfileDefineOutput(config, unconvFPA, "PPSTACK.UNCONV");
     360    psFree(unconvFPA);                  // Drop reference
     361    if (!unConv) {
     362        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.UNCONV"));
     363        return false;
     364    }
     365    if (unConv->type != PM_FPA_FILE_IMAGE) {
     366        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV is not of type IMAGE");
     367        return false;
     368    }
     369    unConv->save = true;
     370
     371    if (!pmFPAAddSourceFromFormat(unconvFPA, "Stack", unConv->format)) {
     372        psError(psErrorCodeLast(), false, "Unable to generate output FPA.");
     373        return false;
     374    }
     375
     376    // Unconvolved mask
     377    pmFPAfile *unconvMask = pmFPAfileDefineOutput(config, unconvFPA, "PPSTACK.UNCONV.MASK");
     378    if (!unconvMask) {
     379        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.UNCONV.MASK"));
     380        return false;
     381    }
     382    if (unconvMask->type != PM_FPA_FILE_MASK) {
     383        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV.MASK is not of type MASK");
     384        return false;
     385    }
     386    unconvMask->save = true;
     387
     388    // Unconvolved variance
     389    if (haveVariances) {
     390        pmFPAfile *unconvVariance = pmFPAfileDefineOutput(config, unconvFPA, "PPSTACK.UNCONV.VARIANCE");
     391        if (!unconvVariance) {
     392            psError(psErrorCodeLast(), false, "Unable to generate output file from PPSTACK.UNCONV.VARIANCE");
     393            return false;
     394        }
     395        if (unconvVariance->type != PM_FPA_FILE_VARIANCE) {
     396            psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV.VARIANCE is not of type VARIANCE");
     397            return false;
     398        }
     399        unconvVariance->save = true;
     400    }
     401
     402
     403    // Exposure image
     404    pmFPA *unconvExpFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain the output
     405    if (!unconvExpFPA) {
     406        psError(psErrorCodeLast(), false, "Unable to construct an FPA from camera configuration.");
     407        return false;
     408    }
     409    pmFPAfile *unconvExp = pmFPAfileDefineOutput(config, unconvExpFPA, "PPSTACK.UNCONV.EXP");
     410    psFree(unconvExpFPA);               // Drop reference
     411    if (!unconvExp) {
     412        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.UNCONV.EXP"));
     413        return false;
     414    }
     415    if (unconvExp->type != PM_FPA_FILE_IMAGE) {
     416        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV.EXP is not of type IMAGE");
     417        return false;
     418    }
     419    unconvExp->save = true;
     420
     421    if (!pmFPAAddSourceFromFormat(unconvExpFPA, "Stack", unconvExp->format)) {
     422        psError(psErrorCodeLast(), false, "Unable to generate output FPA.");
     423        return false;
     424    }
     425
     426    // Exposure numbers
     427    pmFPAfile *unconvExpNum = pmFPAfileDefineOutput(config, unconvExp->fpa, "PPSTACK.UNCONV.EXPNUM");
     428    if (!unconvExpNum) {
     429        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.UNCONV.MASK"));
     430        return false;
     431    }
     432    if (unconvExpNum->type != PM_FPA_FILE_MASK) {
     433        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV.EXPNUM is not of type MASK");
     434        return false;
     435    }
     436    unconvExpNum->save = true;
     437
     438    // Weighted exposure
     439    pmFPAfile *unconvExpWt = pmFPAfileDefineOutput(config, unconvExp->fpa, "PPSTACK.UNCONV.EXPWT");
     440    if (!unconvExpWt) {
     441        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.UNCONV.EXPWT"));
     442        return false;
     443    }
     444    if (unconvExpWt->type != PM_FPA_FILE_VARIANCE) {
     445        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV.EXPWT is not of type VARIANCE");
     446        return false;
     447    }
     448    unconvExpWt->save = true;
    296449
    297450    // Output JPEGs
    298451    pmFPAfile *jpeg1 = pmFPAfileDefineOutput(config, NULL, "PPSTACK.OUTPUT.JPEG1");
    299452    if (!jpeg1) {
    300         psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT.JPEG1"));
     453        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.JPEG1"));
    301454        return false;
    302455    }
    303456    if (jpeg1->type != PM_FPA_FILE_JPEG) {
    304         psError(PS_ERR_IO, true, "PPSTACK.OUTPUT.JPEG1 is not of type JPEG");
     457        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.JPEG1 is not of type JPEG");
    305458        return false;
    306459    }
     
    308461    pmFPAfile *jpeg2 = pmFPAfileDefineOutput(config, NULL, "PPSTACK.OUTPUT.JPEG2");
    309462    if (!jpeg2) {
    310         psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT.JPEG2"));
     463        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.JPEG2"));
    311464        return false;
    312465    }
    313466    if (jpeg2->type != PM_FPA_FILE_JPEG) {
    314         psError(PS_ERR_IO, true, "PPSTACK.OUTPUT.JPEG2 is not of type JPEG");
     467        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.JPEG2 is not of type JPEG");
    315468        return false;
    316469    }
     
    323476        psMetadataLookupBool(&mdok, config->arguments, "-photometry"); // perform photometry
    324477    if (doPhotom) {
    325         // This file, PSPHOT.INPUT, is just used as a carrier; output files (eg, PSPHOT.RESID) are defined by
    326         // psphotDefineFiles
     478        // This pmFPAfile, PSPHOT.INPUT, is just used as a carrier; output files (eg,
     479        // PSPHOT.RESID) are defined by psphotDefineFiles
    327480        pmFPAfile *psphotInput = pmFPAfileDefineFromFPA(config, output->fpa, 1, 1, "PSPHOT.INPUT");
    328481        if (!psphotInput) {
    329             psError(PS_ERR_IO, false, _("Unable to generate output file from PSPHOT.INPUT"));
    330             return false;
    331         }
     482            psError(psErrorCodeLast(), false, _("Unable to generate output file from PSPHOT.INPUT"));
     483            return false;
     484        }
     485        // specify the number of psphot input images
     486        psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);
    332487
    333488        // Define associated psphot input/output files
    334489        if (!psphotDefineFiles(config, psphotInput)) {
    335             psError(PSPHOT_ERR_CONFIG, false,
     490            psError(psErrorCodeLast(), false,
    336491                    "Trouble defining the additional input/output files for psphot");
    337492            return false;
     
    341496        pmFPAfile *outPSF = pmFPAfileDefineOutputFromFile(config, output, "PSPHOT.PSF.SAVE");
    342497        if (!outPSF) {
    343             psError(PS_ERR_IO, false, _("Unable to generate output file from PSPHOT.PSF.SAVE"));
     498            psError(psErrorCodeLast(), false, _("Unable to generate output file from PSPHOT.PSF.SAVE"));
    344499            return false;
    345500        }
    346501        if (outPSF->type != PM_FPA_FILE_PSF) {
    347             psError(PS_ERR_IO, true, "PSPHOT.PSF.SAVE is not of type PSF");
     502            psError(PPSTACK_ERR_CONFIG, true, "PSPHOT.PSF.SAVE is not of type PSF");
    348503            return false;
    349504        }
  • branches/tap_branches/ppStack/src/ppStackCleanup.c

    r23341 r27838  
    44
    55#include <stdio.h>
    6 #include <unistd.h>
    76#include <pslib.h>
    87#include <psmodules.h>
     8#include <ppStats.h>
    99
    1010#include "ppStack.h"
    1111#include "ppStackLoop.h"
    12 
    13 #define WCS_TOLERANCE 0.001             // Tolerance for WCS
    1412
    1513
     
    2220    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
    2321    psAssert(recipe, "We've thrown an error on this before.");
    24 
    25     bool mdok;                          // Status of MD lookup
    26     bool tempDelete = psMetadataLookupBool(&mdok, recipe, "TEMP.DELETE"); // Delete temporary files?
    2722
    2823#if 0
     
    3732#endif
    3833
    39     // Close up
    40     bool wcsDone = false;           // Have we done the WCS?
    41     for (int i = 0; i < options->num; i++) {
    42         if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
    43             continue;
    44         }
    45 
    46         ppStackThread *thread = stack->threads->data[0]; // Representative stack
    47         pmReadout *inRO = thread->readouts->data[i]; // Template readout
    48         if (inRO && !wcsDone) {
    49             // Copy astrometry over
    50             wcsDone = true;
    51             pmHDU *inHDU = pmHDUFromCell(inRO->parent); // Template HDU
    52             pmHDU *outHDU = pmHDUFromCell(options->outRO->parent); // Output HDU
    53             pmChip *outChip = options->outRO->parent->parent; // Output chip
    54             pmFPA *outFPA = outChip->parent; // Output FPA
    55             if (!outHDU || !inHDU) {
    56                 psWarning("Unable to find HDU at FPA level to copy astrometry.");
    57             } else {
    58                 if (!pmAstromReadWCS(outFPA, outChip, inHDU->header, 1.0)) {
    59                     psErrorClear();
    60                     psWarning("Unable to read WCS astrometry from input FPA.");
    61                     wcsDone = false;
    62                 } else {
    63                     if (!outHDU->header) {
    64                         outHDU->header = psMetadataAlloc();
    65                     }
    66                     if (!pmAstromWriteWCS(outHDU->header, outFPA, outChip, WCS_TOLERANCE)) {
    67                         psErrorClear();
    68                         psWarning("Unable to write WCS astrometry to output FPA.");
    69                         wcsDone = false;
    70                     }
    71                 }
    72             }
    73         }
    74 
    75         if (tempDelete) {
    76             psString imageResolved = pmConfigConvertFilename(options->imageNames->data[i],
    77                                                              config, false, false);
    78             psString maskResolved = pmConfigConvertFilename(options->maskNames->data[i],
    79                                                             config, false, false);
    80             psString varianceResolved = pmConfigConvertFilename(options->varianceNames->data[i],
    81                                                                 config, false, false);
    82             if (unlink(imageResolved) == -1 || unlink(maskResolved) == -1 ||
    83                 unlink(varianceResolved) == -1) {
    84                 psWarning("Unable to delete temporary files for image %d", i);
    85             }
    86             psFree(imageResolved);
    87             psFree(maskResolved);
    88             psFree(varianceResolved);
    89         }
    90     }
    91 
    92     ppStackMemDump("cleanup");
    93 
    9434    // Generate binned JPEGs
    9535    {
     
    10343        pmCell *cell2 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG2");
    10444        psImageMaskType maskValue = pmConfigMaskGet("BLANK", config); // Bits to mask
     45        psFree(view);
    10546
    10647        pmReadout *ro1 = pmReadoutAlloc(cell1), *ro2 = pmReadoutAlloc(cell2); // Binned readouts
    10748        if (!pmReadoutRebin(ro1, options->outRO, maskValue, bin1, bin1) ||
    10849            !pmReadoutRebin(ro2, ro1, 0, bin2, bin2)) {
    109             psError(PS_ERR_UNKNOWN, false, "Unable to bin output.");
     50            psError(PPSTACK_ERR_DATA, false, "Unable to bin output.");
    11051            psFree(ro1);
    11152            psFree(ro2);
     
    11657    }
    11758
    118     // Put version information into the header
    119     pmHDU *hdu = pmHDUFromCell(options->outRO->parent);
    120     if (!hdu) {
    121         psError(PS_ERR_UNKNOWN, false, "Unable to find HDU for output.");
     59    // Statistics on output
     60    if (options->stats) {
     61        psTrace("ppStack", 1, "Gathering statistics on stacked image....\n");
     62        psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits for bad
     63        psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
     64
     65        pmFPAview *view = pmFPAviewAlloc(0); // View to readout
     66        view->chip = view->cell = view->readout = 0;
     67
     68        ppStatsFPA(options->stats, options->outRO->parent->parent->parent, view, maskBad, config);
     69
     70        psFree(view);
     71    }
     72
     73    if (!ppStackFilesIterateUp(config)) {
     74        psError(psErrorCodeLast(), false, "Unable to close files.");
    12275        return false;
    12376    }
    124     if (!hdu->header) {
    125         hdu->header = psMetadataAlloc();
     77    ppStackFileActivation(config, PPSTACK_FILES_STACK, false);
     78    ppStackFileActivation(config, PPSTACK_FILES_PHOT, false);
     79
     80    // Ensure files are freed
     81    {
     82        options->outRO->data_exists = false;
     83        options->outRO->parent->data_exists = false;
     84        options->outRO->parent->parent->data_exists = false;
     85        psFree(options->outRO);
     86        options->outRO = NULL;
     87
     88        options->expRO->data_exists = false;
     89        options->expRO->parent->data_exists = false;
     90        options->expRO->parent->parent->data_exists = false;
     91        psFree(options->expRO);
     92        options->expRO = NULL;
     93
     94        pmFPAview *view = pmFPAviewAlloc(0);// Pointer into FPA hierarchy
     95        view->chip = view->cell = 0;        // pmFPAviewFreeData doesn't want to deal with readouts
     96        pmFPAfile *jpeg1 = pmFPAfileSelectSingle(config->files, "PPSTACK.OUTPUT.JPEG1", 0); // JPEG file
     97        pmFPAviewFreeData(view, jpeg1);
     98        pmFPAfile *jpeg2 = pmFPAfileSelectSingle(config->files, "PPSTACK.OUTPUT.JPEG2", 0); // JPEG file
     99        pmFPAviewFreeData(view, jpeg2);
     100        pmFPAfile *phot = NULL;         // Photometry file
     101        if (options->photometry) {
     102            phot = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", 0); // Photometry file
     103            pmFPAviewFreeData(view, phot);
     104        }
     105
     106        view->readout = 0;
     107        pmReadout *ro1 = pmFPAviewThisReadout(view, jpeg1->fpa); // JPEG readout
     108        ro1->data_exists = ro1->parent->data_exists = ro1->parent->parent->data_exists = false;
     109        pmReadout *ro2 = pmFPAviewThisReadout(view, jpeg2->fpa); // JPEG readout
     110        ro2->data_exists = ro2->parent->data_exists = ro2->parent->parent->data_exists = false;
     111        if (options->photometry) {
     112            pmReadout *ro = pmFPAviewThisReadout(view, phot->fpa); // Photometry readout
     113            ro->data_exists = ro->parent->data_exists = ro->parent->parent->data_exists = false;
     114        }
     115        psFree(view);
    126116    }
    127     ppStackVersionHeader(hdu->header);
    128117
    129118    return true;
  • branches/tap_branches/ppStack/src/ppStackCombineFinal.c

    r25096 r27838  
    1010#include "ppStackLoop.h"
    1111
    12 bool ppStackCombineFinal(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config)
     12#define WCS_TOLERANCE 0.001             // Tolerance for WCS
     13
     14//#define TESTING                         // Enable test output
     15
     16bool ppStackCombineFinal(ppStackThreadData *stack, psArray *covariances, ppStackOptions *options,
     17                         pmConfig *config, bool safe, bool normalise, bool grow)
    1318{
    1419    psAssert(stack, "Require stack");
    1520    psAssert(options, "Require options");
    1621    psAssert(config, "Require configuration");
     22
     23    pmReadout *outRO = options->outRO;                                      // Output readout
     24    pmReadout *expRO = options->expRO;                                      // Exposure readout
     25    int numCols = outRO->image->numCols, numRows = outRO->image->numRows; // Size of image
     26
     27    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
     28    psAssert(recipe, "We've thrown an error on this before.");
     29    float poorFrac = psMetadataLookupF32(NULL, recipe, "POOR.FRACTION"); // Fraction for "poor"
     30
     31    // Grow the list of rejected pixels, if desired
     32    psArray *reject = psArrayAlloc(options->num); // Pixels rejected for each image
     33    for (int i = 0; i < options->num; i++) {
     34        if (options->inputMask->data.U8[i]) {
     35            continue;
     36        }
     37        if (grow) {
     38            reject->data[i] = pmStackRejectGrow(options->rejected->data[i], numCols, numRows, poorFrac,
     39                                                options->regions->data[i], options->kernels->data[i]);
     40            if (!reject->data[i]) {
     41                psError(psErrorCodeLast(), false, "Unable to grow rejected pixels for image %d", i);
     42                psFree(reject);
     43                return false;
     44            }
     45        } else {
     46            reject->data[i] = psMemIncrRefCounter(options->rejected->data[i]);
     47        }
     48    }
     49
     50    if (!outRO->mask) {
     51        outRO->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);
     52    }
     53    if (!expRO->mask) {
     54        expRO->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);
     55    }
    1756
    1857    stack->lastScan = 0;            // Reset read
     
    2261        if (!status) {
    2362            // Something went wrong
    24             psError(PS_ERR_UNKNOWN, false, "Unable to read chunk %d", numChunk);
     63            psError(psErrorCodeLast(), false, "Unable to read chunk %d", numChunk);
     64            psFree(reject);
    2565            return false;
    2666        }
     
    3373        psThreadJob *job = psThreadJobAlloc("PPSTACK_FINAL_COMBINE"); // Job to start
    3474        psArrayAdd(job->args, 1, thread);
     75        psArrayAdd(job->args, 1, reject);
    3576        psArrayAdd(job->args, 1, options);
    3677        psArrayAdd(job->args, 1, config);
     78        PS_ARRAY_ADD_SCALAR(job->args, safe, PS_TYPE_U8);
     79        PS_ARRAY_ADD_SCALAR(job->args, normalise, PS_TYPE_U8);
    3780        if (!psThreadJobAddPending(job)) {
    3881            psFree(job);
     82            psFree(reject);
    3983            return false;
    4084        }
     
    4387
    4488    if (!psThreadPoolWait(true)) {
    45         psError(PS_ERR_UNKNOWN, false, "Unable to do final combination.");
     89        psError(psErrorCodeLast(), false, "Unable to do final combination.");
     90        psFree(reject);
    4691        return false;
    4792    }
    4893
     94    psFree(reject);
     95
    4996    // Sum covariance matrices
    50     double sumWeights = 0.0;            // Sum of weights
    51     for (int i = 0; i < options->num; i++) {
    52         if (options->inputMask->data.U8[i]) {
    53             psFree(options->covariances->data[i]);
    54             options->covariances->data[i] = NULL;
     97    if (covariances) {
     98        outRO->covariance = psImageCovarianceAverageWeighted(covariances, options->weightings);
     99    } else {
     100        outRO->covariance = psImageCovarianceNone();
     101    }
     102
     103    // Propagate WCS
     104    bool wcsDone = false;           // Have we done the WCS?
     105    for (int i = 0; i < options->num && !wcsDone; i++) {
     106        if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
    55107            continue;
    56108        }
    57         psKernel *covar = options->covariances->data[i]; // Covariance matrix
    58         if (!covar) {
    59             continue;
     109
     110        ppStackThread *thread = stack->threads->data[0]; // Representative stack
     111        pmReadout *inRO = thread->readouts->data[i]; // Template readout
     112        if (inRO && !wcsDone) {
     113            // Copy astrometry over
     114            wcsDone = true;
     115            pmHDU *inHDU = pmHDUFromCell(inRO->parent); // Template HDU
     116            pmHDU *outHDU = pmHDUFromCell(outRO->parent); // Output HDU
     117            pmChip *outChip = outRO->parent->parent; // Output chip
     118            pmFPA *outFPA = outChip->parent; // Output FPA
     119            if (!outHDU || !inHDU) {
     120                psWarning("Unable to find HDU at FPA level to copy astrometry.");
     121            } else {
     122                if (!pmAstromReadWCS(outFPA, outChip, inHDU->header, 1.0)) {
     123                    psErrorClear();
     124                    psWarning("Unable to read WCS astrometry from input FPA.");
     125                    wcsDone = false;
     126                } else {
     127                    if (!outHDU->header) {
     128                        outHDU->header = psMetadataAlloc();
     129                    }
     130                    if (!pmAstromWriteWCS(outHDU->header, outFPA, outChip, WCS_TOLERANCE)) {
     131                        psErrorClear();
     132                        psWarning("Unable to write WCS astrometry to output FPA.");
     133                        wcsDone = false;
     134                    }
     135                }
     136            }
    60137        }
    61         float weight = options->weightings->data.F32[i]; // Weight to apply
    62         psBinaryOp(covar->image, covar->image, "*", psScalarAlloc(weight, PS_TYPE_F32));
    63         sumWeights += weight;
    64     }
    65     if (sumWeights > 0.0) {
    66         pmReadout *outRO = options->outRO;  // Output readout
    67         outRO->covariance = psImageCovarianceSum(options->covariances);
    68         psBinaryOp(outRO->covariance->image, outRO->covariance->image, "/",
    69                    psScalarAlloc(sumWeights, PS_TYPE_F32));
    70         psFree(options->covariances); options->covariances = NULL;
    71         psImageCovarianceTransfer(outRO->variance, outRO->covariance);
    72138    }
    73139
     140    // Set exposure time correctly
     141    {
     142        float exptime = 0.0;            // Summed exposure time
     143        for (int i = 0; i < options->num; i++) {
     144            if (options->inputMask->data.U8[i]) {
     145                continue;
     146            }
     147            exptime += options->exposures->data.F32[i];
     148        }
     149
     150        {
     151            psMetadataItem *item = psMetadataLookup(outRO->parent->concepts, "CELL.EXPOSURE");
     152            item->data.F32 = exptime;
     153        }
     154        {
     155            psMetadataItem *item = psMetadataLookup(outRO->parent->parent->parent->concepts, "FPA.EXPOSURE");
     156            item->data.F32 = exptime;
     157        }
     158    }
     159
     160    // Put version information into the header
     161    pmHDU *hdu = pmHDUFromCell(outRO->parent);
     162    if (!hdu) {
     163        psError(PPSTACK_ERR_PROG, false, "Unable to find HDU for output.");
     164        return false;
     165    }
     166    if (!hdu->header) {
     167        hdu->header = psMetadataAlloc();
     168    }
     169    ppStackVersionHeader(hdu->header);
     170
     171
    74172#ifdef TESTING
    75     pmStackVisualPlotTestImage(outRO->image, "combined_initial.fits");
    76     ppStackWriteImage("combined_final.fits", NULL, outRO->image, config);
     173    static int pass = 0;                // Pass through
     174    psString name = NULL;               // Name of file
     175    psStringAppend(&name, "combined_image_final_%d.fits", pass);
     176    pass++;
     177    ppStackWriteImage(name, NULL, outRO->image, config);
     178    psStringSubstitute(&name, "mask", "image");
     179    ppStackWriteImage(name, NULL, outRO->mask, config);
     180    psStringSubstitute(&name, "variance", "mask");
     181    ppStackWriteImage(name, NULL, outRO->variance, config);
     182    psFree(name);
     183
     184    pmStackVisualPlotTestImage(outRO->image, "combined_image_final.fits");
    77185#endif
    78186
  • branches/tap_branches/ppStack/src/ppStackCombineInitial.c

    r23767 r27838  
    1010#include "ppStackLoop.h"
    1111
     12//#define TESTING                         // Enable test output
     13
    1214bool ppStackCombineInitial(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config)
    1315{
     
    1820    if (!options->convolve) {
    1921        // No need to do initial combination when we haven't convolved
     22        // XXX either allocate inspect and rejected here, or do not require them downstream
    2023        return true;
    2124    }
     
    3437        if (!status) {
    3538            // Something went wrong
    36             psError(PS_ERR_UNKNOWN, false, "Unable to read chunk %d", numChunk);
     39            psError(psErrorCodeLast(), false, "Unable to read chunk %d", numChunk);
    3740            return false;
    3841        }
     
    5457
    5558    if (!psThreadPoolWait(false)) {
    56         psError(PS_ERR_UNKNOWN, false, "Unable to do initial combination.");
     59        psError(psErrorCodeLast(), false, "Unable to do initial combination.");
    5760        return false;
    5861    }
     
    6063    // Harvest the jobs, gathering the inspection lists
    6164    options->inspect = psArrayAlloc(options->num);
     65    options->rejected = psArrayAlloc(options->num);
    6266    for (int i = 0; i < options->num; i++) {
    6367        if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
     
    6569        }
    6670        options->inspect->data[i] = psArrayAllocEmpty(numChunk);
     71        options->rejected->data[i] = psArrayAllocEmpty(numChunk);
    6772    }
    6873    psThreadJob *job;               // Completed job
     
    7176                 "Job has incorrect type: %s", job->type);
    7277        psArray *results = job->results; // Results of job
     78        psAssert(results->n == 2, "Results array has wrong size!");
     79        psArray *inspect = results->data[0]; // Pixels to inspect
     80        psArray *reject = results->data[1];  // Pixels to reject
    7381        for (int i = 0; i < options->num; i++) {
    7482            if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
    7583                continue;
    7684            }
    77             options->inspect->data[i] = psArrayAdd(options->inspect->data[i], 1, results->data[i]);
     85            options->inspect->data[i] = psArrayAdd(options->inspect->data[i], 1, inspect->data[i]);
     86            options->rejected->data[i] = psArrayAdd(options->rejected->data[i], 1, reject->data[i]);
    7887        }
    7988        psFree(job);
     
    8392
    8493#ifdef TESTING
    85     ppStackWriteImage("combined_initial.fits", NULL, outRO->image, config);
    86     pmStackVisualPlotTestImage(outRO->image, "combined_initial.fits");
     94    ppStackWriteImage("combined_image_initial.fits", NULL, options->outRO->image, config);
     95    ppStackWriteImage("combined_mask_initial.fits", NULL, options->outRO->mask, config);
     96    ppStackWriteImage("combined_variance_initial.fits", NULL, options->outRO->variance, config);
     97
     98    pmStackVisualPlotTestImage(options->outRO->image, "combined_image_initial.fits");
    8799#endif
    88 
    89     psFree(options->matchChi2); options->matchChi2 = NULL;
    90 
    91100
    92101    if (options->stats) {
  • branches/tap_branches/ppStack/src/ppStackCombinePrepare.c

    r23576 r27838  
    1010#include "ppStackLoop.h"
    1111
    12 bool ppStackCombinePrepare(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config)
     12bool ppStackCombinePrepare(const char *outName, const char *expName,
     13                           ppStackFileList files, ppStackThreadData *stack,
     14                           ppStackOptions *options, pmConfig *config)
    1315{
    1416    psAssert(stack, "Require stack");
     
    2022    ppStackThread *thread = stack->threads->data[0]; // Representative thread
    2123    if (!pmReadoutStackSetOutputSize(&col0, &row0, &numCols, &numRows, thread->readouts)) {
    22         psError(PS_ERR_UNKNOWN, false, "problem setting output readout size.");
     24        psError(PPSTACK_ERR_ARGUMENTS, false, "problem setting output readout size.");
    2325        return false;
    2426    }
    2527
    2628    pmFPAfileActivate(config->files, false, NULL);
    27     ppStackFileActivation(config, PPSTACK_FILES_COMBINE, true);
     29    ppStackFileActivation(config, files, true);
    2830    pmFPAview *view = ppStackFilesIterateDown(config); // View to readout
    2931    if (!view) {
     
    3133    }
    3234
    33     pmCell *outCell = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT"); // Output cell
    34     options->outRO = pmReadoutAlloc(outCell); // Output readout
     35    pmCell *cell = pmFPAfileThisCell(config->files, view, outName); // Output cell
     36    options->outRO = pmReadoutAlloc(cell); // Output readout
     37
     38    pmCell *expCell = pmFPAfileThisCell(config->files, view, expName); // Exposure cell
     39    options->expRO = pmReadoutAlloc(expCell); // Output readout
     40
    3541    psFree(view);
    3642
     
    3945    psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad
    4046    psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
     47
    4148    if (!pmReadoutStackDefineOutput(options->outRO, col0, row0, numCols, numRows, true, true, maskBad)) {
    42         psError(PS_ERR_UNKNOWN, false, "Unable to prepare output.");
     49        psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to prepare output.");
     50        return false;
     51    }
     52
     53    if (!pmReadoutStackDefineOutput(options->expRO, col0, row0, numCols, numRows, true, true, 0)) {
     54        psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to prepare output.");
    4355        return false;
    4456    }
  • branches/tap_branches/ppStack/src/ppStackConvolve.c

    r23602 r27838  
    99#include "ppStack.h"
    1010#include "ppStackLoop.h"
     11
     12//#define TESTING
     13
    1114
    1215// Update the value of a concept
     
    3942    options->weightings = psVectorAlloc(num, PS_TYPE_F32); // Combination weightings for images (1/noise^2)
    4043    psVectorInit(options->weightings, 0.0);
    41     options->covariances = psArrayAlloc(num); // Covariance matrices
     44    options->origCovars = psArrayAlloc(num);
     45    options->convCovars = psArrayAlloc(num); // Covariance matrices
     46
     47    psVector *renorms = psVectorAlloc(num, PS_TYPE_F32); // Renormalisation values for variances
     48    psVectorInit(renorms, NAN);
    4249
    4350    psList *fpaList = psListAlloc(NULL); // List of input FPAs, for concept averaging
     
    5259        pmFPAfileActivate(config->files, false, NULL);
    5360        ppStackFileActivationSingle(config, PPSTACK_FILES_CONVOLVE, true, i);
     61        if (options->convolve) {
     62            // XXX PPSTACK.CONV.KERNEL not defined unless convolve
     63            // pmFPAfileActivate(config->files, true, "PPSTACK.CONV.KERNEL");
     64            pmFPAfileActivateSingle(config->files, true, "PPSTACK.CONV.KERNEL", i); // Activated file
     65        }
     66
    5467        pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", i); // File of interest
    5568        pmFPAview *view = ppStackFilesIterateDown(config);
     
    6982        } else if (options->numCols != readout->image->numCols ||
    7083                   options->numRows != readout->image->numRows) {
    71             psError(PS_ERR_UNKNOWN, true, "Sizes of input images don't match: %dx%d vs %dx%d",
     84            psError(PPSTACK_ERR_ARGUMENTS, true, "Sizes of input images don't match: %dx%d vs %dx%d",
    7285                    readout->image->numCols, readout->image->numRows, options->numCols, options->numRows);
    7386            psFree(rng);
     
    7992        // Background subtraction, scaling and normalisation is performed automatically by the image matching
    8093        psTimerStart("PPSTACK_MATCH");
     94        options->origCovars->data[i] = psMemIncrRefCounter(readout->covariance);
    8195        if (!ppStackMatch(readout, options, i, config)) {
    82             psErrorStackPrint(stderr, "Unable to match image %d --- ignoring.", i);
    83             options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_MATCH;
    84             psErrorClear();
    85             continue;
    86         }
    87         options->covariances->data[i] = psMemIncrRefCounter(readout->covariance);
     96            // XXX many things can cause a failure of ppStackMatch -- should some be handled differently?
     97            psErrorCode error = psErrorCodeLast(); // Error code
     98            switch (error) {
     99                // Fatal errors
     100              case PM_ERR_CONFIG:
     101              case PPSTACK_ERR_CONFIG:
     102              case PPSTACK_ERR_IO:
     103                psError(error, false, "Unable to match image %d due to fatal error.", i);
     104                return false;
     105                // Non-fatal errors
     106              case PM_ERR_STAMPS:
     107              case PM_ERR_SMALL_AREA:
     108              case PPSTACK_ERR_DATA:
     109              default:
     110                psErrorStackPrint(stderr, "Unable to match image %d --- ignoring.", i);
     111                options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_MATCH;
     112                psErrorClear();
     113                continue;
     114            }
     115        }
     116        options->convCovars->data[i] = psMemIncrRefCounter(readout->covariance);
     117
     118        float renorm = psMetadataLookupF32(NULL, readout->analysis, PM_READOUT_ANALYSIS_RENORM);
     119        if (!isfinite(renorm)) {
     120            renorm = 1.0;
     121        }
     122        renorms->data.F32[i] = renorm;
    88123
    89124        if (options->stats) {
     
    114149        pmHDU *hdu = readout->parent->parent->parent->hdu; // HDU for convolved image
    115150        assert(hdu);
    116         ppStackWriteImage(options->imageNames->data[i], hdu->header, readout->image, config);
     151        if (!ppStackWriteImage(options->convImages->data[i], hdu->header, readout->image, config)) {
     152            psError(PPSTACK_ERR_IO, false, "Unable to write convolved image %d", i);
     153            psFree(fpaList);
     154            psFree(cellList);
     155            psFree(rng);
     156            return false;
     157        }
    117158        psMetadata *maskHeader = psMetadataCopy(NULL, hdu->header); // Copy of header, for mask
    118159        pmConfigMaskWriteHeader(config, maskHeader);
    119         ppStackWriteImage(options->maskNames->data[i], maskHeader, readout->mask, config);
     160        if (!ppStackWriteImage(options->convMasks->data[i], maskHeader, readout->mask, config)) {
     161            psError(PPSTACK_ERR_IO, false, "Unable to write convolved mask %d", i);
     162            psFree(fpaList);
     163            psFree(cellList);
     164            psFree(rng);
     165            psFree(maskHeader);
     166            return false;
     167        }
    120168        psFree(maskHeader);
    121         psImageCovarianceTransfer(readout->variance, readout->covariance);
    122         ppStackWriteImage(options->varianceNames->data[i], hdu->header, readout->variance, config);
     169        if (!ppStackWriteImage(options->convVariances->data[i], hdu->header, readout->variance, config)) {
     170            psError(PPSTACK_ERR_IO, false, "Unable to write convolved variance %d", i);
     171            psFree(fpaList);
     172            psFree(cellList);
     173            psFree(rng);
     174            return false;
     175        }
    123176#ifdef TESTING
    124177        {
     
    129182            psFree(name);
    130183        }
     184        {
     185            int numCols = readout->image->numCols, numRows = readout->image->numRows;
     186            psImage *sn = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     187            for (int y = 0; y < numRows; y++) {
     188                for (int x = 0; x < numCols; x++) {
     189                    sn->data.F32[y][x] = readout->image->data.F32[y][x] /
     190                        sqrtf(readout->variance->data.F32[y][x]);
     191                }
     192            }
     193            psString name = NULL;
     194            psStringAppend(&name, "signoise_%d.fits", i);
     195            ppStackWriteImage(name, hdu->header, sn, config);
     196            psFree(name);
     197            psFree(sn);
     198        }
    131199#endif
    132200
     
    136204        psListAdd(fpaList, PS_LIST_TAIL, inCell->parent->parent);
    137205
     206        // Correct ZP
     207        if (options->matchZPs) {
     208            // I think I need to take off the exposure time because we're going to set the new exposure time
     209            psMetadataItem *zpItem = psMetadataLookup(inCell->parent->parent->concepts, "FPA.ZP");
     210            zpItem->data.F32 += options->norm->data.F32[i] + 2.5*log10(options->sumExposure);
     211
     212            psMetadataItem *expItem = psMetadataLookup(inCell->parent->parent->concepts, "FPA.EXPOSURE");
     213            expItem->data.F32 = options->sumExposure;
     214
     215            expItem = psMetadataLookup(inCell->concepts, "CELL.EXPOSURE");
     216            expItem->data.F32 = options->sumExposure;
     217        }
     218
    138219        options->cells->data[i] = psMemIncrRefCounter(inCell);
    139220        if (!ppStackFilesIterateUp(config)) {
     
    149230    psFree(rng);
    150231
    151     psFree(options->norm); options->norm = NULL;
    152232    psFree(options->sourceLists); options->sourceLists = NULL;
    153233    psFree(options->psf); options->psf = NULL;
     
    155235
    156236    if (numGood == 0) {
    157         psError(PS_ERR_UNKNOWN, false, "No good images to combine.");
     237        psError(PPSTACK_ERR_REJECTED, false, "No good images to combine.");
    158238        psFree(fpaList);
    159239        psFree(cellList);
     
    167247        pmFPAview view;                 // View for output
    168248        view.chip = view.cell = view.readout = 0;
     249
    169250        pmCell *outCell = pmFPAfileThisCell(config->files, &view, "PPSTACK.OUTPUT"); // Output cell
    170251        pmFPA *outFPA = outCell->parent->parent; // Output FPA
     252
     253        pmCell *unconvCell = pmFPAfileThisCell(config->files, &view, "PPSTACK.UNCONV"); // Unconvolved cell
     254        pmFPA *unconvFPA = unconvCell->parent->parent;                                  // Unconvolved FPA
     255
    171256        pmConceptsAverageFPAs(outFPA, fpaList);
    172257        pmConceptsAverageCells(outCell, cellList, NULL, NULL, true);
     258
     259        pmConceptsAverageFPAs(unconvFPA, fpaList);
     260        pmConceptsAverageCells(unconvCell, cellList, NULL, NULL, true);
     261
    173262        psFree(fpaList);
    174263        psFree(cellList);
     
    177266        UPDATE_CONCEPT(outCell, "CELL.EXPOSURE", options->sumExposure);
    178267        UPDATE_CONCEPT(outCell, "CELL.DARKTIME", NAN);
     268        UPDATE_CONCEPT(outFPA,  "FPA.ZP",        options->zp);
     269
     270        UPDATE_CONCEPT(unconvFPA,  "FPA.EXPOSURE",  options->sumExposure);
     271        UPDATE_CONCEPT(unconvCell, "CELL.EXPOSURE", options->sumExposure);
     272        UPDATE_CONCEPT(unconvCell, "CELL.DARKTIME", NAN);
     273        UPDATE_CONCEPT(unconvFPA,  "FPA.ZP",        options->zp);
    179274    }
    180275
     
    191286        assert(values->n == numGood);
    192287        if (!psVectorSortInPlace(values)) {
    193             psError(PS_ERR_UNKNOWN, false, "Unable to sort vector.");
     288            psError(PPSTACK_ERR_PROG, false, "Unable to sort vector.");
    194289            psFree(values);
    195290            return false;
     
    211306            numGood = 0;                    // Number of good images
    212307            for (int i = 0; i < num; i++) {
    213               if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_ALL) {
     308                if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_ALL) {
    214309                    continue;
    215310                }
     
    229324
    230325    if (numGood == 0) {
    231         psError(PS_ERR_UNKNOWN, false, "No good images to combine.");
     326        psError(PPSTACK_ERR_REJECTED, false, "No good images to combine.");
    232327        return false;
    233328    }
     329
     330    // Correct chi^2 for renormalisation
     331    psBinaryOp(options->matchChi2, options->matchChi2, "/", renorms);
     332    for (int i = 0; i < num; i++) {
     333        psLogMsg("ppStack", PS_LOG_INFO, "Additional variance for image %d: %f\n",
     334                 i, options->matchChi2->data.F32[i]);
     335    }
     336    psFree(renorms);
    234337
    235338    return true;
  • branches/tap_branches/ppStack/src/ppStackFiles.c

    r23357 r27838  
    1717
    1818/// Files required for the convolution
    19 static char *filesConvolve[] = { "PPSTACK.INPUT", "PPSTACK.INPUT.MASK", "PPSTACK.INPUT.VARIANCE",
    20                                  "PPSTACK.CONV.KERNEL", NULL };
    21 
    22 /// Output files for the combination
    23 static char *filesCombine[] = { "PPSTACK.OUTPUT", "PPSTACK.OUTPUT.MASK", "PPSTACK.OUTPUT.VARIANCE",
    24                                 "PPSTACK.OUTPUT.JPEG1", "PPSTACK.OUTPUT.JPEG2", NULL };
     19static char *filesConvolve[] = { "PPSTACK.INPUT", "PPSTACK.INPUT.MASK", "PPSTACK.INPUT.VARIANCE", NULL };
     20
     21//                                 "PPSTACK.CONV.KERNEL", NULL };
     22
     23/// Regular (convolved) stack files
     24static char *filesStack[] = { "PPSTACK.OUTPUT", "PPSTACK.OUTPUT.MASK", "PPSTACK.OUTPUT.VARIANCE",
     25                              "PPSTACK.OUTPUT.EXP", "PPSTACK.OUTPUT.EXPNUM", "PPSTACK.OUTPUT.EXPWT",
     26                              "PPSTACK.OUTPUT.JPEG1", "PPSTACK.OUTPUT.JPEG2",
     27                              NULL };
     28/// Unconvolved stack files
     29static char *filesUnconv[] = { "PPSTACK.UNCONV", "PPSTACK.UNCONV.MASK", "PPSTACK.UNCONV.VARIANCE",
     30                               "PPSTACK.UNCONV.EXP", "PPSTACK.UNCONV.EXPNUM", "PPSTACK.UNCONV.EXPWT",
     31                               NULL };
    2532
    2633/// Files for photometry
     
    3542      case PPSTACK_FILES_PREPARE:  return filesPrepare;
    3643      case PPSTACK_FILES_CONVOLVE: return filesConvolve;
    37       case PPSTACK_FILES_COMBINE:  return filesCombine;
     44      case PPSTACK_FILES_STACK:    return filesStack;
     45      case PPSTACK_FILES_UNCONV:   return filesUnconv;
    3846      case PPSTACK_FILES_PHOT:     return filesPhot;
    3947      default:
     
    113121    pmFPAview *view = pmFPAviewAlloc(0);// Pointer into FPA hierarchy
    114122    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
     123        psError(PPSTACK_ERR_IO, false, "File checks failed.");
    115124        return NULL;
    116125    }
    117126    view->chip = 0;
    118127    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
     128        psError(PPSTACK_ERR_IO, false, "File checks failed.");
    119129        return NULL;
    120130    }
    121131    view->cell = 0;
    122132    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
     133        psError(PPSTACK_ERR_IO, false, "File checks failed.");
    123134        return NULL;
    124135    }
    125136    view->readout = 0;
    126137    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
     138        psError(PPSTACK_ERR_IO, false, "File checks failed.");
    127139        return NULL;
    128140    }
     
    139151    view->chip = view->cell = view->readout = 0;
    140152    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
     153        psError(PPSTACK_ERR_IO, false, "File checks failed.");
    141154        return false;
    142155    }
    143156    view->readout = -1;
    144157    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
     158        psError(PPSTACK_ERR_IO, false, "File checks failed.");
    145159        return false;
    146160    }
    147161    view->cell = -1;
    148162    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
     163        psError(PPSTACK_ERR_IO, false, "File checks failed.");
    149164        return false;
    150165    }
    151166    view->chip = -1;
    152167    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
     168        psError(PPSTACK_ERR_IO, false, "File checks failed.");
    153169        return false;
    154170    }
     
    170186    psFits *fits = psFitsOpen(resolved, "w");
    171187    if (!fits) {
    172         psError(PS_ERR_IO, false, "Unable to open FITS file %s to write image.", resolved);
     188        psError(PPSTACK_ERR_IO, false, "Unable to open FITS file %s to write image.", resolved);
    173189        psFree(resolved);
    174190        return false;
    175191    }
    176192    if (!psFitsWriteImage(fits, header, image, 0, NULL)) {
    177         psError(PS_ERR_IO, false, "Unable to write FITS image %s.", resolved);
     193        psError(PPSTACK_ERR_IO, false, "Unable to write FITS image %s.", resolved);
    178194        psFitsClose(fits);
    179195        psFree(resolved);
    180196        return false;
    181197    }
    182     psFitsClose(fits);
     198    if (!psFitsClose(fits)) {
     199        psError(PPSTACK_ERR_IO, false, "Unable to close FITS image %s.", resolved);
     200        psFree(resolved);
     201        return false;
     202    }
    183203    psFree(resolved);
    184204    return true;
  • branches/tap_branches/ppStack/src/ppStackFinish.c

    r25847 r27838  
    44
    55#include <stdio.h>
     6#include <unistd.h>
    67#include <pslib.h>
    78#include <psmodules.h>
    8 #include <ppStats.h>
     9#include <psphot.h>
    910
    1011#include "ppStack.h"
     
    2122    psAssert(recipe, "We've thrown an error on this before.");
    2223
    23     // Statistics on output
    24     if (options->stats) {
    25         psTrace("ppStack", 1, "Gathering statistics on stacked image....\n");
    26         psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits for bad
    27         psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
     24    bool mdok;                          // Status of MD lookup
     25    bool tempDelete = psMetadataLookupBool(&mdok, recipe, "TEMP.DELETE"); // Delete temporary files?
    2826
    29         pmFPAview *view = pmFPAviewAlloc(0); // View to readout
    30         view->chip = view->cell = view->readout = 0;
     27    // Delete temporary images
     28    if (tempDelete && options->convolve) {
     29        for (int i = 0; i < options->num; i++) {
     30            if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
     31                continue;
     32            }
    3133
    32         ppStatsFPA(options->stats, options->outRO->parent->parent->parent, view, maskBad, config);
    33 
    34         psFree(view);
    35     }
    36 
    37     ppStackMemDump("stats");
    38 
    39     psFree(options->outRO); options->outRO = NULL;
    40 
    41     // Write out the output files
    42     if (!ppStackFilesIterateUp(config)) {
    43         return false;
     34            psString imageResolved = pmConfigConvertFilename(options->convImages->data[i],
     35                                                             config, false, false);
     36            psString maskResolved = pmConfigConvertFilename(options->convMasks->data[i],
     37                                                            config, false, false);
     38            psString varianceResolved = pmConfigConvertFilename(options->convVariances->data[i],
     39                                                                config, false, false);
     40            if (unlink(imageResolved) == -1 || unlink(maskResolved) == -1 ||
     41                unlink(varianceResolved) == -1) {
     42                psWarning("Unable to delete temporary files for image %d", i);
     43            }
     44            psFree(imageResolved);
     45            psFree(maskResolved);
     46            psFree(varianceResolved);
     47        }
    4448    }
    4549
    4650
    47     // Write out summary statistics
    48     if (options->stats) {
    49         psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_STACK", 0,
    50                          "Total time", psTimerClear("PPSTACK_TOTAL"));
     51    return true;
     52}
    5153
    52         const char *statsMDC = psMetadataConfigFormat(options->stats);
    53         if (!statsMDC || strlen(statsMDC) == 0) {
    54             psError(PS_ERR_IO, false, "Unable to get statistics MDC file.\n");
    55         } else {
    56             fprintf(options->statsFile, "%s", statsMDC);
    57         }
    58         psFree((void *)statsMDC);
    59         fclose(options->statsFile); options->statsFile = NULL;
    60         pmConfigRunFilenameAddWrite(config, "STATS", psMetadataLookupStr(NULL, config->arguments, "STATS"));
     54
     55psExit ppStackExitCode(psExit exitValue)
     56{
     57    if (exitValue != PS_EXIT_SUCCESS) {
     58        return exitValue;
    6159    }
    6260
    63 
    64     // Dump configuration
    65     bool mdok;                          // Status of MD lookup
    66     psString dump = psMetadataLookupStr(&mdok, config->arguments, "DUMP_CONFIG"); // File for config
    67     if (dump) {
    68         if (!pmConfigDump(config, dump)) {
    69             psError(PS_ERR_IO, false, "Unable to dump configuration.");
    70             return false;
     61    psErrorCode errorCode = psErrorCodeLast(); // Error code
     62    if (errorCode != PS_ERR_NONE) {
     63        psErrorStackPrint(stderr, "Unable to perform stack.");
     64        switch (errorCode) {
     65          case PPSTACK_ERR_UNKNOWN:
     66          case PS_ERR_UNKNOWN:
     67            psLogMsg("ppStack", PS_LOG_WARN, "Unknown error code: %x", errorCode);
     68            exitValue = PS_EXIT_UNKNOWN_ERROR;
     69            break;
     70          case PS_ERR_IO:
     71          case PS_ERR_DB_CLIENT:
     72          case PS_ERR_DB_SERVER:
     73          case PS_ERR_BAD_FITS:
     74          case PS_ERR_OS_CALL_FAILED:
     75          case PM_ERR_SYS:
     76          case PPSTACK_ERR_IO:
     77            psLogMsg("ppStack", PS_LOG_WARN, "I/O error code: %x", errorCode);
     78            exitValue = PS_EXIT_SYS_ERROR;
     79            break;
     80          case PS_ERR_BAD_PARAMETER_VALUE:
     81          case PS_ERR_BAD_PARAMETER_TYPE:
     82          case PS_ERR_BAD_PARAMETER_NULL:
     83          case PS_ERR_BAD_PARAMETER_SIZE:
     84          case PPSTACK_ERR_ARGUMENTS:
     85          case PPSTACK_ERR_CONFIG:
     86            psLogMsg("ppStack", PS_LOG_WARN, "Configuration error code: %x", errorCode);
     87            exitValue = PS_EXIT_CONFIG_ERROR;
     88            break;
     89          case PPSTACK_ERR_PSF:
     90          case PSPHOT_ERR_PSF:
     91          case PM_ERR_STAMPS:
     92          case PM_ERR_SMALL_AREA:
     93          case PPSTACK_ERR_REJECTED:
     94          case PPSTACK_ERR_DATA:
     95            psLogMsg("ppStack", PS_LOG_WARN, "Data error code: %x", errorCode);
     96            exitValue = PS_EXIT_DATA_ERROR;
     97            break;
     98          case PS_ERR_UNEXPECTED_NULL:
     99          case PS_ERR_PROGRAMMING:
     100          case PPSTACK_ERR_NOT_IMPLEMENTED:
     101          case PPSTACK_ERR_PROG:
     102            psLogMsg("ppStack", PS_LOG_WARN, "Programming error code: %x", errorCode);
     103            exitValue = PS_EXIT_PROG_ERROR;
     104            break;
     105          default:
     106            // It's a programming error if we're not dealing with the error correctly
     107            psLogMsg("ppStack", PS_LOG_WARN, "Unrecognised error code: %x", errorCode);
     108            exitValue = PS_EXIT_PROG_ERROR;
     109            break;
    71110        }
    72111    }
    73 
    74     return true;
     112    return exitValue;
    75113}
  • branches/tap_branches/ppStack/src/ppStackLoop.c

    r25738 r27838  
    1010#include "ppStackLoop.h"
    1111
    12 bool ppStackLoop(pmConfig *config)
     12/// Print a summary of the inputs, and return the number of good inputs
     13static int stackSummary(const ppStackOptions *options, // Stack options, with input mask
     14                        const char *place              // Place in code
     15    )
     16{
     17    int numGood = 0;                // Number of good inputs
     18    psString summary = NULL;        // Summary of images
     19    for (int i = 0; i < options->num; i++) {
     20        psString reason = NULL;         // Reason for rejecting
     21        if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] == 0) {
     22            psStringAppend(&reason, " Good.");
     23            numGood++;
     24        } else {
     25            if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_CAL) {
     26                psStringAppend(&reason, " Calibration failed.");
     27            }
     28            if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_PSF) {
     29                psStringAppend(&reason, " PSF measurement failed.");
     30            }
     31            if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_MATCH) {
     32                psStringAppend(&reason, " PSF matching failed.");
     33            }
     34            if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_CHI2) {
     35                psStringAppend(&reason, " PSF matching chi^2 deviant.");
     36            }
     37            if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_REJECT) {
     38                psStringAppend(&reason, " Rejection exceeded threshold.");
     39            }
     40        }
     41        psStringAppend(&summary, "Image %d: %s\n", i, reason);
     42        psFree(reason);
     43    }
     44    psLogMsg("ppStack", PS_LOG_INFO, "Summary of images for %s:\n%s", place, summary);
     45    psFree(summary);
     46
     47    return numGood;
     48}
     49
     50
     51
     52bool ppStackLoop(pmConfig *config, ppStackOptions *options)
    1353{
    1454    assert(config);
     
    1656    psTimerStart("PPSTACK_TOTAL");
    1757    psTimerStart("PPSTACK_STEPS");
    18 
    19     ppStackOptions *options = ppStackOptionsAlloc(); // Options for stacking
    2058
    2159    // Setup
    2260    psTrace("ppStack", 1, "Setup....\n");
    2361    if (!ppStackSetup(options, config)) {
    24         psError(PS_ERR_UNKNOWN, false, "Unable to setup.");
    25         psFree(options);
     62        psError(psErrorCodeLast(), false, "Unable to setup.");
    2663        return false;
    2764    }
     
    3370    psTrace("ppStack", 1, "Preparation for stacking: merging sources, determining target PSF....\n");
    3471    if (!ppStackPrepare(options, config)) {
    35         psError(PS_ERR_UNKNOWN, false, "Unable to prepare for stacking.");
    36         psFree(options);
     72        psError(psErrorCodeLast(), false, "Unable to prepare for stacking.");
    3773        return false;
    3874    }
     
    4076             psTimerClear("PPSTACK_STEPS"));
    4177    ppStackMemDump("prepare");
    42 
     78    if (options->quality) {
     79        // Can't do anything else
     80        return true;
     81    }
    4382
    4483    // Convolve inputs
    4584    psTrace("ppStack", 1, "Convolving inputs to target PSF....\n");
    4685    if (!ppStackConvolve(options, config)) {
    47         psError(PS_ERR_UNKNOWN, false, "Unable to convolve images.");
    48         psFree(options);
     86        psError(psErrorCodeLast(), false, "Unable to convolve images.");
    4987        return false;
    5088    }
     
    5391    ppStackMemDump("convolve");
    5492
     93    // Ensure sufficient inputs
     94    {
     95        int numGood = stackSummary(options, "initial combination");
     96        psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
     97        bool safe = psMetadataLookupBool(NULL, recipe, "SAFE"); // Be safe when combining
     98        if (safe && numGood <= 1) {
     99            psError(PPSTACK_ERR_REJECTED, true, "Insufficient inputs for combination with safety on");
     100            return false;
     101        }
     102    }
    55103
    56104    // Start threading
    57105    ppStackThreadInit();
    58     ppStackThreadData *stack = ppStackThreadDataSetup(options, config);
     106    ppStackThreadData *stack = ppStackThreadDataSetup(options, config, true);
    59107    if (!stack) {
    60         psError(PS_ERR_IO, false, "Unable to initialise stack threads.");
    61         psFree(options);
    62         return false;
    63     }
    64     psFree(options->cells); options->cells = NULL;
     108        psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
     109        return false;
     110    }
    65111
    66112    // Prepare for combination
    67     if (!ppStackCombinePrepare(stack, options, config)) {
    68         psError(PS_ERR_UNKNOWN, false, "Unable to prepare for combination.");
    69         psFree(stack);
    70         psFree(options);
     113    if (!ppStackCombinePrepare("PPSTACK.OUTPUT", "PPSTACK.OUTPUT.EXP", PPSTACK_FILES_STACK,
     114                               stack, options, config)) {
     115        psError(psErrorCodeLast(), false, "Unable to prepare for combination.");
     116        psFree(stack);
    71117        return false;
    72118    }
     
    75121    psTrace("ppStack", 1, "Initial stack of convolved images....\n");
    76122    if (!ppStackCombineInitial(stack, options, config)) {
    77         psError(PS_ERR_UNKNOWN, false, "Unable to perform initial combination.");
    78         psFree(stack);
    79         psFree(options);
    80         return false;
    81     }
    82     ppStackMemDump("convolve");
     123        psError(psErrorCodeLast(), false, "Unable to perform initial combination.");
     124        psFree(stack);
     125        return false;
     126    }
     127    ppStackMemDump("initial");
    83128    psLogMsg("ppStack", PS_LOG_INFO, "Stage 3: Make Initial Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
    84129
     130    // Done with stack inputs for now
     131    for (int i = 0; i < options->num; i++) {
     132        pmCellFreeData(options->cells->data[i]);
     133    }
     134    psFree(stack);
    85135
    86136    // Pixel rejection
    87137    psTrace("ppStack", 1, "Reject pixels....\n");
    88138    if (!ppStackReject(options, config)) {
    89         psError(PS_ERR_UNKNOWN, false, "Unable to reject pixels.");
    90         psFree(stack);
    91         psFree(options);
     139        psError(psErrorCodeLast(), false, "Unable to reject pixels.");
     140        psFree(stack);
    92141        return false;
    93142    }
    94143    psLogMsg("ppStack", PS_LOG_INFO, "Stage 4: Pixel Rejection: %f sec", psTimerClear("PPSTACK_STEPS"));
    95     ppStackMemDump("reject");
    96 
     144
     145    // Check inputs
     146    {
     147        int numGood = stackSummary(options, "final combination");
     148        if (numGood <= 0) {
     149            psError(PPSTACK_ERR_REJECTED, true, "Insufficient inputs for combination");
     150            return false;
     151        }
     152    }
     153
     154    stack = ppStackThreadDataSetup(options, config, true);
     155    if (!stack) {
     156        psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
     157        return false;
     158    }
    97159
    98160    // Final combination
    99161    psTrace("ppStack", 2, "Final stack of convolved images....\n");
    100     if (!ppStackCombineFinal(stack, options, config)) {
    101         psError(PS_ERR_UNKNOWN, false, "Unable to perform final combination.");
    102         psFree(stack);
    103         psFree(options);
     162    if (!ppStackCombineFinal(stack, options->convCovars, options, config, false, false, true)) {
     163        psError(psErrorCodeLast(), false, "Unable to perform final combination.");
     164        psFree(stack);
    104165        return false;
    105166    }
     
    107168    ppStackMemDump("final");
    108169
     170    // Photometry
     171    psTrace("ppStack", 1, "Photometering stacked image....\n");
     172    if (!ppStackPhotometry(options, config)) {
     173        psError(psErrorCodeLast(), false, "Unable to perform photometry.");
     174        return false;
     175    }
     176    psLogMsg("ppStack", PS_LOG_INFO, "Stage 6: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS"));
     177    ppStackMemDump("photometry");
    109178
    110179    // Clean up
    111180    psTrace("ppStack", 2, "Cleaning up after combination....\n");
    112181    if (!ppStackCleanup(stack, options, config)) {
    113         psError(PS_ERR_UNKNOWN, false, "Unable to clean up.");
    114         psFree(stack);
    115         psFree(options);
    116         return false;
    117     }
    118     psLogMsg("ppStack", PS_LOG_INFO, "Stage 6: WCS & JPEGS: %f sec", psTimerClear("PPSTACK_STEPS"));
     182        psError(psErrorCodeLast(), false, "Unable to clean up.");
     183        psFree(stack);
     184        return false;
     185    }
     186    for (int i = 0; i < options->num; i++) {
     187        pmCellFreeData(options->cells->data[i]);
     188    }
     189    psFree(stack);
     190    psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: Cleanup, WCS & JPEGS: %f sec", psTimerClear("PPSTACK_STEPS"));
    119191    ppStackMemDump("cleanup");
    120192
    121     psFree(stack);
    122 
    123 
    124     // Photometry
    125     psTrace("ppStack", 1, "Photometering stacked image....\n");
    126     if (!ppStackPhotometry(options, config)) {
    127         psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry.");
    128         psFree(options);
    129         return false;
    130     }
    131     psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS"));
    132     ppStackMemDump("photometry");
    133 
     193#if 1
     194    // Unconvolved stack --- it's cheap to calculate, compared to everything else!
     195    if (options->convolve) {
     196        // Start threading
     197        ppStackThreadData *stack = ppStackThreadDataSetup(options, config, false);
     198        if (!stack) {
     199            psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
     200            return false;
     201        }
     202
     203        // Prepare for combination
     204        if (!ppStackCombinePrepare("PPSTACK.UNCONV", "PPSTACK.UNCONV.EXP", PPSTACK_FILES_UNCONV,
     205                                   stack, options, config)) {
     206            psError(psErrorCodeLast(), false, "Unable to prepare for combination.");
     207            psFree(stack);
     208            return false;
     209        }
     210
     211        psTrace("ppStack", 2, "Stack of unconvolved images....\n");
     212        if (!ppStackCombineFinal(stack, options->origCovars, options, config,
     213                                 false, true, false)) {
     214            psError(psErrorCodeLast(), false, "Unable to perform unconvolved combination.");
     215            psFree(stack);
     216            return false;
     217        }
     218        psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Unconvolved Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
     219        ppStackMemDump("unconv");
     220
     221        if (!ppStackFilesIterateUp(config)) {
     222            psError(psErrorCodeLast(), false, "Unable to close files.");
     223            psFree(stack);
     224            return false;
     225        }
     226        ppStackFileActivation(config, PPSTACK_FILES_UNCONV, false);
     227        options->outRO->data_exists = false;
     228        options->outRO->parent->data_exists = false;
     229        options->outRO->parent->parent->data_exists = false;
     230        psFree(options->outRO);
     231        options->outRO = NULL;
     232        options->expRO->data_exists = false;
     233        options->expRO->parent->data_exists = false;
     234        options->expRO->parent->parent->data_exists = false;
     235        psFree(options->expRO);
     236        options->expRO = NULL;
     237
     238        for (int i = 0; i < options->num; i++) {
     239            pmCellFreeData(options->cells->data[i]);
     240        }
     241        psFree(stack);
     242    }
     243    psFree(options->cells); options->cells = NULL;
     244#endif
    134245
    135246    // Finish up
    136247    psTrace("ppStack", 1, "Finishing up....\n");
    137248    if (!ppStackFinish(options, config)) {
    138         psError(PS_ERR_UNKNOWN, false, "Unable to finish up.");
    139         psFree(options);
    140         return false;
    141     }
    142     psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Final output: %f sec", psTimerClear("PPSTACK_STEPS"));
     249        psError(psErrorCodeLast(), false, "Unable to finish up.");
     250        return false;
     251    }
    143252    ppStackMemDump("finish");
    144253
    145     psFree(options);
    146254    return true;
    147255}
  • branches/tap_branches/ppStack/src/ppStackLoop.h

    r23576 r27838  
    77#include "ppStackOptions.h"
    88#include "ppStackThread.h"
     9#include "ppStack.h"
    910
    1011
    1112// Loop over the inputs, doing the combination
    1213bool ppStackLoop(
    13     pmConfig *config                    // Configuration
     14    pmConfig *config,                    // Configuration
     15    ppStackOptions *options             // Options for stacking
    1416    );
    1517
     
    3638// Prepare for combination
    3739bool ppStackCombinePrepare(
     40    const char *outName,                // Name of output file
     41    const char *expName,                // Name of exposure file
     42    ppStackFileList files,              // Files of interest
    3843    ppStackThreadData *stack,           // Stack
    3944    ppStackOptions *options,            // Options
     
    5762bool ppStackCombineFinal(
    5863    ppStackThreadData *stack,           // Stack
     64    psArray *covariances,               // Covariances
    5965    ppStackOptions *options,            // Options
    60     pmConfig *config                    // Configuration
     66    pmConfig *config,                   // Configuration
     67    bool safe,                          // Allow safe combination?
     68    bool norm,                          // Normalise images?
     69    bool grow                           // Grow rejection masks?
    6170    );
    6271
  • branches/tap_branches/ppStack/src/ppStackMatch.c

    r25467 r27838  
    1818#define COVAR_FRAC 0.01                 // Truncation fraction for covariance matrix
    1919
    20 //#define TESTING                         // Enable debugging output
     20// #define TESTING                         // Enable debugging output
    2121
    2222#ifdef TESTING
     
    3131    psFree(resolved);
    3232    if (!fits) {
    33         psError(PS_ERR_IO, false, "Unable to open previously produced image: %s", name);
     33        psError(PPSTACK_ERR_IO, false, "Unable to open previously produced image: %s", name);
    3434        return false;
    3535    }
    3636    psImage *image = psFitsReadImage(fits, psRegionSet(0,0,0,0), 0); // Image of interest
    3737    if (!image) {
    38         psError(PS_ERR_IO, false, "Unable to read previously produced image: %s", name);
     38        psError(PPSTACK_ERR_IO, false, "Unable to read previously produced image: %s", name);
    3939        psFitsClose(fits);
    4040        return false;
     
    115115    psFree(coords);
    116116    psFree(tree);
     117    psFree(x);
     118    psFree(y);
    117119
    118120    psLogMsg("ppStack", PS_LOG_INFO, "Filtered out %d of %d sources", numFiltered, numGood);
     
    144146    psMetadataAddU8(psphotRecipe, PS_LIST_TAIL, "MASK.PSPHOT", PS_META_REPLACE, "user-defined mask", maskBad);
    145147
    146     psImage *binned = psphotBackgroundModel(ro, config); // Binned background model
     148    psImage *binned = psphotModelBackgroundReadoutNoFile(ro, config); // Binned background model
    147149    psImageBinning *binning = psMetadataLookupPtr(NULL, ro->analysis,
    148150                                                  "PSPHOT.BACKGROUND.BINNING"); // Binning for model
     
    150152    psImage *unbinned = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Unbinned background model
    151153    if (!psImageUnbin(unbinned, binned, binning)) {
    152         psError(PS_ERR_UNKNOWN, false, "Unable to unbin background model");
     154        psError(PPSTACK_ERR_DATA, false, "Unable to unbin background model");
     155        psFree(binned);
    153156        psFree(unbinned);
    154157        return NULL;
    155158    }
    156 
    157     // XXX should these really be here?? (probably not...)
    158     // pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL");
    159     // pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL.STDEV");
    160 
    161      return unbinned;
     159    psFree(binned);
     160
     161    return unbinned;
    162162}
    163163
     
    167167    )
    168168{
     169#if 1
    169170    bool mdok; // Status of metadata lookups
    170171
     
    176177    int num = psMetadataLookupS32(&mdok, recipe, "RENORM.NUM");
    177178    if (!mdok) {
    178         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.NUM is not set in the recipe");
     179        psError(PPSTACK_ERR_CONFIG, true, "RENORM.NUM is not set in the recipe");
    179180        return false;
    180181    }
    181182    float minValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MIN");
    182183    if (!mdok) {
    183         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.MIN is not set in the recipe");
     184        psError(PPSTACK_ERR_CONFIG, true, "RENORM.MIN is not set in the recipe");
    184185        return false;
    185186    }
    186187    float maxValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MAX");
    187188    if (!mdok) {
    188         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.MAX is not set in the recipe");
     189        psError(PPSTACK_ERR_CONFIG, true, "RENORM.MAX is not set in the recipe");
    189190        return false;
    190191    }
     
    192193    psImageMaskType maskBad = pmConfigMaskGet("BLANK", config); // Bits to mask
    193194
     195    psImageCovarianceTransfer(readout->variance, readout->covariance);
    194196    return pmReadoutVarianceRenormalise(readout, maskBad, num, minValid, maxValid);
     197#else
     198    return true;
     199#endif
    195200}
    196201
     
    212217    int size = psMetadataLookupS32(NULL, ppsub, "KERNEL.SIZE"); // Kernel half-size
    213218
    214     psString maskValStr = psMetadataLookupStr(NULL, recipe, "MASK.VAL"); // Name of bits to mask going in
     219    psString maskValStr = psMetadataLookupStr(NULL, ppsub, "MASK.VAL"); // Name of bits to mask going in
    215220    psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch
    216221    psString maskPoorStr = psMetadataLookupStr(NULL, recipe, "MASK.POOR"); // Name of bits to mask for poor
     
    224229
    225230    if (!pmReadoutMaskNonfinite(readout, maskVal)) {
    226         psError(PS_ERR_UNKNOWN, false, "Unable to mask non-finite pixels in readout.");
     231        psError(psErrorCodeLast(), false, "Unable to mask non-finite pixels in readout.");
    227232        return false;
    228233    }
     
    251256            psFree(resolved);
    252257            if (!fits || !pmReadoutReadSubtractionKernels(conv, fits)) {
    253                 psError(PS_ERR_IO, false, "Unable to read previously produced kernel");
     258                psError(PPSTACK_ERR_IO, false, "Unable to read previously produced kernel");
    254259                psFitsClose(fits);
    255260                return false;
     
    257262            psFitsClose(fits);
    258263
    259             if (!readImage(&readout->image, options->imageNames->data[index], config) ||
    260                 !readImage(&readout->mask, options->maskNames->data[index], config) ||
    261                 !readImage(&readout->variance, options->varianceNames->data[index], config)) {
    262                 psError(PS_ERR_IO, false, "Unable to read previously produced image.");
     264            if (!readImage(&readout->image, options->convImages->data[index], config) ||
     265                !readImage(&readout->mask, options->convMasks->data[index], config) ||
     266                !readImage(&readout->variance, options->convVariances->data[index], config)) {
     267                psError(PPSTACK_ERR_IO, false, "Unable to read previously produced image.");
    263268                return false;
    264269            }
     
    269274                                                                PM_SUBTRACTION_ANALYSIS_KERNEL);
    270275
    271             pmSubtractionAnalysis(readout->analysis, NULL, kernels, region,
     276            pmSubtractionAnalysis(conv->analysis, NULL, kernels, region,
    272277                                  readout->image->numCols, readout->image->numRows);
    273278
    274279            psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel
     280            bool oldThreads = psImageCovarianceSetThreads(true);              // Old thread setting
    275281            psKernel *covar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix
     282            psImageCovarianceSetThreads(oldThreads);
    276283            psFree(readout->covariance);
    277284            readout->covariance = covar;
     
    292299            int iter = psMetadataLookupS32(NULL, ppsub, "ITER"); // Rejection iterations
    293300            float rej = psMetadataLookupF32(NULL, ppsub, "REJ"); // Rejection threshold
    294             float sysError = psMetadataLookupF32(NULL, ppsub, "SYS"); // Relative systematic error in kernel
     301            float kernelError = psMetadataLookupF32(NULL, ppsub, "KERNEL.ERR"); // Relative systematic error in kernel
     302            float normFrac = psMetadataLookupF32(NULL, ppsub, "NORM.FRAC"); // Fraction of window for normalisn windw
     303            float sysError = psMetadataLookupF32(NULL, ppsub, "SYS.ERR"); // Relative systematic error in images
     304            float skyErr = psMetadataLookupF32(NULL, ppsub, "SKY.ERR"); // Additional error in sky
     305            float covarFrac = psMetadataLookupF32(NULL, ppsub, "COVAR.FRAC"); // Fraction for covariance calculation
     306
    295307            const char *typeStr = psMetadataLookupStr(NULL, ppsub, "KERNEL.TYPE"); // Kernel type
    296308            pmSubtractionKernelsType type = pmSubtractionKernelsTypeFromString(typeStr); // Kernel type
     
    309321            float poorFrac = psMetadataLookupF32(&mdok, ppsub, "POOR.FRACTION"); // Fraction for "poor"
    310322
     323            bool scale = psMetadataLookupBool(NULL, ppsub, "SCALE");        // Scale kernel parameters?
     324            float scaleRef = psMetadataLookupF32(NULL, ppsub, "SCALE.REF"); // Reference for scaling
     325            float scaleMin = psMetadataLookupF32(NULL, ppsub, "SCALE.MIN"); // Minimum for scaling
     326            float scaleMax = psMetadataLookupF32(NULL, ppsub, "SCALE.MAX"); // Maximum for scaling
     327            if (!isfinite(scaleRef) || !isfinite(scaleMin) || !isfinite(scaleMax)) {
     328                psError(PPSTACK_ERR_CONFIG, false,
     329                        "Scale parameters (SCALE.REF=%f, SCALE.MIN=%f, SCALE.MAX=%f) not set in PPSUB recipe.",
     330                        scaleRef, scaleMin, scaleMax);
     331                return false;
     332            }
     333
     334
    311335            // These values are specified specifically for stacking
    312336            const char *stampsName = psMetadataLookupStr(NULL, config->arguments, "STAMPS");// Stamps filename
     
    322346            psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
    323347            if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) {
    324                 psError(PS_ERR_UNKNOWN, false, "Can't measure background for image.");
     348                psError(PPSTACK_ERR_DATA, false, "Can't measure background for image.");
    325349                psFree(fake);
    326350                psFree(optWidths);
     
    338362                                                       footprint); // Filtered list of sources
    339363
     364            bool oldThreads = pmReadoutFakeThreads(true); // Old threading state
    340365            if (!pmReadoutFakeFromSources(fake, readout->image->numCols, readout->image->numRows,
    341366                                          stampSources, SOURCE_MASK, NULL, NULL, options->psf,
    342367                                          minFlux, footprint + size, false, true)) {
    343                 psError(PS_ERR_UNKNOWN, false, "Unable to generate fake image with target PSF.");
     368                psError(PPSTACK_ERR_DATA, false, "Unable to generate fake image with target PSF.");
    344369                psFree(fake);
    345370                psFree(optWidths);
     
    347372                return false;
    348373            }
     374            pmReadoutFakeThreads(oldThreads);
    349375
    350376            fake->mask = psImageCopy(NULL, readout->mask, PS_TYPE_IMAGE_MASK);
    351377
     378#if 1
    352379            // Add the background into the target image
    353380            psImage *bgImage = stackBackgroundModel(readout, config); // Image of background
    354381            psBinaryOp(fake->image, fake->image, "+", bgImage);
    355382            psFree(bgImage);
     383#endif
    356384
    357385#ifdef TESTING
     
    379407
    380408            if (threads > 0) {
    381                 pmSubtractionThreadsInit(readout, fake);
     409                pmSubtractionThreadsInit();
    382410            }
    383411
     
    387415            if (kernel) {
    388416                if (!pmSubtractionMatchPrecalc(NULL, conv, fake, readout, readout->analysis,
    389                                                stride, sysError, maskVal, maskBad, maskPoor,
     417                                               stride, kernelError, covarFrac, maskVal, maskBad, maskPoor,
    390418                                               poorFrac, badFrac)) {
    391                     psError(PS_ERR_UNKNOWN, false, "Unable to convolve images.");
     419                    psError(psErrorCodeLast(), false, "Unable to convolve images.");
    392420                    psFree(fake);
    393421                    psFree(optWidths);
     
    395423                    psFree(conv);
    396424                    if (threads > 0) {
    397                         pmSubtractionThreadsFinalize(readout, fake);
     425                        pmSubtractionThreadsFinalize();
    398426                    }
    399427                    return false;
    400428                }
    401429            } else {
    402                 if (!pmSubtractionMatch(NULL, conv, fake, readout, footprint, stride, regionSize, spacing,
    403                                         threshold, stampSources, stampsName, type, size, order, widths,
    404                                         orders, inner, ringsOrder, binning, penalty,
    405                                         optimum, optWidths, optOrder, optThresh, iter, rej, sysError,
    406                                         maskVal, maskBad, maskPoor, poorFrac, badFrac,
    407                                         PM_SUBTRACTION_MODE_2)) {
    408                     psError(PS_ERR_UNKNOWN, false, "Unable to match images.");
     430                // Scale the input parameters
     431                psVector *widthsCopy = psVectorCopy(NULL, widths, PS_TYPE_F32); // Copy of kernel widths
     432                if (scale && !pmSubtractionParamsScale(&size, &footprint, widthsCopy,
     433                                                       options->inputSeeing->data.F32[index],
     434                                                       options->targetSeeing, scaleRef, scaleMin, scaleMax)) {
     435                    psError(psErrorCodeLast(), false, "Unable to scale kernel parameters");
    409436                    psFree(fake);
    410437                    psFree(optWidths);
    411438                    psFree(stampSources);
    412439                    psFree(conv);
     440                    psFree(widthsCopy);
    413441                    if (threads > 0) {
    414                         pmSubtractionThreadsFinalize(readout, fake);
     442                        pmSubtractionThreadsFinalize();
    415443                    }
    416444                    return false;
    417445                }
    418             }
     446
     447                if (!pmSubtractionMatch(NULL, conv, fake, readout, footprint, stride, regionSize, spacing,
     448                                        threshold, stampSources, stampsName, type, size, order, widthsCopy,
     449                                        orders, inner, ringsOrder, binning, penalty,
     450                                        optimum, optWidths, optOrder, optThresh, iter, rej, normFrac,
     451                                        sysError, skyErr, kernelError, covarFrac, maskVal, maskBad, maskPoor,
     452                                        poorFrac, badFrac, PM_SUBTRACTION_MODE_2)) {
     453                    psError(psErrorCodeLast(), false, "Unable to match images.");
     454                    psFree(fake);
     455                    psFree(optWidths);
     456                    psFree(stampSources);
     457                    psFree(conv);
     458                    psFree(widthsCopy);
     459                    if (threads > 0) {
     460                        pmSubtractionThreadsFinalize();
     461                    }
     462                    return false;
     463                }
     464                psFree(widthsCopy);
     465            }
     466
    419467
    420468#ifdef TESTING
     
    447495
    448496            if (threads > 0) {
    449                 pmSubtractionThreadsFinalize(readout, fake);
     497                pmSubtractionThreadsFinalize();
    450498            }
    451499
     
    487535            while ((item = psMetadataGetAndIncrement(iter))) {
    488536                assert(item->type == PS_DATA_UNKNOWN);
    489                 // Set the normalisation dimensions, since these will be otherwise unavailable when reading
    490                 // the images by scans.
    491537                pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction
    492                 kernel->numCols = readout->image->numCols;
    493                 kernel->numRows = readout->image->numRows;
    494 
    495538                kernels = psArrayAdd(kernels, ARRAY_BUFFER, kernel);
    496539            }
     
    518561        }
    519562
     563        // Kernel normalisation
     564        {
     565            double sum = 0.0;           // Sum of chi^2
     566            int num = 0;                // Number of measurements of chi^2
     567            psString regex = NULL;      // Regular expression
     568            psStringAppend(&regex, "^%s$", PM_SUBTRACTION_ANALYSIS_NORM);
     569            psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex);
     570            psFree(regex);
     571            psMetadataItem *item = NULL;// Item from iteration
     572            while ((item = psMetadataGetAndIncrement(iter))) {
     573                assert(item->type == PS_TYPE_F32);
     574                float norm = item->data.F32; // Normalisation
     575                sum += norm;
     576                num++;
     577            }
     578            psFree(iter);
     579            float conv = sum/num;       // Mean normalisation from convolution
     580            float stars = powf(10.0, -0.4 * options->norm->data.F32[index]); // Normalisation from stars
     581            float renorm =  stars / conv; // Renormalisation to apply
     582            psLogMsg("ppStack", PS_LOG_INFO, "Renormalising image %d by %f (kernel: %f, stars: %f)\n",
     583                     index, renorm, conv, stars);
     584            psBinaryOp(readout->image, readout->image, "*", psScalarAlloc(renorm, PS_TYPE_F32));
     585            psBinaryOp(readout->variance, readout->variance, "*", psScalarAlloc(PS_SQR(renorm), PS_TYPE_F32));
     586        }
     587
    520588        // Reject image completely if the maximum deconvolution fraction exceeds the limit
    521589        float deconv = psMetadataLookupF32(NULL, conv->analysis,
    522590                                           PM_SUBTRACTION_ANALYSIS_DECONV_MAX); // Max deconvolution fraction
    523591        if (deconv > deconvLimit) {
    524             psWarning("Maximum deconvolution fraction (%f) exceeds limit (%f) --- rejecting\n",
    525                       deconv, deconvLimit);
     592            psWarning("Maximum deconvolution fraction (%f) exceeds limit (%f) --- rejecting image %d\n",
     593                      deconv, deconvLimit, index);
    526594            psFree(conv);
    527595            return NULL;
     
    542610    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
    543611    if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) {
    544       psWarning("Can't measure background for image.");
    545       psErrorClear();
     612        psWarning("Can't measure background for image.");
     613        psErrorClear();
    546614    } else {
    547       if (!psMetadataLookupBool(NULL, config->arguments, "PPSTACK.SKIP.BG.SUB")) {
    548         psLogMsg("ppStack", PS_LOG_INFO, "Correcting convolved image background by %lf (+/- %lf)",
    549                  psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN), psStatsGetValue(bg, PS_STAT_ROBUST_STDEV));
    550         (void)psBinaryOp(readout->image, readout->image, "-",
    551                          psScalarAlloc(psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN), PS_TYPE_F32));
    552       }
     615        if (!psMetadataLookupBool(NULL, config->arguments, "PPSTACK.SKIP.BG.SUB")) {
     616            psLogMsg("ppStack", PS_LOG_INFO, "Correcting convolved image background by %lf (+/- %lf)",
     617                     psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN), psStatsGetValue(bg, PS_STAT_ROBUST_STDEV));
     618            (void)psBinaryOp(readout->image, readout->image, "-",
     619                             psScalarAlloc(psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN), PS_TYPE_F32));
     620        }
    553621    }
    554622
     
    560628
    561629    // Measure the variance level for the weighting
    562     if (!psImageBackground(bg, NULL, readout->variance, readout->mask, maskVal | maskBad, rng)) {
    563         psError(PS_ERR_UNKNOWN, false, "Can't measure mean variance for image.");
    564         psFree(rng);
    565         psFree(bg);
    566         return false;
    567     }
    568     options->weightings->data.F32[index] = 1.0 / (psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN) *
    569                                                   psImageCovarianceFactor(readout->covariance));
    570     psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "PPSTACK.WEIGHTING", 0,
    571                      "Weighting by 1/noise^2 for stack", options->weightings->data.F32[index]);
     630    if (psMetadataLookupBool(NULL, recipe, "WEIGHTS")) {
     631        if (!psImageBackground(bg, NULL, readout->variance, readout->mask, maskVal | maskBad, rng)) {
     632            psError(PPSTACK_ERR_DATA, false, "Can't measure mean variance for image.");
     633            psFree(rng);
     634            psFree(bg);
     635            return false;
     636        }
     637        options->weightings->data.F32[index] = 1.0 / (psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN) *
     638                                                      psImageCovarianceFactor(readout->covariance));
     639    } else {
     640        options->weightings->data.F32[index] = 1.0;
     641    }
     642    psLogMsg("ppStack", PS_LOG_INFO, "Weighting for image %d is %f\n",
     643             index, options->weightings->data.F32[index]);
    572644
    573645    psFree(rng);
  • branches/tap_branches/ppStack/src/ppStackOptions.c

    r23573 r27838  
    1212        fclose(options->statsFile);
    1313    }
    14     psFree(options->imageNames);
    15     psFree(options->maskNames);
    16     psFree(options->varianceNames);
     14    psFree(options->origImages);
     15    psFree(options->origMasks);
     16    psFree(options->origVariances);
     17    psFree(options->origCovars);
     18    psFree(options->convImages);
     19    psFree(options->convMasks);
     20    psFree(options->convVariances);
    1721    psFree(options->psf);
     22    psFree(options->inputSeeing);
     23    psFree(options->exposures);
    1824    psFree(options->inputMask);
    1925    psFree(options->sourceLists);
    2026    psFree(options->norm);
     27    psFree(options->sources);
    2128    psFree(options->cells);
    2229    psFree(options->kernels);
     
    2431    psFree(options->matchChi2);
    2532    psFree(options->weightings);
    26     psFree(options->covariances);
     33    psFree(options->convCovars);
    2734    psFree(options->outRO);
     35    psFree(options->expRO);
    2836    psFree(options->inspect);
    2937    psFree(options->rejected);
     
    3745
    3846    options->convolve = true;
     47    options->matchZPs = true;
     48    options->photometry = false;
    3949    options->stats = NULL;
    4050    options->statsFile = NULL;
    41     options->imageNames = NULL;
    42     options->maskNames = NULL;
    43     options->varianceNames = NULL;
     51    options->origImages = NULL;
     52    options->origMasks = NULL;
     53    options->origVariances = NULL;
     54    options->origCovars = NULL;
     55    options->convImages = NULL;
     56    options->convMasks = NULL;
     57    options->convVariances = NULL;
    4458    options->num = 0;
     59    options->quality = 0;
    4560    options->psf = NULL;
     61    options->sumExposure = NAN;
     62    options->zp = NAN;
     63    options->inputSeeing = NULL;
     64    options->exposures = NULL;
     65    options->targetSeeing = NAN;
    4666    options->inputMask = NULL;
    4767    options->sourceLists = NULL;
    4868    options->norm = NULL;
     69    options->sources = NULL;
    4970    options->cells = NULL;
    5071    options->kernels = NULL;
     
    5475    options->matchChi2 = NULL;
    5576    options->weightings = NULL;
    56     options->covariances = NULL;
     77    options->convCovars = NULL;
    5778    options->outRO = NULL;
     79    options->expRO = NULL;
    5880    options->inspect = NULL;
    5981    options->rejected = NULL;
  • branches/tap_branches/ppStack/src/ppStackOptions.h

    r23573 r27838  
    99    // Setup
    1010    bool convolve;                      // Convolve images?
     11    bool matchZPs;                      // Adjust relative fluxes based on transparency analysis?
     12    bool photometry;                    // Perform photometry?
    1113    psMetadata *stats;                  // Statistics for output
    1214    FILE *statsFile;                    // File to which to write statistics
    13     psArray *imageNames, *maskNames, *varianceNames; // Filenames for the temporary convolved images
     15    psArray *origImages, *origMasks, *origVariances; // Filenames of the original images
     16    psArray *convImages, *convMasks, *convVariances; // Filenames for the temporary convolved images
     17    psArray *origCovars;                // Original covariances matrices
    1418    int num;                            // Number of inputs
     19    int quality;                        // Bad data quality flag
    1520    // Prepare
    1621    pmPSF *psf;                         // Target PSF
     22    psVector *inputSeeing;              // Input seeing FWHMs
     23    float targetSeeing;                 // Target seeing FWHM
     24    psVector *exposures;                // Exposure times
    1725    float sumExposure;                  // Sum of exposure times
     26    float zp;                           // Zero point for output
    1827    psVector *inputMask;                // Mask for inputs
    1928    psArray *sourceLists;               // Individual lists of sources for matching
    2029    psVector *norm;                     // Normalisation for each image
     30    psArray *sources;                   // Matched sources
    2131    // Convolve
    2232    psArray *cells;                     // Cells for convolved images --- a handle for reading again
     
    2636    psVector *matchChi2;                // chi^2 for stamps from matching
    2737    psVector *weightings;               // Combination weightings for images (1/noise^2)
    28     psArray *covariances;               // Covariance matrices
     38    psArray *convCovars;                // Convolved covariance matrices
    2939    // Combine initial
    3040    pmReadout *outRO;                   // Output readout
     41    pmReadout *expRO;                   // Exposure readout
    3142    psArray *inspect;                   // Array of arrays of pixels to inspect
    3243    // Rejection
  • branches/tap_branches/ppStack/src/ppStackPSF.c

    r25480 r27838  
    1414                  const psArray *psfs, const psVector *inputMask)
    1515{
     16    bool mdok = false;
     17
    1618#ifndef TESTING
    1719    // Get the recipe values
     
    2426    int psfOrder = psMetadataLookupS32(NULL, recipe, "PSF.ORDER"); // Spatial order for PSF
    2527
     28    psString maskValStr = psMetadataLookupStr(&mdok, recipe, "MASK.VAL"); // Name of bits to mask going in
     29    if (!mdok || !maskValStr) {
     30        psError(PPSTACK_ERR_CONFIG, false, "Unable to find MASK.VAL in recipe");
     31        return false;
     32    }
     33    psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask
     34
    2635    for (int i = 0; i < psfs->n; i++) {
    2736        if (inputMask->data.U8[i]) {
     
    3241
    3342    // Solve for the target PSF
    34     pmPSF *psf = pmPSFEnvelope(numCols, numRows, psfs, psfInstances, psfRadius, psfModel,
    35                                psfOrder, psfOrder);
     43    pmPSF *psf = pmPSFEnvelope(numCols, numRows, psfs, psfInstances, psfRadius, psfModel, psfOrder, psfOrder, maskVal);
    3644    if (!psf) {
    37         psError(PS_ERR_UNKNOWN, false, "Unable to determine output PSF.");
     45        psError(PPSTACK_ERR_PSF, false, "Unable to determine output PSF.");
    3846        return NULL;
    3947    }
     
    4250    pmPSF *psf = pmPSFBuildSimple("PS_MODEL_PS1_V1", 4.0, 4.0, 0.0, 1.0);
    4351    if (!psf) {
    44         psError(PS_ERR_UNKNOWN, false, "Unable to build dummy PSF.");
     52        psError(PPSTACK_ERR_PSF, false, "Unable to build dummy PSF.");
    4553        return NULL;
    4654    }
  • branches/tap_branches/ppStack/src/ppStackPhotometry.c

    r24216 r27838  
    1919    psAssert(recipe, "We've thrown an error on this before.");
    2020
    21     bool mdok;                          // Status of MD lookup
    22     if (!psMetadataLookupBool(&mdok, recipe, "PHOTOMETRY")) {
     21    if (!options->photometry) {
    2322        // Nothing to do
    2423        return true;
     
    2726    psTimerStart("PPSTACK_PHOT");
    2827
    29     ppStackFileActivation(config, PPSTACK_FILES_COMBINE, false);
     28    pmFPAfileActivate(config->files, false, NULL);
    3029    ppStackFileActivation(config, PPSTACK_FILES_PHOT, true);
    3130    pmFPAview *photView = ppStackFilesIterateDown(config); // View to readout
    32     ppStackFileActivation(config, PPSTACK_FILES_COMBINE, true);
     31    ppStackFileActivation(config, PPSTACK_FILES_STACK, true);
    3332
    3433    pmFPAfile *photFile = psMetadataLookupPtr(NULL, config->files, "PSPHOT.INPUT"); // File for photometry
     
    6059                           "Bits to use for mark", markValue);
    6160
    62     pmCell *sourcesCell = pmFPAfileThisCell(config->files, photView, "PPSTACK.OUTPUT");
    63     psArray *inSources = psMetadataLookupPtr(NULL, sourcesCell->analysis, "PSPHOT.SOURCES");
     61    psArray *inSources = options->sources;
    6462    if (!inSources) {
    65         psError(PS_ERR_UNKNOWN, false, "Unable to find input sources");
     63        psError(PPSTACK_ERR_PROG, false, "Unable to find input sources");
    6664        psFree(photView);
    6765        return false;
    6866    }
    6967
     68    pmModelClassSetLimits(PM_MODEL_LIMITS_LAX);
    7069    if (!psphotReadoutKnownSources(config, photView, inSources)) {
    7170        // This is likely a data quality issue
     
    7372        psErrorStackPrint(stderr, "Unable to perform photometry on image");
    7473        psWarning("Unable to perform photometry on image --- suspect bad data quality.");
    75         if (options->stats && psMetadataLookupS32(NULL, options->stats, "QUALITY") == 0) {
    76             psMetadataAddS32(options->stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE,
    77                              "Unable to perform photometry on image", psErrorCodeLast());
     74        if (options->quality == 0) {
     75            options->quality = psErrorCodeLast();
    7876        }
    7977        psErrorClear();
     
    8482        !pmFPAfileDropInternal (config->files, "PSPHOT.BACKMDL.STDEV") ||
    8583        !pmFPAfileDropInternal (config->files, "PSPHOT.BACKGND")) {
    86         psError(PS_ERR_UNKNOWN, false, "Unable to drop PSPHOT internal files.");
     84        psError(PPSTACK_ERR_PROG, false, "Unable to drop PSPHOT internal files.");
    8785        return false;
    8886    }
     
    9290    if (options->stats) {
    9391        pmReadout *photRO = pmFPAviewThisReadout(photView, photFile->fpa); // Readout with the sources
    94         psArray *sources = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.SOURCES"); // Sources
    95         psMetadataAddS32(options->stats, PS_LIST_TAIL, "NUM_SOURCES", 0,
    96                          "Number of sources detected", sources ? sources->n : 0);
    97         psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_PHOT", 0,
    98                          "Time to do photometry", psTimerMark("PPSTACK_PHOT"));
     92        pmDetections *detections = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.DETECTIONS"); // detections
     93        if (detections && detections->allSources) {
     94            psMetadataAddS32(options->stats, PS_LIST_TAIL, "NUM_SOURCES", 0, "Number of sources detected", detections->allSources->n);
     95        } else {
     96            psMetadataAddS32(options->stats, PS_LIST_TAIL, "NUM_SOURCES", 0, "Number of sources detected", 0);
     97        }
     98        psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_PHOT", 0, "Time to do photometry", psTimerMark("PPSTACK_PHOT"));
    9999    }
     100
    100101    psFree(photView);
    101102
  • branches/tap_branches/ppStack/src/ppStackPrepare.c

    r23573 r27838  
    2626    float zpRadius = psMetadataLookupS32(&mdok, recipe, "PHOT.RADIUS"); // Radius for PHOT measurement
    2727    if (!mdok) {
    28         psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.RADIUS in recipe");
     28        psError(PPSTACK_ERR_CONFIG, true, "Unable to find PHOT.RADIUS in recipe");
    2929        return false;
    3030    }
    3131    float zpSigma = psMetadataLookupF32(&mdok, recipe, "PHOT.SIGMA"); // Gaussian sigma for photometry
    3232    if (!mdok) {
    33         psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.SIGMA in recipe");
     33        psError(PPSTACK_ERR_CONFIG, true, "Unable to find PHOT.SIGMA in recipe");
    3434        return false;
    3535    }
    3636    float zpFrac = psMetadataLookupF32(&mdok, recipe, "PHOT.FRAC"); // Fraction of good pixels for photometry
    3737    if (!mdok) {
    38         psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.FRAC in recipe");
     38        psError(PPSTACK_ERR_CONFIG, true, "Unable to find PHOT.FRAC in recipe");
    3939        return false;
    4040    }
     
    4242    psString maskValStr = psMetadataLookupStr(&mdok, recipe, "MASK.VAL"); // Name of bits to mask going in
    4343    if (!mdok || !maskValStr) {
    44         psError(PS_ERR_UNKNOWN, false, "Unable to find MASK.VAL in recipe");
     44        psError(PPSTACK_ERR_CONFIG, false, "Unable to find MASK.VAL in recipe");
    4545        return false;
    4646    }
     
    5353    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics
    5454    if (!psImageBackground(stats, NULL, image, mask, maskVal, rng)) {
    55         psError(PS_ERR_UNKNOWN, false, "Unable to measure background for image");
     55        psError(PPSTACK_ERR_DATA, false, "Unable to measure background for image");
    5656        psFree(stats);
    5757        psFree(rng);
     
    126126    options->inputMask = psVectorAlloc(num, PS_TYPE_VECTOR_MASK); // Mask for inputs
    127127    psVectorInit(options->inputMask, 0);
     128    options->exposures = psVectorAlloc(options->num, PS_TYPE_F32);
     129    psVectorInit(options->exposures, NAN);
    128130
    129131    pmFPAfileActivate(config->files, false, NULL);
     
    134136    }
    135137
    136     psMetadataIterator *fileIter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD, "^PPSTACK.INPUT$");
    137     psMetadataItem *fileItem; // Item from iteration
    138138    psArray *psfs = psArrayAlloc(num); // PSFs for PSF envelope
    139139    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
     140    options->sumExposure = 0.0;
     141    for (int i = 0; i < num; i++) {
     142        pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", i); // File of interest
     143        pmCell *cell = pmFPAviewThisCell(view, file->fpa); // Cell of interest
     144
     145        options->exposures->data.F32[i] = psMetadataLookupF32(NULL, cell->concepts, "CELL.EXPOSURE");
     146        options->sumExposure += options->exposures->data.F32[i];
    144147
    145148        // Get list of PSFs, to determine target PSF
    146149        if (options->convolve) {
    147             pmChip *chip = pmFPAviewThisChip(view, inputFile->fpa); // The chip: holds the PSF
     150            pmChip *chip = pmFPAviewThisChip(view, file->fpa); // The chip: holds the PSF
    148151            pmPSF *psf = psMetadataLookupPtr(NULL, chip->analysis, "PSPHOT.PSF"); // PSF
    149152            if (!psf) {
    150                 psError(PS_ERR_UNKNOWN, false, "Unable to find PSF.");
    151                 psFree(view);
    152                 psFree(fileIter);
     153                psError(PPSTACK_ERR_PROG, false, "Unable to find PSF.");
     154                psFree(view);
    153155                psFree(psfs);
    154156                return false;
    155157            }
    156             psfs->data[index] = psMemIncrRefCounter(psf);
     158            psfs->data[i] = psMemIncrRefCounter(psf);
    157159            psMetadataRemoveKey(chip->analysis, "PSPHOT.PSF");
    158160
    159             pmCell *cell = pmFPAviewThisCell(view, inputFile->fpa); // Cell of interest
     161            pmCell *cell = pmFPAviewThisCell(view, file->fpa); // Cell of interest
    160162            pmHDU *hdu = pmHDUFromCell(cell);
    161163            assert(hdu && hdu->header);
     
    163165            int naxis2 = psMetadataLookupS32(NULL, hdu->header, "NAXIS2"); // Number of rows
    164166            if (naxis1 <= 0 || naxis2 <= 0) {
    165                 psError(PS_ERR_UNKNOWN, false, "Unable to determine size of image from PSF.");
    166                 psFree(view);
    167                 psFree(fileIter);
     167                psError(PPSTACK_ERR_PROG, false, "Unable to determine size of image from PSF.");
     168                psFree(view);
    168169                psFree(psfs);
    169170                return false;
     
    176177
    177178
    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);
     179        bool redoPhot = psMetadataLookupBool(NULL, recipe, "PHOT");
     180
     181        pmDetections *detections = NULL;
     182        if (options->convolve || options->matchZPs || options->photometry || redoPhot) {
     183            pmReadout *ro = pmFPAviewThisReadout(view, file->fpa); // Readout with sources
     184            detections = psMetadataLookupPtr(NULL, ro->analysis, "PSPHOT.DETECTIONS"); // Sources
     185            if (!detections || !detections->allSources) {
     186                psWarning("No detections found for image %d --- rejecting.", i);
     187                options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PPSTACK_MASK_CAL;
     188                continue;
     189            }
     190            psAssert (detections->allSources, "missing sources?");
     191
     192            options->sourceLists->data[i] = psMemIncrRefCounter(detections->allSources);
     193        }
    185194
    186195        // 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);
     196        if (redoPhot) {
     197            psTrace("ppStack", 2, "Photometering input %d of %d....\n", i, num);
    189198            pmFPAfileActivate(config->files, false, NULL);
    190             ppStackFileActivationSingle(config, PPSTACK_FILES_CONVOLVE, true, index);
    191             pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", index); // File
     199            ppStackFileActivationSingle(config, PPSTACK_FILES_CONVOLVE, true, i);
     200            if (options->convolve) {
     201                pmFPAfileActivate(config->files, true, "PPSTACK.CONV.KERNEL");
     202            }
     203            pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", i); // File
    192204            pmFPAview *photView = ppStackFilesIterateDown(config);
    193205            if (!photView) {
     
    198210            pmReadout *ro = pmFPAviewThisReadout(view, file->fpa); // Readout of interest
    199211
    200             if (!ppStackInputPhotometer(ro, sources, config)) {
    201                 psError(PS_ERR_UNKNOWN, false, "Unable to do photometry on input sources");
     212            if (!ppStackInputPhotometer(ro, detections->allSources, config)) {
     213                psError(psErrorCodeLast(), false, "Unable to do photometry on input sources");
    202214                psFree(view);
    203215                psFree(photView);
     
    213225            ppStackFileActivation(config, PPSTACK_FILES_PREPARE, true);
    214226        }
    215 
    216         index++;
    217     }
    218     psFree(fileIter);
     227    }
     228
     229    psString log = psStringCopy("Input seeing FWHMs:\n"); // Log message
     230    bool havePSFs = false;                                // Do we have any PSFs?
     231    options->inputSeeing = psVectorAlloc(num, PS_TYPE_F32);
     232    psVectorInit(options->inputSeeing, NAN);
     233    for (int i = 0; i < num; i++) {
     234        pmPSF *psf = psfs->data[i];     // PSF for image
     235        if (!psf) {
     236            continue;
     237        }
     238        havePSFs = true;
     239
     240        int xNum = PS_MAX(psf->trendNx, 1), yNum = PS_MAX(psf->trendNy, 1); // Number of realisations
     241        double sumFWHM = 0.0;           // FWHM for image
     242        int numFWHM = 0;                // Number of FWHM measurements
     243        for (int y = 0; y < yNum; y++) {
     244            float yPos = ((float)y + 0.5) / (float)yNum * numRows;
     245            for (int x = 0; x < xNum; x++) {
     246                float xPos = ((float)x + 0.5) / (float)xNum * numCols;
     247                float fwhm = pmPSFtoFWHM(psf, xPos, yPos); // FWHM for image
     248                if (isfinite(fwhm)) {
     249                    sumFWHM += fwhm;
     250                    numFWHM++;
     251                }
     252            }
     253        }
     254        if (numFWHM == 0) {
     255            options->inputSeeing->data.F32[i] = NAN;
     256            options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PPSTACK_MASK_PSF;
     257            psLogMsg("ppStack", PS_LOG_INFO, "Unable to measure PSF FWHM for image %d --- rejected.", i);
     258        } else {
     259            options->inputSeeing->data.F32[i] = sumFWHM / (float)numFWHM;
     260        }
     261
     262        psStringAppend(&log, "Input %d: %f\n", i, options->inputSeeing->data.F32[i]);
     263    }
     264    if (havePSFs) {
     265        psLogMsg("ppStack", PS_LOG_INFO, "%s", log);
     266    }
     267    psFree(log);
    219268
    220269    // Generate target PSF
     
    223272        psFree(psfs);
    224273        if (!options->psf) {
    225             psError(PS_ERR_UNKNOWN, false, "Unable to determine output PSF.");
     274            psError(psErrorCodeLast(), false, "Unable to determine output PSF.");
    226275            psFree(view);
    227276            return false;
     
    229278        psMetadataAddPtr(config->arguments, PS_LIST_TAIL, "PSF.TARGET", PS_DATA_UNKNOWN,
    230279                         "Target PSF for stack", options->psf);
    231 
    232         pmChip *outChip = pmFPAfileThisChip(config->files, view, "PPSTACK.OUTPUT"); // Output chip
     280        options->targetSeeing = pmPSFtoFWHM(options->psf, 0.5 * numCols, 0.5 * numRows); // FWHM for target
     281        psLogMsg("ppStack", PS_LOG_INFO, "Target seeing FWHM: %f\n", options->targetSeeing);
     282
     283        pmChip *outChip = pmFPAfileThisChip(config->files, view, "PPSTACK.TARGET.PSF"); // Output chip
    233284        psMetadataAddPtr(outChip->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_DATA_UNKNOWN,
    234285                         "Target PSF", options->psf);
     
    238289    // Zero point calibration
    239290    if (!ppStackSourcesTransparency(options, view, config)) {
    240         psError(PS_ERR_UNKNOWN, false, "Unable to calculate transparency differences");
     291        psError(PPSTACK_ERR_DATA, false, "Unable to calculate transparency differences");
    241292        psFree(view);
    242293        return false;
  • branches/tap_branches/ppStack/src/ppStackReadout.c

    r23577 r27838  
    2323    psVector *mask = options->inputMask; // Mask for inputs
    2424    psVector *weightings = options->weightings; // Weightings (1/noise^2) for each image
     25    psVector *exposures = options->exposures;   // Exposure times for each image
    2526    psVector *addVariance = options->matchChi2; // Additional variance when rejecting
    2627
    27     psArray *inspect = ppStackReadoutInitial(config, outRO, thread->readouts, mask,
    28                                              weightings, addVariance);
    29 
    30     job->results = inspect;
     28    job->results = ppStackReadoutInitial(config, outRO, thread->readouts, mask,
     29                                         weightings, exposures, addVariance);
    3130    thread->busy = false;
    3231
    33     return inspect ? true : false;
     32    return job->results ? true : false;
    3433}
    3534
     
    4039    psArray *args = job->args;          // Arguments
    4140    ppStackThread *thread = args->data[0]; // Thread
    42     ppStackOptions *options = args->data[1]; // Options
    43     pmConfig *config = args->data[2];   // Configuration
    44 
    45     pmReadout *outRO = options->outRO;  // Output readout
     41    psArray *reject = args->data[1];    // Rejected pixels for each image
     42    ppStackOptions *options = args->data[2]; // Options
     43    pmConfig *config = args->data[3];   // Configuration
     44    bool safety = PS_SCALAR_VALUE(args->data[4], U8);    // Safety switch on?
     45    bool normalise = PS_SCALAR_VALUE(args->data[5], U8); // Normalise images?
     46
    4647    psVector *mask = options->inputMask; // Mask for inputs
    47     psArray *rejected = options->rejected; // Rejected pixels
    4848    psVector *weightings = options->weightings; // Weightings (1/noise^2) for each image
     49    psVector *exposures = options->exposures;   // Exposure times for each image
    4950    psVector *addVariance = options->matchChi2; // Additional variance when rejecting
    50 
    51     bool status = ppStackReadoutFinal(config, outRO, thread->readouts, mask, rejected,
    52                                       weightings, addVariance); // Status of operation
     51    psVector *norm = normalise ? options->norm : NULL; // Normalisations to apply to images
     52
     53    bool status = ppStackReadoutFinal(config, options->outRO, options->expRO, thread->readouts, mask, reject,
     54                                      weightings, exposures, addVariance, safety, norm); // Status of operation
    5355
    5456    thread->busy = false;
    5557
     58    psAssert(status, "Stacking failed.");
     59
    5660    return status;
    5761}
     
    6367
    6468    psArray *args = job->args;  // Input arguments
    65     psArray *inspect = args->data[0]; // Array of pixel arrays
    66     int index = PS_SCALAR_VALUE(args->data[1], S32); // Index of interest
    67 
    68     psArray *inputs = inspect->data[index]; // Array of interest
    69     psPixels *output = NULL;    // Output pixel list
    70     for (int i = 0; i < inputs->n; i++) {
    71         psPixels *input = inputs->data[i]; // Input pixel list
    72         if (!input || input->n == 0) {
    73             continue;
    74         }
    75         output = psPixelsConcatenate(output, input);
    76     }
    77 
    78     if (!output) {
    79         // If there are no pixels to inspect, then just fake it
    80         output = psPixelsAllocEmpty(0);
    81     }
    82 
    83     psFree(inputs);
    84     inspect->data[index] = output;
     69    psArray *inspects = args->data[0]; // Array of pixel arrays
     70    psArray *rejects = args->data[1];  // Array of pixel arrays
     71    int index = PS_SCALAR_VALUE(args->data[2], S32); // Index of interest
     72
     73    psArray *inInspects = inspects->data[index]; // Array of interest
     74    psArray *inRejects = rejects->data[index]; // Array of interest
     75    psAssert(inInspects->n == inRejects->n, "Size should be the same");
     76    psPixels *outInspect = NULL, *outReject = NULL; // Output pixel lists
     77    for (int i = 0; i < inInspects->n; i++) {
     78        psPixels *inInspect = inInspects->data[i]; // Input pixel list
     79        if (inInspect && inInspect->n > 0) {
     80            outInspect = psPixelsConcatenate(outInspect, inInspect);
     81        }
     82        psPixels *inReject = inRejects->data[i]; // Input pixel list
     83        if (inReject && inReject->n > 0) {
     84            outReject = psPixelsConcatenate(outReject, inReject);
     85        }
     86    }
     87
     88    // If there are no pixels to inspect, then just fake it
     89    if (!outInspect) {
     90        outInspect = psPixelsAllocEmpty(0);
     91    }
     92    if (!outReject) {
     93        outReject = psPixelsAllocEmpty(0);
     94    }
     95
     96    psFree(inspects->data[index]);
     97    inspects->data[index] = outInspect;
     98    psFree(rejects->data[index]);
     99    rejects->data[index] = outReject;
    85100
    86101    return true;
     
    89104
    90105psArray *ppStackReadoutInitial(const pmConfig *config, pmReadout *outRO, const psArray *readouts,
    91                                const psVector *mask, const psVector *weightings, const psVector *addVariance)
     106                               const psVector *mask, const psVector *weightings, const psVector *exposures,
     107                               const psVector *addVariance)
    92108{
    93109    assert(config);
     
    104120
    105121    bool mdok;                          // Status of MD lookup
    106     int iter = psMetadataLookupS32(NULL, recipe, "ITER"); // Rejection iterations
     122    float iter = psMetadataLookupF32(NULL, recipe, "COMBINE.ITER"); // Rejection iterations
    107123    float combineRej = psMetadataLookupF32(NULL, recipe, "COMBINE.REJ"); // Combination threshold
    108124    float combineSys = psMetadataLookupF32(NULL, recipe, "COMBINE.SYS"); // Combination systematic error
     
    116132    psString maskValStr = psMetadataLookupStr(NULL, recipe, "MASK.VAL"); // Name of bits to mask going in
    117133    psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch
     134    psString maskSuspectStr = psMetadataLookupStr(NULL, recipe, "MASK.SUSPECT"); // Name of suspect mask bits
     135    psImageMaskType maskSuspect = pmConfigMaskGet(maskSuspectStr, config); // Suspect bits
    118136    psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad
    119137    psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
     
    129147        }
    130148
    131 #if 0
    132         // This doesn't seem to work, so getting the weightings directly from a vector
    133         float weighting = psMetadataLookupF32(&mdok, ro->analysis, "PPSTACK.WEIGHTING"); // Relative weight
    134         if (!mdok || !isfinite(weighting)) {
    135             psWarning("No weighting supplied for image %d --- set to unity.", i);
    136             weighting = 1.0;
    137         } else {
    138             psLogMsg("ppStack", PS_LOG_INFO, "Weighting for image %d is %f", i, weighting);
    139         }
    140 #endif
    141 
    142149        // Ensure there is a mask, or pmStackCombine will complain
    143150        if (!ro->mask) {
     
    146153        }
    147154
    148         stack->data[i] = pmStackDataAlloc(ro, weightings->data.F32[i], addVariance->data.F32[i]);
    149     }
    150 
    151     if (!pmStackCombine(outRO, stack, maskVal | maskBad, maskBad, kernelSize, iter,
    152                         combineRej, combineSys, combineDiscard, true, useVariance, safe, false)) {
     155        stack->data[i] = pmStackDataAlloc(ro, weightings->data.F32[i], exposures->data.F32[i],
     156                                          addVariance->data.F32[i]);
     157    }
     158
     159    if (!pmStackCombine(outRO, NULL, stack, maskVal | maskBad, maskSuspect, maskBad, kernelSize, iter,
     160                        combineRej, combineSys, combineDiscard, useVariance, safe, false)) {
    153161        psError(PS_ERR_UNKNOWN, false, "Unable to combine input readouts with rejection.");
    154162        psFree(stack);
     
    156164    }
    157165
    158     // Save list of pixels to inspect
     166    // Save lists of pixels
    159167    psArray *inspect = psArrayAlloc(num); // List of pixels to inspect
     168    psArray *reject = psArrayAlloc(num);  // List of pixels rejected
    160169    for (int i = 0; i < num; i++) {
    161170        pmStackData *data = stack->data[i]; // Data for this image
     
    168177        }
    169178        inspect->data[i] = psMemIncrRefCounter(data->inspect);
     179        reject->data[i] = psMemIncrRefCounter(data->reject);
    170180    }
    171181    psFree(stack);
     
    173183    sectionNum++;
    174184
    175     return inspect;
    176 }
    177 
    178 
    179 
    180 bool ppStackReadoutFinal(const pmConfig *config, pmReadout *outRO, const psArray *readouts,
     185    psArray *results = psArrayAlloc(2); // Array of results
     186    results->data[0] = inspect;
     187    results->data[1] = reject;
     188
     189    return results;
     190}
     191
     192
     193
     194bool ppStackReadoutFinal(const pmConfig *config, pmReadout *outRO, pmReadout *expRO, const psArray *readouts,
    181195                         const psVector *mask, const psArray *rejected, const psVector *weightings,
    182                          const psVector *addVariance)
     196                         const psVector *exposures, const psVector *addVariance, bool safety,
     197                         const psVector *norm)
    183198{
    184199    assert(config);
    185200    assert(outRO);
     201    assert(expRO);
    186202    assert(readouts);
    187203    assert(!rejected || readouts->n == rejected->n);
     
    196212
    197213    bool mdok;                          // Status of MD lookup
    198     int iter = psMetadataLookupS32(NULL, recipe, "ITER"); // Rejection iterations
    199     float combineRej = psMetadataLookupF32(NULL, recipe, "COMBINE.REJ"); // Combination threshold
    200     float combineSys = psMetadataLookupF32(NULL, recipe, "COMBINE.SYS"); // Combination systematic error
    201     float combineDiscard = psMetadataLookupF32(NULL, recipe, "COMBINE.DISCARD"); // Olympic discard fraction
    202214    bool useVariance = psMetadataLookupBool(&mdok, recipe, "VARIANCE"); // Use variance for rejection?
    203215    bool safe = psMetadataLookupBool(&mdok, recipe, "SAFE"); // Be safe when combining small numbers of pixels
     
    205217    psString maskValStr = psMetadataLookupStr(NULL, recipe, "MASK.VAL"); // Name of bits to mask going in
    206218    psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch
     219    psString maskSuspectStr = psMetadataLookupStr(NULL, recipe, "MASK.SUSPECT"); // Name of suspect mask bits
     220    psImageMaskType maskSuspect = pmConfigMaskGet(maskSuspectStr, config); // Suspect bits
    207221    psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad
    208222    psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
     
    211225    psArray *stack = psArrayAlloc(num); // Array for stacking
    212226
    213     bool entire = true;                 // Combine entire image?
    214     if (rejected) {
    215         // We have rejection from a previous combination: combine without flagging pixels to inspect
    216         entire = false;
    217         safe = false;
    218         iter = 0;
    219         combineRej = NAN;
    220         combineSys = NAN;
    221     }
     227    // We have rejection from a previous combination: combine without flagging pixels to inspect
     228    safe &= safety;
     229    int iter = 0;
     230    float combineRej = NAN;
     231    float combineSys = NAN;
     232    float combineDiscard = NAN;
    222233
    223234    for (int i = 0; i < num; i++) {
    224235        pmReadout *ro = readouts->data[i];
    225         if (mask->data.U8[i] & (PPSTACK_MASK_REJECT | PPSTACK_MASK_BAD)) {
    226             // Image completely rejected since previous combination
    227             entire = true;
    228             continue;
    229         } else if (mask->data.U8[i]) {
    230             // Image completely rejected before original combination
    231             continue;
    232         }
    233 
    234 #if 0
    235         // This doesn't seem to work, so getting the weightings directly from a vector
    236         bool mdok;                      // Status of MD lookup
    237         float weighting = psMetadataLookupF32(&mdok, ro->analysis, "PPSTACK.WEIGHTING"); // Relative weight
    238         if (!mdok || !isfinite(weighting)) {
    239             psWarning("No WEIGHTING supplied for image %d --- set to unity.", i);
    240             weighting = 1.0;
    241         }
    242 #endif
     236        if (mask->data.U8[i]) {
     237            // Image completely rejected
     238            continue;
     239        }
    243240
    244241        // Ensure there is a mask, or pmStackCombine will complain
     
    248245        }
    249246
    250         pmStackData *data = pmStackDataAlloc(ro, weightings->data.F32[i],
     247        pmStackData *data = pmStackDataAlloc(ro, weightings->data.F32[i], exposures->data.F32[i],
    251248                                             addVariance ? addVariance->data.F32[i] : NAN);
    252249        data->reject = rejected ? psMemIncrRefCounter(rejected->data[i]) : NULL;
    253250        stack->data[i] = data;
    254     }
    255 
    256     if (!pmStackCombine(outRO, stack, maskVal | maskBad, maskBad, 0,
    257                         iter, combineRej, combineSys, combineDiscard,
    258                         entire, useVariance, safe, !rejected)) {
     251
     252        if (norm) {
     253            float normalise = powf(10.0, -0.4 * norm->data.F32[i]); // Normalisation
     254            psBinaryOp(ro->image, ro->image, "*", psScalarAlloc(normalise, PS_TYPE_F32));
     255            psBinaryOp(ro->variance, ro->variance, "*", psScalarAlloc(PS_SQR(normalise), PS_TYPE_F32));
     256        }
     257    }
     258
     259    if (!pmStackCombine(outRO, expRO, stack, maskVal | maskBad, maskSuspect, maskBad, 0, iter, combineRej,
     260                        combineSys, combineDiscard, useVariance, safe, rejected)) {
    259261        psError(PS_ERR_UNKNOWN, false, "Unable to combine input readouts.");
    260262        psFree(stack);
     
    264266    pmCell *outCell = outRO->parent;    // Output cell
    265267    pmChip *outChip = outCell->parent;  // Output chip
    266 
    267268    outRO->data_exists = true;
    268269    outCell->data_exists = true;
    269270    outChip->data_exists = true;
    270271
     272    pmCell *expCell = expRO->parent;    // Exposure cell
     273    pmChip *expChip = expCell->parent;  // Exposure chip
     274    expRO->data_exists = true;
     275    expCell->data_exists = true;
     276    expChip->data_exists = true;
     277
    271278    psFree(stack);
    272279
  • branches/tap_branches/ppStack/src/ppStackReject.c

    r25466 r27838  
    1010#include "ppStackLoop.h"
    1111
    12 //#define TESTING
     12// #define TESTING
    1313
    1414bool ppStackReject(ppStackOptions *options, pmConfig *config)
     
    2323
    2424    int num = options->num;             // Number of inputs
    25     options->rejected = psArrayAlloc(num);
    2625
    2726    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
     
    3231
    3332    float threshold = psMetadataLookupF32(NULL, recipe, "THRESHOLD.MASK"); // Threshold for mask deconvolution
    34     float poorFrac = psMetadataLookupF32(NULL, recipe, "POOR.FRACTION"); // Fraction for "poor"
    3533    float imageRej = psMetadataLookupF32(NULL, recipe, "IMAGE.REJ"); // Maximum fraction of image to reject
    3634                                                                     // before rejecting entire image
     
    5351        psThreadJob *job = psThreadJobAlloc("PPSTACK_INSPECT"); // Job to start
    5452        psArrayAdd(job->args, 1, options->inspect);
     53        psArrayAdd(job->args, 1, options->rejected);
    5554        PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32);
    5655        if (!psThreadJobAddPending(job)) {
     
    6160    }
    6261    if (!psThreadPoolWait(true)) {
    63         psError(PS_ERR_UNKNOWN, false, "Unable to concatenate inspection lists.");
     62        psError(psErrorCodeLast(), false, "Unable to concatenate inspection lists.");
    6463        return false;
    6564    }
     
    9291#endif
    9392
    94         psPixels *reject = pmStackReject(options->inspect->data[i], options->numCols, options->numRows,
    95                                          threshold, poorFrac, stride, options->regions->data[i],
    96                                          options->kernels->data[i]); // Rejected pixels
    97 
    9893#ifdef TESTING
    9994        {
    100             psImage *mask = psPixelsToMask(NULL, reject,
     95            psImage *mask = psPixelsToMask(NULL, options->rejected->data[i],
    10196                                           psRegionSet(0, options->numCols - 1, 0, options->numRows - 1),
    10297                                           0xff); // Mask image
    10398            psString name = NULL;           // Name of image
    104             psStringAppend(&name, "reject_%03d.fits", i);
     99            psStringAppend(&name, "pre_reject_%03d.fits", i);
    105100            pmStackVisualPlotTestImage(mask, name);
    106101            psFits *fits = psFitsOpen(name, "w");
     
    111106        }
    112107#endif
     108
     109        psPixels *reject = pmStackReject(options->inspect->data[i], options->numCols, options->numRows,
     110                                         threshold, stride, options->regions->data[i],
     111                                         options->kernels->data[i]); // Rejected pixels
    113112
    114113        psFree(options->inspect->data[i]);
     
    127126                          "exceeds limit (%.3f)", i, frac, imageRej);
    128127                psFree(reject);
    129                 // reject == NULL means reject image completely
    130128                reject = NULL;
    131129                options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_BAD;
    132130                numRejected++;
     131            } else {
     132                // Add to list of pixels already rejected
     133                reject = psPixelsConcatenate(reject, options->rejected->data[i]);
     134                options->rejected->data[i] = psPixelsDuplicates(options->rejected->data[i], reject);
    133135            }
    134136        }
    135137
    136         // Images without a list of rejected pixels (the list may be empty) are rejected completely
    137         options->rejected->data[i] = reject;
     138#ifdef TESTING
     139        {
     140            psImage *mask = psPixelsToMask(NULL, options->rejected->data[i],
     141                                           psRegionSet(0, options->numCols - 1, 0, options->numRows - 1),
     142                                           0xff); // Mask image
     143            psString name = NULL;           // Name of image
     144            psStringAppend(&name, "reject_%03d.fits", i);
     145            pmStackVisualPlotTestImage(mask, name);
     146            psFits *fits = psFitsOpen(name, "w");
     147            psFree(name);
     148            psFitsWriteImage(fits, NULL, mask, 0, NULL);
     149            psFree(mask);
     150            psFitsClose(fits);
     151        }
     152#endif
    138153
    139154        if (options->stats) {
     
    143158                             "Number of pixels rejected", reject ? reject->n : 0);
    144159        }
     160
     161        psFree(reject);
    145162        psLogMsg("ppStack", PS_LOG_INFO, "Time to perform rejection on image %d: %f sec", i,
    146163                 psTimerClear("PPSTACK_REJECT"));
     
    148165
    149166    psFree(options->inspect); options->inspect = NULL;
    150     psFree(options->kernels); options->kernels = NULL;
    151     psFree(options->regions); options->regions = NULL;
    152167
    153     if (numRejected >= num - 1) {
    154         psError(PS_ERR_UNKNOWN, true, "All inputs completely rejected; unable to proceed.");
     168    if (numRejected >= num) {
     169        psError(PPSTACK_ERR_REJECTED, true, "All inputs completely rejected; unable to proceed.");
    155170        return false;
    156171    }
  • branches/tap_branches/ppStack/src/ppStackSetup.c

    r23688 r27838  
    2222    psAssert(recipe, "We've thrown an error on this before.");
    2323
     24    // XXX : switch to this name? options->matchZPs = psMetadataLookupBool(NULL, recipe, "MATCH.ZERO.POINTS"); // Adjust zero points based on tranparency analysis?
     25    options->matchZPs = psMetadataLookupBool(NULL, recipe, "ZP"); // Adjust zero points?
     26
     27    options->photometry = psMetadataLookupBool(NULL, recipe, "PHOTOMETRY"); // Perform photometry?
     28
    2429    options->convolve = psMetadataLookupBool(NULL, recipe, "CONVOLVE"); // Convolve images?
    2530    if (!psMetadataLookupBool(NULL, config->arguments, "HAVE.PSF")) {
     
    3742        options->statsFile = fopen(resolved, "w");
    3843        if (!options->statsFile) {
    39             psError(PS_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
     44            psError(PPSTACK_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
    4045            psFree(resolved);
    4146            return false;
     
    4348        psFree(resolved);
    4449        options->stats = psMetadataAlloc();
    45         psMetadataAddS32(options->stats, PS_LIST_TAIL, "QUALITY", 0, "No problems", 0);
    4650    }
    4751
    4852    // Generate temporary names for convolved images
    49     const char *tempDir = psMetadataLookupStr(NULL, recipe, "TEMP.DIR"); // Directory for temporary images
     53    const char *tempDir = psMetadataLookupStr(NULL, config->arguments, "-temp-dir"); // Directory for temps
    5054    if (!tempDir) {
    51         psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find TEMP.DIR in recipe");
     55        tempDir = psMetadataLookupStr(NULL, config->site, "TEMP.DIR");
     56    }
     57    if (!tempDir) {
     58        psError(PPSTACK_ERR_CONFIG, false, "Unable to find TEMP.DIR in site configuration");
    5259        return false;
    5360    }
     
    5764    const char *tempName = basename(outputName);
    5865    if (!tempName) {
    59         psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to construct basename for temporary files.");
     66        psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to construct basename for temporary files.");
    6067        psFree(outputName);
    6168        return false;
     
    6673    const char *tempVariance = psMetadataLookupStr(NULL, recipe, "TEMP.VARIANCE"); // Suffix for var maps
    6774    if (!tempImage || !tempMask || !tempVariance) {
    68         psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     75        psError(PPSTACK_ERR_CONFIG, false,
    6976                "Unable to find TEMP.IMAGE, TEMP.MASK and TEMP.VARIANCE in recipe");
    7077        psFree(outputName);
     
    7279    }
    7380
    74     options->imageNames = psArrayAlloc(num);
    75     options->maskNames = psArrayAlloc(num);
    76     options->varianceNames = psArrayAlloc(num);
     81    options->convImages = psArrayAlloc(num);
     82    options->convMasks = psArrayAlloc(num);
     83    options->convVariances = psArrayAlloc(num);
    7784    for (int i = 0; i < num; i++) {
    7885        psString imageName = NULL, maskName = NULL, varianceName = NULL; // Names for convolved images
     
    8188        psStringAppend(&varianceName, "%s/%s.%d.%s", tempDir, tempName, i, tempVariance);
    8289        psTrace("ppStack", 5, "Temporary files: %s %s %s\n", imageName, maskName, varianceName);
    83         options->imageNames->data[i] = imageName;
    84         options->maskNames->data[i] = maskName;
    85         options->varianceNames->data[i] = varianceName;
     90        options->convImages->data[i] = imageName;
     91        options->convMasks->data[i] = maskName;
     92        options->convVariances->data[i] = varianceName;
    8693    }
    8794    psFree(outputName);
    8895
     96    // Original images
     97    options->origImages = psArrayAlloc(num);
     98    options->origMasks = psArrayAlloc(num);
     99    options->origVariances = psArrayAlloc(num);
     100    pmFPAview *view = pmFPAviewAlloc(0);
     101    for (int i = 0; i < num; i++) {
     102        {
     103            pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", i);
     104            options->origImages->data[i] = pmFPAfileName(file, view, config);
     105        }
     106        {
     107            // We want the convolved mask, since that defines the area that has been tested for outliers
     108            options->origMasks->data[i] = psMemIncrRefCounter(options->convMasks->data[i]);
     109        }
     110        {
     111            pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT.VARIANCE", i);
     112            options->origVariances->data[i] = pmFPAfileName(file, view, config);
     113        }
     114    }
     115    psFree(view);
     116
    89117    if (!pmConfigMaskSetBits(NULL, NULL, config)) {
    90         psError(PS_ERR_UNKNOWN, false, "Unable to determine mask value.");
     118        psError(PPSTACK_ERR_CONFIG, false, "Unable to determine mask value.");
    91119        return false;
    92120    }
  • branches/tap_branches/ppStack/src/ppStackSources.c

    r25313 r27838  
    88
    99//#define TESTING                         // Enable debugging output
     10
     11//#define ASTROMETRY                    // Correct astrometry?
    1012
    1113#ifdef TESTING
     
    6163    PS_ASSERT_PTR_NON_NULL(config, false);
    6264
     65    if (!options->matchZPs && !options->photometry) {
     66        options->norm = psVectorAlloc(options->num, PS_TYPE_F32);
     67        psVectorInit(options->norm, 0.0);
     68        return true;
     69    }
     70
    6371    psArray *sourceLists = options->sourceLists; // Source lists for each input
    6472    psVector *inputMask = options->inputMask; // Mask for inputs
     
    7987            }
    8088            source->psfMag += 1.0;
     89#ifdef ASTROMETRY
     90            if (source->modelPSF) {
     91                source->modelPSF->params->data.F32[PM_PAR_XPOS] += 1.0;
     92                source->modelPSF->params->data.F32[PM_PAR_YPOS] += 1.0;
     93            }
     94            if (source->peak) {
     95                source->peak->xf += 1.0;
     96                source->peak->yf += 1.0;
     97            }
     98#endif
    8199        }
    82100    }
     
    105123    psMetadata *airmassZP = psMetadataLookupMetadata(NULL, recipe, "ZP.AIRMASS"); // Airmass terms
    106124    if (!airmassZP) {
    107         psError(PS_ERR_UNKNOWN, false, "Unable to find ZP.AIRMASS in recipe.");
     125        psError(PPSTACK_ERR_CONFIG, false, "Unable to find ZP.AIRMASS in recipe.");
    108126        return false;
    109127    }
    110 
    111     int num = psMetadataLookupS32(NULL, config->arguments, "INPUTS.NUM"); // Number of inputs
     128    psMetadata *zpTargetMenu = psMetadataLookupMetadata(NULL, recipe, "ZP.TARGET"); // Target zero point terms
     129    if (!zpTargetMenu) {
     130        psError(PPSTACK_ERR_CONFIG, false, "Unable to find ZP.TARGET in recipe.");
     131        return false;
     132    }
     133
     134    int num = options->num;             // Number of inputs
    112135    psAssert(num == sourceLists->n, "Wrong number of source lists: %ld\n", sourceLists->n);
    113136
    114     psVector *zp = psVectorAlloc(num, PS_TYPE_F32); // Zero points for each image
     137    psVector *zp = psVectorAlloc(num, PS_TYPE_F32); // Relative zero points for each image
     138    psVector *zpExp = psVectorAlloc(num, PS_TYPE_F32); // Measured zero points for each image (maybe)
     139    int zpExpNum = 0;                                  // Number of measured zero points
    115140    const char *filter = NULL;          // Filter name
    116141    float airmassTerm = NAN;            // Airmass term
    117     float sumExpTime = 0.0;             // Sum of the exposure time
     142    float zpTarget = NAN;               // Target zero point
     143    int numGoodImages = 0;              // Number of good images
    118144    for (int i = 0; i < num; i++) {
     145        psArray *sources = sourceLists->data[i]; // Source list
     146        if (!sources || sources->n == 0) {
     147            psLogMsg("ppStack", PS_LOG_WARN, "Image %d has no sources for transparency measurement.", i);
     148            options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_CAL;
     149            zp->data.F32[i] = NAN;
     150            continue;
     151        }
     152        numGoodImages++;
     153
    119154        pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", i); // File of interest
    120         pmCell *cell = pmFPAviewThisCell(view, file->fpa); // Cell of interest
    121155
    122156#if defined(TESTING) && 0
     
    135169#endif
    136170
    137 
    138         float exptime = psMetadataLookupF32(NULL, cell->concepts, "CELL.EXPOSURE"); // Exposure time
     171        float exptime = options->exposures->data.F32[i]; // Exposure time
    139172        float airmass = psMetadataLookupF32(NULL, file->fpa->concepts, "FPA.AIRMASS"); // Airmass
    140173        const char *expFilter = psMetadataLookupStr(NULL, file->fpa->concepts, "FPA.FILTER"); // Filter name
     174        zpExp->data.F32[i] = psMetadataLookupF32(NULL, file->fpa->concepts, "FPA.ZP"); // Exposure zero point
     175        psLogMsg("ppStack", PS_LOG_INFO,
     176                 "Image %d: %.2f sec exposure in %s at airmass %.2f with zero point %.2f",
     177                 i, exptime, expFilter, airmass, zpExp->data.F32[i]);
    141178        if (!isfinite(exptime) || exptime == 0 || !isfinite(airmass) || airmass == 0 ||
    142179            !expFilter || strlen(expFilter) == 0) {
    143             psError(PS_ERR_UNEXPECTED_NULL, false,
     180            psError(PPSTACK_ERR_CONFIG, false,
    144181                    "Unable to find exposure time (%f), airmass (%f) or filter (%s)",
    145182                    exptime, airmass, expFilter);
     
    147184            return false;
    148185        }
     186        if (isfinite(zpExp->data.F32[i])) {
     187            zpExp->data.F32[i] += 2.5 * log10(exptime);
     188            zpExpNum++;
     189        }
    149190
    150191        if (!filter) {
    151192            filter = expFilter;
    152             airmassTerm = psMetadataLookupF32(NULL, airmassZP, filter);
    153             if (!isfinite(airmassTerm)) {
    154                 psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     193            bool mdok;
     194            airmassTerm = psMetadataLookupF32(&mdok, airmassZP, filter);
     195            if (!mdok || !isfinite(airmassTerm)) {
     196                psError(PPSTACK_ERR_CONFIG, false,
    155197                        "Unable to find airmass term (ZP.AIRMASS) for filter %s", filter);
    156198                psFree(zp);
    157199                return false;
    158200            }
     201            zpTarget = psMetadataLookupF32(&mdok, zpTargetMenu, filter);
     202            if (!mdok || !isfinite(zpTarget)) {
     203                psError(PPSTACK_ERR_CONFIG, false,
     204                        "Unable to find target zero point (ZP.TARGET) for filter %s", filter);
     205                psFree(zp);
     206                return false;
     207            }
    159208        } else if (strcmp(filter, expFilter) != 0) {
    160             psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Filters don't match: %s vs %s", filter, expFilter);
     209            psError(PPSTACK_ERR_CONFIG, false, "Filters don't match: %s vs %s", filter, expFilter);
    161210            psFree(zp);
    162211            return false;
    163212        }
    164213
    165         zp->data.F32[i] = airmassTerm * airmass - 2.5 * log10(exptime);
    166         sumExpTime += exptime;
    167     }
    168 
    169     options->sumExposure = sumExpTime;
     214        zp->data.F32[i] = airmassTerm * airmass + 2.5 * log10(exptime);
     215    }
     216
     217    if (numGoodImages == 0) {
     218        psLogMsg("ppStack", PS_LOG_WARN, "No images with sources to measure transparency.");
     219        options->quality = PPSTACK_ERR_REJECTED;
     220        psFree(zp);
     221        psFree(zpExp);
     222        return true;
     223    }
     224    if (numGoodImages == 1) {
     225        psArray *sources = NULL;        // Sources
     226        for (int i = 0; i < num && !sources; i++) {
     227            if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
     228                continue;
     229            }
     230            sources = sourceLists->data[i];
     231        }
     232        options->quality = PPSTACK_ERR_REJECTED;
     233        options->sources = psMemIncrRefCounter(sources);
     234        options->norm = psVectorAlloc(num, PS_TYPE_F32);
     235        psVectorInit(options->norm, 1.0);
     236        options->zp = NAN;
     237        psLogMsg("ppStack", PS_LOG_WARN, "Single image with sources --- cannot match transparency.");
     238        psFree(zp);
     239        psFree(zpExp);
     240        return true;
     241    }
     242
     243    if (zpExpNum == numGoodImages) {
     244        for (int i = 0; i < num; i++) {
     245            zp->data.F32[i] = zpExp->data.F32[i];
     246        }
     247    }
    170248
    171249    psArray *matches = pmSourceMatchSources(sourceLists, radius, true); // List of matches
    172250    if (!matches) {
    173         psError(PS_ERR_UNKNOWN, false, "Unable to match sources");
     251        psError(PPSTACK_ERR_DATA, false, "Unable to match sources");
    174252        psFree(zp);
    175253        return false;
     
    180258#endif
    181259
    182     psVector *trans = pmSourceMatchRelphot(matches, zp, tol, iter1, starRej1, starSys1,
    183                                            iter2, starRej2, starSys2, starLimit,
    184                                            transIter, transRej, transThresh); // Transparencies for each image
    185     if (!trans) {
    186         psError(PS_ERR_UNKNOWN, false, "Unable to measure transparencies");
    187         return false;
    188     }
     260    if (options->matchZPs) {
     261        psVector *trans = pmSourceMatchRelphot(matches, zp, tol, iter1, starRej1, starSys1,
     262                                               iter2, starRej2, starSys2, starLimit,
     263                                               transIter, transRej, transThresh); // Transparencies per image
     264        if (!trans) {
     265            psError(PPSTACK_ERR_DATA, false, "Unable to measure transparencies");
     266            return false;
     267        }
     268        for (int i = 0; i < trans->n; i++) {
     269            if (!isfinite(trans->data.F32[i])) {
     270                inputMask->data.U8[i] |= PPSTACK_MASK_CAL;
     271            }
     272        }
     273        // M = m + c0 + c1 * airmass - 2.5log(t) + transparency
     274        // Want sources to have m corresponding to airmass = 1 and t = sumExpTime and transparency = 0
     275        // m_0 + c1 * airmass_0 + 2.5log(t_0) - trans_0 = m_1 + c1 * airmass_1 + 2.5log(t_1) - trans_1
     276        // m_0 = m_1 + zp_1 + trans_1 - c1 * airmass_0 - 2.5log(t_0)
     277        // We don't need to know the magnitude zero point for the filter, since it cancels out
     278        if (options->matchZPs) {
     279            options->norm = psVectorAlloc(num, PS_TYPE_F32);
     280            for (int i = 0; i < num; i++) {
     281                if (inputMask->data.U8[i] || !isfinite(trans->data.F32[i])) {
     282                    continue;
     283                }
     284                psArray *sources = sourceLists->data[i]; // Sources of interest
     285                float magCorr = zp->data.F32[i] + trans->data.F32[i] - 2.5*log10(options->sumExposure);
     286                if (zpExpNum == numGoodImages) {
     287                    // Using measured zero points, so attempt to set target zero point
     288                    magCorr -= zpTarget;
     289                }
     290                options->norm->data.F32[i] = -magCorr;
     291                psLogMsg("ppStack", PS_LOG_INFO,
     292                         "Applying scale correction to image %d: %f mag (%f)\n",
     293                         i, magCorr, trans->data.F32[i]);
     294
     295                for (int j = 0; j < sources->n; j++) {
     296                    pmSource *source = sources->data[j]; // Source of interest
     297                    if (!source) {
     298                        continue;
     299                    }
     300                    source->psfMag -= magCorr;
     301                }
     302            }
     303        }
     304
     305        if (zpExpNum == numGoodImages) {
     306            // Producing image with target zero point
     307            options->zp = zpTarget;
     308        } else {
     309            options->zp = NAN;
     310        }
     311
    189312
    190313#ifdef TESTING
    191     dumpMatches("source_mags.dat", num, matches, zp, trans);
    192 #endif
    193 
    194     for (int i = 0; i < trans->n; i++) {
    195         if (!isfinite(trans->data.F32[i])) {
    196             inputMask->data.U8[i] |= PPSTACK_MASK_CAL;
    197         }
    198     }
    199 
    200     // Save best matches SOMEWHERE for future photometry
    201     // XXX this is a really poor output location; clean up the pmFPAfiles used in ppStack
    202     pmCell *sourcesCell = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT");
    203     psArray *sourcesBest = psArrayAllocEmpty(matches->n);
    204 
    205     // XXX something of a hack: require at least 2 detections or the nominated fraction of the max possible
    206     int minMatches = PS_MAX(2, fracMatch * num);// Minimum number of matches required
    207     for (int i = 0; i < matches->n; i++) {
    208         pmSourceMatch *match = matches->data[i]; // Match of interest
    209         if (match->num < minMatches) {
    210             continue;
    211         }
    212 
    213         // We need to grab a single instance of this source: just take the first available
    214         int image = match->image->data.S32[0]; // Index of image
    215         int index = match->index->data.S32[0]; // Index of source within image
    216         psArray *sources = sourceLists->data[image]; // Sources for image
    217         pmSource *source = sources->data[index]; // Source of interest
    218 
    219         psArrayAdd(sourcesBest, sourcesBest->n, source);
    220     }
    221     psMetadataAdd(sourcesCell->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY | PS_META_REPLACE,
    222                   "psphot sources", sourcesBest);
    223     psLogMsg("ppStack", PS_LOG_INFO, "Selected %ld sources for photometry analysis", sourcesBest->n);
    224     psFree(sourcesBest);
     314        dumpMatches("source_mags.dat", num, matches, zp, trans);
     315#endif
     316        psFree(trans);
     317
     318#ifdef TESTING
     319        // Double check: all transparencies should be zero
     320        {
     321            psArray *matches = pmSourceMatchSources(sourceLists, radius, true); // List of matches
     322            if (!matches) {
     323                psError(PPSTACK_ERR_DATA, false, "Unable to match sources");
     324                psFree(zp);
     325                return false;
     326            }
     327            psVector *trans = pmSourceMatchRelphot(matches, zp, tol, iter1, starRej1, starSys1,
     328                                                   iter2, starRej2, starSys2, starLimit,
     329                                                   transIter, transRej, transThresh); // Transparencies
     330            for (int i = 0; i < num; i++) {
     331                fprintf(stderr, "Transparency of image %d: %f\n", i, trans->data.F32[i]);
     332            }
     333            psFree(trans);
     334            psFree(matches);
     335        }
     336#endif
     337    }
     338
     339    psFree(zp);
     340    psFree(zpExp);
     341
     342#ifdef ASTROMETRY
     343    // Position offsets
     344    {
     345        psArray *offsets = pmSourceMatchRelastro(matches, num, tol, iter1, starRej1,
     346                                                  iter2, starRej2, starLimit); // Shifts for each image
     347        if (!offsets) {
     348            psError(PPSTACK_ERR_DATA, false, "Unable to measure offsets");
     349            return false;
     350        }
     351        for (int i = 0; i < num; i++) {
     352            if (options->inputMask->data.U8[i]) {
     353                continue;
     354            }
     355            psArray *sources = sourceLists->data[i]; // Sources of interest
     356            psVector *offset = offsets->data[i];                      // Offsets for image
     357            float dx = offset->data.F32[0], dy = offset->data.F32[1]; // Offsets to apply
     358            if (!isfinite(dx) || !isfinite(dy)) {
     359                continue;
     360            }
     361            psLogMsg("ppStack", PS_LOG_INFO, "Applying astrometric correction to image %d: %f,%f\n",
     362                     i, dx, dy);
     363            for (int j = 0; j < sources->n; j++) {
     364                pmSource *source = sources->data[j]; // Source of interest
     365                if (!source) {
     366                    continue;
     367                }
     368                if (source->modelPSF) {
     369                    source->modelPSF->params->data.F32[PM_PAR_XPOS] -= dx;
     370                    source->modelPSF->params->data.F32[PM_PAR_YPOS] -= dy;
     371                }
     372                if (source->peak) {
     373                    source->peak->xf -= dx;
     374                    source->peak->yf -= dy;
     375                }
     376            }
     377        }
     378        psFree(offsets);
     379    }
     380#endif
     381
     382#if (defined TESTING && defined ASTROMETRY)
     383        // Double check: all offsets should be zero
     384        {
     385            psArray *matches = pmSourceMatchSources(sourceLists, radius, true); // List of matches
     386            if (!matches) {
     387                psError(PPSTACK_ERR_DATA, false, "Unable to match sources");
     388                psFree(zp);
     389                return false;
     390            }
     391            psArray *offsets = pmSourceMatchRelastro(matches, num, tol, iter1, starRej1,
     392                                                     iter2, starRej2, starLimit); // Shifts for each image
     393            for (int i = 0; i < num; i++) {
     394                psVector *offset = offsets->data[i]; // Offsets for image
     395                fprintf(stderr, "Offset of image %d: %f,%f\n", i, offset->data.F32[0], offset->data.F32[1]);
     396            }
     397            psFree(offsets);
     398            psFree(matches);
     399        }
     400#endif
     401
     402
     403    if (options->photometry) {
     404        // Save best matches for future photometry
     405        psArray *sourcesBest = options->sources = psArrayAllocEmpty(matches->n);
     406
     407        // XXX something of a hack: require at least 2 detections or the nominated fraction of the max possible
     408        int minMatches = PS_MAX(2, fracMatch * num);// Minimum number of matches required
     409        for (int i = 0; i < matches->n; i++) {
     410            pmSourceMatch *match = matches->data[i]; // Match of interest
     411            if (match->num < minMatches) {
     412                continue;
     413            }
     414
     415            // We need to grab a single instance of this source: just take the first available
     416            int image = match->image->data.S32[0]; // Index of image
     417            int index = match->index->data.S32[0]; // Index of source within image
     418            psArray *sources = sourceLists->data[image]; // Sources for image
     419            pmSource *source = sources->data[index]; // Source of interest
     420
     421            psArrayAdd(sourcesBest, sourcesBest->n, source);
     422        }
     423        psLogMsg("ppStack", PS_LOG_INFO, "Selected %ld sources for photometry analysis", sourcesBest->n);
     424    }
    225425
    226426    psFree(matches);
    227 
    228     // M = m + c0 + c1 * airmass - 2.5log(t) + transparency
    229     // Want sources to have m corresponding to airmass = 1 and t = sumExpTime and transparency = 0
    230     // m_0 + c1 * airmass_0 + 2.5log(t_0) - trans_0 = m_1 + c1 * airmass_1 + 2.5log(t_1) - trans_1
    231     // m_0 = m_1 + zp_1 + trans_1 - c1 * airmass_0 - 2.5log(t_0)
    232     // 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);
    234     for (int i = 0; i < num; i++) {
    235         if (!isfinite(trans->data.F32[i])) {
    236             continue;
    237         }
    238         psArray *sources = sourceLists->data[i]; // Sources of interest
    239         float magCorr = airmassTerm - 2.5*log10(sumExpTime) - zp->data.F32[i] - trans->data.F32[i];
    240         options->norm->data.F32[i] = magCorr;
    241         psLogMsg("ppStack", PS_LOG_INFO, "Applying magnitude correction to image %d: %f\n", i, magCorr);
    242 
    243         for (int j = 0; j < sources->n; j++) {
    244             pmSource *source = sources->data[j]; // Source of interest
    245             if (!source) {
    246                 continue;
    247             }
    248             source->psfMag += magCorr;
    249         }
    250     }
    251     psFree(trans);
    252 
    253 #ifdef TESTING
    254     // Double check: all transparencies should be zero
    255     {
    256         psArray *matches = pmSourceMatchSources(sourceLists, radius); // List of matches
    257         if (!matches) {
    258             psError(PS_ERR_UNKNOWN, false, "Unable to match sources");
    259             psFree(zp);
    260             return false;
    261         }
    262         psVector *trans = pmSourceMatchRelphot(matches, zp, iter, tol, starLimit, transIter, transRej,
    263                                                transThresh, starRej, starSys);
    264         for (int i = 0; i < num; i++) {
    265             fprintf(stderr, "Transparency of image %d: %f\n", i, trans->data.F32[i]);
    266         }
    267         psFree(trans);
    268     }
    269 #endif
    270427
    271428    return true;
  • branches/tap_branches/ppStack/src/ppStackThread.c

    r24796 r27838  
    5656}
    5757
    58 ppStackThreadData *ppStackThreadDataSetup(const ppStackOptions *options, const pmConfig *config)
     58ppStackThreadData *ppStackThreadDataSetup(const ppStackOptions *options, const pmConfig *config, bool conv)
    5959{
    6060    psAssert(options, "Require options");
     
    6262
    6363    const psArray *cells = options->cells; // Array of input cells
    64     const psArray *imageNames = options->imageNames; // Names of images to read
    65     const psArray *maskNames = options->maskNames; // Names of masks to read
    66     const psArray *varianceNames = options->varianceNames; // Names of variance maps to read
    67     const psArray *covariances = options->covariances; // Covariance matrices (already read)
     64    const psArray *imageNames = conv ? options->convImages : options->origImages; // Names of images to read
     65    const psArray *maskNames = conv ? options->convMasks : options->origMasks; // Names of masks to read
     66    const psArray *varianceNames = conv ? options->convVariances : options->origVariances; // Variance names
     67    const psArray *covariances = conv ? options->convCovars : options->origCovars; // Covariance matrices
    6868
    6969    PS_ASSERT_ARRAY_NON_NULL(cells, NULL);
    70     PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, imageNames, NULL);
    71     PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, maskNames, NULL);
    72     PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, varianceNames, NULL);
    73     PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, covariances, NULL);
     70    if (imageNames) {
     71        PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, imageNames, NULL);
     72    }
     73    if (maskNames) {
     74        PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, maskNames, NULL);
     75    }
     76    if (varianceNames) {
     77        PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, varianceNames, NULL);
     78    }
     79    if (covariances) {
     80        PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, covariances, NULL);
     81    }
    7482
    7583    ppStackThreadData *stack = psAlloc(sizeof(ppStackThreadData)); // Thread data, to return
     
    8795            continue;
    8896        }
    89         // Resolved names
    90         psString imageResolved = pmConfigConvertFilename(imageNames->data[i], config, false, false);
    91         psString maskResolved = pmConfigConvertFilename(maskNames->data[i], config, false, false);
    92         psString varianceResolved = pmConfigConvertFilename(varianceNames->data[i], config, false, false);
    93         stack->imageFits->data[i] = psFitsOpen(imageResolved, "r");
    94         stack->maskFits->data[i] = psFitsOpen(maskResolved, "r");
    95         stack->varianceFits->data[i] = psFitsOpen(varianceResolved, "r");
    96         psFree(imageResolved);
    97         psFree(maskResolved);
    98         psFree(varianceResolved);
    99         if (!stack->imageFits->data[i] || !stack->maskFits->data[i] || !stack->varianceFits->data[i]) {
    100             psError(PS_ERR_UNKNOWN, false, "Unable to open convolved files %s, %s, %s",
    101                     (char*)imageNames->data[i], (char*)maskNames->data[i], (char*)varianceNames->data[i]);
    102             return NULL;
    103         }
     97
     98// Open an image
     99#define IMAGE_OPEN(NAMES, FITS, INDEX)          \
     100        if (NAMES) { \
     101            psString resolved = pmConfigConvertFilename((NAMES)->data[INDEX], config, false, false); \
     102            (FITS)->data[INDEX] = psFitsOpen(resolved, "r");                            \
     103            if (!(FITS)->data[INDEX]) { \
     104                psError(PPSTACK_ERR_IO, false, "Unable to open file %s", (char*)(NAMES)->data[INDEX]); \
     105                psFree(resolved); \
     106                return NULL; \
     107            } \
     108            psFree(resolved); \
     109        }
     110
     111        IMAGE_OPEN(imageNames, stack->imageFits, i);
     112        IMAGE_OPEN(maskNames, stack->maskFits, i);
     113        IMAGE_OPEN(varianceNames, stack->varianceFits, i);
    104114    }
    105115
     
    116126            }
    117127            pmReadout *ro = pmReadoutAlloc(cell); // Readout for thread
    118             ro->covariance = psMemIncrRefCounter(covariances->data[j]);
     128            if (covariances) {
     129                ro->covariance = psMemIncrRefCounter(covariances->data[j]);
     130            }
    119131            readouts->data[j] = ro;
    120132        }
     
    140152    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // Recipe
    141153    if (!recipe) {
    142         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSTACK_RECIPE);
     154        psError(PPSTACK_ERR_CONFIG, false, "Unable to find recipe %s", PPSTACK_RECIPE);
    143155        return NULL;
    144156    }
    145157    int rows = psMetadataLookupS32(NULL, recipe, "ROWS"); // Number of rows to read per chunk
    146158    if (rows <= 0) {
    147         psError(PS_ERR_BAD_PARAMETER_VALUE, false, "ROWS is not set in the recipe.");
     159        psError(PPSTACK_ERR_CONFIG, false, "ROWS is not set in the recipe.");
    148160        return NULL;
    149161    }
     
    186198                psFits *varianceFits = stack->varianceFits->data[i]; // FITS file for variance
    187199
    188 
    189                 int zMax = 0;
     200                int zMax = 0;
    190201                bool keepReading = false;
    191                 if (pmReadoutMore(ro, imageFits, 0, &zMax, rows, config)) {
     202
     203                if (imageFits && pmReadoutMore(ro, imageFits, 0, &zMax, rows, config)) {
    192204                    keepReading = true;
    193205                    if (!pmReadoutReadChunk(ro, imageFits, 0, NULL, rows, overlap, config)) {
    194                         psError(PS_ERR_IO, false, "Unable to read chunk %d for file PPSTACK.INPUT %d",
     206                        psError(PPSTACK_ERR_IO, false,
     207                                "Unable to read chunk %d for file PPSTACK.INPUT %d",
    195208                                numChunk, i);
    196209                        *status = false;
     
    199212                }
    200213
    201                 if (pmReadoutMoreMask(ro, maskFits, 0, &zMax, rows, config)) {
     214                if (maskFits && pmReadoutMoreMask(ro, maskFits, 0, &zMax, rows, config)) {
    202215                    keepReading = true;
    203216                    if (!pmReadoutReadChunkMask(ro, maskFits, 0, NULL, rows, overlap, config)) {
    204                         psError(PS_ERR_IO, false, "Unable to read chunk %d for file PPSTACK.INPUT.MASK %d",
     217                        psError(PPSTACK_ERR_IO, false,
     218                                "Unable to read chunk %d for file PPSTACK.INPUT.MASK %d",
    205219                                numChunk, i);
    206220                        *status = false;
     
    209223                }
    210224
    211                 if (pmReadoutMoreVariance(ro, varianceFits, 0, &zMax, rows, config)) {
     225                if (varianceFits && pmReadoutMoreVariance(ro, varianceFits, 0, &zMax, rows, config)) {
    212226                    keepReading = true;
    213227                    if (!pmReadoutReadChunkVariance(ro, varianceFits, 0, NULL, rows, overlap, config)) {
    214                         psError(PS_ERR_IO, false,
     228                        psError(PPSTACK_ERR_IO, false,
    215229                                "Unable to read chunk %d for file PPSTACK.INPUT.VARIANCE %d",
    216230                                numChunk, i);
     
    263277
    264278    {
    265         psThreadTask *task = psThreadTaskAlloc("PPSTACK_INSPECT", 2);
     279        psThreadTask *task = psThreadTaskAlloc("PPSTACK_INSPECT", 3);
    266280        task->function = &ppStackInspect;
    267281        psThreadTaskAdd(task);
     
    270284
    271285    {
    272         psThreadTask *task = psThreadTaskAlloc("PPSTACK_FINAL_COMBINE", 3);
     286        psThreadTask *task = psThreadTaskAlloc("PPSTACK_FINAL_COMBINE", 6);
    273287        task->function = &ppStackReadoutFinalThread;
    274288        psThreadTaskAdd(task);
  • branches/tap_branches/ppStack/src/ppStackThread.h

    r23341 r27838  
    3535ppStackThreadData *ppStackThreadDataSetup(
    3636    const ppStackOptions *options,      // Options
    37     const pmConfig *config              // Configuration
     37    const pmConfig *config,             // Configuration
     38    bool conv                           // Use convolved products?
    3839    );
    3940
Note: See TracChangeset for help on using the changeset viewer.