Changeset 14944
- Timestamp:
- Sep 20, 2007, 2:14:47 PM (19 years ago)
- File:
-
- 1 edited
-
trunk/psphot/src/psphotApResid.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psphot/src/psphotApResid.c
r13900 r14944 1 1 # include "psphotInternal.h" 2 // XXXX this code fails if there are too few sources to measure the aperture residual 3 // the larger problem is that the rules for accepting more polynomial terms are weak. 4 5 static pmPSFApTrendOptions DEFAULT_OPTION = PM_PSF_APTREND_SKYBIAS; 6 7 // measure the aperture residual statistics 2 3 // measure the aperture residual statistics and 2D variations 8 4 bool psphotApResid (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psMaskType maskVal, psMaskType mark) 9 5 { … … 16 12 17 13 PS_ASSERT_PTR_NON_NULL(psf, false); 18 PS_ASSERT_PTR_NON_NULL(psf->ApTrend, false);14 // XXX drop this? PS_ASSERT_PTR_NON_NULL(psf->ApTrend, false); 19 15 PS_ASSERT_PTR_NON_NULL(readout, false); 20 16 PS_ASSERT_PTR_NON_NULL(sources, false); … … 30 26 bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH"); 31 27 bool INTERPOLATE_AP = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP"); 32 int NSTAR_APERTURE_CORRECTION_MIN = 33 psMetadataLookupS32(&status, recipe, "NSTAR_APERTURE_CORRECTION_MIN"); 28 29 // XXX is this still needed? the pmTrend2D stuff should be auto-adjusting... 30 int NSTAR_APERTURE_CORRECTION_MIN = psMetadataLookupS32(&status, recipe, "NSTAR_APERTURE_CORRECTION_MIN"); 34 31 if (!status) { 35 32 NSTAR_APERTURE_CORRECTION_MIN = 5; … … 54 51 55 52 psVector *mask = psVectorAllocEmpty (300, PS_TYPE_U8); 56 psVector *xPos = psVectorAllocEmpty (300, PS_TYPE_F64); 57 psVector *yPos = psVectorAllocEmpty (300, PS_TYPE_F64); 58 psVector *flux = psVectorAllocEmpty (300, PS_TYPE_F64); 59 psVector *r2rflux = psVectorAllocEmpty (300, PS_TYPE_F64); 60 psVector *apResid = psVectorAllocEmpty (300, PS_TYPE_F64); 61 psVector *dMag = psVectorAllocEmpty (300, PS_TYPE_F64); 53 psVector *mag = psVectorAllocEmpty (300, PS_TYPE_F32); 54 psVector *xPos = psVectorAllocEmpty (300, PS_TYPE_F32); 55 psVector *yPos = psVectorAllocEmpty (300, PS_TYPE_F32); 56 psVector *apResid = psVectorAllocEmpty (300, PS_TYPE_F32); 57 psVector *dMag = psVectorAllocEmpty (300, PS_TYPE_F32); 62 58 Npsf = 0; 63 64 FILE *dumpFile = NULL;65 if (psTraceGetLevel("psphot") >= 5) {66 dumpFile = fopen ("apresid.dat", "w");67 }68 59 69 60 // select all good PM_SOURCE_TYPE_STAR entries … … 90 81 } 91 82 92 // sanity clipping : if the model is so discrepant, but your expectation in the recipe 93 apResid->data.F64[Npsf] = source->apMag - source->psfMag; 94 95 if ((MAX_AP_OFFSET > 0) && (fabs(apResid->data.F64[Npsf]) > MAX_AP_OFFSET)) { 83 // aperture residual for this source 84 float dap = source->apMag - source->psfMag; 85 86 // sanity clipping : if the model is very discrepant, put your expectation in the recipe 87 if ((MAX_AP_OFFSET > 0) && (fabs(dap) > MAX_AP_OFFSET)) { 96 88 Nfail ++; 97 89 continue; 98 90 } 99 91 100 xPos->data.F64[Npsf] = model->params->data.F32[PM_PAR_XPOS]; 101 yPos->data.F64[Npsf] = model->params->data.F32[PM_PAR_YPOS]; 102 103 flux->data.F64[Npsf] = pow(10.0, -0.4*source->psfMag); 104 r2rflux->data.F64[Npsf] = PS_SQR(model->radiusFit) / flux->data.F64[Npsf]; 92 mag->data.F32[Npsf] = source->psfMag; 93 apResid->data.F32[Npsf] = dap; 94 xPos->data.F32[Npsf] = model->params->data.F32[PM_PAR_XPOS]; 95 yPos->data.F32[Npsf] = model->params->data.F32[PM_PAR_YPOS]; 105 96 106 97 mask->data.U8[Npsf] = 0; 107 98 108 dMag->data.F64[Npsf] = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0]; 109 110 if (psTraceGetLevel("psphot") >= 5) { 111 fprintf (dumpFile, "%f %f %f %f %f %x\n", 112 xPos->data.F64[Npsf], yPos->data.F64[Npsf], 113 source->psfMag, dMag->data.F64[Npsf], apResid->data.F64[Npsf], 114 mask->data.U8[Npsf]); 115 } 99 dMag->data.F32[Npsf] = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0]; 116 100 117 101 psVectorExtend (mask, 100, 1); 118 102 psVectorExtend (xPos, 100, 1); 119 103 psVectorExtend (yPos, 100, 1); 120 psVectorExtend (flux, 100, 1);121 psVectorExtend (r2rflux, 100, 1);122 104 psVectorExtend (dMag, 100, 1); 123 105 psVectorExtend (apResid, 100, 1); 124 106 Npsf ++; 125 }126 127 if (psTraceGetLevel("psphot") >= 5) {128 fclose (dumpFile);129 107 } 130 108 … … 139 117 } 140 118 141 // APTREND options : NONE CONSTANT SKYBIAS XY_LIN XY_QUAD SKY_XY_LIN FULL 142 // APTREND options are used in the switch block below 143 pmPSFApTrendOptions ApTrendOption = DEFAULT_OPTION; 144 char *optionName = psMetadataLookupPtr (&status, recipe, "APTREND"); 145 if (status) ApTrendOption = pmPSFApTrendOptionFromName (optionName); 146 if (ApTrendOption == PM_PSF_APTREND_ERROR) { 147 psError(PSPHOT_ERR_APERTURE, true, "invalid aperture residual trend %s", optionName); 148 return false; 149 } 150 119 // XXX deprecating the old code which allowed the ApResid to be fitted as a function of flux and r^2/flux 120 // XXX is this asymmetric clipping still needed? this analysis should come after neighbors are subtracted... 151 121 // 3hi/1lo sigma clipping on the rflux vs metric fit 152 psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 153 stats->min = 2.0; 154 stats->max = 3.0; 155 156 #define P_APTREND_SWITCH_CLEANUP /* Cleanup memory on error in ApTrendOption switch */ \ 157 psFree(psf->growth); psf->growth = NULL; \ 158 psFree(mask); \ 159 psFree(xPos); \ 160 psFree(yPos); \ 161 psFree(flux); \ 162 psFree(r2rflux); \ 163 psFree(apResid); \ 164 psFree(dMag); \ 165 psFree(stats) 166 167 // no correction 168 switch (ApTrendOption) { 169 case PM_PSF_APTREND_NONE: 170 // remove ApTrend fit from pmPSFtry 171 psf->ApTrend->coeff[0][0][0][0] = 0; 172 break; 173 case PM_PSF_APTREND_CONSTANT: 174 stats->clipIter = 2; 175 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 176 if (!psVectorClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 177 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting nothing"); 178 P_APTREND_SWITCH_CLEANUP; 179 return false; 180 } 181 // apply the fit 182 stats->clipIter = 3; 183 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 184 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 185 psError(PSPHOT_ERR_PHOTOM, false, "Fitting aperture correction"); 186 P_APTREND_SWITCH_CLEANUP; 187 return false; 188 } 189 break; 190 case PM_PSF_APTREND_SKYBIAS: 191 // first clip out objects which are too far from the median 192 stats->clipIter = 2; 193 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 194 if (!psVectorClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 195 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting nothing"); 196 P_APTREND_SWITCH_CLEANUP; 197 return false; 198 } 199 // apply the fit 200 stats->clipIter = 3; 201 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_SKYBIAS); 202 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 203 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting sky bias"); 204 P_APTREND_SWITCH_CLEANUP; 205 return false; 206 } 207 break; 208 case PM_PSF_APTREND_SKYSAT: 209 // first clip out objects which are too far from the median 210 stats->clipIter = 2; 211 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 212 if (!psVectorClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 213 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting nothing"); 214 P_APTREND_SWITCH_CLEANUP; 215 return false; 216 } 217 // apply the fit 218 stats->clipIter = 2; 219 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_SKYBIAS); 220 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 221 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting sky bias"); 222 P_APTREND_SWITCH_CLEANUP; 223 return false; 224 } 225 // apply the fit 226 stats->clipIter = 3; 227 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_SKYSAT); 228 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 229 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting skysat"); 230 P_APTREND_SWITCH_CLEANUP; 231 return false; 232 } 233 break; 234 case PM_PSF_APTREND_XY_LIN: 235 // first clip out objects which are too far from the median 236 stats->clipIter = 2; 237 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 238 if (!psVectorClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 239 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting nothing"); 240 P_APTREND_SWITCH_CLEANUP; 241 return false; 242 } 243 // apply the fit 244 stats->clipIter = 3; 245 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_XY_LIN); 246 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 247 psError(PSPHOT_ERR_PHOTOM, false, "fitting, XY_LIN"); 248 P_APTREND_SWITCH_CLEANUP; 249 return false; 250 } 251 break; 252 case PM_PSF_APTREND_XY_QUAD: 253 // first clip out objects which are too far from the median 254 stats->clipIter = 2; 255 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 256 if (!psVectorClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 257 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting nothing"); 258 P_APTREND_SWITCH_CLEANUP; 259 return false; 260 } 261 // apply the fit 262 stats->clipIter = 3; 263 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_XY_QUAD); 264 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 265 psError(PSPHOT_ERR_PHOTOM, false, "Fitting XY_QUAD"); 266 P_APTREND_SWITCH_CLEANUP; 267 return false; 268 } 269 break; 270 case PM_PSF_APTREND_SKY_XY_LIN: 271 // first clip out objects which are too far from the median 272 stats->clipIter = 2; 273 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 274 if (!psVectorClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 275 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting nothing"); 276 P_APTREND_SWITCH_CLEANUP; 277 return false; 278 } 279 // apply the fit 280 stats->clipIter = 3; 281 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_SKY_XY_LIN); 282 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 283 psError(PSPHOT_ERR_PHOTOM, false, "Fitting sky xy_lin"); 284 P_APTREND_SWITCH_CLEANUP; 285 return false; 286 } 287 break; 288 case PM_PSF_APTREND_SKYSAT_XY_LIN: 289 // first clip out objects which are too far from the median 290 stats->clipIter = 2; 291 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 292 if (!psVectorClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 293 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting nothing"); 294 P_APTREND_SWITCH_CLEANUP; 295 return false; 296 } 297 // apply the fit 298 stats->clipIter = 3; 299 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_SKYBIAS); 300 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 301 psError(PSPHOT_ERR_PHOTOM, false, "clipping, fitting sky bias"); 302 P_APTREND_SWITCH_CLEANUP; 303 return false; 304 } 305 // apply the fit 306 stats->clipIter = 3; 307 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_SKYSAT_XY_LIN); 308 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 309 psError(PSPHOT_ERR_PHOTOM, false, "Fitting skyset xy_lin"); 310 P_APTREND_SWITCH_CLEANUP; 311 return false; 312 } 313 break; 314 case PM_PSF_APTREND_ALL: 315 // first clip out objects which are too far from the median 316 stats->clipIter = 2; 317 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_CONSTANT); 318 if (!psVectorClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 319 psError(PSPHOT_ERR_PHOTOM, false, "Failed to measure apTrend"); 320 P_APTREND_SWITCH_CLEANUP; 321 return false; 322 } 323 // fit just SkyBias and clip out objects which are too far from the median 324 stats->clipIter = 2; 325 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_SKYBIAS); 326 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 327 psError(PSPHOT_ERR_PHOTOM, false, "fitting skyBias"); 328 P_APTREND_SWITCH_CLEANUP; 329 return false; 330 } 331 // finally, fit x, y, SkyBias and clip out objects which are too far from the median 332 stats->clipIter = 3; 333 pmPSFMaskApTrend (psf->ApTrend, PM_PSF_APTREND_ALL); 334 if (!psVectorChiClipFitPolynomial4D (psf->ApTrend, stats, mask, PSFTRY_MASK_ALL, apResid, dMag, xPos, yPos, r2rflux, flux)) { 335 psError(PSPHOT_ERR_PHOTOM, false, "fitting all"); 336 P_APTREND_SWITCH_CLEANUP; 337 return false; 338 } 339 break; 340 default: 341 psError(PSPHOT_ERR_PHOTOM, true, "Unknown APTREND value: %s", optionName); 342 return false; 343 } 344 #undef P_APTREND_SWITCH_CLEANUP 122 // systematic error information 123 float errorScale = 0.0; 124 float errorFloor = 0.0; 125 126 float errorFloorMin = FLT_MAX; 127 int entryMin = -1; 128 129 // *** iterate over spatial scale until error Floor increases 130 // *** fit out the dap vs mag trend? 131 // *** stop if Npsf / (Nx * Ny) < 3 132 for (int i = 1; i < 10; i++) { 133 134 if (!psphotApResidTrend (readout, psf, Npsf, i, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag)) { 135 break; 136 } 137 138 // store the resulting errorFloor values and the scales, redo the best 139 if (errorFloor < errorFloorMin) { 140 errorFloorMin = errorFloor; 141 entryMin = i; 142 } 143 } 144 if (entryMin == -1) { 145 psAbort ("failed on ApResid Trend"); 146 } 147 148 psphotApResidTrend (readout, psf, Npsf, entryMin, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag); 345 149 346 150 // construct the fitted values and the residuals 347 psVector *fit = psPolynomial4DEvalVector (psf->ApTrend, xPos, yPos, r2rflux, flux); 348 psVector *resid = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) fit); 349 350 // measure scatter for sources with dMag < 0.01 (S/N = 100) 351 int Nkeep = 0; 352 psStats *residStats = psStatsAlloc (PS_STAT_SAMPLE_STDEV); 353 for (int i = 0; i < dMag->n; i++) { 354 if (dMag->data.F64[i] > 0.01) { 355 mask->data.U8[i] |= 0x02; 356 } 357 if (! mask->data.U8[i]) Nkeep ++; 358 } 359 psVectorStats (residStats, resid, NULL, mask, 0x03); 151 psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, xPos, yPos); 152 psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit); 153 psVector *dMagSys = (psVector *) psBinaryOp (NULL, (void *) dMag, "*", (void *) psScalarAlloc(errorScale, PS_TYPE_F32)); 154 155 psphotSaveImage (NULL, psf->ApTrend->map->map, "apresid.map.fits"); 156 157 if (psTraceGetLevel("psphot") >= 5) { 158 FILE *dumpFile = fopen ("apresid.dat", "w"); 159 for (int i = 0; i < xPos->n; i++) { 160 fprintf (dumpFile, "%f %f %f %f %f %f %f %x\n", 161 xPos->data.F32[i], yPos->data.F32[i], 162 mag->data.F32[i], dMag->data.F32[i], dMagSys->data.F32[i], 163 apResid->data.F32[i], apResidRes->data.F32[i], 164 mask->data.U8[i]); 165 } 166 fclose (dumpFile); 167 } 360 168 361 169 // apply ApTrend results 362 psf->skyBias = psf->ApTrend->coeff[0][0][1][0]; 363 psf->skySat = psf->ApTrend->coeff[0][0][0][1]; 364 psf->ApResid = psf->ApTrend->coeff[0][0][0][0]; 365 psf->dApResid = residStats->sampleStdev; 366 psf->ApTrend->coeff[0][0][1][0] = 0; 367 psf->ApTrend->coeff[0][0][0][1] = 0; 170 float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5; 171 float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5; 172 psf->ApResid = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center 173 psf->dApResid = errorFloor; 368 174 psf->nApResid = Npsf; 369 175 370 176 // save results for later output 371 psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS", PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias", psf->skyBias);372 psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT", PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias", psf->skySat);177 psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS", PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias", 0.0); 178 psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT", PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias", 0.0); 373 179 psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT", PS_DATA_F32 | PS_META_REPLACE, "aperture residual", psf->ApResid); 374 180 psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid); … … 376 182 psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "ap residual scatter", psf->nApResid); 377 183 378 psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d of %d objects: %f sec\n", 379 Nkeep, Npsf, psTimerMark ("psphot")); 380 psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f : %f bias, %f skysat\n", 381 psf->ApResid, psf->dApResid, psf->skyBias, psf->skySat); 382 psLogMsg ("psphot.apresid", PS_LOG_MINUTIA, "apresid trends: %f %f %f %f %f\n", 383 1e3*psf->ApTrend->coeff[1][0][0][0], 384 1e6*psf->ApTrend->coeff[2][0][0][0], 385 1e6*psf->ApTrend->coeff[1][1][0][0], 386 1e3*psf->ApTrend->coeff[0][1][0][0], 387 1e6*psf->ApTrend->coeff[0][2][0][0]); 388 184 // psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d of %d objects: %f sec\n", Nkeep, Npsf, psTimerMark ("psphot")); 185 psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid); 186 187 psFree (mag); 389 188 psFree (mask); 390 189 psFree (xPos); 391 190 psFree (yPos); 392 psFree (flux);393 psFree (r2rflux);394 191 psFree (apResid); 395 192 psFree (dMag); 396 193 397 psFree (fit);398 psFree (resid);399 psFree (stats);400 psFree (residStats);401 194 return true; 402 195 } … … 408 201 */ 409 202 203 bool psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, int nGroup) { 204 205 psStats *statsS = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 206 psStats *statsM = psStatsAlloc (PS_STAT_SAMPLE_MEAN); 207 208 // measure the trend in bins with 10 values each; if < 10 total, use them all 209 int nBin = PS_MAX (dMag->n / nGroup, 1); 210 211 // output vectors for ApResid trend 212 psVector *dSo = psVectorAlloc (nBin, PS_TYPE_F32); 213 psVector *dMo = psVectorAlloc (nBin, PS_TYPE_F32); 214 psVector *dRo = psVectorAlloc (nBin, PS_TYPE_F32); 215 216 // use dMag to group the dMag and dap vectors 217 psVector *index = psVectorSortIndex (NULL, dMag); 218 219 // subset vectors for dMag and dap values within the given range 220 psVector *dMSubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32); 221 psVector *dASubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32); 222 223 int n = 0; 224 for (int i = 0; i < dMo->n; i++) { 225 int j; 226 for (j = 0; (j < nGroup) && (n < dMag->n); j++, n++) { 227 int N = index->data.U32[n]; 228 dMSubset->data.F32[j] = dMag->data.F32[N]; 229 dASubset->data.F32[j] = dap->data.F32[N]; 230 } 231 dMSubset->n = j; 232 dASubset->n = j; 233 234 psStatsInit (statsS); 235 psStatsInit (statsM); 236 237 psVectorStats (statsS, dASubset, NULL, NULL, 0xff); 238 psVectorStats (statsM, dMSubset, NULL, NULL, 0xff); 239 240 dSo->data.F32[i] = statsS->robustStdev; 241 dMo->data.F32[i] = statsM->sampleMean; 242 243 dRo->data.F32[i] = statsS->robustStdev / statsM->sampleMean; 244 } 245 psFree (dMSubset); 246 psFree (dASubset); 247 248 psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN); 249 psVectorStats (stats, dRo, NULL, NULL, 0); 250 251 *errorScale = stats->sampleMedian; 252 *errorFloor = dSo->data.F32[0]; 253 254 psFree (stats); 255 psFree (index); 256 257 psFree (dRo); 258 psFree (dMo); 259 psFree (dSo); 260 261 psFree (statsS); 262 psFree (statsM); 263 264 return true; 265 } 266 267 bool psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) { 268 269 int Nx, Ny; 270 271 psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 272 stats->min = 2.0; 273 stats->max = 3.0; 274 275 if (readout->image->numCols > readout->image->numRows) { 276 Nx = scale; 277 Ny = PS_MAX (1, Nx * (readout->image->numRows / readout->image->numCols)); 278 } else { 279 Ny = scale; 280 Nx = PS_MAX (1, Ny * (readout->image->numCols / readout->image->numRows)); 281 } 282 283 if (Npsf < 3*Nx*Ny) { 284 return false; 285 } 286 287 // measure Trend2D for the current spatial scale 288 psFree (psf->ApTrend); 289 psf->ApTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats); 290 pmTrend2DFit (psf->ApTrend, mask, 0xff, xPos, yPos, apResid, dMag); 291 292 // construct the fitted values and the residuals 293 psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, xPos, yPos); 294 psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit); 295 296 // measure systematic errorFloor & systematic / photon scale factor 297 // XXX this is a bit arbitrary, but it forces ~3 stars from the bright bin per spatial bin 298 int nGroup = PS_MAX (3*Nx*Ny, 10); 299 psphotMagErrorScale (errorScale, errorFloor, dMag, apResidRes, nGroup); 300 301 psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid (%d stars per bin)\n", Nx, Ny, nGroup); 302 psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic error / photon error: %f\n", *errorScale); 303 psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *errorFloor); 304 305 psFree (stats); 306 psFree (apResidFit); 307 psFree (apResidRes); 308 309 return true; 310 } 311
Note:
See TracChangeset
for help on using the changeset viewer.
