Changeset 23341
- Timestamp:
- Mar 17, 2009, 10:00:02 AM (17 years ago)
- Location:
- trunk/ppStack/src
- Files:
-
- 13 added
- 7 edited
-
Makefile.am (modified) (1 diff)
-
ppStack.c (modified) (1 diff)
-
ppStack.h (modified) (5 diffs)
-
ppStackCleanup.c (added)
-
ppStackCombineFinal.c (added)
-
ppStackCombineInitial.c (added)
-
ppStackConvolve.c (added)
-
ppStackFiles.c (added)
-
ppStackFinish.c (added)
-
ppStackLoop.c (modified) (2 diffs)
-
ppStackLoop.h (added)
-
ppStackOptions.c (added)
-
ppStackOptions.h (added)
-
ppStackPhotometry.c (modified) (5 diffs)
-
ppStackPrepare.c (added)
-
ppStackReadout.c (modified) (3 diffs)
-
ppStackReject.c (added)
-
ppStackSetup.c (added)
-
ppStackThread.c (modified) (4 diffs)
-
ppStackThread.h (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/ppStack/src/Makefile.am
r23229 r23341 17 17 ppStackArguments.c \ 18 18 ppStackCamera.c \ 19 ppStackFiles.c \ 19 20 ppStackLoop.c \ 20 21 ppStackPSF.c \ 21 22 ppStackReadout.c \ 22 ppStackPhotometry.c \23 23 ppStackVersion.c \ 24 24 ppStackMatch.c \ 25 25 ppStackSources.c \ 26 ppStackThread.c 26 ppStackThread.c \ 27 ppStackOptions.c \ 28 ppStackSetup.c \ 29 ppStackPrepare.c \ 30 ppStackConvolve.c \ 31 ppStackCombineInitial.c \ 32 ppStackReject.c \ 33 ppStackCombineFinal.c \ 34 ppStackCleanup.c \ 35 ppStackPhotometry.c \ 36 ppStackFinish.c 27 37 28 38 noinst_HEADERS = \ 29 ppStack.h 39 ppStack.h \ 40 ppStackLoop.h \ 41 ppStackOptions.h \ 42 ppStackThread.h 30 43 31 44 CLEANFILES = *~ -
trunk/ppStack/src/ppStack.c
r23242 r23341 9 9 10 10 #include "ppStack.h" 11 #include "ppStackLoop.h" 11 12 12 13 #define TIMER_NAME "PPSTACK" // Name of timer -
trunk/ppStack/src/ppStack.h
r23195 r23341 1 #ifndef PP _STACK_H2 #define PP _STACK_H1 #ifndef PPSTACK_H 2 #define PPSTACK_H 3 3 4 4 #define PPSTACK_RECIPE "PPSTACK" // Name of the recipe … … 18 18 } ppStackMask; 19 19 20 // Thread for stacking chunks 21 // 22 // Each input file contributes a readout, into which is read a chunk from that file 23 typedef struct { 24 psArray *readouts; // Input readouts to read and stack 25 bool read; // Has the scan been read? 26 bool busy; // Is the scan being processed? 27 int firstScan; // First row of the chunk to be read for this group 28 int lastScan; // Last row of the chunk to be read for this group 29 } ppStackThread; 20 // List of files 21 typedef enum { 22 PPSTACK_FILES_PREPARE, // Files for preparation 23 PPSTACK_FILES_CONVOLVE, // Files for convolution 24 PPSTACK_FILES_COMBINE, // Files for combination 25 PPSTACK_FILES_PHOT // Files for photometry 26 } ppStackFileList; 30 27 31 // Allocator32 ppStackThread *ppStackThreadAlloc(psArray *readouts // Inputs readouts to read and stack33 );34 35 // Data for threads36 typedef struct {37 psArray *threads; // Threads doing stacking38 int lastScan; // Last row that's been read39 psArray *imageFits; // FITS file pointers for images40 psArray *maskFits; // FITS file pointers for masks41 psArray *varianceFits; // FITS file pointers for variances42 } ppStackThreadData;43 44 // Set up thread data45 ppStackThreadData *ppStackThreadDataSetup(const psArray *cells, // Array of input cells46 const psArray *imageNames, // Names of images to read47 const psArray *maskNames, // Names of masks to read48 const psArray *varianceNames, // Names of variance maps to read49 const psArray *covariances, // Covariance matrices (already read)50 const pmConfig *config // Configuration51 );52 53 // Read chunk into the first available file thread54 ppStackThread *ppStackThreadRead(bool *status, // Status of read55 ppStackThreadData *stack, // Stacks available for reading56 pmConfig *config, // Configuration57 int numChunk, // Chunk number (only for interest)58 int overlap // Overlap between subsequent scans59 );60 61 // Initialise the threads62 void ppStackThreadInit(void);63 28 64 29 // Setup command-line arguments … … 73 38 // Parse cameras 74 39 bool ppStackCamera(pmConfig *config // Configuration 75 );76 77 // Loop over the inputs, doing the combination78 bool ppStackLoop(pmConfig *config // Configuration79 40 ); 80 41 … … 127 88 ); 128 89 129 // Perform photometry on stack130 bool ppStackPhotometry(pmConfig *config, // Configuration131 const pmReadout *readout, // Readout to be photometered132 const pmFPAview *view // View to readout133 );134 135 90 // Return software version 136 91 psString ppStackVersion(void); … … 171 126 ); 172 127 128 /// Dump memory debugging information 129 void ppStackMemDump( 130 const char *name ///< Stage name, for inclusion in the output file name 131 ); 132 133 /// Activate/deactivate a list of files 134 void ppStackFileActivation( 135 pmConfig *config, // Configuration 136 ppStackFileList list, // Files to turn on/off 137 bool state // Activation state 138 ); 139 140 // Activate/deactivate a single element for a list 141 void ppStackFileActivationSingle( 142 pmConfig *config, // Configuration 143 ppStackFileList list, // Files to turn on/off 144 bool state, // Activation state 145 int num // Number of file in sequence 146 ); 147 148 /// Iterate down the hierarchy, loading files 149 /// 150 /// We can get away with this simplistic treatment of the FPA hierarchy because we're working on skycells. 151 pmFPAview *ppStackFilesIterateDown( 152 pmConfig *config // Configuration 153 ); 154 155 /// Iterate up the hierarchy, writing files 156 /// 157 /// We can get away with this simplistic treatment of the FPA hierarchy because we're working on skycells. 158 bool ppStackFilesIterateUp( 159 pmConfig *config // Configuration 160 ); 161 162 /// Write an image to a FITS file 163 bool ppStackWriteImage( 164 const char *name, // Name of image 165 psMetadata *header, // Header 166 const psImage *image, // Image 167 pmConfig *config // Configuration 168 ); 169 170 173 171 #endif -
trunk/ppStack/src/ppStackLoop.c
r23259 r23341 4 4 5 5 #include <stdio.h> 6 #include <unistd.h>7 #include <string.h>8 #include <libgen.h>9 6 #include <pslib.h> 10 7 #include <psmodules.h> 11 #include <ppStats.h>12 8 13 9 #include "ppStack.h" 14 15 //#define TESTING 16 17 #define WCS_TOLERANCE 0.001 // Tolerance for WCS 18 #define PIXELS_BUFFER 1024 // Initial size of pixel lists 19 20 // Here follows lists of files for activation/deactivation at various stages. Each must be NULL-terminated. 21 22 // Files required in preparation for convolution 23 static char *prepareFiles[] = { "PPSTACK.INPUT.PSF", "PPSTACK.INPUT.SOURCES", "PPSTACK.TARGET.PSF", NULL }; 24 25 // Files required for the convolution 26 static char *convolveFiles[] = { "PPSTACK.INPUT", "PPSTACK.INPUT.MASK", "PPSTACK.INPUT.VARIANCE", NULL }; 27 28 // Output files for the combination 29 static char *combineFiles[] = { "PPSTACK.OUTPUT", "PPSTACK.OUTPUT.MASK", "PPSTACK.OUTPUT.VARIANCE", 30 "PPSTACK.OUTPUT.JPEG1", "PPSTACK.OUTPUT.JPEG2", NULL }; 31 32 // Files for photometry 33 static char *photFiles[] = { "PSPHOT.INPUT", "PSPHOT.OUTPUT", "PSPHOT.RESID", "PSPHOT.BACKMDL", 34 "PSPHOT.BACKMDL.STDEV", "PSPHOT.BACKGND", "PSPHOT.BACKSUB", 35 "SOURCE.PLOT.MOMENTS", "SOURCE.PLOT.PSFMODEL", "SOURCE.PLOT.APRESID", 36 "PSPHOT.INPUT.CMF", NULL }; 37 38 static void memDump(const char *name) 39 { 40 return; 41 42 static int num = 0; // Counter, to make files unique and give an idea of sequence 43 44 psString filename = NULL; // Name of file 45 psStringAppend(&filename, "memdump_%s_%03d.txt", name, num); 46 FILE *memFile = fopen(filename, "w"); 47 psFree(filename); 48 49 psMemBlock **leaks = NULL; 50 int numLeaks = psMemCheckLeaks(0, &leaks, NULL, true); 51 fprintf(memFile, "# MemBlock Size Source\n"); 52 unsigned long total = 0; // Total memory used 53 for (int i = 0; i < numLeaks; i++) { 54 psMemBlock *mb = leaks[i]; 55 fprintf(memFile, "%12lu\t%12zd\t%s:%d\n", mb->id, mb->userMemorySize, 56 mb->file, mb->lineno); 57 total += mb->userMemorySize; 58 } 59 fclose(memFile); 60 psFree(leaks); 61 62 fprintf(stderr, "Memdump %s %d: Memory use: %ld, sbrk: %p\n", name, num, total, sbrk(0)); 63 num++; 64 } 65 66 67 68 // Activate/deactivate a list of files 69 static void fileActivation(pmConfig *config, // Configuration 70 char **files, // Files to turn on/off 71 bool state // Activation state 72 ) 73 { 74 assert(config); 75 assert(files); 76 77 for (int i = 0; files[i] != NULL; i++) { 78 pmFPAfileActivate(config->files, state, files[i]); 79 } 80 return; 81 } 82 83 // Activate/deactivate a single element for a list 84 static void fileActivationSingle(pmConfig *config, // Configuration 85 char **files, // Files to turn on/off 86 bool state, // Activation state 87 int num // Number of file in sequence 88 ) 89 { 90 assert(config); 91 assert(files); 92 93 for (int i = 0; files[i] != NULL; i++) { 94 pmFPAfileActivateSingle(config->files, state, files[i], num); // Activated file 95 } 96 return; 97 } 98 99 // Iterate down the hierarchy, loading files; we can get away with this because we're working on skycells 100 static pmFPAview *filesIterateDown(pmConfig *config // Configuration 101 ) 102 { 103 assert(config); 104 105 pmFPAview *view = pmFPAviewAlloc(0);// Pointer into FPA hierarchy 106 if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) { 107 return NULL; 108 } 109 view->chip = 0; 110 if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) { 111 return NULL; 112 } 113 view->cell = 0; 114 if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) { 115 return NULL; 116 } 117 view->readout = 0; 118 if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) { 119 return NULL; 120 } 121 return view; 122 } 123 124 // Iterate up the hierarchy, writing files; we can get away with this because we're working on skycells 125 static bool filesIterateUp(pmConfig *config // Configuration 126 ) 127 { 128 assert(config); 129 130 pmFPAview *view = pmFPAviewAlloc(0);// Pointer into FPA hierarchy 131 view->chip = view->cell = view->readout = 0; 132 if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) { 133 return false; 134 } 135 view->readout = -1; 136 if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) { 137 return false; 138 } 139 view->cell = -1; 140 if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) { 141 return false; 142 } 143 view->chip = -1; 144 if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) { 145 return false; 146 } 147 psFree(view); 148 return true; 149 } 150 151 // Write an image to a FITS file 152 static bool writeImage(const char *name, // Name of image 153 psMetadata *header, // Header 154 const psImage *image, // Image 155 pmConfig *config // Configuration 156 ) 157 { 158 assert(name); 159 assert(image); 160 161 psString resolved = pmConfigConvertFilename(name, config, true, true); // Resolved file name 162 psFits *fits = psFitsOpen(resolved, "w"); 163 if (!fits) { 164 psError(PS_ERR_IO, false, "Unable to open FITS file %s to write image.", resolved); 165 psFree(resolved); 166 return false; 167 } 168 if (!psFitsWriteImage(fits, header, image, 0, NULL)) { 169 psError(PS_ERR_IO, false, "Unable to write FITS image %s.", resolved); 170 psFitsClose(fits); 171 psFree(resolved); 172 return false; 173 } 174 psFitsClose(fits); 175 psFree(resolved); 176 return true; 177 } 178 10 #include "ppStackLoop.h" 179 11 180 12 bool ppStackLoop(pmConfig *config) … … 183 15 184 16 psTimerStart("PPSTACK_TOTAL"); 17 psTimerStart("PPSTACK_STEPS"); 185 18 186 psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe 187 psAssert(recipe, "We've thrown an error on this before."); 19 ppStackOptions *options = ppStackOptionsAlloc(); // Options for stacking 188 20 189 bool mdok; // Status of MD lookup 190 bool tempDelete = psMetadataLookupBool(&mdok, recipe, "TEMP.DELETE"); // Delete temporary files? 191 const char *tempDir = psMetadataLookupStr(NULL, recipe, "TEMP.DIR"); // Directory for temporary images 192 if (!tempDir) { 193 psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find TEMP.DIR in recipe"); 21 // Setup 22 psTrace("ppStack", 1, "Setup....\n"); 23 if (!ppStackSetup(options, config)) { 24 psError(PS_ERR_UNKNOWN, false, "Unable to setup."); 25 psFree(options); 26 return false; 27 } 28 psLogMsg("ppStack", PS_LOG_INFO, "Stage 0: Setup: %f sec", psTimerClear("PPSTACK_STEPS")); 29 ppStackMemDump("setup"); 30 31 32 // Preparation for stacking 33 psTrace("ppStack", 1, "Preparation for stacking: merging sources, determining target PSF....\n"); 34 if (!ppStackPrepare(options, config)) { 35 psError(PS_ERR_UNKNOWN, false, "Unable to prepare for stacking."); 36 psFree(options); 37 return false; 38 } 39 psLogMsg("ppStack", PS_LOG_INFO, "Stage 1: Load Sources and Generate Target PSF: %f sec", 40 psTimerClear("PPSTACK_STEPS")); 41 ppStackMemDump("prepare"); 42 43 44 // Convolve inputs 45 psTrace("ppStack", 1, "Convolving inputs to target PSF....\n"); 46 if (!ppStackConvolve(options, config)) { 47 psError(PS_ERR_UNKNOWN, false, "Unable to convolve images."); 48 psFree(options); 49 return false; 50 } 51 psLogMsg("ppStack", PS_LOG_INFO, "Stage 2: Generate Convolutions and Save: %f sec", 52 psTimerClear("PPSTACK_STEPS")); 53 ppStackMemDump("convolve"); 54 55 56 // Start threading 57 ppStackThreadInit(); 58 ppStackThreadData *stack = ppStackThreadDataSetup(options, config); 59 if (!stack) { 60 psError(PS_ERR_IO, false, "Unable to initialise stack threads."); 61 psFree(options); 194 62 return false; 195 63 } 196 64 197 psString outputName = psStringCopy(psMetadataLookupStr(NULL, config->arguments, "OUTPUT")); // Name for temporary files 198 const char *tempName = basename(outputName); 199 if (!tempName) { 200 psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to construct basename for temporary files."); 65 // Initial combination 66 psTrace("ppStack", 1, "Initial stack of convolved images....\n"); 67 if (!ppStackCombineInitial(stack, options, config)) { 68 psError(PS_ERR_UNKNOWN, false, "Unable to perform initial combination."); 69 psFree(stack); 70 psFree(options); 201 71 return false; 202 72 } 73 psLogMsg("ppStack", PS_LOG_INFO, "Stage 2: Generate Convolutions and Save: %f sec", 74 psTimerClear("PPSTACK_STEPS")); 75 ppStackMemDump("convolve"); 76 psLogMsg("ppStack", PS_LOG_INFO, "Stage 4: Make Initial Stack: %f sec", psTimerClear("PPSTACK_STEPS")); 203 77 204 const char *tempImage = psMetadataLookupStr(NULL, recipe, "TEMP.IMAGE"); // Suffix for temporary images 205 const char *tempMask = psMetadataLookupStr(NULL, recipe, "TEMP.MASK"); // Suffix for temporary masks 206 const char *tempVariance = psMetadataLookupStr(NULL, recipe, "TEMP.VARIANCE"); // Suffix for temp variance maps 207 if (!tempImage || !tempMask || !tempVariance) { 208 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 209 "Unable to find TEMP.IMAGE, TEMP.MASK and TEMP.VARIANCE in recipe"); 78 79 // Pixel rejection 80 psTrace("ppStack", 1, "Reject pixels....\n"); 81 if (!ppStackReject(options, config)) { 82 psError(PS_ERR_UNKNOWN, false, "Unable to reject pixels."); 83 psFree(stack); 84 psFree(options); 210 85 return false; 211 86 } 87 psLogMsg("ppStack", PS_LOG_INFO, "Stage 5: Pixel Rejection: %f sec", psTimerClear("PPSTACK_STEPS")); 88 ppStackMemDump("reject"); 212 89 213 float threshold = psMetadataLookupF32(NULL, recipe, "THRESHOLD.MASK"); // Threshold for mask deconvolution214 float imageRej = psMetadataLookupF32(NULL, recipe, "IMAGE.REJ"); // Maximum fraction of image to reject215 // before rejecting entire image216 float poorFrac = psMetadataLookupF32(&mdok, recipe, "POOR.FRACTION"); // Fraction for "poor"217 218 const char *statsName = psMetadataLookupStr(&mdok, config->arguments, "STATS"); // Filename for statistics219 psMetadata *stats = NULL; // Container for statistics220 FILE *statsFile = NULL; // File stream for statistics221 if (statsName && strlen(statsName) > 0) {222 psString resolved = pmConfigConvertFilename(statsName, config, true, true); // Resolved filename223 statsFile = fopen(resolved, "w");224 if (!statsFile) {225 psError(PS_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);226 psFree(resolved);227 return false;228 } else {229 stats = psMetadataAlloc();230 }231 psFree(resolved);232 }233 234 pmFPAfile *output = psMetadataLookupPtr(NULL, config->files, "PPSTACK.OUTPUT"); // Output file235 if (!output) {236 psError(PS_ERR_UNEXPECTED_NULL, false, "Can't find output data!");237 return false;238 }239 int num = psMetadataLookupS32(NULL, config->arguments, "INPUTS.NUM"); // Number of inputs240 241 psMetadata *ppsub = psMetadataLookupMetadata(NULL, config->recipes, "PPSUB"); // PPSUB recipe242 int overlap = 2 * psMetadataLookupS32(NULL, ppsub,243 "KERNEL.SIZE"); // Overlap by kernel size between consecutive scans244 245 if (!pmConfigMaskSetBits(NULL, NULL, config)) {246 psError(PS_ERR_UNKNOWN, false, "Unable to determine mask value.");247 return false;248 }249 250 memDump("start");251 252 psLogMsg("ppStack", PS_LOG_INFO, "Stage 0 : Initialization and Configuration : %f sec", psTimerClear("PPSTACK_STEPS"));253 254 // Preparation iteration: Load the sources, and get a target PSF model255 psTrace("ppStack", 1, "Determining target PSF....\n");256 psArray *sourceLists = psArrayAlloc(num); // Individual lists of sources for matching257 pmPSF *targetPSF = NULL; // Target PSF258 float sumExposure = NAN; // Sum of exposure times259 psVector *inputMask = psVectorAlloc(num, PS_TYPE_VECTOR_MASK); // Mask for inputs260 psVectorInit(inputMask, 0);261 if (psMetadataLookupBool(NULL, config->arguments, "HAVE.PSF")) {262 pmFPAfileActivate(config->files, false, NULL);263 fileActivation(config, prepareFiles, true);264 pmFPAview *view = filesIterateDown(config);265 if (!view) {266 return false;267 }268 269 // Generate list of PSFs270 psMetadataIterator *fileIter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD,271 "^PPSTACK.INPUT$"); // Iterator272 psMetadataItem *fileItem; // Item from iteration273 psArray *psfs = psArrayAlloc(num); // PSFs for PSF envelope274 int numCols = 0, numRows = 0; // Size of image275 int index = 0; // Index for file276 while ((fileItem = psMetadataGetAndIncrement(fileIter))) {277 assert(fileItem->type == PS_DATA_UNKNOWN);278 pmFPAfile *inputFile = fileItem->data.V; // An input file279 pmChip *chip = pmFPAviewThisChip(view, inputFile->fpa); // The chip: holds the PSF280 pmPSF *psf = psMetadataLookupPtr(NULL, chip->analysis, "PSPHOT.PSF"); // PSF281 if (!psf) {282 psError(PS_ERR_UNKNOWN, false, "Unable to find PSF.");283 psFree(view);284 psFree(sourceLists);285 psFree(fileIter);286 psFree(psfs);287 psFree(inputMask);288 return false;289 }290 psfs->data[index] = psMemIncrRefCounter(psf);291 psMetadataRemoveKey(chip->analysis, "PSPHOT.PSF");292 293 pmCell *cell = pmFPAviewThisCell(view, inputFile->fpa); // Cell of interest294 pmHDU *hdu = pmHDUFromCell(cell);295 assert(hdu && hdu->header);296 int naxis1 = psMetadataLookupS32(NULL, hdu->header, "NAXIS1"); // Number of columns297 int naxis2 = psMetadataLookupS32(NULL, hdu->header, "NAXIS2"); // Number of rows298 if (naxis1 <= 0 || naxis2 <= 0) {299 psError(PS_ERR_UNKNOWN, false, "Unable to determine size of image from PSF.");300 psFree(view);301 psFree(sourceLists);302 psFree(fileIter);303 psFree(psfs);304 psFree(inputMask);305 return false;306 }307 if (numCols == 0 && numRows == 0) {308 numCols = naxis1;309 numRows = naxis2;310 }311 312 pmReadout *ro = pmFPAviewThisReadout(view, inputFile->fpa); // Readout with sources313 psArray *sources = psMetadataLookupPtr(NULL, ro->analysis, "PSPHOT.SOURCES"); // Sources314 if (!sources) {315 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find sources in readout.");316 return NULL;317 }318 sourceLists->data[index] = psMemIncrRefCounter(sources);319 320 // Re-do photometry if we don't trust the source lists321 if (psMetadataLookupBool(NULL, recipe, "PHOT")) {322 psTrace("ppStack", 2, "Photometering input %d of %d....\n", index, num);323 pmFPAfileActivate(config->files, false, NULL);324 fileActivationSingle(config, convolveFiles, true, index);325 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", index); // File326 pmFPAview *view = filesIterateDown(config);327 if (!view) {328 psFree(sourceLists);329 psFree(targetPSF);330 psFree(inputMask);331 return false;332 }333 334 pmReadout *ro = pmFPAviewThisReadout(view, file->fpa); // Readout of interest335 336 if (!ppStackInputPhotometry(ro, sources, config)) {337 psError(PS_ERR_UNKNOWN, false, "Unable to do photometry on input sources");338 psFree(sourceLists);339 psFree(targetPSF);340 psFree(inputMask);341 return false;342 }343 344 psFree(view);345 if (!filesIterateUp(config)) {346 psFree(sourceLists);347 psFree(targetPSF);348 psFree(inputMask);349 return false;350 }351 pmFPAfileActivate(config->files, false, NULL);352 fileActivation(config, prepareFiles, true);353 }354 355 index++;356 }357 psFree(fileIter);358 359 // Zero point calibration360 sumExposure = ppStackSourcesTransparency(sourceLists, inputMask, view, config);361 if (!isfinite(sumExposure) || sumExposure <= 0) {362 psError(PS_ERR_UNKNOWN, false, "Unable to calculate transparency differences");363 psFree(sourceLists);364 psFree(targetPSF);365 psFree(inputMask);366 return false;367 }368 369 // Generate target PSF370 targetPSF = ppStackPSF(config, numCols, numRows, psfs, inputMask);371 psFree(psfs);372 if (!targetPSF) {373 psError(PS_ERR_UNKNOWN, false, "Unable to determine output PSF.");374 psFree(sourceLists);375 psFree(view);376 psFree(inputMask);377 return false;378 }379 psMetadataAddPtr(config->arguments, PS_LIST_TAIL, "PSF.TARGET", PS_DATA_UNKNOWN,380 "Target PSF for stack", targetPSF);381 382 pmChip *outChip = pmFPAviewThisChip(view, output->fpa); // Output chip383 psMetadataAddPtr(outChip->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_DATA_UNKNOWN,384 "Target PSF", targetPSF);385 outChip->data_exists = true;386 387 psFree(view);388 if (!filesIterateUp(config)) {389 return false;390 }391 }392 393 psLogMsg("ppStack", PS_LOG_INFO, "Stage 1 : Load Sources and Generate Target PSF : %f sec", psTimerClear("PPSTACK_STEPS"));394 memDump("psf");395 396 psArray *imageNames = psArrayAlloc(num);397 psArray *maskNames = psArrayAlloc(num);398 psArray *varianceNames = psArrayAlloc(num);399 for (int i = 0; i < num; i++) {400 psString imageName = NULL, maskName = NULL, varianceName = NULL; // Names for convolved images401 psStringAppend(&imageName, "%s/%s.%d.%s", tempDir, tempName, i, tempImage);402 psStringAppend(&maskName, "%s/%s.%d.%s", tempDir, tempName, i, tempMask);403 psStringAppend(&varianceName, "%s/%s.%d.%s", tempDir, tempName, i, tempVariance);404 psTrace("ppStack", 5, "Temporary files: %s %s %s\n", imageName, maskName, varianceName);405 imageNames->data[i] = imageName;406 maskNames->data[i] = maskName;407 varianceNames->data[i] = varianceName;408 }409 // Free the outputName that we grabbed above to set up tempName.410 psFree(outputName);411 412 // Generate convolutions and write them to disk413 psTrace("ppStack", 1, "Convolving inputs to target PSF....\n");414 psArray *cells = psArrayAlloc(num); // Cells for convolved images --- a handle for reading again415 psArray *subKernels = psArrayAlloc(num); // Subtraction kernels --- required in the stacking416 psArray *subRegions = psArrayAlloc(num); // Subtraction regions --- required in the stacking417 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator418 int numGood = 0; // Number of good frames419 int numCols = 0, numRows = 0; // Size of image420 psVector *matchChi2 = psVectorAlloc(num, PS_TYPE_F32); // chi^2 for stamps when matching421 psVectorInit(matchChi2, NAN);422 psVector *weightings = psVectorAlloc(num, PS_TYPE_F32); // Combination weightings for images (1/noise^2)423 psVectorInit(weightings, NAN);424 psList *fpaList = psListAlloc(NULL); // List of input FPAs, for concept averaging425 psList *cellList = psListAlloc(NULL); // List of input cells, for concept averaging426 psArray *covariances = psArrayAlloc(num); // Covariance matrices427 for (int i = 0; i < num; i++) {428 if (inputMask->data.U8[i]) {429 continue;430 }431 psTrace("ppStack", 2, "Convolving input %d of %d to target PSF....\n", i, num);432 pmFPAfileActivate(config->files, false, NULL);433 fileActivationSingle(config, convolveFiles, true, i);434 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", i); // File of interest435 pmFPAview *view = filesIterateDown(config);436 if (!view) {437 psFree(sourceLists);438 psFree(targetPSF);439 psFree(rng);440 psFree(inputMask);441 psFree(matchChi2);442 psFree(fpaList);443 psFree(cellList);444 psFree(covariances);445 return false;446 }447 448 pmReadout *readout = pmFPAviewThisReadout(view, file->fpa); // Input readout449 psFree(view);450 451 if (numCols == 0 && numRows == 0) {452 numCols = readout->image->numCols;453 numRows = readout->image->numRows;454 } else if (numCols != readout->image->numCols || numRows != readout->image->numRows) {455 psError(PS_ERR_UNKNOWN, true, "Sizes of input images don't match: %dx%d vs %dx%d",456 readout->image->numCols, readout->image->numRows, numCols, numRows);457 psFree(sourceLists);458 psFree(targetPSF);459 psFree(rng);460 psFree(inputMask);461 psFree(matchChi2);462 psFree(fpaList);463 psFree(cellList);464 psFree(covariances);465 return false;466 }467 468 // Background subtraction, scaling and normalisation is performed automatically by the image matching469 psArray *regions = NULL, *kernels = NULL; // Regions and kernels used in subtraction470 psTimerStart("PPSTACK_MATCH");471 472 if (!ppStackMatch(readout, ®ions, &kernels, &matchChi2->data.F32[i], &weightings->data.F32[i],473 sourceLists->data[i], targetPSF, rng, config)) {474 psErrorStackPrint(stderr, "Unable to match image %d --- ignoring.", i);475 inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PPSTACK_MASK_MATCH;476 psErrorClear();477 continue;478 }479 covariances->data[i] = psMemIncrRefCounter(readout->covariance);480 481 if (stats) {482 pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, readout->analysis,483 PM_SUBTRACTION_ANALYSIS_KERNEL);// Conv kernel484 psMetadataAddF32(stats, PS_LIST_TAIL, "TIME_MATCH", PS_META_DUPLICATE_OK,485 "Time to match PSF", psTimerMark("PPSTACK_MATCH"));486 psMetadataAddF32(stats, PS_LIST_TAIL, "STAMP.MEAN", PS_META_DUPLICATE_OK,487 "Mean deviation for stamps", kernels->mean);488 psMetadataAddF32(stats, PS_LIST_TAIL, "STAMP.RMS", PS_META_DUPLICATE_OK,489 "RMS deviation for stamps", kernels->rms);490 psMetadataAddF32(stats, PS_LIST_TAIL, "STAMP.NUM", PS_META_DUPLICATE_OK,491 "Number of stamps", kernels->numStamps);492 float deconv = psMetadataLookupF32(NULL, readout->analysis,493 PM_SUBTRACTION_ANALYSIS_DECONV_MAX); // Deconvolution fraction494 psMetadataAddF32(stats, PS_LIST_TAIL, "KERNEL.DECONV", PS_META_DUPLICATE_OK,495 "Deconvolution fraction for kernel", deconv);496 psMetadataAddF32(stats, PS_LIST_TAIL, "PPSTACK.WEIGHTING", PS_META_DUPLICATE_OK,497 "Weighting for image", weightings->data.F32[i]);498 }499 psLogMsg("ppStack", PS_LOG_INFO, "Time to match image %d: %f sec", i, psTimerClear("PPSTACK_MATCH"));500 501 subRegions->data[i] = regions;502 subKernels->data[i] = kernels;503 504 // Write the temporary convolved files505 pmHDU *hdu = readout->parent->parent->parent->hdu; // HDU for convolved image506 assert(hdu);507 writeImage(imageNames->data[i], hdu->header, readout->image, config);508 psMetadata *maskHeader = psMetadataCopy(NULL, hdu->header); // Copy of header, for mask509 pmConfigMaskWriteHeader(config, maskHeader);510 writeImage(maskNames->data[i], maskHeader, readout->mask, config);511 psFree(maskHeader);512 psImageCovarianceTransfer(readout->variance, readout->covariance);513 writeImage(varianceNames->data[i], hdu->header, readout->variance, config);514 #ifdef TESTING515 {516 psString name = NULL;517 psStringAppend(&name, "covariance_%d.fits", i);518 writeImage(name, hdu->header, readout->covariance->image, config);519 pmStackVisualPlotTestImage(readout->covariance->image, name);520 psFree(name);521 }522 #endif523 524 pmCell *inCell = readout->parent; // Input cell525 526 psListAdd(cellList, PS_LIST_TAIL, inCell);527 psListAdd(fpaList, PS_LIST_TAIL, inCell->parent->parent);528 529 cells->data[i] = psMemIncrRefCounter(inCell);530 if (!filesIterateUp(config)) {531 psFree(fpaList);532 psFree(cellList);533 psFree(covariances);534 return false;535 }536 numGood++;537 538 memDump("match");539 }540 psFree(sourceLists);541 psFree(targetPSF);542 psFree(rng);543 544 psLogMsg("ppStack", PS_LOG_INFO, "Stage 2 : Generate Convolutions and Save : %f sec", psTimerClear("PPSTACK_STEPS"));545 546 if (numGood == 0) {547 psError(PS_ERR_UNKNOWN, false, "No good images to combine.");548 psFree(subKernels);549 psFree(subRegions);550 psFree(cells);551 psFree(inputMask);552 psFree(matchChi2);553 psFree(fpaList);554 psFree(cellList);555 psFree(covariances);556 return false;557 }558 559 560 // Update concepts for output561 {562 pmFPAview view; // View for output563 view.chip = view.cell = view.readout = 0;564 pmCell *outCell = pmFPAfileThisCell(config->files, &view, "PPSTACK.OUTPUT"); // Output cell565 pmFPA *outFPA = outCell->parent->parent; // Output FPA566 pmConceptsAverageFPAs(outFPA, fpaList);567 pmConceptsAverageCells(outCell, cellList, NULL, NULL, true);568 psFree(fpaList);569 psFree(cellList);570 571 // Update the value of a concept572 #define UPDATE_CONCEPT(SOURCE, NAME, VALUE) { \573 psMetadataItem *item = psMetadataLookup(SOURCE->concepts, NAME); \574 psAssert(item, "Concept should be present"); \575 psAssert(item->type == PS_TYPE_F32, "Concept should be F32"); \576 item->data.F32 = VALUE; \577 }578 579 UPDATE_CONCEPT(outFPA, "FPA.EXPOSURE", sumExposure);580 UPDATE_CONCEPT(outCell, "CELL.EXPOSURE", sumExposure);581 UPDATE_CONCEPT(outCell, "CELL.DARKTIME", NAN);582 }583 584 585 // Reject images out-of-hand on the basis of their match chi^2586 {587 psVector *values = psVectorAllocEmpty(num, PS_TYPE_F32); // Values to sort588 for (int i = 0; i < num; i++) {589 if (inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_ALL) {590 continue;591 }592 values->data.F32[values->n++] = matchChi2->data.F32[i];593 }594 assert(values->n == numGood);595 if (!psVectorSortInPlace(values)) {596 psError(PS_ERR_UNKNOWN, false, "Unable to sort vector.");597 psFree(subKernels);598 psFree(subRegions);599 psFree(cells);600 psFree(inputMask);601 psFree(matchChi2);602 psFree(values);603 psFree(covariances);604 return false;605 }606 float median = numGood % 2 ? values->data.F32[numGood / 2] :607 0.5 * (values->data.F32[numGood / 2 - 1] + values->data.F32[numGood / 2]);608 609 float rms = 0.74 * (values->data.F32[numGood * 3 / 4] -610 values->data.F32[numGood / 4]); // Estimated RMS from interquartile range611 612 psFree(values);613 614 float rej = psMetadataLookupF32(NULL, recipe, "MATCH.REJ"); // Rejection threshold (stdevs)615 if (isfinite(rej)) {616 float thresh = median + rej * rms; // Threshold for rejection617 psLogMsg("ppStack", PS_LOG_INFO, "chi^2 rejection threshold = %f + %f * %f = %f",618 median, rej, rms, thresh);619 620 int numRej = 0; // Number rejected621 numGood = 0; // Number of good images622 for (int i = 0; i < num; i++) {623 if (inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_ALL) {624 continue;625 }626 if (matchChi2->data.F32[i] > thresh) {627 numRej++;628 inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_CHI2;629 psLogMsg("ppStack", PS_LOG_INFO, "Rejecting image %d because of large matching chi^2: %f",630 i, matchChi2->data.F32[i]);631 } else {632 psLogMsg("ppStack", PS_LOG_INFO, "Image %d has matching chi^2: %f",633 i, matchChi2->data.F32[i]);634 numGood++;635 }636 }637 }638 }639 640 if (numGood == 0) {641 psError(PS_ERR_UNKNOWN, false, "No good images to combine.");642 psFree(subKernels);643 psFree(subRegions);644 psFree(cells);645 psFree(inputMask);646 psFree(matchChi2);647 psFree(covariances);648 return false;649 }650 651 #ifdef TESTING652 psTraceSetLevel("psModules.imcombine", 7);653 #endif654 655 psLogMsg("ppStack", PS_LOG_INFO, "Stage 3 : Basic Image Rejection : %f sec", psTimerClear("PPSTACK_STEPS"));656 657 // Start threading658 ppStackThreadInit();659 ppStackThreadData *stack = ppStackThreadDataSetup(cells, imageNames, maskNames, varianceNames,660 covariances, config);661 if (!stack) {662 psError(PS_ERR_IO, false, "Unable to initialise stack threads.");663 psFree(subKernels);664 psFree(subRegions);665 psFree(inputMask);666 psFree(matchChi2);667 psFree(cells);668 psFree(covariances);669 return false;670 }671 672 psTimerStart("PPSTACK_INITIAL");673 674 memDump("preinitial");675 676 // Stack the convolved files677 psTrace("ppStack", 1, "Initial stack of convolved images....\n");678 pmReadout *outRO = NULL; // Output readout679 pmFPAview *view = NULL; // View to readout680 psArray *inspect = NULL; // Array of arrays of pixels to inspect681 {682 int row0, col0; // Offset for readout683 int numCols, numRows; // Size of readout684 ppStackThread *thread = stack->threads->data[0]; // Representative thread685 if (!pmReadoutStackSetOutputSize(&col0, &row0, &numCols, &numRows, thread->readouts)) {686 psError(PS_ERR_UNKNOWN, false, "problem setting output readout size.");687 psFree(subKernels);688 psFree(subRegions);689 psFree(stack);690 psFree(inputMask);691 psFree(matchChi2);692 psFree(cells);693 psFree(covariances);694 return false;695 }696 697 pmFPAfileActivate(config->files, false, NULL);698 fileActivation(config, combineFiles, true);699 view = filesIterateDown(config);700 if (!view) {701 psFree(subKernels);702 psFree(subRegions);703 psFree(stack);704 psFree(inputMask);705 psFree(matchChi2);706 psFree(cells);707 psFree(covariances);708 return false;709 }710 711 pmCell *outCell = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT"); // Output cell712 outRO = pmReadoutAlloc(outCell); // Output readout713 714 psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad715 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels716 if (!pmReadoutStackDefineOutput(outRO, col0, row0, numCols, numRows, true, true, maskBad)) {717 psError(PS_ERR_UNKNOWN, false, "Unable to prepare output.");718 psFree(subKernels);719 psFree(subRegions);720 psFree(stack);721 psFree(inputMask);722 psFree(matchChi2);723 psFree(view);724 psFree(outRO);725 psFree(cells);726 psFree(covariances);727 return false;728 }729 730 psFree(cells);731 732 bool status; // Status of read733 int numChunk; // Number of chunks734 for (numChunk = 0; true; numChunk++) {735 ppStackThread *thread = ppStackThreadRead(&status, stack, config, numChunk, overlap);736 if (!status) {737 // Something went wrong738 psError(PS_ERR_UNKNOWN, false, "Unable to read chunk %d", numChunk);739 psFree(subKernels);740 psFree(subRegions);741 psFree(stack);742 psFree(inputMask);743 psFree(matchChi2);744 psFree(view);745 psFree(outRO);746 psFree(covariances);747 return false;748 }749 if (!thread) {750 // Nothing more to read751 break;752 }753 754 // call: ppStackReadoutInitial(config, outRO, readouts, subRegions, subKernels)755 psThreadJob *job = psThreadJobAlloc("PPSTACK_INITIAL_COMBINE"); // Job to start756 psArrayAdd(job->args, 1, thread);757 psArrayAdd(job->args, 1, config);758 psArrayAdd(job->args, 1, outRO);759 psArrayAdd(job->args, 1, inputMask);760 psArrayAdd(job->args, 1, weightings);761 psArrayAdd(job->args, 1, matchChi2);762 if (!psThreadJobAddPending(job)) {763 psFree(job);764 psFree(subKernels);765 psFree(subRegions);766 psFree(stack);767 psFree(inputMask);768 psFree(weightings);769 psFree(matchChi2);770 psFree(view);771 psFree(outRO);772 psFree(covariances);773 return false;774 }775 psFree(job);776 }777 778 if (!psThreadPoolWait(false)) {779 psError(PS_ERR_UNKNOWN, false, "Unable to do initial combination.");780 psFree(subKernels);781 psFree(subRegions);782 psFree(stack);783 psFree(inputMask);784 psFree(matchChi2);785 psFree(view);786 psFree(outRO);787 psFree(covariances);788 return false;789 }790 791 // Harvest the jobs, gathering the inspection lists792 inspect = psArrayAlloc(num);793 for (int i = 0; i < num; i++) {794 if (inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {795 continue;796 }797 inspect->data[i] = psArrayAllocEmpty(numChunk);798 }799 psThreadJob *job; // Completed job800 while ((job = psThreadJobGetDone())) {801 psAssert(strcmp(job->type, "PPSTACK_INITIAL_COMBINE") == 0,802 "Job has incorrect type: %s", job->type);803 psArray *results = job->results; // Results of job804 for (int i = 0; i < num; i++) {805 if (inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {806 continue;807 }808 inspect->data[i] = psArrayAdd(inspect->data[i], 1, results->data[i]);809 }810 psFree(job);811 }812 813 memDump("initial");814 }815 816 #ifdef TESTING817 writeImage("combined_initial.fits", NULL, outRO->image, config);818 pmStackVisualPlotTestImage(outRO->image, "combined_initial.fits");819 #endif820 821 if (stats) {822 psMetadataAddF32(stats, PS_LIST_TAIL, "TIME_INITIAL", 0,823 "Time to make initial stack", psTimerMark("PPSTACK_INITIAL"));824 }825 psLogMsg("ppStack", PS_LOG_INFO, "Stage 4 : Make Initial Stack : %f sec", psTimerClear("PPSTACK_STEPS"));826 psLogMsg("ppStack", PS_LOG_INFO, "Time to make initial stack: %f sec", psTimerClear("PPSTACK_INITIAL"));827 828 psTimerStart("PPSTACK_REJECT");829 830 // Pixel rejection831 psArray *rejected = psArrayAlloc(num);832 {833 int numRejected = 0; // Number of inputs rejected completely834 835 // Count images rejected out of hand836 for (int i = 0; i < num; i++) {837 if (inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {838 numRejected++;839 }840 }841 842 for (int i = 0; i < num; i++) {843 if (inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {844 continue;845 }846 847 psThreadJob *job = psThreadJobAlloc("PPSTACK_INSPECT"); // Job to start848 psArrayAdd(job->args, 1, inspect);849 PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32);850 if (!psThreadJobAddPending(job)) {851 psFree(job);852 psFree(subKernels);853 psFree(subRegions);854 psFree(stack);855 psFree(inputMask);856 psFree(view);857 psFree(outRO);858 psFree(inspect);859 psFree(rejected);860 psFree(covariances);861 psFree(matchChi2);862 return false;863 }864 psFree(job);865 }866 867 if (!psThreadPoolWait(true)) {868 psError(PS_ERR_UNKNOWN, false, "Unable to concatenate inspection lists.");869 psFree(subKernels);870 psFree(subRegions);871 psFree(stack);872 psFree(inputMask);873 psFree(view);874 psFree(outRO);875 psFree(inspect);876 psFree(rejected);877 psFree(covariances);878 psFree(matchChi2);879 return false;880 }881 882 if (psMetadataLookupS32(NULL, config->arguments, "-threads") > 0) {883 pmStackRejectThreadsInit();884 }885 886 int stride = psMetadataLookupS32(NULL, ppsub, "STRIDE"); // Size of convolution patches887 888 // Reject bad pixels889 for (int i = 0; i < num; i++) {890 if (inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {891 continue;892 }893 psTimerStart("PPSTACK_REJECT");894 895 #ifdef TESTING896 {897 psImage *mask = psPixelsToMask(NULL, inspect->data[i],898 psRegionSet(0, numCols - 1, 0, numRows - 1),899 0xff); // Mask image900 psString name = NULL; // Name of image901 psStringAppend(&name, "inspect_%03d.fits", i);902 pmStackVisualPlotTestImage(mask, name);903 psFits *fits = psFitsOpen(name, "w");904 psFree(name);905 psFitsWriteImage(fits, NULL, mask, 0, NULL);906 psFree(mask);907 psFitsClose(fits);908 }909 #endif910 911 psPixels *reject = pmStackReject(inspect->data[i], numCols, numRows, threshold, poorFrac, stride,912 subRegions->data[i], subKernels->data[i]); // Rejected pixels913 914 #ifdef TESTING915 {916 psImage *mask = psPixelsToMask(NULL, reject, psRegionSet(0, numCols - 1, 0, numRows - 1),917 0xff); // Mask image918 psString name = NULL; // Name of image919 psStringAppend(&name, "reject_%03d.fits", i);920 pmStackVisualPlotTestImage(mask, name);921 psFits *fits = psFitsOpen(name, "w");922 psFree(name);923 psFitsWriteImage(fits, NULL, mask, 0, NULL);924 psFree(mask);925 psFitsClose(fits);926 }927 #endif928 929 psFree(inspect->data[i]);930 inspect->data[i] = NULL;931 932 if (!reject) {933 psWarning("Rejection on image %d didn't work --- reject entire image.", i);934 numRejected++;935 inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PPSTACK_MASK_REJECT;936 } else {937 float frac = reject->n / (float)(numCols * numRows); // Pixel fraction938 psLogMsg("ppStack", PS_LOG_INFO, "%ld pixels rejected from image %d (%.1f%%)",939 reject->n, i, frac * 100.0);940 if (frac > imageRej) {941 psWarning("Image %d rejected completely because rejection fraction (%.3f) "942 "exceeds limit (%.3f)", i, frac, imageRej);943 psFree(reject);944 // reject == NULL means reject image completely945 reject = NULL;946 inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PPSTACK_MASK_BAD;947 numRejected++;948 }949 }950 951 // Images without a list of rejected pixels (the list may be empty) are rejected completely952 rejected->data[i] = reject;953 954 if (stats) {955 psMetadataAddF32(stats, PS_LIST_TAIL, "TIME_REJECT", PS_META_DUPLICATE_OK,956 "Time to perform rejection", psTimerMark("PPSTACK_REJECT"));957 psMetadataAddS32(stats, PS_LIST_TAIL, "REJECT_PIXELS", PS_META_DUPLICATE_OK,958 "Number of pixels rejected", reject ? reject->n : 0);959 }960 psLogMsg("ppStack", PS_LOG_INFO, "Time to perform rejection on image %d: %f sec", i,961 psTimerClear("PPSTACK_REJECT"));962 }963 964 psFree(inspect);965 psFree(subKernels);966 psFree(subRegions);967 968 if (numRejected >= num - 1) {969 psError(PS_ERR_UNKNOWN, true, "All inputs completely rejected; unable to proceed.");970 psFree(stack);971 psFree(rejected);972 psFree(inputMask);973 psFree(view);974 psFree(outRO);975 psFree(covariances);976 psFree(matchChi2);977 return false;978 }979 980 if (stats) {981 psMetadataAddS32(stats, PS_LIST_TAIL, "REJECT_IMAGES", 0,982 "Number of images rejected completely", numRejected);983 }984 }985 986 psLogMsg("ppStack", PS_LOG_INFO, "Stage 5 : Pixel Rejection : %f sec", psTimerClear("PPSTACK_STEPS"));987 psTimerStart("PPSTACK_FINAL");988 989 memDump("reject");990 90 991 91 // Final combination 992 92 psTrace("ppStack", 2, "Final stack of convolved images....\n"); 993 { 994 stack->lastScan = 0; // Reset read 995 bool status; // Status of read 996 for (int numChunk = 0; true; numChunk++) { 997 ppStackThread *thread = ppStackThreadRead(&status, stack, config, numChunk, 0); 998 if (!status) { 999 // Something went wrong 1000 psError(PS_ERR_UNKNOWN, false, "Unable to read chunk %d", numChunk); 1001 psFree(stack); 1002 psFree(rejected); 1003 psFree(inputMask); 1004 psFree(view); 1005 psFree(outRO); 1006 psFree(covariances); 1007 psFree(matchChi2); 1008 return false; 1009 } 1010 if (!thread) { 1011 // Nothing more to read 1012 break; 1013 } 93 if (!ppStackCombineFinal(stack, options, config)) { 94 psError(PS_ERR_UNKNOWN, false, "Unable to perform final combination."); 95 psFree(stack); 96 psFree(options); 97 return false; 98 } 99 psLogMsg("ppStack", PS_LOG_INFO, "Stage 6: Final Stack: %f sec", psTimerClear("PPSTACK_STEPS")); 100 ppStackMemDump("final"); 1014 101 1015 // call: ppStackReadoutFinal(config, outRO, readouts, rejected)1016 psThreadJob *job = psThreadJobAlloc("PPSTACK_FINAL_COMBINE"); // Job to start1017 psArrayAdd(job->args, 1, thread);1018 psArrayAdd(job->args, 1, config);1019 psArrayAdd(job->args, 1, outRO);1020 psArrayAdd(job->args, 1, inputMask);1021 psArrayAdd(job->args, 1, rejected);1022 psArrayAdd(job->args, 1, weightings);1023 psArrayAdd(job->args, 1, matchChi2);1024 if (!psThreadJobAddPending(job)) {1025 psFree(job);1026 psFree(stack);1027 psFree(rejected);1028 psFree(inputMask);1029 psFree(view);1030 psFree(outRO);1031 psFree(covariances);1032 psFree(matchChi2);1033 return false;1034 }1035 psFree(job);1036 }1037 102 1038 if (!psThreadPoolWait(true)) { 1039 psError(PS_ERR_UNKNOWN, false, "Unable to do final combination."); 1040 psFree(stack); 1041 psFree(inputMask); 1042 psFree(rejected); 1043 psFree(view); 1044 psFree(outRO); 1045 psFree(covariances); 1046 psFree(matchChi2); 1047 return false; 1048 } 103 // Clean up 104 psTrace("ppStack", 2, "Cleaning up after combination....\n"); 105 if (!ppStackCombineFinal(stack, options, config)) { 106 psError(PS_ERR_UNKNOWN, false, "Unable to clean up."); 107 psFree(stack); 108 psFree(options); 109 return false; 1049 110 } 111 psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: WCS & JPEGS: %f sec", psTimerClear("PPSTACK_STEPS")); 112 ppStackMemDump("cleanup"); 1050 113 1051 memDump("final");1052 1053 #ifdef TESTING1054 pmStackVisualPlotTestImage(outRO->image, "combined_initial.fits");1055 writeImage("combined_final.fits", NULL, outRO->image, config);1056 #endif1057 1058 // Sum covariance matrices1059 for (int i = 0; i < num; i++) {1060 if (inputMask->data.U8[i]) {1061 psFree(covariances->data[i]);1062 covariances->data[i] = NULL;1063 }1064 }1065 outRO->covariance = psImageCovarianceSum(covariances);1066 psFree(covariances);1067 psFree(matchChi2);1068 1069 if (stats) {1070 psMetadataAddF32(stats, PS_LIST_TAIL, "TIME_FINAL", 0,1071 "Time to make final stack", psTimerMark("PPSTACK_FINAL"));1072 }1073 1074 psLogMsg("ppStack", PS_LOG_INFO, "Stage 6 : Final Stack : %f sec", psTimerClear("PPSTACK_STEPS"));1075 psLogMsg("ppStack", PS_LOG_INFO, "Time to make final stack: %f sec", psTimerClear("PPSTACK_FINAL"));1076 1077 psTrace("ppStack", 2, "Cleaning up after combination....\n");1078 1079 #if 01080 // Ensure masked regions really look masked1081 {1082 psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits for bad1083 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels1084 if (!pmReadoutMaskApply(outRO, maskBad)) {1085 psWarning("Unable to apply mask");1086 }1087 }1088 #endif1089 1090 // Close up1091 bool wcsDone = false; // Have we done the WCS?1092 for (int i = 0; i < num; i++) {1093 if (inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {1094 continue;1095 }1096 1097 ppStackThread *thread = stack->threads->data[0]; // Representative stack1098 pmReadout *inRO = thread->readouts->data[i]; // Template readout1099 if (inRO && !wcsDone) {1100 // Copy astrometry over1101 wcsDone = true;1102 pmHDU *inHDU = pmHDUFromCell(inRO->parent); // Template HDU1103 pmHDU *outHDU = pmHDUFromCell(outRO->parent); // Output HDU1104 pmChip *outChip = outRO->parent->parent; // Output chip1105 pmFPA *outFPA = outChip->parent; // Output FPA1106 if (!outHDU || !inHDU) {1107 psWarning("Unable to find HDU at FPA level to copy astrometry.");1108 } else {1109 if (!pmAstromReadWCS(outFPA, outChip, inHDU->header, 1.0)) {1110 psErrorClear();1111 psWarning("Unable to read WCS astrometry from input FPA.");1112 wcsDone = false;1113 } else {1114 if (!outHDU->header) {1115 outHDU->header = psMetadataAlloc();1116 }1117 if (!pmAstromWriteWCS(outHDU->header, outFPA, outChip, WCS_TOLERANCE)) {1118 psErrorClear();1119 psWarning("Unable to write WCS astrometry to output FPA.");1120 wcsDone = false;1121 }1122 }1123 }1124 }1125 1126 if (tempDelete) {1127 psString imageResolved = pmConfigConvertFilename(imageNames->data[i], config, false, false);1128 psString maskResolved = pmConfigConvertFilename(maskNames->data[i], config, false, false);1129 psString varianceResolved = pmConfigConvertFilename(varianceNames->data[i], config, false, false);1130 if (unlink(imageResolved) == -1 || unlink(maskResolved) == -1 ||1131 unlink(varianceResolved) == -1) {1132 psWarning("Unable to delete temporary files for image %d", i);1133 }1134 psFree(imageResolved);1135 psFree(maskResolved);1136 psFree(varianceResolved);1137 }1138 }1139 psFree(imageNames);1140 psFree(maskNames);1141 psFree(varianceNames);1142 1143 psFree(inputMask);1144 114 psFree(stack); 1145 115 1146 memDump("cleanup");1147 116 1148 // Generate binned JPEGs 1149 { 1150 int bin1 = psMetadataLookupS32(NULL, recipe, "BIN1"); // First binning level 1151 int bin2 = psMetadataLookupS32(NULL, recipe, "BIN2"); // Second binning level 1152 1153 // Target cells 1154 pmCell *cell1 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG1"); 1155 pmCell *cell2 = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT.JPEG2"); 1156 psImageMaskType maskValue = pmConfigMaskGet("BLANK", config); // Bits to mask 1157 1158 pmReadout *ro1 = pmReadoutAlloc(cell1), *ro2 = pmReadoutAlloc(cell2); // Binned readouts 1159 if (!pmReadoutRebin(ro1, outRO, maskValue, bin1, bin1) || !pmReadoutRebin(ro2, ro1, 0, bin2, bin2)) { 1160 psError(PS_ERR_UNKNOWN, false, "Unable to bin output."); 1161 psFree(ro1); 1162 psFree(ro2); 1163 psFree(outRO); 1164 return false; 1165 } 1166 psFree(ro1); 1167 psFree(ro2); 1168 } 1169 1170 psLogMsg("ppStack", PS_LOG_INFO, "Stage 7 : WCS & JPEGS : %f sec", psTimerClear("PPSTACK_STEPS")); 1171 1172 if (psMetadataLookupBool(&mdok, recipe, "PHOTOMETRY")) { 1173 psTrace("ppStack", 1, "Photometering stacked image....\n"); 1174 1175 psTimerStart("PPSTACK_PHOT"); 1176 1177 fileActivation(config, combineFiles, false); 1178 fileActivation(config, photFiles, true); 1179 pmFPAview *photView = filesIterateDown(config); 1180 fileActivation(config, combineFiles, true); 1181 1182 if (!ppStackPhotometry(config, outRO, photView)) { 1183 psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry on output."); 1184 filesIterateUp(config); 1185 psFree(outRO); 1186 psFree(photView); 1187 return false; 1188 } 1189 psFree(photView); 1190 1191 if (stats) { 1192 pmFPAfile *photFile = psMetadataLookupPtr(NULL, config->files, "PSPHOT.INPUT"); // File 1193 pmReadout *photRO = pmFPAviewThisReadout(view, photFile->fpa); // Readout with the sources 1194 psArray *sources = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.SOURCES"); // Sources 1195 psMetadataAddS32(stats, PS_LIST_TAIL, "NUM_SOURCES", 0, "Number of sources detected", sources->n); 1196 psMetadataAddF32(stats, PS_LIST_TAIL, "TIME_PHOT", 0, 1197 "Time to do photometry", psTimerMark("PPSTACK_PHOT")); 1198 } 1199 psLogMsg("ppStack", PS_LOG_INFO, "Time to do photometry: %f sec", psTimerClear("PPSTACK_PHOT")); 1200 } 1201 1202 psLogMsg("ppStack", PS_LOG_INFO, "Stage 8 : Photometry Analysis : %f sec", psTimerClear("PPSTACK_STEPS")); 1203 1204 psThreadPoolFinalize(); 1205 1206 memDump("phot"); 1207 1208 // Statistics on output 1209 if (stats) { 1210 psTrace("ppStack", 1, "Gathering statistics on stacked image....\n"); 1211 psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits for bad 1212 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels 1213 1214 ppStatsFPA(stats, outRO->parent->parent->parent, view, maskBad, config); 1215 } 1216 1217 memDump("stats"); 1218 1219 // Put version information into the header 1220 pmHDU *hdu = pmHDUFromCell(outRO->parent); 1221 if (!hdu) { 1222 psError(PS_ERR_UNKNOWN, false, "Unable to find HDU for output."); 1223 psFree(outRO); 1224 psFree(view); 117 // Photometry 118 psTrace("ppStack", 1, "Photometering stacked image....\n"); 119 if (!ppStackPhotometry(options, config)) { 120 psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry."); 121 psFree(options); 1225 122 return false; 1226 123 } 1227 if (!hdu->header) { 1228 hdu->header = psMetadataAlloc(); 1229 } 1230 ppStackVersionHeader(hdu->header); 124 psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS")); 125 ppStackMemDump("photometry"); 1231 126 1232 psFree(outRO);1233 psFree(view);1234 127 1235 // Write out summary statistics 1236 if (stats) { 1237 psMetadataAddF32(stats, PS_LIST_TAIL, "TIME_STACK", 0, 1238 "Time to do photometry", psTimerClear("PPSTACK_TOTAL")); 1239 1240 const char *statsMDC = psMetadataConfigFormat(stats); 1241 if (!statsMDC || strlen(statsMDC) == 0) { 1242 psError(PS_ERR_IO, false, "Unable to get statistics MDC file.\n"); 1243 } else { 1244 fprintf(statsFile, "%s", statsMDC); 1245 } 1246 psFree((void *)statsMDC); 1247 fclose(statsFile); 1248 1249 psFree(stats); 1250 } 1251 1252 // Write out the output files 1253 if (!filesIterateUp(config)) { 128 // Finish up 129 psTrace("ppStack", 1, "Finishing up....\n"); 130 if (!ppStackFinish(options, config)) { 131 psError(PS_ERR_UNKNOWN, false, "Unable to finish up."); 132 psFree(options); 1254 133 return false; 1255 134 } 135 psLogMsg("ppStack", PS_LOG_INFO, "Stage 9: Final output: %f sec", psTimerClear("PPSTACK_STEPS")); 136 ppStackMemDump("finish"); 1256 137 1257 psLogMsg("ppStack", PS_LOG_INFO, "Stage 9 : Final Output : %f sec", psTimerClear("PPSTACK_STEPS")); 1258 1259 memDump("finish"); 1260 138 psFree(options); 1261 139 return true; 1262 140 } -
trunk/ppStack/src/ppStackPhotometry.c
r23259 r23341 9 9 10 10 #include "ppStack.h" 11 #include "ppStackLoop.h" 11 12 12 #define PHOT_SOURCE_MASK (PM_SOURCE_MODE_FAIL | PM_SOURCE_MODE_SATSTAR | PM_SOURCE_MODE_BLEND | \ 13 PM_SOURCE_MODE_BADPSF | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_SATURATED | \ 14 PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT) // Mask to apply to sources 15 16 bool ppStackInputPhotometry(const pmReadout *ro, const psArray *sources, const pmConfig *config) 13 bool ppStackPhotometry(ppStackOptions *options, pmConfig *config) 17 14 { 18 PM_ASSERT_READOUT_NON_NULL(ro, false);19 PS_ASSERT_ARRAY_NON_NULL(sources, false);15 psAssert(options, "Require options"); 16 psAssert(config, "Require configuration"); 20 17 21 18 psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe … … 23 20 24 21 bool mdok; // Status of MD lookup 25 26 float zpRadius = psMetadataLookupS32(&mdok, recipe, "PHOT.RADIUS"); // Radius for PHOT measurement 27 if (!mdok) { 28 psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.RADIUS in recipe"); 29 return false; 30 } 31 float zpSigma = psMetadataLookupF32(&mdok, recipe, "PHOT.SIGMA"); // Gaussian sigma for photometry 32 if (!mdok) { 33 psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.SIGMA in recipe"); 34 return false; 35 } 36 float zpFrac = psMetadataLookupF32(&mdok, recipe, "PHOT.FRAC"); // Fraction of good pixels for photometry 37 if (!mdok) { 38 psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.FRAC in recipe"); 39 return false; 22 if (!psMetadataLookupBool(&mdok, recipe, "PHOTOMETRY")) { 23 // Nothing to do 24 return true; 40 25 } 41 26 42 psString maskValStr = psMetadataLookupStr(&mdok, recipe, "MASK.VAL"); // Name of bits to mask going in 43 if (!mdok || !maskValStr) { 44 psError(PS_ERR_UNKNOWN, false, "Unable to find MASK.VAL in recipe"); 45 return false; 46 } 47 psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask 27 psTimerStart("PPSTACK_PHOT"); 48 28 49 psImage *image = ro->image, *mask = ro->mask; // Image and mask from readout 29 ppStackFileActivation(config, PPSTACK_FILES_COMBINE, false); 30 ppStackFileActivation(config, PPSTACK_FILES_PHOT, true); 31 pmFPAview *photView = ppStackFilesIterateDown(config); // View to readout 32 ppStackFileActivation(config, PPSTACK_FILES_COMBINE, true); 50 33 51 // Measure background 52 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 53 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics 54 if (!psImageBackground(stats, NULL, image, mask, maskVal, rng)) { 55 psError(PS_ERR_UNKNOWN, false, "Unable to measure background for image"); 56 psFree(stats); 57 psFree(rng); 58 return false; 59 } 60 float bg = stats->robustMedian; // Background level 61 psFree(stats); 62 psFree(rng); 63 64 // Photometer sources 65 int numCols = image->numCols, numRows = image->numRows; // Size of image 66 int numSources = sources->n; // Number of sources 67 int numGood = 0; // Number of good sources 68 float maxMag = -INFINITY; // Maximum magnitude 69 for (int j = 0; j < numSources; j++) { 70 pmSource *source = sources->data[j]; // Source of interest 71 if (source->mode & PHOT_SOURCE_MASK || !isfinite(source->psfMag)) { 72 source->psfMag = NAN; 73 continue; 74 } 75 float x = source->peak->xf, y = source->peak->yf; // Coordinates of source 76 int xCentral = x + 0.5, yCentral = y + 0.5; // Central pixel 77 // Range of integration 78 int xMin = PS_MAX(0, xCentral - zpRadius), xMax = PS_MIN(numCols - 1, xCentral + zpRadius); 79 int yMin = PS_MAX(0, yCentral - zpRadius), yMax = PS_MIN(numRows - 1, yCentral + zpRadius); 80 81 // Integrate 82 double sumImage = 0.0, sumKernel = 0.0; // Sums from integration 83 int numBadPix = 0; // Number of bad pixels 84 for (int v = yMin; v <= yMax; v++) { 85 float dy2 = PS_SQR(y - v); // Distance from centroid 86 for (int u = xMin; u <= xMax; u++) { 87 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[v][u] & maskVal) { 88 numBadPix++; 89 continue; 90 } 91 float dx2 = PS_SQR(x - u); // Distance from centroid 92 double kernel = exp(-0.5 * (dx2 + dy2) / PS_SQR(zpSigma)); // Kernel value 93 sumImage += (image->data.F32[v][u] - bg) * kernel; 94 sumKernel += kernel; 95 } 96 } 97 98 if (numBadPix > zpFrac * M_PI * PS_SQR(zpRadius) || !isfinite(sumImage)) { 99 source->psfMag = NAN; 100 } else { 101 source->psfMag = - 2.5 * log10(sumImage / sumKernel * M_PI * PS_SQR(zpRadius)); 102 if (isfinite(source->psfMag)) { 103 numGood++; 104 maxMag = PS_MAX(maxMag, source->psfMag); 105 } 106 } 107 } 108 psLogMsg("ppStack", PS_LOG_INFO, "Photometered %d good sources in image; max mag %f", numGood, maxMag); 109 110 return true; 111 } 112 113 114 115 bool ppStackPhotometry(pmConfig *config, const pmReadout *readout, const pmFPAview *view) 116 { 117 pmFPAfile *photFile = psMetadataLookupPtr(NULL, config->files, "PSPHOT.INPUT"); 118 pmFPACopy(photFile->fpa, readout->parent->parent->parent); 34 pmFPAfile *photFile = psMetadataLookupPtr(NULL, config->files, "PSPHOT.INPUT"); // File for photometry 35 pmFPACopy(photFile->fpa, options->outRO->parent->parent->parent); 119 36 120 37 if (psMetadataLookupBool(NULL, config->arguments, "-visual")) { … … 122 39 } 123 40 41 #if 0 124 42 // Need to ensure aperture residual is not calculated 125 43 psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PSPHOT_RECIPE); // Recipe … … 131 49 item->data.B = false; 132 50 } 51 #endif 133 52 134 53 // set maskValue and markValue in the psphot recipe 135 54 psImageMaskType maskValue = pmConfigMaskGet("BLANK", config); // Bits to mask 136 55 psImageMaskType markValue = pmConfigMaskGet("MARK.VALUE", config); // Bits to use for marking 137 psMetadataAddImageMask (recipe, PS_LIST_TAIL, "MASK.PSPHOT", PS_META_REPLACE, "Bits to mask", maskValue); 138 psMetadataAddImageMask (recipe, PS_LIST_TAIL, "MARK.PSPHOT", PS_META_REPLACE, "Bits to use for mark", markValue); 56 psMetadataAddImageMask(recipe, PS_LIST_TAIL, "MASK.PSPHOT", PS_META_REPLACE, 57 "Bits to mask", maskValue); 58 psMetadataAddImageMask(recipe, PS_LIST_TAIL, "MARK.PSPHOT", PS_META_REPLACE, 59 "Bits to use for mark", markValue); 139 60 140 // XXX replace with psphotReadoutKnownSources (config, view) 141 // XXX this function requires that we construct the input source list and place it on PSPHOT.INPUT.CMF 142 pmCell *sourcesCell = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT"); 143 psArray *inSources = psMetadataLookupPtr (NULL, sourcesCell->analysis, "PSPHOT.SOURCES"); 61 pmCell *sourcesCell = pmFPAfileThisCell(config->files, photView, "PPSTACK.OUTPUT"); 62 psArray *inSources = psMetadataLookupPtr(NULL, sourcesCell->analysis, "PSPHOT.SOURCES"); 144 63 if (!inSources) { 145 64 psError(PS_ERR_UNKNOWN, false, "Unable to find input sources"); 65 psFree(photView); 146 66 return false; 147 67 } 148 68 149 if (!psphotReadoutKnownSources(config, view, inSources)) {69 if (!psphotReadoutKnownSources(config, photView, inSources)) { 150 70 // Clear the error, so that the output files are written. 151 71 psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry on stacked image."); 72 psFree(photView); 152 73 return false; 153 74 } 75 psFree(photView); 154 76 155 77 if (!pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL") || … … 162 84 pmFPAfileActivate(config->files, false, "PSPHOT.INPUT"); 163 85 86 if (options->stats) { 87 pmReadout *photRO = pmFPAviewThisReadout(photView, photFile->fpa); // Readout with the sources 88 psArray *sources = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.SOURCES"); // Sources 89 psMetadataAddS32(options->stats, PS_LIST_TAIL, "NUM_SOURCES", 0, 90 "Number of sources detected", sources->n); 91 psMetadataAddF32(options->stats, PS_LIST_TAIL, "TIME_PHOT", 0, 92 "Time to do photometry", psTimerMark("PPSTACK_PHOT")); 93 } 94 psLogMsg("ppStack", PS_LOG_INFO, "Time to do photometry: %f sec", psTimerClear("PPSTACK_PHOT")); 95 164 96 return true; 165 97 } -
trunk/ppStack/src/ppStackReadout.c
r21477 r23341 8 8 #include <psphot.h> 9 9 10 #include "ppStackThread.h" 10 11 #include "ppStack.h" 11 12 … … 16 17 psArray *args = job->args; // Arguments 17 18 ppStackThread *thread = args->data[0]; // Thread 18 pmConfig *config = args->data[1]; // Configuration 19 pmReadout *outRO = args->data[2]; // Output readout 20 psVector *mask = args->data[3]; // Mask for inputs 21 psVector *weightings = args->data[4]; // Weightings (1/noise^2) for each image 22 psVector *addVariance = args->data[5]; // Additional variance when rejecting 19 ppStackOptions *options = args->data[1]; // Options 20 pmConfig *config = args->data[2]; // Configuration 21 22 pmReadout *outRO = options->outRO; // Output readout 23 psVector *mask = options->inputMask; // Mask for inputs 24 psVector *weightings = options->weightings; // Weightings (1/noise^2) for each image 25 psVector *addVariance = options->matchChi2; // Additional variance when rejecting 23 26 24 27 psArray *inspect = ppStackReadoutInitial(config, outRO, thread->readouts, mask, … … 37 40 psArray *args = job->args; // Arguments 38 41 ppStackThread *thread = args->data[0]; // Thread 39 pmConfig *config = args->data[1]; // Configuration 40 pmReadout *outRO = args->data[2]; // Output readout 41 psVector *mask = args->data[3]; // Mask for inputs 42 psArray *rejected = args->data[4]; // Rejected pixels 43 psVector *weightings = args->data[5]; // Weighting (1/noise^2) for each image 44 psVector *addVariance = args->data[6]; // Weighting (1/noise^2) for each image 42 ppStackOptions *options = args->data[1]; // Options 43 pmConfig *config = args->data[2]; // Configuration 44 45 pmReadout *outRO = options->outRO; // Output readout 46 psVector *mask = options->inputMask; // Mask for inputs 47 psArray *rejected = options->rejected; // Rejected pixels 48 psVector *weightings = options->weightings; // Weightings (1/noise^2) for each image 49 psVector *addVariance = options->matchChi2; // Additional variance when rejecting 45 50 46 51 bool status = ppStackReadoutFinal(config, outRO, thread->readouts, mask, rejected, -
trunk/ppStack/src/ppStackThread.c
r23190 r23341 9 9 10 10 #include "ppStack.h" 11 #include "ppStackOptions.h" 12 #include "ppStackThread.h" 13 11 14 12 15 #define THREAD_WAIT 10000 // Microseconds to wait if thread is not available … … 53 56 } 54 57 55 ppStackThreadData *ppStackThreadDataSetup(const psArray *cells, const psArray *imageNames, 56 const psArray *maskNames, const psArray *varianceNames, 57 const psArray *covariances, const pmConfig *config) 58 { 58 ppStackThreadData *ppStackThreadDataSetup(const ppStackOptions *options, const pmConfig *config) 59 { 60 psAssert(options, "Require options"); 61 psAssert(config, "Require configuration"); 62 63 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) 68 59 69 PS_ASSERT_ARRAY_NON_NULL(cells, NULL); 60 70 PS_ASSERT_ARRAYS_SIZE_EQUAL(cells, imageNames, NULL); … … 245 255 246 256 { 247 psThreadTask *task = psThreadTaskAlloc("PPSTACK_INITIAL_COMBINE", 6);257 psThreadTask *task = psThreadTaskAlloc("PPSTACK_INITIAL_COMBINE", 3); 248 258 task->function = &ppStackReadoutInitialThread; 249 259 psThreadTaskAdd(task); … … 259 269 260 270 { 261 psThreadTask *task = psThreadTaskAlloc("PPSTACK_FINAL_COMBINE", 7);271 psThreadTask *task = psThreadTaskAlloc("PPSTACK_FINAL_COMBINE", 3); 262 272 task->function = &ppStackReadoutFinalThread; 263 273 psThreadTaskAdd(task);
Note:
See TracChangeset
for help on using the changeset viewer.
