- Timestamp:
- Oct 20, 2010, 8:55:04 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-20100823/psphot/src/psphotSourceSize.c
r29459 r29491 1 1 # include "psphotInternal.h" 2 2 # include <gsl/gsl_sf_gamma.h> 3 4 # define KRON 15 3 6 4 typedef struct { … … 16 14 int grow; 17 15 int xtest, ytest; 18 bool apply; // apply CR mask? 16 bool applyCRmask; // apply CR mask? 17 bool dynamicLimitsCR; // apply CR mask? 18 float sizeLimitCR; 19 float magLimitCR; 19 20 } psphotSourceSizeOptions; 20 21 21 22 // local functions: 22 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf); 23 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, pmReadout *readout, psArray *sources, pmPSF *psf, psMetadata *recipe); 24 bool psphotDynamicLimitsCR (psphotSourceSizeOptions *options, pmReadout *readout, psArray *sources, pmPSF *psf, psMetadata *recipe); 23 25 bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options); 24 26 bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options); 25 bool psphotSourceS izeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options);27 bool psphotSourceSelectCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options); 26 28 bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal); 27 29 bool psphotMaskCosmicRayFootprintCheck (psArray *sources); 28 30 int psphotMaskCosmicRayConnected (int xPeak, int yPeak, psImage *mymask, psImage *myvar, psImage *edges, int binning, float sigma_thresh); 31 float psphotSourceSizeFindThreshold (psVector *value, psVector *mask, int maskValue, float minValue, float maxValue, float delta, float guess, float fraction); 29 32 30 33 // we need to call this function after sources have been fitted to the PSF model and … … 111 114 assert (status); 112 115 113 // XXX recipe name is not great116 // location of a single test source 114 117 options.xtest = psMetadataLookupS32 (&status, recipe, "PSPHOT.CRMASK.XTEST"); 115 118 options.ytest = psMetadataLookupS32 (&status, recipe, "PSPHOT.CRMASK.YTEST"); … … 128 131 } 129 132 130 options.apply = psMetadataLookupBool(&status, recipe, "PSPHOT.CRMASK.APPLY"); // Growth size for CRs133 options.applyCRmask = psMetadataLookupBool(&status, recipe, "PSPHOT.CRMASK.APPLY"); // Growth size for CRs 131 134 if (!status) { 132 135 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSPHOT.CRMASK.APPLY is not defined."); … … 134 137 } 135 138 136 // We are using the value psfMag - 2.5*log10(moment.Sum) as a measure of the extendedness 137 // of an object. We need to model this distribution for the PSF stars before we can test 138 // the significance for a specific object 139 // XXX move this to the code that generates the PSF? 140 // XXX store the results on pmPSF? 141 142 // XXX this should only be done on the first pass (ie, if we have newSources or allSources?) 143 if (getPSFsize) { 144 psphotSourceSizePSF (&options, sources, psf); 145 } 146 147 // classify the sources based on ApResid and Moments (extended sources) 139 // determine the distribution of (PSF_mag - KRON_mag) for the PSF sources (saved on readout->analysis) 140 psphotSourceSizePSF (&options, readout, sources, psf, recipe); 141 142 // adjust the user-supplied limits based on the distribution of CRs in the (Mminor, mKron) space 143 psphotDynamicLimitsCR(&options, readout, sources, psf, recipe); 144 145 // classify the sources based on ApResid and Moments 148 146 // NOTE: only sources not already measured !(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) 149 147 psphotSourceClass(readout, sources, recipe, psf, &options); 150 148 151 // NOTE: only sources not already measured !(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)152 psphotSourceS izeCR(readout, sources, &options);149 // attempt to mask the candidate CRs; flag if CR nature is confirmed 150 psphotSourceSelectCR(readout, sources, &options); 153 151 154 152 // XXX fix this (was source->n - first) … … 156 154 157 155 psphotVisualPlotSourceSize (recipe, readout->analysis, sources); 156 psphotVisualPlotSourceSizeAlt (recipe, readout->analysis, sources); 158 157 psphotVisualShowSourceSize (readout, sources); 159 psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr );158 psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr, false); 160 159 psphotVisualShowSatStars (recipe, psf, sources); 161 160 … … 163 162 } 164 163 164 # define SAVE_PSF_OPTIONS(RO,OPT) \ 165 /* save these on readout->analysis (a) for output to the header and (b) to prevent re-calculating in another pass */ \ 166 psMetadataAddF32(RO->analysis, PS_LIST_TAIL, "PSPHOT.PSF.APRESID", PS_META_REPLACE, "locus of PSF stars in PSF_MAG - KRON_MAG", OPT->ApResid); \ 167 psMetadataAddF32(RO->analysis, PS_LIST_TAIL, "PSPHOT.PSF.APRESID.SYSERR", PS_META_REPLACE, "systematic error of PSF_MAG - KRON_MAG", OPT->ApSysErr); 168 165 169 // model the apmifit distribution for the psf stars: 166 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) { 170 bool psphotSourceSizePSF (psphotSourceSizeOptions *options, pmReadout *readout, psArray *sources, pmPSF *psf, psMetadata *recipe) { 171 172 // We are using the value PSF_MAG - KRON_MAG as a measure of the extendedness of an object. 173 // We need to model this distribution for the PSF stars before we can test the significance 174 // for a specific object. 175 176 // NOTE: we require that objects have had moments measured, and we also require psfMags to 177 // be calculated. but, we do not require aperture mags or any other photometry values that 178 // require pixel analysis. 179 180 bool status1 = false; 181 bool status2 = false; 182 options->ApResid = psMetadataLookupF32 (&status1, readout->analysis, "PSPHOT.PSF.APRESID"); 183 options->ApSysErr = psMetadataLookupF32 (&status2, readout->analysis, "PSPHOT.PSF.APRESID.SYSERR"); 184 psAssert ((status1 && status2) || (!status1 && !status2), "inconsistent record of PSF ApResid values"); 185 186 // if they are saved on readout->analysis, we have already calculated these values 187 if (status1 && status2) { 188 return true; 189 } 167 190 168 191 // select stats from the psf stars 169 psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32);192 psVector *ApOff = psVectorAllocEmpty (100, PS_TYPE_F32); 170 193 psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32); 171 194 … … 173 196 psImageMaskType maskVal = options->maskVal | options->markVal; 174 197 175 // XXX why PHOT_WEIGHT??176 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_ WEIGHT;198 // with PSFONLY, we do not need modify the pixels 199 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_PSFONLY; 177 200 178 201 int num = 0; // Number of sources measured … … 182 205 num++; 183 206 184 // replace object in image185 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {186 pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);187 }188 189 // clear the mask bit and set the circular mask pixels190 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));191 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);192 193 // XXX can we test if psfMag is set and calculate only if needed?194 207 pmSourceMagnitudes (source, psf, photMode, maskVal, markVal); 195 208 196 // clear the mask bit 197 psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal)); 198 199 // re-subtract the object, leave local sky 200 pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal); 201 202 // XXX test: switch to kron flux 203 # if (KRON) 204 float apMag = -2.5*log10(source->moments->KronFlux); 205 # else 206 float apMag = -2.5*log10(source->moments->Sum); 207 # endif 208 float dMag = source->psfMag - apMag; 209 210 psVectorAppend (Ap, dMag); 209 float kMag = -2.5*log10(source->moments->KronFlux); 210 float dMag = source->psfMag - kMag; 211 212 psVectorAppend (ApOff, dMag); 211 213 psVectorAppend (ApErr, source->errMag); 212 214 } 213 215 if (num == 0) { 214 // Not raising an error, because errors aren't being checked elsewhere in this function 215 psFree(Ap); 216 // if we cannot determine the PSF distribution, call all objects PSFs... 217 options->ApResid = NAN; 218 options->ApSysErr = NAN; 219 psFree(ApOff); 216 220 psFree(ApErr); 221 SAVE_PSF_OPTIONS(readout, options); 217 222 return false; 218 223 } … … 221 226 // psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); 222 227 psStats *stats = psStatsAlloc(PS_STAT_CLIPPED_MEAN); 223 psVectorStats (stats, Ap , NULL, NULL, 0);224 225 psVector *dAp = psVectorAlloc (Ap ->n, PS_TYPE_F32);226 for (int i = 0; i < Ap ->n; i++) {227 dAp->data.F32[i] = Ap ->data.F32[i] - stats->clippedMean;228 psVectorStats (stats, ApOff, NULL, NULL, 0); 229 230 psVector *dAp = psVectorAlloc (ApOff->n, PS_TYPE_F32); 231 for (int i = 0; i < ApOff->n; i++) { 232 dAp->data.F32[i] = ApOff->data.F32[i] - stats->clippedMean; 228 233 } 229 234 230 235 options->ApResid = stats->clippedMean; 231 236 options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.1); 232 // XXX this is quite arbitrary... 233 if (!isfinite(options->ApSysErr)) options->ApSysErr = 0.01; 237 238 // this is quite arbitrary... a large value means fewer things classified as extended. 239 if (!isfinite(options->ApSysErr)) options->ApSysErr = 0.05; 234 240 psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr); 235 241 236 psFree (Ap );242 psFree (ApOff); 237 243 psFree (ApErr); 238 244 psFree (stats); 239 245 psFree (dAp); 240 246 247 SAVE_PSF_OPTIONS(readout, options); 241 248 return true; 249 } 250 251 # define SAVE_CR_OPTIONS(RO,OPT) \ 252 /* save these on readout->analysis (a) for output to the header and (b) to prevent re-calculating in another pass */ \ 253 psMetadataAddF32(RO->analysis, PS_LIST_TAIL, "PSPHOT.CR.MAX.SIZE", PS_META_REPLACE, "dynamically-set minor axis size limit for cosmic rays", OPT->sizeLimitCR); \ 254 psMetadataAddF32(RO->analysis, PS_LIST_TAIL, "PSPHOT.CR.MAX.MAG", PS_META_REPLACE, "dynamically-set kron magnitude limit for cosmic rays", OPT->magLimitCR); 255 256 // model the size and magnitude distribution of the Cosmic Rays 257 // ** CRs are reliably flagged by a combination on Mminor < X && mag (or flux) > Y 258 bool psphotDynamicLimitsCR (psphotSourceSizeOptions *options, pmReadout *readout, psArray *sources, pmPSF *psf, psMetadata *recipe) { 259 260 /* attempt to describe the CR sources: 261 - input parameters are sizeLimit, magLimit 262 - first try to refine the sizeLimit: 263 -- select objects which meet the magLimit and exceed the sizeLimit by a factor of 1.5 264 -- generate the histogram 265 -- look for a peak in the histogram 266 -- look for the min between valley and upper limit 267 -- look for first bin within 5% of the valley floor after peak (new sizeLimit) 268 269 - next try to refine the magLimit 270 -- select objects which meet the sizeLimit and go fainter than the magLimit by 1.0 mag 271 -- generate the histogram 272 -- look for a peak in the histogram 273 -- look for the min between valley and upper limit 274 -- look for first bin within 5% of the valley floor after peak (new magLimit) 275 */ 276 277 bool status = false; 278 bool status1 = false; 279 bool status2 = false; 280 options->sizeLimitCR = psMetadataLookupF32 (&status1, readout->analysis, "PSPHOT.CR.MAX.SIZE"); 281 if (!status1) { 282 options->sizeLimitCR = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.MAX.SIZE"); 283 if (!status) { 284 options->sizeLimitCR = 1.0; 285 } 286 } 287 options->magLimitCR = psMetadataLookupF32 (&status2, readout->analysis, "PSPHOT.CR.MAX.MAG"); 288 if (!status2) { 289 options->magLimitCR = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.MAX.MAG"); 290 if (!status) { 291 options->magLimitCR = -8.0; 292 } 293 } 294 psAssert ((status1 && status2) || (!status1 && !status2), "inconsistent record of dynamic CR limits"); 295 296 // if they are saved on readout->analysis, we have already calculated these values 297 if (status1 && status2) { 298 return true; 299 } 300 301 // if we do not want to dynamically set these, save the user-supplied values and exit 302 options->dynamicLimitsCR = psMetadataLookupBool (&status, recipe, "PSPHOT.CR.AUTOSCALE"); 303 if (!status) { 304 options->dynamicLimitsCR = true; 305 } 306 if (!options->dynamicLimitsCR) { 307 SAVE_CR_OPTIONS(readout, options); // macro defined above 308 return true; 309 } 310 311 psVector *minor = psVectorAllocEmpty (100, PS_TYPE_F32); 312 psVector *mKron = psVectorAllocEmpty (100, PS_TYPE_F32); 313 psVector *mask = NULL; 314 315 psImageMaskType markVal = options->markVal; 316 psImageMaskType maskVal = options->maskVal | options->markVal; 317 318 // with PSFONLY, we do not need modify the pixels 319 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_PSFONLY; 320 321 // generate vectors for all the objects of possible interest (so we can just access those 322 // vectors in the next sections) 323 for (int i = 0; i < sources->n; i++) { 324 pmSource *source = sources->data[i]; 325 326 // XXX can we test if psfMag is set and calculate only if needed? 327 pmSourceMagnitudes (source, psf, photMode, maskVal, markVal); 328 329 // convert to Mmaj, Mmin: 330 psF32 Mxx = source->moments->Mxx; 331 psF32 Myy = source->moments->Myy; 332 psF32 Mxy = source->moments->Mxy; 333 334 float KronMag = -2.5*log10(source->moments->KronFlux); 335 336 float Mminor = 0.5*(Mxx + Myy) - 0.5*sqrt(PS_SQR(Mxx - Myy) + 4.0*PS_SQR(Mxy)); 337 338 if (Mminor > options->sizeLimitCR * 1.5) continue; 339 if (KronMag > options->magLimitCR + 2.5) continue; 340 341 psVectorAppend (mKron, KronMag); 342 psVectorAppend (minor, Mminor); 343 } 344 345 // if too few objects meet the criterion, give up.. 346 if (mKron->n < 50) goto escape; 347 348 // set distinct masks for (minor > sizeLimit) or (mKron > magLimit) 349 mask = psVectorAlloc(mKron->n, PS_TYPE_U8); 350 psVectorInit(mask, 0); 351 for (int i = 0; i < mKron->n; i++) { 352 if (mKron->data.F32[i] > options->magLimitCR) { 353 mask->data.U8[i] |= 0x01; 354 } 355 if (minor->data.F32[i] > options->sizeLimitCR) { 356 mask->data.U8[i] |= 0x02; 357 } 358 } 359 360 float delta1 = PS_MAX(0.02, PS_MIN(0.2, 5.0 * 0.5 / minor->n)); 361 float newSizeLimit = psphotSourceSizeFindThreshold(minor, mask, 0x01, 0.0, options->sizeLimitCR * 1.5, delta1, options->sizeLimitCR, 0.05); 362 if (isfinite(newSizeLimit)) { 363 options->sizeLimitCR = newSizeLimit; 364 } 365 366 float delta2 = PS_MAX(0.02, PS_MIN(0.2, 5.0 * 2.0 / minor->n)); 367 float newMagLimit = psphotSourceSizeFindThreshold(mKron, mask, 0x02, -15.0, options->magLimitCR + 2.5, delta2, options->magLimitCR, 0.05); 368 if (isfinite(newMagLimit)) { 369 options->magLimitCR = newMagLimit; 370 } 371 372 psLogMsg ("psphot", PS_LOG_DETAIL, "CR limits : %f mag | %f pix^2\n", options->magLimitCR, options->sizeLimitCR); 373 374 psFree (mKron); 375 psFree (minor); 376 psFree (mask); 377 378 // save these on readout->analysis (a) for output to the header and (b) to prevent re-calculating in another pass 379 SAVE_CR_OPTIONS(readout, options); // macro defined above 380 return true; 381 382 escape: 383 SAVE_CR_OPTIONS(readout, options); // macro defined above 384 return false; 242 385 } 243 386 … … 249 392 char regionName[64]; 250 393 251 psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip"); 394 psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nskip"); 395 396 if (!psphotSourceClassRegion (NULL, &psfClump, sources, recipe, psf, options)) { 397 psLogMsg ("psphot", 4, "Failed to determine source classification for full image\n"); 398 } else { 399 psLogMsg ("psphot", 4, "source classification for full image\n"); 400 } 401 return true; 252 402 253 403 int nRegions = psMetadataLookupS32 (&status, readout->analysis, "PSF.CLUMP.NREGIONS"); … … 275 425 continue; 276 426 } 427 psLogMsg ("psphot", 4, "source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1); 277 428 // psphotVisualPlotSourceSize (recipe, readout->analysis, sources); 278 429 } … … 281 432 } 282 433 283 # define SIZE_SN_LIM 10284 434 bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) { 285 435 … … 291 441 int Npsf = 0; 292 442 int Ncr = 0; 293 int Nmiss = 0;294 443 int Nskip = 0; 295 444 296 445 pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN; 297 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT; 446 447 // request the pixWeight values as well as the magnitudes 448 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT; 298 449 299 450 psImageMaskType markVal = options->markVal; … … 306 457 // psfClumps are found for image subregions: 307 458 // skip sources not in this region 308 if (source->peak->x < region->x0) continue; 309 if (source->peak->x >= region->x1) continue; 310 if (source->peak->y < region->y0) continue; 311 if (source->peak->y >= region->y1) continue; 459 if (region) { 460 if (source->peak->x < region->x0) continue; 461 if (source->peak->x >= region->x1) continue; 462 if (source->peak->y < region->y0) continue; 463 if (source->peak->y >= region->y1) continue; 464 } 312 465 313 466 // skip source if it was already measured … … 321 474 source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED; 322 475 psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n"); 323 continue; 324 } 325 326 // we are basically classifying by moments 476 Nskip ++; 477 continue; 478 } 479 480 // we are classifying by moments and PSF_MAG - KRON_MAG 327 481 psAssert (source->moments, "why is this source missing moments?"); 328 482 if (source->mode & noMoments) { … … 335 489 psF32 Myy = source->moments->Myy; 336 490 psF32 Mxy = source->moments->Mxy; 337 338 // replace object in image 491 float Mminor = 0.5*(Mxx + Myy) - 0.5*sqrt(PS_SQR(Mxx - Myy) + 4.0*PS_SQR(Mxy)); 492 493 // replace object in image to measure mag & psfWeights 339 494 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) { 340 495 pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal); … … 345 500 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal); 346 501 347 // XXX can we test if psfMag is set and calculate only if needed?348 502 pmSourceMagnitudes (source, psf, photMode, maskVal, markVal); 349 503 … … 354 508 pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal); 355 509 356 # if (KRON) 357 float apMag = -2.5*log10(source->moments->KronFlux); 358 # else 359 float apMag = -2.5*log10(source->moments->Sum); 360 # endif 361 float dMag = source->psfMag - apMag; 362 363 // set nSigma to include both systematic and poisson error terms 364 // XXX need to handle NAN psfMag and apMag (ie, skip?) 365 // XXX the 'poisson error' contribution for size is probably wrong... 366 // XXX add in a hard floor on the Ap Sys Err (to be a bit generous) 367 float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, hypot(options->ApSysErr, 0.025)); 368 float nSigmaMXX = (Mxx - psfClump->X) / hypot(psfClump->dX, psfClump->X*psfClump->X*source->errMag); 369 float nSigmaMYY = (Myy - psfClump->Y) / hypot(psfClump->dY, psfClump->Y*psfClump->Y*source->errMag); 370 371 // XXX should I change psfClump to use minor, major? 372 373 // fprintf (stderr, "%f %f : Mxx: %f, Myy: %f, dx: %f, dy: %f, psfMag: %f, apMag: %f, dMag: %f, errMag: %f, nSigmaMag: %f, nSigmaMxx: %f, nSigmaMyy: %f\n", 374 // source->peak->xf, source->peak->yf, Mxx, Myy, source->peak->xf - source->moments->Mx, source->peak->yf - source->moments->My, 375 // source->psfMag, apMag, dMag, source->errMag, nSigmaMAG, nSigmaMXX, nSigmaMYY); 376 377 // XXX double check on ths stuff!! partially-masked sources are more likely to be mis-measured PSFs 378 float sizeBias = 1.0; 379 if (source->pixWeightNotBad < 0.9) { 380 sizeBias = 3.0; 381 } 382 if (source->pixWeightNotPoor < 0.9) { 383 sizeBias = 3.0; 384 } 385 386 float minMxx = psfClump->X - sizeBias*options->nSigmaMoments*psfClump->dX; 387 float minMyy = psfClump->Y - sizeBias*options->nSigmaMoments*psfClump->dY; 388 389 // include MAG, MXX, and MYY? 510 float kMag = -2.5*log10(source->moments->KronFlux); 511 float dMag = source->psfMag - kMag; 512 513 // sources without a valid magnitudes cannot have their size measured 514 if (!isfinite(kMag) || !isfinite(source->psfMag)) { 515 Nskip ++; 516 continue; 517 } 518 519 // set nSigmaMAG to include both systematic and poisson error terms. we include a hard 520 // floor on the Ap Sys Err (to be a bit generous). XXX put the floor in the recipe... 521 float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, hypot(options->ApSysErr, 0.02)); 390 522 source->extNsigma = nSigmaMAG; 391 523 … … 394 526 // * CR & defect should have a faintess limit (min S/N) 395 527 // * SAT stars should not be faint, but defects may? 396 397 // Anything within this region is a probably PSF-like object. Saturated stars may land398 // in this region, but are detected elsewhere on the basis of their peak value.399 bool isPSF = (fabs(nSigmaMAG) < options->nSigmaApResid) && (fabs(nSigmaMXX) < sizeBias*options->nSigmaMoments) && (fabs(nSigmaMYY) < sizeBias*options->nSigmaMoments);400 if (isPSF) {401 psTrace("psphotSourceClassRegion.PSF",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g PSF\t%g %g\n",402 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,403 options->nSigmaApResid,sizeBias*options->nSigmaMoments);404 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;405 Npsf ++;406 continue;407 }408 528 409 529 // Defects may not always match CRs from peak curvature analysis … … 413 533 // (nSigmaMAG < -options->nSigmaApResid) || 414 534 415 // ** CRs are reliably flagged by a combination on Mminor < X && mag (or flux) > Y 416 417 float Mminor = 0.5*(Mxx + Myy) - 0.5*sqrt(PS_SQR(Mxx - Myy) + 4.0*PS_SQR(Mxy)); 418 if ((Mminor < 1.0) && (apMag < -8.0)) { 419 fprintf (stderr, "likely CR @ %f,%f\n", source->peak->xf, source->peak->yf); 420 } 421 422 // XXX do I need to find the Mminor, Mmajor distribution? 423 424 bool isCR = isCR = (source->errMag < 1.0 / SIZE_SN_LIM) && ((Mxx < minMxx) || (Myy < minMyy)); 535 // saturated star (too many saturated pixels or peak above saturation limit). These 536 // may also be saturated galaxies, or just large saturated regions. 537 if (source->mode & PM_SOURCE_MODE_SATSTAR) { 538 psTrace("psphotSourceClassRegion.SAT",4,"CLASS: %g %g\t%g %g\t%g %g\t%g %g\t%g SAT\n", 539 source->peak->xf, source->peak->yf, Mminor, kMag, dMag, nSigmaMAG, options->sizeLimitCR, options->magLimitCR, options->nSigmaApResid); 540 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 541 Nsat ++; 542 continue; 543 } 544 545 // any sources missing a large fraction should just be treated as PSFs 546 if ((source->pixWeightNotBad < 0.9) || (source->pixWeightNotPoor < 0.9)) { 547 psTrace("psphotSourceClassRegion.PSF",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g PSF\t%g %g\n", 548 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,kMag,dMag,nSigmaMAG, 549 options->nSigmaApResid,options->nSigmaMoments); 550 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 551 Npsf ++; 552 continue; 553 } 554 555 // CRs are flagged by a combination on Mminor < options->sizeLimitCR && kmag < options->magLimitCR 556 // NOTE: we only flag the CRs here; when we mask them we verify their CR nature (otherwise -> PSF) 557 // bool isCR = (kMag < options->magLimitCR) && (Mminor < options->sizeLimitCR); 558 bool isCR = (source->moments->SN > 7.0) && (Mminor < options->sizeLimitCR); 425 559 if (isCR) { 426 psTrace("psphotSourceClassRegion.CR",4,"CLASS: %g %g %f\t%g %g %g %g %g %g\t%g %g\t%g CR\t%g %g\n", 427 source->peak->xf,source->peak->yf,source->pixWeightNotBad,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 428 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 560 psTrace("psphotSourceClassRegion.CR",4,"CLASS: %g %g\t%g %g\t%g %g\t%g %g\t%g CR\n", 561 source->peak->xf, source->peak->yf, Mminor, kMag, dMag, nSigmaMAG, options->sizeLimitCR, options->magLimitCR, options->nSigmaApResid); 429 562 source->mode |= PM_SOURCE_MODE_DEFECT; 430 563 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_CR_CANDIDATE; 564 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 431 565 Ncr ++; 432 566 continue; 433 567 } 434 568 435 // saturated star (determined in PSF fit). These may also be saturated galaxies, or 436 // just large saturated regions. 437 if (source->mode & PM_SOURCE_MODE_SATSTAR) { 438 psTrace("psphotSourceClassRegion.SAT",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g SAT\t%g %g\n", 439 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 440 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 441 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 442 Nsat ++; 443 continue; 444 } 445 446 // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)? 447 bool isEXT = (nSigmaMAG > options->nSigmaApResid) || (Mxx > minMxx) || (Myy > minMyy); 569 // Likely extended source (PSF_MAG - KRON_MAG is larger than limit) 570 bool isEXT = (nSigmaMAG > options->nSigmaApResid); 448 571 if (isEXT) { 449 psTrace("psphotSourceClassRegion.EXT",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g Ext\t%g %g\n", 450 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 451 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 452 572 psTrace("psphotSourceClassRegion.EXT",4,"CLASS: %g %g\t%g %g\t%g %g\t%g %g\t%g EXT\n", 573 source->peak->xf, source->peak->yf, Mminor, kMag, dMag, nSigmaMAG, options->sizeLimitCR, options->magLimitCR, options->nSigmaApResid); 453 574 source->mode |= PM_SOURCE_MODE_EXT_LIMIT; 454 575 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; … … 456 577 continue; 457 578 } 458 psTrace("psphotSourceClassRegion.MISS",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g Unk\t%g %g\n", 459 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 460 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 461 462 // sources that reach here are probably too faint for a reasonable source size measurement 463 // psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigmaMAG); 464 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 465 Nmiss ++; 466 } 467 468 psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip); 579 580 // Everything else should just be treated as a PSF 581 psTrace("psphotSourceClassRegion.PSF",4,"CLASS: %g %g\t%g %g\t%g %g\t%g %g\t%g PSF\n", 582 source->peak->xf, source->peak->yf, Mminor, kMag, dMag, nSigmaMAG, options->sizeLimitCR, options->magLimitCR, options->nSigmaApResid); 583 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 584 Npsf ++; 585 } 586 587 psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nskip); 469 588 470 589 return true; … … 473 592 // given an object suspected to be a defect, generate a pixel mask using the Lapacian transform 474 593 // if enough of the object is detected as 'sharp', consider the object a cosmic ray 475 bool psphotSourceS izeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {594 bool psphotSourceSelectCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) { 476 595 477 596 psTimerStart ("psphot.cr"); … … 481 600 pmSource *source = sources->data[i]; 482 601 483 // skip source if it was already measured484 if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {485 psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");486 continue;487 }488 489 602 // only check candidates marked above 490 603 if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_CR_CANDIDATE)) { … … 493 606 } 494 607 495 // skip unless this source is thought to be a cosmic ray. flag the detection and mask the pixels 496 // XXX this may be degenerate with the above test 497 if (!(source->mode & PM_SOURCE_MODE_DEFECT)) continue; 608 // once we are here, remove the temporary flag 609 source->mode &= ~PM_SOURCE_TMPF_SIZE_CR_CANDIDATE; 498 610 499 611 // Integer position of peak … … 519 631 // XXX this is running slowly and is too agressive, but it more-or-less works 520 632 psTrace("psphot", 6, "mask cosmic ray at %f, %f\n", source->peak->xf, source->peak->yf); 521 if (options->apply ) {633 if (options->applyCRmask) { 522 634 psphotMaskCosmicRay(readout, source, options->crMask); 523 635 } else { … … 546 658 547 659 // XXX test : save the mask image 548 if ( 0) {549 psphotSaveImage (NULL, readout->mask, " mask.fits");660 if (1) { 661 psphotSaveImage (NULL, readout->mask, "crmask.fits"); 550 662 } 551 663 … … 736 848 if (nCRpix > 1) { 737 849 source->mode |= PM_SOURCE_MODE_CR_LIMIT; 738 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;739 850 } 740 851 // fprintf (stderr, "CRMASK %d %d %d %d %d\n", peak->x, peak->y, dx, dy, nCRpix); … … 1231 1342 } 1232 1343 1344 float psphotSourceSizeFindThreshold (psVector *value, psVector *mask, int maskValue, float minValue, float maxValue, float delta, float guess, float fraction) { 1345 1346 // make a histogram of the sources with mKron < magLimit 1347 int nValue = (int)((maxValue - minValue) / delta) + 1; 1348 1349 psVector *histogram = psVectorAlloc(nValue, PS_TYPE_S32); 1350 psVectorInit (histogram, 0); 1351 1352 for (int i = 0; i < value->n; i++) { 1353 if (mask->data.U8[i] & maskValue) continue; 1354 int bin = (value->data.F32[i] - minValue) / delta; 1355 if (bin < 0.0) continue; 1356 if (bin > histogram->n - 1) continue; 1357 histogram->data.S32[bin] ++; 1358 } 1359 1360 // find the peak of this histogram, but stop search at guess 1361 int last = (guess - minValue) / delta; 1362 int nPeak = 0; 1363 int vPeak = histogram->data.S32[0]; 1364 for (int i = 1; (i < last) && (i < histogram->n); i++) { 1365 if (histogram->data.S32[i] < vPeak) continue; 1366 nPeak = i; 1367 vPeak = histogram->data.S32[i]; 1368 } 1369 1370 // start at the peak and find the valley between here and the end of the histogram 1371 int nValley = nPeak; 1372 int vValley = histogram->data.S32[nPeak]; 1373 for (int i = nPeak + 1; i < histogram->n; i++) { 1374 if (histogram->data.S32[i] > vValley) continue; 1375 nValley = i; 1376 vValley = histogram->data.S32[i]; 1377 } 1378 1379 psLogMsg ("psphot", PS_LOG_MINUTIA, "CR limits threshold : peak %d @ %f, valley %d @ %f (%f sigma)\n", 1380 vPeak, delta * nPeak + minValue, vValley, delta * nValley + minValue, vPeak / PS_MAX(1.0, sqrt(vValley))); 1381 1382 if (nValley == nPeak) { 1383 psFree (histogram); 1384 return NAN; 1385 } 1386 1387 if (vPeak < 3.0*sqrt(vValley)) { 1388 psFree (histogram); 1389 return NAN; 1390 } 1391 1392 /// search for the first bin after the peak with f < vValley + 0.05*(vPeak - vValley) 1393 float vLimit = vValley + fraction*(vPeak - vValley); 1394 int nLimit = nValley; 1395 for (int i = nPeak; i < nValley; i++) { 1396 if (histogram->data.S32[i] > vLimit) continue; 1397 nLimit = i; 1398 break; 1399 } 1400 float result = nLimit * delta + minValue; 1401 1402 psFree (histogram); 1403 1404 return result; 1405 }
Note:
See TracChangeset
for help on using the changeset viewer.
