Changeset 27850
- Timestamp:
- May 4, 2010, 8:59:10 AM (16 years ago)
- Location:
- trunk/psphot/src
- Files:
-
- 1 added
- 1 edited
-
psphotStackMatchPSFs.c (modified) (10 diffs)
-
psphotStackMatchPSFsUtils.c (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psphot/src/psphotStackMatchPSFs.c
r27848 r27850 5 5 bool status = true; 6 6 7 // select the appropriate recipe information8 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);9 psAssert (recipe, "missing recipe?");10 11 7 int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM"); 12 8 psAssert (status, "programming error: must define PSPHOT.INPUT.NUM"); … … 14 10 // loop over the available readouts 15 11 for (int i = 0; i < num; i++) { 16 if (!psphotStackMatchPSFsReadout (config, view, i , recipe)) {12 if (!psphotStackMatchPSFsReadout (config, view, i)) { 17 13 psError (PSPHOT_ERR_CONFIG, false, "failed to find initial detections for PSPHOT.INPUT entry %d", i); 18 14 return false; … … 23 19 24 20 // convolve the image to match desired PSF 25 bool psphotStackMatchPSFsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {21 bool psphotStackMatchPSFsReadout (pmConfig *config, const pmFPAview *view, int index) { 26 22 27 23 bool status; … … 29 25 float NSIGMA_PEAK = 25.0; 30 26 int NMAX = 0; 31 32 Raw;33 Cnv;34 27 35 28 // find the currently selected readout … … 50 43 psAssert (maskVal, "missing mask value?"); 51 44 52 psphotStackMatch();45 /***** set up recipe options *****/ 53 46 54 return true; 55 } 56 57 #define ARRAY_BUFFER 16 // Number to add to array at a time 58 #define MAG_IGNORE 50 // Ignore magnitudes fainter than this --- they're not real! 59 #define FAKE_SIZE 1 // Size of fake convolution kernel 60 #define SOURCE_MASK (PM_SOURCE_MODE_FAIL | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_SATURATED | \ 61 PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT) // Mask to apply to input sources 62 #define NOISE_FRACTION 0.01 // Set minimum flux to this fraction of noise 63 #define COVAR_FRAC 0.01 // Truncation fraction for covariance matrix 64 65 // #define TESTING // Enable debugging output 66 67 #ifdef TESTING 68 // Read a FITS image 69 static bool readImage(psImage **target, // Target for image 70 const char *name, // Name of FITS file 71 const pmConfig *config // Configuration 72 ) 73 { 74 psString resolved = pmConfigConvertFilename(name, config, false, false); // Resolved filename 75 psFits *fits = psFitsOpen(resolved, "r"); 76 psFree(resolved); 77 if (!fits) { 78 psError(PPSTACK_ERR_IO, false, "Unable to open previously produced image: %s", name); 79 return false; 80 } 81 psImage *image = psFitsReadImage(fits, psRegionSet(0,0,0,0), 0); // Image of interest 82 if (!image) { 83 psError(PPSTACK_ERR_IO, false, "Unable to read previously produced image: %s", name); 84 psFitsClose(fits); 85 return false; 86 } 87 psFitsClose(fits); 88 89 psFree(*target); 90 *target = image; 91 92 return true; 93 } 94 #endif 95 96 // Get coordinates from a source 97 static void coordsFromSource(float *x, float *y, const pmSource *source) 98 { 99 assert(x && y); 100 assert(source); 101 102 if (source->modelPSF) { 103 *x = source->modelPSF->params->data.F32[PM_PAR_XPOS]; 104 *y = source->modelPSF->params->data.F32[PM_PAR_YPOS]; 105 } else { 106 *x = source->peak->xf; 107 *y = source->peak->yf; 108 } 109 return; 110 } 111 112 static psArray *stackSourcesFilter(psArray *sources, // Source list to filter 113 int exclusion // Exclusion zone, pixels 114 ) 115 { 116 psAssert(sources && sources->n > 0, "Require array of sources"); 117 if (exclusion <= 0) { 118 return psMemIncrRefCounter(sources); 119 } 120 121 int num = sources->n; // Number of sources 122 psVector *x = psVectorAlloc(num, PS_TYPE_F32), *y = psVectorAlloc(num, PS_TYPE_F32); // Coordinates 123 int numGood = 0; // Number of good sources 124 for (int i = 0; i < num; i++) { 125 pmSource *source = sources->data[i]; // Source of interest 126 if (!source) { 127 continue; 128 } 129 coordsFromSource(&x->data.F32[numGood], &y->data.F32[numGood], source); 130 numGood++; 131 } 132 x->n = y->n = numGood; 133 134 psTree *tree = psTreePlant(2, 2, PS_TREE_EUCLIDEAN, x, y); // kd tree 135 136 psArray *filtered = psArrayAllocEmpty(numGood); // Filtered list of sources 137 psVector *coords = psVectorAlloc(2, PS_TYPE_F64); // Coordinates of source 138 int numFiltered = 0; // Number of filtered sources 139 for (int i = 0; i < num; i++) { 140 pmSource *source = sources->data[i]; // Source of interest 141 if (!source) { 142 continue; 143 } 144 float xSource, ySource; // Coordinates of source 145 coordsFromSource(&xSource, &ySource, source); 146 147 coords->data.F64[0] = xSource; 148 coords->data.F64[1] = ySource; 149 150 long numWithin = psTreeWithin(tree, coords, exclusion); // Number within exclusion zone 151 psTrace("ppStack", 9, "Source at %.0lf,%.0lf has %ld sources in exclusion zone", 152 coords->data.F64[0], coords->data.F64[1], numWithin); 153 if (numWithin == 1) { 154 // Only itself inside the exclusion zone 155 filtered = psArrayAdd(filtered, filtered->n, source); 156 } else { 157 numFiltered++; 158 } 159 } 160 psFree(coords); 161 psFree(tree); 162 psFree(x); 163 psFree(y); 164 165 psLogMsg("ppStack", PS_LOG_INFO, "Filtered out %d of %d sources", numFiltered, numGood); 166 167 return filtered; 168 } 169 170 // Add background into the fake image 171 // Based on ppSubBackground() 172 static psImage *stackBackgroundModel(pmReadout *ro, // Readout for which to generate background model 173 const pmConfig *config // Configuration 174 ) 175 { 176 psAssert(ro && ro->image, "Need readout image"); 177 psAssert(config, "Need configuration"); 178 179 psImage *image = ro->image; // Image of interest 180 int numCols = image->numCols, numRows = image->numRows; // Size of image 181 182 psMetadata *ppStackRecipe = psMetadataLookupPtr(NULL, config->recipes, PPSTACK_RECIPE); 183 psAssert(ppStackRecipe, "Need PPSTACK recipe"); 184 psMetadata *psphotRecipe = psMetadataLookupPtr(NULL, config->recipes, PSPHOT_RECIPE); 185 psAssert(psphotRecipe, "Need PSPHOT recipe"); 186 187 psString maskBadStr = psMetadataLookupStr(NULL, ppStackRecipe, "MASK.BAD");// Name of bits to mask for bad 188 psMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels 189 190 // user-defined masks to test for good/bad pixels (build from recipe list if not yet set) 191 psMetadataAddU8(psphotRecipe, PS_LIST_TAIL, "MASK.PSPHOT", PS_META_REPLACE, "user-defined mask", maskBad); 192 193 psImage *binned = psphotModelBackgroundReadoutNoFile(ro, config); // Binned background model 194 psImageBinning *binning = psMetadataLookupPtr(NULL, ro->analysis, 195 "PSPHOT.BACKGROUND.BINNING"); // Binning for model 196 psAssert(binning, "Need binning parameters"); 197 psImage *unbinned = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Unbinned background model 198 if (!psImageUnbin(unbinned, binned, binning)) { 199 psError(PPSTACK_ERR_DATA, false, "Unable to unbin background model"); 200 psFree(binned); 201 psFree(unbinned); 202 return NULL; 203 } 204 psFree(binned); 205 206 return unbinned; 207 } 208 209 // Renormalise a readout's variance map 210 bool stackRenormaliseReadout(const pmConfig *config, // Configuration 211 pmReadout *readout // Readout to renormalise 212 ) 213 { 214 #if 1 215 bool mdok; // Status of metadata lookups 216 217 psMetadata *recipe = psMetadataLookupPtr(NULL, config->recipes, PPSTACK_RECIPE); // Recipe for ppStack 218 psAssert(recipe, "Need PPSTACK recipe"); 219 220 if (!psMetadataLookupBool(&mdok, recipe, "RENORM")) return true; 221 222 int num = psMetadataLookupS32(&mdok, recipe, "RENORM.NUM"); 223 if (!mdok) { 224 psError(PPSTACK_ERR_CONFIG, true, "RENORM.NUM is not set in the recipe"); 225 return false; 226 } 227 float minValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MIN"); 228 if (!mdok) { 229 psError(PPSTACK_ERR_CONFIG, true, "RENORM.MIN is not set in the recipe"); 230 return false; 231 } 232 float maxValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MAX"); 233 if (!mdok) { 234 psError(PPSTACK_ERR_CONFIG, true, "RENORM.MAX is not set in the recipe"); 235 return false; 236 } 237 238 psImageMaskType maskBad = pmConfigMaskGet("BLANK", config); // Bits to mask 239 240 psImageCovarianceTransfer(readout->variance, readout->covariance); 241 return pmReadoutVarianceRenormalise(readout, maskBad, num, minValid, maxValid); 242 #else 243 return true; 244 #endif 245 } 246 247 bool ppStackMatch(pmReadout *readout, ppStackOptions *options, int index, const pmConfig *config) 248 { 249 assert(readout); 250 assert(options); 251 assert(config); 252 253 psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe 254 psAssert(recipe, "We've thrown an error on this before."); 255 256 float deconvLimit = psMetadataLookupF32(NULL, recipe, "DECONV.LIMIT"); // Limit on deconvolution fraction 47 psMetadata *stackRecipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe 48 psAssert(stackRecipe, "We've thrown an error on this before."); 257 49 258 50 // Look up appropriate values from the ppSub recipe 259 psMetadata * ppsub= psMetadataLookupMetadata(NULL, config->recipes, "PPSUB"); // PPSUB recipe260 int size = psMetadataLookupS32(NULL, ppsub, "KERNEL.SIZE"); // Kernel half-size51 psMetadata *subRecipe = psMetadataLookupMetadata(NULL, config->recipes, "PPSUB"); // PPSUB recipe 52 psAssert(subRecipe, "recipe missing"); 261 53 262 psString maskValStr = psMetadataLookupStr(NULL, ppsub, "MASK.VAL"); // Name of bits to mask going in 54 int size = psMetadataLookupS32(NULL, subRecipe, "KERNEL.SIZE"); // Kernel half-size 55 56 float deconvLimit = psMetadataLookupF32(NULL, stackRecipe, "DECONV.LIMIT"); // Limit on deconvolution fraction 57 58 psString maskValStr = psMetadataLookupStr(NULL, subRecipe, "MASK.VAL"); // Name of bits to mask going in 263 59 psImageMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask going in to pmSubtractionMatch 264 psString maskPoorStr = psMetadataLookupStr(NULL, recipe, "MASK.POOR"); // Name of bits to mask for poor60 psString maskPoorStr = psMetadataLookupStr(NULL, stackRecipe, "MASK.POOR"); // Name of bits to mask for poor 265 61 psImageMaskType maskPoor = pmConfigMaskGet(maskPoorStr, config); // Bits to mask for poor pixels 266 psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad62 psString maskBadStr = psMetadataLookupStr(NULL, stackRecipe, "MASK.BAD"); // Name of bits to mask for bad 267 63 psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels 268 64 269 65 bool mdok; // Status of MD lookup 270 float penalty = psMetadataLookupF32(NULL, ppsub, "PENALTY"); // Penalty for wideness66 float penalty = psMetadataLookupF32(NULL, subRecipe, "PENALTY"); // Penalty for wideness 271 67 int threads = psMetadataLookupS32(NULL, config->arguments, "-threads"); // Number of threads 272 68 … … 276 72 } 277 73 278 // Match the PSF74 // Image Matching (PSFs or just flux) 279 75 if (options->convolve) { 76 // Full match of PSFs 280 77 pmReadout *conv = pmReadoutAlloc(NULL); // Conv readout, for holding results temporarily 281 #ifdef TESTING282 // This is a hack to use the temporary convolved images and kernel generated previously.283 // This makes the 'matching' operation much faster, allowing debugging of the stack process easier.284 // It implicitly assumes the output root name is the same between invocations.285 78 286 79 // Read previously produced kernel 287 80 if (psMetadataLookupBool(NULL, config->arguments, "PPSTACK.DEBUG.STACK")) { 288 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.CONV.KERNEL", index); 289 psAssert(file, "Require file"); 81 loadKernel(); 82 } else { 83 matchKernel(); 84 } // !DEBUG.STACK 290 85 291 pmFPAview *view = pmFPAviewAlloc(0); // View to readout of interest 292 view->chip = view->cell = view->readout = 0; 293 psString filename = pmFPAfileNameFromRule(file->filerule, file, view); // Filename of interest 86 saveMatchData(); 294 87 295 // Read convolution kernel 296 psString resolved = pmConfigConvertFilename(filename, config, false, false); // Resolved filename 297 psFree(filename); 298 psFits *fits = psFitsOpen(resolved, "r"); // FITS file for subtraction kernel 299 psFree(resolved); 300 if (!fits || !pmReadoutReadSubtractionKernels(conv, fits)) { 301 psError(PPSTACK_ERR_IO, false, "Unable to read previously produced kernel"); 302 psFitsClose(fits); 303 return false; 304 } 305 psFitsClose(fits); 88 saveChiSquare(); 306 89 307 if (!readImage(&readout->image, options->convImages->data[index], config) || 308 !readImage(&readout->mask, options->convMasks->data[index], config) || 309 !readImage(&readout->variance, options->convVariances->data[index], config)) { 310 psError(PPSTACK_ERR_IO, false, "Unable to read previously produced image."); 311 return false; 312 } 313 314 psRegion *region = psMetadataLookupPtr(NULL, conv->analysis, 315 PM_SUBTRACTION_ANALYSIS_REGION); // Convolution region 316 pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, conv->analysis, 317 PM_SUBTRACTION_ANALYSIS_KERNEL); 318 319 pmSubtractionAnalysis(conv->analysis, NULL, kernels, region, 320 readout->image->numCols, readout->image->numRows); 321 322 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel 323 bool oldThreads = psImageCovarianceSetThreads(true); // Old thread setting 324 psKernel *covar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix 325 psImageCovarianceSetThreads(oldThreads); 326 psFree(readout->covariance); 327 readout->covariance = covar; 328 psFree(kernel); 329 } else { 330 #endif 331 332 // Normal operations here 333 psAssert(options->psf, "Require target PSF"); 334 psAssert(options->sourceLists && options->sourceLists->data[index], "Require source list"); 335 336 int order = psMetadataLookupS32(NULL, ppsub, "SPATIAL.ORDER"); // Spatial polynomial order 337 float regionSize = psMetadataLookupF32(NULL, ppsub, "REGION.SIZE"); // Size of iso-kernel regs 338 float spacing = psMetadataLookupF32(NULL, ppsub, "STAMP.SPACING"); // Typical stamp spacing 339 int footprint = psMetadataLookupS32(NULL, ppsub, "STAMP.FOOTPRINT"); // Stamp half-size 340 float threshold = psMetadataLookupF32(NULL, ppsub, "STAMP.THRESHOLD"); // Threshold for stmps 341 int stride = psMetadataLookupS32(NULL, ppsub, "STRIDE"); // Size of convolution patches 342 int iter = psMetadataLookupS32(NULL, ppsub, "ITER"); // Rejection iterations 343 float rej = psMetadataLookupF32(NULL, ppsub, "REJ"); // Rejection threshold 344 float kernelError = psMetadataLookupF32(NULL, ppsub, "KERNEL.ERR"); // Relative systematic error in kernel 345 float normFrac = psMetadataLookupF32(NULL, ppsub, "NORM.FRAC"); // Fraction of window for normalisn windw 346 float sysError = psMetadataLookupF32(NULL, ppsub, "SYS.ERR"); // Relative systematic error in images 347 float skyErr = psMetadataLookupF32(NULL, ppsub, "SKY.ERR"); // Additional error in sky 348 float covarFrac = psMetadataLookupF32(NULL, ppsub, "COVAR.FRAC"); // Fraction for covariance calculation 349 350 const char *typeStr = psMetadataLookupStr(NULL, ppsub, "KERNEL.TYPE"); // Kernel type 351 pmSubtractionKernelsType type = pmSubtractionKernelsTypeFromString(typeStr); // Kernel type 352 psVector *widths = psMetadataLookupPtr(NULL, ppsub, "ISIS.WIDTHS"); // ISIS Gaussian widths 353 psVector *orders = psMetadataLookupPtr(NULL, ppsub, "ISIS.ORDERS"); // ISIS Polynomial orders 354 int inner = psMetadataLookupS32(NULL, ppsub, "INNER"); // Inner radius 355 int ringsOrder = psMetadataLookupS32(NULL, ppsub, "RINGS.ORDER"); // RINGS polynomial order 356 int binning = psMetadataLookupS32(NULL, ppsub, "SPAM.BINNING"); // Binning for SPAM kernel 357 float badFrac = psMetadataLookupF32(NULL, ppsub, "BADFRAC"); // Maximum bad fraction 358 bool optimum = psMetadataLookupBool(&mdok, ppsub, "OPTIMUM"); // Derive optimum parameters? 359 float optMin = psMetadataLookupF32(&mdok, ppsub, "OPTIMUM.MIN"); // Minimum width for search 360 float optMax = psMetadataLookupF32(&mdok, ppsub, "OPTIMUM.MAX"); // Maximum width for search 361 float optStep = psMetadataLookupF32(&mdok, ppsub, "OPTIMUM.STEP"); // Step for search 362 float optThresh = psMetadataLookupF32(&mdok, ppsub, "OPTIMUM.TOL"); // Tolerance for search 363 int optOrder = psMetadataLookupS32(&mdok, ppsub, "OPTIMUM.ORDER"); // Order for search 364 float poorFrac = psMetadataLookupF32(&mdok, ppsub, "POOR.FRACTION"); // Fraction for "poor" 365 366 bool scale = psMetadataLookupBool(NULL, ppsub, "SCALE"); // Scale kernel parameters? 367 float scaleRef = psMetadataLookupF32(NULL, ppsub, "SCALE.REF"); // Reference for scaling 368 float scaleMin = psMetadataLookupF32(NULL, ppsub, "SCALE.MIN"); // Minimum for scaling 369 float scaleMax = psMetadataLookupF32(NULL, ppsub, "SCALE.MAX"); // Maximum for scaling 370 if (!isfinite(scaleRef) || !isfinite(scaleMin) || !isfinite(scaleMax)) { 371 psError(PPSTACK_ERR_CONFIG, false, 372 "Scale parameters (SCALE.REF=%f, SCALE.MIN=%f, SCALE.MAX=%f) not set in PPSUB recipe.", 373 scaleRef, scaleMin, scaleMax); 374 return false; 375 } 376 377 378 // These values are specified specifically for stacking 379 const char *stampsName = psMetadataLookupStr(NULL, config->arguments, "STAMPS");// Stamps filename 380 381 psVector *optWidths = NULL; // Vector with FWHMs for optimum search 382 if (optimum) { 383 optWidths = psVectorCreate(optWidths, optMin, optMax, optStep, PS_TYPE_F32); 384 } 385 386 pmReadout *fake = pmReadoutAlloc(NULL); // Fake readout with target PSF 387 388 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_STDEV); // Statistics for background 389 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 390 if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) { 391 psError(PPSTACK_ERR_DATA, false, "Can't measure background for image."); 392 psFree(fake); 393 psFree(optWidths); 394 psFree(conv); 395 psFree(bg); 396 psFree(rng); 397 return false; 398 } 399 float minFlux = NOISE_FRACTION * bg->robustStdev; // Minimum flux level for fake image 400 psFree(rng); 401 psFree(bg); 402 403 // For the sake of stamps, remove nearby sources 404 psArray *stampSources = stackSourcesFilter(options->sourceLists->data[index], 405 footprint); // Filtered list of sources 406 407 bool oldThreads = pmReadoutFakeThreads(true); // Old threading state 408 if (!pmReadoutFakeFromSources(fake, readout->image->numCols, readout->image->numRows, 409 stampSources, SOURCE_MASK, NULL, NULL, options->psf, 410 minFlux, footprint + size, false, true)) { 411 psError(PPSTACK_ERR_DATA, false, "Unable to generate fake image with target PSF."); 412 psFree(fake); 413 psFree(optWidths); 414 psFree(conv); 415 return false; 416 } 417 pmReadoutFakeThreads(oldThreads); 418 419 fake->mask = psImageCopy(NULL, readout->mask, PS_TYPE_IMAGE_MASK); 420 421 #if 1 422 // Add the background into the target image 423 psImage *bgImage = stackBackgroundModel(readout, config); // Image of background 424 psBinaryOp(fake->image, fake->image, "+", bgImage); 425 psFree(bgImage); 426 #endif 427 428 #ifdef TESTING 429 { 430 pmHDU *hdu = pmHDUFromCell(readout->parent); 431 psString name = NULL; 432 psStringAppend(&name, "fake_%03d.fits", index); 433 pmStackVisualPlotTestImage(fake->image, name); 434 psFits *fits = psFitsOpen(name, "w"); 435 psFree(name); 436 psFitsWriteImage(fits, hdu->header, fake->image, 0, NULL); 437 psFitsClose(fits); 438 } 439 { 440 pmHDU *hdu = pmHDUFromCell(readout->parent); 441 psString name = NULL; 442 psStringAppend(&name, "real_%03d.fits", index); 443 pmStackVisualPlotTestImage(readout->image, name); 444 psFits *fits = psFitsOpen(name, "w"); 445 psFree(name); 446 psFitsWriteImage(fits, hdu->header, readout->image, 0, NULL); 447 psFitsClose(fits); 448 } 449 #endif 450 451 if (threads > 0) { 452 pmSubtractionThreadsInit(); 453 } 454 455 // Do the image matching 456 pmSubtractionKernels *kernel = psMetadataLookupPtr(&mdok, readout->analysis, 457 PM_SUBTRACTION_ANALYSIS_KERNEL); // Conv kernel 458 if (kernel) { 459 if (!pmSubtractionMatchPrecalc(NULL, conv, fake, readout, readout->analysis, 460 stride, kernelError, covarFrac, maskVal, maskBad, maskPoor, 461 poorFrac, badFrac)) { 462 psError(psErrorCodeLast(), false, "Unable to convolve images."); 463 psFree(fake); 464 psFree(optWidths); 465 psFree(stampSources); 466 psFree(conv); 467 if (threads > 0) { 468 pmSubtractionThreadsFinalize(); 469 } 470 return false; 471 } 472 } else { 473 // Scale the input parameters 474 psVector *widthsCopy = psVectorCopy(NULL, widths, PS_TYPE_F32); // Copy of kernel widths 475 if (scale && !pmSubtractionParamsScale(&size, &footprint, widthsCopy, 476 options->inputSeeing->data.F32[index], 477 options->targetSeeing, scaleRef, scaleMin, scaleMax)) { 478 psError(psErrorCodeLast(), false, "Unable to scale kernel parameters"); 479 psFree(fake); 480 psFree(optWidths); 481 psFree(stampSources); 482 psFree(conv); 483 psFree(widthsCopy); 484 if (threads > 0) { 485 pmSubtractionThreadsFinalize(); 486 } 487 return false; 488 } 489 490 if (!pmSubtractionMatch(NULL, conv, fake, readout, footprint, stride, regionSize, spacing, 491 threshold, stampSources, stampsName, type, size, order, widthsCopy, 492 orders, inner, ringsOrder, binning, penalty, 493 optimum, optWidths, optOrder, optThresh, iter, rej, normFrac, 494 sysError, skyErr, kernelError, covarFrac, maskVal, maskBad, maskPoor, 495 poorFrac, badFrac, PM_SUBTRACTION_MODE_2)) { 496 psError(psErrorCodeLast(), false, "Unable to match images."); 497 psFree(fake); 498 psFree(optWidths); 499 psFree(stampSources); 500 psFree(conv); 501 psFree(widthsCopy); 502 if (threads > 0) { 503 pmSubtractionThreadsFinalize(); 504 } 505 return false; 506 } 507 psFree(widthsCopy); 508 } 509 510 511 #ifdef TESTING 512 { 513 pmHDU *hdu = pmHDUFromCell(readout->parent); 514 psString name = NULL; 515 psStringAppend(&name, "conv_%03d.fits", index); 516 pmStackVisualPlotTestImage(conv->image, name); 517 psFits *fits = psFitsOpen(name, "w"); 518 psFree(name); 519 psFitsWriteImage(fits, hdu->header, conv->image, 0, NULL); 520 psFitsClose(fits); 521 } 522 { 523 pmHDU *hdu = pmHDUFromCell(readout->parent); 524 psString name = NULL; 525 psStringAppend(&name, "diff_%03d.fits", index); 526 pmStackVisualPlotTestImage(fake->image, name); 527 psFits *fits = psFitsOpen(name, "w"); 528 psFree(name); 529 psBinaryOp(fake->image, conv->image, "-", fake->image); 530 psFitsWriteImage(fits, hdu->header, fake->image, 0, NULL); 531 psFitsClose(fits); 532 } 533 #endif 534 535 psFree(fake); 536 psFree(optWidths); 537 psFree(stampSources); 538 539 if (threads > 0) { 540 pmSubtractionThreadsFinalize(); 541 } 542 543 // Replace original images with convolved 544 psFree(readout->image); 545 psFree(readout->mask); 546 psFree(readout->variance); 547 psFree(readout->covariance); 548 readout->image = psMemIncrRefCounter(conv->image); 549 readout->mask = psMemIncrRefCounter(conv->mask); 550 readout->variance = psMemIncrRefCounter(conv->variance); 551 readout->covariance = psImageCovarianceTruncate(conv->covariance, COVAR_FRAC); 552 #ifdef TESTING 553 } 554 #endif 555 556 // Extract the regions and solutions used in the image matching 557 // This stops them from being freed when we iterate back up the FPA 558 psArray *regions = options->regions->data[index] = psArrayAllocEmpty(ARRAY_BUFFER); // Match regions 559 { 560 psString regex = NULL; // Regular expression 561 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_REGION); 562 psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex); 563 psFree(regex); 564 psMetadataItem *item = NULL;// Item from iteration 565 while ((item = psMetadataGetAndIncrement(iter))) { 566 assert(item->type == PS_DATA_REGION); 567 regions = psArrayAdd(regions, ARRAY_BUFFER, item->data.V); 568 } 569 psFree(iter); 570 } 571 psArray *kernels = options->kernels->data[index] = psArrayAllocEmpty(ARRAY_BUFFER); // Match kernels 572 { 573 psString regex = NULL; // Regular expression 574 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL); 575 psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex); 576 psFree(regex); 577 psMetadataItem *item = NULL;// Item from iteration 578 while ((item = psMetadataGetAndIncrement(iter))) { 579 assert(item->type == PS_DATA_UNKNOWN); 580 pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction 581 kernels = psArrayAdd(kernels, ARRAY_BUFFER, kernel); 582 } 583 psFree(iter); 584 } 585 psAssert((regions)->n == (kernels)->n, "Number of match regions and kernels should match"); 586 587 // Record chi^2 588 { 589 double sum = 0.0; // Sum of chi^2 590 int num = 0; // Number of measurements of chi^2 591 psString regex = NULL; // Regular expression 592 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_KERNEL); 593 psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex); 594 psFree(regex); 595 psMetadataItem *item = NULL;// Item from iteration 596 while ((item = psMetadataGetAndIncrement(iter))) { 597 assert(item->type == PS_DATA_UNKNOWN); 598 pmSubtractionKernels *kernels = item->data.V; // Convolution kernels 599 sum += kernels->mean; 600 num++; 601 } 602 psFree(iter); 603 options->matchChi2->data.F32[index] = sum / (psImageCovarianceFactor(readout->covariance) * num); 604 } 605 606 // Kernel normalisation 607 { 608 double sum = 0.0; // Sum of chi^2 609 int num = 0; // Number of measurements of chi^2 610 psString regex = NULL; // Regular expression 611 psStringAppend(®ex, "^%s$", PM_SUBTRACTION_ANALYSIS_NORM); 612 psMetadataIterator *iter = psMetadataIteratorAlloc(conv->analysis, PS_LIST_HEAD, regex); 613 psFree(regex); 614 psMetadataItem *item = NULL;// Item from iteration 615 while ((item = psMetadataGetAndIncrement(iter))) { 616 assert(item->type == PS_TYPE_F32); 617 float norm = item->data.F32; // Normalisation 618 sum += norm; 619 num++; 620 } 621 psFree(iter); 622 float conv = sum/num; // Mean normalisation from convolution 623 float stars = powf(10.0, -0.4 * options->norm->data.F32[index]); // Normalisation from stars 624 float renorm = stars / conv; // Renormalisation to apply 625 psLogMsg("ppStack", PS_LOG_INFO, "Renormalising image %d by %f (kernel: %f, stars: %f)\n", 626 index, renorm, conv, stars); 627 psBinaryOp(readout->image, readout->image, "*", psScalarAlloc(renorm, PS_TYPE_F32)); 628 psBinaryOp(readout->variance, readout->variance, "*", psScalarAlloc(PS_SQR(renorm), PS_TYPE_F32)); 629 } 90 renormKernel(); 630 91 631 92 // Reject image completely if the maximum deconvolution fraction exceeds the limit 632 float deconv = psMetadataLookupF32(NULL, conv->analysis, 633 PM_SUBTRACTION_ANALYSIS_DECONV_MAX); // Max deconvolution fraction 93 float deconv = psMetadataLookupF32(NULL, conv->analysis, PM_SUBTRACTION_ANALYSIS_DECONV_MAX); // Max deconvolution fraction 634 94 if (deconv > deconvLimit) { 635 psWarning("Maximum deconvolution fraction (%f) exceeds limit (%f) --- rejecting image %d\n", 636 deconv, deconvLimit, index); 95 psWarning("Maximum deconvolution fraction (%f) exceeds limit (%f) --- rejecting image %d\n", deconv, deconvLimit, index); 637 96 psFree(conv); 638 97 return NULL; … … 643 102 psFree(conv); 644 103 } else { 645 // Match the normalisation104 // only match the flux 646 105 float norm = powf(10.0, -0.4 * options->norm->data.F32[index]); // Normalisation 647 106 psBinaryOp(readout->image, readout->image, "*", psScalarAlloc(norm, PS_TYPE_F32)); … … 671 130 672 131 // Measure the variance level for the weighting 673 if (psMetadataLookupBool(NULL, recipe, "WEIGHTS")) {132 if (psMetadataLookupBool(NULL, stackRecipe, "WEIGHTS")) { 674 133 if (!psImageBackground(bg, NULL, readout->variance, readout->mask, maskVal | maskBad, rng)) { 675 134 psError(PPSTACK_ERR_DATA, false, "Can't measure mean variance for image."); … … 678 137 return false; 679 138 } 680 options->weightings->data.F32[index] = 1.0 / (psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN) * 681 psImageCovarianceFactor(readout->covariance)); 139 options->weightings->data.F32[index] = 1.0 / (psStatsGetValue(bg, PS_STAT_ROBUST_MEDIAN) * psImageCovarianceFactor(readout->covariance)); 682 140 } else { 683 141 options->weightings->data.F32[index] = 1.0; … … 689 147 psFree(bg); 690 148 691 #ifdef TESTING 692 { 693 pmHDU *hdu = pmHDUFromCell(readout->parent); 694 psString name = NULL; 695 psStringAppend(&name, "convolved_%03d.fits", index); 696 pmStackVisualPlotTestImage(readout->image, name); 697 psFits *fits = psFitsOpen(name, "w"); 698 psFree(name); 699 psFitsWriteImage(fits, hdu->header, readout->image, 0, NULL); 700 psFitsClose(fits); 701 } 702 #endif 149 dumpImage3(); 703 150 704 151 return true;
Note:
See TracChangeset
for help on using the changeset viewer.
