Changeset 27532
- Timestamp:
- Mar 30, 2010, 1:33:47 PM (16 years ago)
- Location:
- trunk/psphot
- Files:
-
- 11 edited
- 2 copied
-
doc/notes.20100131.txt (modified) (1 diff)
-
src/psphot.h (modified) (2 diffs)
-
src/psphotEfficiency.c (modified) (14 diffs)
-
src/psphotFitSourcesLinear.c (modified) (5 diffs)
-
src/psphotFitSourcesLinearStack.c (modified) (2 diffs)
-
src/psphotKernelFromPSF.c (modified) (2 diffs)
-
src/psphotMagnitudes.c (modified) (3 diffs)
-
src/psphotMakeResiduals.c (modified) (1 diff)
-
src/psphotReadout.c (modified) (1 diff)
-
src/psphotSourceMerge.c (copied) (copied from branches/eam_branches/20100225/psphot/src/psphotSourceMerge.c )
-
src/psphotSourceSize.c (modified) (21 diffs)
-
src/psphotStackChisqImage.c (copied) (copied from branches/eam_branches/20100225/psphot/src/psphotStackChisqImage.c )
-
src/psphotVisual.c (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psphot/doc/notes.20100131.txt
r26894 r27532 1 2 2010.03.24 3 4 I have finished another iteration on source size analysis. I feel 5 fairly confident of the extended source and CR identifications. They 6 are not perfect, but they are in pretty good shape. The CR IDs use 7 the moments to find things smaller in one dimension than a PSF, while 8 the EXT is set for things larger than a PSF in one dimention. 9 10 There still seems to be some trouble with SATSTARS : these are being 11 set for sources which are fainter than the SAT limit -- I'm not sure 12 if this is due to the quality of the PSF fit or if they really are 13 SAT, but have integrated fluxes lower than expected (underfitted in 14 PSF). 15 16 Additional Parameters needed from psphot for distinguishing dipoles: 17 18 -- note regarding CfA parameters -- 19 20 Here are our settings. 21 22 Note that Fpos is the flux which is 3-sigma above background, and 23 Fneg is the flux which is 3-sigma below background. 24 25 Npos is the # of pixels with flux which is 3-sigma above background. 26 27 etc. 28 29 # for positive objects: 30 # Ngood = Npos, Nbad = Nneg, Fgood = Fpos, Fbad = Fneg 31 32 # for negative objects: 33 # Ngood = Nneg, Nbad = Npos, Fgood = Fneg, Fbad = Fpos 34 # FRATIO=Fgood/(Fgood+Fbad) 35 # NRATIO_BAD=Ngood/(Ngood+Nbad) 36 # NRATIO_MASK=Ngood/(Ngood+Nmask) 37 # NRATIO_ALL=Ngood/(Ngood+Nbad+Nmask) 38 DC_FRATIO_MIN 0.75 39 DC_NRATIO_BAD_MIN 0.70 40 DC_NRATIO_MASK_MIN 0.60 41 DC_NRATIO_ALL_MIN 0.50 42 DC_NGOOD_MIN 3 43 44 *** double-check on the use of fluxScale in pmSourcePhotometry.c:106 1 45 2 46 20100131 -
trunk/psphot/src/psphot.h
r26894 r27532 92 92 93 93 bool psphotFitSourcesLinear (pmConfig *config, const pmFPAview *view, bool final); 94 bool psphotFitSourcesLinearReadout (p mConfig *config, const pmFPAview *view, const char *filename, int index, bool final);94 bool psphotFitSourcesLinearReadout (psMetadata *recipe, pmReadout *readout, psArray *sources, pmPSF *psf, bool final); 95 95 96 96 bool psphotSourceSize (pmConfig *config, const pmFPAview *view, bool getPSFsize); … … 119 119 120 120 bool psphotMagnitudes (pmConfig *config, const pmFPAview *view); 121 bool psphotMagnitudesReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe);121 bool psphotMagnitudesReadout(pmConfig *config, psMetadata *recipe, const pmFPAview *view, pmReadout *readout, psArray *sources, pmPSF *psf); 122 122 bool psphotMagnitudes_Threaded (psThreadJob *job); 123 123 -
trunk/psphot/src/psphotEfficiency.c
r26894 r27532 4 4 PM_MODEL_STATUS_BADARGS | PM_MODEL_STATUS_LIMITS) // Mask to apply to models 5 5 6 //#define TESTING 7 8 9 # if 0 6 # define TESTING 0 10 7 11 8 // Calculate the limiting magnitude for an image … … 19 16 float *covarFactor,// Covariance factor 20 17 const pmReadout *ro, // Readout of interest 21 const pmPSF *psf,// Point-spread function18 pmPSF *psf, // Point-spread function 22 19 float thresh, // Threshold for source identification 23 20 float smoothSigma, // Gaussian smoothing sigma … … 152 149 } 153 150 154 # endif155 156 151 bool psphotEfficiency (pmConfig *config, const pmFPAview *view) 157 152 { … … 178 173 bool psphotEfficiencyReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) 179 174 { 180 # if 0181 175 bool status = true; 182 176 … … 206 200 207 201 // Collect recipe information 208 float fwhmMajor = psMetadataLookupF32(NULL, recipe, "FWHM_MAJ"); // PSF size in x 209 float fwhmMinor = psMetadataLookupF32(NULL, recipe, "FWHM_MIN"); // PSF size in y 202 float smoothNsigma = psMetadataLookupF32(&status, recipe, "PEAKS_SMOOTH_NSIGMA"); // Smoothing limit 203 psAssert (status && isfinite(smoothNsigma), "Unable to find PEAKS_SMOOTH_NSIGMA in recipe (or invalid value)"); 204 205 float thresh = psMetadataLookupF32(&status, recipe, "PEAKS_NSIGMA_LIMIT_2"); 206 psAssert (status && isfinite(thresh), "Unable to find PEAKS_NSIGMA_LIMIT_2 in recipe (or invalid value)"); 207 208 psVector *magOffsets = psMetadataLookupVector(&status, recipe, "EFF.MAG"); // Magnitude offsets 209 psAssert (status, "Unable to find EFF.MAG F32 vector in recipe"); 210 psAssert (magOffsets->type.type == PS_TYPE_F32, "Unable to find EFF.MAG F32 vector in recipe"); 211 212 int numSources = psMetadataLookupS32(&status, recipe, "EFF.NUM"); // Number of sources for each bin 213 psAssert (status && (numSources > 0), "Unable to find EFF.NUM in recipe (or invalid value)"); 214 215 float minGauss = psMetadataLookupF32(&status, recipe, "PEAKS_MIN_GAUSS"); // Minimum valid fraction of kernel 216 psAssert (status && isfinite(minGauss), "PEAKS_MIN_GAUSS is not set in recipe (or invalid)"); 217 218 // find the PSF size information (why is this not part of the psf structure?) 219 float fwhmMajor = psMetadataLookupF32(NULL, readout->analysis, "FWHM_MAJ"); // PSF size in x 220 float fwhmMinor = psMetadataLookupF32(NULL, readout->analysis, "FWHM_MIN"); // PSF size in y 210 221 if (!isfinite(fwhmMajor) || !isfinite(fwhmMinor) || fwhmMajor == 0.0 || fwhmMinor == 0.0) { 211 psError(PSPHOT_ERR_CONFIG, false, "Unable to find FWHM_MAJ and FWHM_MIN in recipe"); 212 return false; 213 } 214 float smoothNsigma = psMetadataLookupF32(NULL, recipe, "PEAKS_SMOOTH_NSIGMA"); // Smoothing limit 215 if (!isfinite(smoothNsigma)) { 216 psError(PSPHOT_ERR_CONFIG, false, "Unable to find PEAKS_SMOOTH_NSIGMA in recipe"); 217 return false; 218 } 219 float thresh = psMetadataLookupF32(NULL, recipe, "PEAKS_NSIGMA_LIMIT_2"); 220 if (!isfinite(thresh)) { 221 psError(PSPHOT_ERR_CONFIG, false, "Unable to find PEAKS_NSIGMA_LIMIT_2 in recipe"); 222 return false; 223 } 224 psVector *magOffsets = psMetadataLookupVector(NULL, recipe, "EFF.MAG"); // Magnitude offsets 225 if (!magOffsets || magOffsets->type.type != PS_TYPE_F32) { 226 psError(PSPHOT_ERR_CONFIG, false, "Unable to find EFF.MAG F32 vector in recipe"); 227 return NULL; 228 } 229 int numSources = psMetadataLookupS32(NULL, recipe, "EFF.NUM"); // Number of sources for each bin 230 if (numSources == 0) { 231 psError(PSPHOT_ERR_CONFIG, false, "Unable to find EFF.NUM in recipe"); 232 return NULL; 233 } 234 float minGauss = psMetadataLookupF32(NULL, recipe, "PEAKS_MIN_GAUSS"); // Minimum valid fraction of kernel 235 if (!isfinite(minGauss)) { 236 psWarning("PEAKS_MIN_GAUSS is not set in recipe; using default value"); 237 minGauss = 0.5; 222 psError(PSPHOT_ERR_CONFIG, false, "Unable to find FWHM_MAJ and FWHM_MIN in readout->analysis"); 223 return false; 238 224 } 239 225 … … 246 232 // remove all sources, adding noise for subtracted sources 247 233 psphotRemoveAllSources(realSources, recipe); 248 // psphotAddNoise(readout, realSources, recipe); 249 250 251 #if defined(TESTING) && 0 234 235 #if TESTING 252 236 { 253 237 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); … … 278 262 } 279 263 280 #if defTESTING264 #if TESTING 281 265 psphotSaveImage(NULL, readout->image, "orig_image.fits"); 282 266 psphotSaveImage(NULL, readout->variance, "orig_variance.fits"); … … 293 277 } 294 278 295 #if defTESTING279 #if TESTING 296 280 psphotSaveImage(NULL, readout->image, "fake_image.fits"); 297 281 psphotSaveImage(NULL, readout->variance, "fake_variance.fits"); … … 408 392 psFree(significance); 409 393 410 if (!psphotFitSourcesLinear (readout, fakeSourcesAll, recipe, psf, true)) {394 if (!psphotFitSourcesLinearReadout(recipe, readout, fakeSourcesAll, psf, true)) { 411 395 psError(PS_ERR_UNKNOWN, false, "Unable to perform linear fit on fake sources."); 412 396 psFree(fakeSources); … … 415 399 } 416 400 417 // Disable aperture corrections ; casting away const!401 // Disable aperture corrections (save current value) 418 402 pmTrend2D *apTrend = psf->ApTrend; // Aperture trend 419 ((pmPSF*)psf)->ApTrend = NULL;420 421 if (!psphotMagnitudes (config, readout, view, fakeSourcesAll, psf)) {403 psf->ApTrend = NULL; 404 405 if (!psphotMagnitudesReadout(config, recipe, view, readout, fakeSourcesAll, psf)) { 422 406 psError(PS_ERR_UNKNOWN, false, "Unable to measure magnitudes of fake sources."); 423 407 psFree(fakeSources); 424 408 psFree(count); 425 ((pmPSF*)psf)->ApTrend = apTrend; // Casting away const!409 psf->ApTrend = apTrend; // Casting away const! 426 410 return false; 427 411 } 428 412 psFree(fakeSourcesAll); 429 413 430 // Re -enable aperture corrections; casting away const!431 ((pmPSF*)psf)->ApTrend = apTrend;414 // Replace aperture corrections 415 psf->ApTrend = apTrend; 432 416 433 417 psVector *magDiffMean = psVectorAlloc(numBins, PS_TYPE_F32); // Mean difference in magnitude for each bin … … 443 427 psVectorInit(magMask, 0); 444 428 445 #if defTESTING429 #if TESTING 446 430 psString name = NULL; 447 431 psStringAppend(&name, "fake_%d.dat", i); … … 459 443 } 460 444 461 #if defTESTING445 #if TESTING 462 446 fprintf(file, "%f %f %f %f %f %f %f\n", source->peak->xf, source->peak->yf, 463 447 source->modelPSF->params->data.F32[PM_PAR_XPOS], … … 495 479 } 496 480 497 #if defTESTING481 #if TESTING 498 482 fclose(file); 499 483 #endif … … 520 504 psLogMsg("psphot", PS_LOG_INFO, "Detection efficiency: %lf sec\n", psTimerClear("psphot.fake")); 521 505 522 # endif523 524 506 return true; 525 507 } -
trunk/psphot/src/psphotFitSourcesLinear.c
r26894 r27532 17 17 bool status = true; 18 18 19 // select the appropriate recipe information 20 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE); 21 assert (recipe); 22 19 23 int num = psMetadataLookupS32 (&status, config->arguments, "PSPHOT.INPUT.NUM"); 20 24 psAssert (status, "programming error: must define PSPHOT.INPUT.NUM"); … … 22 26 // loop over the available readouts 23 27 for (int i = 0; i < num; i++) { 24 if (!psphotFitSourcesLinearReadout (config, view, "PSPHOT.INPUT", i, final)) { 28 29 // find the currently selected readout 30 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", i); // File of interest 31 psAssert (file, "missing file?"); 32 33 pmReadout *readout = pmFPAviewThisReadout(view, file->fpa); 34 psAssert (readout, "missing readout?"); 35 36 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 37 psAssert (detections, "missing detections?"); 38 39 psArray *sources = detections->allSources; 40 psAssert (sources, "missing sources?"); 41 42 pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF"); 43 psAssert (psf, "missing psf?"); 44 45 if (!psphotFitSourcesLinearReadout (recipe, readout, sources, psf, final)) { 25 46 psError (PSPHOT_ERR_CONFIG, false, "failed to fit sources (linear) for PSPHOT.INPUT entry %d", i); 26 47 return false; … … 30 51 } 31 52 32 bool psphotFitSourcesLinearReadout (p mConfig *config, const pmFPAview *view, const char *filename, int index, bool final) {53 bool psphotFitSourcesLinearReadout (psMetadata *recipe, pmReadout *readout, psArray *sources, pmPSF *psf, bool final) { 33 54 34 55 bool status; … … 36 57 float y; 37 58 float f; 38 // float r;39 40 // select the appropriate recipe information41 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);42 assert (recipe);43 44 // find the currently selected readout45 pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest46 psAssert (file, "missing file?");47 48 pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);49 psAssert (readout, "missing readout?");50 51 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");52 psAssert (detections, "missing detections?");53 54 psArray *sources = detections->allSources;55 psAssert (sources, "missing sources?");56 59 57 60 if (!sources->n) { … … 59 62 return true; 60 63 } 61 62 pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");63 psAssert (sources, "missing psf?");64 64 65 65 psTimerStart ("psphot.linear"); -
trunk/psphot/src/psphotFitSourcesLinearStack.c
r25755 r27532 9 9 // these are used to determine the simultaneous linear fit of fluxes. 10 10 // the analysis is performed wrt the simulated pixel values 11 12 static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, psImageMaskType markVal);13 11 14 12 bool psphotFitSourcesLinear (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, bool final) { … … 194 192 return true; 195 193 } 196 197 // Calculate the weight terms for the sky fit component of the matrix. This function operates198 // on the pixels which correspond to all of the sources of interest. These elements fill in199 // the border matrix components in the sparse matrix equation.200 static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, psImageMaskType markVal) {201 202 // generate the image-wide weight terms203 // turn on MARK for all image pixels204 psRegion fullArray = psRegionSet (0, 0, 0, 0);205 fullArray = psRegionForImage (readout->mask, fullArray);206 psImageMaskRegion (readout->mask, fullArray, "OR", markVal);207 208 // turn off MARK for all object pixels209 for (int i = 0; i < sources->n; i++) {210 pmSource *source = sources->data[i];211 pmModel *model = pmSourceGetModel (NULL, source);212 if (model == NULL) continue;213 float x = model->params->data.F32[PM_PAR_XPOS];214 float y = model->params->data.F32[PM_PAR_YPOS];215 psImageMaskCircle (source->maskView, x, y, model->radiusFit, "AND", PS_NOT_IMAGE_MASK(markVal));216 }217 218 // accumulate the image statistics from the masked regions219 psF32 **image = readout->image->data.F32;220 psF32 **variance = readout->variance->data.F32;221 psImageMaskType **mask = readout->mask->data.PS_TYPE_IMAGE_MASK_DATA;222 223 double w, x, y, x2, xy, y2, xc, yc, wt, f, fo, fx, fy;224 w = x = y = x2 = xy = y2 = fo = fx = fy = 0;225 226 int col0 = readout->image->col0;227 int row0 = readout->image->row0;228 229 for (int j = 0; j < readout->image->numRows; j++) {230 for (int i = 0; i < readout->image->numCols; i++) {231 if (mask[j][i]) continue;232 if (constant_weights) {233 wt = 1.0;234 } else {235 wt = variance[j][i];236 }237 f = image[j][i];238 w += 1/wt;239 fo += f/wt;240 }241 }242 243 // turn off MARK for all image pixels244 psImageMaskRegion (readout->mask, fullArray, "AND", PS_NOT_IMAGE_MASK(markVal));245 246 // set the Border T elements247 psSparseBorderElementG (border, 0, fo);248 psSparseBorderElementT (border, 0, 0, w);249 250 return true;251 } -
trunk/psphot/src/psphotKernelFromPSF.c
r17396 r27532 4 4 5 5 assert (source); 6 assert (source->psf Flux); // XXX build if needed?6 assert (source->psfImage); // XXX build if needed? 7 7 8 int x0 = source->peak->xf - source->psf Flux->col0;9 int y0 = source->peak->yf - source->psf Flux->row0;8 int x0 = source->peak->xf - source->psfImage->col0; 9 int y0 = source->peak->yf - source->psfImage->row0; 10 10 11 11 // need to decide on the size: dynamically? statically? … … 17 17 // if the realized PSF for this object does not cover the full kernel, give up for now 18 18 if (x0 + psf->xMin < 0) goto escape; 19 if (x0 + psf->xMax >= source->psf Flux->numCols) goto escape;19 if (x0 + psf->xMax >= source->psfImage->numCols) goto escape; 20 20 if (y0 + psf->yMin < 0) goto escape; 21 if (y0 + psf->yMax >= source->psf Flux->numRows) goto escape;21 if (y0 + psf->yMax >= source->psfImage->numRows) goto escape; 22 22 23 23 double sum = 0.0; 24 24 for (int j = psf->yMin; j <= psf->yMax; j++) { 25 25 for (int i = psf->xMin; i <= psf->xMax; i++) { 26 double value = source->psf Flux->data.F32[y0 + j][x0 + i];26 double value = source->psfImage->data.F32[y0 + j][x0 + i]; 27 27 psf->kernel[j][i] = value; 28 28 sum += value; -
trunk/psphot/src/psphotMagnitudes.c
r26894 r27532 14 14 // loop over the available readouts 15 15 for (int i = 0; i < num; i++) { 16 if (!psphotMagnitudesReadout (config, view, "PSPHOT.INPUT", i, recipe)) { 16 17 // find the currently selected readout 18 pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PSPHOT.INPUT", i); // File of interest 19 psAssert (file, "missing file?"); 20 21 pmReadout *readout = pmFPAviewThisReadout(view, file->fpa); 22 psAssert (readout, "missing readout?"); 23 24 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 25 psAssert (detections, "missing detections?"); 26 27 psArray *sources = detections->allSources; 28 psAssert (sources, "missing sources?"); 29 30 pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF"); 31 psAssert (psf, "missing psf?"); 32 33 if (!psphotMagnitudesReadout (config, recipe, view, readout, sources, psf)) { 17 34 psError (PSPHOT_ERR_CONFIG, false, "failed to measure magnitudes for PSPHOT.INPUT entry %d", i); 18 35 return false; … … 22 39 } 23 40 24 bool psphotMagnitudesReadout(pmConfig *config, const pmFPAview *view, const char *filename, int index, psMetadata *recipe) {41 bool psphotMagnitudesReadout(pmConfig *config, psMetadata *recipe, const pmFPAview *view, pmReadout *readout, psArray *sources, pmPSF *psf) { 25 42 26 43 bool status = false; 27 44 int Nap = 0; 28 45 46 if (!sources->n) { 47 psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source magnitudes"); 48 return true; 49 } 50 29 51 psTimerStart ("psphot.mags"); 30 31 // find the currently selected readout32 pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest33 psAssert (file, "missing file?");34 35 pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);36 psAssert (readout, "missing readout?");37 38 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");39 psAssert (detections, "missing detections?");40 41 psArray *sources = detections->allSources;42 psAssert (sources, "missing sources?");43 44 if (!sources->n) {45 psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");46 return true;47 }48 49 pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");50 psAssert (psf, "missing psf?");51 52 52 53 // determine the number of allowed threads … … 79 80 } 80 81 81 bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");82 bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH"); 82 83 bool INTERPOLATE_AP = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP"); 84 bool DIFF_STATS = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP"); 83 85 84 86 pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_APCORR | PM_SOURCE_PHOT_WEIGHT; 85 87 if (!IGNORE_GROWTH) photMode |= PM_SOURCE_PHOT_GROWTH; 86 88 if (INTERPOLATE_AP) photMode |= PM_SOURCE_PHOT_INTERP; 89 if (DIFF_STATS) photMode |= PM_SOURCE_PHOT_DIFFSTATS; 87 90 88 91 // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts) -
trunk/psphot/src/psphotMakeResiduals.c
r25755 r27532 305 305 if (fabs(resid->Ro->data.F32[oy][ox]) < pixelSN*dRo/sqrt(nKeep)) { 306 306 resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1; 307 resid->Ro->data.F32[oy][ox] = 0.0; 308 resid->Rx->data.F32[oy][ox] = 0.0; 309 resid->Ry->data.F32[oy][ox] = 0.0; 307 310 } 308 311 } -
trunk/psphot/src/psphotReadout.c
r26894 r27532 91 91 return psphotReadoutCleanup (config, view); 92 92 } 93 if (!strcasecmp (breakPt, "MOMENTS")) {94 return psphotReadoutCleanup(config, view);95 }96 97 93 // if we were not supplied a PSF model, determine the IQ stats here (detections->newSources) 98 94 if (!psphotImageQuality (config, view)) { // pass 1 99 95 psError (PSPHOT_ERR_UNKNOWN, false, "failed to measure image quality"); 96 return psphotReadoutCleanup(config, view); 97 } 98 if (!strcasecmp (breakPt, "MOMENTS")) { 100 99 return psphotReadoutCleanup(config, view); 101 100 } -
trunk/psphot/src/psphotSourceSize.c
r26894 r27532 13 13 float soft; 14 14 int grow; 15 int xtest, ytest; 16 bool apply; // apply CR mask? 15 17 } psphotSourceSizeOptions; 16 18 … … 22 24 bool psphotMaskCosmicRay (pmReadout *readout, pmSource *source, psImageMaskType maskVal); 23 25 bool psphotMaskCosmicRayFootprintCheck (psArray *sources); 26 int psphotMaskCosmicRayConnected (int xPeak, int yPeak, psImage *mymask, psImage *myvar, psImage *edges, int binning, float sigma_thresh); 24 27 25 28 // we need to call this function after sources have been fitted to the PSF model and … … 101 104 assert (status); 102 105 106 // XXX recipe name is not great 107 options.xtest = psMetadataLookupS32 (&status, recipe, "PSPHOT.CRMASK.XTEST"); 108 options.ytest = psMetadataLookupS32 (&status, recipe, "PSPHOT.CRMASK.YTEST"); 109 assert (status); 110 103 111 options.grow = psMetadataLookupS32(&status, recipe, "PSPHOT.CR.GROW"); // Growth size for CRs 104 112 if (!status || options.grow < 0) { … … 111 119 psWarning("PSPHOT.CR.NSIGMA.SOFTEN not set; defaulting to zero."); 112 120 options.soft = 0.0; 121 } 122 123 options.apply = psMetadataLookupBool(&status, recipe, "PSPHOT.CRMASK.APPLY"); // Growth size for CRs 124 if (!status) { 125 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSPHOT.CRMASK.APPLY is not defined."); 126 return false; 113 127 } 114 128 … … 239 253 continue; 240 254 } 255 // psphotVisualPlotSourceSize (recipe, readout->analysis, sources); 241 256 } 242 257 … … 244 259 } 245 260 261 # define SIZE_SN_LIM 10 246 262 bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) { 247 263 … … 285 301 } 286 302 287 // we are basically classifying by moments ; use the default if not found303 // we are basically classifying by moments 288 304 psAssert (source->moments, "why is this source missing moments?"); 289 305 if (source->mode & noMoments) { … … 292 308 } 293 309 310 // convert to Mmaj, Mmin: 294 311 psF32 Mxx = source->moments->Mxx; 295 312 psF32 Myy = source->moments->Myy; … … 315 332 float apMag = -2.5*log10(source->moments->Sum); 316 333 float dMag = source->psfMag - apMag; 317 float nSigma = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr); 318 319 source->extNsigma = nSigma; 320 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 334 335 // set nSigma to include both systematic and poisson error terms 336 // XXX the 'poisson error' contribution for size is probably wrong... 337 float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr); 338 float nSigmaMXX = (Mxx - psfClump->X) / hypot(psfClump->dX, psfClump->X*psfClump->X*source->errMag); 339 float nSigmaMYY = (Myy - psfClump->Y) / hypot(psfClump->dY, psfClump->Y*psfClump->Y*source->errMag); 340 341 // partially-masked sources are more likely to be mis-measured PSFs 342 float sizeBias = 1.0; 343 if (source->pixWeight < 0.9) { 344 sizeBias = 3.0; 345 } 346 347 float minMxx = psfClump->X - sizeBias*options->nSigmaMoments*psfClump->dX; 348 float minMyy = psfClump->Y - sizeBias*options->nSigmaMoments*psfClump->dY; 349 350 // include MAG, MXX, and MYY? 351 source->extNsigma = nSigmaMAG; 352 353 // notes to clarify the source size classification rules: 354 // * a defect should be functionally equivalent to a cosmic ray 355 // * CR & defect should have a faintess limit (min S/N) 356 // * SAT stars should not be faint, but defects may? 321 357 322 358 // Anything within this region is a probably PSF-like object. Saturated stars may land 323 359 // in this region, but are detected elsewhere on the basis of their peak value. 324 bool isPSF = ((fabs(nSigma) < options->nSigmaApResid) && 325 (fabs(Mxx - psfClump->X) < options->nSigmaMoments*psfClump->dX) && 326 (fabs(Myy - psfClump->Y) < options->nSigmaMoments*psfClump->dY)); 360 bool isPSF = (fabs(nSigmaMAG) < options->nSigmaApResid) && (fabs(nSigmaMXX) < sizeBias*options->nSigmaMoments) && (fabs(nSigmaMYY) < sizeBias*options->nSigmaMoments); 327 361 if (isPSF) { 328 psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g PSF\t%g %g\n", 329 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma, 330 options->nSigmaApResid,options->nSigmaMoments); 362 psTrace("psphotSourceClassRegion.PSF",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g PSF\t%g %g\n", 363 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 364 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 365 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 331 366 Npsf ++; 332 367 continue; … … 336 371 // Defects may also be marked as SATSTAR -- XXX deactivate this flag? 337 372 // XXX this rule is not great 338 if ((Mxx < psfClump->X) || (Myy < psfClump->Y)) { 339 340 psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g CR\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); 373 // XXX only accept brightish detections as CRs 374 // (nSigmaMAG < -options->nSigmaApResid) || 375 bool isCR = isCR = (source->errMag < 1.0 / SIZE_SN_LIM) && ((Mxx < minMxx) || (Myy < minMyy)); 376 if (isCR) { 377 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", 378 source->peak->xf,source->peak->yf,source->pixWeight,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 379 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 343 380 source->mode |= PM_SOURCE_MODE_DEFECT; 381 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_CR_CANDIDATE; 344 382 Ncr ++; 345 383 continue; … … 349 387 // just large saturated regions. 350 388 if (source->mode & PM_SOURCE_MODE_SATSTAR) { 351 psTrace("psphot.czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g SAT\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 389 psTrace("psphotSourceClassRegion.SAT",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g SAT\t%g %g\n", 390 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 391 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 392 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 355 393 Nsat ++; 356 394 continue; … … 358 396 359 397 // XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)? 360 bool isEXT = (nSigma > options->nSigmaApResid) || ((Mxx > psfClump->X) && (Myy > psfClump->Y));398 bool isEXT = (nSigmaMAG > options->nSigmaApResid) || (Mxx > minMxx) || (Myy > minMyy); 361 399 if (isEXT) { 362 psTrace("psphot .czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g Ext\t%g %g\n",363 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma ,364 options->nSigmaApResid, options->nSigmaMoments);400 psTrace("psphotSourceClassRegion.EXT",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g Ext\t%g %g\n", 401 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 402 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 365 403 366 404 source->mode |= PM_SOURCE_MODE_EXT_LIMIT; 405 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 367 406 Next ++; 368 407 continue; 369 408 } 370 psTrace("psphot .czw",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g Unk\t%g %g\n",371 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigma ,372 options->nSigmaApResid, options->nSigmaMoments);409 psTrace("psphotSourceClassRegion.MISS",4,"CLASS: %g %g\t%g %g %g %g %g %g\t%g %g\t%g Unk\t%g %g\n", 410 source->peak->xf,source->peak->yf,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG, 411 options->nSigmaApResid,sizeBias*options->nSigmaMoments); 373 412 374 psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigma); 413 // sources that reach here are probably too faint for a reasonable source size measurement 414 // psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigmaMAG); 415 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 375 416 Nmiss ++; 376 417 } … … 385 426 bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) { 386 427 428 psTimerStart ("psphot.cr"); 429 430 int nMasked = 0; 387 431 for (int i = 0; i < sources->n; i++) { 388 432 pmSource *source = sources->data[i]; … … 393 437 continue; 394 438 } 439 440 // only check candidates marked above 441 if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_CR_CANDIDATE)) { 442 psTrace("psphot", 7, "Not calculating source size since it has already been measured\n"); 443 continue; 444 } 445 446 // skip unless this source is thought to be a cosmic ray. flag the detection and mask the pixels 447 // XXX this may be degenerate with the above test 448 if (!(source->mode & PM_SOURCE_MODE_DEFECT)) continue; 395 449 396 450 // Integer position of peak … … 402 456 yPeak < 1 || yPeak > source->pixels->numRows - 2) { 403 457 psTrace("psphot", 7, "Not calculating crNsigma due to edge\n"); 404 // psTrace("psphot.czw", 2, "Not calculating crNsigma due to edge\n");405 458 continue; 406 459 } 407 460 408 // this source is thought to be a cosmic ray. flag the detection and mask the pixels 409 if (source->mode & PM_SOURCE_MODE_DEFECT) { 410 // XXX this is running slowly and is too agressive, but it more-or-less works 411 // psphotMaskCosmicRayCZW(readout, source, options->crMask); 412 413 // XXX these are the old versions which we are not using 414 // psphotMaskCosmicRay (readout->mask, source, maskVal, crMask); 415 // psphotMaskCosmicRay_Old (source, maskVal, crMask); 416 } 461 // XXX for testing, only CRMASK a single source: 462 if (options->xtest && (fabs(source->peak->xf - options->xtest) > 5)) continue; 463 if (options->ytest && (fabs(source->peak->yf - options->ytest) > 5)) continue; 464 465 // replace object in image 466 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) { 467 pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal); 468 } 469 470 // XXX this is running slowly and is too agressive, but it more-or-less works 471 psTrace("psphot", 6, "mask cosmic ray at %f, %f\n", source->peak->xf, source->peak->yf); 472 if (options->apply) { 473 psphotMaskCosmicRay(readout, source, options->crMask); 474 } else { 475 source->mode |= PM_SOURCE_MODE_CR_LIMIT; 476 } 477 nMasked ++; 478 479 // re-subtract the object, leave local sky 480 pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal); 417 481 } 418 482 … … 430 494 } 431 495 496 psLogMsg ("psphot.cr", PS_LOG_INFO, "mask CR: %d masked in %f sec\n", nMasked, psTimerMark ("psphot.cr")); 497 432 498 // XXX test : save the mask image 433 499 if (0) { 434 500 psphotSaveImage (NULL, readout->mask, "mask.fits"); 435 501 } 502 436 503 return true; 437 504 } 505 506 # define DUMPPICS 0 507 # define LIMIT_XRANGE(X, IMAGE) { X = PS_MIN(PS_MAX(0, X), IMAGE->numCols); } 508 # define LIMIT_YRANGE(Y, IMAGE) { Y = PS_MIN(PS_MAX(0, Y), IMAGE->numRows); } 438 509 439 510 // Comments by CZW 20091209 : Mechanics of how to identify CR pixels taken from "Cosmic-Ray … … 448 519 pmFootprint *footprint = peak->footprint; 449 520 450 int xm = footprint->bbox.x0;451 int xM = footprint->bbox.x1;452 int ym = footprint->bbox.y0;453 int yM = footprint->bbox.y1;454 455 if (xm < 0) { xm = 0; }456 if (ym < 0) { ym = 0; }457 if (xM > mask->numCols) { xM = mask->numCols; }458 if (yM > mask->numRows) { yM = mask->numRows; }459 int dx = xM - xm;460 int dy = yM - ym;461 462 521 // Bounding boxes are inclusive of final pixel 463 // XXX ensure dx,dy do not become too large here 464 dx++; 465 dy++; 522 int xs = footprint->bbox.x0; 523 int xe = footprint->bbox.x1 + 1; 524 int ys = footprint->bbox.y0; 525 int ye = footprint->bbox.y1 + 1; 526 527 LIMIT_XRANGE(xs, mask); 528 LIMIT_XRANGE(xe, mask); 529 LIMIT_YRANGE(ys, mask); 530 LIMIT_YRANGE(ye, mask); 531 532 int dx = xe - xs; 533 int dy = ye - ys; 466 534 467 535 psImage *image= readout->image; 468 536 psImage *variance = readout->variance; 469 537 470 int binning = 1; 471 float sigma_thresh = 2.0; 472 int iteration = 0; 473 int max_iter = 5; 474 float noise_factor = 5.0 / 4.0; // Intrinsic to the Laplacian making noise spikes spikier. 538 int binning = 2; 539 float sigma_thresh = 3.0; 540 int max_iter = 1; // XXX with isophot masking, we only want to do a single pass 475 541 476 542 // Temporary images. 477 543 psImage *mypix = psImageAlloc(dx,dy,image->type.type); 544 psImage *myfix = psImageAlloc(dx,dy,image->type.type); 478 545 psImage *myvar = psImageAlloc(dx,dy,image->type.type); 479 546 psImage *binned = psImageAlloc(dx * binning,dy * binning,image->type.type); … … 482 549 psImage *mymask = psImageAlloc(dx,dy,PS_TYPE_IMAGE_MASK); 483 550 484 int x,y;485 551 // Load my copy of things. 486 for ( x = 0; x < dx; x++) {487 for ( y = 0; y < dy; y++) {488 psImageSet(mypix,x,y,psImageGet(image,x+xm,y+ym));489 psImageSet(myvar,x,y,psImageGet(variance,x+xm,y+ym));552 for (int y = 0; y < dy; y++) { 553 for (int x = 0; x < dx; x++) { 554 mypix->data.F32[y][x] = image->data.F32[y+ys][x+xs]; 555 myvar->data.F32[y][x] = variance->data.F32[y+ys][x+xs]; 490 556 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0x00; 491 557 } … … 495 561 pmSpan *sp = footprint->spans->data[i]; 496 562 for (int j = sp->x0; j <= sp->x1; j++) { 497 y = sp->y - ym;498 x = j - xm;563 int y = sp->y - ys; 564 int x = j - xs; 499 565 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= 0x01; 500 566 } 501 567 } 502 568 503 int CRpix_count = 0; 504 do { 505 CRpix_count = 0; 506 // Zero out my temp images. 507 for (x = 0; x < binning * dx; x++) { 508 for (y = 0; y < binning * dy; y++) { 509 psImageSet(binned,x,y,0.0); 510 psImageSet(conved,x,y,0.0); 511 psImageSet(edges,x/binning,y/ binning,0.0); 569 int nCRpix = 1; // force at least one pass... 570 for (int iteration = 0; (iteration < max_iter) && (nCRpix > 0); iteration++) { 571 nCRpix = 0; 572 psImageInit (binned, 0.0); 573 psImageInit (conved, 0.0); 574 psImageInit (edges, 0.0); 575 576 // Make subsampled image. Maybe this should be called "unbinned" or something 577 for (int y = 0; y < binning * dy; y++) { 578 int yraw = y / binning; 579 for (int x = 0; x < binning * dx; x++) { 580 int xraw = x / binning; 581 binned->data.F32[y][x] = mypix->data.F32[yraw][xraw]; 512 582 } 513 } 514 // Make subsampled image. Maybe this should be called "unbinned" or something 515 for (x = 0; x < binning * dx; x++) { 516 for (y = 0; y < binning * dy; y++) { 517 psImageSet(binned,x,y,psImageGet(mypix,x / binning,y / binning)); 583 } 584 585 // Apply Laplace transform (kernel = [[0 -0.25 0][-0.25 1 -0.25][0 -0.25 0]]), clipping at zero 586 for (int y = 1; y < binning * dy - 1; y++) { 587 for (int x = 1; x < binning * dx - 1; x++) { 588 float value = binned->data.F32[y][x] - 0.25 * 589 (binned->data.F32[y+0][x-1] + binned->data.F32[y+0][x+1] + 590 binned->data.F32[y-1][x+0] + binned->data.F32[y+1][x+0]); 591 value = PS_MAX(0.0, value); 592 593 conved->data.F32[y][x] = value; 518 594 } 519 595 } 520 // Apply Laplace transform (kernel = [[0 -0.25 0][-0.25 1 -0.25][0 -0.25 0]]), clipping at zero 521 for (x = 1; x < dx - 1; x++) { 522 for (y = 1; y < dy - 1; y++) { 523 psImageSet(conved,x,y,psImageGet(binned,x,y) - 0.25 * 524 (psImageGet(binned,x-1,y) + psImageGet(binned,x+1,y) + 525 psImageGet(binned,x,y-1) + psImageGet(binned,x,y+1))); 526 if (psImageGet(conved,x,y) < 0.0) { 527 psImageSet(conved,x,y,0.0); 528 } 596 597 // Create an edge map by rebinning 598 for (int y = 0; y < binning * dy; y++) { 599 int yraw = y / binning; 600 for (int x = 0; x < binning * dx; x++) { 601 int xraw = x / binning; 602 edges->data.F32[yraw][xraw] += conved->data.F32[y][x]; 529 603 } 530 604 } 531 // Create an edge map by rebinning 532 for (x = 0; x < binning * dx; x++) { 533 for (y = 0; y < binning * dy; y++) { 534 psImageSet(edges,x / binning, y / binning, 535 psImageGet(edges, x / binning, y / binning) + 536 psImageGet(conved,x,y)); 537 } 538 } 539 // Modify my mask if we're above the significance threshold 540 for (x = 0; x < dx; x++) { 541 for (y = 0; y < dy; y++) { 542 if ( psImageGet(edges,x,y) / (binning * sqrt(noise_factor * psImageGet(myvar,x,y))) > sigma_thresh ) { 543 if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x01) { 544 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= 0x40; 545 CRpix_count++; 546 } 547 } 548 } 549 } 550 605 606 // coordinate of peak in subimage pixels: 607 int xPeak = peak->x - xs; 608 int yPeak = peak->y - ys; 609 610 // Modify my mask if we're above the significance threshold, but only for connected pixels 611 nCRpix = psphotMaskCosmicRayConnected (xPeak, yPeak, mymask, myvar, edges, binning, sigma_thresh); 612 613 # if DUMPPICS 614 psphotSaveImage (NULL, mypix, "crmask.pix.fits"); 615 # endif 616 617 // XXX do not repair the pixels in isophot version 618 # if 0 551 619 // "Repair" Masked pixels for the next round. 552 for (x = 1; x < dx - 1; x++) { 553 for (y = 1; y < dy - 1; y++) { 554 if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) { 555 psImageSet(mypix,x,y,0.25 * 556 (psImageGet(mypix,x-1,y) + psImageGet(mypix,x+1,y) + 557 psImageGet(mypix,x,y-1) + psImageGet(mypix,x,y+1))); 558 } 559 } 560 } 561 562 # if 0 563 if ((psTraceGetLevel("psphot.czw") >= 2)&&(abs(xm - 2770) < 5)&&(abs(ym - 2581) < 5)&&(iteration == 0)) { 564 psTrace("psphot.czw",2,"TRACEMOTRON %d %d %d %d %d\n",xm,ym,dx,dy,iteration); 565 psphotSaveImage (NULL, mypix, "czw.pix.fits"); 566 psphotSaveImage (NULL, myvar, "czw.var.fits"); 567 psphotSaveImage (NULL, binned, "czw.binn.fits"); 568 psphotSaveImage (NULL, conved, "czw.conv.fits"); 569 psphotSaveImage (NULL, edges, "czw.edge.fits"); 570 psphotSaveImage (NULL, mymask, "czw.mask.fits"); 571 } 572 # endif 573 574 psTrace("psphot.czw",2,"Iter: %d Count: %d",iteration,CRpix_count); 575 iteration++; 576 } while ((iteration < max_iter)&&(CRpix_count > 0)); 577 578 // A solitary masked pixel is likely a lie. Remove those. 579 for (x = 0; x < dx; x++) { 580 for (y = 0; y < dy; y++) { 581 if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) { 582 if ((x-1 >= 0)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x-1] & 0x40)) { 620 for (int y = 1; y < dy - 1; y++) { 621 for (int x = 1; x < dx - 1; x++) { 622 if (!(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40)) { 623 myfix->data.F32[y][x] = mypix->data.F32[y][x]; 583 624 continue; 584 625 } 585 if ((y-1 >= 0)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y-1][x] & 0x40)) { 586 continue; 587 } 588 if ((x+1 < dx)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x+1] & 0x40)) { 589 continue; 590 } 591 if ((y+1 < dy)&&(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y+1][x] & 0x40)) { 592 continue; 593 } 594 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] ^= 0x40; 626 myfix->data.F32[y][x] = 0.25 * 627 (mypix->data.F32[y+0][x-1] + mypix->data.F32[y+0][x+1] + 628 mypix->data.F32[y-1][x+0] + mypix->data.F32[y+1][x+0]); 595 629 } 596 630 } 597 } 598 599 // transfer temporary mask to real mask 600 for (x = 0; x < dx; x++) { 601 for (y = 0; y < dy; y++) { 631 632 // "Repair" Masked pixels for the next round. 633 for (int y = 1; y < dy - 1; y++) { 634 for (int x = 1; x < dx - 1; x++) { 635 mypix->data.F32[y][x] = myfix->data.F32[y][x]; 636 } 637 } 638 # endif 639 640 # if DUMPPICS 641 fprintf (stderr, "CRMASK %d %d %d %d %d\n", xs, ys, dx, dy, iteration); 642 psphotSaveImage (NULL, mypix, "crmask.fix.fits"); 643 psphotSaveImage (NULL, myvar, "crmask.var.fits"); 644 psphotSaveImage (NULL, binned, "crmask.binn.fits"); 645 psphotSaveImage (NULL, conved, "crmask.conv.fits"); 646 psphotSaveImage (NULL, edges, "crmask.edge.fits"); 647 psphotSaveImage (NULL, mymask, "crmask.mask.fits"); 648 # endif 649 psTrace("psphot.czw",2,"Iter: %d Count: %d",iteration, nCRpix); 650 } 651 652 # if 0 653 // A solitary masked pixel is likely a lie. Remove those 654 // XXX can't we use nCRpix == 1 to test for these? 655 for (int x = 0; x < dx; x++) { 656 for (int y = 0; y < dy; y++) { 657 if (!(mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40)) continue; 658 if ((x-1 >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x-1] & 0x40)) { 659 continue; 660 } 661 if ((y-1 >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y-1][x] & 0x40)) { 662 continue; 663 } 664 if ((x+1 < dx) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x+1] & 0x40)) { 665 continue; 666 } 667 if ((y+1 < dy) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y+1][x] & 0x40)) { 668 continue; 669 } 670 mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] ^= 0x40; 671 } 672 } 673 # endif 674 675 // transfer temporary mask to real mask & count masked pixels 676 nCRpix = 0; 677 for (int x = 0; x < dx; x++) { 678 for (int y = 0; y < dy; y++) { 602 679 if (mymask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & 0x40) { 603 mask->data.PS_TYPE_IMAGE_MASK_DATA[y+ym+mask->row0][x+xm+mask->col0] |= maskVal; 680 mask->data.PS_TYPE_IMAGE_MASK_DATA[y+ys+mask->row0][x+xs+mask->col0] |= maskVal; 681 nCRpix ++; 604 682 } 605 683 } … … 607 685 608 686 // XXX if we decide this REALLY is a cosmic ray, set the CR_LIMIT bit 609 source->mode |= PM_SOURCE_MODE_CR_LIMIT; 687 if (nCRpix > 1) { 688 source->mode |= PM_SOURCE_MODE_CR_LIMIT; 689 source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED; 690 } 691 // fprintf (stderr, "CRMASK %d %d %d %d %d\n", peak->x, peak->y, dx, dy, nCRpix); 610 692 611 693 psFree(mypix); 694 psFree(myfix); 612 695 psFree(myvar); 613 696 psFree(binned); … … 680 763 } 681 764 return true; 765 } 766 767 # define VERBOSE 0 768 int psphotMaskCosmicRayConnected (int xPeak, int yPeak, psImage *mymask, psImage *myvar, psImage *edges, int binning, float sigma_thresh) { 769 770 int xLo, xRo; 771 int nCRpix = 0; 772 773 float noise_factor = 5.0 / 4.0; // Intrinsic to the Laplacian making noise spikes spikier. 774 775 // mark the pixels in this row to the left, then the right. stay within footprint 776 int xL = xPeak; // find the range of valid pixels in this row 777 int xR = xPeak; 778 for (int ix = xPeak; (ix >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[yPeak][ix] & 0x01); ix--) { 779 float noise = binning * sqrt(noise_factor * myvar->data.F32[yPeak][ix]); 780 float value = edges->data.F32[yPeak][ix] / noise; 781 if (value < sigma_thresh ) break; 782 mymask->data.PS_TYPE_IMAGE_MASK_DATA[yPeak][ix] |= 0x40; 783 xL = ix; 784 nCRpix ++; 785 if (VERBOSE) fprintf (stderr, "mark %d,%d (%d) : %d - %d\n", ix, yPeak, nCRpix, xL, xR); 786 } 787 for (int ix = xPeak; (ix < mymask->numCols) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[yPeak][ix] & 0x01); ix++) { 788 float noise = binning * sqrt(noise_factor * myvar->data.F32[yPeak][ix]); 789 float value = edges->data.F32[yPeak][ix] / noise; 790 if (value < sigma_thresh ) break; 791 mymask->data.PS_TYPE_IMAGE_MASK_DATA[yPeak][ix] |= 0x40; 792 xR = ix; 793 nCRpix ++; 794 if (VERBOSE) fprintf (stderr, "mark %d,%d (%d) : %d - %d\n", ix, yPeak, nCRpix, xL, xR); 795 } 796 // xL and xR mark the first and last valid pixel in the row 797 798 // for each of the neighboring rows, mark the high pixels if they touch the range xL to xR 799 xLo = PS_MAX(xL - 1, 0); 800 xRo = PS_MIN(xR + 1, mymask->numCols); 801 802 // first go down: 803 for (int iy = yPeak - 1; iy >= 0; iy--) { 804 805 int xLn = -1; 806 int xRn = -1; 807 int newPix = 0; 808 809 // mark the pixels in the good range 810 for (int ix = xLo; ix < xRo; ix++) { 811 if (!(mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01)) continue; // only use pixels in the footprint 812 float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]); 813 float value = edges->data.F32[iy][ix] / noise; 814 if (value < sigma_thresh ) continue; 815 mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40; 816 if (xLn == -1) xLn = ix; // first valid pixel in this row 817 xRn = ix; // last valid pixel in this row 818 nCRpix ++; 819 newPix ++; 820 if (VERBOSE) fprintf (stderr, "mark C %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn); 821 } 822 823 // mark the pixels to the left of the good range 824 for (int ix = xLo; (ix >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01); ix--) { 825 float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]); 826 float value = edges->data.F32[iy][ix] / noise; 827 if (value < sigma_thresh ) break; 828 mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40; 829 if (xRn == -1) xRn = ix; // last valid pixel in this row 830 xLn = ix; 831 nCRpix ++; 832 newPix ++; 833 if (VERBOSE) fprintf (stderr, "mark L %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn); 834 } 835 836 // mark the pixels to the right of the good range 837 for (int ix = xRo; (ix < mymask->numCols) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01); ix++) { 838 float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]); 839 float value = edges->data.F32[iy][ix] / noise; 840 if (value < sigma_thresh ) break; 841 mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40; 842 if (xLn == -1) xLn = ix; // first valid pixel in this row 843 xRn = ix; 844 nCRpix ++; 845 newPix ++; 846 if (VERBOSE) fprintf (stderr, "mark R %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn); 847 } 848 if (newPix == 0) break; 849 xLo = PS_MAX(xLn - 1, 0); 850 xRo = PS_MIN(xRn + 1, mymask->numCols); 851 } 852 853 xLo = PS_MAX(xL - 1, 0); 854 xRo = PS_MIN(xR + 1, mymask->numCols); 855 856 // next go up: 857 for (int iy = yPeak + 1; iy < mymask->numRows; iy++) { 858 859 int xLn = -1; 860 int xRn = -1; 861 int newPix = 0; 862 863 // mark the pixels in the good range 864 for (int ix = xLo; ix < xRo; ix++) { 865 if (!(mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01)) continue; // only use pixels in the footprint 866 float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]); 867 float value = edges->data.F32[iy][ix] / noise; 868 if (value < sigma_thresh ) continue; 869 mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40; 870 if (xLn == -1) xLn = ix; // first valid pixel in this row 871 xRn = ix; // last valid pixel in this row 872 nCRpix ++; 873 newPix ++; 874 if (VERBOSE) fprintf (stderr, "mark C %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn); 875 } 876 877 // mark the pixels to the left of the good range 878 for (int ix = xLo; (ix >= 0) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01); ix--) { 879 float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]); 880 float value = edges->data.F32[iy][ix] / noise; 881 if (value < sigma_thresh ) break; 882 mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40; 883 if (xRn == -1) xRn = ix; // last valid pixel in this row 884 xLn = ix; 885 nCRpix ++; 886 newPix ++; 887 if (VERBOSE) fprintf (stderr, "mark L %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn); 888 } 889 890 // mark the pixels to the right of the good range 891 for (int ix = xRo; (ix < mymask->numCols) && (mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & 0x01); ix++) { 892 float noise = binning * sqrt(noise_factor * myvar->data.F32[iy][ix]); 893 float value = edges->data.F32[iy][ix] / noise; 894 if (value < sigma_thresh ) break; 895 mymask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= 0x40; 896 if (xLn == -1) xLn = ix; // first valid pixel in this row 897 xRn = ix; 898 nCRpix ++; 899 newPix ++; 900 if (VERBOSE) fprintf (stderr, "mark R %d,%d (%d) : %d - %d | %d - %d | %d - %d \n", ix, iy, nCRpix, xL, xR, xLo, xRo, xLn, xRn); 901 } 902 if (newPix == 0) break; 903 xLo = PS_MAX(xLn - 1, 0); 904 xRo = PS_MIN(xRn + 1, mymask->numCols); 905 } 906 907 return nCRpix; 682 908 } 683 909 -
trunk/psphot/src/psphotVisual.c
r26894 r27532 1099 1099 psFree (outsat); 1100 1100 return true; 1101 } 1102 1103 static void plotline (int myKapa, Graphdata *graphdata, float x0, float y0, float x1, float y1) 1104 { 1105 float x[2], y[2]; 1106 x[0] = x0; 1107 x[1] = x1; 1108 y[0] = y0; 1109 y[1] = y1; 1110 KapaPrepPlot (myKapa, 2, graphdata); 1111 KapaPlotVector (myKapa, 2, x, "x"); 1112 KapaPlotVector (myKapa, 2, y, "y"); 1101 1113 } 1102 1114 … … 1138 1150 } 1139 1151 1152 // generate model profiles (major and minor axis): 1153 // create a model with theta = 0.0 so major and minor axes are equiv to x and y: 1154 psEllipseShape rawShape, rotShape; 1155 1156 rawShape.sx = source->modelPSF->params->data.F32[PM_PAR_SXX] / M_SQRT2; 1157 rawShape.sy = source->modelPSF->params->data.F32[PM_PAR_SYY] / M_SQRT2; 1158 rawShape.sxy = source->modelPSF->params->data.F32[PM_PAR_SXY]; 1159 1160 psEllipseAxes axes = psEllipseShapeToAxes (rawShape, 20.0); 1161 1162 axes.theta = 0.0; 1163 1164 rotShape = psEllipseAxesToShape (axes); 1165 1166 psVector *params = psVectorAlloc(source->modelPSF->params->n, PS_TYPE_F32); 1167 for (int i = 0; i < source->modelPSF->params->n; i++) { 1168 params->data.F32[i] = source->modelPSF->params->data.F32[i]; 1169 } 1170 params->data.F32[PM_PAR_SXX] = rotShape.sx * M_SQRT2; 1171 params->data.F32[PM_PAR_SYY] = rotShape.sy * M_SQRT2; 1172 params->data.F32[PM_PAR_SXY] = rotShape.sxy; 1173 params->data.F32[PM_PAR_XPOS] = 0.0; 1174 params->data.F32[PM_PAR_YPOS] = 0.0; 1175 1176 psVector *rmod = psVectorAlloc(300, PS_TYPE_F32); 1177 psVector *fmaj = psVectorAlloc(300, PS_TYPE_F32); 1178 psVector *fmin = psVectorAlloc(300, PS_TYPE_F32); 1179 1180 psVector *coord = psVectorAlloc(2, PS_TYPE_F32); 1181 1182 float r = 0.0; 1183 for (int i = 0; i < rmod->n; i++) { 1184 r = i*0.1; 1185 rmod->data.F32[i] = r; 1186 1187 coord->data.F32[1] = r; 1188 coord->data.F32[0] = 0.0; 1189 fmaj->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord)); 1190 1191 coord->data.F32[0] = r; 1192 coord->data.F32[1] = 0.0; 1193 fmin->data.F32[i] = log10(source->modelPSF->modelFunc (NULL, params, coord)); 1194 } 1195 psFree (coord); 1196 psFree (params); 1197 1198 float FWHM_MAJOR = 2.0*source->modelPSF->modelRadius (source->modelPSF->params, 0.5*source->modelPSF->params->data.F32[PM_PAR_I0]); 1199 float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major); 1200 if (FWHM_MAJOR < FWHM_MINOR) PS_SWAP (FWHM_MAJOR, FWHM_MINOR); 1201 1202 psEllipseMoments emoments; 1203 emoments.x2 = source->moments->Mxx; 1204 emoments.xy = source->moments->Mxy; 1205 emoments.y2 = source->moments->Myy; 1206 axes = psEllipseMomentsToAxes (emoments, 20.0); 1207 float MOMENTS_MAJOR = 2.355*axes.major; 1208 float MOMENTS_MINOR = 2.355*axes.minor; 1209 1210 float logHM = log10(0.5*source->modelPSF->params->data.F32[PM_PAR_I0]); 1211 1140 1212 // reset source Add/Sub state to recorded 1141 1213 if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal); … … 1174 1246 KapaPlotVector (myKapa, nb, fb->data.F32, "y"); 1175 1247 1248 graphdata.color = KapaColorByName ("blue"); 1249 graphdata.ptype = 0; 1250 graphdata.size = 0.0; 1251 graphdata.style = 0; 1252 KapaPrepPlot (myKapa, rmod->n, &graphdata); 1253 KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x"); 1254 KapaPlotVector (myKapa, rmod->n, fmin->data.F32, "y"); 1255 plotline (myKapa, &graphdata, 0.0, logHM, 30.0, logHM); 1256 plotline (myKapa, &graphdata, 0.5*FWHM_MINOR, 0.0, 0.5*FWHM_MINOR, 5.0); 1257 graphdata.ltype = 1; 1258 plotline (myKapa, &graphdata, 0.5*MOMENTS_MINOR, 0.0, 0.5*MOMENTS_MINOR, 5.0); 1259 graphdata.ltype = 0; 1260 1261 graphdata.color = KapaColorByName ("green"); 1262 graphdata.ptype = 0; 1263 graphdata.size = 0.0; 1264 graphdata.style = 0; 1265 KapaPrepPlot (myKapa, rmod->n, &graphdata); 1266 KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x"); 1267 KapaPlotVector (myKapa, rmod->n, fmaj->data.F32, "y"); 1268 plotline (myKapa, &graphdata, 0.5*FWHM_MAJOR, 0.0, 0.5*FWHM_MAJOR, 5.0); 1269 graphdata.ltype = 1; 1270 plotline (myKapa, &graphdata, 0.5*MOMENTS_MAJOR, 0.0, 0.5*MOMENTS_MAJOR, 5.0); 1271 graphdata.ltype = 0; 1272 1273 for (int i = 0; i < rmod->n; i++) { 1274 rmod->data.F32[i] = log10(rmod->data.F32[i]); 1275 } 1276 1176 1277 // ** loglog ** 1177 1278 KapaSelectSection (myKapa, "loglog"); … … 1182 1283 graphdata.ymin = -0.05; 1183 1284 graphdata.ymax = +5.05; 1285 graphdata.color = KapaColorByName ("black"); 1184 1286 KapaSetLimits (myKapa, &graphdata); 1185 1287 … … 1204 1306 KapaPlotVector (myKapa, nb, Rb->data.F32, "x"); 1205 1307 KapaPlotVector (myKapa, nb, fb->data.F32, "y"); 1308 1309 graphdata.color = KapaColorByName ("blue"); 1310 graphdata.ptype = 0; 1311 graphdata.size = 0.0; 1312 graphdata.style = 0; 1313 KapaPrepPlot (myKapa, rmod->n, &graphdata); 1314 KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x"); 1315 KapaPlotVector (myKapa, rmod->n, fmin->data.F32, "y"); 1316 1317 graphdata.color = KapaColorByName ("green"); 1318 graphdata.ptype = 0; 1319 graphdata.size = 0.0; 1320 graphdata.style = 0; 1321 KapaPrepPlot (myKapa, rmod->n, &graphdata); 1322 KapaPlotVector (myKapa, rmod->n, rmod->data.F32, "x"); 1323 KapaPlotVector (myKapa, rmod->n, fmaj->data.F32, "y"); 1324 1325 psFree (rmod); 1326 psFree (fmin); 1327 psFree (fmaj); 1206 1328 1207 1329 psFree (rg); … … 1392 1514 if (source == NULL) continue; 1393 1515 1394 // if (source->type != type) continue;1395 1516 if (mode) { 1396 1517 if (keep) { … … 1516 1637 psVector *sDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 1517 1638 1639 psVector *xLOW = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 1640 psVector *yLOW = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 1641 psVector *mLOW = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 1642 psVector *sLOW = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 1643 1518 1644 psVector *xCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 1519 1645 psVector *yCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32); … … 1526 1652 int nPSF = 0; 1527 1653 int nDEF = 0; 1654 int nLOW = 0; 1528 1655 int nCR = 0; 1529 1656 for (int i = 0; i < sources->n; i++) { 1530 1657 pmSource *source = sources->data[i]; 1531 1658 if (source->moments == NULL) continue; 1659 1660 // only plot the measured sources... 1661 if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)) continue; 1532 1662 1533 1663 if (source->mode & PM_SOURCE_MODE_CR_LIMIT) { … … 1561 1691 continue; 1562 1692 } 1563 if ((source->mode & PM_SOURCE_MODE_CR_LIMIT) || (source->mode & PM_SOURCE_MODE_SATSTAR)) { 1693 if (source->errMag > 0.1) { 1694 xLOW->data.F32[nLOW] = source->moments->Mxx; 1695 yLOW->data.F32[nLOW] = source->moments->Myy; 1696 mLOW->data.F32[nLOW] = -2.5*log10(source->moments->Sum); 1697 sLOW->data.F32[nLOW] = source->extNsigma; 1698 nLOW++; 1564 1699 continue; 1565 1700 } … … 1570 1705 nPSF++; 1571 1706 } 1707 1572 1708 xSAT->n = nSAT; 1573 1709 ySAT->n = nSAT; … … 1594 1730 mDEF->n = nDEF; 1595 1731 sDEF->n = nDEF; 1732 1733 xLOW->n = nLOW; 1734 yLOW->n = nLOW; 1735 mLOW->n = nLOW; 1736 sLOW->n = nLOW; 1596 1737 1597 1738 // four sections: MxxMyy, MagMxx, MagMyy, MagSigma … … 1657 1798 KapaPlotVector (myKapa, nSAT, ySAT->data.F32, "y"); 1658 1799 1800 graphdata.color = KapaColorByName ("black"); 1801 graphdata.ptype = 7; 1802 graphdata.size = 1.0; 1803 graphdata.style = 2; 1804 KapaPrepPlot (myKapa, nLOW, &graphdata); 1805 KapaPlotVector (myKapa, nLOW, xLOW->data.F32, "x"); 1806 KapaPlotVector (myKapa, nLOW, yLOW->data.F32, "y"); 1807 1659 1808 // second section: MagMyy 1660 1809 section.dx = 0.75; … … 1668 1817 graphdata.color = KapaColorByName ("black"); 1669 1818 graphdata.xmin = -17.1; 1670 graphdata.xmax = - 7.9;1819 graphdata.xmax = -6.9; 1671 1820 graphdata.ymin = Ymin; 1672 1821 graphdata.ymax = Ymax; … … 1730 1879 graphdata.xmin = Xmin; 1731 1880 graphdata.xmax = Xmax; 1732 graphdata.ymin = - 7.9;1881 graphdata.ymin = -6.9; 1733 1882 graphdata.ymax = -17.1; 1734 1883 KapaSetLimits (myKapa, &graphdata); … … 1789 1938 1790 1939 graphdata.color = KapaColorByName ("black"); 1791 graphdata.xmax = - 7.9;1940 graphdata.xmax = -6.9; 1792 1941 graphdata.xmin = -17.1; 1793 1942 graphdata.ymin = -20.1;
Note:
See TracChangeset
for help on using the changeset viewer.
