- Timestamp:
- May 6, 2010, 8:02:38 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/psphot.20100506/src/psphotStackMatchPSFsUtils.c
r27850 r27876 1 /***** defines *****/ 2 3 #define ARRAY_BUFFER 16 // Number to add to array at a time 4 #define MAG_IGNORE 50 // Ignore magnitudes fainter than this --- they're not real! 5 #define FAKE_SIZE 1 // Size of fake convolution kernel 6 #define SOURCE_MASK (PM_SOURCE_MODE_FAIL | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_SATURATED | PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT) // Mask to apply to input sources 7 #define NOISE_FRACTION 0.01 // Set minimum flux to this fraction of noise 8 #define COVAR_FRAC 0.01 // Truncation fraction for covariance matrix 1 # include "psphotInternal.h" 2 # define ARRAY_BUFFER 16 // Number to add to array at a time 9 3 10 4 // XXX better name … … 18 12 psFree(resolved); 19 13 if (!fits) { 20 psError(P PSTACK_ERR_IO, false, "Unable to open previously produced image: %s", name);14 psError(PSPHOT_ERR_IO, false, "Unable to open previously produced image: %s", name); 21 15 return false; 22 16 } 23 17 psImage *image = psFitsReadImage(fits, psRegionSet(0,0,0,0), 0); // Image of interest 24 18 if (!image) { 25 psError(P PSTACK_ERR_IO, false, "Unable to read previously produced image: %s", name);19 psError(PSPHOT_ERR_IO, false, "Unable to read previously produced image: %s", name); 26 20 psFitsClose(fits); 27 21 return false; … … 52 46 53 47 psArray *stackSourcesFilter(psArray *sources, // Source list to filter 54 int exclusion // Exclusion zone, pixels48 int exclusion // Exclusion zone, pixels 55 49 ) 56 50 { … … 90 84 91 85 long numWithin = psTreeWithin(tree, coords, exclusion); // Number within exclusion zone 92 psTrace("p pStack", 9, "Source at %.0lf,%.0lf has %ld sources in exclusion zone",86 psTrace("psphotStack", 9, "Source at %.0lf,%.0lf has %ld sources in exclusion zone", 93 87 coords->data.F64[0], coords->data.F64[1], numWithin); 94 88 if (numWithin == 1) { … … 104 98 psFree(y); 105 99 106 psLogMsg("p pStack", PS_LOG_INFO, "Filtered out %d of %d sources", numFiltered, numGood);100 psLogMsg("psphotStack", PS_LOG_INFO, "Filtered out %d of %d sources", numFiltered, numGood); 107 101 108 102 return filtered; … … 111 105 // Add background into the fake image 112 106 // Based on ppSubBackground() 113 staticpsImage *stackBackgroundModel(pmReadout *ro, // Readout for which to generate background model107 psImage *stackBackgroundModel(pmReadout *ro, // Readout for which to generate background model 114 108 const pmConfig *config // Configuration 115 109 ) … … 121 115 int numCols = image->numCols, numRows = image->numRows; // Size of image 122 116 123 psMetadata *ppStackRecipe = psMetadataLookupPtr(NULL, config->recipes, PPSTACK_RECIPE);117 psMetadata *ppStackRecipe = psMetadataLookupPtr(NULL, config->recipes, "PPSTACK"); 124 118 psAssert(ppStackRecipe, "Need PPSTACK recipe"); 125 psMetadata *psphotRecipe = psMetadataLookupPtr(NULL, config->recipes, PSPHOT_RECIPE);119 psMetadata *psphotRecipe = psMetadataLookupPtr(NULL, config->recipes, "PSPHOT"); 126 120 psAssert(psphotRecipe, "Need PSPHOT recipe"); 127 121 … … 138 132 psImage *unbinned = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Unbinned background model 139 133 if (!psImageUnbin(unbinned, binned, binning)) { 140 psError(P PSTACK_ERR_DATA, false, "Unable to unbin background model");134 psError(PSPHOT_ERR_DATA, false, "Unable to unbin background model"); 141 135 psFree(binned); 142 136 psFree(unbinned); … … 153 147 ) 154 148 { 155 #if 1156 149 bool mdok; // Status of metadata lookups 157 150 158 psMetadata *recipe = psMetadataLookupPtr(NULL, config->recipes, PPSTACK_RECIPE); // Recipe for ppStack151 psMetadata *recipe = psMetadataLookupPtr(NULL, config->recipes, "PPSTACK"); // Recipe for ppStack 159 152 psAssert(recipe, "Need PPSTACK recipe"); 160 153 … … 163 156 int num = psMetadataLookupS32(&mdok, recipe, "RENORM.NUM"); 164 157 if (!mdok) { 165 psError(P PSTACK_ERR_CONFIG, true, "RENORM.NUM is not set in the recipe");158 psError(PSPHOT_ERR_CONFIG, true, "RENORM.NUM is not set in the recipe"); 166 159 return false; 167 160 } 168 161 float minValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MIN"); 169 162 if (!mdok) { 170 psError(P PSTACK_ERR_CONFIG, true, "RENORM.MIN is not set in the recipe");163 psError(PSPHOT_ERR_CONFIG, true, "RENORM.MIN is not set in the recipe"); 171 164 return false; 172 165 } 173 166 float maxValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MAX"); 174 167 if (!mdok) { 175 psError(P PSTACK_ERR_CONFIG, true, "RENORM.MAX is not set in the recipe");168 psError(PSPHOT_ERR_CONFIG, true, "RENORM.MAX is not set in the recipe"); 176 169 return false; 177 170 } … … 181 174 psImageCovarianceTransfer(readout->variance, readout->covariance); 182 175 return pmReadoutVarianceRenormalise(readout, maskBad, num, minValid, maxValid); 183 #else184 return true;185 #endif186 176 } 187 177 … … 190 180 // It implicitly assumes the output root name is the same between invocations. 191 181 192 bool loadKernel () { 193 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.CONV.KERNEL", index); 194 psAssert(file, "Require file"); 195 196 pmFPAview *view = pmFPAviewAlloc(0); // View to readout of interest 197 view->chip = view->cell = view->readout = 0; 198 psString filename = pmFPAfileNameFromRule(file->filerule, file, view); // Filename of interest 199 200 // Read convolution kernel 201 psString resolved = pmConfigConvertFilename(filename, config, false, false); // Resolved filename 202 psFree(filename); 203 psFits *fits = psFitsOpen(resolved, "r"); // FITS file for subtraction kernel 204 psFree(resolved); 205 if (!fits || !pmReadoutReadSubtractionKernels(conv, fits)) { 206 psError(PPSTACK_ERR_IO, false, "Unable to read previously produced kernel"); 207 psFitsClose(fits); 208 return false; 209 } 210 psFitsClose(fits); 211 212 if (!readImage(&readout->image, options->convImages->data[index], config) || 213 !readImage(&readout->mask, options->convMasks->data[index], config) || 214 !readImage(&readout->variance, options->convVariances->data[index], config)) { 215 psError(PPSTACK_ERR_IO, false, "Unable to read previously produced image."); 216 return false; 217 } 218 219 psRegion *region = psMetadataLookupPtr(NULL, conv->analysis, 220 PM_SUBTRACTION_ANALYSIS_REGION); // Convolution region 221 pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, conv->analysis, 222 PM_SUBTRACTION_ANALYSIS_KERNEL); 223 224 pmSubtractionAnalysis(conv->analysis, NULL, kernels, region, 225 readout->image->numCols, readout->image->numRows); 226 227 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel 228 bool oldThreads = psImageCovarianceSetThreads(true); // Old thread setting 229 psKernel *covar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix 230 psImageCovarianceSetThreads(oldThreads); 231 psFree(readout->covariance); 232 readout->covariance = covar; 233 psFree(kernel); 234 } 235 236 bool dumpImage() { 237 // XXX should be optional 238 { 239 pmHDU *hdu = pmHDUFromCell(readout->parent); 240 psString name = NULL; 241 psStringAppend(&name, "fake_%03d.fits", index); 242 pmStackVisualPlotTestImage(fake->image, name); 243 psFits *fits = psFitsOpen(name, "w"); 244 psFree(name); 245 psFitsWriteImage(fits, hdu->header, fake->image, 0, NULL); 246 psFitsClose(fits); 247 } 248 { 249 pmHDU *hdu = pmHDUFromCell(readout->parent); 250 psString name = NULL; 251 psStringAppend(&name, "real_%03d.fits", index); 252 pmStackVisualPlotTestImage(readout->image, name); 253 psFits *fits = psFitsOpen(name, "w"); 254 psFree(name); 255 psFitsWriteImage(fits, hdu->header, readout->image, 0, NULL); 256 psFitsClose(fits); 257 } 258 } 259 260 bool dumpImage2() { 261 // XXX should be optional 262 263 { 264 pmHDU *hdu = pmHDUFromCell(readout->parent); 265 psString name = NULL; 266 psStringAppend(&name, "conv_%03d.fits", index); 267 pmStackVisualPlotTestImage(conv->image, name); 268 psFits *fits = psFitsOpen(name, "w"); 269 psFree(name); 270 psFitsWriteImage(fits, hdu->header, conv->image, 0, NULL); 271 psFitsClose(fits); 272 } 273 { 274 pmHDU *hdu = pmHDUFromCell(readout->parent); 275 psString name = NULL; 276 psStringAppend(&name, "diff_%03d.fits", index); 277 pmStackVisualPlotTestImage(fake->image, name); 278 psFits *fits = psFitsOpen(name, "w"); 279 psFree(name); 280 psBinaryOp(fake->image, conv->image, "-", fake->image); 281 psFitsWriteImage(fits, hdu->header, fake->image, 0, NULL); 282 psFitsClose(fits); 283 } 284 } 285 286 bool dumpImage3() 182 bool loadKernel (pmConfig *config, pmReadout *readoutCnv, psphotStackOptions *options, int index) { 183 184 // Read the convolution kernel from the saved file 185 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.CONV.KERNEL", index); 186 psAssert(file, "Require file"); 187 188 pmFPAview *view = pmFPAviewAlloc(0); // View to readout of interest 189 view->chip = view->cell = view->readout = 0; 190 psString filename = pmFPAfileNameFromRule(file->filerule, file, view); // Filename of interest 191 192 // Read convolution kernel data 193 psString resolved = pmConfigConvertFilename(filename, config, false, false); // Resolved filename 194 psFree(filename); 195 psFits *fits = psFitsOpen(resolved, "r"); // FITS file for subtraction kernel 196 psFree(resolved); 197 if (!fits || !pmReadoutReadSubtractionKernels(readoutCnv, fits)) { 198 psError(PSPHOT_ERR_IO, false, "Unable to read previously produced kernel"); 199 psFitsClose(fits); 200 return false; 201 } 202 psFitsClose(fits); 203 204 // read the convolved pixels (image, mask, variance) -- names are pre-defined 205 if (!readImage(&readoutCnv->image, options->convImages->data[index], config) || 206 !readImage(&readoutCnv->mask, options->convMasks->data[index], config) || 207 !readImage(&readoutCnv->variance, options->convVariances->data[index], config)) { 208 psError(PSPHOT_ERR_IO, false, "Unable to read previously produced image."); 209 return false; 210 } 211 212 // XXX ??? not sure what is happening here -- consult Paul 213 psRegion *region = psMetadataLookupPtr(NULL, readoutCnv->analysis, PM_SUBTRACTION_ANALYSIS_REGION); // Convolution region 214 pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, readoutCnv->analysis, PM_SUBTRACTION_ANALYSIS_KERNEL); 215 216 pmSubtractionAnalysis(readoutCnv->analysis, NULL, kernels, region, readoutCnv->image->numCols, readoutCnv->image->numRows); 217 218 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel 219 220 // update the covariance matrix 221 // XXX why is this needed if we have correctly read the saved data? 222 bool oldThreads = psImageCovarianceSetThreads(true); // Old thread setting 223 psKernel *covar = psImageCovarianceCalculate(kernel, readoutCnv->covariance); // Covariance matrix 224 psImageCovarianceSetThreads(oldThreads); 225 psFree(readoutCnv->covariance); 226 readoutCnv->covariance = covar; 227 psFree(kernel); 228 return true; 229 } 230 231 bool dumpImage(pmReadout *readoutOut, pmReadout *readoutRef, int index, char *rootname) { 232 233 pmHDU *hdu = pmHDUFromCell(readoutRef->parent); 234 psString name = NULL; 235 psStringAppend(&name, "%s_%03d.fits", rootname, index); 236 pmStackVisualPlotTestImage(readoutOut->image, name); 237 psFits *fits = psFitsOpen(name, "w"); 238 psFree(name); 239 psFitsWriteImage(fits, hdu->header, readoutOut->image, 0, NULL); 240 psFitsClose(fits); 241 return true; 242 } 243 244 bool dumpImageDiff(pmReadout *readoutConv, pmReadout *readoutFake, pmReadout *readoutRef, int index, char *rootname) { 245 246 pmHDU *hdu = pmHDUFromCell(readoutRef->parent); 247 psString name = NULL; 248 psStringAppend(&name, "%s_%03d.fits", rootname, index); 249 pmStackVisualPlotTestImage(readoutFake->image, name); 250 psFits *fits = psFitsOpen(name, "w"); 251 psFree(name); 252 psBinaryOp(readoutFake->image, readoutConv->image, "-", readoutFake->image); 253 psFitsWriteImage(fits, hdu->header, readoutFake->image, 0, NULL); 254 psFitsClose(fits); 255 return true; 256 } 257 258 // perform the bulk of the PSF-matching 259 bool matchKernel(pmConfig *config, pmReadout *readoutCnv, pmReadout *readoutRaw, psphotStackOptions *options, int index) { 260 261 bool mdok; 262 263 psAssert(options->psf, "Require target PSF"); 264 psAssert(options->sourceLists && options->sourceLists->data[index], "Require source list"); 265 266 psMetadata *stackRecipe = psMetadataLookupMetadata(NULL, config->recipes, "PPSTACK"); // ppStack recipe 267 psAssert(stackRecipe, "We've thrown an error on this before."); 268 269 // Look up appropriate values from the ppSub recipe 270 psMetadata *subRecipe = psMetadataLookupMetadata(NULL, config->recipes, "PPSUB"); // PPSUB recipe 271 psAssert(subRecipe, "recipe missing"); 272 273 psString maskValStr = psMetadataLookupStr(NULL, subRecipe, "MASK.VAL"); // Name of bits to mask going in 274 psString maskPoorStr = psMetadataLookupStr(NULL, stackRecipe, "MASK.POOR"); // Name of bits to mask for poor 275 psString maskBadStr = psMetadataLookupStr(NULL, stackRecipe, "MASK.BAD"); // Name of bits to mask for bad 276 277 psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch 278 psImageMaskType maskPoor = pmConfigMaskGet(maskPoorStr, config); // Bits to mask for poor pixels 279 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels 280 281 float penalty = psMetadataLookupF32(NULL, subRecipe, "PENALTY"); // Penalty for wideness 282 int threads = psMetadataLookupS32(NULL, config->arguments, "-threads"); // Number of threads 283 284 int order = psMetadataLookupS32(NULL, subRecipe, "SPATIAL.ORDER"); // Spatial polynomial order 285 float regionSize = psMetadataLookupF32(NULL, subRecipe, "REGION.SIZE"); // Size of iso-kernel regs 286 float spacing = psMetadataLookupF32(NULL, subRecipe, "STAMP.SPACING"); // Typical stamp spacing 287 288 int footprint = psMetadataLookupS32(NULL, subRecipe, "STAMP.FOOTPRINT"); // Stamp half-size 289 int size = psMetadataLookupS32(NULL, subRecipe, "KERNEL.SIZE"); // Kernel half-size 290 291 float threshold = psMetadataLookupF32(NULL, subRecipe, "STAMP.THRESHOLD"); // Threshold for stmps 292 int stride = psMetadataLookupS32(NULL, subRecipe, "STRIDE"); // Size of convolution patches 293 int iter = psMetadataLookupS32(NULL, subRecipe, "ITER"); // Rejection iterations 294 float rej = psMetadataLookupF32(NULL, subRecipe, "REJ"); // Rejection threshold 295 float kernelError = psMetadataLookupF32(NULL, subRecipe, "KERNEL.ERR"); // Relative systematic error in kernel 296 float normFrac = psMetadataLookupF32(NULL, subRecipe, "NORM.FRAC"); // Fraction of window for normalisn windw 297 float sysError = psMetadataLookupF32(NULL, subRecipe, "SYS.ERR"); // Relative systematic error in images 298 float skyErr = psMetadataLookupF32(NULL, subRecipe, "SKY.ERR"); // Additional error in sky 299 float covarFrac = psMetadataLookupF32(NULL, subRecipe, "COVAR.FRAC"); // Fraction for covariance calculation 300 301 const char *typeStr = psMetadataLookupStr(NULL, subRecipe, "KERNEL.TYPE"); // Kernel type 302 pmSubtractionKernelsType type = pmSubtractionKernelsTypeFromString(typeStr); // Kernel type 303 psVector *widths = psMetadataLookupPtr(NULL, subRecipe, "ISIS.WIDTHS"); // ISIS Gaussian widths 304 psVector *orders = psMetadataLookupPtr(NULL, subRecipe, "ISIS.ORDERS"); // ISIS Polynomial orders 305 int inner = psMetadataLookupS32(NULL, subRecipe, "INNER"); // Inner radius 306 int ringsOrder = psMetadataLookupS32(NULL, subRecipe, "RINGS.ORDER"); // RINGS polynomial order 307 int binning = psMetadataLookupS32(NULL, subRecipe, "SPAM.BINNING"); // Binning for SPAM kernel 308 float badFrac = psMetadataLookupF32(NULL, subRecipe, "BADFRAC"); // Maximum bad fraction 309 float optThresh = psMetadataLookupF32(&mdok, subRecipe, "OPTIMUM.TOL"); // Tolerance for search 310 int optOrder = psMetadataLookupS32(&mdok, subRecipe, "OPTIMUM.ORDER"); // Order for search 311 float poorFrac = psMetadataLookupF32(&mdok, subRecipe, "POOR.FRACTION"); // Fraction for "poor" 312 313 bool scale = psMetadataLookupBool(NULL, subRecipe, "SCALE"); // Scale kernel parameters? 314 float scaleRef = psMetadataLookupF32(NULL, subRecipe, "SCALE.REF"); // Reference for scaling 315 float scaleMin = psMetadataLookupF32(NULL, subRecipe, "SCALE.MIN"); // Minimum for scaling 316 float scaleMax = psMetadataLookupF32(NULL, subRecipe, "SCALE.MAX"); // Maximum for scaling 317 if (!isfinite(scaleRef) || !isfinite(scaleMin) || !isfinite(scaleMax)) { 318 psError(PSPHOT_ERR_CONFIG, false, 319 "Scale parameters (SCALE.REF=%f, SCALE.MIN=%f, SCALE.MAX=%f) not set in PPSUB recipe.", 320 scaleRef, scaleMin, scaleMax); 321 return false; 322 } 323 324 // These values are specified specifically for stacking 325 const char *stampsName = psMetadataLookupStr(NULL, config->arguments, "STAMPS");// Stamps filename 326 327 psVector *widthsCopy = NULL; 328 psVector *optWidths = NULL; 329 pmReadout *fake = NULL; 330 psArray *stampSources = NULL; 331 332 bool optimum = false; 333 optWidths = SetOptWidths(&optimum, subRecipe); // Vector with FWHMs for optimum search 334 335 // For the sake of stamps, remove nearby sources 336 stampSources = stackSourcesFilter(options->sourceLists->data[index], footprint); // Filtered list of sources 337 338 fake = makeFakeReadout(config, readoutRaw, stampSources, options->psf, maskVal | maskBad, footprint + size); 339 if (!fake) goto escape; 340 341 dumpImage(fake, readoutRaw, index, "fake"); 342 dumpImage(readoutRaw, readoutRaw, index, "real"); 343 344 if (threads) pmSubtractionThreadsInit(); 345 346 // Do the image matching 347 pmSubtractionKernels *kernel = psMetadataLookupPtr(&mdok, readoutRaw->analysis, PM_SUBTRACTION_ANALYSIS_KERNEL); // Conv kernel 348 if (kernel) { 349 if (!pmSubtractionMatchPrecalc(NULL, readoutCnv, fake, readoutRaw, readoutRaw->analysis, stride, kernelError, covarFrac, maskVal, maskBad, maskPoor, poorFrac, badFrac)) { 350 psError(psErrorCodeLast(), false, "Unable to convolve images."); 351 goto escape; 352 } 353 } else { 354 // Scale the input parameters 355 widthsCopy = psVectorCopy(NULL, widths, PS_TYPE_F32); // Copy of kernel widths 356 if (scale && !pmSubtractionParamsScale(&size, &footprint, widthsCopy, options->inputSeeing->data.F32[index], options->targetSeeing, scaleRef, scaleMin, scaleMax)) { 357 psError(psErrorCodeLast(), false, "Unable to scale kernel parameters"); 358 goto escape; 359 } 360 361 if (!pmSubtractionMatch(NULL, readoutCnv, fake, readoutRaw, footprint, stride, regionSize, spacing, threshold, stampSources, stampsName, type, size, order, widthsCopy, orders, inner, ringsOrder, binning, penalty, optimum, optWidths, optOrder, optThresh, iter, rej, normFrac, sysError, skyErr, kernelError, covarFrac, maskVal, maskBad, maskPoor, poorFrac, badFrac, PM_SUBTRACTION_MODE_2)) { 362 psError(psErrorCodeLast(), false, "Unable to match images."); 363 goto escape; 364 } 365 } 366 367 // Reject image completely if the maximum deconvolution fraction exceeds the limit 368 float deconvLimit = psMetadataLookupF32(NULL, stackRecipe, "DECONV.LIMIT"); // Limit on deconvolution fraction 369 float deconv = psMetadataLookupF32(NULL, readoutCnv->analysis, PM_SUBTRACTION_ANALYSIS_DECONV_MAX); // Max deconvolution fraction 370 if (deconv > deconvLimit) { 371 psWarning("Maximum deconvolution fraction (%f) exceeds limit (%f) --- rejecting image %d\n", deconv, deconvLimit, index); 372 goto escape; 373 } 374 375 dumpImage(readoutCnv, readoutRaw, index, "conv"); 376 dumpImageDiff(readoutCnv, fake, readoutRaw, index, "diff"); 377 378 psFree(fake); 379 psFree(optWidths); 380 psFree(stampSources); 381 psFree(widthsCopy); 382 pmSubtractionThreadsFinalize(); 383 return true; 384 385 escape: 386 psFree(fake); 387 psFree(optWidths); 388 psFree(stampSources); 389 psFree(widthsCopy); 390 pmSubtractionThreadsFinalize(); 391 return false; 392 } 393 394 // Extract the regions and solutions used in the image matching 395 // This stops them from being freed when we iterate back up the FPA 396 // Record the chi-square value 397 // XXX this function may not be needed for psphotStack 398 bool saveMatchData (pmReadout *readout, psphotStackOptions *options, int index) { 399 400 psArray *regions = options->regions->data[index] = psArrayAllocEmpty(ARRAY_BUFFER); // Match regions 287 401 { 288 pmHDU *hdu = pmHDUFromCell(readout->parent); 289 psString name = NULL; 290 psStringAppend(&name, "convolved_%03d.fits", index); 291 pmStackVisualPlotTestImage(readout->image, name); 292 psFits *fits = psFitsOpen(name, "w"); 293 psFree(name); 294 psFitsWriteImage(fits, hdu->header, readout->image, 0, NULL); 295 psFitsClose(fits); 296 } 297 298 bool matchKernel() { 299 // Normal operations here 300 psAssert(options->psf, "Require target PSF"); 301 psAssert(options->sourceLists && options->sourceLists->data[index], "Require source list"); 302 303 int order = psMetadataLookupS32(NULL, subRecipe, "SPATIAL.ORDER"); // Spatial polynomial order 304 float regionSize = psMetadataLookupF32(NULL, subRecipe, "REGION.SIZE"); // Size of iso-kernel regs 305 float spacing = psMetadataLookupF32(NULL, subRecipe, "STAMP.SPACING"); // Typical stamp spacing 306 int footprint = psMetadataLookupS32(NULL, subRecipe, "STAMP.FOOTPRINT"); // Stamp half-size 307 float threshold = psMetadataLookupF32(NULL, subRecipe, "STAMP.THRESHOLD"); // Threshold for stmps 308 int stride = psMetadataLookupS32(NULL, subRecipe, "STRIDE"); // Size of convolution patches 309 int iter = psMetadataLookupS32(NULL, subRecipe, "ITER"); // Rejection iterations 310 float rej = psMetadataLookupF32(NULL, subRecipe, "REJ"); // Rejection threshold 311 float kernelError = psMetadataLookupF32(NULL, subRecipe, "KERNEL.ERR"); // Relative systematic error in kernel 312 float normFrac = psMetadataLookupF32(NULL, subRecipe, "NORM.FRAC"); // Fraction of window for normalisn windw 313 float sysError = psMetadataLookupF32(NULL, subRecipe, "SYS.ERR"); // Relative systematic error in images 314 float skyErr = psMetadataLookupF32(NULL, subRecipe, "SKY.ERR"); // Additional error in sky 315 float covarFrac = psMetadataLookupF32(NULL, subRecipe, "COVAR.FRAC"); // Fraction for covariance calculation 316 317 const char *typeStr = psMetadataLookupStr(NULL, subRecipe, "KERNEL.TYPE"); // Kernel type 318 pmSubtractionKernelsType type = pmSubtractionKernelsTypeFromString(typeStr); // Kernel type 319 psVector *widths = psMetadataLookupPtr(NULL, subRecipe, "ISIS.WIDTHS"); // ISIS Gaussian widths 320 psVector *orders = psMetadataLookupPtr(NULL, subRecipe, "ISIS.ORDERS"); // ISIS Polynomial orders 321 int inner = psMetadataLookupS32(NULL, subRecipe, "INNER"); // Inner radius 322 int ringsOrder = psMetadataLookupS32(NULL, subRecipe, "RINGS.ORDER"); // RINGS polynomial order 323 int binning = psMetadataLookupS32(NULL, subRecipe, "SPAM.BINNING"); // Binning for SPAM kernel 324 float badFrac = psMetadataLookupF32(NULL, subRecipe, "BADFRAC"); // Maximum bad fraction 325 bool optimum = psMetadataLookupBool(&mdok, subRecipe, "OPTIMUM"); // Derive optimum parameters? 326 float optMin = psMetadataLookupF32(&mdok, subRecipe, "OPTIMUM.MIN"); // Minimum width for search 327 float optMax = psMetadataLookupF32(&mdok, subRecipe, "OPTIMUM.MAX"); // Maximum width for search 328 float optStep = psMetadataLookupF32(&mdok, subRecipe, "OPTIMUM.STEP"); // Step for search 329 float optThresh = psMetadataLookupF32(&mdok, subRecipe, "OPTIMUM.TOL"); // Tolerance for search 330 int optOrder = psMetadataLookupS32(&mdok, subRecipe, "OPTIMUM.ORDER"); // Order for search 331 float poorFrac = psMetadataLookupF32(&mdok, subRecipe, "POOR.FRACTION"); // Fraction for "poor" 332 333 bool scale = psMetadataLookupBool(NULL, subRecipe, "SCALE"); // Scale kernel parameters? 334 float scaleRef = psMetadataLookupF32(NULL, subRecipe, "SCALE.REF"); // Reference for scaling 335 float scaleMin = psMetadataLookupF32(NULL, subRecipe, "SCALE.MIN"); // Minimum for scaling 336 float scaleMax = psMetadataLookupF32(NULL, subRecipe, "SCALE.MAX"); // Maximum for scaling 337 if (!isfinite(scaleRef) || !isfinite(scaleMin) || !isfinite(scaleMax)) { 338 psError(PPSTACK_ERR_CONFIG, false, 339 "Scale parameters (SCALE.REF=%f, SCALE.MIN=%f, SCALE.MAX=%f) not set in PPSUB recipe.", 340 scaleRef, scaleMin, scaleMax); 341 return false; 342 } 343 344 345 // These values are specified specifically for stacking 346 const char *stampsName = psMetadataLookupStr(NULL, config->arguments, "STAMPS");// Stamps filename 347 348 psVector *optWidths = NULL; // Vector with FWHMs for optimum search 349 if (optimum) { 350 optWidths = psVectorCreate(optWidths, optMin, optMax, optStep, PS_TYPE_F32); 351 } 352 353 pmReadout *fake = pmReadoutAlloc(NULL); // Fake readout with target PSF 354 355 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_STDEV); // Statistics for background 356 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 357 if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) { 358 psError(PPSTACK_ERR_DATA, false, "Can't measure background for image."); 359 psFree(fake); 360 psFree(optWidths); 361 psFree(conv); 362 psFree(bg); 363 psFree(rng); 364 return false; 365 } 366 float minFlux = NOISE_FRACTION * bg->robustStdev; // Minimum flux level for fake image 402 psString regex = NULL; // Regular expression 403 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_REGION); 404 psMetadataIterator *iter = psMetadataIteratorAlloc(readout->analysis, PS_LIST_HEAD, regex); 405 psFree(regex); 406 psMetadataItem *item = NULL;// Item from iteration 407 while ((item = psMetadataGetAndIncrement(iter))) { 408 assert(item->type == PS_DATA_REGION); 409 regions = psArrayAdd(regions, ARRAY_BUFFER, item->data.V); 410 } 411 psFree(iter); 412 } 413 414 psArray *kernels = options->kernels->data[index] = psArrayAllocEmpty(ARRAY_BUFFER); // Match kernels 415 { 416 psString regex = NULL; // Regular expression 417 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL); 418 psMetadataIterator *iter = psMetadataIteratorAlloc(readout->analysis, PS_LIST_HEAD, regex); 419 psFree(regex); 420 psMetadataItem *item = NULL;// Item from iteration 421 while ((item = psMetadataGetAndIncrement(iter))) { 422 assert(item->type == PS_DATA_UNKNOWN); 423 pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction 424 kernels = psArrayAdd(kernels, ARRAY_BUFFER, kernel); 425 } 426 psFree(iter); 427 } 428 psAssert((regions)->n == (kernels)->n, "Number of match regions and kernels should match"); 429 430 // Record chi^2 431 { 432 double sum = 0.0; // Sum of chi^2 433 int num = 0; // Number of measurements of chi^2 434 psString regex = NULL; // Regular expression 435 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL); 436 psMetadataIterator *iter = psMetadataIteratorAlloc(readout->analysis, PS_LIST_HEAD, regex); 437 psFree(regex); 438 psMetadataItem *item = NULL;// Item from iteration 439 while ((item = psMetadataGetAndIncrement(iter))) { 440 assert(item->type == PS_DATA_UNKNOWN); 441 pmSubtractionKernels *kernels = item->data.V; // Convolution kernels 442 sum += kernels->mean; 443 num++; 444 } 445 psFree(iter); 446 options->matchChi2->data.F32[index] = sum / (psImageCovarianceFactor(readout->covariance) * num); 447 } 448 449 return true; 450 } 451 452 // Kernel normalisation for convolved readout 453 bool renormKernel(pmReadout *readout, psphotStackOptions *options, int index) { 454 455 double sum = 0.0; // Sum of chi^2 456 int num = 0; // Number of measurements of chi^2 457 psString regex = NULL; // Regular expression 458 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_NORM); 459 psMetadataIterator *iter = psMetadataIteratorAlloc(readout->analysis, PS_LIST_HEAD, regex); 460 psFree(regex); 461 psMetadataItem *item = NULL;// Item from iteration 462 while ((item = psMetadataGetAndIncrement(iter))) { 463 assert(item->type == PS_TYPE_F32); 464 float norm = item->data.F32; // Normalisation 465 sum += norm; 466 num++; 467 } 468 psFree(iter); 469 float conv = sum/num; // Mean normalisation from convolution 470 float stars = powf(10.0, -0.4 * options->norm->data.F32[index]); // Normalisation from stars 471 float renorm = stars / conv; // Renormalisation to apply 472 psLogMsg("psphotStack", PS_LOG_INFO, "Renormalising image %d by %f (kernel: %f, stars: %f)\n", index, renorm, conv, stars); 473 474 psBinaryOp(readout->image, readout->image, "*", psScalarAlloc(renorm, PS_TYPE_F32)); 475 psBinaryOp(readout->variance, readout->variance, "*", psScalarAlloc(PS_SQR(renorm), PS_TYPE_F32)); 476 return true; 477 } 478 479 // adjust scaling for readout (remove background, ..., determine weighting) 480 bool rescaleData(pmReadout *readout, pmConfig *config, psphotStackOptions *options, int index) { 481 482 psMetadata *stackRecipe = psMetadataLookupMetadata(NULL, config->recipes, "PPSTACK"); // ppStack recipe 483 psAssert(stackRecipe, "We've thrown an error on this before."); 484 485 // Look up appropriate values from the ppSub recipe 486 psMetadata *subRecipe = psMetadataLookupMetadata(NULL, config->recipes, "PPSUB"); // PPSUB recipe 487 psAssert(subRecipe, "recipe missing"); 488 489 psString maskValStr = psMetadataLookupStr(NULL, subRecipe, "MASK.VAL"); // Name of bits to mask going in 490 psString maskBadStr = psMetadataLookupStr(NULL, stackRecipe, "MASK.BAD"); // Name of bits to mask for bad 491 492 psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch 493 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels 494 495 // Ensure the background value is zero 496 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for background 497 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 498 499 // XXX why is this in config->arguments and not recipe? 500 if (!psMetadataLookupBool(NULL, config->arguments, "PPSTACK.SKIP.BG.SUB")) { 501 if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) { 502 psAbort("Can't measure background for image."); 503 // XXX we used to clear error: why is this acceptable? psErrorClear(); 504 } 505 506 float value = psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN); 507 float stdev = psStatsGetValue(bg, PS_STAT_ROBUST_STDEV); 508 509 psLogMsg("psphotStack", PS_LOG_INFO, "Correcting convolved image background by %lf (+/- %lf)", value, stdev); 510 psBinaryOp(readout->image, readout->image, "-", psScalarAlloc(value, PS_TYPE_F32)); 511 } 512 513 if (!stackRenormaliseReadout(config, readout)) { 514 psFree(rng); 515 psFree(bg); 516 return false; 517 } 518 519 // Measure the variance level for the weighting 520 if (psMetadataLookupBool(NULL, stackRecipe, "WEIGHTS")) { 521 if (!psImageBackground(bg, NULL, readout->variance, readout->mask, maskVal | maskBad, rng)) { 522 psError(PSPHOT_ERR_DATA, false, "Can't measure mean variance for image."); 367 523 psFree(rng); 368 524 psFree(bg); 369 370 // For the sake of stamps, remove nearby sources 371 psArray *stampSources = stackSourcesFilter(options->sourceLists->data[index], 372 footprint); // Filtered list of sources 373 374 bool oldThreads = pmReadoutFakeThreads(true); // Old threading state 375 if (!pmReadoutFakeFromSources(fake, readout->image->numCols, readout->image->numRows, 376 stampSources, SOURCE_MASK, NULL, NULL, options->psf, 377 minFlux, footprint + size, false, true)) { 378 psError(PPSTACK_ERR_DATA, false, "Unable to generate fake image with target PSF."); 379 psFree(fake); 380 psFree(optWidths); 381 psFree(conv); 382 return false; 383 } 384 pmReadoutFakeThreads(oldThreads); 385 386 fake->mask = psImageCopy(NULL, readout->mask, PS_TYPE_IMAGE_MASK); 387 388 // Add the background into the target image 389 psImage *bgImage = stackBackgroundModel(readout, config); // Image of background 390 psBinaryOp(fake->image, fake->image, "+", bgImage); 391 psFree(bgImage); 392 393 dumpImage(); 394 395 if (threads > 0) { 396 pmSubtractionThreadsInit(); 397 } 398 399 // Do the image matching 400 pmSubtractionKernels *kernel = psMetadataLookupPtr(&mdok, readout->analysis, PM_SUBTRACTION_ANALYSIS_KERNEL); // Conv kernel 401 if (kernel) { 402 if (!pmSubtractionMatchPrecalc(NULL, conv, fake, readout, readout->analysis, 403 stride, kernelError, covarFrac, maskVal, maskBad, maskPoor, 404 poorFrac, badFrac)) { 405 psError(psErrorCodeLast(), false, "Unable to convolve images."); 406 psFree(fake); 407 psFree(optWidths); 408 psFree(stampSources); 409 psFree(conv); 410 if (threads > 0) { 411 pmSubtractionThreadsFinalize(); 412 } 413 return false; 414 } 415 } else { 416 // Scale the input parameters 417 psVector *widthsCopy = psVectorCopy(NULL, widths, PS_TYPE_F32); // Copy of kernel widths 418 if (scale && !pmSubtractionParamsScale(&size, &footprint, widthsCopy, 419 options->inputSeeing->data.F32[index], 420 options->targetSeeing, scaleRef, scaleMin, scaleMax)) { 421 psError(psErrorCodeLast(), false, "Unable to scale kernel parameters"); 422 psFree(fake); 423 psFree(optWidths); 424 psFree(stampSources); 425 psFree(conv); 426 psFree(widthsCopy); 427 if (threads > 0) { 428 pmSubtractionThreadsFinalize(); 429 } 430 return false; 431 } 432 433 if (!pmSubtractionMatch(NULL, conv, fake, readout, footprint, stride, regionSize, spacing, 434 threshold, stampSources, stampsName, type, size, order, widthsCopy, 435 orders, inner, ringsOrder, binning, penalty, 436 optimum, optWidths, optOrder, optThresh, iter, rej, normFrac, 437 sysError, skyErr, kernelError, covarFrac, maskVal, maskBad, maskPoor, 438 poorFrac, badFrac, PM_SUBTRACTION_MODE_2)) { 439 psError(psErrorCodeLast(), false, "Unable to match images."); 440 psFree(fake); 441 psFree(optWidths); 442 psFree(stampSources); 443 psFree(conv); 444 psFree(widthsCopy); 445 if (threads > 0) { 446 pmSubtractionThreadsFinalize(); 447 } 448 return false; 449 } 450 psFree(widthsCopy); 451 } 452 453 dumpImage2(); 454 455 psFree(fake); 456 psFree(optWidths); 457 psFree(stampSources); 458 459 if (threads > 0) { 460 pmSubtractionThreadsFinalize(); 461 } 462 463 // Replace original images with convolved 464 psFree(readout->image); 465 psFree(readout->mask); 466 psFree(readout->variance); 467 psFree(readout->covariance); 468 readout->image = psMemIncrRefCounter(conv->image); 469 readout->mask = psMemIncrRefCounter(conv->mask); 470 readout->variance = psMemIncrRefCounter(conv->variance); 471 readout->covariance = psImageCovarianceTruncate(conv->covariance, COVAR_FRAC); 472 473 } 474 475 bool saveMatchData () { 476 // Extract the regions and solutions used in the image matching 477 // This stops them from being freed when we iterate back up the FPA 478 psArray *regions = options->regions->data[index] = psArrayAllocEmpty(ARRAY_BUFFER); // Match regions 479 { 480 psString regex = NULL; // Regular expression 481 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_REGION); 482 psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex); 483 psFree(regex); 484 psMetadataItem *item = NULL;// Item from iteration 485 while ((item = psMetadataGetAndIncrement(iter))) { 486 assert(item->type == PS_DATA_REGION); 487 regions = psArrayAdd(regions, ARRAY_BUFFER, item->data.V); 488 } 489 psFree(iter); 525 return false; 490 526 } 491 psArray *kernels = options->kernels->data[index] = psArrayAllocEmpty(ARRAY_BUFFER); // Match kernels 492 { 493 psString regex = NULL; // Regular expression 494 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL); 495 psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex); 496 psFree(regex); 497 psMetadataItem *item = NULL;// Item from iteration 498 while ((item = psMetadataGetAndIncrement(iter))) { 499 assert(item->type == PS_DATA_UNKNOWN); 500 pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction 501 kernels = psArrayAdd(kernels, ARRAY_BUFFER, kernel); 502 } 503 psFree(iter); 504 } 505 psAssert((regions)->n == (kernels)->n, "Number of match regions and kernels should match"); 506 } 507 508 bool saveChiSquare() { 509 // Record chi^2 510 { 511 double sum = 0.0; // Sum of chi^2 512 int num = 0; // Number of measurements of chi^2 513 psString regex = NULL; // Regular expression 514 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL); 515 psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex); 516 psFree(regex); 517 psMetadataItem *item = NULL;// Item from iteration 518 while ((item = psMetadataGetAndIncrement(iter))) { 519 assert(item->type == PS_DATA_UNKNOWN); 520 pmSubtractionKernels *kernels = item->data.V; // Convolution kernels 521 sum += kernels->mean; 522 num++; 523 } 524 psFree(iter); 525 options->matchChi2->data.F32[index] = sum / (psImageCovarianceFactor(readout->covariance) * num); 526 } 527 528 } 529 530 bool renormKernel() { 531 // Kernel normalisation 532 { 533 double sum = 0.0; // Sum of chi^2 534 int num = 0; // Number of measurements of chi^2 535 psString regex = NULL; // Regular expression 536 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_NORM); 537 psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex); 538 psFree(regex); 539 psMetadataItem *item = NULL;// Item from iteration 540 while ((item = psMetadataGetAndIncrement(iter))) { 541 assert(item->type == PS_TYPE_F32); 542 float norm = item->data.F32; // Normalisation 543 sum += norm; 544 num++; 545 } 546 psFree(iter); 547 float conv = sum/num; // Mean normalisation from convolution 548 float stars = powf(10.0, -0.4 * options->norm->data.F32[index]); // Normalisation from stars 549 float renorm = stars / conv; // Renormalisation to apply 550 psLogMsg("ppStack", PS_LOG_INFO, "Renormalising image %d by %f (kernel: %f, stars: %f)\n", 551 index, renorm, conv, stars); 552 psBinaryOp(readout->image, readout->image, "*", psScalarAlloc(renorm, PS_TYPE_F32)); 553 psBinaryOp(readout->variance, readout->variance, "*", psScalarAlloc(PS_SQR(renorm), PS_TYPE_F32)); 554 } 555 556 } 527 options->weightings->data.F32[index] = 1.0 / (psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN) * psImageCovarianceFactor(readout->covariance)); 528 } else { 529 options->weightings->data.F32[index] = 1.0; 530 } 531 psLogMsg("psphotStack", PS_LOG_INFO, "Weighting for image %d is %f\n", index, options->weightings->data.F32[index]); 532 533 psFree(rng); 534 psFree(bg); 535 return true; 536 } 537 538 # define NOISE_FRACTION 0.01 // Set minimum flux to this fraction of noise 539 # define SOURCE_MASK (PM_SOURCE_MODE_FAIL | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_SATURATED | PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT) // Mask to apply to input sources 540 541 // generate a fake readout against which to PSF match 542 pmReadout *makeFakeReadout(pmConfig *config, pmReadout *readoutRaw, psArray *sources, pmPSF *psf, psImageMaskType maskVal, int fullSize) { 543 544 pmReadout *fake = pmReadoutAlloc(NULL); // Fake readout with target PSF 545 546 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_STDEV); // Statistics for background 547 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 548 if (!psImageBackground(bg, NULL, readoutRaw->image, readoutRaw->mask, maskVal, rng)) { 549 psError(PSPHOT_ERR_DATA, false, "Can't measure background for image."); 550 psFree(fake); 551 psFree(bg); 552 psFree(rng); 553 return NULL; 554 } 555 float minFlux = NOISE_FRACTION * bg->robustStdev; // Minimum flux level for fake image 556 psFree(rng); 557 psFree(bg); 558 559 bool oldThreads = pmReadoutFakeThreads(true); // Old threading state 560 if (!pmReadoutFakeFromSources(fake, readoutRaw->image->numCols, readoutRaw->image->numRows, sources, SOURCE_MASK, NULL, NULL, psf, minFlux, fullSize, false, true)) { 561 psError(PSPHOT_ERR_DATA, false, "Unable to generate fake image with target PSF."); 562 psFree(fake); 563 return NULL; 564 } 565 pmReadoutFakeThreads(oldThreads); 566 567 fake->mask = psImageCopy(NULL, readoutRaw->mask, PS_TYPE_IMAGE_MASK); 568 569 // Add the background into the target image 570 psImage *bgImage = stackBackgroundModel(readoutRaw, config); // Image of background 571 psBinaryOp(fake->image, fake->image, "+", bgImage); 572 psFree(bgImage); 573 574 return fake; 575 } 576 577 // set the widths 578 psVector *SetOptWidths (bool *optimum, psMetadata *recipe) { 579 580 bool status; 581 582 *optimum = psMetadataLookupBool(&status, recipe, "OPTIMUM"); // Derive optimum parameters? 583 psAssert (status, "missing recipe value %s", "OPTIMUM"); 584 585 psVector *optWidths = NULL; // Vector with FWHMs for optimum search 586 587 if (*optimum) { 588 float optMin = psMetadataLookupF32(&status, recipe, "OPTIMUM.MIN"); // Minimum width for search 589 psAssert (status, "missing recipe value %s", "OPTIMUM.MIN"); 590 591 float optMax = psMetadataLookupF32(&status, recipe, "OPTIMUM.MAX"); // Maximum width for search 592 psAssert (status, "missing recipe value %s", "OPTIMUM.MAX"); 593 594 float optStep = psMetadataLookupF32(&status, recipe, "OPTIMUM.STEP"); // Step for search 595 psAssert (status, "missing recipe value %s", "OPTIMUM.STEP"); 596 597 optWidths = psVectorCreate(optWidths, optMin, optMax, optStep, PS_TYPE_F32); 598 } 599 600 return optWidths; 601 }
Note:
See TracChangeset
for help on using the changeset viewer.
