Changeset 26076
- Timestamp:
- Nov 9, 2009, 2:53:12 PM (17 years ago)
- Location:
- trunk
- Files:
-
- 37 edited
-
ippconfig/recipes (modified) (1 prop)
-
ippconfig/recipes/filerules-mef.mdc (modified) (1 diff)
-
ippconfig/recipes/filerules-simple.mdc (modified) (1 diff)
-
ippconfig/recipes/filerules-split.mdc (modified) (1 diff)
-
ippconfig/recipes/ppStack.config (modified) (2 diffs)
-
ippconfig/recipes/ppSub.config (modified) (1 diff)
-
ppStack (modified) (1 prop)
-
ppStack/src/ppStack.h (modified) (2 diffs)
-
ppStack/src/ppStackArguments.c (modified) (3 diffs)
-
ppStack/src/ppStackCamera.c (modified) (3 diffs)
-
ppStack/src/ppStackCleanup.c (modified) (1 diff)
-
ppStack/src/ppStackCombineFinal.c (modified) (3 diffs)
-
ppStack/src/ppStackCombineInitial.c (modified) (5 diffs)
-
ppStack/src/ppStackCombinePrepare.c (modified) (3 diffs)
-
ppStack/src/ppStackConvolve.c (modified) (9 diffs)
-
ppStack/src/ppStackFiles.c (modified) (1 diff)
-
ppStack/src/ppStackLoop.c (modified) (7 diffs)
-
ppStack/src/ppStackLoop.h (modified) (1 diff)
-
ppStack/src/ppStackMatch.c (modified) (8 diffs)
-
ppStack/src/ppStackOptions.c (modified) (4 diffs)
-
ppStack/src/ppStackOptions.h (modified) (2 diffs)
-
ppStack/src/ppStackReadout.c (modified) (13 diffs)
-
ppStack/src/ppStackReject.c (modified) (7 diffs)
-
ppStack/src/ppStackSetup.c (modified) (2 diffs)
-
ppStack/src/ppStackSources.c (modified) (1 diff)
-
ppStack/src/ppStackThread.c (modified) (9 diffs)
-
ppStack/src/ppStackThread.h (modified) (1 diff)
-
ppSub/src/ppSubArguments.c (modified) (1 diff)
-
psModules/src/camera (modified) (1 prop)
-
psModules/src/camera/pmFPAMaskWeight.c (modified) (1 diff)
-
psModules/src/camera/pmFPAMaskWeight.h (modified) (1 diff)
-
psModules/src/camera/pmReadoutFake.c (modified) (1 prop)
-
psModules/src/imcombine/pmStack.c (modified) (23 diffs, 1 prop)
-
psModules/src/imcombine/pmStack.h (modified) (1 diff, 1 prop)
-
psModules/src/objects (modified) (1 prop)
-
psModules/src/objects/pmSourceMatch.c (modified) (18 diffs)
-
psModules/src/objects/pmSourceMatch.h (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/ippconfig/recipes
- Property svn:mergeinfo changed
/branches/pap/ippconfig/recipes merged: 26009-26011
- Property svn:mergeinfo changed
-
trunk/ippconfig/recipes/filerules-mef.mdc
r25997 r26076 263 263 PPSTACK.OUTPUT.MASK OUTPUT {OUTPUT}.mk.fits MASK COMP_MASK FPA TRUE NONE 264 264 PPSTACK.OUTPUT.VARIANCE OUTPUT {OUTPUT}.wt.fits VARIANCE COMP_WT FPA TRUE NONE 265 PPSTACK.UNCONV.MASK OUTPUT {OUTPUT}.unconv.mask.fits MASK COMP_MASK FPA TRUE NONE 266 PPSTACK.UNCONV.VARIANCE OUTPUT {OUTPUT}.unconv.wt.fits VARIANCE COMP_WT FPA TRUE NONE 265 267 PPSTACK.TARGET.PSF OUTPUT {OUTPUT}.target.psf PSF NONE CHIP TRUE NONE 266 268 PPSTACK.CONV.KERNEL OUTPUT {OUTPUT}.{FILE.INDEX}.kernel SUBKERNEL NONE FPA TRUE NONE -
trunk/ippconfig/recipes/filerules-simple.mdc
r25997 r26076 212 212 PPSTACK.OUTPUT.MASK OUTPUT {OUTPUT}.mask.fits MASK NONE FPA TRUE NONE 213 213 PPSTACK.OUTPUT.VARIANCE OUTPUT {OUTPUT}.weight.fits VARIANCE NONE FPA TRUE NONE 214 PPSTACK.UNCONV.MASK OUTPUT {OUTPUT}.unconv.mask.fits MASK COMP_MASK FPA TRUE NONE 215 PPSTACK.UNCONV.VARIANCE OUTPUT {OUTPUT}.unconv.wt.fits VARIANCE COMP_WT FPA TRUE NONE 214 216 PPSTACK.TARGET.PSF OUTPUT {OUTPUT}.target.psf PSF NONE CHIP TRUE NONE 215 217 PPSTACK.CONV.KERNEL OUTPUT {OUTPUT}.{FILE.INDEX}.kernel SUBKERNEL NONE FPA TRUE NONE -
trunk/ippconfig/recipes/filerules-split.mdc
r25997 r26076 229 229 PPSTACK.OUTPUT.MASK OUTPUT {OUTPUT}.mask.fits MASK COMP_MASK FPA TRUE NONE 230 230 PPSTACK.OUTPUT.VARIANCE OUTPUT {OUTPUT}.wt.fits VARIANCE COMP_WT FPA TRUE NONE 231 PPSTACK.UNCONV.MASK OUTPUT {OUTPUT}.unconv.mask.fits MASK COMP_MASK FPA TRUE NONE 232 PPSTACK.UNCONV.VARIANCE OUTPUT {OUTPUT}.unconv.wt.fits VARIANCE COMP_WT FPA TRUE NONE 231 233 PPSTACK.TARGET.PSF OUTPUT {OUTPUT}.target.psf PSF NONE CHIP TRUE NONE 232 234 PPSTACK.CONV.KERNEL OUTPUT {OUTPUT}.{FILE.INDEX}.kernel SUBKERNEL NONE FPA TRUE NONE -
trunk/ippconfig/recipes/ppStack.config
r26020 r26076 2 2 3 3 CONVOLVE BOOL TRUE # Convolve images when stacking? 4 ITER S32 1 # Number of rejection iterations 4 COMBINE.ITER F32 0.5 # Number of rejection iterations per input 5 5 COMBINE.REJ F32 2.5 # Rejection threshold in combination (sigma) 6 COMBINE.SYS F32 0. 03# Relative systematic error in combination6 COMBINE.SYS F32 0.1 # Relative systematic error in combination 7 7 COMBINE.DISCARD F32 0.2 # Discard fraction for Olympic weighted mean 8 MASK.VAL STR MASK.VALUE,CONV.BAD,BURNTOOL # Mask value of input bad pixels 8 MASK.IN STR MASK.VALUE,CONV.BAD # Mask value of input bad pixels 9 MASK.SUSPECT STR SUSPECT,CONV.POOR # Mask value of suspect pixels 9 10 MASK.BAD STR BLANK # Mask value to give bad pixels 10 11 MASK.POOR STR CONV.POOR # Mask value to give poor pixels … … 33 34 PHOT.FRAC F32 0.9 # Minimum fraction of good pixels 34 35 35 ZP.RADIUS F32 1.0 # Radius (pixels) for matching sources36 ZP.RADIUS F32 4.0 # Radius (pixels) for matching sources 36 37 ZP.ITER.1 S32 5 # Iterations for zero point; pass 1 37 38 ZP.ITER.2 S32 1000 # Iterations for zero point; pass 2 -
trunk/ippconfig/recipes/ppSub.config
r26038 r26076 15 15 SYS.ERR F32 0.1 # Relative systematic error in images 16 16 17 MASK. INSTR MASK.VALUE,CONV.BAD # Mask value for input17 MASK.VAL STR MASK.VALUE,CONV.BAD # Mask value for input 18 18 MASK.BAD STR CONV.BAD # Mask value to give bad pixels 19 19 MASK.POOR STR CONV.POOR # Mask value to give poor pixels -
trunk/ppStack
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/ppStack merged eligible /branches/eam_branches/20090522/ppStack merged eligible /branches/eam_branches/20090715/ppStack merged eligible /branches/eam_branches/20090820/ppStack merged eligible /branches/pap/ppStack merged eligible /branches/pap_mops/ppStack 25137-25255
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/ppStack/src/ppStack.h
r23573 r26076 59 59 // Perform stacking on a readout 60 60 // 61 // Returns an array of pixels to inspect for each input image61 // Returns two arrays: pixels to inspect for each input image, and pixels to reject for each input image. 62 62 psArray *ppStackReadoutInitial(const pmConfig *config, // Configuration 63 63 pmReadout *outRO, // Output readout … … 83 83 const psArray *rejected, // Array with pixels rejected in each image 84 84 const psVector *weightings, // Weighting factors for each image 85 const psVector *addVariance // Additional variance for rejection 85 const psVector *addVariance, // Additional variance for rejection 86 bool safety, // Enable safety switch? 87 const psVector *norm // Normalisations to apply 86 88 ); 87 89 -
trunk/ppStack/src/ppStackArguments.c
r23841 r26076 148 148 psMetadataAddStr(arguments, PS_LIST_TAIL, "-stamps", 0, "Stamps file with x,y,flux per line", NULL); 149 149 psMetadataAddStr(arguments, PS_LIST_TAIL, "-stats", 0, "Statistics file", NULL); 150 psMetadataAdd S32(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); 151 151 psMetadataAddF32(arguments, PS_LIST_TAIL, "-combine-rej", 0, 152 152 "Combination rejection thresold (sigma)", NAN); … … 250 250 } 251 251 252 VALUE_ARG_RECIPE_ INT("-iter", "ITER", S32, 0);252 VALUE_ARG_RECIPE_FLOAT("-combine-iter", "COMBINE.ITER", F32); 253 253 VALUE_ARG_RECIPE_FLOAT("-combine-rej", "COMBINE.REJ", F32); 254 254 VALUE_ARG_RECIPE_FLOAT("-combine-sys", "COMBINE.SYS", F32); … … 260 260 VALUE_ARG_RECIPE_FLOAT("-poor-frac", "POOR.FRACTION", F32); 261 261 262 valueArgRecipeStr(arguments, recipe, "-mask-val", "MASK. VAL",recipe);262 valueArgRecipeStr(arguments, recipe, "-mask-val", "MASK.IN", recipe); 263 263 valueArgRecipeStr(arguments, recipe, "-mask-bad", "MASK.BAD", recipe); 264 264 valueArgRecipeStr(arguments, recipe, "-mask-poor", "MASK.POOR", recipe); -
trunk/ppStack/src/ppStackCamera.c
r25519 r26076 233 233 234 234 // Output image 235 pmFPA * fpa= pmFPAConstruct(config->camera, config->cameraName); // FPA to contain the output236 if (! fpa) {235 pmFPA *outFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain the output 236 if (!outFPA) { 237 237 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to construct an FPA from camera configuration."); 238 238 return false; 239 239 } 240 pmFPAfile *output = pmFPAfileDefineOutput(config, fpa, "PPSTACK.OUTPUT");241 psFree( fpa); // Drop reference240 pmFPAfile *output = pmFPAfileDefineOutput(config, outFPA, "PPSTACK.OUTPUT"); 241 psFree(outFPA); // Drop reference 242 242 if (!output) { 243 243 psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT")); … … 250 250 output->save = true; 251 251 252 if (!pmFPAAddSourceFromFormat( fpa, "Stack", output->format)) {252 if (!pmFPAAddSourceFromFormat(outFPA, "Stack", output->format)) { 253 253 psError(PS_ERR_UNKNOWN, false, "Unable to generate output FPA."); 254 psFree(fpa);255 254 return false; 256 255 } … … 294 293 targetPSF->save = true; 295 294 } 295 296 #if 1 297 // Unconvolved stack 298 pmFPA *unconvFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain unconvolved output 299 if (!unconvFPA) { 300 psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to construct an FPA from camera configuration."); 301 return false; 302 } 303 pmFPAfile *unConv = pmFPAfileDefineOutput(config, unconvFPA, "PPSTACK.UNCONV"); 304 psFree(unconvFPA); // Drop reference 305 if (!unConv) { 306 psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.UNCONV")); 307 return false; 308 } 309 if (unConv->type != PM_FPA_FILE_IMAGE) { 310 psError(PS_ERR_IO, true, "PPSTACK.UNCONV is not of type IMAGE"); 311 return false; 312 } 313 unConv->save = true; 314 315 if (!pmFPAAddSourceFromFormat(unconvFPA, "Stack", unConv->format)) { 316 psError(PS_ERR_UNKNOWN, false, "Unable to generate output FPA."); 317 return false; 318 } 319 320 // Unconvolved mask 321 pmFPAfile *unconvMask = pmFPAfileDefineOutput(config, unconvFPA, "PPSTACK.UNCONV.MASK"); 322 if (!unconvMask) { 323 psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.UNCONV.MASK")); 324 return false; 325 } 326 if (unconvMask->type != PM_FPA_FILE_MASK) { 327 psError(PS_ERR_IO, true, "PPSTACK.UNCONV.MASK is not of type MASK"); 328 return false; 329 } 330 unconvMask->save = true; 331 332 // Unconvolved variance 333 if (haveVariances) { 334 pmFPAfile *unconvVariance = pmFPAfileDefineOutput(config, unconvFPA, "PPSTACK.UNCONV.VARIANCE"); 335 if (!unconvVariance) { 336 psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.UNCONV.VARIANCE")); 337 return false; 338 } 339 if (unconvVariance->type != PM_FPA_FILE_VARIANCE) { 340 psError(PS_ERR_IO, true, "PPSTACK.UNCONV.VARIANCE is not of type VARIANCE"); 341 return false; 342 } 343 unconvVariance->save = true; 344 } 345 #endif 296 346 297 347 // Output JPEGs -
trunk/ppStack/src/ppStackCleanup.c
r23341 r26076 74 74 75 75 if (tempDelete) { 76 psString imageResolved = pmConfigConvertFilename(options-> imageNames->data[i],76 psString imageResolved = pmConfigConvertFilename(options->convImages->data[i], 77 77 config, false, false); 78 psString maskResolved = pmConfigConvertFilename(options-> maskNames->data[i],78 psString maskResolved = pmConfigConvertFilename(options->convMasks->data[i], 79 79 config, false, false); 80 psString varianceResolved = pmConfigConvertFilename(options-> varianceNames->data[i],80 psString varianceResolved = pmConfigConvertFilename(options->convVariances->data[i], 81 81 config, false, false); 82 82 if (unlink(imageResolved) == -1 || unlink(maskResolved) == -1 || -
trunk/ppStack/src/ppStackCombineFinal.c
r25096 r26076 10 10 #include "ppStackLoop.h" 11 11 12 bool ppStackCombineFinal(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config) 12 //#define TESTING // Enable test output 13 14 bool ppStackCombineFinal(pmReadout *target, ppStackThreadData *stack, psArray *covariances, 15 ppStackOptions *options, pmConfig *config, bool safe, bool normalise) 13 16 { 14 17 psAssert(stack, "Require stack"); 15 18 psAssert(options, "Require options"); 16 19 psAssert(config, "Require configuration"); 20 21 if (!target->mask) { 22 target->mask = psImageAlloc(target->image->numCols, target->image->numRows, PS_TYPE_IMAGE_MASK); 23 } 17 24 18 25 stack->lastScan = 0; // Reset read … … 30 37 } 31 38 32 // call: ppStackReadoutFinal(config, outRO, readouts, rejected)39 // call: ppStackReadoutFinal(config, target, readouts, rejected) 33 40 psThreadJob *job = psThreadJobAlloc("PPSTACK_FINAL_COMBINE"); // Job to start 41 psArrayAdd(job->args, 1, target); 34 42 psArrayAdd(job->args, 1, thread); 35 43 psArrayAdd(job->args, 1, options); 36 44 psArrayAdd(job->args, 1, config); 45 PS_ARRAY_ADD_SCALAR(job->args, safe, PS_TYPE_U8); 46 PS_ARRAY_ADD_SCALAR(job->args, normalise, PS_TYPE_U8); 37 47 if (!psThreadJobAddPending(job)) { 38 48 psFree(job); … … 48 58 49 59 // 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; 55 continue; 60 if (covariances) { 61 double sumWeights = 0.0; // Sum of weights 62 for (int i = 0; i < options->num; i++) { 63 if (options->inputMask->data.U8[i]) { 64 psFree(covariances->data[i]); 65 covariances->data[i] = NULL; 66 continue; 67 } 68 psKernel *covar = covariances->data[i]; // Covariance matrix 69 if (!covar) { 70 continue; 71 } 72 float weight = options->weightings->data.F32[i]; // Weight to apply 73 psBinaryOp(covar->image, covar->image, "*", psScalarAlloc(weight, PS_TYPE_F32)); 74 sumWeights += weight; 56 75 } 57 psKernel *covar = options->covariances->data[i]; // Covariance matrix 58 if (!covar) { 59 continue; 76 if (sumWeights > 0.0) { 77 target->covariance = psImageCovarianceSum(covariances); 78 psBinaryOp(target->covariance->image, target->covariance->image, "/", 79 psScalarAlloc(sumWeights, PS_TYPE_F32)); 80 psImageCovarianceTransfer(target->variance, target->covariance); 60 81 } 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); 82 } else { 83 target->covariance = psImageCovarianceNone(); 72 84 } 73 85 74 86 #ifdef TESTING 75 pmStackVisualPlotTestImage(outRO->image, "combined_initial.fits"); 76 ppStackWriteImage("combined_final.fits", NULL, outRO->image, config); 87 static int pass = 0; // Pass through 88 psString name = NULL; // Name of file 89 psStringAppend(&name, "combined_image_final_%d.fits", pass); 90 pass++; 91 ppStackWriteImage(name, NULL, target->image, config); 92 psStringSubstitute(&name, "mask", "image"); 93 ppStackWriteImage(name, NULL, target->mask, config); 94 psStringSubstitute(&name, "variance", "mask"); 95 ppStackWriteImage(name, NULL, target->variance, config); 96 psFree(name); 97 98 pmStackVisualPlotTestImage(target->image, "combined_image_final.fits"); 77 99 #endif 78 100 -
trunk/ppStack/src/ppStackCombineInitial.c
r23767 r26076 9 9 #include "ppStack.h" 10 10 #include "ppStackLoop.h" 11 12 //#define TESTING // Enable test output 11 13 12 14 bool ppStackCombineInitial(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config) … … 60 62 // Harvest the jobs, gathering the inspection lists 61 63 options->inspect = psArrayAlloc(options->num); 64 options->rejected = psArrayAlloc(options->num); 62 65 for (int i = 0; i < options->num; i++) { 63 66 if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) { … … 65 68 } 66 69 options->inspect->data[i] = psArrayAllocEmpty(numChunk); 70 options->rejected->data[i] = psArrayAllocEmpty(numChunk); 67 71 } 68 72 psThreadJob *job; // Completed job … … 71 75 "Job has incorrect type: %s", job->type); 72 76 psArray *results = job->results; // Results of job 77 psAssert(results->n == 2, "Results array has wrong size!"); 78 psArray *inspect = results->data[0]; // Pixels to inspect 79 psArray *reject = results->data[1]; // Pixels to reject 73 80 for (int i = 0; i < options->num; i++) { 74 81 if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 75 82 continue; 76 83 } 77 options->inspect->data[i] = psArrayAdd(options->inspect->data[i], 1, results->data[i]); 84 options->inspect->data[i] = psArrayAdd(options->inspect->data[i], 1, inspect->data[i]); 85 options->rejected->data[i] = psArrayAdd(options->rejected->data[i], 1, reject->data[i]); 78 86 } 79 87 psFree(job); … … 83 91 84 92 #ifdef TESTING 85 ppStackWriteImage("combined_initial.fits", NULL, outRO->image, config); 86 pmStackVisualPlotTestImage(outRO->image, "combined_initial.fits"); 93 ppStackWriteImage("combined_image_initial.fits", NULL, options->outRO->image, config); 94 ppStackWriteImage("combined_mask_initial.fits", NULL, options->outRO->mask, config); 95 ppStackWriteImage("combined_variance_initial.fits", NULL, options->outRO->variance, config); 96 97 pmStackVisualPlotTestImage(options->outRO->image, "combined_image_initial.fits"); 87 98 #endif 88 89 psFree(options->matchChi2); options->matchChi2 = NULL;90 91 99 92 100 if (options->stats) { -
trunk/ppStack/src/ppStackCombinePrepare.c
r23576 r26076 33 33 pmCell *outCell = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT"); // Output cell 34 34 options->outRO = pmReadoutAlloc(outCell); // Output readout 35 36 pmCell *unconvCell = pmFPAfileThisCell(config->files, view, "PPSTACK.UNCONV"); // Unconvolved cell 37 options->unconvRO = pmReadoutAlloc(unconvCell); // Unconvolved readout 38 35 39 psFree(view); 36 40 … … 39 43 psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad 40 44 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels 45 41 46 if (!pmReadoutStackDefineOutput(options->outRO, col0, row0, numCols, numRows, true, true, maskBad)) { 42 47 psError(PS_ERR_UNKNOWN, false, "Unable to prepare output."); … … 44 49 } 45 50 51 options->unconvRO->image = psImageCopy(NULL, options->outRO->image, PS_TYPE_F32); 52 // options->unconvRO->mask = psImageCopy(NULL, options->outRO->mask, PS_TYPE_IMAGE_MASK); 53 options->unconvRO->col0 = options->outRO->col0; 54 options->unconvRO->row0 = options->outRO->row0; 55 56 57 46 58 return true; 47 59 } -
trunk/ppStack/src/ppStackConvolve.c
r23602 r26076 9 9 #include "ppStack.h" 10 10 #include "ppStackLoop.h" 11 12 //#define TESTING 13 11 14 12 15 // Update the value of a concept … … 39 42 options->weightings = psVectorAlloc(num, PS_TYPE_F32); // Combination weightings for images (1/noise^2) 40 43 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); 42 49 43 50 psList *fpaList = psListAlloc(NULL); // List of input FPAs, for concept averaging … … 79 86 // Background subtraction, scaling and normalisation is performed automatically by the image matching 80 87 psTimerStart("PPSTACK_MATCH"); 88 options->origCovars->data[i] = psMemIncrRefCounter(readout->covariance); 81 89 if (!ppStackMatch(readout, options, i, config)) { 82 90 psErrorStackPrint(stderr, "Unable to match image %d --- ignoring.", i); … … 85 93 continue; 86 94 } 87 options->covariances->data[i] = psMemIncrRefCounter(readout->covariance); 95 options->convCovars->data[i] = psMemIncrRefCounter(readout->covariance); 96 97 float renorm = psMetadataLookupF32(NULL, readout->analysis, PM_READOUT_ANALYSIS_RENORM); 98 if (!isfinite(renorm)) { 99 renorm = 1.0; 100 } 101 renorms->data.F32[i] = renorm; 88 102 89 103 if (options->stats) { … … 114 128 pmHDU *hdu = readout->parent->parent->parent->hdu; // HDU for convolved image 115 129 assert(hdu); 116 ppStackWriteImage(options-> imageNames->data[i], hdu->header, readout->image, config);130 ppStackWriteImage(options->convImages->data[i], hdu->header, readout->image, config); 117 131 psMetadata *maskHeader = psMetadataCopy(NULL, hdu->header); // Copy of header, for mask 118 132 pmConfigMaskWriteHeader(config, maskHeader); 119 ppStackWriteImage(options-> maskNames->data[i], maskHeader, readout->mask, config);133 ppStackWriteImage(options->convMasks->data[i], maskHeader, readout->mask, config); 120 134 psFree(maskHeader); 121 psImageCovarianceTransfer(readout->variance, readout->covariance); 122 ppStackWriteImage(options->varianceNames->data[i], hdu->header, readout->variance, config); 135 ppStackWriteImage(options->convVariances->data[i], hdu->header, readout->variance, config); 123 136 #ifdef TESTING 124 137 { … … 129 142 psFree(name); 130 143 } 144 { 145 int numCols = readout->image->numCols, numRows = readout->image->numRows; 146 psImage *sn = psImageAlloc(numCols, numRows, PS_TYPE_F32); 147 for (int y = 0; y < numRows; y++) { 148 for (int x = 0; x < numCols; x++) { 149 sn->data.F32[y][x] = readout->image->data.F32[y][x] / 150 sqrtf(readout->variance->data.F32[y][x]); 151 } 152 } 153 psString name = NULL; 154 psStringAppend(&name, "signoise_%d.fits", i); 155 ppStackWriteImage(name, hdu->header, sn, config); 156 psFree(name); 157 psFree(sn); 158 } 131 159 #endif 132 160 … … 149 177 psFree(rng); 150 178 151 psFree(options->norm); options->norm = NULL;152 179 psFree(options->sourceLists); options->sourceLists = NULL; 153 180 psFree(options->psf); options->psf = NULL; … … 211 238 numGood = 0; // Number of good images 212 239 for (int i = 0; i < num; i++) { 213 if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_ALL) {240 if (options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PPSTACK_MASK_ALL) { 214 241 continue; 215 242 } … … 233 260 } 234 261 262 // Correct chi^2 for renormalisation 263 psBinaryOp(options->matchChi2, options->matchChi2, "/", renorms); 264 for (int i = 0; i < num; i++) { 265 psLogMsg("ppStack", PS_LOG_INFO, "Additional variance for image %d: %f\n", 266 i, options->matchChi2->data.F32[i]); 267 } 268 psFree(renorms); 269 235 270 return true; 236 271 } -
trunk/ppStack/src/ppStackFiles.c
r23357 r26076 22 22 /// Output files for the combination 23 23 static char *filesCombine[] = { "PPSTACK.OUTPUT", "PPSTACK.OUTPUT.MASK", "PPSTACK.OUTPUT.VARIANCE", 24 "PPSTACK.UNCONV", "PPSTACK.UNCONV.MASK", "PPSTACK.UNCONV.VARIANCE", 24 25 "PPSTACK.OUTPUT.JPEG1", "PPSTACK.OUTPUT.JPEG2", NULL }; 25 26 -
trunk/ppStack/src/ppStackLoop.c
r25738 r26076 56 56 // Start threading 57 57 ppStackThreadInit(); 58 ppStackThreadData *stack = ppStackThreadDataSetup(options, config );58 ppStackThreadData *stack = ppStackThreadDataSetup(options, config, true); 59 59 if (!stack) { 60 60 psError(PS_ERR_IO, false, "Unable to initialise stack threads."); … … 62 62 return false; 63 63 } 64 psFree(options->cells); options->cells = NULL;65 64 66 65 // Prepare for combination … … 98 97 // Final combination 99 98 psTrace("ppStack", 2, "Final stack of convolved images....\n"); 100 if (!ppStackCombineFinal( stack, options, config)) {99 if (!ppStackCombineFinal(options->outRO, stack, options->convCovars, options, config, false, false)) { 101 100 psError(PS_ERR_UNKNOWN, false, "Unable to perform final combination."); 102 101 psFree(stack); … … 106 105 psLogMsg("ppStack", PS_LOG_INFO, "Stage 5: Final Stack: %f sec", psTimerClear("PPSTACK_STEPS")); 107 106 ppStackMemDump("final"); 108 109 107 110 108 // Clean up … … 121 119 psFree(stack); 122 120 121 #if 1 122 // Unconvolved stack --- it's cheap to calculate, compared to everything else! 123 if (options->convolve) { 124 // Start threading 125 ppStackThreadData *stack = ppStackThreadDataSetup(options, config, false); 126 if (!stack) { 127 psError(PS_ERR_IO, false, "Unable to initialise stack threads."); 128 psFree(options); 129 return false; 130 } 131 psTrace("ppStack", 2, "Stack of unconvolved images....\n"); 132 if (!ppStackCombineFinal(options->unconvRO, stack, options->origCovars, options, config, false, true)) { 133 psError(PS_ERR_UNKNOWN, false, "Unable to perform unconvolved combination."); 134 psFree(stack); 135 psFree(options); 136 return false; 137 } 138 psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: Unconvolved Stack: %f sec", psTimerClear("PPSTACK_STEPS")); 139 ppStackMemDump("unconv"); 140 141 psFree(stack); 142 } 143 psFree(options->cells); options->cells = NULL; 144 #endif 123 145 124 146 // Photometry … … 129 151 return false; 130 152 } 131 psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS"));153 psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS")); 132 154 ppStackMemDump("photometry"); 133 134 155 135 156 // Finish up … … 140 161 return false; 141 162 } 142 psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Final output: %f sec", psTimerClear("PPSTACK_STEPS"));163 psLogMsg("ppStack", PS_LOG_INFO, "Stage 9: Final output: %f sec", psTimerClear("PPSTACK_STEPS")); 143 164 ppStackMemDump("finish"); 144 165 145 166 psFree(options); 167 146 168 return true; 147 169 } -
trunk/ppStack/src/ppStackLoop.h
r23576 r26076 56 56 // Final combination 57 57 bool ppStackCombineFinal( 58 pmReadout *target, // Target readout 58 59 ppStackThreadData *stack, // Stack 60 psArray *covariances, // Covariances 59 61 ppStackOptions *options, // Options 60 pmConfig *config // Configuration 62 pmConfig *config, // Configuration 63 bool safe, // Allow safe combination? 64 bool norm // Normalise images? 61 65 ); 62 66 -
trunk/ppStack/src/ppStackMatch.c
r26074 r26076 167 167 ) 168 168 { 169 #if 1 169 170 bool mdok; // Status of metadata lookups 170 171 … … 192 193 psImageMaskType maskBad = pmConfigMaskGet("BLANK", config); // Bits to mask 193 194 195 psImageCovarianceTransfer(readout->variance, readout->covariance); 194 196 return pmReadoutVarianceRenormalise(readout, maskBad, num, minValid, maxValid); 197 #else 198 return true; 199 #endif 195 200 } 196 201 … … 212 217 int size = psMetadataLookupS32(NULL, ppsub, "KERNEL.SIZE"); // Kernel half-size 213 218 214 psString maskValStr = psMetadataLookupStr(NULL, recipe, "MASK.VAL"); // Name of bits to mask going in219 psString maskValStr = psMetadataLookupStr(NULL, ppsub, "MASK.VAL"); // Name of bits to mask going in 215 220 psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch 216 221 psString maskPoorStr = psMetadataLookupStr(NULL, recipe, "MASK.POOR"); // Name of bits to mask for poor … … 257 262 psFitsClose(fits); 258 263 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)) {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)) { 262 267 psError(PS_ERR_IO, false, "Unable to read previously produced image."); 263 268 return false; … … 378 383 } 379 384 #endif 385 386 fprintf(stderr, "vf = %f\n", psImageCovarianceFactor(readout->covariance)); 387 380 388 381 389 if (threads > 0) { … … 517 525 psFree(iter); 518 526 options->matchChi2->data.F32[index] = sum / (psImageCovarianceFactor(readout->covariance) * num); 527 fprintf(stderr, "chi2 = %f ; vf = %f\n", sum/num, psImageCovarianceFactor(readout->covariance)); 519 528 } 520 529 … … 543 552 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 544 553 if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) { 545 psWarning("Can't measure background for image.");546 psErrorClear();554 psWarning("Can't measure background for image."); 555 psErrorClear(); 547 556 } else { 548 if (!psMetadataLookupBool(NULL, config->arguments, "PPSTACK.SKIP.BG.SUB")) {549 psLogMsg("ppStack", PS_LOG_INFO, "Correcting convolved image background by %lf (+/- %lf)",550 psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN), psStatsGetValue(bg, PS_STAT_ROBUST_STDEV));551 (void)psBinaryOp(readout->image, readout->image, "-",552 psScalarAlloc(psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN), PS_TYPE_F32));553 }557 if (!psMetadataLookupBool(NULL, config->arguments, "PPSTACK.SKIP.BG.SUB")) { 558 psLogMsg("ppStack", PS_LOG_INFO, "Correcting convolved image background by %lf (+/- %lf)", 559 psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN), psStatsGetValue(bg, PS_STAT_ROBUST_STDEV)); 560 (void)psBinaryOp(readout->image, readout->image, "-", 561 psScalarAlloc(psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN), PS_TYPE_F32)); 562 } 554 563 } 555 564 … … 569 578 options->weightings->data.F32[index] = 1.0 / (psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN) * 570 579 psImageCovarianceFactor(readout->covariance)); 580 psLogMsg("ppStack", PS_LOG_INFO, "Weighting for image %d is %f\n", 581 index, options->weightings->data.F32[index]); 571 582 psMetadataAddF32(readout->analysis, PS_LIST_TAIL, "PPSTACK.WEIGHTING", 0, 572 583 "Weighting by 1/noise^2 for stack", options->weightings->data.F32[index]); -
trunk/ppStack/src/ppStackOptions.c
r23573 r26076 12 12 fclose(options->statsFile); 13 13 } 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); 17 21 psFree(options->psf); 18 22 psFree(options->inputMask); … … 24 28 psFree(options->matchChi2); 25 29 psFree(options->weightings); 26 psFree(options->co variances);30 psFree(options->convCovars); 27 31 psFree(options->outRO); 32 psFree(options->unconvRO); 28 33 psFree(options->inspect); 29 34 psFree(options->rejected); … … 39 44 options->stats = NULL; 40 45 options->statsFile = NULL; 41 options->imageNames = NULL; 42 options->maskNames = NULL; 43 options->varianceNames = NULL; 46 options->origImages = NULL; 47 options->origMasks = NULL; 48 options->origVariances = NULL; 49 options->origCovars = NULL; 50 options->convImages = NULL; 51 options->convMasks = NULL; 52 options->convVariances = NULL; 44 53 options->num = 0; 45 54 options->psf = NULL; … … 54 63 options->matchChi2 = NULL; 55 64 options->weightings = NULL; 56 options->co variances = NULL;65 options->convCovars = NULL; 57 66 options->outRO = NULL; 67 options->unconvRO = NULL; 58 68 options->inspect = NULL; 59 69 options->rejected = NULL; -
trunk/ppStack/src/ppStackOptions.h
r23573 r26076 11 11 psMetadata *stats; // Statistics for output 12 12 FILE *statsFile; // File to which to write statistics 13 psArray *imageNames, *maskNames, *varianceNames; // Filenames for the temporary convolved images 13 psArray *origImages, *origMasks, *origVariances; // Filenames of the original images 14 psArray *convImages, *convMasks, *convVariances; // Filenames for the temporary convolved images 15 psArray *origCovars; // Original covariances matrices 14 16 int num; // Number of inputs 15 17 // Prepare … … 26 28 psVector *matchChi2; // chi^2 for stamps from matching 27 29 psVector *weightings; // Combination weightings for images (1/noise^2) 28 psArray *co variances; // Covariance matrices30 psArray *convCovars; // Convolved covariance matrices 29 31 // Combine initial 30 32 pmReadout *outRO; // Output readout 33 pmReadout *unconvRO; // Unconvolved readout 31 34 psArray *inspect; // Array of arrays of pixels to inspect 32 35 // Rejection -
trunk/ppStack/src/ppStackReadout.c
r23577 r26076 25 25 psVector *addVariance = options->matchChi2; // Additional variance when rejecting 26 26 27 psArray *inspect = ppStackReadoutInitial(config, outRO, thread->readouts, mask, 28 weightings, addVariance); 29 30 job->results = inspect; 27 job->results = ppStackReadoutInitial(config, outRO, thread->readouts, mask, 28 weightings, addVariance); 31 29 thread->busy = false; 32 30 33 return inspect? true : false;31 return job->results ? true : false; 34 32 } 35 33 … … 39 37 40 38 psArray *args = job->args; // Arguments 41 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 39 pmReadout *target = args->data[0]; // Output readout 40 ppStackThread *thread = args->data[1]; // Thread 41 ppStackOptions *options = args->data[2]; // Options 42 pmConfig *config = args->data[3]; // Configuration 43 bool safety = PS_SCALAR_VALUE(args->data[4], U8); // Safety switch on? 44 bool normalise = PS_SCALAR_VALUE(args->data[5], U8); // Normalise images? 45 46 46 psVector *mask = options->inputMask; // Mask for inputs 47 47 psArray *rejected = options->rejected; // Rejected pixels 48 48 psVector *weightings = options->weightings; // Weightings (1/noise^2) for each image 49 49 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 50 psVector *norm = normalise ? options->norm : NULL; // Normalisations to apply to images 51 52 bool status = ppStackReadoutFinal(config, target, thread->readouts, mask, rejected, 53 weightings, addVariance, safety, norm); // Status of operation 53 54 54 55 thread->busy = false; … … 63 64 64 65 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; 66 psArray *inspects = args->data[0]; // Array of pixel arrays 67 psArray *rejects = args->data[1]; // Array of pixel arrays 68 int index = PS_SCALAR_VALUE(args->data[2], S32); // Index of interest 69 70 psArray *inInspects = inspects->data[index]; // Array of interest 71 psArray *inRejects = rejects->data[index]; // Array of interest 72 psAssert(inInspects->n == inRejects->n, "Size should be the same"); 73 psPixels *outInspect = NULL, *outReject = NULL; // Output pixel lists 74 for (int i = 0; i < inInspects->n; i++) { 75 psPixels *inInspect = inInspects->data[i]; // Input pixel list 76 if (inInspect && inInspect->n > 0) { 77 outInspect = psPixelsConcatenate(outInspect, inInspect); 78 } 79 psPixels *inReject = inRejects->data[i]; // Input pixel list 80 if (inReject && inReject->n > 0) { 81 outReject = psPixelsConcatenate(outReject, inReject); 82 } 83 } 84 85 // If there are no pixels to inspect, then just fake it 86 if (!outInspect) { 87 outInspect = psPixelsAllocEmpty(0); 88 } 89 if (!outReject) { 90 outReject = psPixelsAllocEmpty(0); 91 } 92 93 psFree(inspects->data[index]); 94 inspects->data[index] = outInspect; 95 psFree(rejects->data[index]); 96 rejects->data[index] = outReject; 85 97 86 98 return true; … … 104 116 105 117 bool mdok; // Status of MD lookup 106 int iter = psMetadataLookupS32(NULL, recipe, "ITER"); // Rejection iterations118 float iter = psMetadataLookupF32(NULL, recipe, "COMBINE.ITER"); // Rejection iterations 107 119 float combineRej = psMetadataLookupF32(NULL, recipe, "COMBINE.REJ"); // Combination threshold 108 120 float combineSys = psMetadataLookupF32(NULL, recipe, "COMBINE.SYS"); // Combination systematic error … … 114 126 int kernelSize = psMetadataLookupS32(NULL, ppsub, "KERNEL.SIZE"); // Kernel half-size 115 127 116 psString maskValStr = psMetadataLookupStr(NULL, recipe, "MASK. VAL"); // Name of bits to mask going in128 psString maskValStr = psMetadataLookupStr(NULL, recipe, "MASK.IN"); // Name of bits to mask going in 117 129 psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch 130 psString maskSuspectStr = psMetadataLookupStr(NULL, recipe, "MASK.SUSPECT"); // Name of suspect mask bits 131 psImageMaskType maskSuspect = pmConfigMaskGet(maskSuspectStr, config); // Suspect bits 118 132 psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad 119 133 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels … … 149 163 } 150 164 151 if (!pmStackCombine(outRO, stack, maskVal | maskBad, mask Bad, kernelSize, iter,152 combineRej, combineSys, combineDiscard, true,useVariance, safe, false)) {165 if (!pmStackCombine(outRO, stack, maskVal | maskBad, maskSuspect, maskBad, kernelSize, iter, 166 combineRej, combineSys, combineDiscard, useVariance, safe, false)) { 153 167 psError(PS_ERR_UNKNOWN, false, "Unable to combine input readouts with rejection."); 154 168 psFree(stack); … … 156 170 } 157 171 158 // Save list of pixels to inspect172 // Save lists of pixels 159 173 psArray *inspect = psArrayAlloc(num); // List of pixels to inspect 174 psArray *reject = psArrayAlloc(num); // List of pixels rejected 160 175 for (int i = 0; i < num; i++) { 161 176 pmStackData *data = stack->data[i]; // Data for this image … … 168 183 } 169 184 inspect->data[i] = psMemIncrRefCounter(data->inspect); 185 reject->data[i] = psMemIncrRefCounter(data->reject); 170 186 } 171 187 psFree(stack); … … 173 189 sectionNum++; 174 190 175 return inspect; 191 psArray *results = psArrayAlloc(2); // Array of results 192 results->data[0] = inspect; 193 results->data[1] = reject; 194 195 return results; 176 196 } 177 197 … … 180 200 bool ppStackReadoutFinal(const pmConfig *config, pmReadout *outRO, const psArray *readouts, 181 201 const psVector *mask, const psArray *rejected, const psVector *weightings, 182 const psVector *addVariance )202 const psVector *addVariance, bool safety, const psVector *norm) 183 203 { 184 204 assert(config); … … 196 216 197 217 bool mdok; // Status of MD lookup 198 int iter = psMetadataLookupS32(NULL, recipe, "ITER"); // Rejection iterations199 float combineRej = psMetadataLookupF32(NULL, recipe, "COMBINE.REJ"); // Combination threshold200 float combineSys = psMetadataLookupF32(NULL, recipe, "COMBINE.SYS"); // Combination systematic error201 float combineDiscard = psMetadataLookupF32(NULL, recipe, "COMBINE.DISCARD"); // Olympic discard fraction202 218 bool useVariance = psMetadataLookupBool(&mdok, recipe, "VARIANCE"); // Use variance for rejection? 203 219 bool safe = psMetadataLookupBool(&mdok, recipe, "SAFE"); // Be safe when combining small numbers of pixels 204 220 205 psString maskValStr = psMetadataLookupStr(NULL, recipe, "MASK. VAL"); // Name of bits to mask going in221 psString maskValStr = psMetadataLookupStr(NULL, recipe, "MASK.IN"); // Name of bits to mask going in 206 222 psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch 223 psString maskSuspectStr = psMetadataLookupStr(NULL, recipe, "MASK.SUSPECT"); // Name of suspect mask bits 224 psImageMaskType maskSuspect = pmConfigMaskGet(maskSuspectStr, config); // Suspect bits 207 225 psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad 208 226 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels … … 211 229 psArray *stack = psArrayAlloc(num); // Array for stacking 212 230 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 } 231 // We have rejection from a previous combination: combine without flagging pixels to inspect 232 safe &= safety; 233 int iter = 0; 234 float combineRej = NAN; 235 float combineSys = NAN; 236 float combineDiscard = NAN; 222 237 223 238 for (int i = 0; i < num; i++) { 224 239 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 240 if (mask->data.U8[i]) { 241 // Image completely rejected 231 242 continue; 232 243 } … … 252 263 data->reject = rejected ? psMemIncrRefCounter(rejected->data[i]) : NULL; 253 264 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)) { 265 266 if (norm) { 267 float normalise = powf(10.0, -0.4 * norm->data.F32[i]); // Normalisation 268 psBinaryOp(ro->image, ro->image, "*", psScalarAlloc(normalise, PS_TYPE_F32)); 269 psBinaryOp(ro->variance, ro->variance, "*", psScalarAlloc(PS_SQR(normalise), PS_TYPE_F32)); 270 } 271 } 272 273 if (!pmStackCombine(outRO, stack, maskVal | maskBad, maskSuspect, maskBad, 0, iter, combineRej, 274 combineSys, combineDiscard, useVariance, safe, true)) { 259 275 psError(PS_ERR_UNKNOWN, false, "Unable to combine input readouts."); 260 276 psFree(stack); -
trunk/ppStack/src/ppStackReject.c
r25466 r26076 23 23 24 24 int num = options->num; // Number of inputs 25 options->rejected = psArrayAlloc(num);26 25 27 26 psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe … … 53 52 psThreadJob *job = psThreadJobAlloc("PPSTACK_INSPECT"); // Job to start 54 53 psArrayAdd(job->args, 1, options->inspect); 54 psArrayAdd(job->args, 1, options->rejected); 55 55 PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32); 56 56 if (!psThreadJobAddPending(job)) { … … 92 92 #endif 93 93 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 pixels97 98 94 #ifdef TESTING 99 95 { 100 psImage *mask = psPixelsToMask(NULL, reject,96 psImage *mask = psPixelsToMask(NULL, options->rejected->data[i], 101 97 psRegionSet(0, options->numCols - 1, 0, options->numRows - 1), 102 98 0xff); // Mask image 103 99 psString name = NULL; // Name of image 104 psStringAppend(&name, " reject_%03d.fits", i);100 psStringAppend(&name, "pre_reject_%03d.fits", i); 105 101 pmStackVisualPlotTestImage(mask, name); 106 102 psFits *fits = psFitsOpen(name, "w"); … … 111 107 } 112 108 #endif 109 110 psPixels *reject = pmStackReject(options->inspect->data[i], options->numCols, options->numRows, 111 threshold, poorFrac, stride, options->regions->data[i], 112 options->kernels->data[i]); // Rejected pixels 113 113 114 114 psFree(options->inspect->data[i]); … … 127 127 "exceeds limit (%.3f)", i, frac, imageRej); 128 128 psFree(reject); 129 // reject == NULL means reject image completely130 129 reject = NULL; 131 130 options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_BAD; … … 134 133 } 135 134 136 // Images without a list of rejected pixels (the list may be empty) are rejected completely 137 options->rejected->data[i] = reject; 135 if (reject) { 136 // Add to list of pixels already rejected 137 reject = psPixelsConcatenate(reject, options->rejected->data[i]); 138 options->rejected->data[i] = psPixelsDuplicates(options->rejected->data[i], reject); 139 } 140 141 #ifdef TESTING 142 { 143 psImage *mask = psPixelsToMask(NULL, options->rejected->data[i], 144 psRegionSet(0, options->numCols - 1, 0, options->numRows - 1), 145 0xff); // Mask image 146 psString name = NULL; // Name of image 147 psStringAppend(&name, "reject_%03d.fits", i); 148 pmStackVisualPlotTestImage(mask, name); 149 psFits *fits = psFitsOpen(name, "w"); 150 psFree(name); 151 psFitsWriteImage(fits, NULL, mask, 0, NULL); 152 psFree(mask); 153 psFitsClose(fits); 154 } 155 #endif 138 156 139 157 if (options->stats) { … … 143 161 "Number of pixels rejected", reject ? reject->n : 0); 144 162 } 163 164 psFree(reject); 145 165 psLogMsg("ppStack", PS_LOG_INFO, "Time to perform rejection on image %d: %f sec", i, 146 166 psTimerClear("PPSTACK_REJECT")); -
trunk/ppStack/src/ppStackSetup.c
r26020 r26076 72 72 } 73 73 74 options-> imageNames = psArrayAlloc(num);75 options-> maskNames = psArrayAlloc(num);76 options-> varianceNames = psArrayAlloc(num);74 options->convImages = psArrayAlloc(num); 75 options->convMasks = psArrayAlloc(num); 76 options->convVariances = psArrayAlloc(num); 77 77 for (int i = 0; i < num; i++) { 78 78 psString imageName = NULL, maskName = NULL, varianceName = NULL; // Names for convolved images … … 81 81 psStringAppend(&varianceName, "%s/%s.%d.%s", tempDir, tempName, i, tempVariance); 82 82 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;83 options->convImages->data[i] = imageName; 84 options->convMasks->data[i] = maskName; 85 options->convVariances->data[i] = varianceName; 86 86 } 87 87 psFree(outputName); 88 89 // Original images 90 options->origImages = psArrayAlloc(num); 91 options->origMasks = psArrayAlloc(num); 92 options->origVariances = psArrayAlloc(num); 93 pmFPAview *view = pmFPAviewAlloc(0); 94 for (int i = 0; i < num; i++) { 95 { 96 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT", i); 97 options->origImages->data[i] = pmFPAfileName(file, view, config); 98 } 99 { 100 // We want the convolved mask, since that defines the area that has been tested for outliers 101 options->origMasks->data[i] = psMemIncrRefCounter(options->convMasks->data[i]); 102 } 103 { 104 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT.VARIANCE", i); 105 options->origVariances->data[i] = pmFPAfileName(file, view, config); 106 } 107 } 108 psFree(view); 88 109 89 110 if (!pmConfigMaskSetBits(NULL, NULL, config)) { -
trunk/ppStack/src/ppStackSources.c
r25313 r26076 188 188 } 189 189 190 #if 0 191 // Position offsets 192 { 193 psArray *offsets = pmSourceMatchRelastro(matches, num, tol, iter1, starRej1, 194 iter2, starRej2, starLimit); // Shifts for each image 195 if (!offsets) { 196 psError(PS_ERR_UNKNOWN, false, "Unable to measure offsets"); 197 return false; 198 } 199 for (int i = 0; i < num; i++) { 200 psVector *offset = offsets->data[i]; 201 fprintf(stderr, "Offset %d: %f,%f\n", i, offset->data.F32[0], offset->data.F32[1]); 202 } 203 psFree(offsets); 204 } 205 #endif 206 190 207 #ifdef TESTING 191 208 dumpMatches("source_mags.dat", num, matches, zp, trans); -
trunk/ppStack/src/ppStackThread.c
r24796 r26076 56 56 } 57 57 58 ppStackThreadData *ppStackThreadDataSetup(const ppStackOptions *options, const pmConfig *config )58 ppStackThreadData *ppStackThreadDataSetup(const ppStackOptions *options, const pmConfig *config, bool conv) 59 59 { 60 60 psAssert(options, "Require options"); … … 62 62 63 63 const psArray *cells = options->cells; // Array of input cells 64 const psArray *imageNames = options->imageNames; // Names of images to read65 const psArray *maskNames = options->maskNames; // Names of masks to read66 const psArray *varianceNames = options->varianceNames; // Names of variance maps to read67 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 68 68 69 69 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 } 74 82 75 83 ppStackThreadData *stack = psAlloc(sizeof(ppStackThreadData)); // Thread data, to return … … 87 95 continue; 88 96 } 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(PS_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); 104 114 } 105 115 … … 116 126 } 117 127 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 } 119 131 readouts->data[j] = ro; 120 132 } … … 186 198 psFits *varianceFits = stack->varianceFits->data[i]; // FITS file for variance 187 199 188 189 int zMax = 0; 200 int zMax = 0; 190 201 bool keepReading = false; 191 if (pmReadoutMore(ro, imageFits, 0, &zMax, rows, config)) { 202 203 if (imageFits && pmReadoutMore(ro, imageFits, 0, &zMax, rows, config)) { 192 204 keepReading = true; 193 205 if (!pmReadoutReadChunk(ro, imageFits, 0, NULL, rows, overlap, config)) { … … 199 211 } 200 212 201 if ( pmReadoutMoreMask(ro, maskFits, 0, &zMax, rows, config)) {213 if (maskFits && pmReadoutMoreMask(ro, maskFits, 0, &zMax, rows, config)) { 202 214 keepReading = true; 203 215 if (!pmReadoutReadChunkMask(ro, maskFits, 0, NULL, rows, overlap, config)) { … … 209 221 } 210 222 211 if ( pmReadoutMoreVariance(ro, varianceFits, 0, &zMax, rows, config)) {223 if (varianceFits && pmReadoutMoreVariance(ro, varianceFits, 0, &zMax, rows, config)) { 212 224 keepReading = true; 213 225 if (!pmReadoutReadChunkVariance(ro, varianceFits, 0, NULL, rows, overlap, config)) { … … 263 275 264 276 { 265 psThreadTask *task = psThreadTaskAlloc("PPSTACK_INSPECT", 2);277 psThreadTask *task = psThreadTaskAlloc("PPSTACK_INSPECT", 3); 266 278 task->function = &ppStackInspect; 267 279 psThreadTaskAdd(task); … … 270 282 271 283 { 272 psThreadTask *task = psThreadTaskAlloc("PPSTACK_FINAL_COMBINE", 3);284 psThreadTask *task = psThreadTaskAlloc("PPSTACK_FINAL_COMBINE", 6); 273 285 task->function = &ppStackReadoutFinalThread; 274 286 psThreadTaskAdd(task); -
trunk/ppStack/src/ppStackThread.h
r23341 r26076 35 35 ppStackThreadData *ppStackThreadDataSetup( 36 36 const ppStackOptions *options, // Options 37 const pmConfig *config // Configuration 37 const pmConfig *config, // Configuration 38 bool conv // Use convolved products? 38 39 ); 39 40 -
trunk/ppSub/src/ppSubArguments.c
r24833 r26076 86 86 psMetadataAddS32(arguments, PS_LIST_TAIL, "-convolve", 0, "Image to convolve [1 or 2]", 0); 87 87 psMetadataAddBool(arguments, PS_LIST_TAIL, "-photometry", 0, "Perform photometry?", NULL); 88 psMetadataAddF32(arguments, PS_LIST_TAIL, "-zp", 0, "Zero point for photometry", NAN); 88 89 psMetadataAddBool(arguments, PS_LIST_TAIL, "-inverse", 0, "Generate inverse subtractions?", NULL); 89 90 psMetadataAddBool(arguments, PS_LIST_TAIL, "-visual", 0, "Show diagnostic plots", NULL); -
trunk/psModules/src/camera
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/camera merged eligible /branches/eam_branches/20090522/psModules/src/camera merged eligible /branches/eam_branches/20090715/psModules/src/camera merged eligible /branches/eam_branches/20090820/psModules/src/camera merged eligible /branches/pap/psModules/src/camera merged eligible /branches/pap_mops/psModules/src/camera 25137-25255
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/camera/pmFPAMaskWeight.c
r25379 r26076 444 444 } 445 445 446 return true; 446 return psMetadataAddF32(readout->analysis, PS_LIST_TAIL, PM_READOUT_ANALYSIS_RENORM, 0, 447 "Renormalisation of variance", PS_SQR(correction)); 447 448 } 448 449 -
trunk/psModules/src/camera/pmFPAMaskWeight.h
r25372 r26076 15 15 /// @addtogroup Camera Camera Layout 16 16 /// @{ 17 18 #define PM_READOUT_ANALYSIS_RENORM "READOUT.RENORM" // Name on analysis metadata for renormalisation 17 19 18 20 /// Set a temporary readout mask using CELL.SATURATION and CELL.BAD -
trunk/psModules/src/camera/pmReadoutFake.c
- Property svn:mergeinfo changed (with no actual effect on merging)
-
trunk/psModules/src/imcombine/pmStack.c
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/imcombine/pmStack.c merged eligible /branches/eam_branches/20090522/psModules/src/imcombine/pmStack.c merged eligible /branches/eam_branches/20090715/psModules/src/imcombine/pmStack.c merged eligible /branches/eam_branches/20090820/psModules/src/imcombine/pmStack.c merged eligible /branches/pap/psModules/src/imcombine/pmStack.c merged eligible /branches/pap_mops/psModules/src/imcombine/pmStack.c 25137-25255
r25380 r26076 33 33 #define NUM_DIRECT_STDEV 5 // For less than this number of values, measure stdev directly 34 34 35 35 36 //#define TESTING // Enable test output 36 //#define TEST_X 1085// x coordinate to examine37 //#define TEST_Y 3371 // y coordinate to examine37 //#define TEST_X 3122-1 // x coordinate to examine 38 //#define TEST_Y 1028-1 // y coordinate to examine 38 39 39 40 … … 42 43 typedef struct { 43 44 psVector *pixels; // Pixel values 44 psVector *masks; // Pixel masks45 45 psVector *variances; // Pixel variances 46 46 psVector *weights; // Pixel weightings 47 47 psVector *sources; // Pixel sources (which image did they come from?) 48 48 psVector *limits; // Rejection limits 49 psVector *suspects; // Pixel is suspect? 49 50 psVector *sort; // Buffer for sorting (to get a robust estimator of the standard dev) 50 51 } combineBuffer; … … 53 54 { 54 55 psFree(buffer->pixels); 55 psFree(buffer->masks);56 56 psFree(buffer->variances); 57 57 psFree(buffer->weights); 58 58 psFree(buffer->sources); 59 59 psFree(buffer->limits); 60 psFree(buffer->suspects); 60 61 psFree(buffer->sort); 61 62 return; … … 69 70 70 71 buffer->pixels = psVectorAlloc(numImages, PS_TYPE_F32); 71 buffer->masks = psVectorAlloc(numImages, PS_TYPE_VECTOR_MASK);72 72 buffer->variances = psVectorAlloc(numImages, PS_TYPE_F32); 73 73 buffer->weights = psVectorAlloc(numImages, PS_TYPE_F32); 74 74 buffer->sources = psVectorAlloc(numImages, PS_TYPE_U16); 75 75 buffer->limits = psVectorAlloc(numImages, PS_TYPE_F32); 76 buffer->suspects = psVectorAlloc(numImages, PS_TYPE_U8); 76 77 buffer->sort = psVectorAlloc(numImages, PS_TYPE_F32); 77 78 return buffer; … … 143 144 float *stdev, // Standard deviation value, to return 144 145 const psVector *values, // Values to combine 145 const psVector *masks, // Mask to apply146 146 psVector *sortBuffer // Buffer for sorting 147 147 ) 148 148 { 149 149 assert(values); 150 assert(!masks || values->n == masks->n);151 150 assert(values->type.type == PS_TYPE_F32); 152 assert(!masks || masks->type.type == PS_TYPE_VECTOR_MASK);153 151 assert(sortBuffer && sortBuffer->nalloc >= values->n && sortBuffer->type.type == PS_TYPE_F32); 154 152 155 // Need to filter out clipped values 156 int num = 0; // Number of valid values 157 for (int i = 0; i < values->n; i++) { 158 if (!masks || !masks->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 159 sortBuffer->data.F32[num++] = values->data.F32[i]; 160 } 161 } 162 sortBuffer->n = num; 163 if (!psVectorSortInPlace(sortBuffer)) { 153 int num = values->n; // Number of values 154 sortBuffer = psVectorSortIndex(sortBuffer, values); 155 if (!sortBuffer) { 156 *median = NAN; 157 *stdev = NAN; 164 158 return false; 165 159 } … … 167 161 if (num == 3) { 168 162 // Attempt to measure standard deviation with only three values (and one of those possibly corrupted) 169 *median = sortBuffer->data.F32[1];163 *median = values->data.F32[sortBuffer->data.S32[1]]; 170 164 if (stdev) { 171 float diff1 = sortBuffer->data.F32[0] - *median;172 float diff2 = sortBuffer->data.F32[2] - *median;165 float diff1 = values->data.F32[sortBuffer->data.S32[0]] - *median; 166 float diff2 = values->data.F32[sortBuffer->data.S32[2]] - *median; 173 167 // This factor of sqrt(2) might not be exact, but it's about right 174 168 *stdev = M_SQRT2 * PS_MIN(fabsf(diff1), fabsf(diff2)); 175 169 } 176 170 } else { 177 *median = num % 2 ? sortBuffer->data.F32[num / 2] : 178 (sortBuffer->data.F32[num / 2 - 1] + sortBuffer->data.F32[num / 2]) / 2.0; 171 *median = num % 2 ? values->data.F32[sortBuffer->data.S32[num / 2]] : 172 (values->data.F32[sortBuffer->data.S32[num / 2 - 1]] + 173 values->data.F32[sortBuffer->data.S32[num / 2]]) / 2.0; 179 174 if (stdev) { 180 175 if (num <= NUM_DIRECT_STDEV) { … … 182 177 double sum = 0.0; 183 178 for (int i = 0; i < num; i++) { 184 sum += PS_SQR( sortBuffer->data.F32[i] - *median);179 sum += PS_SQR(values->data.F32[sortBuffer->data.S32[i]] - *median); 185 180 } 186 181 *stdev = sqrt(sum / (double)(num - 1)); 187 182 } else { 188 183 // Standard deviation from the interquartile range 189 *stdev = 0.74 * ( sortBuffer->data.F32[(int)(0.75 * num)] -190 sortBuffer->data.F32[(int)(0.25 * num)]);184 *stdev = 0.74 * (values->data.F32[sortBuffer->data.S32[(int)(0.75 * num)]] - 185 values->data.F32[sortBuffer->data.S32[(int)(0.25 * num)]]); 191 186 } 192 187 } … … 195 190 return true; 196 191 } 197 198 #if 0199 // Return the weighted median for the pixels200 // This does not appear to produce as clean images as the weighted Olympic mean201 static float combinationWeightedMedian(const psVector *values, // Values to combine202 const psVector *weights, // Weights to combine203 const psVector *masks, // Mask to apply204 psVector *sortBuffer // Buffer for sorting205 )206 {207 double sumWeight = 0.0; // Sum of weights208 for (int j = 0; j < values->n; j++) {209 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {210 continue;211 }212 sumWeight += weights->data.F32[j];213 }214 215 sortBuffer = psVectorSortIndex(sortBuffer, values);216 double target = sumWeight / 2.0; // Target weight217 218 int dominant = -1; // Index of dominant value, if any219 double cumulativeWeight = 0.0; // Sum of weights220 for (int j = 0; j < values->n; j++) {221 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {222 continue;223 }224 int index = sortBuffer->data.S32[j]; // Index of value of interest225 float weight = weights->data.F32[index]; // Weight for value of interest226 if (weight >= target) {227 // Get the weighted median of the rest228 dominant = index;229 sumWeight -= weight;230 target = sumWeight / 2.0;231 continue;232 }233 cumulativeWeight += weight;234 if (cumulativeWeight >= target) {235 float median = values->data.F32[index]; // Weighted median median236 if (dominant != -1) {237 // In the case that a single value contains a disproportionate weight compared to the rest,238 // we use a weighted mean between that dominant value and the weighted median of the rest.239 return (values->data.F32[dominant] * weights->data.F32[dominant] + median * sumWeight) /240 (weights->data.F32[dominant] + sumWeight);241 }242 return median;243 }244 }245 246 return NAN;247 }248 #endif249 192 250 193 // Return the weighted Olympic mean for the pixels 251 194 static float combinationWeightedOlympic(const psVector *values, // Values to combine 252 195 const psVector *weights, // Weights to combine 253 const psVector *masks, // Mask to apply254 196 float frac, // Fraction to discard 255 197 psVector *sortBuffer // Buffer for sorting 256 198 ) 257 199 { 258 int numGood = 0; // Number of good values 259 for (int i = 0; i < values->n; i++) { 260 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 261 continue; 262 } 263 numGood++; 264 } 200 int numGood = values->n; // Number of good values 265 201 266 202 int numBad = frac * numGood + 0.5; // Number of bad values … … 272 208 for (int i = 0, j = 0; i < values->n; i++) { 273 209 int index = sortBuffer->data.S32[i]; // Index of interest 274 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[index]) {275 continue;276 }277 210 j++; 278 211 if (j > high) { … … 290 223 291 224 // Mark a pixel for inspection 292 static inline void combineInspect(const psArray *inputs, // Stack data 293 int x, int y, // Pixel 294 int source // Source image index 295 ) 296 { 225 // Value in pixel doesn't seem to agree with the stack, so need to look closer 226 static inline void combineMarkInspect(const psArray *inputs, // Stack data 227 int x, int y, // Pixel 228 int source // Source image index 229 ) 230 { 231 #ifdef TESTING 232 if (x == TEST_X && y == TEST_Y) { 233 fprintf(stderr, "Marking image %d for inspection\n", source); 234 } 235 #endif 297 236 pmStackData *data = inputs->data[source]; // Stack data of interest 298 237 if (!data) { … … 304 243 } 305 244 306 // Given a stack of images, combine with optional rejection. 307 // Pixels in the stack that are rejected are marked for subsequent inspection 308 static void combinePixels(psImage *image, // Combined image, for output 309 psImage *mask, // Combined mask, for output 310 psImage *variance, // Combined variance map, for output 311 const psArray *inputs, // Stack data 312 const psVector *weights, // Global (single value) weights for data, or NULL 313 const psVector *addVariance, // Additional variance for data 314 const psVector *reject, // Indices of pixels to reject, or NULL 315 int x, int y, // Coordinates of interest; frame of output image 316 psImageMaskType maskVal, // Value to mask 317 psImageMaskType bad, // Value to give bad pixels 318 int numIter, // Number of rejection iterations 319 float rej, // Number of standard deviations at which to reject 320 float sys, // Relative systematic error 321 float discard,// Fraction of values to discard (Olympic weighted mean) 322 bool useVariance, // Use variance for rejection when combining? 323 bool safe, // Combine safely? 324 bool rejectInspect, // Reject values marked for inspection from combination? 325 combineBuffer *buffer // Buffer for combination; to avoid multiple allocations 326 ) 245 // Mark a pixel for rejection 246 // Cannot possibly inspect this pixel and confirm that it's good. 247 // e.g., Only a single input 248 static inline void combineMarkReject(const psArray *inputs, // Stack data 249 int x, int y, // Pixel 250 int source // Source image index 251 ) 252 { 253 #ifdef TESTING 254 if (x == TEST_X && y == TEST_Y) { 255 fprintf(stderr, "Marking pixel image %d for rejection\n", source); 256 } 257 #endif 258 pmStackData *data = inputs->data[source]; // Stack data of interest 259 if (!data) { 260 psWarning("Can't find input data for source %d", source); 261 return; 262 } 263 data->reject = psPixelsAdd(data->reject, data->reject->nalloc, x, y); 264 return; 265 } 266 267 268 // Extract vectors for simple combination/rejection operations 269 static void combineExtract(int *num, // Number of good pixels 270 bool *suspect, // Any suspect pixels? 271 combineBuffer *buffer, // Buffer with vectors 272 psImage *image, // Combined image, for output 273 psImage *mask, // Combined mask, for output 274 psImage *variance, // Combined variance map, for output 275 const psArray *inputs, // Stack data 276 const psVector *weights, // Global (single value) weights for data, or NULL 277 const psVector *addVariance, // Additional variance for data 278 const psVector *reject, // Indices of pixels to reject, or NULL 279 int x, int y, // Coordinates of interest; frame of output image 280 psImageMaskType maskVal, // Value to mask 281 psImageMaskType maskSuspect // Value to suspect 282 ) 327 283 { 328 284 // Rudimentary error checking 285 assert(buffer); 329 286 assert(image); 330 287 assert(mask); 331 288 assert(inputs); 332 assert(numIter >= 0);333 assert(buffer);334 assert(addVariance);335 assert((useVariance && variance) || !useVariance);336 289 337 290 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 338 psVector *pixelMasks = buffer->masks; // Masks for the pixel of interest339 291 psVector *pixelVariances = variance ? buffer->variances : NULL; // Variances for the pixel of interest 340 292 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 341 293 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 342 294 psVector *pixelLimits = buffer->limits; // Limits for the pixel of interest 343 psVector *sort = buffer->sort; // Sort buffer 295 psVector *pixelSuspects = buffer->suspects; // Is the pixel suspect? 296 297 if (suspect) { 298 *suspect = false; 299 } 344 300 345 301 // Extract the pixel and mask data 346 int num = 0; // Number of good images302 int numGood = 0; // Number of good pixels 347 303 for (int i = 0, j = 0; i < inputs->n; i++) { 348 304 // Check if this pixel has been rejected. Assumes that the rejection pixel list is sorted --- it … … 364 320 } 365 321 322 pixelSuspects->data.U8[numGood] = mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & maskSuspect ? 323 true : false; 324 366 325 psImage *image = data->readout->image; // Image of interest 367 326 psImage *variance = data->readout->variance; // Variance map of interest 368 pixelData->data.F32[num ] = image->data.F32[yIn][xIn];327 pixelData->data.F32[numGood] = image->data.F32[yIn][xIn]; 369 328 if (variance) { 370 pixelVariances->data.F32[num ] = variance->data.F32[yIn][xIn] * addVariance->data.F32[i];371 } 372 pixelWeights->data.F32[num ] = data->weight;373 pixelSources->data.U16[num ] = i;374 num ++;375 } 376 pixelData->n = num ;329 pixelVariances->data.F32[numGood] = variance->data.F32[yIn][xIn] * addVariance->data.F32[i]; 330 } 331 pixelWeights->data.F32[numGood] = data->weight; 332 pixelSources->data.U16[numGood] = i; 333 numGood++; 334 } 335 pixelData->n = numGood; 377 336 if (variance) { 378 pixelVariances->n = num; 379 } 380 pixelWeights->n = num; 381 pixelSources->n = num; 382 pixelLimits->n = num; 337 pixelVariances->n = numGood; 338 } 339 pixelWeights->n = numGood; 340 pixelSources->n = numGood; 341 pixelLimits->n = numGood; 342 pixelSuspects->n = numGood; 343 *num = numGood; 383 344 384 345 #ifdef TESTING 385 346 if (x == TEST_X && y == TEST_Y) { 386 for (int i = 0; i < num ; i++) {387 fprintf(stderr, "Input %d (%" PRIu16 "): %f %f %f\n",347 for (int i = 0; i < numGood; i++) { 348 fprintf(stderr, "Input %d (%" PRIu16 "): %f %f (%f) %f %d\n", 388 349 i, pixelSources->data.U16[i], pixelData->data.F32[i], pixelVariances->data.F32[i], 389 pixelWeights->data.F32[i]); 390 } 391 } 392 #endif 393 394 // The sensible thing to do varies according to how many good pixels there are. 350 addVariance->data.F32[i], pixelWeights->data.F32[i], pixelSuspects->data.U8[i]); 351 } 352 } 353 #endif 354 355 return; 356 } 357 358 359 // Combine pixels 360 static void combinePixels(psImage *image, // Combined image, for output 361 psImage *mask, // Combined mask, for output 362 psImage *variance, // Combined variance map, for output 363 int num, // Number of good pixels 364 combineBuffer *buffer, // Buffer with vectors 365 int x, int y, // Coordinates of interest; frame of output image 366 psImageMaskType bad, // Value for bad pixels 367 bool safe // Safe combination? 368 ) 369 { 370 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 371 psVector *pixelVariances = variance ? buffer->variances : NULL; // Variances for the pixel of interest 372 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 373 395 374 // Default option is that the pixel is bad 396 375 float imageValue = NAN, varianceValue = NAN; // Value for combined image and variance map 397 376 psImageMaskType maskValue = bad; // Value for combined mask 398 377 switch (num) { 399 case 0: 400 // Nothing to combine: it's bad 401 #ifdef TESTING 402 if (x == TEST_X && y == TEST_Y) { 403 fprintf(stderr, "No inputs to combine, pixel is bad.\n"); 404 } 405 #endif 406 break; 378 case 0: { 379 // Nothing to combine: it's bad 380 #ifdef TESTING 381 if (x == TEST_X && y == TEST_Y) { 382 fprintf(stderr, "No inputs to combine, pixel is bad.\n"); 383 } 384 #endif 385 break; 386 } 407 387 case 1: { 408 388 // Accept the single pixel unless we have to be safe … … 427 407 } 428 408 case 2: { 429 // Accept the mean of the pixels only if we're going to reject based on the variance, or we're not 430 // playing safe 431 if (useVariance || !safe) { 409 // Automatically accept the mean of the pixels only if we're not playing safe 410 if (!safe) { 432 411 float mean, var; // Mean and variance from combination 433 412 if (combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { … … 437 416 #ifdef TESTING 438 417 if (x == TEST_X && y == TEST_Y) { 439 fprintf(stderr, "Two inputs to combine using variance/unsafe --> %f %f\n", 440 mean, var); 418 fprintf(stderr, "Two inputs to combine using unsafe --> %f %f\n", mean, var); 441 419 } 442 420 #endif 443 421 } 444 422 } 445 if (useVariance && numIter > 0) { 446 // Use variance to check that the two are consistent 447 float diff = 0.5 * (pixelData->data.F32[0] - pixelData->data.F32[1]); // Mean flux difference 448 float var1 = pixelVariances->data.F32[0]; // Variance of first 449 float var2 = pixelVariances->data.F32[1]; // Variance of second 450 // Systematic error contributes to the rejection level 451 var1 += PS_SQR(sys * pixelData->data.F32[0]); 452 var2 += PS_SQR(sys * pixelData->data.F32[1]); 453 454 float sigma2 = var1 + var2; // Combined variance 455 if (PS_SQR(diff) > PS_SQR(rej) * sigma2) { 456 // Not consistent: mark both for inspection 457 if (rejectInspect) { 458 imageValue = NAN; 459 varianceValue = NAN; 460 maskValue = bad; 461 } else { 462 combineInspect(inputs, x, y, pixelSources->data.U16[0]); 463 combineInspect(inputs, x, y, pixelSources->data.U16[1]); 464 } 465 #ifdef TESTING 466 if (x == TEST_X && y == TEST_Y) { 467 fprintf(stderr, "Both pixels marked for inspection (%f > %f x %f\n)", 468 diff, rej, sqrtf(sigma2)); 469 } 470 #endif 423 #ifdef TESTING 424 else { 425 if (x == TEST_X && y == TEST_Y) { 426 fprintf(stderr, "Two inputs to combine, safety on, pixel is bad\n"); 471 427 } 472 428 } 429 #endif 473 430 break; 474 431 } 475 432 default: { 476 // Record the value derived with no clipping, because pixels rejected using the harsh clipping 477 // applied in the first pass might later be accepted. 433 // Can combine without too much worrying 478 434 float mean, var; // Mean and variance of the combination 479 435 if (!combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { … … 488 444 } 489 445 #endif 490 491 // Prepare for clipping iteration492 if (numIter > 0) {493 pixelMasks->n = num;494 psVectorInit(pixelMasks, 0);495 if (useVariance) {496 // Convert to rejection limits --- saves doing it later.497 // Using squared rejection limit because it's cheaper than sqrts498 float rej2 = PS_SQR(rej); // Rejection level squared499 double sumWeights = 0.0;500 for (int i = 0; i < num; i++) {501 sumWeights += pixelWeights->data.F32[i];502 }503 for (int i = 0; i < num; i++) {504 // Systematic error contributes to the rejection level505 float sysVar = PS_SQR(sys * pixelData->data.F32[i]);506 #ifdef TESTING507 // Correct variance for comparison against weighted mean including itself508 float compare = 1.0 - pixelWeights->data.F32[i] / sumWeights;509 if (x == TEST_X && y == TEST_Y) {510 fprintf(stderr, "Variance %d (%d): %f %f %f\n", i, pixelSources->data.U16[i],511 pixelVariances->data.F32[i], sysVar, compare);512 }513 #endif514 515 pixelLimits->data.F32[i] = rej2 * (pixelVariances->data.F32[i] + sysVar);516 }517 }518 }519 520 // The clipping that follows is solely to identify suspect pixels.521 // These suspect pixels will be inspected in more detail by other functions.522 int numClipped = INT_MAX; // Number of pixels clipped per iteration523 int totalClipped = 0; // Total number of pixels clipped524 for (int i = 0; i < numIter && numClipped > 0 && num - totalClipped > 2; i++) {525 numClipped = 0;526 float median = NAN; // Middle of distribution527 float limit = NAN; // Rejection limit528 if (!useVariance) {529 float stdev; // Median and stdev of the combination, for rejection530 if (!combinationMedianStdev(&median, useVariance ? NULL : &stdev,531 pixelData, pixelMasks, sort)) {532 psWarning("Bad median/stdev at %d,%d", x, y);533 break;534 }535 limit = rej * stdev;536 #ifdef TESTING537 if (x == TEST_X && y == TEST_Y) {538 fprintf(stderr, "Rejecting without variance; rejection limit: %f\n", limit);539 }540 #endif541 } else {542 #ifdef TESTING543 if (x == TEST_X && y == TEST_Y) {544 fprintf(stderr, "Rejecting with variance...\n");545 }546 #endif547 median = combinationWeightedOlympic(pixelData, pixelWeights, pixelMasks, discard, sort);548 }549 550 #ifdef TESTING551 if (x == TEST_X && y == TEST_Y) {552 fprintf(stderr, "Median: %f\n", median);553 }554 #endif555 556 557 // Mask a pixel for inspection558 #define MASK_PIXEL_FOR_INSPECTION() \559 pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xff; \560 if (!rejectInspect) { \561 combineInspect(inputs, x, y, pixelSources->data.U16[j]); \562 } \563 numClipped++; \564 totalClipped++;565 566 for (int j = 0; j < num; j++) {567 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {568 continue;569 }570 float diff = pixelData->data.F32[j] - median; // Difference from expected571 if (useVariance) {572 // Comparing squares --- cheaper than lots of sqrts573 // pixelVariances includes the rejection limit, from above574 if (PS_SQR(diff) > pixelLimits->data.F32[j]) {575 MASK_PIXEL_FOR_INSPECTION();576 #ifdef TESTING577 if (x == TEST_X && y == TEST_Y) {578 fprintf(stderr, "Rejecting input %d based on variance: %f > %f\n",579 j, diff, sqrtf(pixelLimits->data.F32[j]));580 }581 #endif582 }583 } else if (fabsf(diff) > limit) {584 MASK_PIXEL_FOR_INSPECTION();585 #ifdef TESTING586 if (x == TEST_X && y == TEST_Y) {587 fprintf(stderr, "Rejecting input %d based on distribution: %f > %f\n",588 j, diff, limit);589 }590 #endif591 }592 }593 }594 595 if (rejectInspect && totalClipped > 0) {596 // Get rid of the masked values597 // The alternative to this is to make combinationMeanVariance() accept a mask598 int good = 0; // Index of good value599 for (int i = 0; i < num; i++) {600 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[i]) {601 continue;602 }603 if (i != good) {604 pixelData->data.F32[good] = pixelData->data.F32[i];605 pixelVariances->data.F32[good] = pixelVariances->data.F32[i];606 pixelWeights->data.F32[good] = pixelWeights->data.F32[i];607 pixelData->data.F32[good] = pixelData->data.F32[i];608 }609 good++;610 }611 pixelData->n = good;612 pixelVariances->n = good;613 pixelWeights->n = good;614 if (combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) {615 imageValue = mean;616 varianceValue = var;617 maskValue = 0;618 } else {619 imageValue = NAN;620 varianceValue = NAN;621 maskValue = bad;622 }623 }624 625 446 break; 626 447 } … … 633 454 } 634 455 456 #ifdef TESTING 457 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = num; 458 #endif 459 460 635 461 return; 462 } 463 464 465 // Test pixels to be combined 466 // Returns false to repeat without suspect pixels 467 static bool combineTest(int num, // Number of good pixels 468 bool suspect, // Does the stack contain suspect pixels? 469 psArray *inputs, // Original inputs (for flagging) 470 combineBuffer *buffer, // Buffer with vectors 471 int x, int y, // Coordinates of interest; frame of output image 472 float iter, // Number of rejection iterations per input 473 float rej, // Number of standard deviations at which to reject 474 float sys, // Relative systematic error 475 float olympic,// Fraction of values to discard (Olympic weighted mean) 476 bool useVariance, // Use variance for rejection when combining? 477 bool safe // Combine safely? 478 ) 479 { 480 if (iter <= 0) { 481 return true; 482 } 483 484 int numIter = PS_MAX(iter * num, 1); // Number of iterations 485 486 #ifdef TESTING 487 if (x == TEST_X && y == TEST_Y) { 488 fprintf(stderr, "Testing pixel %d,%d: %d %f %f %f %d %d\n", 489 x, y, numIter, rej, sys, olympic, useVariance, safe); 490 } 491 #endif 492 493 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 494 psVector *pixelWeights = buffer->weights; // Is the pixel suspect? 495 psVector *pixelVariances = buffer->variances; // Variances for the pixel of interest 496 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 497 psVector *pixelSuspects = buffer->suspects; // Is the pixel suspect? 498 psVector *pixelLimits = buffer->limits; // Is the pixel suspect? 499 500 // Set up rejection limits 501 float rej2 = PS_SQR(rej); // Rejection level squared 502 if (num > 2 && useVariance) { 503 // Convert rejection limits --- saves doing it later multiple times 504 // Using squared rejection limit because it's cheaper than sqrts 505 double sumWeights = 0.0; 506 for (int i = 0; i < num; i++) { 507 sumWeights += pixelWeights->data.F32[i]; 508 } 509 for (int i = 0; i < num; i++) { 510 // Systematic error contributes to the rejection level 511 float sysVar = PS_SQR(sys * pixelData->data.F32[i]); 512 #ifdef TESTING 513 // Correct variance for comparison against weighted mean including itself 514 float compare = 1.0 - pixelWeights->data.F32[i] / sumWeights; 515 if (x == TEST_X && y == TEST_Y) { 516 fprintf(stderr, "Variance %d (%d): %f %f %f\n", i, pixelSources->data.U16[i], 517 pixelVariances->data.F32[i], sysVar, compare); 518 } 519 #endif 520 pixelLimits->data.F32[i] = rej2 * (pixelVariances->data.F32[i] + sysVar); 521 } 522 } 523 524 int maskIndex = 0; // Index of pixel to mask 525 int totalClipped = 0; // Total number of pixels clipped 526 for (int i = 0; i < numIter && maskIndex >= 0; i++) { 527 maskIndex = -1; // Nothing to reject 528 529 switch (num) { 530 case 0: 531 break; 532 case 1: 533 if (i == 0 && safe) { 534 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 535 } 536 break; 537 case 2: { 538 if (useVariance) { 539 // Use variance to check that the two are consistent 540 float diff = 0.5 * (pixelData->data.F32[0] - pixelData->data.F32[1]); // Mean flux difference 541 float var1 = pixelVariances->data.F32[0]; // Variance of first 542 float var2 = pixelVariances->data.F32[1]; // Variance of second 543 // Systematic error contributes to the rejection level 544 var1 += PS_SQR(sys * pixelData->data.F32[0]); 545 var2 += PS_SQR(sys * pixelData->data.F32[1]); 546 547 float sigma2 = var1 + var2; // Combined variance 548 if (PS_SQR(diff) > rej2 * sigma2) { 549 // Not consistent: don't believe either! 550 if (i == 0 && suspect) { 551 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 552 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 553 } else { 554 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 555 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 556 } 557 #ifdef TESTING 558 if (x == TEST_X && y == TEST_Y) { 559 fprintf(stderr, "Flagged both pixels (%f > %f x %f\n)", 560 diff, rej, sqrtf(sigma2)); 561 } 562 #endif 563 } 564 } else if (i == 0 && safe) { 565 // Can't test them, and we want to be safe, so reject 566 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 567 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 568 } 569 break; 570 } 571 #if 0 572 case 3: { 573 // Want to be a bit careful on the rejection than for a larger number of inputs 574 if (!useVariance) { 575 return combineTestGeneral(num, suspect, inputs, buffer, x, y, numIter, rej, sys, 576 olympic, useVariance, safe, allowSuspect); 577 } 578 579 // Differences between pixel values 580 float diff01 = pixelData->data.F32[0] - pixelData->data.F32[1]; 581 float diff12 = pixelData->data.F32[1] - pixelData->data.F32[2]; 582 float diff20 = pixelData->data.F32[2] - pixelData->data.F32[0]; 583 // Variance for each pixel 584 float var0 = pixelVariances->data.F32[0] + PS_SQR(sys * pixelData->data.F32[0]); 585 float var1 = pixelVariances->data.F32[1] + PS_SQR(sys * pixelData->data.F32[1]); 586 float var2 = pixelVariances->data.F32[2] + PS_SQR(sys * pixelData->data.F32[2]); 587 // Errors in pixel differences 588 float err01 = var0 + var1; 589 float err12 = var1 + var2; 590 float err20 = var2 + var0; 591 592 #ifdef TESTING 593 if (x == TEST_X && y == TEST_Y) { 594 fprintf(stderr, "Diff 0-1: %f %f\n", diff01, err01); 595 fprintf(stderr, "Diff 1-2: %f %f\n", diff12, err12); 596 fprintf(stderr, "Diff 2-0: %f %f\n", diff20, err20); 597 } 598 #endif 599 600 int badPairs = 0; // Number of bad pairs 601 bool bad01 = false, bad12 = false, bad20 = false; // Pair is bad? 602 if (PS_SQR(diff01) > rej2 * err01) { 603 bad01 = true; 604 badPairs++; 605 } 606 if (PS_SQR(diff12) > rej2 * err12) { 607 bad12 = true; 608 badPairs++; 609 } 610 if (PS_SQR(diff20) > rej2 * err20) { 611 bad20 = true; 612 badPairs++; 613 } 614 615 if (badPairs > 0 && allowSuspect && suspect) { 616 return false; 617 } 618 619 switch (badPairs) { 620 case 0: 621 // Nothing to worry about! 622 break; 623 case 1: 624 // Can't tell which image is bad, so be sure to get it 625 if (bad01) { 626 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 627 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 628 break; 629 } 630 if (bad12) { 631 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 632 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 633 break; 634 } 635 if (bad20) { 636 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 637 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 638 break; 639 } 640 psAbort("Should never get here"); 641 case 2: 642 if (bad01 && bad12) { 643 // 2 and 0 are good 644 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 645 break; 646 } 647 if (bad12 && bad20) { 648 // 0 and 1 are good 649 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 650 break; 651 } 652 if (bad20 && bad01) { 653 // 1 and 2 are good 654 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 655 break; 656 } 657 psAbort("Should never get here"); 658 case 3: 659 // Everything's bad 660 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 661 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 662 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 663 break; 664 } 665 break; 666 } 667 #endif 668 default: { 669 if (useVariance) { 670 float median = combinationWeightedOlympic(pixelData, pixelWeights, 671 olympic, buffer->sort); // Median for stack 672 #ifdef TESTING 673 if (x == TEST_X && y == TEST_Y) { 674 fprintf(stderr, "Flag with variance, median = %f\n", median); 675 } 676 #endif 677 float worst = -INFINITY; // Largest deviation 678 for (int j = 0; j < num; j++) { 679 float diff = pixelData->data.F32[j] - median; // Difference from expected 680 #ifdef TESTING 681 if (x == TEST_X && y == TEST_Y) { 682 fprintf(stderr, "Testing input %d: %f\n", j, diff); 683 } 684 #endif 685 686 // Comparing squares --- cheaper than lots of sqrts 687 // pixelVariances includes the rejection limit, from above 688 float diff2 = PS_SQR(diff); // Square difference 689 if (diff2 > pixelLimits->data.F32[j]) { 690 float dev = diff2 / pixelLimits->data.F32[j]; // Deviation 691 if (dev > worst) { 692 worst = dev; 693 maskIndex = j; 694 } 695 } 696 } 697 } else { 698 float median = NAN, stdev = NAN; // Median and stdev of the combination, for rejection 699 combinationMedianStdev(&median, &stdev, pixelData, buffer->sort); 700 float limit = rej * stdev; // Rejection limit 701 #ifdef TESTING 702 if (x == TEST_X && y == TEST_Y) { 703 fprintf(stderr, "Flag without variance; median = %f, stdev = %f, limit = %f\n", 704 median, stdev, limit); 705 } 706 #endif 707 float worst = -INFINITY; // Largest deviation 708 for (int j = 0; j < num; j++) { 709 float diff = fabsf(pixelData->data.F32[j] - median); // Difference from expected 710 711 if (diff > limit) { 712 float dev = diff / limit; // Deviation 713 if (dev > worst) { 714 worst = dev; 715 maskIndex = j; 716 } 717 } 718 } 719 } 720 } 721 } 722 723 // Do the actual rejection of the pixel 724 if (maskIndex >= 0) { 725 if (suspect) { 726 #ifdef TESTING 727 if (x == TEST_X && y == TEST_Y) { 728 fprintf(stderr, "Throwing out all suspect pixels\n"); 729 } 730 #endif 731 // Throw out all suspect pixels 732 int numGood = 0; // Number of good pixels 733 for (int j = 0; j < num; j++) { 734 if (pixelSuspects->data.U8[j]) { 735 combineMarkReject(inputs, x, y, pixelSources->data.U16[j]); 736 continue; 737 } 738 if (numGood == j) { 739 numGood++; 740 continue; 741 } 742 pixelData->data.F32[numGood] = pixelData->data.F32[j]; 743 pixelWeights->data.F32[numGood] = pixelWeights->data.F32[j]; 744 pixelSources->data.U16[numGood] = pixelSources->data.U16[j]; 745 pixelLimits->data.F32[numGood] = pixelLimits->data.F32[j]; 746 pixelVariances->data.F32[numGood] = pixelVariances->data.F32[j]; 747 numGood++; 748 } 749 pixelData->n = numGood; 750 pixelWeights->n = numGood; 751 pixelSources->n = numGood; 752 pixelLimits->n = numGood; 753 pixelVariances->n = numGood; 754 totalClipped += num - numGood; 755 num = numGood; 756 suspect = false; 757 } else { 758 // Throw out masked pixel 759 #ifdef TESTING 760 if (x == TEST_X && y == TEST_Y) { 761 fprintf(stderr, "Throwing out input %d\n", maskIndex); 762 } 763 #endif 764 combineMarkInspect(inputs, x, y, pixelSources->data.U16[maskIndex]); 765 int numGood = 0; // Number of good pixels 766 for (int j = 0; j < num; j++) { 767 if (j == maskIndex) { 768 continue; 769 } 770 if (numGood == j) { 771 numGood++; 772 continue; 773 } 774 pixelData->data.F32[numGood] = pixelData->data.F32[j]; 775 pixelWeights->data.F32[numGood] = pixelWeights->data.F32[j]; 776 pixelSources->data.U16[numGood] = pixelSources->data.U16[j]; 777 pixelLimits->data.F32[numGood] = pixelLimits->data.F32[j]; 778 pixelVariances->data.F32[numGood] = pixelVariances->data.F32[j]; 779 numGood++; 780 } 781 pixelData->n = numGood; 782 pixelWeights->n = numGood; 783 pixelSources->n = numGood; 784 pixelLimits->n = numGood; 785 pixelVariances->n = numGood; 786 totalClipped++; 787 num--; 788 } 789 } 790 } 791 792 return true; 636 793 } 637 794 … … 639 796 // Ensure the input array of pmStackData is valid, and get some details out of it 640 797 static bool validateInputData(bool *haveVariances, // Do we have variance maps in the sky images? 641 bool *haveRejects, // Do we have lists of rejected pixels?642 798 int *num, // Number of inputs 643 799 int *numCols, int *numRows, // Size of (sky) images 644 psArray *input // Input array of pmStackData to validate 800 const psArray *input, // Input array of pmStackData to validate 801 const pmReadout *output // Output readout 645 802 ) 646 803 { … … 668 825 PS_ASSERT_IMAGE_TYPE(data->readout->variance, PS_TYPE_F32, false); 669 826 } 670 *haveRejects = (data->reject != NULL);827 bool haveRejects = (data->reject != NULL); // Do we have rejected pixels? 671 828 672 829 // Make sure the rest correspond with the first … … 681 838 return false; 682 839 } 683 if (( *haveRejects && !data->reject) || (data->reject && !*haveRejects)) {840 if ((haveRejects && !data->reject) || (data->reject && !haveRejects)) { 684 841 psError(PS_ERR_UNEXPECTED_NULL, true, 685 842 "The rejected pixels are specified in some but not all inputs."); … … 697 854 PS_ASSERT_IMAGE_TYPE(data->readout->variance, PS_TYPE_F32, false); 698 855 } 856 } 857 858 PM_ASSERT_READOUT_NON_NULL(output, false); 859 if (output->image) { 860 PS_ASSERT_IMAGE_NON_NULL(output->image, false); 861 PS_ASSERT_IMAGE_TYPE(output->image, PS_TYPE_F32, false); 862 PS_ASSERT_IMAGE_NON_NULL(output->mask, false); 863 PS_ASSERT_IMAGE_TYPE(output->mask, PS_TYPE_IMAGE_MASK, false); 864 PS_ASSERT_IMAGES_SIZE_EQUAL(output->image, output->mask, false); 699 865 } 700 866 … … 782 948 783 949 /// Stack input images 784 bool pmStackCombine(pmReadout *combined, psArray *input, psImageMaskType maskVal, psImageMaskType bad, 785 int kernelSize, int numIter, float rej, float sys, float discard, 786 bool entire, bool useVariance, bool safe, bool rejectInspect) 787 { 788 PS_ASSERT_PTR_NON_NULL(combined, false); 950 bool pmStackCombine(pmReadout *combined, psArray *input, psImageMaskType maskVal, psImageMaskType maskSuspect, 951 psImageMaskType bad, int kernelSize, float iter, float rej, float sys, float olympic, 952 bool useVariance, bool safe, bool rejection) 953 { 789 954 bool haveVariances; // Do we have the variance maps? 790 bool haveRejects; // Do we have lists of rejected pixels?791 955 int num; // Number of inputs 792 956 int numCols, numRows; // Size of (sky) images 793 if (!validateInputData(&haveVariances, & haveRejects, &num, &numCols, &numRows, input)) {957 if (!validateInputData(&haveVariances, &num, &numCols, &numRows, input, combined)) { 794 958 return false; 795 959 } 796 960 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 797 961 PS_ASSERT_INT_POSITIVE(bad, false); 798 PS_ASSERT_INT_NONNEGATIVE(numIter, false);799 962 if (isnan(rej)) { 800 PS_ASSERT_ INT_EQUAL(numIter, 0, false);963 PS_ASSERT_FLOAT_EQUAL(iter, 0, false); 801 964 } else { 965 PS_ASSERT_FLOAT_LARGER_THAN(iter, 0, false); 802 966 PS_ASSERT_FLOAT_LARGER_THAN(rej, 0.0, false); 803 }804 if (haveRejects) {805 // This is a subsequent combination, so expect that the image and mask already exist806 PS_ASSERT_IMAGE_NON_NULL(combined->image, false);807 PS_ASSERT_IMAGE_TYPE(combined->image, PS_TYPE_F32, false);808 PS_ASSERT_IMAGE_NON_NULL(combined->mask, false);809 PS_ASSERT_IMAGE_TYPE(combined->mask, PS_TYPE_IMAGE_MASK, false);810 PS_ASSERT_IMAGES_SIZE_EQUAL(combined->image, combined->mask, false);811 967 } 812 968 if (useVariance && !haveVariances) { … … 833 989 } 834 990 #endif 835 if (!haveRejects && !data->inspect) { 836 data->inspect = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 991 if (!rejection) { 992 // Ensure pixels can be put on the appropriate list 993 if (!data->inspect) { 994 data->inspect = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 995 } 996 if (!data->reject) { 997 data->reject = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 998 } 837 999 } 838 1000 } … … 863 1025 combineBuffer *buffer = combineBufferAlloc(num); 864 1026 865 if (haveRejects) { 866 psImage *combinedImage = combined->image; // Combined image 867 psImage *combinedMask = combined->mask; // Combined mask 868 psImage *combinedVariance = combined->variance; // Combined variance map 869 870 psArray *pixelMap = pixelMapGenerate(input, minInputCols, maxInputCols, 871 minInputRows, maxInputRows); // Map of pixels to source 872 psPixels *pixels = NULL; // Total list of pixels, with no duplicates 1027 // Pull the products out, allocate if necessary 1028 psImage *combinedImage = combined->image; // Combined image 1029 if (!combinedImage) { 1030 combined->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1031 combinedImage = combined->image; 1032 } 1033 psImage *combinedMask = combined->mask; // Combined mask 1034 if (!combinedMask) { 1035 combined->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 1036 combinedMask = combined->mask; 1037 } 1038 1039 psImage *combinedVariance = combined->variance; // Combined variance map 1040 if (haveVariances && !combinedVariance) { 1041 combined->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1042 combinedVariance = combined->variance; 1043 } 1044 1045 // Set up rejection list 1046 psArray *pixelMap = NULL; // Map of pixels to source 1047 if (rejection) { 1048 pixelMap = pixelMapGenerate(input, minInputCols, maxInputCols, minInputRows, maxInputRows); 1049 } 1050 1051 // Combine each pixel 1052 for (int y = minInputRows; y < maxInputRows; y++) { 1053 for (int x = minInputCols; x < maxInputCols; x++) { 1054 #ifdef TESTING 1055 if (x == TEST_X && y == TEST_Y) { 1056 fprintf(stderr, "Combining pixel %d,%d: %x %x %f %f %f %f %d %d %d\n", 1057 x, y, maskVal, bad, iter, rej, sys, olympic, useVariance, safe, rejection); 1058 } 1059 #endif 1060 psVector *reject = NULL; // Images to reject for this pixel 1061 if (rejection) { 1062 reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, x, y); 1063 #ifdef TESTING 1064 if (x == TEST_X && y == TEST_Y) { 1065 fprintf(stderr, "Rejected inputs: "); 1066 if (!reject) { 1067 fprintf(stderr, "<none>\n"); 1068 } else { 1069 for (int i = 0; i < reject->n; i++) { 1070 fprintf(stderr, "%d ", reject->data.U16[i]); 1071 } 1072 fprintf(stderr, "\n"); 1073 } 1074 } 1075 #endif 1076 } 1077 1078 int num; // Number of good pixels 1079 bool suspect; // Suspect pixels in stack? 1080 combineExtract(&num, &suspect, buffer, combinedImage, combinedMask, combinedVariance, 1081 input, weights, addVariance, reject, x, y, maskVal, maskSuspect); 1082 combinePixels(combinedImage, combinedMask, combinedVariance, num, buffer, x, y, bad, safe); 1083 1084 if (iter > 0) { 1085 combineTest(num, suspect, input, buffer, x, y, iter, rej, sys, olympic, 1086 useVariance, safe); 1087 } 1088 } 1089 } 1090 1091 psFree(pixelMap); 1092 psFree(weights); 1093 psFree(buffer); 1094 1095 1096 1097 #ifndef PS_NO_TRACE 1098 if (!rejection && psTraceGetLevel("psModules.imcombine") >= 5) { 873 1099 for (int i = 0; i < num; i++) { 874 pmStackData *data = input->data[i]; // Stack ing data; contains the list of pixels875 if (!data ) {1100 pmStackData *data = input->data[i]; // Stack data for this input 1101 if (!data || !data->inspect) { 876 1102 continue; 877 1103 } 878 pixels = psPixelsConcatenate(pixels, data->reject); 879 } 880 pixels = psPixelsDuplicates(pixels, pixels); 881 882 if (entire) { 883 // Combine entire image 884 for (int y = minInputRows; y < maxInputRows; y++) { 885 for (int x = minInputCols; x < maxInputCols; x++) { 886 psVector *reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, 887 x, y); // Reject these images 888 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 889 addVariance, reject, x, y, maskVal, bad, numIter, rej, sys, discard, 890 useVariance, safe, rejectInspect, buffer); 891 } 892 } 893 } else { 894 // Only combine previously rejected pixels 895 for (int i = 0; i < pixels->n; i++) { 896 // Pixel coordinates are in the frame of the original image 897 int x = pixels->data[i].x, y = pixels->data[i].y; // Coordinates of interest 898 if (x < minInputCols || x >= maxInputCols || y < minInputRows || y >= maxInputRows) { 899 continue; 900 } 901 psVector *reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, 902 x, y); // Reject these images 903 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 904 addVariance, reject, x, y, maskVal, bad, numIter, rej, sys, discard, 905 useVariance, safe, rejectInspect, buffer); 906 } 907 } 908 psFree(pixels); 909 psFree(pixelMap); 910 } else { 911 // Pull the products out, allocate if necessary 912 psImage *combinedImage = combined->image; // Combined image 913 if (!combinedImage) { 914 combined->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 915 combinedImage = combined->image; 916 } 917 psImage *combinedMask = combined->mask; // Combined mask 918 if (!combinedMask) { 919 combined->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 920 combinedMask = combined->mask; 921 } 922 923 psImage *combinedVariance = combined->variance; // Combined variance map 924 if (haveVariances && !combinedVariance) { 925 combined->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 926 combinedVariance = combined->variance; 927 } 928 929 for (int y = minInputRows; y < maxInputRows; y++) { 930 for (int x = minInputCols; x < maxInputCols; x++) { 931 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 932 addVariance, NULL, x, y, maskVal, bad, numIter, rej, sys, discard, 933 useVariance, safe, rejectInspect, buffer); 934 } 935 } 936 937 #ifndef PS_NO_TRACE 938 if (psTraceGetLevel("psModules.imcombine") >= 5) { 939 for (int i = 0; i < num; i++) { 940 pmStackData *data = input->data[i]; // Stack data for this input 941 if (!data || !data->inspect) { 942 continue; 943 } 944 psTrace("psModules.imcombine", 5, "Image %d: %ld pixels to inspect.\n", i, data->inspect->n); 945 } 946 } 947 #endif 948 } 949 950 psFree(weights); 951 psFree(buffer); 1104 psTrace("psModules.imcombine", 5, "Image %d: %ld pixels to inspect.\n", i, data->inspect->n); 1105 } 1106 } 1107 #endif 952 1108 953 1109 return true; -
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/imcombine/pmStack.h
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/imcombine/pmStack.h merged eligible /branches/eam_branches/20090522/psModules/src/imcombine/pmStack.h merged eligible /branches/eam_branches/20090715/psModules/src/imcombine/pmStack.h merged eligible /branches/eam_branches/20090820/psModules/src/imcombine/pmStack.h merged eligible /branches/pap/psModules/src/imcombine/pmStack.h merged eligible /branches/pap_mops/psModules/src/imcombine/pmStack.h 25137-25255
r23577 r26076 44 44 psArray *input, ///< Input array of pmStackData 45 45 psImageMaskType maskVal, ///< Mask value of bad pixels 46 psImageMaskType suspect, ///< Mask value of suspect pixels 46 47 psImageMaskType bad, ///< Mask value to give rejected pixels 47 48 int kernelSize, ///< Half-size of the convolution kernel 48 int numIter, ///< Number of iterations49 float iter, ///< Number of iterations per input 49 50 float rej, ///< Rejection limit (standard deviations) 50 51 float sys, ///< Relative systematic error 51 52 float discard, ///< Fraction of values to discard for Olympic weighted mean 52 bool entire, ///< Combine entire image even if rejection lists provided?53 53 bool useVariance, ///< Use variance values for rejection? 54 54 bool safe, ///< Play safe with small numbers of input pixels (mask if N <= 2)? -
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/objects
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/objects merged eligible /branches/eam_branches/20090522/psModules/src/objects merged eligible /branches/eam_branches/20090715/psModules/src/objects merged eligible /branches/eam_branches/20090820/psModules/src/objects merged eligible /branches/pap/psModules/src/objects merged eligible /branches/pap_mops/psModules/src/objects 25137-25255
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/objects/pmSourceMatch.c
r25256 r26076 17 17 #define SOURCES_MAX_LEAF 2 // Maximum number of points on a tree leaf 18 18 #define ARRAY_BUFFER 16 // Buffer for array 19 19 20 20 21 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 124 125 match->mag = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 125 126 match->magErr = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 127 match->x = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 128 match->y = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 126 129 match->image = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_U32); 127 130 match->index = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_U32); … … 133 136 void pmSourceMatchAdd(pmSourceMatch *match, // Match data 134 137 float mag, float magErr, // Magnitude and error 138 float x, float y, // Position 135 139 int image, // Image index 136 140 int index // Source index … … 141 145 match->mag = psVectorExtend(match->mag, match->mag->nalloc, 1); 142 146 match->magErr = psVectorExtend(match->magErr, match->magErr->nalloc, 1); 147 match->x = psVectorExtend(match->x, match->x->nalloc, 1); 148 match->y = psVectorExtend(match->y, match->y->nalloc, 1); 143 149 match->image = psVectorExtend(match->image, match->image->nalloc, 1); 144 150 match->index = psVectorExtend(match->index, match->index->nalloc, 1); … … 147 153 match->mag->data.F32[num] = mag; 148 154 match->magErr->data.F32[num] = magErr; 155 match->x->data.F32[num] = x; 156 match->y->data.F32[num] = y; 149 157 match->image->data.S32[num] = image; 150 158 match->index->data.S32[num] = index; … … 192 200 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 193 201 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 194 i, indices->data.S32[j]);202 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 195 203 matches->data[j] = match; 196 204 } … … 212 220 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 213 221 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 214 i, indices->data.S32[j]);222 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 215 223 matches->data[k] = match; 216 224 } … … 238 246 pmSourceMatch *match = matches->data[index]; // Match data 239 247 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 240 i, indices->data.S32[j]);248 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 241 249 numMatch++; 242 250 } else { … … 244 252 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 245 253 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 246 i, indices->data.S32[j]);254 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 247 255 xMaster->data.F32[numMaster] = xImage->data.F32[j]; 248 256 yMaster->data.F32[numMaster] = yImage->data.F32[j]; … … 304 312 pmSourceMatch *match = matches->data[i]; // Match of interest 305 313 for (int j = 0; j < match->num && !source; j++) { 306 if (!isfinite(match->mag->data.F32[j]) || !isfinite(match->magErr->data.F32[j])) { 314 if (!isfinite(match->mag->data.F32[j]) || !isfinite(match->magErr->data.F32[j]) || 315 !isfinite(match->x->data.F32[j]) || !isfinite(match->y->data.F32[j])) { 307 316 continue; 308 317 } … … 365 374 double star = 0.0, starErr = 0.0; // Accumulators for star 366 375 for (int j = 0; j < match->num; j++) { 367 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {376 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 368 377 continue; 369 378 } … … 396 405 pmSourceMatch *match = matches->data[i]; // Matched stars 397 406 for (int j = 0; j < match->num; j++) { 398 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {407 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 399 408 continue; 400 409 } … … 424 433 pmSourceMatch *match = matches->data[i]; // Matched stars 425 434 for (int j = 0; j < match->num; j++) { 426 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {435 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 427 436 continue; 428 437 } … … 543 552 pmSourceMatch *match = matches->data[i]; // Matched stars 544 553 for (int j = 0; j < match->num; j++) { 545 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {554 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 546 555 continue; 547 556 } … … 564 573 if (PS_SQR(dev) > starClip * (PS_SQR(magErr) + sysErr2)) { 565 574 numRejected++; 566 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xFF;575 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] |= PM_SOURCE_MATCH_MASK_PHOT; 567 576 } 568 577 } … … 627 636 return NULL; 628 637 } 629 psTrace("psModules.objects", 3, "Pass 1: Determined %d/%d are photometric ", numPhoto, numImages);638 psTrace("psModules.objects", 3, "Pass 1: Determined %d/%d are photometric\n", numPhoto, numImages); 630 639 631 640 fracRej = sourceMatchRelphotReject(trans, stars, matches, zp, photo, badImage, rej1, sys1); 632 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected ", fracRej * 100);641 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected\n", fracRej * 100); 633 642 634 643 chi2 = sourceMatchRelphotIterate(trans, stars, badImage, matches, zp, photo, sys1); … … 649 658 return NULL; 650 659 } 651 psTrace("psModules.objects", 3, "Pass 2: Determined %d/%d are photometric ", numPhoto, numImages);660 psTrace("psModules.objects", 3, "Pass 2: Determined %d/%d are photometric\n", numPhoto, numImages); 652 661 653 662 fracRej = sourceMatchRelphotReject(trans, stars, matches, zp, photo, badImage, rej2, sys2); 654 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected ", fracRej * 100);663 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected\n", fracRej * 100); 655 664 656 665 chi2 = sourceMatchRelphotIterate(trans, stars, badImage, matches, zp, photo, sys2); … … 668 677 return trans; 669 678 } 679 680 681 // Iterate on the star positions and image shifts 682 // Returns the solution chi^2 683 static float sourceMatchRelastroIterate(psVector *xShift, psVector *yShift, // Shift for image 684 psVector *xStar, psVector *yStar, // Position for star 685 const psArray *matches // Array of matches 686 ) 687 { 688 psAssert(matches, "Need list of matches"); 689 690 int numImages = xShift->n; // Number of images 691 int numStars = matches->n; // Number of stars 692 693 psAssert(xShift && xShift->type.type == PS_TYPE_F32 && yShift && yShift->type.type == PS_TYPE_F32, 694 "Need shifts"); 695 psAssert(yShift->n == numImages, "Not enough shifts: %ld\n", yShift->n); 696 psAssert(xStar && xStar->type.type == PS_TYPE_F32 && yStar && yStar->type.type == PS_TYPE_F32, 697 "Need star positions"); 698 psAssert(xStar->n == numStars && yStar->n == numStars, "Not enough stars\n"); 699 700 // Solve the star positions 701 psVectorInit(xStar, NAN); 702 psVectorInit(yStar, NAN); 703 psVector *starMask = psVectorAlloc(numStars, PS_TYPE_U8); // Mask for stars 704 psVectorInit(starMask, 0xFF); 705 int numGoodStars = 0; // Number of stars with good measurements 706 for (int i = 0; i < numStars; i++) { 707 pmSourceMatch *match = matches->data[i]; // Matched stars 708 int numMeasurements = 0; // Number of unmasked measurements for star 709 double xSum = 0.0, ySum = 0.0; // Accumulators for star 710 for (int j = 0; j < match->num; j++) { 711 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 712 continue; 713 } 714 numMeasurements++; 715 int index = match->image->data.U32[j]; // Image index 716 717 xSum += match->x->data.F32[j] - xShift->data.F32[index]; 718 ySum += match->y->data.F32[j] - yShift->data.F32[index]; 719 } 720 if (numMeasurements > 1) { 721 // It's only a good star (contributing to the chi^2) if there's more than 1 measurement 722 numGoodStars++; 723 xStar->data.F32[i] = xSum / numMeasurements; 724 yStar->data.F32[i] = ySum / numMeasurements; 725 starMask->data.U8[i] = 0; 726 } 727 } 728 729 // Solve for the shifts 730 psVectorInit(xShift, 0.0); 731 psVectorInit(yShift, 0.0); 732 psVector *num = psVectorAlloc(numImages, PS_TYPE_S32); // Number of stars 733 psVectorInit(num, 0); 734 for (int i = 0; i < numStars; i++) { 735 if (starMask->data.U8[i]) { 736 continue; 737 } 738 pmSourceMatch *match = matches->data[i]; // Matched stars 739 for (int j = 0; j < match->num; j++) { 740 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 741 continue; 742 } 743 int index = match->image->data.U32[j]; // Image index 744 745 xShift->data.F32[index] += match->x->data.F32[j] - xStar->data.F32[i]; 746 yShift->data.F32[index] += match->y->data.F32[j] - yStar->data.F32[i]; 747 num->data.S32[index]++; 748 } 749 } 750 for (int i = 0; i < numImages; i++) { 751 xShift->data.F32[i] /= num->data.S32[i]; 752 yShift->data.F32[i] /= num->data.S32[i]; 753 psTrace("psModules.objects", 3, "Shift for image %d: %f,%f\n", 754 i, xShift->data.F32[i], yShift->data.F32[i]); 755 } 756 psFree(num); 757 758 // Once more through to evaluate chi^2 759 float chi2 = 0.0; // chi^2 for iteration 760 int dof = 0; // Degrees of freedom 761 for (int i = 0; i < numStars; i++) { 762 pmSourceMatch *match = matches->data[i]; // Matched stars 763 if (starMask->data.U8[i]) { 764 continue; 765 } 766 for (int j = 0; j < match->num; j++) { 767 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j]) { 768 continue; 769 } 770 771 int index = match->image->data.U32[j]; // Image index 772 float dx = match->x->data.F32[j] - xShift->data.F32[index] - xStar->data.F32[i]; 773 float dy = match->y->data.F32[j] - yShift->data.F32[index] - yStar->data.F32[i]; 774 775 chi2 += PS_SQR(dx) + PS_SQR(dy); 776 dof++; 777 } 778 } 779 dof -= numGoodStars + numImages; 780 chi2 /= dof; 781 782 return chi2; 783 } 784 785 // Reject star measurements 786 // Returns the fraction of measurements that were rejected 787 static float sourceMatchRelastroReject(const psVector *xShift, const psVector *yShift, // Shifts for each image 788 const psVector *xStar, const psVector *yStar, // Positions for each star 789 const psArray *matches, // Array of matches 790 float chi2, // chi^2 from fit 791 float rej // Rejection threshold 792 ) 793 { 794 psAssert(matches, "Need list of matches"); 795 796 int numImages = xShift->n; // Number of images 797 int numStars = matches->n; // Number of stars 798 799 psAssert(xShift && xShift->type.type == PS_TYPE_F32 && yShift && yShift->type.type == PS_TYPE_F32, 800 "Need shifts"); 801 psAssert(yShift->n == numImages, "Not enough shifts: %ld\n", yShift->n); 802 psAssert(xStar && xStar->type.type == PS_TYPE_F32 && yStar && yStar->type.type == PS_TYPE_F32, 803 "Need star positions"); 804 psAssert(xStar->n == numStars && yStar->n == numStars, "Not enough stars\n"); 805 806 int numRejected = 0; // Number rejected 807 int numMeasurements = 0; // Number of measurements 808 809 float thresh = PS_SQR(rej) * chi2; // Threshold for rejection 810 811 for (int i = 0; i < numStars; i++) { 812 pmSourceMatch *match = matches->data[i]; // Matched stars 813 for (int j = 0; j < match->num; j++) { 814 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 815 continue; 816 } 817 numMeasurements++; 818 int index = match->image->data.U32[j]; // Image index 819 820 float dx = match->x->data.F32[j] - xShift->data.F32[index] - xStar->data.F32[i]; 821 float dy = match->y->data.F32[j] - yShift->data.F32[index] - yStar->data.F32[i]; 822 823 if (PS_SQR(dx) + PS_SQR(dy) > thresh) { 824 numRejected++; 825 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] |= PM_SOURCE_MATCH_MASK_ASTRO; 826 } 827 } 828 } 829 830 return (float)numRejected / (float)numMeasurements; 831 } 832 833 psArray *pmSourceMatchRelastro(const psArray *matches, // Array of matches 834 int numImages, // Number of images 835 float tol, // Relative tolerance for convergence 836 int iter1, // Number of iterations for pass 1 837 float rej1, // Limit on rejection between iterations for pass 1 838 int iter2, // Number of iterations for pass 2 839 float rej2, // Limit on rejection between iterations for pass 2 840 float rejLimit // Limit on rejection between iterations 841 ) 842 { 843 PS_ASSERT_ARRAY_NON_NULL(matches, NULL); 844 845 int numStars = matches->n; // Number of stars 846 psVector *xShift = psVectorAlloc(numImages, PS_TYPE_F32); // x shift for each image 847 psVector *yShift = psVectorAlloc(numImages, PS_TYPE_F32); // y shift for each image 848 psVectorInit(xShift, 0.0); 849 psVectorInit(yShift, 0.0); 850 psVector *xStar = psVectorAlloc(numStars, PS_TYPE_F32); // x position for each star 851 psVector *yStar = psVectorAlloc(numStars, PS_TYPE_F32); // y position for each star 852 853 float chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); // chi^2 for solution 854 psTrace("psModules.objects", 1, "Initial: chi^2 = %f\n", chi2); 855 float lastChi2 = INFINITY; // chi^2 on last iteration 856 float fracRej = INFINITY; // Fraction of measurements rejected 857 858 // In the first passes, the shifts are not well deteremined: use high systematic error and 859 // rejection thresholds 860 for (int i = 0; i < iter1; i++) { 861 fracRej = sourceMatchRelastroReject(xShift, yShift, xStar, yStar, matches, chi2, rej1); 862 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected\n", fracRej * 100); 863 864 chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); 865 psTrace("psModules.objects", 1, "Pass 1: iter = %d: chi^2 = %f rejected = %f\n", i, chi2, fracRej); 866 } 867 868 for (int i = 0; i < iter2 && (fabsf(lastChi2 - chi2) > tol * chi2 || fracRej > rejLimit); i++) { 869 lastChi2 = chi2; 870 871 fracRej = sourceMatchRelastroReject(xShift, yShift, xStar, yStar, matches, chi2, rej2); 872 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected\n", fracRej * 100); 873 874 chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); 875 psTrace("psModules.objects", 1, "Pass 2: iter = %d: chi^2 = %f rejected = %f\n", i, chi2, fracRej); 876 } 877 878 psFree(xStar); 879 psFree(yStar); 880 881 if (fabsf(lastChi2 - chi2) > tol * chi2 || fracRej > rejLimit) { 882 psWarning("Unable to converge to relphot solution (%f,%f)", (lastChi2 - chi2) / chi2, fracRej); 883 } 884 885 psArray *results = psArrayAlloc(numImages); // Array of results 886 for (int i = 0; i < numImages; i++) { 887 psVector *offset = results->data[i] = psVectorAlloc(2, PS_TYPE_F32); // Offset for image 888 offset->data.F32[0] = xShift->data.F32[i]; 889 offset->data.F32[1] = yShift->data.F32[i]; 890 } 891 psFree(xShift); 892 psFree(yShift); 893 894 return results; 895 } 896 -
trunk/psModules/src/objects/pmSourceMatch.h
r23241 r26076 1 1 #ifndef PM_SOURCE_MATCH_H 2 2 #define PM_SOURCE_MATCH_H 3 4 #include <pslib.h> 5 6 /// Mask values for matched sources 7 typedef enum { 8 PM_SOURCE_MATCH_MASK_PHOT = 0x01, // Source was rejected from photometry fit 9 PM_SOURCE_MATCH_MASK_ASTRO = 0x02, // Source was rejected from astrometry fit 10 } pmSourceMatchMask; 3 11 4 12 /// Matched sources … … 12 20 psVector *mag; // Magnitudes 13 21 psVector *magErr; // Magnitude errors 22 psVector *x, *y; // Positions 14 23 psVector *mask; // Mask for measurements 15 24 } pmSourceMatch; … … 26 35 PS_ASSERT_VECTOR_NON_NULL((MATCH)->mag, RVAL); \ 27 36 PS_ASSERT_VECTOR_NON_NULL((MATCH)->magErr, RVAL); \ 37 PS_ASSERT_VECTOR_NON_NULL((MATCH)->x, RVAL); \ 38 PS_ASSERT_VECTOR_NON_NULL((MATCH)->y, RVAL); \ 28 39 PS_ASSERT_VECTOR_SIZE((MATCH)->image, (MATCH)->num, RVAL); \ 29 40 PS_ASSERT_VECTOR_SIZE((MATCH)->index, (MATCH)->num, RVAL); \ 30 41 PS_ASSERT_VECTOR_SIZE((MATCH)->mag, (MATCH)->num, RVAL); \ 31 42 PS_ASSERT_VECTOR_SIZE((MATCH)->magErr, (MATCH)->num, RVAL); \ 43 PS_ASSERT_VECTOR_SIZE((MATCH)->x, (MATCH)->num, RVAL); \ 44 PS_ASSERT_VECTOR_SIZE((MATCH)->y, (MATCH)->num, RVAL); \ 32 45 } 33 46 … … 38 51 void pmSourceMatchAdd(pmSourceMatch *match, // Match data 39 52 float mag, float magErr, // Magnitude and error 53 float x, float y, // Position 40 54 int image, // Image index 41 55 int index // Source index … … 75 89 ); 76 90 91 /// Perform relative astrometry to calibrate images 92 psArray *pmSourceMatchRelastro(const psArray *matches, // Array of matches 93 int numImages, // Number of images 94 float tol, // Relative tolerance for convergence 95 int iter1, // Number of iterations for pass 1 96 float rej1, // Limit on rejection between iterations for pass 1 97 int iter2, // Number of iterations for pass 2 98 float rej2, // Limit on rejection between iterations for pass 2 99 float rejLimit // Limit on rejection between iterations 100 ); 101 77 102 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
