- Timestamp:
- Jan 25, 2010, 7:52:41 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/psphot.stack.20100120/src/psphotSourceSize.c
r26643 r26681 15 15 } psphotSourceSizeOptions; 16 16 17 // local functions: 18 bool psphotSourceSizeReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index); 17 19 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf); 18 20 bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options); 19 21 bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options); 20 22 bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options); 21 bool psphotMaskCosmicRay (p sImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);22 bool psphotMaskCosmicRay Isophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);23 bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal); 24 bool psphotMaskCosmicRayFootprintCheck (psArray *sources); 23 25 24 26 // we need to call this function after sources have been fitted to the PSF model and … … 33 35 bool status = true; 34 36 37 // select the appropriate recipe information 38 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE); 39 psAssert (recipe, "missing recipe?"); 40 35 41 int num = psMetadataAddS32 (&status, config->arguments, "PSPHOT.INPUT.NUM"); 36 42 psAssert (status, "programming error: must define PSPHOT.INPUT.NUM"); … … 38 44 // loop over the available readouts 39 45 for (int i = 0; i < num; i++) { 40 if (!psphotSourceSizeReadout (config, view, "PSPHOT.INPUT", i )) {46 if (!psphotSourceSizeReadout (config, view, "PSPHOT.INPUT", i, recipe)) { 41 47 psError (PSPHOT_ERR_CONFIG, false, "failed on saturated star deblend analysis for PSPHOT.INPUT entry %d", i); 42 48 return false; … … 47 53 48 54 // XXX use an internal flag to mark sources which have already been measured 49 // how to track the sources already measured? 50 bool psphotSourceSize(pmConfig *config, const pmFPAview *view, const char *filename, int index) 55 bool psphotSourceSizeReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) 51 56 { 52 57 bool status; … … 65 70 psAssert (sources, "missing sources?"); 66 71 72 if (!sources->n) { 73 psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size"); 74 return true; 75 } 76 67 77 pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF"); 68 78 psAssert (psf, "missing psf?"); 69 70 // select the appropriate recipe information71 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);72 psAssert (recipe, "missing recipe?");73 79 74 80 // user-defined masks to test for good/bad pixels (build from recipe list if not yet set) … … 106 112 107 113 // We are using the value psfMag - 2.5*log10(moment.Sum) as a measure of the extendedness 108 // of an dobject. We need to model this distribution for the PSF stars before we can test114 // of an object. We need to model this distribution for the PSF stars before we can test 109 115 // the significance for a specific object 110 116 // XXX move this to the code that generates the PSF? … … 122 128 psphotVisualShowSourceSize (readout, sources); 123 129 psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr); 124 125 return true; 126 } 127 128 bool psphotMaskCosmicRay (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) { 130 psphotVisualShowSatStars (recipe, psf, sources); 131 132 return true; 133 } 134 135 // model the apmifit distribution for the psf stars: 136 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) { 137 138 // select stats from the psf stars 139 psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32); 140 psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32); 141 142 psImageMaskType maskVal = options->maskVal | options->markVal; 143 144 // XXX why PHOT_WEIGHT?? 145 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT; 146 147 for (int i = 0; i < sources->n; i++) { 148 pmSource *source = sources->data[i]; 149 if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue; 150 151 // replace object in image 152 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) { 153 pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal); 154 } 155 156 // clear the mask bit and set the circular mask pixels 157 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal)); 158 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal); 159 160 // XXX can we test if psfMag is set and calculate only if needed? 161 pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal 162 163 // clear the mask bit 164 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal)); 165 166 // re-subtract the object, leave local sky 167 pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal); 168 169 float apMag = -2.5*log10(source->moments->Sum); 170 float dMag = source->psfMag - apMag; 171 172 psVectorAppend (Ap, 100, dMag); 173 psVectorAppend (ApErr, 100, source->errMag); 174 } 175 176 // model the distribution as a mean or median value and a systematic error from that value: 177 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); 178 psVectorStats (stats, Ap, NULL, NULL, 0); 179 180 psVector *dAp = psVectorAlloc (Ap->n, PS_TYPE_F32); 181 for (int i = 0; i < Ap->n; i++) { 182 dAp->data.F32[i] = Ap->data.F32[i] - stats->robustMedian; 183 } 184 185 options->ApResid = stats->robustMedian; 186 options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.05); 187 psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr); 188 189 psFree (Ap); 190 psFree (ApErr); 191 psFree (stats); 192 psFree (dAp); 193 194 return true; 195 } 196 197 // classify sources based on the combination of psf-mag, Mxx, Myy 198 bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) { 199 200 bool status; 201 pmPSFClump psfClump; 202 char regionName[64]; 203 204 psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip"); 205 206 int nRegions = psMetadataLookupS32 (&status, readout->analysis, "PSF.CLUMP.NREGIONS"); 207 for (int i = 0; i < nRegions; i ++) { 208 snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i); 209 psMetadata *regionMD = psMetadataLookupPtr (&status, readout->analysis, regionName); 210 psAssert (regionMD, "regions must be defined by earlier call to psphotRoughClassRegion"); 211 212 psRegion *region = psMetadataLookupPtr (&status, regionMD, "REGION"); 213 psAssert (region, "regions must be defined by earlier call to psphotRoughClassRegion"); 214 215 // pull FWHM_X,Y from the recipe, use to define psfClump.X,Y 216 psfClump.X = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X"); psAssert (status, "missing PSF.CLUMP.X"); 217 psfClump.Y = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y"); psAssert (status, "missing PSF.CLUMP.Y"); 218 psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX"); psAssert (status, "missing PSF.CLUMP.DX"); 219 psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY"); psAssert (status, "missing PSF.CLUMP.DY"); 220 221 if ((psfClump.X < 0) || (psfClump.Y < 0) || !psfClump.X || !psfClump.Y || isnan(psfClump.X) || isnan(psfClump.Y)) { 222 psLogMsg ("psphot", 4, "Failed to find a valid PSF clump for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1); 223 continue; 224 } 225 226 if (!psphotSourceClassRegion (region, &psfClump, sources, recipe, psf, options)) { 227 psLogMsg ("psphot", 4, "Failed to determine source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1); 228 continue; 229 } 230 } 231 232 return true; 233 } 234 235 bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) { 236 237 PS_ASSERT_PTR_NON_NULL(sources, false); 238 PS_ASSERT_PTR_NON_NULL(recipe, false); 239 240 int Nsat = 0; 241 int Next = 0; 242 int Npsf = 0; 243 int Ncr = 0; 244 int Nmiss = 0; 245 int Nskip = 0; 246 247 pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN; 248 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT; 249 250 psImageMaskType maskVal = options->maskVal | options->markVal; 251 252 for (psS32 i = 0 ; i < sources->n ; i++) { 253 254 pmSource *source = (pmSource *) sources->data[i]; 255 256 // psfClumps are found for image subregions: 257 // skip sources not in this region 258 if (source->peak->x < region->x0) continue; 259 if (source->peak->x >= region->x1) continue; 260 if (source->peak->y < region->y0) continue; 261 if (source->peak->y >= region->y1) continue; 262 263 // skip source if it was already measured 264 if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) { 265 psTrace("psphot", 7, "Not calculating source size since it has already been measured\n"); 266 continue; 267 } 268 269 // source must have been subtracted 270 if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) { 271 source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED; 272 psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n"); 273 continue; 274 } 275 276 // we are basically classifying by moments; use the default if not found 277 psAssert (source->moments, "why is this source missing moments?"); 278 if (source->mode & noMoments) { 279 Nskip ++; 280 continue; 281 } 282 283 psF32 Mxx = source->moments->Mxx; 284 psF32 Myy = source->moments->Myy; 285 286 // replace object in image 287 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) { 288 pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal); 289 } 290 291 // clear the mask bit and set the circular mask pixels 292 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal)); 293 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal); 294 295 // XXX can we test if psfMag is set and calculate only if needed? 296 pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal 297 298 // clear the mask bit 299 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal)); 300 301 // re-subtract the object, leave local sky 302 pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal); 303 304 float apMag = -2.5*log10(source->moments->Sum); 305 float dMag = source->psfMag - apMag; 306 float nSigma = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr); 307 308 source->extNsigma = nSigma; 309 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 310 311 // Anything within this region is a probably PSF-like object. Saturated stars may land 312 // in this region, but are detected elsewhere on the basis of their peak value. 313 bool isPSF = ((fabs(nSigma) < options->nSigmaApResid) && 314 (fabs(Mxx - psfClump->X) < options->nSigmaMoments*psfClump->dX) && 315 (fabs(Myy - psfClump->Y) < options->nSigmaMoments*psfClump->dY)); 316 if (isPSF) { 317 psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g PSF\t%g %g\n", 318 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma, 319 options->nSigmaApResid,options->nSigmaMoments); 320 Npsf ++; 321 continue; 322 } 323 324 // Defects may not always match CRs from peak curvature analysis 325 // Defects may also be marked as SATSTAR -- XXX deactivate this flag? 326 // XXX this rule is not great 327 if ((Mxx < psfClump->X) || (Myy < psfClump->Y)) { 328 329 psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g CR\t%g %g\n", 330 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma, 331 options->nSigmaApResid,options->nSigmaMoments); 332 source->mode |= PM_SOURCE_MODE_DEFECT; 333 Ncr ++; 334 continue; 335 } 336 337 // saturated star (determined in PSF fit). These may also be saturated galaxies, or 338 // just large saturated regions. 339 if (source->mode & PM_SOURCE_MODE_SATSTAR) { 340 psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g SAT\t%g %g\n", 341 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma, 342 options->nSigmaApResid,options->nSigmaMoments); 343 344 Nsat ++; 345 continue; 346 } 347 348 // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)? 349 bool isEXT = (nSigma > options->nSigmaApResid) || ((Mxx > psfClump->X) && (Myy > psfClump->Y)); 350 if (isEXT) { 351 psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g Ext\t%g %g\n", 352 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma, 353 options->nSigmaApResid,options->nSigmaMoments); 354 355 source->mode |= PM_SOURCE_MODE_EXT_LIMIT; 356 Next ++; 357 continue; 358 } 359 psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g Unk\t%g %g\n", 360 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma, 361 options->nSigmaApResid,options->nSigmaMoments); 362 363 psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigma); 364 Nmiss ++; 365 } 366 367 psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip); 368 369 return true; 370 } 371 372 // given an object suspected to be a defect, generate a pixel mask using the Lapacian transform 373 // if enough of the object is detected as 'sharp', consider the object a cosmic ray 374 bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) { 375 376 for (int i = 0; i < sources->n; i++) { 377 pmSource *source = sources->data[i]; 378 379 // Integer position of peak 380 int xPeak = source->peak->xf - source->pixels->col0 + 0.5; 381 int yPeak = source->peak->yf - source->pixels->row0 + 0.5; 382 383 // Skip sources which are too close to a boundary. These are mostly caught as DEFECT 384 if (xPeak < 1 || xPeak > source->pixels->numCols - 2 || 385 yPeak < 1 || yPeak > source->pixels->numRows - 2) { 386 psTrace("psphot", 7, "Not calculating crNsigma due to edge\n"); 387 // psTrace("psphot.czw", 2, "Not calculating crNsigma due to edge\n"); 388 continue; 389 } 390 391 // this source is thought to be a cosmic ray. flag the detection and mask the pixels 392 if (source->mode & PM_SOURCE_MODE_DEFECT) { 393 // XXX this is running slowly and is too agressive, but it more-or-less works 394 // psphotMaskCosmicRayCZW(readout, source, options->crMask); 395 396 // XXX these are the old versions which we are not using 397 // psphotMaskCosmicRay (readout->mask, source, maskVal, crMask); 398 // psphotMaskCosmicRay_Old (source, maskVal, crMask); 399 } 400 } 401 402 // now that we have masked pixels associated with CRs, we can grow the mask 403 if (options->grow > 0) { 404 bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolveMask 405 psImage *newMask = psImageConvolveMask(NULL, readout->mask, options->crMask, options->crMask, -options->grow, options->grow, -options->grow, options->grow); 406 psImageConvolveSetThreads(oldThreads); 407 if (!newMask) { 408 psError(PS_ERR_UNKNOWN, false, "Unable to grow CR mask"); 409 return false; 410 } 411 psFree(readout->mask); 412 readout->mask = newMask; 413 } 414 415 // XXX test : save the mask image 416 if (0) { 417 psphotSaveImage (NULL, readout->mask, "mask.fits"); 418 } 419 return true; 420 } 421 422 // Comments by CZW 20091209 : Mechanics of how to identify CR pixels taken from "Cosmic-Ray 423 // Rejection by Laplacian Edge Detection" by Pieter van Dokkum, arXiv:astro-ph/0108003. This 424 // does no repair or recovery of the CR pixels, it only masks them out. My test code can be 425 // found at /data/ipp031.0/watersc1/psphot.20091209/algo_check.c 426 bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal) { 427 428 // Get the actual images and information about the peak. 429 psImage *mask = readout->mask; 430 pmPeak *peak = source->peak; 431 pmFootprint *footprint = peak->footprint; 432 433 int xm = footprint->bbox.x0; 434 int xM = footprint->bbox.x1; 435 int ym = footprint->bbox.y0; 436 int yM = footprint->bbox.y1; 437 438 if (xm < 0) { xm = 0; } 439 if (ym < 0) { ym = 0; } 440 if (xM > mask->numCols) { xM = mask->numCols; } 441 if (yM > mask->numRows) { yM = mask->numRows; } 442 int dx = xM - xm; 443 int dy = yM - ym; 444 445 // Bounding boxes are inclusive of final pixel 446 // XXX ensure dx,dy do not become too large here 447 dx++; 448 dy++; 449 450 psImage *image= readout->image; 451 psImage *variance = readout->variance; 452 453 int binning = 1; 454 float sigma_thresh = 2.0; 455 int iteration = 0; 456 int max_iter = 5; 457 float noise_factor = 5.0 / 4.0; // Intrinsic to the Laplacian making noise spikes spikier. 458 459 // Temporary images. 460 psImage *mypix = psImageAlloc(dx,dy,image->type.type); 461 psImage *myvar = psImageAlloc(dx,dy,image->type.type); 462 psImage *binned = psImageAlloc(dx * binning,dy * binning,image->type.type); 463 psImage *conved = psImageAlloc(dx * binning,dy * binning,image->type.type); 464 psImage *edges = psImageAlloc(dx,dy,image->type.type); 465 psImage *mymask = psImageAlloc(dx,dy,PS_TYPE_IMAGE_MASK); 466 467 int x,y; 468 // Load my copy of things. 469 for (x = 0; x < dx; x++) { 470 for (y = 0; y < dy; y++) { 471 psImageSet(mypix,x,y,psImageGet(image,x+xm,y+ym)); 472 psImageSet(myvar,x,y,psImageGet(variance,x+xm,y+ym)); 473 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0x00; 474 } 475 } 476 // Mask so I can see on the output image where the footprint is. 477 for (int i = 0; i < footprint->spans->n; i++) { 478 pmSpan *sp = footprint->spans->data[i]; 479 for (int j = sp->x0; j <= sp->x1; j++) { 480 y = sp->y - ym; 481 x = j - xm; 482 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= 0x01; 483 } 484 } 485 486 int CRpix_count = 0; 487 do { 488 CRpix_count = 0; 489 // Zero out my temp images. 490 for (x = 0; x < binning * dx; x++) { 491 for (y = 0; y < binning * dy; y++) { 492 psImageSet(binned,x,y,0.0); 493 psImageSet(conved,x,y,0.0); 494 psImageSet(edges,x/binning,y/ binning,0.0); 495 } 496 } 497 // Make subsampled image. Maybe this should be called "unbinned" or something 498 for (x = 0; x < binning * dx; x++) { 499 for (y = 0; y < binning * dy; y++) { 500 psImageSet(binned,x,y,psImageGet(mypix,x / binning,y / binning)); 501 } 502 } 503 // Apply Laplace transform (kernel = [[0 -0.25 0][-0.25 1 -0.25][0 -0.25 0]]), clipping at zero 504 for (x = 1; x < dx - 1; x++) { 505 for (y = 1; y < dy - 1; y++) { 506 psImageSet(conved,x,y,psImageGet(binned,x,y) - 0.25 * 507 (psImageGet(binned,x-1,y) + psImageGet(binned,x+1,y) + 508 psImageGet(binned,x,y-1) + psImageGet(binned,x,y+1))); 509 if (psImageGet(conved,x,y) < 0.0) { 510 psImageSet(conved,x,y,0.0); 511 } 512 } 513 } 514 // Create an edge map by rebinning 515 for (x = 0; x < binning * dx; x++) { 516 for (y = 0; y < binning * dy; y++) { 517 psImageSet(edges,x / binning, y / binning, 518 psImageGet(edges, x / binning, y / binning) + 519 psImageGet(conved,x,y)); 520 } 521 } 522 // Modify my mask if we're above the significance threshold 523 for (x = 0; x < dx; x++) { 524 for (y = 0; y < dy; y++) { 525 if ( psImageGet(edges,x,y) / (binning * sqrt(noise_factor * psImageGet(myvar,x,y))) > sigma_thresh ) { 526 if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x01) { 527 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= 0x40; 528 CRpix_count++; 529 } 530 } 531 } 532 } 533 534 // "Repair" Masked pixels for the next round. 535 for (x = 1; x < dx - 1; x++) { 536 for (y = 1; y < dy - 1; y++) { 537 if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) { 538 psImageSet(mypix,x,y,0.25 * 539 (psImageGet(mypix,x-1,y) + psImageGet(mypix,x+1,y) + 540 psImageGet(mypix,x,y-1) + psImageGet(mypix,x,y+1))); 541 } 542 } 543 } 544 545 # if 0 546 if ((psTraceGetLevel("psphot.czw") >= 2)&&(abs(xm - 2770) < 5)&&(abs(ym - 2581) < 5)&&(iteration == 0)) { 547 psTrace("psphot.czw",2,"TRACEMOTRON %d %d %d %d %d\n",xm,ym,dx,dy,iteration); 548 psphotSaveImage (NULL, mypix, "czw.pix.fits"); 549 psphotSaveImage (NULL, myvar, "czw.var.fits"); 550 psphotSaveImage (NULL, binned, "czw.binn.fits"); 551 psphotSaveImage (NULL, conved, "czw.conv.fits"); 552 psphotSaveImage (NULL, edges, "czw.edge.fits"); 553 psphotSaveImage (NULL, mymask, "czw.mask.fits"); 554 } 555 # endif 556 557 psTrace("psphot.czw",2,"Iter: %d Count: %d",iteration,CRpix_count); 558 iteration++; 559 } while ((iteration < max_iter)&&(CRpix_count > 0)); 560 561 // A solitary masked pixel is likely a lie. Remove those. 562 for (x = 0; x < dx; x++) { 563 for (y = 0; y < dy; y++) { 564 if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) { 565 if ((x-1 >= 0)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x-1] & 0x40)) { 566 continue; 567 } 568 if ((y-1 >= 0)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y-1][x] & 0x40)) { 569 continue; 570 } 571 if ((x+1 < dx)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x+1] & 0x40)) { 572 continue; 573 } 574 if ((y+1 < dy)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y+1][x] & 0x40)) { 575 continue; 576 } 577 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] ^= 0x40; 578 } 579 } 580 } 581 582 // transfer temporary mask to real mask 583 for (x = 0; x < dx; x++) { 584 for (y = 0; y < dy; y++) { 585 if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) { 586 mask->data.PS_TYPE_IMAGE_MASK_DATA[y+ym+mask->row0][x+xm+mask->col0] |= maskVal; 587 } 588 } 589 } 590 591 // XXX if we decide this REALLY is a cosmic ray, set the CR_LIMIT bit 592 source->mode |= PM_SOURCE_MODE_CR_LIMIT; 593 594 psFree(mypix); 595 psFree(myvar); 596 psFree(binned); 597 psFree(conved); 598 psFree(edges); 599 psFree(mymask); 600 601 return true; 602 } 603 604 bool psphotMaskCosmicRayFootprintCheck (psArray *sources) { 605 606 for (int i = 0; i < sources->n; i++) { 607 pmSource *source = sources->data[i]; 608 pmPeak *peak = source->peak; 609 pmFootprint *footprint = peak->footprint; 610 if (!footprint) continue; 611 for (int j = 0; j < footprint->spans->n; j++) { 612 pmSpan *sp = footprint->spans->data[j]; 613 psAssert (sp, "missing span"); 614 } 615 } 616 return true; 617 } 618 619 /**** ------ old versions of cosmic ray masking ----- ****/ 620 621 // This attempt to mask the cosmic rays used the isophotal boundary 622 bool psphotMaskCosmicRay_V1 (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) { 129 623 130 624 // replace the source flux … … 139 633 pmFootprint *footprint = peak->footprint; 140 634 if (!footprint) { 635 psTrace("psphot.czw",2,"Using isophot CR mask code."); 636 141 637 // if we have not footprint, use the old code to mask by isophot 142 638 psphotMaskCosmicRayIsophot (source, maskVal, crMask); … … 145 641 146 642 if (!footprint->spans) { 643 psTrace("psphot.czw",2,"Using isophot CR mask code."); 644 147 645 // if we have no footprint, use the old code to mask by isophot 148 646 psphotMaskCosmicRayIsophot (source, maskVal, crMask); 149 647 return true; 150 648 } 151 649 psphotMaskCosmicRayIsophot (source, maskVal, crMask); 152 650 // mask all of the pixels covered by the spans of the footprint 153 for (int j = 1; j < footprint->spans->n; j++) { 154 pmSpan *span1 = footprint->spans->data[j]; 155 156 int iy = span1->y; 157 int xs = span1->x0; 158 int xe = span1->x1; 159 160 for (int ix = xs; ix < xe; ix++) { 161 mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask; 162 } 163 } 651 for (int j = 1; j < footprint->spans->n; j++) { 652 pmSpan *span1 = footprint->spans->data[j]; 653 654 int iy = span1->y; 655 int xs = span1->x0; 656 int xe = span1->x1; 657 658 for (int ix = xs; ix < xe; ix++) { 659 mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask; 660 } 661 } 164 662 return true; 165 663 } … … 228 726 } 229 727 } 230 return true;231 }232 233 // model the apmifit distribution for the psf stars:234 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) {235 236 // select stats from the psf stars237 psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32);238 psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);239 240 psImageMaskType maskVal = options->maskVal | options->markVal;241 242 // XXX why PHOT_WEIGHT??243 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;244 245 for (int i = 0; i < sources->n; i++) {246 pmSource *source = sources->data[i];247 if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;248 249 // replace object in image250 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {251 pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);252 }253 254 // clear the mask bit and set the circular mask pixels255 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));256 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);257 258 // XXX can we test if psfMag is set and calculate only if needed?259 pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal260 261 // clear the mask bit262 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));263 264 // re-subtract the object, leave local sky265 pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);266 267 float apMag = -2.5*log10(source->moments->Sum);268 float dMag = source->psfMag - apMag;269 270 psVectorAppend (Ap, dMag);271 psVectorAppend (ApErr, source->errMag);272 }273 274 // model the distribution as a mean or median value and a systematic error from that value:275 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);276 psVectorStats (stats, Ap, NULL, NULL, 0);277 278 psVector *dAp = psVectorAlloc (Ap->n, PS_TYPE_F32);279 for (int i = 0; i < Ap->n; i++) {280 dAp->data.F32[i] = Ap->data.F32[i] - stats->robustMedian;281 }282 283 options->ApResid = stats->robustMedian;284 options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.05);285 // XXX this is quite arbitrary...286 if (!isfinite(options->ApSysErr)) options->ApSysErr = 0.01;287 psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr);288 289 psFree (Ap);290 psFree (ApErr);291 psFree (stats);292 psFree (dAp);293 294 return true;295 }296 297 // classify sources based on the combination of psf-mag, Mxx, Myy298 bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {299 300 bool status;301 pmPSFClump psfClump;302 char regionName[64];303 304 psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip");305 306 int nRegions = psMetadataLookupS32 (&status, readout->analysis, "PSF.CLUMP.NREGIONS");307 for (int i = 0; i < nRegions; i ++) {308 snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);309 psMetadata *regionMD = psMetadataLookupPtr (&status, readout->analysis, regionName);310 psAssert (regionMD, "regions must be defined by earlier call to psphotRoughClassRegion");311 312 psRegion *region = psMetadataLookupPtr (&status, regionMD, "REGION");313 psAssert (region, "regions must be defined by earlier call to psphotRoughClassRegion");314 315 // pull FWHM_X,Y from the recipe, use to define psfClump.X,Y316 psfClump.X = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X"); psAssert (status, "missing PSF.CLUMP.X");317 psfClump.Y = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y"); psAssert (status, "missing PSF.CLUMP.Y");318 psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX"); psAssert (status, "missing PSF.CLUMP.DX");319 psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY"); psAssert (status, "missing PSF.CLUMP.DY");320 321 if ((psfClump.X < 0) || (psfClump.Y < 0) || !psfClump.X || !psfClump.Y || isnan(psfClump.X) || isnan(psfClump.Y)) {322 psLogMsg ("psphot", 4, "Failed to find a valid PSF clump for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);323 continue;324 }325 326 if (!psphotSourceClassRegion (region, &psfClump, sources, recipe, psf, options)) {327 psLogMsg ("psphot", 4, "Failed to determine source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);328 continue;329 }330 }331 332 return true;333 }334 335 bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {336 337 PS_ASSERT_PTR_NON_NULL(sources, false);338 PS_ASSERT_PTR_NON_NULL(recipe, false);339 340 int Nsat = 0;341 int Next = 0;342 int Npsf = 0;343 int Ncr = 0;344 int Nmiss = 0;345 int Nskip = 0;346 347 pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN;348 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;349 350 psImageMaskType maskVal = options->maskVal | options->markVal;351 352 for (psS32 i = 0 ; i < sources->n ; i++) {353 354 pmSource *source = (pmSource *) sources->data[i];355 356 // psfClumps are found for image subregions:357 // skip sources not in this region358 if (source->peak->x < region->x0) continue;359 if (source->peak->x >= region->x1) continue;360 if (source->peak->y < region->y0) continue;361 if (source->peak->y >= region->y1) continue;362 363 // skip source if it was already measured364 if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {365 psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");366 continue;367 }368 369 // source must have been subtracted370 if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {371 source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;372 psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");373 continue;374 }375 376 // we are basically classifying by moments; use the default if not found377 psAssert (source->moments, "why is this source missing moments?");378 if (source->mode & noMoments) {379 Nskip ++;380 continue;381 }382 383 psF32 Mxx = source->moments->Mxx;384 psF32 Myy = source->moments->Myy;385 386 // replace object in image387 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {388 pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);389 }390 391 // clear the mask bit and set the circular mask pixels392 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));393 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);394 395 // XXX can we test if psfMag is set and calculate only if needed?396 pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal397 398 // clear the mask bit399 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));400 401 // re-subtract the object, leave local sky402 pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);403 404 float apMag = -2.5*log10(source->moments->Sum);405 float dMag = source->psfMag - apMag;406 float nSigma = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr);407 408 source->extNsigma = nSigma;409 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;410 411 // Anything within this region is a probably PSF-like object. Saturated stars may land412 // in this region, but are detected elsewhere on the basis of their peak value.413 bool isPSF = (fabs(nSigma) < options->nSigmaApResid) && (fabs(Mxx - psfClump->X) < options->nSigmaMoments*psfClump->dX) && (fabs(Myy - psfClump->Y) < options->nSigmaMoments*psfClump->dY);414 if (isPSF) {415 Npsf ++;416 continue;417 }418 419 // Defects may not always match CRs from peak curvature analysis420 // Defects may also be marked as SATSTAR -- XXX deactivate this flag?421 // XXX this rule is not great422 if ((Mxx < psfClump->X) || (Myy < psfClump->Y)) {423 source->mode |= PM_SOURCE_MODE_DEFECT;424 Ncr ++;425 continue;426 }427 428 // saturated star (determined in PSF fit). These may also be saturated galaxies, or429 // just large saturated regions.430 if (source->mode & PM_SOURCE_MODE_SATSTAR) {431 Nsat ++;432 continue;433 }434 435 // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)?436 bool isEXT = (nSigma > options->nSigmaApResid) || ((Mxx > psfClump->X) && (Myy > psfClump->Y));437 if (isEXT) {438 source->mode |= PM_SOURCE_MODE_EXT_LIMIT;439 Next ++;440 continue;441 }442 443 psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigma);444 Nmiss ++;445 }446 447 psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip);448 449 728 return true; 450 729 } … … 524 803 } 525 804 526 bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) { 805 // this was an old attempt to identify cosmic rays based on the peak curvature 806 bool psphotSourcePeakCurvature (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) { 527 807 528 808 // classify the sources based on the CR test (place this in a function?) … … 656 936 return true; 657 937 } 938
Note:
See TracChangeset
for help on using the changeset viewer.
