Changeset 27840 for branches/simtest_nebulous_branches/psModules
- Timestamp:
- May 3, 2010, 8:50:52 AM (16 years ago)
- Location:
- branches/simtest_nebulous_branches
- Files:
-
- 8 deleted
- 136 edited
- 33 copied
-
. (modified) (1 prop)
-
psModules (modified) (1 prop)
-
psModules/src/astrom/pmAstrometryModel.c (modified) (1 diff)
-
psModules/src/astrom/pmAstrometryObjects.c (modified) (11 diffs)
-
psModules/src/astrom/pmAstrometryObjects.h (modified) (4 diffs)
-
psModules/src/astrom/pmAstrometryVisual.c (modified) (8 diffs)
-
psModules/src/astrom/pmAstrometryVisual.h (modified) (1 diff)
-
psModules/src/astrom/pmAstrometryWCS.c (modified) (13 diffs)
-
psModules/src/astrom/pmAstrometryWCS.h (modified) (2 diffs)
-
psModules/src/camera/pmFPA.c (modified) (2 diffs)
-
psModules/src/camera/pmFPA.h (modified) (1 diff)
-
psModules/src/camera/pmFPAMaskWeight.c (modified) (10 diffs)
-
psModules/src/camera/pmFPAMaskWeight.h (modified) (6 diffs)
-
psModules/src/camera/pmFPAMosaic.c (modified) (19 diffs)
-
psModules/src/camera/pmFPARead.c (modified) (5 diffs)
-
psModules/src/camera/pmFPAWrite.c (modified) (1 diff)
-
psModules/src/camera/pmFPAfile.c (modified) (8 diffs)
-
psModules/src/camera/pmFPAfile.h (modified) (3 diffs)
-
psModules/src/camera/pmFPAfileDefine.c (modified) (53 diffs)
-
psModules/src/camera/pmFPAfileDefine.h (modified) (1 diff)
-
psModules/src/camera/pmFPAfileFitsIO.c (modified) (3 diffs)
-
psModules/src/camera/pmFPAfileIO.c (modified) (12 diffs)
-
psModules/src/camera/pmHDUGenerate.c (modified) (3 diffs)
-
psModules/src/camera/pmReadoutFake.c (modified) (5 diffs)
-
psModules/src/camera/pmReadoutFake.h (modified) (1 diff)
-
psModules/src/concepts/pmConcepts.c (modified) (5 diffs)
-
psModules/src/concepts/pmConceptsAverage.c (modified) (7 diffs)
-
psModules/src/concepts/pmConceptsRead.c (modified) (5 diffs)
-
psModules/src/concepts/pmConceptsStandard.c (modified) (6 diffs)
-
psModules/src/concepts/pmConceptsStandard.h (modified) (2 diffs)
-
psModules/src/concepts/pmConceptsWrite.c (modified) (1 diff)
-
psModules/src/config/Makefile.am (modified) (2 diffs)
-
psModules/src/config/pmConfig.c (modified) (63 diffs)
-
psModules/src/config/pmConfigCamera.c (modified) (7 diffs)
-
psModules/src/config/pmConfigDump.c (modified) (6 diffs)
-
psModules/src/config/pmConfigMask.c (modified) (2 diffs)
-
psModules/src/config/pmConfigRecipeValue.c (copied) (copied from trunk/psModules/src/config/pmConfigRecipeValue.c )
-
psModules/src/config/pmConfigRecipeValue.h (copied) (copied from trunk/psModules/src/config/pmConfigRecipeValue.h )
-
psModules/src/config/pmConfigRun.c (modified) (1 diff)
-
psModules/src/detrend/Makefile.am (modified) (2 diffs)
-
psModules/src/detrend/pmDark.c (modified) (18 diffs)
-
psModules/src/detrend/pmFringeStats.c (modified) (7 diffs)
-
psModules/src/detrend/pmMaskBadPixels.c (modified) (1 diff)
-
psModules/src/detrend/pmPattern.c (modified) (9 diffs)
-
psModules/src/detrend/pmPattern.h (modified) (2 diffs)
-
psModules/src/detrend/pmPatternIO.c (copied) (copied from trunk/psModules/src/detrend/pmPatternIO.c )
-
psModules/src/detrend/pmPatternIO.h (copied) (copied from trunk/psModules/src/detrend/pmPatternIO.h )
-
psModules/src/detrend/pmShutterCorrection.c (modified) (1 diff)
-
psModules/src/extras/Makefile.am (modified) (1 diff)
-
psModules/src/extras/ippDiffMode.h (copied) (copied from trunk/psModules/src/extras/ippDiffMode.h )
-
psModules/src/extras/ippStages.h (modified) (1 diff)
-
psModules/src/extras/pmVisual.c (modified) (2 diffs)
-
psModules/src/imcombine/Makefile.am (modified) (2 diffs)
-
psModules/src/imcombine/pmImageCombine.c (modified) (5 diffs)
-
psModules/src/imcombine/pmPSFEnvelope.c (modified) (10 diffs)
-
psModules/src/imcombine/pmPSFEnvelope.h (modified) (1 diff)
-
psModules/src/imcombine/pmStack.c (modified) (29 diffs)
-
psModules/src/imcombine/pmStack.h (modified) (3 diffs)
-
psModules/src/imcombine/pmStackReject.c (modified) (15 diffs)
-
psModules/src/imcombine/pmStackReject.h (modified) (1 diff)
-
psModules/src/imcombine/pmSubtraction.c (modified) (51 diffs)
-
psModules/src/imcombine/pmSubtraction.h (modified) (5 diffs)
-
psModules/src/imcombine/pmSubtractionAnalysis.c (modified) (12 diffs)
-
psModules/src/imcombine/pmSubtractionAnalysis.h (modified) (1 diff)
-
psModules/src/imcombine/pmSubtractionDeconvolve.c (copied) (copied from trunk/psModules/src/imcombine/pmSubtractionDeconvolve.c )
-
psModules/src/imcombine/pmSubtractionDeconvolve.h (copied) (copied from trunk/psModules/src/imcombine/pmSubtractionDeconvolve.h )
-
psModules/src/imcombine/pmSubtractionEquation.c (modified) (34 diffs)
-
psModules/src/imcombine/pmSubtractionEquation.h (modified) (2 diffs)
-
psModules/src/imcombine/pmSubtractionHermitian.c (copied) (copied from trunk/psModules/src/imcombine/pmSubtractionHermitian.c )
-
psModules/src/imcombine/pmSubtractionHermitian.h (copied) (copied from trunk/psModules/src/imcombine/pmSubtractionHermitian.h )
-
psModules/src/imcombine/pmSubtractionIO.c (modified) (30 diffs)
-
psModules/src/imcombine/pmSubtractionKernels.c (modified) (30 diffs)
-
psModules/src/imcombine/pmSubtractionKernels.h (modified) (17 diffs)
-
psModules/src/imcombine/pmSubtractionMask.c (modified) (5 diffs)
-
psModules/src/imcombine/pmSubtractionMask.h (modified) (1 diff)
-
psModules/src/imcombine/pmSubtractionMatch.c (modified) (38 diffs)
-
psModules/src/imcombine/pmSubtractionMatch.h (modified) (3 diffs)
-
psModules/src/imcombine/pmSubtractionParams.c (modified) (18 diffs)
-
psModules/src/imcombine/pmSubtractionParams.h (modified) (1 diff)
-
psModules/src/imcombine/pmSubtractionStamps.c (modified) (35 diffs)
-
psModules/src/imcombine/pmSubtractionStamps.h (modified) (8 diffs)
-
psModules/src/imcombine/pmSubtractionThreads.c (modified) (5 diffs)
-
psModules/src/imcombine/pmSubtractionThreads.h (modified) (1 diff)
-
psModules/src/imcombine/pmSubtractionVisual.c (modified) (14 diffs)
-
psModules/src/imcombine/pmSubtractionVisual.h (modified) (1 diff)
-
psModules/src/objects/Makefile.am (modified) (7 diffs)
-
psModules/src/objects/models/pmModel_GAUSS.c (modified) (10 diffs)
-
psModules/src/objects/models/pmModel_GAUSS.h (copied) (copied from trunk/psModules/src/objects/models/pmModel_GAUSS.h )
-
psModules/src/objects/models/pmModel_PGAUSS.c (modified) (11 diffs)
-
psModules/src/objects/models/pmModel_PGAUSS.h (copied) (copied from trunk/psModules/src/objects/models/pmModel_PGAUSS.h )
-
psModules/src/objects/models/pmModel_PS1_V1.c (modified) (13 diffs)
-
psModules/src/objects/models/pmModel_PS1_V1.h (copied) (copied from trunk/psModules/src/objects/models/pmModel_PS1_V1.h )
-
psModules/src/objects/models/pmModel_QGAUSS.c (modified) (15 diffs)
-
psModules/src/objects/models/pmModel_QGAUSS.h (copied) (copied from trunk/psModules/src/objects/models/pmModel_QGAUSS.h )
-
psModules/src/objects/models/pmModel_RGAUSS.c (modified) (12 diffs)
-
psModules/src/objects/models/pmModel_RGAUSS.h (copied) (copied from trunk/psModules/src/objects/models/pmModel_RGAUSS.h )
-
psModules/src/objects/models/pmModel_SERSIC.c (modified) (10 diffs)
-
psModules/src/objects/models/pmModel_SERSIC.h (copied) (copied from trunk/psModules/src/objects/models/pmModel_SERSIC.h )
-
psModules/src/objects/models/pmModel_SGAUSS.c (deleted)
-
psModules/src/objects/models/pmModel_TGAUSS.c (deleted)
-
psModules/src/objects/models/pmModel_WAUSS.c (deleted)
-
psModules/src/objects/models/pmModel_ZGAUSS.c (deleted)
-
psModules/src/objects/pmDetEff.c (copied) (copied from trunk/psModules/src/objects/pmDetEff.c )
-
psModules/src/objects/pmDetEff.h (copied) (copied from trunk/psModules/src/objects/pmDetEff.h )
-
psModules/src/objects/pmDetections.c (modified) (2 diffs)
-
psModules/src/objects/pmDetections.h (modified) (1 diff)
-
psModules/src/objects/pmFootprint.c (modified) (6 diffs)
-
psModules/src/objects/pmFootprint.h (modified) (3 diffs)
-
psModules/src/objects/pmFootprintCullPeaks.c (modified) (7 diffs)
-
psModules/src/objects/pmFootprintFindAtPoint.c (modified) (2 diffs)
-
psModules/src/objects/pmFootprintIDs.c (modified) (1 diff)
-
psModules/src/objects/pmFootprintSpans.c (copied) (copied from trunk/psModules/src/objects/pmFootprintSpans.c )
-
psModules/src/objects/pmFootprintSpans.h (copied) (copied from trunk/psModules/src/objects/pmFootprintSpans.h )
-
psModules/src/objects/pmGrowthCurveGenerate.c (modified) (3 diffs)
-
psModules/src/objects/pmModel.c (modified) (8 diffs)
-
psModules/src/objects/pmModel.h (modified) (7 diffs)
-
psModules/src/objects/pmModelClass.c (modified) (2 diffs)
-
psModules/src/objects/pmModelClass.h (modified) (3 diffs)
-
psModules/src/objects/pmModelGroup.c (deleted)
-
psModules/src/objects/pmModelGroup.h (deleted)
-
psModules/src/objects/pmModelUtils.c (modified) (2 diffs)
-
psModules/src/objects/pmObjects.c (deleted)
-
psModules/src/objects/pmObjects.h (deleted)
-
psModules/src/objects/pmPSF.c (modified) (2 diffs)
-
psModules/src/objects/pmPSF.h (modified) (4 diffs)
-
psModules/src/objects/pmPSF_IO.c (modified) (35 diffs)
-
psModules/src/objects/pmPSFtry.c (modified) (3 diffs)
-
psModules/src/objects/pmPSFtry.h (modified) (4 diffs)
-
psModules/src/objects/pmPSFtryFitEXT.c (copied) (copied from trunk/psModules/src/objects/pmPSFtryFitEXT.c )
-
psModules/src/objects/pmPSFtryFitPSF.c (copied) (copied from trunk/psModules/src/objects/pmPSFtryFitPSF.c )
-
psModules/src/objects/pmPSFtryMakePSF.c (copied) (copied from trunk/psModules/src/objects/pmPSFtryMakePSF.c )
-
psModules/src/objects/pmPSFtryMetric.c (copied) (copied from trunk/psModules/src/objects/pmPSFtryMetric.c )
-
psModules/src/objects/pmPSFtryModel.c (copied) (copied from trunk/psModules/src/objects/pmPSFtryModel.c )
-
psModules/src/objects/pmPeaks.c (modified) (6 diffs)
-
psModules/src/objects/pmPeaks.h (modified) (1 diff)
-
psModules/src/objects/pmPetrosian.c (copied) (copied from trunk/psModules/src/objects/pmPetrosian.c )
-
psModules/src/objects/pmPetrosian.h (copied) (copied from trunk/psModules/src/objects/pmPetrosian.h )
-
psModules/src/objects/pmPhotObj.c (copied) (copied from trunk/psModules/src/objects/pmPhotObj.c )
-
psModules/src/objects/pmPhotObj.h (copied) (copied from trunk/psModules/src/objects/pmPhotObj.h )
-
psModules/src/objects/pmSource.c (modified) (24 diffs)
-
psModules/src/objects/pmSource.h (modified) (10 diffs)
-
psModules/src/objects/pmSourceDiffStats.c (copied) (copied from trunk/psModules/src/objects/pmSourceDiffStats.c )
-
psModules/src/objects/pmSourceDiffStats.h (copied) (copied from trunk/psModules/src/objects/pmSourceDiffStats.h )
-
psModules/src/objects/pmSourceExtendedPars.c (modified) (3 diffs)
-
psModules/src/objects/pmSourceExtendedPars.h (modified) (1 diff)
-
psModules/src/objects/pmSourceFitModel.c (modified) (3 diffs)
-
psModules/src/objects/pmSourceFitSet.c (modified) (2 diffs)
-
psModules/src/objects/pmSourceGroups.c (copied) (copied from trunk/psModules/src/objects/pmSourceGroups.c )
-
psModules/src/objects/pmSourceGroups.h (copied) (copied from trunk/psModules/src/objects/pmSourceGroups.h )
-
psModules/src/objects/pmSourceIO.c (modified) (15 diffs)
-
psModules/src/objects/pmSourceIO.h (modified) (2 diffs)
-
psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c (copied) (copied from trunk/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c )
-
psModules/src/objects/pmSourceIO_CMF_PS1_V1.c (modified) (15 diffs)
-
psModules/src/objects/pmSourceIO_CMF_PS1_V2.c (modified) (22 diffs)
-
psModules/src/objects/pmSourceIO_MatchedRefs.c (modified) (3 diffs)
-
psModules/src/objects/pmSourceIO_PS1_CAL_0.c (modified) (4 diffs)
-
psModules/src/objects/pmSourceIO_PS1_DEV_0.c (modified) (1 diff)
-
psModules/src/objects/pmSourceIO_PS1_DEV_1.c (modified) (4 diffs)
-
psModules/src/objects/pmSourceIO_RAW.c (modified) (2 diffs)
-
psModules/src/objects/pmSourceIO_SMPDATA.c (modified) (2 diffs)
-
psModules/src/objects/pmSourceMatch.c (modified) (23 diffs)
-
psModules/src/objects/pmSourceMatch.h (modified) (5 diffs)
-
psModules/src/objects/pmSourceMoments.c (modified) (12 diffs)
-
psModules/src/objects/pmSourcePhotometry.c (modified) (18 diffs)
-
psModules/src/objects/pmSourcePhotometry.h (modified) (2 diffs)
-
psModules/src/objects/pmSourcePlotApResid.c (modified) (3 diffs)
-
psModules/src/objects/pmSourcePlotMoments.c (modified) (3 diffs)
-
psModules/src/objects/pmSourcePlotPSFModel.c (modified) (3 diffs)
-
psModules/src/objects/pmSourceVisual.c (modified) (7 diffs)
-
psModules/src/objects/pmSourceVisual.h (modified) (1 diff)
-
psModules/src/objects/pmTrend2D.c (modified) (1 diff)
-
psModules/src/objects/pmTrend2D.h (modified) (1 diff)
-
psModules/src/psmodules.h (modified) (7 diffs)
-
psModules/test/objects/tap_pmGrowthCurve.c (modified) (3 diffs)
-
psModules/test/objects/tap_pmModel.c (modified) (3 diffs)
-
psModules/test/objects/tap_pmModelUtils.c (modified) (2 diffs)
-
psModules/test/objects/tap_pmSourcePhotometry.c (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
branches/simtest_nebulous_branches
- Property svn:mergeinfo changed
-
branches/simtest_nebulous_branches/psModules
-
Property svn:mergeinfo
set to (toggle deleted branches)
/trunk/psModules merged eligible /branches/eam_branches/stackphot.20100406/psModules 27623-27653 /branches/pap_delete/psModules 27530-27595
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
branches/simtest_nebulous_branches/psModules/src/astrom/pmAstrometryModel.c
r19595 r27840 725 725 double X = Xo + RX*cos(POS - To)*cos(Po) + RY*sin(POS - To)*sin(Po); 726 726 double Y = Yo + RY*sin(POS - To)*cos(Po) - RX*cos(POS - To)*sin(Po); 727 psLogMsg ("psModules.astrom", 4, "Boresite coords on reference chip: %f, %f \n", X, Y);727 psLogMsg ("psModules.astrom", 4, "Boresite coords on reference chip: %f, %f pix = %f, %f sky\n", X, Y, PM_DEG_RAD*RA, PM_DEG_RAD*DEC); 728 728 729 729 // get reference chip from name -
branches/simtest_nebulous_branches/psModules/src/astrom/pmAstrometryObjects.c
r24034 r27840 38 38 #include "pmAstrometryVisual.h" 39 39 40 // XXX this is defined in pmPSFtry.h, which makes no sense 41 float psVectorSystematicError (psVector *residuals, psVector *errors, float clipFraction); 42 40 43 #define PM_ASTROMETRYOBJECTS_DEBUG 1 41 44 … … 105 108 } 106 109 107 if (found1->data.S8[i]) {108 i++;109 continue;110 }111 if (found2->data.S8[j]) {112 j++;113 continue;114 }110 if (found1->data.S8[i]) { 111 i++; 112 continue; 113 } 114 if (found2->data.S8[j]) { 115 j++; 116 continue; 117 } 115 118 116 119 jStart = j; … … 125 128 continue; 126 129 } 127 if (found2->data.S8[j]) {128 j++;129 continue;130 }130 if (found2->data.S8[j]) { 131 j++; 132 continue; 133 } 131 134 132 135 // got a match; add to output list … … 135 138 psFree (match); 136 139 137 found1->data.S8[i] = 1;138 found2->data.S8[j] = 1;140 found1->data.S8[i] = 1; 141 found2->data.S8[j] = 1; 139 142 140 143 j++; … … 193 196 psArray *matches = match_lists(x1, y1, x2, y2, sorted1, sorted2, RADIUS); \ 194 197 \ 195 psFree( (void *)sorted1); \196 psFree( (void *)sorted2); \198 psFree(sorted1); \ 199 psFree(sorted2); \ 197 200 psFree(x1); \ 198 201 psFree(y1); \ … … 283 286 return results; 284 287 } 285 psTrace ("psModules.astrom", 3, "x resid: %f +/- %f (%ld of %ld)\n", results->xStats->clippedMean, results->xStats->clippedStdev, results->xStats->clippedNvalues, x->n); 288 // psTrace ("psModules.astrom", 3, "x resid: %f +/- %f (%ld of %ld)\n", results->xStats->clippedMean, results->xStats->clippedStdev, results->xStats->clippedNvalues, x->n); 289 psTrace ("psModules.astrom", 3, "x resid: %f +/- %f (%ld of %ld)\n", results->xStats->robustMedian, results->xStats->robustStdev, results->xStats->clippedNvalues, x->n); 286 290 287 291 if (!psVectorClipFitPolynomial2D (map->y, results->yStats, mask, 0xff, y, wt, X, Y)) { … … 296 300 return results; 297 301 } 298 psTrace ("psModules.astrom", 3, "y resid: %f +/- %f (%ld of %ld)\n", results->yStats->clippedMean, results->yStats->clippedStdev, results->yStats->clippedNvalues, y->n); 302 // psTrace ("psModules.astrom", 3, "y resid: %f +/- %f (%ld of %ld)\n", results->yStats->clippedMean, results->yStats->clippedStdev, results->yStats->clippedNvalues, y->n); 303 psTrace ("psModules.astrom", 3, "y resid: %f +/- %f (%ld of %ld)\n", results->yStats->robustMedian, results->yStats->robustStdev, results->yStats->clippedNvalues, y->n); 299 304 } 300 305 results->xStats->clipIter = stats->clipIter; 301 306 results->yStats->clipIter = stats->clipIter; 307 308 // *** calculate the 90%-ile and the systematic scatter for each direction. 309 310 // generate the X residual vector 311 psVector *xFit = psPolynomial2DEvalVector (map->x, X, Y); 312 if (!xFit) abort(); 313 psVector *xRes = (psVector *) psBinaryOp (NULL, x, "-", xFit); 314 if (!xRes) abort(); 315 psFree (xFit); 316 317 psVector *yFit = psPolynomial2DEvalVector (map->y, X, Y); 318 if (!yFit) abort(); 319 psVector *yRes = (psVector *) psBinaryOp (NULL, y, "-", yFit); 320 if (!yRes) abort(); 321 psFree (yFit); 322 323 // extract a high-quality subset (unmasked, S/N > XXX) and position errors 324 // XXX for now, generate a position error based on the magnitude error 325 psVector *xErr = psVectorAllocEmpty (match->n, PS_TYPE_F32); 326 psVector *yErr = psVectorAllocEmpty (match->n, PS_TYPE_F32); 327 psVector *xResGood = psVectorAllocEmpty (match->n, PS_TYPE_F32); 328 psVector *yResGood = psVectorAllocEmpty (match->n, PS_TYPE_F32); 329 330 for (int i = 0; i < match->n; i++) { 331 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue; 332 pmAstromMatch *pair = match->data[i]; 333 pmAstromObj *rawStar = raw->data[pair->raw]; 334 if (!isfinite(rawStar->dMag)) continue; 335 if (rawStar->dMag > 0.02) continue; 336 337 // two likely failure values: NAN or 0.0 --> use dMag in this case 338 float xErrValue, yErrValue; 339 if (isfinite(rawStar->chip->xErr) && (rawStar->chip->xErr > 0.0)) { 340 xErrValue = rawStar->chip->xErr; 341 } else { 342 xErrValue = PS_MAX(0.005, rawStar->dMag); 343 } 344 if (isfinite(rawStar->chip->yErr) && (rawStar->chip->yErr > 0.0)) { 345 yErrValue = rawStar->chip->yErr; 346 } else { 347 yErrValue = PS_MAX(0.005, rawStar->dMag); 348 } 349 350 psVectorAppend (xErr, xErrValue); 351 psVectorAppend (yErr, yErrValue); 352 psVectorAppend (xResGood, xRes->data.F32[i]); 353 psVectorAppend (yResGood, yRes->data.F32[i]); 354 } 355 356 results->dXsys = psVectorSystematicError (xResGood, xErr, 0.05); 357 results->dYsys = psVectorSystematicError (yResGood, yErr, 0.05); 358 359 results->dXrange = pmAstromVectorRange (xResGood, 0.1, 0.9, results->xStats->clippedStdev); 360 results->dYrange = pmAstromVectorRange (yResGood, 0.1, 0.9, results->yStats->clippedStdev); 361 362 psTrace ("psModules.astrom", 3, "dXsys: %f, dXrange: %f\n", results->dXsys, results->dXrange); 363 psTrace ("psModules.astrom", 3, "dYsys: %f, dYrange: %f\n", results->dYsys, results->dYrange); 364 365 psFree (xErr); 366 psFree (yErr); 367 psFree (xRes); 368 psFree (yRes); 369 psFree (xResGood); 370 psFree (yResGood); 302 371 303 372 psFree (x); … … 311 380 } 312 381 382 // set the bin closest to the corresponding value. if USE_END is +/- 1, 383 // out-of-range saturates on lower/upper bin REGARDLESS of actual value 384 #define PS_BIN_FOR_VALUE(RESULT, VECTOR, VALUE, USE_END) { \ 385 psVectorBinaryDisectResult result; \ 386 psScalar tmpScalar; \ 387 tmpScalar.type.type = PS_TYPE_F32; \ 388 tmpScalar.data.F32 = (VALUE); \ 389 RESULT = psVectorBinaryDisect (&result, VECTOR, &tmpScalar); \ 390 switch (result) { \ 391 case PS_BINARY_DISECT_PASS: \ 392 break; \ 393 case PS_BINARY_DISECT_OUTSIDE_RANGE: \ 394 psTrace("psModules.astrom", 6, "selected bin outside range"); \ 395 if (USE_END == -1) { RESULT = 0; } \ 396 if (USE_END == +1) { RESULT = VECTOR->n - 1; } \ 397 break; \ 398 case PS_BINARY_DISECT_INVALID_INPUT: \ 399 case PS_BINARY_DISECT_INVALID_TYPE: \ 400 psAbort ("programming error"); \ 401 break; \ 402 } } 403 404 # define PS_BIN_INTERPOLATE(RESULT, VECTOR, BOUNDS, BIN, VALUE) { \ 405 float dX, dY, Xo, Yo, Xt; \ 406 if (BIN == BOUNDS->n - 1) { \ 407 dX = 0.5*(BOUNDS->data.F32[BIN+1] - BOUNDS->data.F32[BIN-1]); \ 408 dY = VECTOR->data.F32[BIN] - VECTOR->data.F32[BIN-1]; \ 409 Xo = 0.5*(BOUNDS->data.F32[BIN+1] + BOUNDS->data.F32[BIN]); \ 410 Yo = VECTOR->data.F32[BIN]; \ 411 } else { \ 412 dX = 0.5*(BOUNDS->data.F32[BIN+2] - BOUNDS->data.F32[BIN]); \ 413 dY = VECTOR->data.F32[BIN+1] - VECTOR->data.F32[BIN]; \ 414 Xo = 0.5*(BOUNDS->data.F32[BIN+1] + BOUNDS->data.F32[BIN]); \ 415 Yo = VECTOR->data.F32[BIN]; \ 416 } \ 417 if (dY != 0) { \ 418 Xt = (VALUE - Yo)*dX/dY + Xo; \ 419 } else { \ 420 Xt = Xo; \ 421 } \ 422 Xt = PS_MIN (BOUNDS->data.F32[BIN+1], PS_MAX(BOUNDS->data.F32[BIN], Xt)); \ 423 psTrace("psModules.astrom", 6, "(Xo, Yo, dX, dY, Xt, Yt) is (%.2f %.2f %.2f %.2f %.2f %.2f)\n", \ 424 Xo, Yo, dX, dY, Xt, VALUE); \ 425 RESULT = Xt; } 426 427 float pmAstromVectorRange (psVector *myVector, float minFrac, float maxFrac, float stdevGuess) { 428 429 psStats *stats = psStatsAlloc(PS_STAT_MIN | PS_STAT_MAX); // Statistics for min and max 430 psHistogram *histogram = NULL; // Histogram of the data 431 psHistogram *cumulative = NULL; // Cumulative histogram of the data 432 float min = NAN, max = NAN; // Mimimum and maximum values 433 434 // Get the minimum and maximum values 435 if (!psVectorStats(stats, myVector, NULL, NULL, 0)) { 436 psFree(stats); 437 return NAN; 438 } 439 min = stats->min; 440 max = stats->max; 441 if (isnan(min) || isnan(max)) { 442 psFree(stats); 443 return NAN; 444 } 445 446 psTrace("psModules.astrom", 5, "Data min/max is (%.2f, %.2f)\n", min, max); 447 448 // If all data points have the same value, then we set the appropriate members of stats and return. 449 if (fabs(max - min) <= FLT_EPSILON) { 450 psFree (stats); 451 return 0.0; 452 } 453 454 // Define the histogram bin size. 455 float binSize = 0.001; 456 long numBins = PS_MAX(PS_MIN(100000, (max - min) / binSize), 2); // Number of bins 457 psTrace("psModules.astrom", 5, "Numbins is %ld\n", numBins); 458 psTrace("psModules.astrom", 5, "Creating a robust histogram from data range (%.2f - %.2f)\n", min, max); 459 460 // allocate the histogram containers 461 histogram = psHistogramAlloc(min, max, numBins); 462 cumulative = psHistogramAlloc(min, max, numBins); 463 464 if (!psVectorHistogram(histogram, myVector, NULL, NULL, 0)) { 465 // if psVectorHistogram returns false, we have a programming error 466 psAbort ("Unable to generate histogram"); 467 } 468 if (psTraceGetLevel("psModules.astrom") >= 8) { 469 PS_VECTOR_PRINT_F32(histogram->bounds); 470 PS_VECTOR_PRINT_F32(histogram->nums); 471 } 472 473 // Convert the specific histogram to a cumulative histogram 474 // The cumulative histogram data points correspond to the UPPER bound value (N < Bin[i+1]) 475 cumulative->nums->data.F32[0] = histogram->nums->data.F32[0]; 476 for (long i = 1; i < histogram->nums->n; i++) { 477 cumulative->nums->data.F32[i] = cumulative->nums->data.F32[i-1] + histogram->nums->data.F32[i]; 478 cumulative->bounds->data.F32[i-1] = histogram->bounds->data.F32[i]; 479 } 480 if (psTraceGetLevel("psModules.astrom") >= 8) { 481 PS_VECTOR_PRINT_F32(cumulative->bounds); 482 PS_VECTOR_PRINT_F32(cumulative->nums); 483 } 484 485 // Find the bin which contains the first data point above the limit 486 long totalDataPoints = cumulative->nums->data.F32[numBins - 1]; 487 psTrace("psModules.astrom", 6, "Total data points is %ld\n", totalDataPoints); 488 489 // find bin which is the lower bound of the limit value (value[bin] < f < value[bin+1] 490 long binMin; 491 PS_BIN_FOR_VALUE(binMin, cumulative->nums, minFrac * totalDataPoints, 0); 492 psTrace("psModules.astrom", 6, "The bin is %ld (%.4f to %.4f)\n", binMin, cumulative->bounds->data.F32[binMin], cumulative->bounds->data.F32[binMin+1]); 493 494 // Linear interpolation to the limit value in bin units 495 float valueMin; 496 PS_BIN_INTERPOLATE (valueMin, cumulative->nums, cumulative->bounds, binMin, totalDataPoints * minFrac); 497 psTrace("psModules.astrom", 6, "limit value is %f\n", valueMin); 498 499 // find bin which is the lower bound of the limit value (value[bin] < f < value[bin+1] 500 long binMax; 501 PS_BIN_FOR_VALUE(binMax, cumulative->nums, maxFrac * totalDataPoints, 0); 502 psTrace("psModules.astrom", 6, "The bin is %ld (%.4f to %.4f)\n", binMax, cumulative->bounds->data.F32[binMax], cumulative->bounds->data.F32[binMax+1]); 503 504 // Linear interpolation to the limit value in bin units 505 float valueMax; 506 PS_BIN_INTERPOLATE (valueMax, cumulative->nums, cumulative->bounds, binMax, totalDataPoints * maxFrac); 507 psTrace("psModules.astrom", 6, "limit value is %f\n", valueMax); 508 509 // Clean up 510 psFree(histogram); 511 psFree(cumulative); 512 psFree(stats); 513 514 return (valueMax - valueMin); 515 } 313 516 314 517 /****************************************************************************** … … 634 837 } 635 838 636 # if 0 637 char line[16]; 638 psFits *fits = psFitsOpen ("grid.image.fits", "w"); 639 psFitsWriteImage (fits, NULL, gridNP, 0, NULL); 640 psFitsClose (fits); 641 fprintf (stderr, "wrote grid image, press return to continue\n"); 642 fgets (line, 15, stdin); 643 # endif 839 if (psTraceGetLevel("psModules.astrom") >= 5) { 840 char line[16]; 841 psFits *fits = psFitsOpen ("grid.image.fits", "w"); 842 psFitsWriteImage (fits, NULL, gridNP, 0, NULL); 843 psFitsClose (fits); 844 fprintf (stderr, "wrote grid image, press return to continue\n"); 845 if (!fgets (line, 15, stdin)) { 846 fprintf(stderr, "Error waiting for RETURN."); 847 } 848 } 644 849 645 850 // only check bins with at least 1/2 of max bin 646 851 // XXX requiring at least 3 matches in bin 647 852 int minNpts = PS_MAX (0.5*imStats->max, 5); 648 psTrace("psModule.astrom", 5, "minNpts: %d, min: %d, max: %d, median: %f, stdev: %f", minNpts, (int)(imStats->min), (int)(imStats->max), imStats->sampleMedian, imStats->sampleStdev);853 psTrace("psModule.astrom", 4, "minNpts: %d, min: %d, max: %d, median: %f, stdev: %f", minNpts, (int)(imStats->min), (int)(imStats->max), imStats->sampleMedian, imStats->sampleStdev); 649 854 650 855 // find the 'best' bin … … 687 892 688 893 // XXX this function is crashing 689 // pmAstromVisualPlotGridMatch(raw, ref, gridNP, stats->offset.x, stats->offset.y, maxOffpix, Scale, Offset); 894 pmAstromVisualPlotGridMatch(raw, ref, gridNP, stats->offset.x, stats->offset.y, maxOffpix, Scale, Offset); 895 pmAstromVisualPlotGridMatchOverlay(raw, ref); 690 896 691 897 psFree (imStats); … … 962 1168 */ 963 1169 1170 /*****************************************************************************/ 1171 static void pmAstromMatchInfoFree (pmAstromMatchInfo *info) 1172 { 1173 if (info == NULL) return; 1174 return; 1175 } 1176 1177 1178 /*****************************************************************************/ 1179 pmAstromMatchInfo *pmAstromMatchInfoAlloc() 1180 { 1181 pmAstromMatchInfo *info = psAlloc (sizeof(pmAstromMatchInfo)); 1182 psMemSetDeallocator(info, (psFreeFunc) pmAstromMatchInfoFree); 1183 1184 info->match = NULL; 1185 info->radius = NAN; 1186 1187 return (info); 1188 } 1189 1190 // generate a unique set of matches (choose closest match) 1191 psArray *pmAstromRadiusMatchUniq (psArray *rawstars, psArray *refstars, psArray *matches) { 1192 1193 // I have the matches between the refstars and the rawstars. 1194 // For each refstar, find the single match which has the smallest radius and reject 1195 // all others. 1196 1197 // create an array of refstars->n arrays, each containing all of the matches for the 1198 // given refstar. 1199 1200 psArray *refstarMatches = psArrayAlloc (refstars->n); 1201 1202 for (int i = 0; i < matches->n; i++) { 1203 1204 pmAstromMatch *match = matches->data[i]; 1205 1206 // accumulate this refstar match on the array for this refstar (create if needed) 1207 psArray *refSet = refstarMatches->data[match->ref]; 1208 if (!refSet) { 1209 refstarMatches->data[match->ref] = psArrayAllocEmpty (8); 1210 refSet = refstarMatches->data[match->ref]; 1211 } 1212 1213 pmAstromMatchInfo *matchInfo = pmAstromMatchInfoAlloc(); 1214 1215 pmAstromObj *refStar = refstars->data[match->ref]; 1216 pmAstromObj *rawStar = rawstars->data[match->raw]; 1217 1218 matchInfo->match = match; // reference to the match of interest 1219 matchInfo->radius = hypot (refStar->FP->x - rawStar->FP->x, refStar->FP->y - rawStar->FP->y); 1220 1221 psArrayAdd (refSet, 8, matchInfo); // matchInfo->match is just a reference 1222 psFree (matchInfo); 1223 } 1224 1225 // we now have a set of matches for each refstar and their distances; create a new set 1226 // keeping only the closest entry for each match 1227 1228 psArray *unique = psArrayAllocEmpty (PS_MAX(16, matches->n / 2)); 1229 for (int i = 0; i < refstars->n; i++) { 1230 1231 psArray *refSet = refstarMatches->data[i]; 1232 if (!refSet) continue; 1233 if (refSet->n == 0) continue; // not certain how this can happen... 1234 1235 if (refSet->n == 1) { 1236 pmAstromMatchInfo *matchInfo = refSet->data[0]; 1237 psArrayAdd (unique, 32, matchInfo->match); 1238 continue; 1239 } 1240 1241 pmAstromMatchInfo *matchInfo = refSet->data[0]; 1242 float minRadius = matchInfo->radius; 1243 pmAstromMatch *minMatch = matchInfo->match; 1244 for (int j = 1; j < refSet->n; j++) { 1245 pmAstromMatchInfo *matchInfo = refSet->data[j]; 1246 if (minRadius < matchInfo->radius) continue; 1247 minMatch = matchInfo->match; 1248 minRadius = matchInfo->radius; 1249 } 1250 1251 psArrayAdd (unique, 32, minMatch); // minMatch is just a reference to a match on matches, 1252 } 1253 1254 psLogMsg ("psModules.astrom", 3, "generate unique matches to reference stars: %ld matches -> %ld matches\n", matches->n, unique->n); 1255 psFree (refstarMatches); 1256 1257 return unique; 1258 } -
branches/simtest_nebulous_branches/psModules/src/astrom/pmAstrometryObjects.h
r24021 r27840 54 54 typedef struct 55 55 { 56 int raw; ///< What is this?57 int ref; ///< What is this?56 int raw; ///< reference to the rawstar entry 57 int ref; ///< reference to the refstar entry 58 58 } 59 59 pmAstromMatch; 60 61 62 /* 63 * The pmAstromMatchInfo structure is used to generate a unique set of matches 64 */ 65 typedef struct 66 { 67 pmAstromMatch *match; ///< reference to the match 68 float radius; ///< distance between the object 69 } 70 pmAstromMatchInfo; 60 71 61 72 … … 85 96 int nMatch; ///< 86 97 double nSigma; ///< 98 double dXsys; ///< systematic error in X 99 double dYsys; ///< systematic error in Y 100 double dXrange; ///< 10% - 90% range X residuals (unmasked, high S/N) 101 double dYrange; ///< 10% - 90% range Y residuals (unmasked, high S/N) 87 102 } 88 103 pmAstromFitResults; … … 121 136 ); 122 137 138 psArray *pmAstromRadiusMatchUniq (psArray *refstars, psArray *rawstars, psArray *matches); 123 139 124 140 pmAstromStats *pmAstromStatsAlloc(void); … … 343 359 ); 344 360 361 float pmAstromVectorRange (psVector *myVector, float minFrac, float maxFrac, float stdevGuess); 362 345 363 /// @} 346 364 #endif // PM_ASTROMETRY_OBJECTS_H -
branches/simtest_nebulous_branches/psModules/src/astrom/pmAstrometryVisual.c
r24818 r27840 450 450 451 451 graphdata.color = KapaColorByName ("red"); 452 graphdata.style = 1;452 graphdata.style = 0; 453 453 454 454 //overplot clumpy regions excluded from analysis … … 905 905 KapaPlotVector (kapa, gridNP->numCols, horizontalIndices, "x"); 906 906 KapaPlotVector (kapa, gridNP->numCols, horizHistSlice, "y"); 907 907 908 float xslice[2] = {offsetX - Scale / 2., offsetX - Scale / 2.}; 908 909 float yslice[2] = {-5, 100}; 910 graphdata.style = 0; 909 911 graphdata.color = KapaColorByName("red"); 910 912 KapaPrepPlot(kapa, 2, &graphdata); … … 927 929 KapaPlotVector (kapa, gridNP->numRows, vertHistSlice, "x"); 928 930 KapaPlotVector (kapa, gridNP->numRows, verticalIndices, "y"); 931 929 932 yslice[0] = yslice[1] = offsetY - Scale / 2.; 930 933 xslice[0] = -5; xslice[1] = 100; 934 graphdata.style = 0; 931 935 graphdata.color = KapaColorByName("red"); 932 936 KapaPrepPlot(kapa, 2, &graphdata); … … 940 944 } // end of pmAstromVisualPlotGridMatch 941 945 946 947 bool pmAstromVisualPlotGridMatchOverlay (const psArray *raw, 948 const psArray *ref) 949 { 950 //make sure we want to plot this 951 if (!pmVisualIsVisual() || !plotGridMatch) return true; 952 if (!pmVisualInitWindow(&kapa2, "psastro:plots")){ 953 return false; 954 } 955 956 Graphdata graphdata; 957 psVector *xPlot = psVectorAlloc (PS_MAX(raw->n, ref->n), PS_TYPE_F32); // x data points 958 psVector *yPlot = psVectorAlloc (PS_MAX(raw->n, ref->n), PS_TYPE_F32); // y data points 959 psVector *zPlot = psVectorAlloc (PS_MAX(raw->n, ref->n), PS_TYPE_F32); // y data points 960 961 // set up plot information 962 KapaClearPlots(kapa2); 963 KapaInitGraph(&graphdata); 964 965 KapaSetFont(kapa2, "helvetica", 14); 966 KapaBox(kapa2, &graphdata); 967 KapaSendLabel (kapa2, "X (FP)", KAPA_LABEL_XM); 968 KapaSendLabel (kapa2, "Y (FP)", KAPA_LABEL_YM); 969 KapaSendLabel (kapa2, "pmAstromGridAngle residuals. Box: Correlation Peak.", KAPA_LABEL_XP); 970 971 // plot the REF data. (also calculate the plot ranges, accumulate the plot vectors) 972 graphdata.xmin = +INT_MAX; 973 graphdata.xmax = -INT_MAX; 974 graphdata.ymin = +INT_MAX; 975 graphdata.ymax = -INT_MAX; 976 for (int i = 0; i < ref->n; i++) { 977 pmAstromObj *obj = ref->data[i]; 978 graphdata.xmin = PS_MIN(graphdata.xmin, obj->FP->x); 979 graphdata.xmax = PS_MAX(graphdata.xmax, obj->FP->x); 980 graphdata.ymin = PS_MIN(graphdata.ymin, obj->FP->y); 981 graphdata.ymax = PS_MAX(graphdata.ymax, obj->FP->y); 982 xPlot->data.F32[i] = obj->FP->x; 983 yPlot->data.F32[i] = obj->FP->y; 984 zPlot->data.F32[i] = obj->Mag; 985 } 986 xPlot->n = yPlot->n = zPlot->n = ref->n; 987 KapaSetLimits(kapa2, &graphdata); 988 989 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN); 990 psVectorStats (stats, zPlot, NULL, NULL, 0); 991 float zero = stats->sampleMedian + 3.0; 992 float range = 6.0; 993 994 for (int i = 0; i < zPlot->n; i++) { 995 float value = (zero - zPlot->data.F32[i]) / range; 996 zPlot->data.F32[i] = PS_MAX(0.0, PS_MIN(1.0, value)); 997 } 998 999 // the point size will be scaled from the z vector 1000 graphdata.style = 2; 1001 graphdata.ptype = 7; 1002 graphdata.size = -1; 1003 graphdata.color = KapaColorByName ("black"); 1004 1005 KapaPrepPlot (kapa2, xPlot->n, &graphdata); 1006 KapaPlotVector (kapa2, xPlot->n, xPlot->data.F32, "x"); 1007 KapaPlotVector (kapa2, yPlot->n, yPlot->data.F32, "y"); 1008 KapaPlotVector (kapa2, zPlot->n, zPlot->data.F32, "z"); 1009 1010 // plot the RAW data (keep previous limits) 1011 for (int i = 0; i < raw->n; i++) { 1012 pmAstromObj *obj = raw->data[i]; 1013 xPlot->data.F32[i] = obj->FP->x; 1014 yPlot->data.F32[i] = obj->FP->y; 1015 zPlot->data.F32[i] = obj->Mag; 1016 } 1017 xPlot->n = yPlot->n = zPlot->n = raw->n; 1018 1019 psStatsInit(stats); 1020 psVectorStats (stats, zPlot, NULL, NULL, 0); 1021 zero = stats->sampleMedian + 3.0; 1022 range = 6.0; 1023 1024 for (int i = 0; i < zPlot->n; i++) { 1025 float value = (zero - zPlot->data.F32[i]) / range; 1026 zPlot->data.F32[i] = PS_MAX(0.0, PS_MIN(1.0, value)); 1027 } 1028 1029 // the point size will be scaled from the z vector 1030 graphdata.style = 2; 1031 graphdata.ptype = 7; 1032 graphdata.size = -1; 1033 graphdata.color = KapaColorByName ("red"); 1034 1035 KapaPrepPlot (kapa2, xPlot->n, &graphdata); 1036 KapaPlotVector (kapa2, xPlot->n, xPlot->data.F32, "x"); 1037 KapaPlotVector (kapa2, yPlot->n, yPlot->data.F32, "y"); 1038 KapaPlotVector (kapa2, zPlot->n, zPlot->data.F32, "z"); 1039 1040 pmVisualAskUser(&plotGridMatch); 1041 psFree(xPlot); 1042 psFree(yPlot); 1043 psFree(zPlot); 1044 psFree(stats); 1045 return true; 1046 } 942 1047 943 1048 bool pmAstromVisualPlotTweak (psVector *xHist, // Smoothed Horizontal cut through the histogram … … 1209 1314 KapaClearPlots (kapa2); 1210 1315 1211 graphdata.color = KapaColorByName ("black"); 1212 graphdata.ptype = 2; 1316 KapaSendLabel (kapa2, "X", KAPA_LABEL_XM); 1317 KapaSendLabel (kapa2, "Y", KAPA_LABEL_YM); 1318 KapaSendLabel (kapa2, "Chip Coordinates. Black = Raw Stars. Red = Ref Stars. Blue = Matched Stars", KAPA_LABEL_XP); 1319 1320 // X vs Y by mag (ref) 1321 graphdata.color = KapaColorByName ("red"); 1322 graphdata.ptype = 7; 1213 1323 graphdata.style = 2; 1214 1324 … … 1217 1327 psFree (zVec); 1218 1328 1219 xVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);1220 yVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);1221 zVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);1222 1223 // X vs Y by mag (raw)1224 n = 0;1225 for (int i = 0; i < rawstars->n; i++) {1226 pmAstromObj *raw = rawstars->data[i];1227 if (!isfinite(raw->Mag)) continue;1228 if (raw->Mag < iMagMin) continue;1229 if (raw->Mag > iMagMax) continue;1230 1231 xVec->data.F32[n] = raw->chip->x;1232 yVec->data.F32[n] = raw->chip->y;1233 zVec->data.F32[n] = raw->Mag;1234 n++;1235 }1236 xVec->n = yVec->n = zVec->n = n;1237 1238 KapaSendLabel (kapa2, "X", KAPA_LABEL_XM);1239 KapaSendLabel (kapa2, "Y", KAPA_LABEL_YM);1240 KapaSendLabel (kapa2,1241 "Chip Coordinates. Black = Raw Stars. Red = Ref Stars. Blue = Matched Stars"1242 , KAPA_LABEL_XP);1243 pmVisualTriplePlot (kapa2, &graphdata, xVec, yVec, zVec, false);1244 1245 // X vs Y by mag (ref)1246 psFree (xVec);1247 psFree (yVec);1248 psFree (zVec);1249 1250 1329 xVec = psVectorAlloc (refstars->n, PS_TYPE_F32); 1251 1330 yVec = psVectorAlloc (refstars->n, PS_TYPE_F32); 1252 1331 zVec = psVectorAlloc (refstars->n, PS_TYPE_F32); 1253 1254 graphdata.color = KapaColorByName ("red");1255 graphdata.ptype = 7;1256 graphdata.style = 2;1257 1332 1258 1333 n = 0; … … 1269 1344 } 1270 1345 xVec->n = yVec->n = zVec->n = n; 1271 pmVisualTriple Overplot (kapa2, &graphdata, xVec, yVec, zVec, false);1346 pmVisualTriplePlot (kapa2, &graphdata, xVec, yVec, zVec, false); 1272 1347 1273 1348 //rescale the graph to include all points … … 1282 1357 graphdata.ymax = PS_MAX(ymax, graphdata.ymax); 1283 1358 KapaSetLimits (kapa2, &graphdata); 1359 1360 bool plotTweak; 1361 pmVisualAskUser(&plotTweak); 1362 1363 // X vs Y by mag (raw) 1364 graphdata.color = KapaColorByName ("black"); 1365 graphdata.ptype = 2; 1366 graphdata.style = 2; 1367 1368 psFree (xVec); 1369 psFree (yVec); 1370 psFree (zVec); 1371 1372 xVec = psVectorAlloc (rawstars->n, PS_TYPE_F32); 1373 yVec = psVectorAlloc (rawstars->n, PS_TYPE_F32); 1374 zVec = psVectorAlloc (rawstars->n, PS_TYPE_F32); 1375 1376 n = 0; 1377 for (int i = 0; i < rawstars->n; i++) { 1378 pmAstromObj *raw = rawstars->data[i]; 1379 if (!isfinite(raw->Mag)) continue; 1380 if (raw->Mag < iMagMin) continue; 1381 if (raw->Mag > iMagMax) continue; 1382 1383 xVec->data.F32[n] = raw->chip->x; 1384 yVec->data.F32[n] = raw->chip->y; 1385 zVec->data.F32[n] = raw->Mag; 1386 n++; 1387 } 1388 xVec->n = yVec->n = zVec->n = n; 1389 pmVisualTripleOverplot (kapa2, &graphdata, xVec, yVec, zVec, false); 1284 1390 1285 1391 //overplot matched stars in blue -
branches/simtest_nebulous_branches/psModules/src/astrom/pmAstrometryVisual.h
r23487 r27840 45 45 ); 46 46 47 48 bool pmAstromVisualPlotGridMatchOverlay (const psArray *raw, 49 const psArray *ref); 47 50 48 51 /** -
branches/simtest_nebulous_branches/psModules/src/astrom/pmAstrometryWCS.c
r24052 r27840 289 289 // test the CDELTi varient 290 290 if (pcKeys) { 291 wcs->wcsCDkeys = 0; 291 292 wcs->cdelt1 = psMetadataLookupF64 (&status, header, "CDELT1"); 292 293 wcs->cdelt2 = psMetadataLookupF64 (&status, header, "CDELT2"); … … 334 335 // test the CDi_j varient 335 336 if (cdKeys) { 337 wcs->wcsCDkeys = 1; 338 336 339 wcs->trans->x->coeff[1][0] = psMetadataLookupF64 (&status, header, "CD1_1"); // == PC1_1 337 340 wcs->trans->x->coeff[0][1] = psMetadataLookupF64 (&status, header, "CD1_2"); // == PC1_2 … … 375 378 // XXX make it optional to write out CDi_j terms, or other versions 376 379 // apply CDELT1,2 (degrees / pixel) to yield PCi,j terms of order unity 377 double cdelt1 = wcs->cdelt1; 378 double cdelt2 = wcs->cdelt2; 379 psMetadataAddF64 (header, PS_LIST_TAIL, "CDELT1", PS_META_REPLACE, "", cdelt1); 380 psMetadataAddF64 (header, PS_LIST_TAIL, "CDELT2", PS_META_REPLACE, "", cdelt2); 381 382 // test the PC00i00j varient: 383 psMetadataAddF64 (header, PS_LIST_TAIL, "PC001001", PS_META_REPLACE, "", wcs->trans->x->coeff[1][0] / cdelt1); // == PC1_1 384 psMetadataAddF64 (header, PS_LIST_TAIL, "PC001002", PS_META_REPLACE, "", wcs->trans->x->coeff[0][1] / cdelt2); // == PC1_2 385 psMetadataAddF64 (header, PS_LIST_TAIL, "PC002001", PS_META_REPLACE, "", wcs->trans->y->coeff[1][0] / cdelt1); // == PC2_1 386 psMetadataAddF64 (header, PS_LIST_TAIL, "PC002002", PS_META_REPLACE, "", wcs->trans->y->coeff[0][1] / cdelt2); // == PC2_2 387 388 // Elixir-style polynomial terms 389 // XXX currently, Elixir/DVO cannot accept mixed orders 390 // XXX need to respect the masks 391 // XXX is wcs->cdelt1,2 always consistent? 392 int fitOrder = wcs->trans->x->nX; 393 if (fitOrder > 1) { 380 if (!wcs->wcsCDkeys) { 381 382 double cdelt1 = wcs->cdelt1; 383 double cdelt2 = wcs->cdelt2; 384 psMetadataAddF64 (header, PS_LIST_TAIL, "CDELT1", PS_META_REPLACE, "", cdelt1); 385 psMetadataAddF64 (header, PS_LIST_TAIL, "CDELT2", PS_META_REPLACE, "", cdelt2); 386 387 // test the PC00i00j varient: 388 psMetadataAddF64 (header, PS_LIST_TAIL, "PC001001", PS_META_REPLACE, "", wcs->trans->x->coeff[1][0] / cdelt1); // == PC1_1 389 psMetadataAddF64 (header, PS_LIST_TAIL, "PC001002", PS_META_REPLACE, "", wcs->trans->x->coeff[0][1] / cdelt2); // == PC1_2 390 psMetadataAddF64 (header, PS_LIST_TAIL, "PC002001", PS_META_REPLACE, "", wcs->trans->y->coeff[1][0] / cdelt1); // == PC2_1 391 psMetadataAddF64 (header, PS_LIST_TAIL, "PC002002", PS_META_REPLACE, "", wcs->trans->y->coeff[0][1] / cdelt2); // == PC2_2 392 393 // Elixir-style polynomial terms 394 // XXX currently, Elixir/DVO cannot accept mixed orders 395 // XXX need to respect the masks 396 // XXX is wcs->cdelt1,2 always consistent? 397 int fitOrder = wcs->trans->x->nX; 398 if (fitOrder > 1) { 394 399 for (int i = 0; i <= fitOrder; i++) { 395 for (int j = 0; j <= fitOrder; j++) {396 if (i + j < 2)397 continue;398 if (i + j > fitOrder)399 continue;400 sprintf (name, "PCA1X%1dY%1d", i, j);401 psMetadataAddF64 (header, PS_LIST_TAIL, name, PS_META_REPLACE, "", wcs->trans->x->coeff[i][j] / pow(cdelt1, i) / pow(cdelt2, j));402 sprintf (name, "PCA2X%1dY%1d", i, j);403 psMetadataAddF64 (header, PS_LIST_TAIL, name, PS_META_REPLACE, "", wcs->trans->y->coeff[i][j] / pow(cdelt1, i) / pow(cdelt2, j));404 }400 for (int j = 0; j <= fitOrder; j++) { 401 if (i + j < 2) 402 continue; 403 if (i + j > fitOrder) 404 continue; 405 sprintf (name, "PCA1X%1dY%1d", i, j); 406 psMetadataAddF64 (header, PS_LIST_TAIL, name, PS_META_REPLACE, "", wcs->trans->x->coeff[i][j] / pow(cdelt1, i) / pow(cdelt2, j)); 407 sprintf (name, "PCA2X%1dY%1d", i, j); 408 psMetadataAddF64 (header, PS_LIST_TAIL, name, PS_META_REPLACE, "", wcs->trans->y->coeff[i][j] / pow(cdelt1, i) / pow(cdelt2, j)); 409 } 405 410 } 406 411 psMetadataAddS32 (header, PS_LIST_TAIL, "NPLYTERM", PS_META_REPLACE, "", fitOrder); 407 }408 409 // remove any existing 'CDi_j style' wcs keywords410 if (psMetadataLookup(header, "CD1_1")) {412 } 413 414 // remove any existing 'CDi_j style' wcs keywords 415 if (psMetadataLookup(header, "CD1_1")) { 411 416 psMetadataRemoveKey(header, "CD1_1"); 412 417 psMetadataRemoveKey(header, "CD1_2"); 413 418 psMetadataRemoveKey(header, "CD2_1"); 414 419 psMetadataRemoveKey(header, "CD2_2"); 420 } 421 } else { 422 423 psMetadataAddF64 (header, PS_LIST_TAIL, "CD1_1", PS_META_REPLACE, "", wcs->trans->x->coeff[1][0]); 424 psMetadataAddF64 (header, PS_LIST_TAIL, "CD1_2", PS_META_REPLACE, "", wcs->trans->x->coeff[0][1]); 425 psMetadataAddF64 (header, PS_LIST_TAIL, "CD2_1", PS_META_REPLACE, "", wcs->trans->y->coeff[1][0]); 426 psMetadataAddF64 (header, PS_LIST_TAIL, "CD2_2", PS_META_REPLACE, "", wcs->trans->y->coeff[0][1]); 427 428 if (psMetadataLookup(header, "PC001001")) { 429 psMetadataRemoveKey(header, "PC001001"); 430 psMetadataRemoveKey(header, "PC001002"); 431 psMetadataRemoveKey(header, "PC002001"); 432 psMetadataRemoveKey(header, "PC002002"); 433 } 415 434 } 416 435 … … 535 554 fpa->toSky->R -= 2.0*M_PI; 536 555 556 fpa->wcsCDkeys = wcs->wcsCDkeys; 557 537 558 psTrace ("psastro", 5, "toFPA: %f %f (%f,%f),(%f,%f)\n", 538 559 chip->toFPA->x->coeff[0][0], chip->toFPA->y->coeff[0][0], … … 648 669 wcs->crval2 = fpa->toSky->D*PS_DEG_RAD; 649 670 671 // generate a transform that has 0.0 rotation: 672 // get the current posangle of the ref chip 673 // XXX average angles for x and y... 674 float angle = atan2 (toTPA->y->coeff[1][0], toTPA->x->coeff[1][0]); 675 // fprintf (stderr, "angle: %f\n", angle*PS_DEG_RAD); 676 psPlaneTransform *tpa1 = psPlaneTransformRotate (NULL, toTPA, angle); 677 650 678 // given transformation, solve for coordinates which yields output coordinates of 0,0 651 psPlane *center = psPlaneTransformGetCenter (t oTPA, tol);679 psPlane *center = psPlaneTransformGetCenter (tpa1, tol); 652 680 if (!center) { 653 681 psError(PS_ERR_UNKNOWN, false, "Unable to solve for TPA center."); … … 657 685 } 658 686 687 // generate transform with the original orientation (does this rotate about 'center'?) 688 psPlaneTransform *tpa2 = psPlaneTransformRotate (NULL, tpa1, -1.0*angle); 689 690 // prove that the center coordinates give 0,0: 691 // float Xo = psPolynomial2DEval (tpa1->x, center->x, center->y); 692 // float Yo = psPolynomial2DEval (tpa1->x, center->x, center->y); 693 // fprintf (stderr, "tpa1: Xo, Yo: %f, %f\n", Xo, Yo); 694 695 // prove that the center coordinates give 0,0: 696 // Xo = psPolynomial2DEval (tpa2->x, center->x, center->y); 697 // Yo = psPolynomial2DEval (tpa2->x, center->x, center->y); 698 // fprintf (stderr, "tpa2: Xo, Yo: %f, %f\n", Xo, Yo); 699 659 700 // create wcs transform from toFPA, resulting transformation has units of microns/pixel 660 701 // adjust wcs transform to use center as reference coordinate 661 psPlaneTransformSetCenter (wcs->trans, t oTPA, center->x, center->y);702 psPlaneTransformSetCenter (wcs->trans, tpa2, center->x, center->y); 662 703 663 704 // calculated center is crpix1,2 … … 665 706 wcs->crpix2 = center->y; 666 707 psFree (center); 708 psFree (tpa1); 709 psFree (tpa2); 667 710 668 711 // pdelt1,2 has units of degrees/micron … … 682 725 wcs->cdelt2 = hypot (wcs->trans->y->coeff[1][0], wcs->trans->y->coeff[0][1]); 683 726 727 wcs->wcsCDkeys = fpa->wcsCDkeys; 684 728 psFree (toTPA); 685 729 … … 800 844 int k=0; 801 845 for (int j=0; j<nSamples; j++) { 802 double y = j * deltaY / nSamples;846 double y = bounds->y0 + (j * deltaY / nSamples); 803 847 for (int i=0; i<nSamples; i++) { 804 848 psPlane *s = psPlaneAlloc(); 805 s->x = i * deltaX / nSamples;849 s->x = bounds->x0 + (i * deltaX / nSamples); 806 850 s->y = y; 807 851 psArraySet(src, k, s); 808 852 psPlane *d = psPlaneTransformApply(NULL, trans, s); 809 853 psArraySet(dst, k, d); 810 psFree(s); 854 psFree(s); // drop our refs to s and d 811 855 psFree(d); 812 856 ++k; … … 821 865 } 822 866 867 #define noCOMPARE_TRANS 823 868 #ifdef COMPARE_TRANS 824 869 // compare the computed coordintes from this transform with the original 825 870 psPlane *new = psPlaneAlloc(); 871 printf(" i chip_x tpa_x tpa_x_fit dx chip_y tpa_y tpa_y_fit dy dx > 0.5 || dy > 0.5\n"); 826 872 for (int i=0; i<psArrayLength(dst); i++) { 827 873 psPlane *d = (psPlane *) psArrayGet(dst, i); … … 830 876 new = psPlaneTransformApply(new, newTrans, s); 831 877 832 printf("%4d %f %f\n", i, 100.*(new->x - d->x)/d->x, 100.*(new->y - d->y)/d->y); 878 double xerr = new->x - d->x; 879 double yerr = new->y - d->y; 880 bool bigerr = (fabs(xerr) > .5) || (fabs(yerr) > .5); 881 printf("%4d %9.2f %9.2f %9.2f %9.4f %9.2f %9.2f %9.2f %9.4f %s\n" 882 , i, s->x, new->x, d->x, xerr, s->y, new->y, d->y, yerr, bigerr ? "BIGERR" : ""); 833 883 } 834 884 psFree(new); … … 842 892 } 843 893 844 bool pmAstromLinearizeTransforms(pmFPA *fpa, pmChip *chip) 845 { 846 psRegion *chipBounds = pmChipPixels(chip); 847 848 psPlaneTransform *newToFPA = linearFitToTransform(chip->toFPA, chipBounds); 849 if (!newToFPA) { 850 psFree(chipBounds); 851 psError(PS_ERR_UNKNOWN, false, "linear fit for toFPA failed"); 852 return false; 853 } 854 855 psFree(chip->toFPA); 856 chip->toFPA = newToFPA; 857 858 psFree(chip->fromFPA); 859 chip->fromFPA = psPlaneTransformInvert(NULL, chip->toFPA, *chipBounds, 50); 860 if (!chip->fromFPA) { 861 psError(PS_ERR_UNKNOWN, false, "failed to invert linear fit for toFPA"); 862 return false; 863 } 864 865 psPlane *chip0 = psPlaneAlloc(); 866 chip0->x = 0; 867 chip0->y = 0; 868 psPlane *chip1 = psPlaneAlloc(); 869 chip1->x = chipBounds->x1; 870 chip1->y = chipBounds->y1; 871 872 // compute bounding region for fpa 873 psPlane *fpa0 = psPlaneTransformApply(NULL, newToFPA, chip0); 874 psPlane *fpa1 = psPlaneTransformApply(NULL, newToFPA, chip1); 875 876 psRegion *fpaBounds = psRegionAlloc(fpa0->x, fpa1->x, fpa0->y, fpa1->y); 877 psFree(chip0); 878 psFree(chip1); 879 psFree(fpa0); 880 psFree(fpa1); 881 882 psPlaneTransform *newToTPA = linearFitToTransform(fpa->toTPA, fpaBounds); 883 if (!newToTPA) { 884 psError(PS_ERR_UNKNOWN, false, "failed to perform linear fit to toTPA"); 885 psFree(fpaBounds); 886 return false; 887 } 888 psFree(fpa->toTPA); 889 fpa->toTPA = newToTPA; 890 891 // XXX: is this region ok? 892 psFree(fpa->fromTPA); 893 fpa->fromTPA = psPlaneTransformInvert(NULL, fpa->toTPA, *fpaBounds, 50); 894 if (!fpa->fromTPA) { 895 psError(PS_ERR_UNKNOWN, false, "failed to invert linear fit to toTPA"); 896 return false; 897 } 898 899 fpa->toSky->type = PS_PROJ_TAN; 900 901 psFree(chipBounds); 902 psFree(fpaBounds); 894 bool pmAstromLinearizeTransforms(pmFPA *inFPA, pmChip *inChip, pmFPA *outFPA, pmChip *outChip, psRegion *outputBounds, double offset_x, double offset_y) 895 { 896 PS_ASSERT_PTR_NON_NULL(inFPA, NULL); 897 PS_ASSERT_PTR_NON_NULL(inChip, NULL); 898 899 if (outFPA == NULL) { 900 outFPA = inFPA; 901 } 902 if (outChip == NULL) { 903 outChip = inChip; 904 } 905 if (outputBounds == NULL) { 906 outputBounds = pmChipPixels(outChip); 907 } 908 909 // First combine the "chip to FPA" and "FPA to TPA" into a single transformation 910 psPlaneTransform *chipToTPA = psPlaneTransformCombine(NULL, inChip->toFPA, inFPA->toTPA, *outputBounds, 50); 911 if (!chipToTPA) { 912 psError(PS_ERR_UNKNOWN, false, "failed to create chipToTPA"); 913 return false; 914 } 915 916 // Next do the linear fit within the output boundary pixels 917 psPlaneTransform *chipToFPA = linearFitToTransform(chipToTPA, outputBounds); 918 psFree(chipToTPA); 919 if (!chipToFPA) { 920 psError(PS_ERR_UNKNOWN, false, "linear fit of chip to TPA transform failed"); 921 return false; 922 } 923 924 // if requested, change the center 925 psPlaneTransform *outToFPA; 926 if (offset_x != 0. && offset_y != 0.) { 927 outToFPA = psPlaneTransformSetCenter(NULL, chipToFPA, offset_x, offset_y); 928 psFree(chipToFPA); 929 } else { 930 outToFPA = chipToFPA; 931 } 932 933 psPlaneTransform *outFromFPA = psPlaneTransformInvert(NULL, outToFPA, *outputBounds, 50); 934 if (!outFromFPA) { 935 psFree(outToFPA); 936 psError(PS_ERR_UNKNOWN, false, "inversion of fit of output chip toFPA failed"); 937 return false; 938 } 939 940 // Success. Now set the fpa's toTPA and fromTPA to identity and replace the chip's transforms. 941 942 psFree(outFPA->toTPA); 943 outFPA->toTPA = psPlaneTransformIdentity(1); 944 945 psFree(outFPA->fromTPA); 946 outFPA->fromTPA = psPlaneTransformIdentity(1); 947 948 psFree(outChip->toFPA); 949 outChip->toFPA = outToFPA; 950 951 psFree(outChip->fromFPA); 952 outChip->fromFPA = outFromFPA; 953 954 // Finally, change the type for the projection. 955 outFPA->toSky->type = PS_PROJ_TAN; 956 957 return true; 958 } 959 960 bool pmAstromLinearizeToSky(pmFPA *inFPA, pmChip *inChip, pmFPA *outFPA, pmChip *outChip, psRegion *bounds) 961 { 962 PS_ASSERT_PTR_NON_NULL(inFPA, NULL); 963 PS_ASSERT_PTR_NON_NULL(inChip, NULL); 964 PS_ASSERT_PTR_NON_NULL(outFPA, NULL); 965 PS_ASSERT_PTR_NON_NULL(outChip, NULL); 966 PS_ASSERT_PTR_NON_NULL(bounds, NULL); 967 968 // outFPA projection must be defined as the goal 969 970 // the output transformations are: 971 // chip -> FPA : standard linear trans with needed rotation, etc 972 // FPA -> TPA : identidy 973 974 int nSamples = 10; // 10 samples in each dimension 975 976 double deltaX = (bounds->x1 - bounds->x0); 977 double deltaY = (bounds->y1 - bounds->y0); 978 979 psArray *src = psArrayAllocEmpty(nSamples * nSamples); 980 psArray *dst = psArrayAllocEmpty(nSamples * nSamples); 981 982 psPlane srcFP, srcTP; 983 984 for (int j = 0; j < nSamples; j++) { 985 double y = bounds->y0 + (j * deltaY / nSamples); 986 for (int i = 0; i < nSamples; i++) { 987 988 psSphere srcSky; 989 psPlane *srcChip = psPlaneAlloc(); 990 psPlane *dstTP = psPlaneAlloc(); 991 992 srcChip->x = bounds->x0 + (i * deltaX / nSamples); 993 srcChip->y = y; 994 995 psPlaneTransformApply (&srcFP, inChip->toFPA, srcChip); 996 psPlaneTransformApply (&srcTP, inFPA->toTPA, &srcFP); 997 psDeproject (&srcSky, &srcTP, inFPA->toSky); 998 999 // fprintf (stderr, "%f %f | %f %f | %f %f | %f %f\n", srcChip->x, srcChip->y, srcFP.x, srcFP.y, srcTP.x, srcTP.y, srcSky.r*PS_DEG_RAD, srcSky.d*PS_DEG_RAD); 1000 1001 psProject (dstTP, &srcSky, outFPA->toSky); 1002 1003 srcChip->x -= bounds->x0; 1004 srcChip->y -= bounds->y0; 1005 psArrayAdd (src, 100, srcChip); 1006 psArrayAdd (dst, 100, dstTP); 1007 1008 psFree(srcChip); // drop our refs to s and d 1009 psFree(dstTP); 1010 } 1011 } 1012 1013 psPlaneTransform *newToFPA = psPlaneTransformAlloc(1, 1); 1014 newToFPA->x->coeffMask[1][1] = 1; 1015 newToFPA->y->coeffMask[1][1] = 1; 1016 1017 if (!psPlaneTransformFit(newToFPA, src, dst, 0, 0)) { 1018 psError(PS_ERR_UNKNOWN, false, "linear fit to transform failed"); 1019 psFree(src); 1020 psFree(dst); 1021 return NULL; 1022 } 1023 1024 # if (0) 1025 for (int i = 0; i < src->n; i++) { 1026 1027 psSphere srcSky, dstSky; 1028 psPlane *srcChip = src->data[i]; 1029 psPlane *dstTP = dst->data[i]; 1030 1031 psPlaneTransformApply (&srcFP, newToFPA, srcChip); 1032 psDeproject (&srcSky, &srcFP, outFPA->toSky); 1033 psDeproject (&dstSky, dstTP, outFPA->toSky); 1034 1035 double dX = (srcSky.r*PS_DEG_RAD - dstSky.r*PS_DEG_RAD)*3600.0; 1036 double dY = (srcSky.d*PS_DEG_RAD - dstSky.d*PS_DEG_RAD)*3600.0; 1037 fprintf (stderr, "%f %f | %f %f | %f %f | %f %f | %f %f | %f %f\n", dX, dY, srcChip->x, srcChip->y, srcFP.x, srcFP.y, dstTP->x, dstTP->y, srcSky.r*PS_DEG_RAD, srcSky.d*PS_DEG_RAD, dstSky.r*PS_DEG_RAD, dstSky.d*PS_DEG_RAD); 1038 1039 } 1040 # endif 1041 1042 psFree(src); 1043 psFree(dst); 1044 1045 // this is a linear transformation 1046 psPlaneTransform *newFromFPA = psPlaneTransformInvert(NULL, newToFPA, *bounds, 1); 1047 if (!newFromFPA) { 1048 psFree(newToFPA); 1049 psError(PS_ERR_UNKNOWN, false, "inversion of fit of output chip toFPA failed"); 1050 return false; 1051 } 1052 1053 // Success. Now set the fpa's toTPA and fromTPA to identity and replace the chip's transforms. 1054 psFree(outChip->toFPA); 1055 outChip->toFPA = newToFPA; 1056 1057 psFree(outChip->fromFPA); 1058 outChip->fromFPA = newFromFPA; 1059 1060 psFree(outFPA->toTPA); 1061 outFPA->toTPA = psPlaneTransformIdentity(1); 1062 1063 psFree(outFPA->fromTPA); 1064 outFPA->fromTPA = psPlaneTransformIdentity(1); 903 1065 904 1066 return true; … … 922 1084 wcs->trans = psPlaneTransformAlloc (nXorder, nYorder); 923 1085 wcs->toSky = NULL; 1086 wcs->wcsCDkeys = 0; 924 1087 925 1088 memset (wcs->ctype1, 0, PM_ASTROM_WCS_TYPE_SIZE); -
branches/simtest_nebulous_branches/psModules/src/astrom/pmAstrometryWCS.h
r24766 r27840 23 23 double crpix1, crpix2; 24 24 double cdelt1, cdelt2; 25 bool wcsCDkeys; 25 26 psProjection *toSky; 26 27 psPlaneTransform *trans; … … 62 63 bool pmAstromWriteBilevelMosaic (psMetadata *header, const pmFPA *fpa, double tol); 63 64 64 bool pmAstromLinearizeTransforms(pmFPA *fpa, pmChip *); 65 bool pmAstromLinearizeTransforms(pmFPA *inFPA, pmChip *inChip, pmFPA *outFPA, pmChip *outChip, psRegion *outputBounds, double offset_x, double offset_y); 66 bool pmAstromLinearizeToSky(pmFPA *inFPA, pmChip *inChip, pmFPA *outFPA, pmChip *outChip, psRegion *bounds); 65 67 66 68 // move to pslib -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPA.c
r23740 r27840 105 105 psFree(fpa->concepts); 106 106 psFree(fpa->analysis); 107 psFree( (void *)fpa->camera);107 psFree(fpa->camera); 108 108 psFree(fpa->hdu); 109 109 … … 378 378 tmpFPA->toTPA = NULL; 379 379 tmpFPA->toSky = NULL; 380 tmpFPA->wcsCDkeys = false; 380 381 381 382 tmpFPA->analysis = psMetadataAlloc(); -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPA.h
r21363 r27840 48 48 psPlaneTransform *toTPA; ///< Transformation from focal plane to tangent plane, or NULL 49 49 psProjection *toSky; ///< Projection from tangent plane to sky, or NULL 50 bool wcsCDkeys; 50 51 // Information 51 52 psMetadata *concepts; ///< FPA-level concepts -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAMaskWeight.c
r24767 r27840 111 111 // psError(PS_ERR_IO, true, "CELL.SATURATION is not set --- unable to set mask.\n"); 112 112 // return false; 113 psWarning("CELL.SATURATION is not set --- completely masking cell.\n");114 saturation = NAN;113 psWarning("CELL.SATURATION is not set --- completely masking cell.\n"); 114 saturation = NAN; 115 115 } 116 116 float bad = psMetadataLookupF32(&mdok, cell->concepts, "CELL.BAD"); // Bad level … … 118 118 // psError(PS_ERR_IO, true, "CELL.BAD is not set --- unable to set mask.\n"); 119 119 // return false; 120 psWarning("CELL.BAD is not set --- completely masking cell.\n");121 bad = NAN;120 psWarning("CELL.BAD is not set --- completely masking cell.\n"); 121 bad = NAN; 122 122 } 123 123 psTrace("psModules.camera", 5, "Saturation: %f, bad: %f\n", saturation, bad); 124 124 125 // if CELL.GAIN or CELL.READNOISE are not set, then the variance will be set to NAN; 125 // if CELL.GAIN or CELL.READNOISE are not set, then the variance will be set to NAN; 126 126 // in this case, we have to set the mask as well 127 127 float gain = psMetadataLookupF32(&mdok, cell->concepts, "CELL.GAIN"); // Cell gain … … 140 140 // completely mask if SATURATION or BAD are invalid 141 141 if (isnan(saturation) || isnan(bad) || isnan(gain) || isnan(readnoise)) { 142 psImageInit(mask, badMask);143 return true;142 psImageInit(mask, badMask); 143 return true; 144 144 } 145 145 … … 230 230 // return false; 231 231 psWarning("CELL.GAIN is not set --- setting variance to NAN\n"); 232 gain = NAN;232 gain = NAN; 233 233 } 234 234 float readnoise = psMetadataLookupF32(&mdok, cell->concepts, "CELL.READNOISE"); // Cell read noise … … 237 237 // return false; 238 238 psWarning("CELL.READNOISE is not set --- setting variance to NAN\n"); 239 readnoise = NAN;239 readnoise = NAN; 240 240 } 241 241 // if we have a non-NAN readnoise, then we need to ensure it has been updated (not necessary if NAN) … … 248 248 if (isnan(gain) || isnan(readnoise)) { 249 249 if (!readout->variance) { 250 // generate the image if needed250 // generate the image if needed 251 251 readout->variance = psImageAlloc(readout->image->numCols, readout->image->numRows, PS_TYPE_F32); 252 252 } 253 // XXX need to set the mask, if defined253 // XXX need to set the mask, if defined 254 254 psImageInit(readout->variance, NAN); 255 return true;255 return true; 256 256 } 257 257 … … 262 262 263 263 // a negative variance is non-sensical. if the image value drops below 1, the variance must be 1. 264 // XXX this calculation is wrong: limit is 1 e-, but this is in DN264 // XXX this calculation is wrong: limit is 1 e-, but this is in DN 265 265 readout->variance = (psImage*)psUnaryOp(readout->variance, readout->variance, "abs"); 266 266 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "max", … … 276 276 // apply a supplied readnoise map (NOTE: in DN, not electrons): 277 277 if (noiseMap) { 278 psImage *rdVar = (psImage*)psBinaryOp(NULL, (const psPtr) noiseMap, "*", (const psPtr) noiseMap);279 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", rdVar);280 psFree (rdVar);278 psImage *rdVar = (psImage*)psBinaryOp(NULL, (const psPtr) noiseMap, "*", (const psPtr) noiseMap); 279 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", rdVar); 280 psFree (rdVar); 281 281 } else { 282 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", psScalarAlloc(readnoise*readnoise/gain/gain, PS_TYPE_F32));282 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", psScalarAlloc(readnoise*readnoise/gain/gain, PS_TYPE_F32)); 283 283 } 284 284 … … 362 362 363 363 364 bool pmReadoutVarianceRenorm Pixels(const pmReadout *readout, psImageMaskType maskVal,365 psStatsOptions meanStat, psStatsOptions stdevStat, psRandom *rng)364 bool pmReadoutVarianceRenormalise(const pmReadout *readout, psImageMaskType maskVal, 365 int sample, float minValid, float maxValid) 366 366 { 367 367 PM_ASSERT_READOUT_NON_NULL(readout, false); … … 370 370 371 371 psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout parts 372 373 if (!psMemIncrRefCounter(rng)) { 374 rng = psRandomAlloc(PS_RANDOM_TAUS); 375 } 376 377 psStats *varianceStats = psStatsAlloc(meanStat);// Statistics for mean 378 if (!psImageBackground(varianceStats, NULL, variance, mask, maskVal, rng)) { 379 psError(PS_ERR_UNKNOWN, false, "Unable to measure mean variance for image"); 380 psFree(varianceStats); 381 psFree(rng); 382 return false; 383 } 384 float meanVariance = varianceStats->robustMedian; // Mean variance 385 psFree(varianceStats); 386 387 psStats *imageStats = psStatsAlloc(stdevStat);// Statistics for mean 388 if (!psImageBackground(imageStats, NULL, image, mask, maskVal, rng)) { 389 psError(PS_ERR_UNKNOWN, false, "Unable to measure stdev of image"); 390 psFree(imageStats); 391 psFree(rng); 392 return false; 393 } 394 float stdevImage = imageStats->robustStdev; // Standard deviation of image 395 psFree(imageStats); 396 psFree(rng); 397 398 float correction = PS_SQR(stdevImage) / meanVariance; // Correction to take variance to what it should be 399 psLogMsg("psModules.camera", PS_LOG_INFO, "Renormalising variance map by %f", correction); 400 psBinaryOp(variance, variance, "*", psScalarAlloc(correction, PS_TYPE_F32)); 401 402 return true; 403 } 404 405 406 bool pmReadoutVarianceRenormPhot(const pmReadout *readout, psImageMaskType maskVal, int num, float width, 407 psStatsOptions meanStat, psStatsOptions stdevStat, psRandom *rng) 408 { 409 PM_ASSERT_READOUT_NON_NULL(readout, false); 410 PM_ASSERT_READOUT_IMAGE(readout, false); 411 PM_ASSERT_READOUT_VARIANCE(readout, false); 412 413 if (!psMemIncrRefCounter(rng)) { 414 rng = psRandomAlloc(PS_RANDOM_TAUS); 415 } 416 417 psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout images 418 419 // Measure background 420 psStats *bgStats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);// Statistics for background 421 if (!psImageBackground(bgStats, NULL, image, mask, maskVal, rng)) { 422 psError(PS_ERR_UNKNOWN, false, "Unable to measure background for image"); 423 psFree(bgStats); 424 psFree(rng); 425 return false; 426 } 427 float bgMean = bgStats->robustMedian; // Background level 428 float bgNoise = bgStats->robustStdev; // Background standard deviation 429 psFree(bgStats); 430 psTrace("psModules.camera", 5, "Background is %f +/- %f\n", bgMean, bgNoise); 431 432 433 // Construct kernels for flux measurement 434 // We use N(0,width) and N(0,width/sqrt(2)) kernels, following psphotSignificanceImage. 435 float sigFactor = 4.0 * M_PI * PS_SQR(width); // Factor for conversion from im/wt ratio to significance 436 int size = RENORM_NUM_SIGMA, fullSize = 2 * size + 1; // Half-size and full size of Gaussian 437 psVector *gauss = psVectorAlloc(fullSize, PS_TYPE_F32); // Gaussian for weighting 438 psVector *gauss2 = psVectorAlloc(fullSize, PS_TYPE_F32); // Gaussian squared 439 for (int i = 0, x = -size; i < fullSize; i++, x++) { 440 gauss->data.F32[i] = expf(-0.5 * PS_SQR(x) / PS_SQR(width)); 441 gauss2->data.F32[i] = expf(-PS_SQR(x) / PS_SQR(width)); 442 } 443 444 // Size of image 445 int numCols = image->numCols, numRows = image->numRows; // Size of images 446 int xSize = numCols - fullSize, ySize = numRows - fullSize; // Size of consideration 447 int xOffset = size, yOffset = size; // Offset to region of consideration 448 449 // Measure fluxes 450 float peakFlux = RENORM_PEAK * bgNoise; // Peak flux for fake sources 451 psVector *noise = psVectorAlloc(num, PS_TYPE_F32); // Measurements of the noise 452 psVector *source = psVectorAlloc(num, PS_TYPE_F32); // Measurements of fake sources 453 psVector *guess = psVectorAlloc(num, PS_TYPE_F32); // Guess at significance 454 psVector *photMask = psVectorAlloc(num, PS_TYPE_VECTOR_MASK); // Mask for fluxes 455 for (int i = 0; i < num; i++) { 456 // Coordinates of interest 457 int xPix = psRandomUniform(rng) * xSize + xOffset + 0.5; 458 int yPix = psRandomUniform(rng) * ySize + yOffset + 0.5; 459 psAssert(xPix - size >= 0 && xPix + size < numCols && 460 yPix - size >= 0 && yPix + size < numRows, 461 "Bad pixel position: %d,%d", xPix, yPix); 462 463 // Weighted aperture photometry 464 // This has the same effect as smoothing the image by the window function 465 float sumNoise = 0.0; // Sum for noise measurement 466 float sumSource = 0.0; // Sum for source measurement 467 float sumVariance = 0.0; // Sum for variance measurement 468 float sumGauss = 0.0, sumGauss2 = 0.0; // Sums of Gaussian kernels 469 for (int v = 0, y = yPix - size; v < fullSize; v++, y++) { 470 float xSumNoise = 0.0; // Sum for noise measurement in x 471 float xSumSource = 0.0; // Sum for source measurement in x 472 float xSumVariance = 0.0; // Sum for variance measurement in x 473 float xSumGauss = 0.0, xSumGauss2 = 0.0; // Sums of Gaussian kernels in x 474 float yGauss = gauss->data.F32[v]; // Value of Gaussian in y 475 for (int u = 0, x = xPix - size; u < fullSize; u++, x++) { 476 if (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) { 372 int numCols = image->numCols, numRows = image->numRows; // Size of image 373 374 int xMin, xMax, yMin, yMax; // Bounds of image 375 if (mask) { 376 xMin = numCols; 377 xMax = 0; 378 yMin = numRows; 379 yMax = 0; 380 for (int y = 0; y < numRows; y++) { 381 for (int x = 0; x < numCols; x++) { 382 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) { 477 383 continue; 478 384 } 479 float value = image->data.F32[y][x] - bgMean; // Value of image 480 float xGauss = gauss->data.F32[u]; // Value of Gaussian in x 481 float xGauss2 = gauss2->data.F32[u]; // Value of Gaussian^2 in x 482 xSumNoise += value * xGauss; 483 xSumSource += (value + peakFlux * xGauss * yGauss) * xGauss; 484 xSumVariance += variance->data.F32[y][x] * xGauss2; 485 xSumGauss += xGauss; 486 xSumGauss2 += xGauss2; 487 } 488 float yGauss2 = gauss2->data.F32[v]; // Value of Gaussian^2 in y 489 sumNoise += xSumNoise * yGauss; 490 sumSource += xSumSource * yGauss; 491 sumVariance += xSumVariance * yGauss2; 492 sumGauss += xSumGauss * yGauss; 493 sumGauss2 += xSumGauss2 * yGauss2; 494 } 495 496 photMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = ((isfinite(sumNoise) && isfinite(sumSource) && 497 isfinite(sumVariance) && sumGauss > 0 && sumGauss2 > 0) ? 498 0 : 0xFF); 499 500 float smoothImageNoise = sumNoise / sumGauss; // Value of smoothed image pixel for noise 501 float smoothImageSource = sumSource / sumGauss; // Value of smoothed image pixel for source 502 float smoothVariance = sumVariance / sumGauss2; // Value of smoothed variance pixel 503 504 noise->data.F32[i] = smoothImageNoise; 505 source->data.F32[i] = smoothImageSource; 506 guess->data.F32[i] = (sumSource > 0) ? sigFactor * PS_SQR(smoothImageSource) / smoothVariance : 0.0; 507 psTrace("psModules.camera", 10, "Flux %d (%d,%d): %f, %f, %f\n", 508 i, xPix, yPix, smoothImageNoise, smoothImageSource, smoothVariance); 509 } 510 psFree(gauss); 511 psFree(gauss2); 512 psFree(rng); 513 514 // Standard deviation of fluxes gives us the real significance 515 psStats *stdevStats = psStatsAlloc(stdevStat); // Statistics 516 if (!psVectorStats(stdevStats, noise, NULL, photMask, 0xFF)) { 517 psError(PS_ERR_UNKNOWN, false, "Unable to measure standard deviation of fluxes"); 518 psFree(stdevStats); 519 psFree(noise); 520 psFree(source); 521 psFree(guess); 522 psFree(photMask); 385 xMin = PS_MIN(xMin, x); 386 xMax = PS_MAX(xMax, x); 387 yMin = PS_MIN(yMin, y); 388 yMax = PS_MAX(yMax, y); 389 } 390 } 391 } else { 392 xMin = 0; 393 xMax = numCols; 394 yMin = 0; 395 yMax = numRows; 396 } 397 398 int xNum = xMax - xMin, yNum = yMax - yMin; // Number of pixels 399 400 int numPix = xNum * yNum; // Number of pixels 401 int num = PS_MIN(sample, numPix); // Number we care about 402 psVector *signoise = psVectorAllocEmpty(num, PS_TYPE_F32); // Signal-to-noise values 403 404 if (num >= numPix) { 405 // We have an image smaller than Nsubset, so just loop over the image pixels 406 int index = 0; // Index for vector 407 for (int y = yMin; y < yMax; y++) { 408 for (int x = xMin; x < xMax; x++) { 409 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) || 410 !isfinite(image->data.F32[y][x]) || !isfinite(variance->data.F32[y][x])) { 411 continue; 412 } 413 414 signoise->data.F32[index] = image->data.F32[y][x] / sqrtf(variance->data.F32[y][x]); 415 index++; 416 } 417 } 418 signoise->n = index; 419 } else { 420 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 421 int index = 0; // Index for vector 422 for (long i = 0; i < num; i++) { 423 // Pixel coordinates 424 int pixel = numPix * psRandomUniform(rng); 425 int x = xMin + pixel % xNum; 426 int y = yMin + pixel / xNum; 427 428 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) || 429 !isfinite(image->data.F32[y][x]) || !isfinite(variance->data.F32[y][x])) { 430 continue; 431 } 432 433 signoise->data.F32[index] = image->data.F32[y][x] / sqrtf(variance->data.F32[y][x]); 434 index++; 435 } 436 signoise->n = index; 437 psFree(rng); 438 } 439 440 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_STDEV); // Statistics 441 442 if (!psVectorStats(stats, signoise, NULL, NULL, 0)) { 443 psError(PS_ERR_UNKNOWN, false, "Unable to measure statistics on S/N image"); 444 psFree(signoise); 523 445 return false; 524 446 } 525 float stdev = psStatsGetValue(stdevStats, stdevStat); // Standard deviation of fluxes 526 psFree(stdevStats); 527 psFree(noise); 528 psTrace("psModules.camera", 5, "Standard deviation of fluxes is %f\n", stdev); 529 530 // Ratio of measured significance to guessed significance 531 psVector *ratio = psVectorAlloc(num, PS_TYPE_F32); // Ratio of measured to guess 532 for (int i = 0; i < num; i++) { 533 float measuredSig = PS_SQR(source->data.F32[i] / stdev); // Measured significance 534 ratio->data.F32[i] = measuredSig / guess->data.F32[i]; 535 if (guess->data.F32[i] <= 0.0 || source->data.F32[i] <= 0.0 || !isfinite(ratio->data.F32[i])) { 536 photMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xFF; 537 } 538 psTrace("psModules.camera", 9, "Ratio %d: %f, %f, %f\n", 539 i, guess->data.F32[i], measuredSig, ratio->data.F32[i]); 540 } 541 psFree(source); 542 psFree(guess); 543 544 psStats *meanStats = psStatsAlloc(meanStat | stdevStat); // Statistics 545 if (!psVectorStats(meanStats, ratio, NULL, photMask, 0xFF)) { 546 psError(PS_ERR_UNKNOWN, false, "Unable to measure mean ratio"); 547 psFree(meanStats); 548 psFree(ratio); 549 psFree(photMask); 447 psFree(signoise); 448 449 float covar = sqrtf(psImageCovarianceFactor(readout->covariance)); // Covariance factor 450 float correction = stats->robustStdev / covar; // Correction factor 451 psFree(stats); 452 psLogMsg("psModules.camera", PS_LOG_DETAIL, "Variance renormalisation factor is %f", correction); 453 454 // Check valid range of correction factor 455 if ((isfinite(minValid) && correction < minValid) || (isfinite(maxValid) && correction > maxValid)) { 456 psError(PS_ERR_UNKNOWN, true, "Variance renormalisation is outside valid range: %f vs %f:%f --- no correction made", correction, minValid, maxValid); 457 psMetadataAddF32(readout->analysis, PS_LIST_TAIL, PM_READOUT_ANALYSIS_RENORM, 0, "Renormalisation of variance", PS_SQR(correction)); 550 458 return false; 551 459 } 552 float meanRatio = psStatsGetValue(meanStats, meanStat); // Mean ratio 553 psTrace("psModules.camera", 5, "Mean significance ratio is %f +/- %f\n", 554 meanRatio, psStatsGetValue(meanStats, stdevStat)); 555 psFree(meanStats); 556 psFree(ratio); 557 psFree(photMask); 558 559 psLogMsg("psModules.camera", PS_LOG_INFO, "Renormalising variance map by %f", meanRatio); 560 psBinaryOp(variance, variance, "*", psScalarAlloc(meanRatio, PS_TYPE_F32)); 561 562 return true; 563 } 564 565 566 bool pmReadoutVarianceRenorm(const pmReadout *readout, psImageMaskType maskVal, psStatsOptions meanStat, 567 psStatsOptions stdevStat, int width, psRandom *rng) 568 { 569 PM_ASSERT_READOUT_NON_NULL(readout, false); 570 PM_ASSERT_READOUT_IMAGE(readout, false); 571 PM_ASSERT_READOUT_VARIANCE(readout, false); 572 PS_ASSERT_INT_POSITIVE(width, false); 573 574 if (!psMemIncrRefCounter(rng)) { 575 rng = psRandomAlloc(PS_RANDOM_TAUS); 576 } 577 578 psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout images 579 int numCols = image->numCols, numRows = image->numRows; // Size of images 580 int xNum = numCols / width + 1, yNum = numRows / width + 1; // Number of renormalisation regions 581 float xSize = numCols / (float)xNum, ySize = numRows / (float)yNum; // Size of renormalisation regions 582 583 psStats *meanStats = psStatsAlloc(meanStat), *stdevStats = psStatsAlloc(stdevStat); // Statistics 584 psVector *buffer = NULL; 585 586 for (int j = 0; j < yNum; j++) { 587 // Bounds in y 588 int yMin = j * ySize; 589 int yMax = (j + 1) * ySize; 590 for (int i = 0; i < xNum; i++) { 591 // Bounds in x 592 int xMin = i * xSize; 593 int xMax = (i + 1) * xSize; 594 595 psRegion region = psRegionSet(xMin, xMax, yMin, yMax); // Region of interest 596 psImage *subImage = psImageSubset(image, region); // Sub-image of the image pixels 597 psImage *subVariance = psImageSubset(variance, region); // Sub image of the variance pixels 598 psImage *subMask = mask ? psImageSubset(mask, region) : NULL; // Sub-image of the mask pixels 599 600 if (!psImageBackground(stdevStats, &buffer, subImage, subMask, maskVal, rng) || 601 !psImageBackground(meanStats, &buffer, subVariance, subMask, maskVal, rng)) { 602 // Nothing we can do about it, but don't want to keel over and die, so do our best to flag it. 603 psString regionStr = psRegionToString(region); // String with region 604 psWarning("Unable to measure statistics over %s", regionStr); 605 psFree(regionStr); 606 psErrorClear(); 607 psImageInit(subVariance, NAN); 608 if (subMask) { 609 psImageInit(subMask, maskVal); 610 } 611 } else { 612 double meanVar = psStatsGetValue(meanStats, meanStat); // Mean of variance map 613 double stdev = psStatsGetValue(stdevStats, stdevStat); // Standard deviation of image 614 psTrace("psModules.camera", 3, 615 "Region [%d:%d,%d:%d] has variance %lf, but mean of variance map is %lf\n", 616 xMin, xMax, yMin, yMax, PS_SQR(stdev), meanVar); 617 psBinaryOp(subVariance, subVariance, "*", psScalarAlloc(PS_SQR(stdev) / meanVar, PS_TYPE_F32)); 618 } 619 620 psFree(subImage); 621 psFree(subVariance); 622 psFree(subMask); 623 } 624 } 625 psFree(meanStats); 626 psFree(stdevStats); 627 psFree(rng); 628 psFree(buffer); 629 630 return true; 631 } 460 461 psImage *subImage = psImageSubset(variance, psRegionSet(xMin, xMax, yMin, yMax)); // Smaller image 462 psBinaryOp(subImage, subImage, "*", psScalarAlloc(PS_SQR(correction), PS_TYPE_F32)); 463 psFree(subImage); 464 465 pmHDU *hdu = pmHDUFromReadout(readout); // HDU for readout 466 if (hdu) { 467 psString history = NULL; 468 psStringAppend(&history, "Rescaled variance by %6.4f (stdev by %6.4f)", 469 PS_SQR(correction), correction); 470 psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, history); 471 psFree(history); 472 } 473 474 return psMetadataAddF32(readout->analysis, PS_LIST_TAIL, PM_READOUT_ANALYSIS_RENORM, 0, 475 "Renormalisation of variance", PS_SQR(correction)); 476 } 477 632 478 633 479 -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAMaskWeight.h
r24483 r27840 16 16 /// @{ 17 17 18 #if 0 19 /// Pixel mask values 20 typedef enum { 21 PM_MASK_CLEAR = 0x00, ///< The pixel is not masked 22 PM_MASK_BLANK = 0x01, ///< The pixel is blank or has no (valid) data 23 PM_MASK_FLAT = 0x02, ///< The pixel is non-positive in the flat-field 24 PM_MASK_DETECTOR = 0x02, ///< The detector pixel is bad (e.g., bad column, charge trap) 25 PM_MASK_SAT = 0x04, ///< The pixel is saturated in the image of interest 26 PM_MASK_BAD = 0x04, ///< The pixel is low in the image of interest 27 PM_MASK_RANGE = 0x04, ///< The pixel is out of range in the image of interest 28 PM_MASK_CR = 0x08, ///< The pixel is probably a CR 29 PM_MASK_SPARE1 = 0x10, ///< Spare mask value 30 PM_MASK_SPARE2 = 0x20, ///< Spare mask value 31 PM_MASK_SUSPECT = 0x40, ///< The pixel is suspected of being bad, but may not be 32 PM_MASK_MARK = 0x80, ///< The pixel is marked as temporarily ignored 33 } pmMaskValue; 34 #define PM_MASK_MARK 0x80 ///< The pixel is marked as temporarily ignored 35 #define PM_MASK_SAT 0x04 ///< The pixel is saturated in the image of interest 36 #endif 18 #define PM_READOUT_ANALYSIS_RENORM "READOUT.RENORM" // Name on analysis metadata for renormalisation 37 19 38 20 /// Set a temporary readout mask using CELL.SATURATION and CELL.BAD … … 54 36 /// can't be generated. 55 37 bool pmReadoutSetVariance(pmReadout *readout, ///< Readout for which to set variance 56 const psImage *noiseMap, ///< 2D image of the read noise in DN38 const psImage *noiseMap, ///< 2D image of the read noise in DN 57 39 bool poisson ///< Include poisson variance (in addition to read noise)? 58 40 ); … … 73 55 /// with HDU entry). This is intended for most operations. 74 56 bool pmReadoutGenerateVariance(pmReadout *readout, ///< Readout for which to generate variance 75 const psImage *noiseMap, ///< 2D image of the read noise in DN57 const psImage *noiseMap, ///< 2D image of the read noise in DN 76 58 bool poisson ///< Include poisson variance (in addition to read noise)? 77 59 ); … … 83 65 psImageMaskType sat, ///< Mask value to give saturated pixels 84 66 psImageMaskType bad, ///< Mask value to give bad (low) pixels 85 const psImage *noiseMap, ///< 2D image of the read noise in DN67 const psImage *noiseMap, ///< 2D image of the read noise in DN 86 68 bool poisson ///< Include poisson variance (in addition to read noise)? 87 69 ); … … 93 75 psImageMaskType sat, ///< Mask value to give saturated pixels 94 76 psImageMaskType bad, ///< Mask value to give bad (low) pixels 95 const psImage *noiseMap, ///< 2D image of the read noise in DN77 const psImage *noiseMap, ///< 2D image of the read noise in DN 96 78 bool poisson ///< Include poisson variance (in addition to read noise)? 97 79 ); … … 100 82 /// 101 83 /// The variance map is adjusted so that the mean matches the actual pixel variance in the image 102 bool pmReadoutVarianceRenormPixels( 103 const pmReadout *readout, ///< Readout to normalise 104 psImageMaskType maskVal, ///< Value to mask 105 psStatsOptions meanStat, ///< Statistic to measure the mean (of the variance map) 106 psStatsOptions stdevStat, ///< Statistic to measure the stdev (of the image) 107 psRandom *rng ///< Random number generator 108 ); 109 110 /// Renormalise the variance map to match the actual photometry variance 111 /// 112 /// The variance map is adjusted so that the actual significance of fake sources matches the 113 /// guestimated significance 114 bool pmReadoutVarianceRenormPhot( 84 bool pmReadoutVarianceRenormalise( 115 85 const pmReadout *readout, ///< Readout to normalise 116 86 psImageMaskType maskVal, ///< Value to mask 117 int num, ///< Number of instances to measure over the image 118 float width, ///< Photometry width 119 psStatsOptions meanStat, ///< Statistic to measure the mean 120 psStatsOptions stdevStat, ///< Statistic to measure the stdev 121 psRandom *rng ///< Random number generator 122 ); 123 124 /// Renormalise the variance map to match the actual variance 125 /// 126 /// The variance in the image is measured in patches, and the variance map is adjusted so that the mean for 127 /// that patch corresponds. 128 bool pmReadoutVarianceRenorm(const pmReadout *readout, // Readout to normalise 129 psImageMaskType maskVal, // Value to mask 130 psStatsOptions meanStat, // Statistic to measure the mean (of the variance map) 131 psStatsOptions stdevStat, // Statistic to measure the stdev (of the image) 132 int width, // Width of patch (pixels) 133 psRandom *rng // Random number generator (for sub-sampling images) 87 int sample, ///< Sample size 88 float minValid, ///< Minimum valid renormalisation, or NAN 89 float maxValid ///< Maximum valid renormalisation, or NAN 134 90 ); 135 91 -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAMosaic.c
r21363 r27840 626 626 bool good = true; // Is everything good? 627 627 628 const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell 629 const char *chipName = psMetadataLookupStr(NULL, cell->parent->concepts, "CHIP.NAME"); // Name of chip 630 628 631 // Offset of the cell on the chip 629 632 int x0Cell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0"); 630 633 if (!mdok) { 631 psError(PS_ERR_UNKNOWN, true, "CELL.X0 for cell is not set.\n");634 psError(PS_ERR_UNKNOWN, true, "CELL.X0 for cell %s,%s is not set.\n", chipName, cellName); 632 635 good = false; 633 636 } 634 637 int y0Cell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0"); 635 638 if (!mdok) { 636 psError(PS_ERR_UNKNOWN, true, "CELL.Y0 for cell is not set.\n");639 psError(PS_ERR_UNKNOWN, true, "CELL.Y0 for cell %s,%s is not set.\n", chipName, cellName); 637 640 good = false; 638 641 } 639 psTrace("psModules.camera", 5, "Cell %ld: x0=%d y0=%d\n", index, x0Cell, y0Cell); 642 psTrace("psModules.camera", 5, "Cell %s,%s (%ld): x0=%d y0=%d\n", 643 chipName, cellName, index, x0Cell, y0Cell); 640 644 641 645 // Offset of the chip on the FPA … … 649 653 x0Chip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.X0"); 650 654 if (!mdok) { 651 psError(PS_ERR_UNKNOWN, true, "CHIP.X0 for chip is not set.\n");655 psError(PS_ERR_UNKNOWN, true, "CHIP.X0 for chip %s is not set.\n", chipName); 652 656 good = false; 653 657 } 654 658 y0Chip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.Y0"); 655 659 if (!mdok) { 656 psError(PS_ERR_UNKNOWN, true, "CHIP.Y0 for chip is not set.\n");660 psError(PS_ERR_UNKNOWN, true, "CHIP.Y0 for chip %s is not set.\n", chipName); 657 661 good = false; 658 662 } … … 662 666 xBin->data.S32[index] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN"); 663 667 if (!mdok || xBin->data.S32[index] == 0) { 664 psError(PS_ERR_UNKNOWN, true, "CELL.XBIN for cell is not set.\n");668 psError(PS_ERR_UNKNOWN, true, "CELL.XBIN for cell %s,%s is not set.\n", chipName, cellName); 665 669 return false; 666 670 } else if (xBin->data.S32[index] < *xBinMin) { … … 669 673 yBin->data.S32[index] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN"); 670 674 if (!mdok || yBin->data.S32[index] == 0) { 671 psError(PS_ERR_UNKNOWN, true, "CELL.YBIN for cell is not set.\n");675 psError(PS_ERR_UNKNOWN, true, "CELL.YBIN for cell %s,%s is not set.\n", chipName, cellName); 672 676 return false; 673 677 } else if (yBin->data.S32[index] < *yBinMin) { … … 678 682 int xParityCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY"); 679 683 if (!mdok || (xParityCell != 1 && xParityCell != -1)) { 680 psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY for cell is not set.\n");684 psError(PS_ERR_UNKNOWN, true, "CELL.XPARITY for cell %s,%s is not set.\n", chipName, cellName); 681 685 return false; 682 686 } 683 687 int yParityCell = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY"); 684 688 if (!mdok || (yParityCell != 1 && yParityCell != -1)) { 685 psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY for cell is not set.\n");689 psError(PS_ERR_UNKNOWN, true, "CELL.YPARITY for cell %s,%s is not set.\n", chipName, cellName); 686 690 return false; 687 691 } … … 693 697 xParityChip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.XPARITY"); 694 698 if (!mdok || (xParityChip != 1 && xParityChip != -1)) { 695 psError(PS_ERR_UNKNOWN, true, "CHIP.XPARITY for chip is not set.\n");699 psError(PS_ERR_UNKNOWN, true, "CHIP.XPARITY for chip %s is not set.\n", chipName); 696 700 return false; 697 701 } 698 702 yParityChip = psMetadataLookupS32(&mdok, chip->concepts, "CHIP.YPARITY"); 699 703 if (!mdok || (yParityChip != 1 && yParityChip != -1)) { 700 psError(PS_ERR_UNKNOWN, true, "CHIP.YPARITY for chip is not set.\n");704 psError(PS_ERR_UNKNOWN, true, "CHIP.YPARITY for chip %s is not set.\n", chipName); 701 705 return false; 702 706 } … … 740 744 static bool chipMosaic(psImage **mosaicImage, // The mosaic image, to be returned 741 745 psImage **mosaicMask, // The mosaic mask, to be returned 742 psImage **mosaicVariance s, // The mosaic variances, to be returned746 psImage **mosaicVariance, // The mosaic variance, to be returned 743 747 int *xBinChip, int *yBinChip, // The binning in x and y, to be returned 744 748 const pmChip *chip, // Chip to mosaic … … 749 753 assert(mosaicImage); 750 754 assert(mosaicMask); 751 assert(mosaicVariance s);755 assert(mosaicVariance); 752 756 assert(xBinChip); 753 757 assert(yBinChip); … … 826 830 if (allGood) { 827 831 *mosaicImage = imageMosaic(images, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0, BLANK_VALUE); 828 *mosaicVariance s= imageMosaic(variances, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0, BLANK_VALUE);832 *mosaicVariance = imageMosaic(variances, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0, BLANK_VALUE); 829 833 *mosaicMask = imageMosaic(masks, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0, blank); 830 834 } … … 847 851 static bool fpaMosaic(psImage **mosaicImage, // The mosaic image, to be returned 848 852 psImage **mosaicMask, // The mosaic mask, to be returned 849 psImage **mosaicVariance s, // The mosaic variances, to be returned853 psImage **mosaicVariance, // The mosaic variance, to be returned 850 854 int *xBinFPA, int *yBinFPA, // The binning in x and y, to be returned 851 855 const pmFPA *fpa, // FPA to mosaic … … 857 861 assert(mosaicImage); 858 862 assert(mosaicMask); 859 assert(mosaicVariance s);863 assert(mosaicVariance); 860 864 assert(xBinFPA); 861 865 assert(yBinFPA); … … 960 964 if (allGood) { 961 965 *mosaicImage = imageMosaic(images, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0, BLANK_VALUE); 962 *mosaicVariance s= imageMosaic(variances, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0, BLANK_VALUE);966 *mosaicVariance = imageMosaic(variances, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0, BLANK_VALUE); 963 967 *mosaicMask = imageMosaic(masks, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0, blank); 964 968 } … … 1025 1029 psImage *mosaicImage = NULL; // The mosaic image 1026 1030 psImage *mosaicMask = NULL; // The mosaic mask 1027 psImage *mosaicVariance s= NULL; // The mosaic variances1031 psImage *mosaicVariance = NULL; // The mosaic variances 1028 1032 1029 1033 // Find the HDU … … 1052 1056 } 1053 1057 if (hdu->variances) { 1054 mosaicVariance s= psImageSubset(hdu->variances->data[0], bounds);1055 if (!mosaicVariance s) {1058 mosaicVariance = psImageSubset(hdu->variances->data[0], bounds); 1059 if (!mosaicVariance) { 1056 1060 psError(PS_ERR_UNKNOWN, false, "Unable to select variance pixels.\n"); 1057 1061 return false; … … 1061 1065 // Case 2 --- we need to mosaic by cut and paste 1062 1066 psTrace("psModules.camera", 1, "Case 2 mosaicking: cut and paste.\n"); 1063 if (!chipMosaic(&mosaicImage, &mosaicMask, &mosaicVariance s, &xBin, &yBin, source, targetCell, blank)) {1067 if (!chipMosaic(&mosaicImage, &mosaicMask, &mosaicVariance, &xBin, &yBin, source, targetCell, blank)) { 1064 1068 psError(PS_ERR_UNKNOWN, false, "Unable to mosaic cells.\n"); 1065 1069 return false; … … 1069 1073 } 1070 1074 psTrace("psModules.camera", 1, "xBin,yBin: %d,%d\n", xBin, yBin); 1075 1071 1076 1072 1077 // Set the concepts for the target cell … … 1090 1095 target->parent->concepts = psMetadataCopy(target->parent->concepts, source->parent->concepts); // FPA lvl 1091 1096 1097 // Average the covariances 1098 psList *covariances = psListAlloc(NULL); // Input covariance matrices 1099 for (int i = 0; i < source->cells->n; i++) { 1100 pmCell *cell = source->cells->data[i]; // Cell of interest 1101 if (!cell || !cell->data_exists) { 1102 continue; 1103 } 1104 pmReadout *ro = cell->readouts->data[0]; // Readout of interest 1105 if (!ro || !ro->covariance) { 1106 continue; 1107 } 1108 psListAdd(covariances, PS_LIST_TAIL, ro->covariance); 1109 } 1110 psKernel *mosaicCovariance = NULL; // Covariance for mosaic 1111 if (psListLength(covariances) > 0) { 1112 psArray *covarArray = psListToArray(covariances); // Array with covariances 1113 mosaicCovariance = psImageCovarianceAverage(covarArray); 1114 psFree(covarArray); 1115 } 1116 psFree(covariances); 1117 1092 1118 // Now make a new readout to go in the target cell 1093 1119 pmReadout *newReadout = pmReadoutAlloc(targetCell); // New readout 1094 1120 newReadout->image = mosaicImage; 1095 1121 newReadout->mask = mosaicMask; 1096 newReadout->variance = mosaicVariances; 1122 newReadout->variance = mosaicVariance; 1123 newReadout->covariance = mosaicCovariance; 1097 1124 psFree(newReadout); // Drop reference 1098 1125 … … 1334 1361 target->concepts = psMetadataCopy(target->concepts, source->concepts); 1335 1362 1363 // Average the covariances 1364 psList *covariances = psListAlloc(NULL); // Input covariance matrices 1365 for (int i = 0; i < covariances->n; i++) { 1366 pmChip *chip = chips->data[i]; // Chip of interest 1367 if (!chip || !chip->data_exists) { 1368 continue; 1369 } 1370 psArray *cells = chip->cells; // Cells in chip 1371 for (long j = 0; j < cells->n; j++) { 1372 pmCell *cell = cells->data[i]; // Cell of interest 1373 if (!cell || !cell->data_exists) { 1374 continue; 1375 } 1376 pmReadout *ro = cell->readouts->data[0]; // Readout of interest 1377 if (!ro || !ro->covariance) { 1378 continue; 1379 } 1380 psListAdd(covariances, PS_LIST_TAIL, ro->covariance); 1381 } 1382 } 1383 psKernel *mosaicCovariances = NULL; // Covariance for mosaic 1384 if (psListLength(covariances) > 0) { 1385 psArray *covarArray = psListToArray(covariances); // Array with covariances 1386 mosaicCovariances = psImageCovarianceAverage(covarArray); 1387 psFree(covarArray); 1388 } 1389 psFree(covariances); 1390 1336 1391 // Now make a new readout to go in the new cell 1337 1392 pmReadout *newReadout = pmReadoutAlloc(targetCell); // New readout … … 1339 1394 newReadout->mask = mosaicMask; 1340 1395 newReadout->variance = mosaicVariances; 1396 newReadout->covariance = mosaicCovariances; 1341 1397 psFree(newReadout); // Drop reference 1342 1398 -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPARead.c
r24792 r27840 296 296 psFits *fits, // FITS file 297 297 int z, // Plane number to read 298 int *zMax, // Max plane number in this cell298 int *zMax, // Max plane number in this cell 299 299 int numScans, // Number of scans to read at a time 300 300 fpaReadType type, // Type of image … … 314 314 return true; 315 315 } else { 316 return false;316 return false; 317 317 } 318 318 } … … 387 387 psFree(regionString); 388 388 psFree(readout); 389 psFree(iter); 389 390 return false; 390 391 } … … 485 486 psFits *fits, // FITS file 486 487 int z, // Desired image plane 487 int *zMax,// Max plane number in this cell488 int *zMax, // Max plane number in this cell 488 489 int numScans, // Number of scans (row or col depends on CELL.READDIR); 0 for all 489 490 int overlap, // Number of scans (row/col) to overlap between scans … … 627 628 // Blow away existing data. 628 629 // Do this before returning, so that we're not returning data from a previous read 629 psFree(*image);630 *image = NULL;630 // psFree(*image); 631 // *image = NULL; 631 632 *image = readoutReadComponent(*image, fits, trimsec, readdir, thisScan, lastScan, z, bad, pixelTypes[type]); 632 633 -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAWrite.c
r24854 r27840 307 307 308 308 if (writeBlank || writeImage) { 309 if (!pmConceptsWriteFPA(fpa, true, config)) {309 if (!pmConceptsWriteFPA(fpa, true, config)) { 310 310 psError(PS_ERR_IO, false, "Unable to write concepts for FPA.\n"); 311 311 return false; -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAfile.c
r23746 r27840 22 22 static int fileNum = 0; // Number of file 23 23 24 static bool fpaFileFreeStrict = true; // Strict checking when file has been freed? 25 26 bool pmFPAfileFreeSetStrict(bool new) 27 { 28 bool old = fpaFileFreeStrict; // Old value, to return 29 fpaFileFreeStrict = new; 30 return old; 31 } 32 24 33 static void pmFPAfileFree(pmFPAfile *file) 25 34 { … … 27 36 return; 28 37 } 38 39 psAssert(!fpaFileFreeStrict || file->fits == NULL, "File %s wasn't closed.", file->name); 29 40 30 41 psTrace ("pmFPAfileFree", 5, "freeing %s\n", file->name); … … 40 51 psFree (file->name); 41 52 42 if (file->fits != NULL) {43 psFitsClose (file->fits);44 }45 53 psFree(file->compression); 46 54 psFree(file->options); … … 103 111 file->save = false; 104 112 105 file->index = fileNum++; 113 file->fileIndex = fileNum++; 114 file->fileID = 0; 106 115 107 116 file->imageId = 0; … … 364 373 // Number of the file in list 365 374 psString num = NULL; // Number to use 366 psStringAppend(&num, "%d", file-> index);375 psStringAppend(&num, "%d", file->fileIndex); 367 376 psStringSubstitute(&newRule, num, "{FILE.INDEX}"); 377 psFree(num); 378 } 379 380 if (strstr(newRule, "{FILE.ID}")) { 381 // Number of the file in list 382 psString num = NULL; // Number to use 383 psStringAppend(&num, "%03d", file->fileID); 384 psStringSubstitute(&newRule, num, "{FILE.ID}"); 368 385 psFree(num); 369 386 } … … 519 536 if (!strcasecmp(type, "SUBKERNEL")) { 520 537 return PM_FPA_FILE_SUBKERNEL; 538 } 539 if (!strcasecmp(type, "PATTERN")) { 540 return PM_FPA_FILE_PATTERN; 521 541 } 522 542 … … 563 583 case PM_FPA_FILE_SUBKERNEL: 564 584 return ("SUBKERNEL"); 585 case PM_FPA_FILE_PATTERN: 586 return "PATTERN"; 565 587 default: 566 588 return ("NONE"); … … 625 647 psFree(iter); 626 648 627 ps Error(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find instance %d of file %s", num, name);649 psLogMsg("psModules.camera", PS_LOG_MINUTIA, "Unable to find instance %d of file %s", num, name); 628 650 return NULL; 629 651 } -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAfile.h
r23487 r27840 48 48 PM_FPA_FILE_ASTROM_REFSTARS, 49 49 PM_FPA_FILE_SUBKERNEL, 50 PM_FPA_FILE_SRCTEXT, 51 PM_FPA_FILE_PATTERN, 50 52 } pmFPAfileType; 51 53 … … 109 111 psString formatName; // name of the camera format 110 112 111 int index; // Index of file 113 int fileIndex; // Index of file 114 int fileID; // internal sequence number 112 115 113 116 psS64 imageId, sourceId; // Image and source identifiers … … 160 163 ); 161 164 165 /// Set strict checking when freeing file 166 /// 167 /// If true (default), freeing a pmFPAfile involves asserting that the FITS filehandle has been closed. 168 bool pmFPAfileFreeSetStrict(bool new // New state 169 ); 162 170 163 171 -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAfileDefine.c
r23370 r27840 57 57 return NAN; 58 58 } 59 int value = psMetadataItemParseF32(item); // Value of interst59 float value = psMetadataItemParseF32(item); // Value of interst 60 60 return value; 61 61 } … … 72 72 return NAN; 73 73 } 74 intvalue = psMetadataItemParseF64(item); // Value of interst74 double value = psMetadataItemParseF64(item); // Value of interst 75 75 return value; 76 76 } … … 91 91 psMetadata *data = pmConfigFileRule(config, camera, name); // File rule 92 92 if (!data) { 93 psError( PS_ERR_IO, true, "Can't find file rule %s!", name);93 psError(psErrorCodeLast(), false, "Can't find file rule %s!", name); 94 94 return NULL; 95 95 } … … 105 105 file->type = pmFPAfileTypeFromString(type); 106 106 if (file->type == PM_FPA_FILE_NONE) { 107 psError(P S_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);107 psError(PM_ERR_CONFIG, true, "FILE.TYPE is not defined for %s\n", name); 108 108 psFree(file); 109 109 return NULL; … … 115 115 file->dataLevel = pmFPALevelFromName(psMetadataLookupStr (&status, data, "DATA.LEVEL")); 116 116 if (file->dataLevel == PM_FPA_LEVEL_NONE) { 117 psError(P S_ERR_IO, true, "DATA.LEVEL is not set for %s\n", name);117 psError(PM_ERR_CONFIG, true, "DATA.LEVEL is not set for %s\n", name); 118 118 psFree(file); 119 119 return NULL; … … 137 137 if (!psMetadataAddPtr(config->files, PS_LIST_TAIL, name, 138 138 PS_DATA_UNKNOWN | PS_META_DUPLICATE_OK, "", file)) { 139 psError(P S_ERR_IO, false, "could not add %s to config files", name);139 psError(PM_ERR_CONFIG, false, "could not add %s to config files", name); 140 140 return NULL; 141 141 } … … 167 167 psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->system, "CAMERAS"); // Known cameras 168 168 if (!mdok || !cameras) { 169 psError(P S_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");169 psError(PM_ERR_CONFIG, true, "Unable to find CAMERAS in the system configuration.\n"); 170 170 return NULL; 171 171 } 172 172 camera = psMetadataLookupMetadata(&mdok, cameras, cameraName); // Camera configuration of interest 173 173 if (!mdok || !camera) { 174 psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find automatically generated " 175 "camera configuration %s in system configuration.\n", cameraName); 174 psError(PM_ERR_CONFIG, true, 175 "Unable to find automatically generated camera configuration %s in system configuration.", 176 cameraName); 176 177 return NULL; 177 178 } … … 184 185 psMetadata *filerule = pmConfigFileRule(config, camera, name); // File rule 185 186 if (!filerule) { 186 psError( PS_ERR_IO, true, "Can't find file rule %s!", name);187 psError(psErrorCodeLast(), false, "Can't find file rule %s!", name); 187 188 return NULL; 188 189 } … … 199 200 file->type = pmFPAfileTypeFromString(type); 200 201 if (file->type == PM_FPA_FILE_NONE) { 201 psError(P S_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);202 psError(PM_ERR_CONFIG, true, "FILE.TYPE is not defined for %s\n", name); 202 203 psFree(file); 203 204 return NULL; … … 230 231 psMetadata *format = psMetadataLookupMetadata(&status, formats, formatName); // Camera format to use 231 232 if (!format) { 232 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Unable to find format %s for file %s.\n",233 psError(PM_ERR_CONFIG, true, "Unable to find format %s for file %s.\n", 233 234 formatName, file->name); 234 235 psFree(file); … … 287 288 options->stdevNum = parseOptionFloat(scheme, "STDEV.NUM", source); // Padding to edge 288 289 if (!isfinite(options->stdevNum)) { 289 psError(P S_ERR_BAD_PARAMETER_VALUE, false, "Bad value for STDEV.NUM for %s", source);290 psError(PM_ERR_CONFIG, true, "Bad value for STDEV.NUM for %s", source); 290 291 psFree(source); 291 292 psFree(file); … … 296 297 options->stdevBits = parseOptionInt(scheme, "STDEV.BITS", source, 0); // Bits for stdev 297 298 if (options->stdevBits <= 0) { 298 psError(P S_ERR_BAD_PARAMETER_VALUE, false, "Bad value for STDEV.BITS (%d) for %s",299 psError(PM_ERR_CONFIG, true, "Bad value for STDEV.BITS (%d) for %s", 299 300 options->stdevBits, source); 300 301 psFree(source); … … 310 311 psAbort("Should never get here."); 311 312 } 313 } 314 315 psMetadataItem *fuzz = psMetadataLookup(scheme, "FUZZ"); // Quantisation fuzz? 316 if (fuzz) { 317 if (fuzz->type != PS_TYPE_BOOL) { 318 psWarning("FUZZ in compression scheme %s isn't boolean.", fitsType); 319 goto FITS_OPTIONS_DONE; 320 } 321 options->fuzz = fuzz->data.B; 312 322 } 313 323 … … 337 347 file->fileLevel = pmFPAPHULevel(format); 338 348 if (file->fileLevel == PM_FPA_LEVEL_NONE) { 339 psError(P S_ERR_IO, true, "Unable to determine file level for %s\n", name);349 psError(PM_ERR_CONFIG, true, "Unable to determine file level for %s\n", name); 340 350 psFree(file); 341 351 return NULL; … … 344 354 file->dataLevel = pmFPALevelFromName(psMetadataLookupStr(&status, filerule, "DATA.LEVEL")); 345 355 if (file->dataLevel == PM_FPA_LEVEL_NONE) { 346 psError(P S_ERR_IO, true, "DATA.LEVEL is not set for %s\n", name);356 psError(PM_ERR_CONFIG, true, "DATA.LEVEL is not set for %s\n", name); 347 357 psFree(file); 348 358 return NULL; … … 443 453 psString realName = pmConfigConvertFilename(filenames->data[0], config, false, false); 444 454 if (!realName) { 445 psError( PS_ERR_IO, false, "Failed to convert file name %s", (char *)filenames->data[0]);455 psError(psErrorCodeLast(), false, "Failed to convert file name %s", (char *)filenames->data[0]); 446 456 return NULL; 447 457 } … … 451 461 psFits *fits = psFitsOpen(realName, "r"); // FITS file 452 462 if (!fits) { 453 psError( PS_ERR_IO, false, "Failed to open file %s", realName);463 psError(psErrorCodeLast(), false, "Failed to open file %s", realName); 454 464 psFree(realName); 455 465 return NULL; … … 457 467 phu = psFitsReadHeader (NULL, fits); // Primary header 458 468 if (!phu) { 459 psError( PS_ERR_IO, false, "Failed to read file header %s", realName);469 psError(psErrorCodeLast(), false, "Failed to read file header %s", realName); 460 470 psFree(realName); 461 471 return NULL; 462 472 } 463 psFitsClose(fits); 473 if (!psFitsClose(fits)) { 474 psError(psErrorCodeLast(), false, "Failed to close file %s", realName); 475 psFree(realName); 476 return NULL; 477 } 464 478 465 479 // Determine the current format from the header; determine camera if not specified already. … … 467 481 format = pmConfigCameraFormatFromHeader(&camera, &cameraName, &formatName, config, phu, true); 468 482 if (!format) { 469 psError( PS_ERR_IO, false, "Failed to determine camera format for %s", realName);483 psError(psErrorCodeLast(), false, "Failed to determine camera format for %s", realName); 470 484 psFree(camera); 471 485 psFree(formatName); … … 477 491 fileLevel = pmFPAPHULevel(format); 478 492 if (fileLevel == PM_FPA_LEVEL_NONE) { 479 psError(P S_ERR_IO, true, "Unable to determine file level for %s", realName);493 psError(PM_ERR_CONFIG, true, "Unable to determine file level for %s", realName); 480 494 psFree(camera); 481 495 psFree(formatName); … … 490 504 psFree(camera); 491 505 if (!fpa) { 492 psError( PS_ERR_IO, false, "Failed to construct FPA from %s", realName);506 psError(psErrorCodeLast(), false, "Failed to construct FPA from %s", realName); 493 507 psFree(formatName); 494 508 psFree(realName); … … 504 518 pmFPAfile *file = pmFPAfileDefineInput(config, fpa, cameraName, name); // File, to return 505 519 if (!file) { 506 psError( PS_ERR_IO, false, "File %s not defined", name);520 psError(psErrorCodeLast(), false, "File %s not defined", name); 507 521 psFree(formatName); 508 522 psFree(format); … … 531 545 psString realName = pmConfigConvertFilename(filenames->data[i], config, false, false); 532 546 if (!realName) { 533 psError( PS_ERR_IO, false, "Failed to convert file name %s", (char*)filenames->data[i]);547 psError(psErrorCodeLast(), false, "Failed to convert file name %s", (char*)filenames->data[i]); 534 548 return NULL; 535 549 } 536 550 psFits *fits = psFitsOpen(realName, "r"); // FITS file 537 551 if (!fits) { 538 psError( PS_ERR_IO, false, "Failed to open file %s", realName);552 psError(psErrorCodeLast(), false, "Failed to open file %s", realName); 539 553 psFree(realName); 540 554 return NULL; 541 555 } 542 556 phu = psFitsReadHeader(NULL, fits); 543 psFitsClose(fits); 557 if (!psFitsClose(fits)) { 558 psError(psErrorCodeLast(), false, "Failed to close file %s", realName); 559 psFree(realName); 560 return NULL; 561 } 544 562 if (!phu) { 545 psError( PS_ERR_IO, false, "Failed to read file header %s", realName);563 psError(psErrorCodeLast(), false, "Failed to read file header %s", realName); 546 564 psFree(realName); 547 565 return NULL; … … 552 570 if (i == 0 && file->type == PM_FPA_FILE_MASK) { 553 571 if (!pmConfigMaskReadHeader(config, phu)) { 554 psError( PS_ERR_IO, false, "Error reading mask bits");572 psError(psErrorCodeLast(), false, "Error reading mask bits"); 555 573 psFree(phu); 556 574 return NULL; … … 562 580 bool valid = false; 563 581 if (!pmConfigValidateCameraFormat(&valid, format, phu)) { 564 psError( PS_ERR_UNKNOWN, false, "Error in config scripts\n");582 psError(psErrorCodeLast(), false, "Error in config scripts\n"); 565 583 psFree(phu); 566 584 return NULL; 567 585 } 568 586 if (!valid) { 569 psError( PS_ERR_IO, false, "File %s is not from the required camera",587 psError(psErrorCodeLast(), false, "File %s is not from the required camera", 570 588 (char*)filenames->data[i]); 571 589 psFree(phu); … … 575 593 format = pmConfigCameraFormatFromHeader(NULL, NULL, NULL, config, phu, true); 576 594 if (!format) { 577 psError( PS_ERR_IO, false, "Failed to determine camera format from %s",595 psError(psErrorCodeLast(), false, "Failed to determine camera format from %s", 578 596 (char*)filenames->data[i]); 579 597 psFree(phu); … … 601 619 phu = NULL; 602 620 if (!view) { 603 psError(P S_ERR_IO, false, "Unable to determine source for %s", name);621 psError(PM_ERR_CONFIG, true, "Unable to determine source for %s", name); 604 622 return NULL; 605 623 } … … 633 651 } 634 652 if (filenames->n == 0) { 635 psError(P S_ERR_IO, false, "No files in array in %s in arguments", argname);653 psError(PM_ERR_CONFIG, true, "No files in array in %s in arguments", argname); 636 654 if (success) { 637 655 *success = false; … … 667 685 } 668 686 if (filenames->n == 0) { 669 psError(P S_ERR_IO, false, "No files in array in %s in arguments", argname);687 psError(PM_ERR_CONFIG, true, "No files in array in %s in arguments", argname); 670 688 if (success) { 671 689 *success = false; … … 700 718 } 701 719 if (filenames->n <= entry) { 702 psError(P S_ERR_IO, false, "Insufficient files (%ld) in array in %s in arguments",720 psError(PM_ERR_CONFIG, true, "Insufficient files (%ld) in array in %s in arguments", 703 721 filenames->n, argname); 704 722 if (success) { … … 760 778 } 761 779 if (bind && files->n != bind->n) { 762 psError(P S_ERR_BAD_PARAMETER_VALUE, true,780 psError(PM_ERR_CONFIG, true, 763 781 "Length of filenames (%ld) and bind files (%ld) does not match.", 764 782 files->n, bind->n); … … 774 792 files->data[i] = psMemIncrRefCounter(fpaFileDefineFromArray(config, bindFile, filename, dummy)); 775 793 if (!files->data[i]) { 776 psError( PS_ERR_UNKNOWN, false, "Unable to define file %s %d", filename, i);794 psError(psErrorCodeLast(), false, "Unable to define file %s %d", filename, i); 777 795 psFree(dummy); 778 796 psFree(files); … … 802 820 // a camera config is needed (as source of file rule) 803 821 if (config->camera == NULL) { 804 psError(P S_ERR_IO, true, "camera is not defined");822 psError(PM_ERR_PROG, true, "camera is not defined"); 805 823 return NULL; 806 824 } … … 809 827 pmFPA *fpa = pmFPAConstruct(config->camera, config->cameraName); 810 828 if (!fpa) { 811 psError( PS_ERR_IO, false, "Failed to construct FPA for %s", filename);829 psError(psErrorCodeLast(), false, "Failed to construct FPA for %s", filename); 812 830 return NULL; 813 831 } … … 818 836 psFree (fpa); 819 837 if (!file) { 820 psError( PS_ERR_IO, false, "file %s not defined\n", filename);838 psError(psErrorCodeLast(), false, "file %s not defined\n", filename); 821 839 return NULL; 822 840 } … … 824 842 // image names may not come from file->names 825 843 if (!strcasecmp(file->filerule, "@FILES")) { 826 psError(P S_ERR_IO, true, "supplied filerule uses illegal value @FILES");844 psError(PM_ERR_CONFIG, true, "supplied filerule uses illegal value @FILES"); 827 845 // XXX remove the file from config->files 828 846 return NULL; … … 881 899 // a camera config is needed (as source of file rule) 882 900 if (config->camera == NULL) { 883 psError(P S_ERR_IO, true, "camera is not defined");901 psError(PM_ERR_PROG, true, "camera is not defined"); 884 902 return NULL; 885 903 } … … 895 913 fpa = pmFPAConstruct(config->camera, config->cameraName); 896 914 if (!fpa) { 897 psError( PS_ERR_IO, false, "Failed to construct FPA for %s", filename);915 psError(psErrorCodeLast(), false, "Failed to construct FPA for %s", filename); 898 916 return NULL; 899 917 } … … 902 920 file = pmFPAfileDefineInput (config, fpa, NULL, filename); 903 921 if (!file) { 904 psError( PS_ERR_IO, false, "file %s not defined\n", filename);922 psError(psErrorCodeLast(), false, "file %s not defined\n", filename); 905 923 psFree(fpa); 906 924 return NULL; … … 934 952 psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, "PPIMAGE"); 935 953 if (!status) { 936 psError(P S_ERR_UNEXPECTED_NULL, true, "PPIMAGE recipe not found.");954 psError(PM_ERR_CONFIG, true, "PPIMAGE recipe not found."); 937 955 psFree(options); 938 956 psFree(fpa); … … 1012 1030 pmDetrendSelectResults *results = pmDetrendSelect (options, config); 1013 1031 if (!results) { 1014 psError ( PS_ERR_IO, false, "no matching detrend data");1032 psError (psErrorCodeLast(), false, "no matching detrend data"); 1015 1033 return NULL; 1016 1034 } … … 1018 1036 file->fileLevel = pmFPALevelFromName(results->level); 1019 1037 if (file->fileLevel == PM_FPA_LEVEL_NONE) { 1020 psError (P S_ERR_IO, false, "invalid file level for selected detrend data");1038 psError (PM_ERR_CONFIG, false, "invalid file level for selected detrend data"); 1021 1039 return NULL; 1022 1040 } … … 1043 1061 pmFPAfile *file = pmFPAfileDefineOutput (config, fpa, filename); 1044 1062 if (!file) { 1045 psError( PS_ERR_UNEXPECTED_NULL, false, "file %s not defined\n", filename);1063 psError(psErrorCodeLast(), false, "file %s not defined\n", filename); 1046 1064 return NULL; 1047 1065 } … … 1062 1080 pmFPAfile *file = pmFPAfileDefineOutputForFormat(config, NULL, filename, src->cameraName, src->formatName); 1063 1081 if (!file) { 1064 psError( PS_ERR_UNEXPECTED_NULL, false, "file %s not defined\n", filename);1082 psError(psErrorCodeLast(), false, "file %s not defined\n", filename); 1065 1083 return NULL; 1066 1084 } … … 1084 1102 pmFPAfile *file = pmFPAfileDefineOutput (config, NULL, filename); 1085 1103 if (!file) { 1086 psError( PS_ERR_UNEXPECTED_NULL, false, "file %s not defined\n", filename);1104 psError(psErrorCodeLast(), false, "file %s not defined\n", filename); 1087 1105 return NULL; 1088 1106 } 1089 1107 if (!file->camera) { 1090 psError(P S_ERR_UNEXPECTED_NULL, false, "file %s does not define a new camera\n", filename);1108 psError(PM_ERR_CONFIG, false, "file %s does not define a new camera\n", filename); 1091 1109 return NULL; 1092 1110 } … … 1127 1145 } 1128 1146 if (!file) { 1129 psError(P S_ERR_UNEXPECTED_NULL, false, "file %s not defined\n", filename);1147 psError(PM_ERR_CONFIG, true, "file %s not defined\n", filename); 1130 1148 return NULL; 1131 1149 } … … 1170 1188 } 1171 1189 if (!file) { 1172 psError(P S_ERR_UNEXPECTED_NULL, false, "file %s not defined\n", filename);1190 psError(PM_ERR_CONFIG, true, "file %s not defined\n", filename); 1173 1191 return NULL; 1174 1192 } … … 1177 1195 if (src) { 1178 1196 if (!pmConceptsCopyFPA(file->fpa, src, true, false)) { 1179 psError( PS_ERR_UNKNOWN, false, "Unable to copy concepts from source to new FPA");1197 psError(psErrorCodeLast(), false, "Unable to copy concepts from source to new FPA"); 1180 1198 return NULL; 1181 1199 } … … 1221 1239 } 1222 1240 if (!file) { 1223 psError(P S_ERR_UNEXPECTED_NULL, false, "file %s not defined\n", filename);1241 psError(PM_ERR_CONFIG, true, "file %s not defined\n", filename); 1224 1242 return NULL; 1225 1243 } … … 1228 1246 if (src) { 1229 1247 if (!pmConceptsCopyFPA(file->fpa, src, false, false)) { 1230 psError( PS_ERR_UNKNOWN, false, "Unable to copy concepts from source to new FPA");1248 psError(psErrorCodeLast(), false, "Unable to copy concepts from source to new FPA"); 1231 1249 return NULL; 1232 1250 } … … 1253 1271 file->name = psStringCopy (name); 1254 1272 1273 // free a previously existing readout 1274 psFree(file->readout); 1255 1275 file->readout = readout; 1256 psMetadataAddPtr(files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "", file); 1276 1277 // allow for multiple entries 1278 // XXX handle replace vs multiple? 1279 psMetadataAddPtr(files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN | PS_META_DUPLICATE_OK, "", file); 1257 1280 psFree(file); 1258 1281 // we free this copy of file, but 'files' still has a copy … … 1274 1297 } 1275 1298 if (file == NULL) { 1276 psError(P S_ERR_IO, true, "file %s is NULL", name);1299 psError(PM_ERR_CONFIG, true, "file %s is NULL", name); 1277 1300 return false; 1278 1301 } … … 1295 1318 const char *name, // name of internal/external file 1296 1319 const pmFPA *fpa, // use this fpa to generate 1297 const psImageBinning *binning) { 1320 const psImageBinning *binning, 1321 int index) { 1298 1322 pmReadout *readout = NULL; 1299 1323 1300 bool status = true; 1301 pmFPAfile *file = psMetadataLookupPtr(&status, config->files, name); 1324 pmFPAfile *file = pmFPAfileSelectSingle(config->files, name, index); 1302 1325 1303 1326 // if the file does not exist, it is not being used as an I/O file: define an internal version 1304 1327 if (file == NULL) { 1305 readout = pmFPAfileDefineInternal (config->files, name, binning->nXruff, binning->nYruff, PS_TYPE_F32); 1306 return readout; 1328 // XXX currently, we do not guarantee that the defined file lands on entry 'index' 1329 psAssert (binning, "internal files must be supplied a psImageBinning for the output images size"); 1330 readout = pmFPAfileDefineInternal (config->files, name, binning->nXruff, binning->nYruff, PS_TYPE_F32); 1331 return readout; 1307 1332 } 1308 1333 -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAfileDefine.h
r23354 r27840 172 172 const char *name, // name of internal/external file 173 173 const pmFPA *fpa, // use this fpa to generate 174 const psImageBinning *binning); 174 const psImageBinning *binning, 175 int index 176 ); 175 177 176 178 /// @} -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAfileFitsIO.c
r23428 r27840 162 162 hdu->header = psMetadataAlloc(); 163 163 } 164 164 165 pmConfigConformHeader(hdu->header, file->format); 165 166 … … 178 179 pmChip *chip = pmFPAviewThisChip(view, fpa); // Chip of interest, or NULL 179 180 pmCell *cell = pmFPAviewThisCell(view, fpa); // Cell of interest, or NULL 180 if (!pmFPAUpdateNames(fpa, chip, cell, file->imageId, file->sourceId)) {181 psError(PS_ERR_UNKNOWN, false, "Unable to update names in header.");182 return false;183 }184 185 181 if (cell) { 186 182 if (!pmConceptsWriteCell(cell, true, config)) { … … 195 191 } else if (!pmConceptsWriteFPA(fpa, true, config)) { 196 192 psError(PS_ERR_IO, false, "Unable to write concepts for FPA.\n"); 193 return false; 194 } 195 196 if (!pmFPAUpdateNames(fpa, chip, cell, file->imageId, file->sourceId)) { 197 psError(PS_ERR_UNKNOWN, false, "Unable to update names in header."); 197 198 return false; 198 199 } -
branches/simtest_nebulous_branches/psModules/src/camera/pmFPAfileIO.c
r24836 r27840 43 43 #include "pmFPAConstruct.h" 44 44 #include "pmSubtractionIO.h" 45 #include "pmPatternIO.h" 45 46 #include "pmConcepts.h" 46 47 #include "pmConfigRun.h" … … 66 67 67 68 switch (place) { 68 case PM_FPA_BEFORE:69 case PM_FPA_BEFORE: 69 70 if (!pmFPAfileRead (file, view, config)) { 70 71 psError(PS_ERR_IO, false, "failed READ in FPA_BEFORE block for %s", file->name); … … 76 77 } 77 78 break; 78 case PM_FPA_AFTER:79 case PM_FPA_AFTER: 79 80 if (!pmFPAfileWrite (file, view, config)) { 80 81 psError(PS_ERR_IO, false, "failed WRITE in FPA_AFTER block for %s", file->name); … … 86 87 } 87 88 break; 88 default:89 default: 89 90 psAbort("You can't get here"); 90 91 } … … 202 203 status = pmSubtractionReadKernels(view, file, config); 203 204 break; 205 case PM_FPA_FILE_PATTERN: 206 status = pmPatternRead(view, file, config); 207 break; 204 208 case PM_FPA_FILE_SX: 205 209 case PM_FPA_FILE_RAW: … … 208 212 case PM_FPA_FILE_CMF: 209 213 case PM_FPA_FILE_WCS: 214 case PM_FPA_FILE_SRCTEXT: 210 215 status = pmFPAviewReadObjects (view, file, config); 211 216 break; … … 272 277 case PM_FPA_FILE_VARIANCE: 273 278 case PM_FPA_FILE_FRINGE: 274 case PM_FPA_FILE_DARK: { 275 // create FPA structure component based on view 276 psMetadata *format = file->format; // Camera format configuration 277 if (!format) { 278 format = config->format; 279 } 280 281 pmFPA *nameSource = file->src; // Source of FPA.OBS 282 if (!nameSource) { 283 nameSource = file->fpa; 284 } 285 bool mdok; // Status of MD lookup 286 const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id 287 288 pmFPAAddSourceFromView(file->fpa, fpaObs, view, format); 289 psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n", 290 file->name, file->name, view->chip, view->cell, view->readout); 291 break; 292 } 279 case PM_FPA_FILE_DARK: 280 case PM_FPA_FILE_PATTERN: 281 { 282 // create FPA structure component based on view 283 psMetadata *format = file->format; // Camera format configuration 284 if (!format) { 285 format = config->format; 286 } 287 288 pmFPA *nameSource = file->src; // Source of FPA.OBS 289 if (!nameSource) { 290 nameSource = file->fpa; 291 } 292 bool mdok; // Status of MD lookup 293 const char *fpaObs = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.OBS"); // Obs. id 294 295 pmFPAAddSourceFromView(file->fpa, fpaObs, view, format); 296 psTrace ("psModules.camera", 5, "created fpa data elements for %s (%s) (%d:%d:%d)\n", 297 file->name, file->name, view->chip, view->cell, view->readout); 298 break; 299 } 293 300 case PM_FPA_FILE_HEADER: 294 301 psAbort ("Create not defined for HEADER"); … … 461 468 status = pmSubtractionWriteKernels(view, file, config); 462 469 break; 470 case PM_FPA_FILE_PATTERN: 471 status = pmPatternWrite(view, file, config); 472 break; 463 473 case PM_FPA_FILE_SX: 464 474 case PM_FPA_FILE_RAW: … … 542 552 case PM_FPA_FILE_DARK: 543 553 case PM_FPA_FILE_SUBKERNEL: 554 case PM_FPA_FILE_PATTERN: 544 555 case PM_FPA_FILE_CMF: 545 556 case PM_FPA_FILE_WCS: … … 609 620 break; 610 621 case PM_FPA_FILE_SUBKERNEL: 622 case PM_FPA_FILE_PATTERN: 611 623 case PM_FPA_FILE_SX: 612 624 case PM_FPA_FILE_RAW: … … 770 782 case PM_FPA_FILE_DARK: 771 783 case PM_FPA_FILE_SUBKERNEL: 784 case PM_FPA_FILE_PATTERN: 772 785 case PM_FPA_FILE_CMF: 773 786 case PM_FPA_FILE_WCS: … … 961 974 case PM_FPA_FILE_SUBKERNEL: 962 975 status = pmSubtractionWritePHU(view, file, config); 976 break; 977 case PM_FPA_FILE_PATTERN: 978 status = pmPatternWritePHU(view, file, config); 979 break; 963 980 case PM_FPA_FILE_CMF: 964 981 status = pmSource_CMF_WritePHU (view, file, config); -
branches/simtest_nebulous_branches/psModules/src/camera/pmHDUGenerate.c
r24769 r27840 611 611 if (cells->n == 0) { 612 612 // Nothing to do 613 psFree (cells); 613 614 return true; 614 615 } … … 660 661 if (cells->n == 0) { 661 662 // Nothing to do 663 psFree (cells); 662 664 return true; 663 665 } … … 707 709 if (cells->n == 0) { 708 710 // Nothing to do 711 psFree(cells); 709 712 return true; 710 713 } 711 712 return generateHDU(hdu, cells); 714 bool status = generateHDU(hdu, cells); 715 psFree(cells); 716 return status; 713 717 } 714 718 default: -
branches/simtest_nebulous_branches/psModules/src/camera/pmReadoutFake.c
r23960 r27840 23 23 #include "pmSourceUtils.h" 24 24 #include "pmModelUtils.h" 25 #include "pmSourceGroups.h" 25 26 26 27 #include "pmReadoutFake.h" 27 28 28 #define MODEL_TYPE "PS_MODEL_RGAUSS" // Type of model to use29 29 #define MAX_AXIS_RATIO 20.0 // Maximum axis ratio for PSF model 30 #define SOURCE_MASK (PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_CR_LIMIT) // Mask to apply to input sources31 30 #define MODEL_MASK (PM_MODEL_STATUS_NONCONVERGE | PM_MODEL_STATUS_OFFIMAGE | \ 32 31 PM_MODEL_STATUS_BADARGS | PM_MODEL_STATUS_LIMITS) // Mask to apply to models 32 33 34 static bool threaded = false; // Running threaded? 35 36 33 37 34 38 … … 50 54 } 51 55 52 bool pmReadoutFakeFromSources(pmReadout *readout, int numCols, int numRows, const psArray *sources, 53 const psVector *xOffset, const psVector *yOffset, const pmPSF *psf, 54 float minFlux, int radius, bool circularise, bool normalisePeak) 56 /// Generate fake sources on a readout 57 static bool readoutFake(pmReadout *readout, // Readout of interest 58 const pmSourceGroups *groups, // Source groups 59 const psVector *x, // x coordinates 60 const psVector *y, // y coordinates 61 const psVector *mag, // Magnitudes 62 const psVector *xOffset, // Offsets in x 63 const psVector *yOffset, // Offsets in y 64 const pmPSF *psf, // PSF 65 float minFlux, // Minimum flux 66 float radius, // Minimum radius 67 bool circularise, // Circularise PSF? 68 bool normalisePeak, // Normalise sources for peak? 69 int groupIndex, // Group index 70 int cellIndex // Cell index 71 ) 72 { 73 psArray *cells = groups->groups->data[groupIndex]; // Cells in group 74 psVector *cellSources = cells->data[cellIndex]; // Sources in cell 75 76 for (int i = 0; i < cellSources->n; i++) { 77 int index = cellSources->data.S32[i]; // Index for source of interest 78 float flux = powf(10.0, -0.4 * mag->data.F32[index]); // Flux of source 79 float xSrc = x->data.F32[index], ySrc = y->data.F32[index]; // Coordinates of source 80 81 if (normalisePeak) { 82 // Normalise flux 83 pmModel *normModel = pmModelFromPSFforXY(psf, xSrc, ySrc, 1.0); // Model for normalisation 84 if (!normModel || (normModel->flags & MODEL_MASK)) { 85 psFree(normModel); 86 continue; 87 } 88 // check that all params are valid: 89 bool validParams = true; 90 for (int j = 0; validParams && (j < normModel->params->n); j++) { 91 switch (j) { 92 case PM_PAR_SKY: 93 case PM_PAR_I0: 94 case PM_PAR_XPOS: 95 case PM_PAR_YPOS: 96 continue; 97 default: 98 if (!isfinite(normModel->params->data.F32[j])) { 99 validParams = false; 100 } 101 } 102 } 103 if (!validParams) { 104 psFree(normModel); 105 continue; 106 } 107 if (circularise && !circulariseModel(normModel)) { 108 psError(PS_ERR_UNKNOWN, false, "Unable to circularise PSF model."); 109 psFree(normModel); 110 return false; 111 } 112 113 flux /= normModel->modelFlux(normModel->params); 114 psFree(normModel); 115 } 116 117 pmModel *fakeModel = pmModelFromPSFforXY(psf, xSrc, ySrc, flux); 118 if (!fakeModel || (fakeModel->flags & MODEL_MASK)) { 119 psFree(fakeModel); 120 continue; 121 } 122 // check that all params are valid: 123 bool validParams = true; 124 for (int j = 0; validParams && (j < fakeModel->params->n); j++) { 125 switch (j) { 126 case PM_PAR_SKY: 127 case PM_PAR_I0: 128 case PM_PAR_XPOS: 129 case PM_PAR_YPOS: 130 continue; 131 default: 132 if (!isfinite(fakeModel->params->data.F32[j])) { 133 validParams = false; 134 } 135 } 136 } 137 if (!validParams) { 138 psFree(fakeModel); 139 continue; 140 } 141 if (circularise && !circulariseModel(fakeModel)) { 142 psError(PS_ERR_UNKNOWN, false, "Unable to circularise PSF model."); 143 psFree(fakeModel); 144 return false; 145 } 146 147 psTrace("psModules.camera", 10, "Adding source at %f,%f with flux %f\n", 148 fakeModel->params->data.F32[PM_PAR_XPOS], fakeModel->params->data.F32[PM_PAR_YPOS], 149 fakeModel->params->data.F32[PM_PAR_I0]); 150 151 pmSource *fakeSource = pmSourceAlloc(); // Fake source to generate 152 fakeSource->peak = pmPeakAlloc(xSrc, ySrc, fakeModel->params->data.F32[PM_PAR_I0], PM_PEAK_LONE); 153 float fakeRadius = 1.0; // Radius of fake source 154 if (isfinite(minFlux)) { 155 fakeRadius = PS_MAX(fakeRadius, fakeModel->modelRadius(fakeModel->params, minFlux)); 156 } 157 if (radius > 0) { 158 fakeRadius = PS_MAX(fakeRadius, radius); 159 } 160 161 if (xOffset) { 162 if (!pmSourceDefinePixels(fakeSource, readout, xSrc + xOffset->data.S32[index], 163 ySrc + yOffset->data.S32[index], fakeRadius)) { 164 psErrorClear(); 165 continue; 166 } 167 if (!pmModelAddWithOffset(fakeSource->pixels, NULL, fakeModel, PM_MODEL_OP_FULL, 0, 168 xOffset->data.S32[index], yOffset->data.S32[index])) { 169 psErrorClear(); 170 continue; 171 } 172 } else { 173 if (!pmSourceDefinePixels(fakeSource, readout, xSrc, ySrc, fakeRadius)) { 174 psErrorClear(); 175 continue; 176 } 177 if (!pmModelAdd(fakeSource->pixels, NULL, fakeModel, PM_MODEL_OP_FULL, 0)) { 178 psErrorClear(); 179 continue; 180 } 181 } 182 psFree(fakeSource); 183 psFree(fakeModel); 184 } 185 186 return true; 187 } 188 189 /// Thread job for readoutFake() 190 static bool readoutFakeThread(psThreadJob *job) 191 { 192 PS_ASSERT_THREAD_JOB_NON_NULL(job, false); 193 194 psArray *args = job->args; // Arguments 195 196 pmReadout *readout = args->data[0]; // Readout of interest 197 const pmSourceGroups *groups = args->data[1]; // Source groups 198 const psVector *x = args->data[2]; // x coordinates 199 const psVector *y = args->data[3]; // y coordinates 200 const psVector *mag = args->data[4]; // Magnitudes 201 const psVector *xOffset = args->data[5]; // Offsets in x 202 const psVector *yOffset = args->data[6]; // Offsets in y 203 const pmPSF *psf = args->data[7]; // PSF 204 float minFlux = PS_SCALAR_VALUE(args->data[8], F32); // Minimum flux 205 float radius = PS_SCALAR_VALUE(args->data[9], F32); // Minimum radius 206 bool circularise = PS_SCALAR_VALUE(args->data[10], U8); // Circularise PSF? 207 bool normalisePeak = PS_SCALAR_VALUE(args->data[11], U8); // Normalise for peak? 208 int groupIndex = PS_SCALAR_VALUE(args->data[12], S32); // Group index 209 int cellIndex = PS_SCALAR_VALUE(args->data[13], S32); // Cell index 210 211 return readoutFake(readout, groups, x, y, mag, xOffset, yOffset, psf, minFlux, radius, circularise, 212 normalisePeak, groupIndex, cellIndex); 213 } 214 215 216 bool pmReadoutFakeThreads(bool new) 217 { 218 bool old = threaded; // Old status, to return 219 220 if (!old && new) { 221 threaded = true; 222 223 { 224 psThreadTask *task = psThreadTaskAlloc("PSMODULES_READOUT_FAKE", 14); 225 task->function = &readoutFakeThread; 226 psThreadTaskAdd(task); 227 psFree(task); 228 } 229 230 } else if (old && !new) { 231 threaded = false; 232 psThreadTaskRemove("PSMODULES_READOUT_FAKE"); 233 } 234 235 return old; 236 } 237 238 239 bool pmReadoutFakeFromVectors(pmReadout *readout, int numCols, int numRows, 240 const psVector *x, const psVector *y, const psVector *mag, 241 const psVector *xOffset, const psVector *yOffset, 242 const pmPSF *psf, float minFlux, int radius, 243 bool circularise, bool normalisePeak) 55 244 { 56 245 PS_ASSERT_PTR_NON_NULL(readout, false); 57 246 PS_ASSERT_INT_LARGER_THAN(numCols, 0, false); 58 247 PS_ASSERT_INT_LARGER_THAN(numRows, 0, false); 59 PS_ASSERT_ARRAY_NON_NULL(sources, false); 60 248 PS_ASSERT_VECTOR_NON_NULL(x, false); 249 PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F32, false); 250 PS_ASSERT_VECTOR_NON_NULL(y, false); 251 PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F32, false); 252 PS_ASSERT_VECTORS_SIZE_EQUAL(y, x, false); 253 PS_ASSERT_VECTOR_NON_NULL(mag, false); 254 PS_ASSERT_VECTOR_TYPE(mag, PS_TYPE_F32, false); 255 PS_ASSERT_VECTORS_SIZE_EQUAL(mag, x, false); 256 long numSources = x->n; // Number of sources 61 257 if (xOffset || yOffset) { 62 258 PS_ASSERT_VECTOR_NON_NULL(xOffset, false); … … 64 260 PS_ASSERT_VECTORS_SIZE_EQUAL(xOffset, yOffset, false); 65 261 PS_ASSERT_VECTOR_TYPE(xOffset, PS_TYPE_S32, false); 66 PS_ASSERT_VECTOR_TYPE _EQUAL(xOffset, yOffset, false);67 if (xOffset->n != sources->n) {262 PS_ASSERT_VECTOR_TYPE(yOffset, PS_TYPE_S32, false); 263 if (xOffset->n != numSources) { 68 264 psError(PS_ERR_BAD_PARAMETER_SIZE, true, 69 265 "Number of offset vectors (%ld) and sources (%ld) doesn't match", 70 xOffset->n, sources->n);266 xOffset->n, numSources); 71 267 return false; 72 268 } 73 269 } 74 270 PS_ASSERT_PTR_NON_NULL(psf, false); 75 if (radius > 0 && isfinite(minFlux) && minFlux > 0.0) {76 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Cannot define both minimum flux and fixed radius.");77 return false;78 }79 271 80 272 readout->image = psImageRecycle(readout->image, numCols, numRows, PS_TYPE_F32); 81 273 psImageInit(readout->image, 0); 82 274 275 int numThreads = threaded ? psThreadPoolSize() : 0; // Number of threads 276 pmSourceGroups *groups = pmSourceGroupsFromVectors(readout, x, y, numThreads); // Groups of sources 277 if (!groups) { 278 psError(PS_ERR_UNKNOWN, false, "Unable to generate source groups"); 279 return false; 280 } 281 282 if (threaded) { 283 for (int i = 0; i < groups->groups->n; i++) { 284 psArray *cells = groups->groups->data[i]; // Cell with sources 285 for (int j = 0; j < cells->n; j++) { 286 psThreadJob *job = psThreadJobAlloc("PSMODULES_READOUT_FAKE"); 287 psArray *args = job->args; 288 psArrayAdd(args, 1, readout); 289 psArrayAdd(args, 1, groups); 290 // Casting away const to add to array 291 psArrayAdd(args, 1, (psVector*)x); 292 psArrayAdd(args, 1, (psVector*)y); 293 psArrayAdd(args, 1, (psVector*)mag); 294 psArrayAdd(args, 1, (psVector*)xOffset); 295 psArrayAdd(args, 1, (psVector*)yOffset); 296 psArrayAdd(args, 1, (pmPSF*)psf); 297 PS_ARRAY_ADD_SCALAR(args, minFlux, PS_TYPE_F32); 298 PS_ARRAY_ADD_SCALAR(args, radius, PS_TYPE_S32); 299 PS_ARRAY_ADD_SCALAR(args, circularise, PS_TYPE_U8); 300 PS_ARRAY_ADD_SCALAR(args, normalisePeak, PS_TYPE_U8); 301 PS_ARRAY_ADD_SCALAR(args, i, PS_TYPE_S32); 302 PS_ARRAY_ADD_SCALAR(args, j, PS_TYPE_S32); 303 304 if (!psThreadJobAddPending(job)) { 305 psFree(job); 306 psFree(groups); 307 return false; 308 } 309 psFree(job); 310 } 311 if (!psThreadPoolWait(true)) { 312 psError(PS_ERR_UNKNOWN, false, "Error waiting for threads."); 313 psFree(groups); 314 return false; 315 } 316 } 317 } else if (!readoutFake(readout, groups, x, y, mag, xOffset, yOffset, psf, minFlux, radius, circularise, 318 normalisePeak, 0, 0)) { 319 psError(PS_ERR_UNKNOWN, false, "Unable to generate fake sources on readout"); 320 psFree(groups); 321 return false; 322 } 323 324 psFree(groups); 325 326 // Set a concept value 327 #define CONCEPT_SET_S32(CONCEPTS, NAME, OLD, NEW) { \ 328 psMetadataItem *item = psMetadataLookup(CONCEPTS, NAME); \ 329 psAssert(item->type == PS_TYPE_S32, "Incorrect type: %x", item->type); \ 330 if (item->data.S32 == OLD) { \ 331 item->data.S32 = NEW; \ 332 } \ 333 } 334 335 if (readout->parent) { 336 CONCEPT_SET_S32(readout->parent->concepts, "CELL.XPARITY", 0, 1); 337 CONCEPT_SET_S32(readout->parent->concepts, "CELL.YPARITY", 0, 1); 338 CONCEPT_SET_S32(readout->parent->concepts, "CELL.XBIN", 0, 1); 339 CONCEPT_SET_S32(readout->parent->concepts, "CELL.YBIN", 0, 1); 340 } 341 342 return true; 343 344 } 345 346 347 bool pmReadoutFakeFromSources(pmReadout *readout, int numCols, int numRows, const psArray *sources, 348 pmSourceMode sourceMask, const psVector *xOffset, const psVector *yOffset, 349 const pmPSF *psf, float minFlux, int radius, 350 bool circularise, bool normalisePeak) 351 { 352 PS_ASSERT_ARRAY_NON_NULL(sources, false); 353 83 354 int numSources = sources->n; // Number of stars 355 psVector *x = psVectorAllocEmpty(numSources, PS_TYPE_F32); 356 psVector *y = psVectorAllocEmpty(numSources, PS_TYPE_F32); 357 psVector *mag = psVectorAllocEmpty(numSources, PS_TYPE_F32); 358 359 int numGood = 0; // Number of good sources 84 360 for (int i = 0; i < numSources; i++) { 85 361 pmSource *source = sources->data[i]; // Source of interest … … 87 363 continue; 88 364 } 89 if (source->mode & SOURCE_MASK) {365 if (source->mode & sourceMask) { 90 366 continue; 91 367 } … … 93 369 continue; 94 370 } 95 float x , y; // Coordinates of source371 float xSrc, ySrc; // Coordinates of source 96 372 if (source->modelPSF) { 97 x = source->modelPSF->params->data.F32[PM_PAR_XPOS];98 y = source->modelPSF->params->data.F32[PM_PAR_YPOS];373 xSrc = source->modelPSF->params->data.F32[PM_PAR_XPOS]; 374 ySrc = source->modelPSF->params->data.F32[PM_PAR_YPOS]; 99 375 } else { 100 x = source->peak->xf; 101 y = source->peak->yf; 102 } 103 104 float flux = powf(10.0, -0.4 * source->psfMag); // Flux of source 105 106 if (normalisePeak) { 107 // Normalise flux 108 pmModel *normModel = pmModelFromPSFforXY(psf, x, y, 1.0); // Model for normalisation 109 if (!normModel || (normModel->flags & MODEL_MASK)) { 110 psFree(normModel); 111 continue; 112 } 113 if (circularise && !circulariseModel(normModel)) { 114 psError(PS_ERR_UNKNOWN, false, "Unable to circularise PSF model."); 115 psFree(normModel); 116 return false; 117 } 118 119 flux /= normModel->modelFlux(normModel->params); 120 psFree(normModel); 121 } 122 123 pmModel *fakeModel = pmModelFromPSFforXY(psf, x, y, flux); 124 if (!fakeModel || (fakeModel->flags & MODEL_MASK)) { 125 psFree(fakeModel); 126 continue; 127 } 128 if (circularise && !circulariseModel(fakeModel)) { 129 psError(PS_ERR_UNKNOWN, false, "Unable to circularise PSF model."); 130 psFree(fakeModel); 131 return false; 132 } 133 134 psTrace("psModules.camera", 10, "Adding source at %f,%f with flux %f\n", 135 fakeModel->params->data.F32[PM_PAR_XPOS], fakeModel->params->data.F32[PM_PAR_YPOS], 136 fakeModel->params->data.F32[PM_PAR_I0]); 137 138 pmSource *fakeSource = pmSourceAlloc(); // Fake source to generate 139 fakeSource->peak = pmPeakAlloc(x, y, fakeModel->params->data.F32[PM_PAR_I0], PM_PEAK_LONE); 140 float fakeRadius = radius > 0 ? radius : 141 PS_MAX(1.0, fakeModel->modelRadius(fakeModel->params, minFlux)); // Radius of fake source 142 143 if (xOffset) { 144 if (!pmSourceDefinePixels(fakeSource, readout, x + xOffset->data.S32[i], 145 y + yOffset->data.S32[i], fakeRadius)) { 146 psErrorClear(); 147 continue; 148 } 149 if (!pmModelAddWithOffset(fakeSource->pixels, NULL, fakeModel, PM_MODEL_OP_FULL, 0, 150 xOffset->data.S32[i], yOffset->data.S32[i])) { 151 psErrorClear(); 152 continue; 153 } 154 } else { 155 if (!pmSourceDefinePixels(fakeSource, readout, x, y, fakeRadius)) { 156 psErrorClear(); 157 continue; 158 } 159 if (!pmModelAdd(fakeSource->pixels, NULL, fakeModel, PM_MODEL_OP_FULL, 0)) { 160 psErrorClear(); 161 continue; 162 } 163 } 164 psFree(fakeSource); 165 psFree(fakeModel); 166 } 167 168 return true; 169 } 376 xSrc = source->peak->xf; 377 ySrc = source->peak->yf; 378 } 379 380 x->data.F32[numGood] = xSrc; 381 y->data.F32[numGood] = ySrc; 382 mag->data.F32[numGood] = source->psfMag; 383 numGood++; 384 } 385 x->n = numGood; 386 y->n = numGood; 387 mag->n = numGood; 388 389 bool status = pmReadoutFakeFromVectors(readout, numCols, numRows, x, y, mag, xOffset, yOffset, psf, 390 minFlux, radius, circularise, normalisePeak); 391 psFree(x); 392 psFree(y); 393 psFree(mag); 394 395 return status; 396 } -
branches/simtest_nebulous_branches/psModules/src/camera/pmReadoutFake.h
r20999 r27840 11 11 #include <pmTrend2D.h> 12 12 #include <pmPSF.h> 13 #include <pmSourceMasks.h> 14 15 /// Set threading 16 /// 17 /// Returns old threading state 18 bool pmReadoutFakeThreads( 19 bool new // New threading state 20 ); 21 22 /// Generate a fake readout from vectors 23 bool pmReadoutFakeFromVectors(pmReadout *readout, ///< Output readout 24 int numCols, int numRows, ///< Dimension of image 25 const psVector *x, const psVector *y, ///< Source coordinates 26 const psVector *mag, ///< Source magnitudes 27 const psVector *xOffset, ///< x offsets for sources (source -> img), or NULL 28 const psVector *yOffset, ///< y offsets for sources (source -> img), or NULL 29 const pmPSF *psf, ///< PSF for sources 30 float minFlux, ///< Minimum flux to bother about; for setting source radius 31 int radius, ///< Fixed radius for sources 32 bool circularise, ///< Circularise PSF model? 33 bool normalisePeak ///< Normalise the peak value? 34 ); 13 35 14 36 /// Generate a fake readout from an array of sources 15 bool pmReadoutFakeFromSources(pmReadout *readout, ///< Output readout , or NULL37 bool pmReadoutFakeFromSources(pmReadout *readout, ///< Output readout 16 38 int numCols, int numRows, ///< Dimension of image 17 39 const psArray *sources, ///< Array of pmSource 40 pmSourceMode sourceMask, ///< Mask for sources 18 41 const psVector *xOffset, ///< x offsets for sources (source -> img), or NULL 19 42 const psVector *yOffset, ///< y offsets for sources (source -> img), or NULL -
branches/simtest_nebulous_branches/psModules/src/concepts/pmConcepts.c
r25046 r27840 249 249 CONCEPT_REGISTER_FUNCTION(S32, Enum, -1); // For enums: set default to -1 250 250 CONCEPT_REGISTER_FUNCTION(S32, S32, 0); // For values: set default to 0 251 //CONCEPT_REGISTER_FUNCTION(Bool, Bool, NULL); // For values: set default to 0 251 252 252 253 static void conceptRegisterTime(const char *name, /* Name of concept */ \ … … 291 292 conceptRegisterF32("FPA.FOCUS", "Telescope focus", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 292 293 conceptRegisterF32("FPA.AIRMASS", "Airmass at boresight", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 294 // XXX p_pmConceptParse_FPA_FILTER -> p_pmConceptParse_FPA_FILTERID (and Format as well)? 293 295 conceptRegisterStr("FPA.FILTERID", "Filter used (parsed, abstract name)", p_pmConceptParse_FPA_FILTER, p_pmConceptFormat_FPA_FILTER, NULL, false, PM_FPA_LEVEL_FPA); 294 296 conceptRegisterStr("FPA.FILTER", "Filter used (instrument name)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); … … 300 302 conceptRegisterF64("FPA.LONGITUDE", "West longitude of observatory", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, NULL, false, PM_FPA_LEVEL_FPA); 301 303 conceptRegisterF64("FPA.LATITUDE", "Latitude of observatory", p_pmConceptParse_FPA_Coords, p_pmConceptFormat_FPA_Coords, NULL, false, PM_FPA_LEVEL_FPA); 302 conceptRegisterF32("FPA.ELEVATION", "Elevation of observatory (metres)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 303 conceptRegisterStr("FPA.OBSTYPE", "Type of observation", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 304 conceptRegisterF32("FPA.ELEVATION", "Elevation of observatory (meters)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 305 306 // conceptRegisterStr("FPA.OBSTYPE", "Type of observation", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 307 conceptRegisterStr("FPA.OBSTYPE", "Type of observation", p_pmConceptParse_FPA_OBSTYPE, p_pmConceptFormat_FPA_OBSTYPE, NULL, false, PM_FPA_LEVEL_FPA); 308 304 309 conceptRegisterStr("FPA.OBJECT", "Object of observation", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 305 310 conceptRegisterF64("FPA.ALT", "Altitude of boresight", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); … … 329 334 conceptRegisterF32("FPA.TELTEMP.EXTRA", "Telescope Temperatures: extra", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA); 330 335 conceptRegisterF32("FPA.PON.TIME", "Power On Time", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 336 conceptRegisterS32("FPA.BURNTOOL.APPLIED", "[T=applied] Burn streaks applied to image data", p_pmConceptParse_BTOOLAPP,p_pmConceptFormat_BTOOLAPP,NULL,false,PM_FPA_LEVEL_FPA); 331 337 conceptRegisterF32("FPA.EXPOSURE", "Exposure time (sec)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 338 conceptRegisterF32("FPA.ZP", "Magnitude zero point", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA); 332 339 } 333 340 if (!conceptsChip) { … … 344 351 conceptRegisterF32("CHIP.TEMP", "Temperature of chip", NULL, NULL, NULL, false, PM_FPA_LEVEL_CHIP); 345 352 conceptRegisterStr("CHIP.ID", "Chip identifier", NULL, NULL, NULL, false, PM_FPA_LEVEL_CHIP); 353 conceptRegisterF32("CHIP.SEEING", "Seeing FWHM (pixels)", NULL, NULL, NULL, false, PM_FPA_LEVEL_CHIP); 346 354 } 347 355 -
branches/simtest_nebulous_branches/psModules/src/concepts/pmConceptsAverage.c
r22706 r27840 36 36 37 37 double time = 0.0; // Time of observation 38 double zp = 0.0; // Zero point 38 39 psTimeType timeSys = 0; // Time system 39 40 char *filter = NULL; // Filter … … 63 64 psTimeConvert(fpaTime, PS_TIME_TAI); 64 65 time += psTimeToMJD(fpaTime); 66 67 zp += psMetadataLookupF32(NULL, fpa->concepts, "FPA.ZP"); 68 65 69 if (num == 1) { 66 70 timeSys = psMetadataLookupS32(NULL, fpa->concepts, "FPA.TIMESYS"); … … 85 89 86 90 time /= (double)num; 91 zp /= (double)num; 87 92 88 93 MD_UPDATE(target->concepts, "FPA.TIMESYS", S32, timeSys); … … 92 97 MD_UPDATE_STR(target->concepts, "FPA.INSTRUMENT", instrument); 93 98 MD_UPDATE_STR(target->concepts, "FPA.DETECTOR", detector); 99 MD_UPDATE(target->concepts, "FPA.ZP", F32, zp); 94 100 95 101 // FPA.TIME needs special care … … 278 284 279 285 float temp = 0.0; // Temperature 286 float seeing = 0.0; // Seeing FWHM 280 287 int x0 = 0, y0 = 0; // Offset 281 288 int xParity = 0, yParity = 0; // Parity … … 291 298 } 292 299 temp += psMetadataLookupF32(NULL, chip->concepts, "CHIP.TEMP"); 300 seeing += psMetadataLookupF32(NULL, chip->concepts, "CHIP.SEEING"); 293 301 if (nChips == 0) { 294 302 xSize = psMetadataLookupS32(NULL, chip->concepts, "CHIP.XSIZE"); … … 335 343 336 344 temp /= (float)nChips; 345 seeing /= (float)nChips; 337 346 338 347 MD_UPDATE(target->concepts, "CHIP.TEMP", F32, temp); 348 MD_UPDATE(target->concepts, "CHIP.SEEING", F32, seeing); 339 349 if (same) { 340 350 MD_UPDATE(target->concepts, "CHIP.X0", S32, x0); -
branches/simtest_nebulous_branches/psModules/src/concepts/pmConceptsRead.c
r24824 r27840 47 47 case PS_DATA_F64: 48 48 return psMetadataItemAllocF64(pattern->name, pattern->comment, psMetadataItemParseF64(concept)); 49 case PS_DATA_BOOL: 50 return psMetadataItemAllocBool(pattern->name, pattern->comment, psMetadataItemParseBool(concept)); 49 51 default: 50 52 psWarning("Concept %s (%s) is not of a standard type (%x)\n", … … 73 75 return false; 74 76 } 75 76 77 psTrace ("psModules.concepts", 3, "parsing concept: %s\n", spec->blank->name); 77 78 if (!strcmp (spec->blank->name, "CELL.XPARITY")) { … … 275 276 psMetadataItem *headerItem = NULL; // The value of the concept from the header 276 277 278 277 279 psTrace ("psModules.concepts", 3, "reading concept: %s\n", name); 278 280 if (!strcmp (name, "CELL.XPARITY")) { … … 307 309 } 308 310 } 309 310 311 if (!headerItem) { 311 312 psMetadataItem *formatItem = psMetadataLookup(transSpec, name); // Item with keyword … … 328 329 } 329 330 psString keywords = formatItem->data.str; // The FITS keywords 330 331 331 // In case there are multiple headers 332 332 psList *keys = psStringSplit(keywords, " ,;", true); // List of keywords -
branches/simtest_nebulous_branches/psModules/src/concepts/pmConceptsStandard.c
r24419 r27840 4 4 5 5 #include <stdio.h> 6 #include <ctype.h> // for tolower() 6 7 #include <string.h> 7 #include <strings.h> /* for strn?casecmp */8 #include <strings.h> // for strn?casecmp 8 9 #include <assert.h> 9 10 #include <pslib.h> … … 160 161 assert(concept); 161 162 assert(pattern); 162 163 163 double value = NAN; 164 164 switch (concept->type) { … … 318 318 "Unable to find %s in FILTER.ID in camera configuration.\n", key); 319 319 return NULL; 320 } 321 322 // FPA.OBSTYPE 323 // convert concept->data.str to new value 324 psMetadataItem *p_pmConceptParse_FPA_OBSTYPE(const psMetadataItem *concept, 325 const psMetadataItem *pattern, 326 pmConceptSource source, 327 const psMetadata *cameraFormat, 328 const pmFPA *fpa, 329 const pmChip *chip, 330 const pmCell *cell) 331 { 332 assert(concept); 333 assert(pattern); 334 assert(fpa); 335 assert(fpa->camera); 336 337 if (concept->type != PS_DATA_STRING) { 338 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Type for %s (%x) is not STR\n", 339 pattern->name, concept->type); 340 return NULL; 341 } 342 if (!concept->data.str || strlen(concept->data.str) == 0) { 343 return psMetadataItemAllocStr(pattern->name, pattern->comment, ""); 344 } 345 346 bool mdok; // Status of MD lookup 347 psMetadata *table = psMetadataLookupMetadata(&mdok, fpa->camera, "OBSTYPE.TABLE"); 348 if (!mdok || !table) { 349 // if the table is not defined, pass the supplied value unmodified 350 return psMetadataItemAllocStr(pattern->name, pattern->comment, concept->data.str); 351 } 352 353 // the metadata is in the format (external) STR (internal) 354 // do a lookup to get the internal name 355 char *extname = psStringCopy (concept->data.str); 356 for (int i = 0; i < strlen(extname); i++) { 357 extname[i] = tolower(extname[i]); 358 } 359 char *name = psMetadataLookupStr (&mdok, table, extname); 360 psFree(extname); 361 if (!name) { 362 // if the entry is not defined, pass the supplied value unmodified 363 return psMetadataItemAllocStr(pattern->name, pattern->comment, concept->data.str); 364 } 365 366 return psMetadataItemAllocStr(pattern->name, pattern->comment, name); 367 } 368 369 // convert concept->data.str to new value 370 psMetadataItem *p_pmConceptFormat_FPA_OBSTYPE(const psMetadataItem *concept, 371 pmConceptSource source, 372 const psMetadata *cameraFormat, 373 const pmFPA *fpa, 374 const pmChip *chip, 375 const pmCell *cell) 376 { 377 assert(concept); 378 assert(fpa); 379 assert(fpa->camera); 380 381 if (concept->type != PS_DATA_STRING) { 382 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Type for %s (%x) is not STR\n", 383 concept->name, concept->type); 384 return NULL; 385 } 386 if (!concept->data.str || strlen(concept->data.str) == 0) { 387 return psMetadataItemAllocStr(concept->name, concept->comment, ""); 388 } 389 390 bool mdok; // Status of MD lookup 391 psMetadata *table = psMetadataLookupMetadata(&mdok, fpa->camera, "OBSTYPE.TABLE"); 392 if (!mdok || !table) { 393 // if the table is not defined, pass the supplied value unmodified 394 return psMetadataItemAllocStr(concept->name, concept->comment, concept->data.str); 395 } 396 397 const char *key = concept->data.str; // The name to look up 398 if (!key || strlen(key) == 0) { 399 return psMetadataItemAllocStr(concept->name, concept->comment, NULL); 400 } 401 402 // the metadata is in the format (internal) STR (external) 403 // do a reverse lookup to get the internal name 404 psMetadataIterator *iter = psMetadataIteratorAlloc(table, PS_LIST_HEAD, NULL); // Iterator for filters 405 psMetadataItem *item; // Item from iteration 406 char *name = NULL; // The winning name 407 while ((item = psMetadataGetAndIncrement(iter))) { 408 if (item->type != PS_DATA_STRING) { 409 psWarning("Type for %s (%x) in OBSTYPE.TABLE in camera configuration is not STR\n", item->name, item->type); 410 continue; 411 } 412 if (strcmp(item->data.str, key) == 0) { 413 name = item->name; 414 break; 415 } 416 } 417 psFree(iter); 418 419 if (!name) { 420 return psMetadataItemAllocStr(concept->name, concept->comment, key); 421 } 422 return psMetadataItemAllocStr(concept->name, concept->comment, name); 320 423 } 321 424 … … 429 532 } 430 533 431 psString ra = psMetadataLookupStr(&mdok, formats, "FPA.RA"); // Format for RA 432 psString dec = psMetadataLookupStr(&mdok, formats, "FPA.DEC"); // Format for Dec 433 if (ra && strcasecmp(ra, "HOURS") == 0 && dec && strcasecmp(dec, "DEGREES") == 0) { 434 sexagesimal = true; 534 if (strcmp(concept->name, "FPA.RA") == 0 || strcmp(concept->name, "FPA.DEC") == 0) { 535 psString ra = psMetadataLookupStr(&mdok, formats, "FPA.RA"); // Format for RA 536 psString dec = psMetadataLookupStr(&mdok, formats, "FPA.DEC"); // Format for Dec 537 if (ra && strcasecmp(ra, "HOURS") == 0 && dec && strcasecmp(dec, "DEGREES") == 0) { 538 sexagesimal = true; 539 } 435 540 } 436 541 } else { … … 450 555 small = 3600.0 * coords; 451 556 small = (float)((int)(small * 1000.0)) / 1000.0; 452 if (negative) {453 big *= -1;454 }455 557 psString coordString = NULL; // String with the coordinates in sexagesimal format 456 psStringAppend(&coordString, "%d:%02d:%06.3f", big, medium, small); 558 psStringAppend(&coordString, "%s%02d:%02d:%06.3f", 559 negative ? "-" : (strcmp(concept->name, "FPA.DEC") == 0 ? "+" : ""), 560 big, medium, small); 457 561 coordItem = psMetadataItemAllocStr(concept->name, concept->comment, coordString); 458 562 psFree(coordString); … … 631 735 return psMetadataItemAllocS32(pattern->name, pattern->comment, binning); 632 736 } 737 738 // BTOOLAPP 739 psMetadataItem *p_pmConceptParse_BTOOLAPP(const psMetadataItem *concept, 740 const psMetadataItem *pattern, 741 pmConceptSource source, 742 const psMetadata *cameraFormat, 743 const pmFPA *fpa, 744 const pmChip *chip, 745 const pmCell *cell) 746 { 747 assert(concept); 748 assert(pattern); 749 750 int bt_status = 0; 751 752 if (concept->type != PS_DATA_BOOL) { 753 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Type for %s (%x) is not BOOL\n", 754 concept->name, concept->type); 755 if (concept->type != PS_DATA_S32) { 756 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Wasn't the type I'd guessed either.\n"); 757 return NULL; 758 } 759 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Looks like an S32 value? (%d)\n", 760 concept->data.S32); 761 762 if (concept->data.S32 == 0) { 763 bt_status = 1; 764 } 765 else if (concept->data.S32 == 1) { 766 bt_status = -2; 767 } 768 } 769 770 if (concept->data.B == true) { 771 bt_status = -2; 772 } 773 else if (concept->data.B == false) { 774 bt_status = 1 ; 775 } 776 777 return psMetadataItemAllocS32(concept->name, concept->comment, bt_status); 778 } 779 psMetadataItem *p_pmConceptFormat_BTOOLAPP(const psMetadataItem *concept, 780 pmConceptSource source, 781 const psMetadata *cameraFormat, 782 const pmFPA *fpa, 783 const pmChip *chip, 784 const pmCell *cell) 785 { 786 assert(concept); 787 788 if (concept->type != PS_DATA_S32) { 789 return NULL; 790 } 791 792 if (concept->data.S32 == 0) { 793 return NULL; 794 } 795 else if (concept->data.S32 == -2) { 796 return psMetadataItemAllocBool(concept->name,concept->comment,true); 797 } 798 else if (concept->data.S32 == 1) { 799 return psMetadataItemAllocBool(concept->name,concept->comment,false); 800 } 801 else { 802 return NULL; 803 } 804 805 } 806 633 807 634 808 // Get the current value of a concept -
branches/simtest_nebulous_branches/psModules/src/concepts/pmConceptsStandard.h
r22699 r27840 72 72 ); 73 73 74 /// Parse the FPA.OBSTYPE concept to apply a lookup table 75 psMetadataItem *p_pmConceptParse_FPA_OBSTYPE( 76 const psMetadataItem *concept, ///< Concept to parse 77 const psMetadataItem *pattern, ///< Pattern to use in parsing 78 pmConceptSource source, ///< Source for concept 79 const psMetadata *cameraFormat, ///< Camera format definition 80 const pmFPA *fpa, ///< FPA for concept, or NULL 81 const pmChip *chip, ///< Chip for concept, or NULL 82 const pmCell *cell ///< Cell for concept, or NULL 83 ); 84 85 /// Format the FPA.OBSTYPE concept to (reverse-)apply a lookup table 86 psMetadataItem *p_pmConceptFormat_FPA_OBSTYPE( 87 const psMetadataItem *concept, ///< Concept to format 88 pmConceptSource source, ///< Source for concept 89 const psMetadata *cameraFormat, ///< Camera format definition 90 const pmFPA *fpa, ///< FPA for concept, or NULL 91 const pmChip *chip, ///< Chip for concept, or NULL 92 const pmCell *cell ///< Cell for concept, or NULL 93 ); 94 74 95 /// Parse the coordinates concepts: FPA.RA and FPA.DEC 75 96 psMetadataItem *p_pmConceptParse_FPA_Coords( … … 114 135 const pmCell *cell ///< Cell for concept, or NULL 115 136 ); 137 138 /// Format for the BTOOLAPP conceptn 139 psMetadataItem *p_pmConceptParse_BTOOLAPP( 140 const psMetadataItem *concept, ///< Concept to format 141 const psMetadataItem *pattern, 142 pmConceptSource source, ///< Source for concept 143 const psMetadata *cameraFormat, ///< Camera format definition 144 const pmFPA *fpa, ///< FPA for concept, or NULL 145 const pmChip *chip, ///< Chip for concept, or NULL 146 const pmCell *cell ///< Cell for concept, or NULL 147 ); 148 psMetadataItem *p_pmConceptFormat_BTOOLAPP( 149 const psMetadataItem *concept, ///< Concept to format 150 pmConceptSource source, ///< Source for concept 151 const psMetadata *cameraFormat, ///< Camera format definition 152 const pmFPA *fpa, ///< FPA for concept, or NULL 153 const pmChip *chip, ///< Chip for concept, or NULL 154 const pmCell *cell ///< Cell for concept, or NULL 155 ); 156 116 157 117 158 /// Parse the cell binning concepts: CELL.XBIN, CELL.YBIN -
branches/simtest_nebulous_branches/psModules/src/concepts/pmConceptsWrite.c
r23623 r27840 157 157 } 158 158 switch (item->type) { 159 case PS_DATA_STRING: 159 case PS_DATA_BOOL: 160 psTrace("psModules.concepts", 9, "Writing header %s: %d\n", keyword, item->data.B); 161 return psMetadataAddBool(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 162 item->data.B); 163 case PS_DATA_STRING: 160 164 psTrace("psModules.concepts", 9, "Writing header %s: %s\n", keyword, item->data.str); 161 165 return psMetadataAddStr(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 162 166 item->data.V); 163 case PS_DATA_S32:167 case PS_DATA_S32: 164 168 psTrace("psModules.concepts", 9, "Writing header %s: %d\n", keyword, item->data.S32); 165 169 return psMetadataAddS32(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 166 170 item->data.S32); 167 case PS_DATA_F32:171 case PS_DATA_F32: 168 172 psTrace("psModules.concepts", 9, "Writing header %s: %f\n", keyword, item->data.F32); 169 173 return psMetadataAddF32(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 170 174 item->data.F32); 171 case PS_DATA_F64:175 case PS_DATA_F64: 172 176 psTrace("psModules.concepts", 9, "Writing header %s: %f\n", keyword, item->data.F64); 173 177 return psMetadataAddF64(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 174 178 item->data.F64); 175 case PS_DATA_REGION: {176 psString region = psRegionToString(*(psRegion*)item->data.V);177 psTrace("psModules.concepts", 9, "Writing header %s: %s\n", keyword, region);178 bool result = psMetadataAddStr(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment,179 region);180 psFree(region);181 return result;182 }183 default:184 psWarning("Type of %s is not suitable for a FITS header --- not added.\n",185 item->name);179 case PS_DATA_REGION: { 180 psString region = psRegionToString(*(psRegion*)item->data.V); 181 psTrace("psModules.concepts", 9, "Writing header %s: %s\n", keyword, region); 182 bool result = psMetadataAddStr(hdu->header, PS_LIST_TAIL, keyword, PS_META_REPLACE, item->comment, 183 region); 184 psFree(region); 185 return result; 186 } 187 default: 188 psWarning("Type of %s is not suitable for a FITS header --- not added.\n", 189 item->name); 186 190 return false; 187 191 } -
branches/simtest_nebulous_branches/psModules/src/config/Makefile.am
r23794 r27840 32 32 pmConfigDump.c \ 33 33 pmConfigRun.c \ 34 pmConfigRecipeValue.c \ 34 35 pmVersion.c \ 35 36 pmErrorCodes.c … … 43 44 pmConfigDump.h \ 44 45 pmConfigRun.h \ 46 pmConfigRecipeValue.h \ 45 47 pmVersion.h \ 46 48 pmErrorCodes.h -
branches/simtest_nebulous_branches/psModules/src/config/pmConfig.c
r24496 r27840 43 43 #define DEFAULT_TRACE STDERR_FILENO // Default file descriptor for trace messages 44 44 45 #define CHECK_FILE_RETRY 5 // Number of retries when checking a file 46 #define CHECK_FILE_WAIT 250000 // Wait between retries (usec) when checking a file 47 45 48 static bool readCameraConfig = true; // Read the camera config on startup (with pmConfigRead)? 46 49 static psArray *configPath = NULL; // Search path for configuration files 47 50 48 51 static bool checkPath(const char *filename, bool create, bool trunc); 52 static psString resolveConfigFile(const char *name); 49 53 50 54 bool pmConfigReadParamsSet(bool newReadCameraConfig) … … 174 178 char *envName = envStart + 1; // Start of the environment variable name 175 179 if (envName[0] == '\0') { 176 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Path %s contains a bad environment variable.\n", dir);180 psError(PM_ERR_CONFIG, true, "Path %s contains a bad environment variable.\n", dir); 177 181 return NULL; 178 182 } … … 180 184 envName++; 181 185 if (envName[0] == '\0') { 182 psError(P S_ERR_BAD_PARAMETER_VALUE, true,186 psError(PM_ERR_CONFIG, true, 183 187 "Path %s contains a bad environment variable.\n", dir); 184 188 return NULL; … … 272 276 273 277 if (configPath == NULL) { 274 psError(P S_ERR_IO, true, "Cannot find %s configuration file (%s) in path\n", description, name);278 psError(PM_ERR_CONFIG, true, "Cannot find %s configuration file (%s) in path\n", description, name); 275 279 return false; 276 280 } … … 296 300 } 297 301 298 psError(P S_ERR_IO, true, "Cannot find %s configuration file %s in path\n", description, name);302 psError(PM_ERR_CONFIG, true, "Cannot find %s configuration file %s in path\n", description, name); 299 303 return false; 300 304 … … 302 306 *config = psMetadataConfigRead(NULL, &numBadLines, realName, true); 303 307 if (numBadLines > 0) { 304 psError(P S_ERR_IO, false, "%d bad lines in %s configuration file (%s)",308 psError(PM_ERR_CONFIG, false, "%d bad lines in %s configuration file (%s)", 305 309 numBadLines, description, realName); 306 310 psFree (realName); … … 309 313 } 310 314 if (!*config) { 311 psError(P S_ERR_IO, true, "Unable to read %s configuration from %s",315 psError(PM_ERR_CONFIG, true, "Unable to read %s configuration from %s", 312 316 description, realName); 313 317 psFree (realName); … … 328 332 } 329 333 if (item->type != PS_DATA_STRING) { 330 ps Trace("config", 2, "Element %s in %s metadata is not of type STR.\n",334 psError(PM_ERR_CONFIG, true, "Element %s in %s metadata is not of type STR.\n", 331 335 item->name, description); 332 336 return false; … … 336 340 psMetadata *new = NULL; // New metadata 337 341 if (!pmConfigFileRead(&new, item->data.str, item->name)) { 338 psError( PM_ERR_CONFIG, false, "Trouble reading reading %s %s.\n",342 psError(psErrorCodeLast(), false, "Trouble reading reading %s %s.\n", 339 343 description, item->name); 340 344 psFree(new); … … 361 365 while ((item = psMetadataGetAndIncrement(iter))) { 362 366 if (!pmConfigFileIngest(item, description)) { 363 psError( PM_ERR_CONFIG, false, "Unable to read %s %s.", description, item->name);367 psError(psErrorCodeLast(), false, "Unable to read %s %s.", description, item->name); 364 368 psFree(iter); 365 369 return false; … … 382 386 psMetadata *formats = psMetadataLookupMetadata(&mdok, camera, "FORMATS"); // Formats 383 387 if (!mdok || !formats) { 384 psError(P S_ERR_UNEXPECTED_NULL, true, "Unable to find FORMATS in camera configuration %s.\n", name);388 psError(PM_ERR_CONFIG, true, "Unable to find FORMATS in camera configuration %s.\n", name); 385 389 return false; 386 390 } 387 391 if (!metadataReadFiles(formats, "camera format")) { 388 psError( PS_ERR_UNKNOWN, false, "Unable to read formats within camera configuration %s.\n", name);392 psError(psErrorCodeLast(), false, "Unable to read formats within camera configuration %s.\n", name); 389 393 return false; 390 394 } … … 447 451 psWarning("-ipprc command-line switch provided without the required filename --- ignored.\n"); 448 452 } else { 449 configFile = psStringCopy(argv[argNum]);453 configFile = resolveConfigFile(argv[argNum]); 450 454 psArgumentRemove(argNum, argc, argv); 451 455 } … … 486 490 psMetadataItem *siteItem = psMetadataLookup(config->user, "SITE"); 487 491 if (!siteItem) { 488 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Unable to find SITE in user configuration.");492 psError(PM_ERR_CONFIG, true, "Unable to find SITE in user configuration."); 489 493 psFree(config); 490 494 return NULL; 491 495 } 492 496 if (!pmConfigFileIngest(siteItem, "site configuration")) { 493 psError( PS_ERR_UNKNOWN, false, "Unable to read site configuration");497 psError(psErrorCodeLast(), false, "Unable to read site configuration"); 494 498 psFree(config); 495 499 return NULL; … … 500 504 psMetadataItem *systemItem = psMetadataLookup(config->user, "SYSTEM"); 501 505 if (!systemItem) { 502 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Unable to find SYSTEM in user configuration.");506 psError(PM_ERR_CONFIG, true, "Unable to find SYSTEM in user configuration."); 503 507 psFree(config); 504 508 return NULL; 505 509 } 506 510 if (!pmConfigFileIngest(systemItem, "system configuration")) { 507 psError( PS_ERR_UNKNOWN, false, "Unable to read system configuration");511 psError(psErrorCodeLast(), false, "Unable to read system configuration"); 508 512 psFree(config); 509 513 return NULL; … … 551 555 psString resolved = pmConfigConvertFilename(logDest, config, true, false); // Resolved filename 552 556 if (!resolved || strlen(resolved) == 0) { 553 psWarning("Unable to resolve log destination: %s --- ignored", logDest); 554 } else { 555 pmConfigRunFilenameAddWrite(config, "LOG", logDest); 556 config->logFD = psMessageDestination(resolved); 557 } 557 psError(psErrorCodeLast(), false, "Unable to resolve log destination: %s", logDest); 558 psFree(logDest); 559 return NULL; 560 } 561 pmConfigRunFilenameAddWrite(config, "LOG", logDest); 562 config->logFD = psMessageDestination(resolved); 558 563 psFree(resolved); 559 564 psFree(logDest); … … 610 615 psString resolved = pmConfigConvertFilename(traceDest, config, true, false); // Resolved filename 611 616 if (!resolved || strlen(resolved) == 0) { 612 psWarning("Unable to resolve trace destination: %s --- ignored", traceDest); 613 } else { 614 pmConfigRunFilenameAddWrite(config, "TRACE", traceDest); 615 config->traceFD = psMessageDestination(resolved); 616 } 617 psError(psErrorCodeLast(), false, "Unable to resolve trace destination: %s", traceDest); 618 psFree(traceDest); 619 return NULL; 620 } 621 pmConfigRunFilenameAddWrite(config, "TRACE", traceDest); 622 config->traceFD = psMessageDestination(resolved); 617 623 psFree(resolved); 618 624 psFree(traceDest); … … 659 665 seed = strtoll(argv[argNum], &end, 0); 660 666 if (strlen(end) > 0) { 661 psError(PS_ERR_IO, true, "Unable to read random number generator seed: %s", argv[argNum]); 667 psError(PM_ERR_CONFIG, true, "Unable to read random number generator seed: %s", 668 argv[argNum]); 662 669 psFree(config); 663 670 return NULL; … … 684 691 psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->system, "CAMERAS"); 685 692 if (!cameras) { 686 psError(P S_ERR_IO, false, "Unable to find CAMERAS in site configuration.\n");693 psError(PM_ERR_CONFIG, false, "Unable to find CAMERAS in site configuration.\n"); 687 694 psFree(config); 688 695 return NULL; … … 692 699 char *cameraFile = psMetadataLookupStr(&mdok, cameras, cameraName); // The filename 693 700 if (!cameraFile) { 694 psError(P S_ERR_IO, false, "%s is not listed in the site CAMERAS list\n", cameraName);701 psError(PM_ERR_CONFIG, false, "%s is not listed in the site CAMERAS list\n", cameraName); 695 702 psFree(config); 696 703 return NULL; … … 699 706 // load this camera's configuration informatoin 700 707 if (!pmConfigFileRead(&config->camera, cameraFile, "camera")) { 701 psError( PM_ERR_CONFIG, false, "Problem reading %s", cameraName);708 psError(psErrorCodeLast(), false, "Problem reading %s", cameraName); 702 709 psFree(config); 703 710 return NULL; … … 710 717 // Read in the formats 711 718 if (!cameraReadFormats(config->camera, cameraFile)) { 712 psError( PS_ERR_UNKNOWN, false, "Unable to read formats within camera configuration %s.\n",719 psError(psErrorCodeLast(), false, "Unable to read formats within camera configuration %s.\n", 713 720 cameraFile); 714 721 psFree(config); … … 718 725 // Read in any camera-specific calibrations 719 726 if (!cameraReadCalibrations(config->camera, cameraName)) { 720 psError( PS_ERR_UNKNOWN, false,727 psError(psErrorCodeLast(), false, 721 728 "Unable to read calibrations within camera configuration %s.\n", 722 729 cameraName); … … 729 736 730 737 if (!pmConfigCameraSkycellVersion(config->system, cameraName)) { 731 psError( PS_ERR_UNKNOWN, false,738 psError(psErrorCodeLast(), false, 732 739 "Unable to generate skycell versions of specified camera %s.\n", 733 740 cameraName); … … 737 744 738 745 if (!pmConfigCameraMosaickedVersions(config->system, cameraName)) { 739 psError( PS_ERR_UNKNOWN, false,746 psError(psErrorCodeLast(), false, 740 747 "Unable to generate mosaicked versions of specified camera %s.\n", 741 748 cameraName); … … 751 758 psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->system, "CAMERAS"); // List of cameras 752 759 if (!mdok || !cameras) { 753 psError(P S_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the system configuration.\n");760 psError(PM_ERR_CONFIG, true, "Unable to find CAMERAS in the system configuration.\n"); 754 761 return false; 755 762 } 756 763 757 764 if (!metadataReadFiles(cameras, "camera configuration")) { 758 psError( PS_ERR_UNKNOWN, false, "Unable to read cameras within system configuration.\n");765 psError(psErrorCodeLast(), false, "Unable to read cameras within system configuration.\n"); 759 766 psFree(config); 760 767 return NULL; … … 784 791 785 792 if (!pmConfigCameraSkycellVersionsAll(config->system)) { 786 psError( PS_ERR_UNKNOWN, false, "Unable to generate skycell versions of cameras.\n");793 psError(psErrorCodeLast(), false, "Unable to generate skycell versions of cameras.\n"); 787 794 psFree(config); 788 795 return NULL; 789 796 } 790 797 if (!pmConfigCameraMosaickedVersionsAll(config->system)) { 791 psError( PS_ERR_UNKNOWN, false, "Unable to generate mosaicked versions of cameras.\n");798 psError(psErrorCodeLast(), false, "Unable to generate mosaicked versions of cameras.\n"); 792 799 psFree(config); 793 800 return NULL; … … 797 804 // Load the recipes from the camera file, if appropriate 798 805 if(!pmConfigReadRecipes(config, PM_RECIPE_SOURCE_SYSTEM | PM_RECIPE_SOURCE_CAMERA)) { 799 psError( PS_ERR_IO, false, "Failed to read recipes from camera file");806 psError(psErrorCodeLast(), false, "Failed to read recipes from camera file"); 800 807 psFree(config); 801 808 return NULL; … … 812 819 813 820 if (!pmConfigReadRecipes(config, PM_RECIPE_SOURCE_CL)) { 814 psError( PS_ERR_IO, false, "Failed to read recipes from command-line");821 psError(psErrorCodeLast(), false, "Failed to read recipes from command-line"); 815 822 psFree(config); 816 823 return NULL; … … 821 828 psArgumentRemove(argNum, argc, argv); 822 829 if (argNum + 1 >= *argc) { 823 psError(P S_ERR_BAD_PARAMETER_SIZE, true,830 psError(PM_ERR_CONFIG, true, 824 831 "Filerule switch (-F) provided without old and new filerule."); 825 832 psFree(config); … … 834 841 psMetadata *cameras = psMetadataLookupMetadata(NULL, config->system, "CAMERAS"); // List of cameras 835 842 if (!cameras) { 836 psError(P S_ERR_UNEXPECTED_NULL, false, "Unable to find CAMERAS in the site configuration.\n");843 psError(PM_ERR_CONFIG, false, "Unable to find CAMERAS in the site configuration.\n"); 837 844 return false; 838 845 } … … 995 1002 psMetadata *rule = psMetadataLookupMetadata(&mdStatus, cameraFormat, "RULE"); 996 1003 if (! mdStatus || ! rule) { 997 psError(P S_ERR_UNKNOWN, false, "Unable to read rule for camera.");1004 psError(PM_ERR_CONFIG, false, "Unable to read rule for camera."); 998 1005 *valid = false; 999 1006 return false; … … 1004 1011 psArray *keys = psListToArray (keyList); 1005 1012 if (! keys) { 1006 psError(P S_ERR_UNKNOWN, false, "Unable to read rule for camera.");1013 psError(PM_ERR_CONFIG, false, "Unable to read rule for camera."); 1007 1014 *valid = false; 1008 1015 return false; … … 1053 1060 } 1054 1061 1055 psError(P S_ERR_UNKNOWN, false, "Invalid type for RULE %s.", ruleItem->name);1062 psError(PM_ERR_CONFIG, false, "Invalid type for RULE %s.", ruleItem->name); 1056 1063 *valid = false; 1057 1064 psFree (keyList); … … 1088 1095 psMetadata *formats = psMetadataLookupMetadata(&mdok, camera, "FORMATS"); // List of formats 1089 1096 if (!mdok || !formats) { 1090 psError(P S_ERR_UNKNOWN, false, "Unable to find list of FORMATS in camera %s", cameraName);1097 psError(PM_ERR_CONFIG, false, "Unable to find list of FORMATS in camera %s", cameraName); 1091 1098 *status = false; 1092 1099 return false; … … 1094 1101 1095 1102 if (!metadataReadFiles(formats, "camera format")) { 1096 psError( PS_ERR_UNKNOWN, false, "Unable to read cameras formats within camera configuration.\n");1103 psError(psErrorCodeLast(), false, "Unable to read cameras formats within camera configuration.\n"); 1097 1104 *status = false; 1098 1105 return false; … … 1110 1117 bool valid = false; 1111 1118 if (!pmConfigValidateCameraFormat(&valid, testFormat, header)) { 1112 psError ( PS_ERR_UNKNOWN, false, "Error in config scripts for camera %s, format %s\n",1119 psError (psErrorCodeLast(), false, "Error in config scripts for camera %s, format %s\n", 1113 1120 cameraName, formatsItem->name); 1114 1121 *status = false; … … 1156 1163 psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->system, "CAMERAS"); 1157 1164 if (! mdok || !cameras) { 1158 psError(P S_ERR_IO, true, "Unable to find CAMERAS in the configuration.");1165 psError(PM_ERR_CONFIG, true, "Unable to find CAMERAS in the configuration."); 1159 1166 return NULL; 1160 1167 } 1161 1168 1162 1169 if (!metadataReadFiles(cameras, "camera configuration")) { 1163 psError( PS_ERR_UNKNOWN, false, "Unable to read cameras within site configuration.\n");1170 psError(psErrorCodeLast(), false, "Unable to read cameras within site configuration.\n"); 1164 1171 return NULL; 1165 1172 } … … 1190 1197 } else { 1191 1198 if (!status) { 1192 psError(PS_ERR_IO, false, "Error reading camera config data for %s", camerasItem->name); 1199 psError(psErrorCodeLast(), false, "Error reading camera config data for %s", 1200 camerasItem->name); 1193 1201 return NULL; 1194 1202 } … … 1199 1207 // Done looking at all cameras 1200 1208 if (!config->camera) { 1201 psError(P S_ERR_IO, false, "Unable to find a camera that matches input FITS header!");1209 psError(PM_ERR_CONFIG, true, "Unable to find a camera that matches input FITS header!"); 1202 1210 return NULL; 1203 1211 } … … 1205 1213 // Now we have the camera, we can read the recipes 1206 1214 if (readRecipes && !pmConfigReadRecipes(config, PM_RECIPE_SOURCE_CAMERA | PM_RECIPE_SOURCE_CL)) { 1207 psError(PS_ERR_IO, false, "Error reading recipes from camera config for %s", config->cameraName); 1215 psError(psErrorCodeLast(), false, "Error reading recipes from camera config for %s", 1216 config->cameraName); 1208 1217 return NULL; 1209 1218 } … … 1281 1290 1282 1291 if (!found) { 1283 psError(PS_ERR_IO, true, "Unable to find a format with the specified camera (%s) that matches the " 1284 "given header.\n", baseName); 1292 psError(PM_ERR_CONFIG, true, 1293 "Unable to find a format with the specified camera (%s) that matches the given header.", 1294 baseName); 1285 1295 psFree (baseName); 1286 1296 return NULL; … … 1313 1323 psMetadata *cameras = psMetadataLookupMetadata(NULL, config->system, "CAMERAS"); 1314 1324 if (!cameras) { 1315 psError(P S_ERR_IO, true, "Unable to find CAMERAS in the configuration.");1325 psError(PM_ERR_CONFIG, true, "Unable to find CAMERAS in the configuration."); 1316 1326 return NULL; 1317 1327 } … … 1319 1329 psMetadataItem *item = psMetadataLookup(cameras, cameraName); // Item with camera of interest 1320 1330 if (!pmConfigFileIngest(item, "camera configuration")) { 1321 psError( PS_ERR_UNKNOWN, false, "Unable to ingest camera configuration.");1331 psError(psErrorCodeLast(), false, "Unable to ingest camera configuration."); 1322 1332 return NULL; 1323 1333 } … … 1335 1345 item = psMetadataLookup(config->site, name); 1336 1346 if (!item) { 1337 psError(P S_ERR_BAD_PARAMETER_VALUE, true,1347 psError(PM_ERR_CONFIG, true, 1338 1348 "Unable to find %s in user or site configuration", name); 1339 1349 return NULL; … … 1341 1351 } 1342 1352 if (item->type != type) { 1343 psError(P S_ERR_BAD_PARAMETER_TYPE, true,1353 psError(PM_ERR_CONFIG, true, 1344 1354 "Type of %s (%x) in user/site configuration does not match expected (%x)", 1345 1355 name, item->type, type); … … 1358 1368 #ifndef HAVE_PSDB 1359 1369 1360 psError(P S_ERR_UNKNOWN, false,1370 psError(PM_ERR_PROG, false, 1361 1371 "Cannot configure database: psModules was compiled without database support."); 1362 1372 return NULL; … … 1407 1417 psMetadata *rules = psMetadataLookupMetadata(&mdok, format, "RULE"); // How to identify this format 1408 1418 if (!mdok || !rules) { 1409 psError(P S_ERR_IO, true, "Unable to find RULE in camera format.\n");1419 psError(PM_ERR_CONFIG, true, "Unable to find RULE in camera format.\n"); 1410 1420 return false; 1411 1421 } … … 1415 1425 while ((rulesItem = psMetadataGetAndIncrement(rulesIter))) { 1416 1426 if (!PS_DATA_IS_PRIMITIVE(rulesItem->type) && rulesItem->type != PS_DATA_STRING) { 1417 psError(P S_ERR_UNKNOWN, false, "Invalid type for RULE %s.", rulesItem->name);1427 psError(PM_ERR_CONFIG, false, "Invalid type for RULE %s.", rulesItem->name); 1418 1428 return false; 1419 1429 } … … 1447 1457 case PS_METADATA_ITEM_COMPARE_OP_NE: 1448 1458 // It's not at all obvious what the value should be, so return an error. 1449 psError(P S_ERR_IO, true,1459 psError(PM_ERR_CONFIG, true, 1450 1460 "RULE %s (defined by an OPeration) is not present or not consistent in output header", 1451 1461 rulesItem->name); … … 1530 1540 default: 1531 1541 // rigid format, no comments allowed? 1532 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Unable to parse file list: spaces detected.");1542 psError(PM_ERR_CONFIG, true, "Unable to parse file list: spaces detected."); 1533 1543 psFree(input); 1534 1544 fclose(f); … … 1563 1573 if (!files) { 1564 1574 psAbort("error parsing argument list"); 1565 psError( PS_ERR_IO, false, "error parsing argument list");1575 psError(psErrorCodeLast(), false, "error parsing argument list"); 1566 1576 psFree (files); 1567 1577 return false; … … 1590 1600 1591 1601 char *point = newName + strlen("file:"); 1592 while (*point == '/') 1602 while (*point == '/') { 1593 1603 point ++; 1604 } 1594 1605 char *tmpName = NULL; 1595 1606 psStringAppend (&tmpName, "/%s", point); … … 1599 1610 if (!checkPath(newName, create, trunc)) { 1600 1611 // let checkPath()'s psError() call float up 1601 psError( PS_ERR_UNKNOWN, false, "error from checkPath for file:// (%s)", newName);1612 psError(psErrorCodeLast(), false, "error from checkPath for file:// (%s)", newName); 1602 1613 psFree (newName); 1603 1614 return NULL; … … 1617 1628 psMetadata *datapath = psMetadataLookupPtr (NULL, config->site, "DATAPATH"); 1618 1629 if (datapath == NULL) { 1619 psError(P S_ERR_UNKNOWN, true, "DATAPATH is not defined in config.site");1630 psError(PM_ERR_CONFIG, true, "DATAPATH is not defined in config.site"); 1620 1631 psFree (newName); 1621 1632 return NULL; … … 1625 1636 char *mark = strchr (point, '/'); 1626 1637 if (mark == NULL) { 1627 psError(P S_ERR_UNKNOWN, true, "syntax error in PATH-style name %s", newName);1638 psError(PM_ERR_CONFIG, true, "syntax error in PATH-style name %s", newName); 1628 1639 psFree (newName); 1629 1640 return false; … … 1633 1644 char *realpath = psMetadataLookupStr (NULL, datapath, path); 1634 1645 if (realpath == NULL) { 1635 psError(P S_ERR_UNKNOWN, true,1646 psError(PM_ERR_CONFIG, true, 1636 1647 "path (%s) not defined in config.site:DATAPATH for PATH-style name %s", 1637 1648 path, newName); … … 1649 1660 if (!checkPath(newName, create, trunc)) { 1650 1661 // let checkPath()'s psError() call float up 1651 psError( PS_ERR_UNKNOWN, false, "error from checkPath for path:// (%s)", newName);1662 psError(psErrorCodeLast(), false, "error from checkPath for path:// (%s)", newName); 1652 1663 psFree (newName); 1653 1664 return NULL; … … 1711 1722 nebServerFree(server); 1712 1723 1713 if (trunc) { 1714 if(truncate(path, 0) != 0) { 1715 psError(PS_ERR_IO, true, "Failed to truncate Nebulous file %s (real name %s)\n", 1716 filename, path); 1717 return NULL; 1718 } 1724 // Check to ensure it's there. Will create the file if Nebulous failed to do so. 1725 if (!checkPath(path, create, trunc)) { 1726 psError(psErrorCodeLast(), false, "Cannot find file %s", path); 1727 psFree(path); 1728 return NULL; 1719 1729 } 1720 1730 … … 1741 1751 psMetadataItem *item = psMetadataLookup(camera, "FILERULES"); // Item with the file rule of interest 1742 1752 if (!item) { 1743 psError(P S_ERR_UNEXPECTED_NULL, false, "Unable to find FILERULES in the camera configuration.");1753 psError(PM_ERR_CONFIG, false, "Unable to find FILERULES in the camera configuration."); 1744 1754 return NULL; 1745 1755 } … … 1774 1784 psMetadataItem *item = psMetadataLookup(camera, "FITSTYPES"); // Item with the file rule of interest 1775 1785 if (!item) { 1776 psError(P S_ERR_UNEXPECTED_NULL, false, "Unable to find FITSTYPES in the camera configuration.");1786 psError(PM_ERR_CONFIG, false, "Unable to find FITSTYPES in the camera configuration."); 1777 1787 return NULL; 1778 1788 } … … 1801 1811 1802 1812 // re-try access up to 5 times (1.25sec) to reduce NFS lurches 1803 for (int i = 0; i < 5; i++) {1813 for (int i = 0; i < CHECK_FILE_RETRY; i++) { 1804 1814 if (access(filename, R_OK) == 0) { 1805 1815 // file already exists … … 1826 1836 return true; 1827 1837 } 1828 usleep (250000);1838 usleep(CHECK_FILE_WAIT); 1829 1839 } 1830 1840 … … 1834 1844 return false; 1835 1845 } 1846 1847 static psString resolveConfigFile(const char *nameArg) 1848 { 1849 // if config file name is nebulous path resolve it 1850 // otherwise just return a copy of the argument 1851 if (strncasecmp(nameArg, "neb://", strlen("neb://"))) { 1852 return psStringCopy(nameArg); 1853 } 1854 1855 #ifdef HAVE_NEBCLIENT 1856 char *neb_server = getenv("NEB_SERVER"); 1857 1858 // if env isn't set, check the config system 1859 if (!neb_server) { 1860 psError(PM_ERR_CONFIG, true, "NEB_SERVER environment variable must be set in order to resolve config file."); 1861 return NULL; 1862 } 1863 1864 nebServer *server = nebServerAlloc(neb_server); 1865 if (!server) { 1866 psError(PM_ERR_SYS, true, "failed to create a nebServer object."); 1867 return NULL; 1868 } 1869 1870 char *nebfile = nebFind(server, nameArg); 1871 nebServerFree(server); 1872 if (!nebfile) { 1873 // object does not exist 1874 psError(PM_ERR_SYS, true, "failed to resolve nebulous path: %s.", nameArg); 1875 return NULL; 1876 } 1877 // XXX: do I need to free nebfile? 1878 1879 return psStringCopy(nebfile); 1880 #else 1881 psError(PM_ERR_PROG, true, "psModules was compiled without nebulous support."); 1882 return NULL; 1883 #endif // ifdef HAVE_NEBCLIENT 1884 } -
branches/simtest_nebulous_branches/psModules/src/config/pmConfigCamera.c
r23452 r27840 149 149 camerasIter = psMetadataIteratorAlloc(new, PS_LIST_HEAD, NULL); // Iterator 150 150 while ((camerasItem = psMetadataGetAndIncrement(camerasIter))) { 151 psMetadataAddItem(cameras, camerasItem, PS_LIST_HEAD, 0);151 psMetadataAddItem(cameras, camerasItem, PS_LIST_HEAD, PS_META_REPLACE); 152 152 } 153 153 psFree(camerasIter); … … 210 210 211 211 // See if the new one is already there 212 psString newName = NULL; // Name of skycelled camera 213 psStringAppend(&newName, "_%s-SKYCELL", name); 214 if (psMetadataLookup(oldCameras, newName)) { 212 psString newName = pmConfigCameraSkycellName(name); // Name of skycelled camera 213 bool mdok; // Status of MD lookup 214 psMetadata *oldCam = psMetadataLookupMetadata(&mdok, oldCameras, newName); // Existing camera configuration 215 if (mdok && oldCam) { 216 // Ensure new camera goes to the head of the metadata, so that it will be recognised first 217 // The old camera doesn't contain the PSMOSAIC header, so it will match anything! 218 psTrace("psModules.config", 6, "Camera configuration for %s exists, so moving to the front.", newName); 219 psMetadataAddMetadata(newCameras, PS_LIST_HEAD, newName, PS_META_REPLACE, NULL, oldCam); 215 220 psFree(newName); 216 221 return true; … … 366 371 // New camera MUST go to the head of the metadata, so that it will be recognised first 367 372 // The old camera doesn't contain the PSCAMERA and PSFORMAT headers, so it will match anything! 373 psTrace("psModules.config", 6, "Generated new camera configuration for %s.", newName); 368 374 psMetadataAddMetadata(newCameras, PS_LIST_HEAD, newName, PS_META_REPLACE, 369 375 "Automatically generated", new); … … 436 442 camerasIter = psMetadataIteratorAlloc(new, PS_LIST_HEAD, NULL); // Iterator 437 443 while ((camerasItem = psMetadataGetAndIncrement(camerasIter))) { 438 psMetadataAddItem(cameras, camerasItem, PS_LIST_HEAD, 0);444 psMetadataAddItem(cameras, camerasItem, PS_LIST_HEAD, PS_META_REPLACE); 439 445 } 440 446 psFree(camerasIter); … … 469 475 470 476 // See if the new one is already there 471 psString newName = NULL; // Name of mosaicked camera 472 psStringAppend(&newName, "_%s-%s", name, mosaicLevel == PM_FPA_LEVEL_CHIP ? "CHIP" : "FPA"); 473 if (psMetadataLookup(oldCameras, newName)) { 477 psString newName = mosaicLevel == PM_FPA_LEVEL_CHIP ? pmConfigCameraChipName(name) : 478 pmConfigCameraFPAName(name); // Name of mosaicked camera 479 bool mdok; // Status of MD lookup 480 psMetadata *oldCam = psMetadataLookupMetadata(&mdok, oldCameras, newName); // Existing camera configuration 481 if (mdok && oldCam) { 482 // Ensure new camera goes to the head of the metadata, so that it will be recognised first 483 // The old camera doesn't contain the PSMOSAIC header, so it will match anything! 484 psTrace("psModules.config", 6, "Camera configuration for %s exists, so moving to the front.", newName); 485 psMetadataAddMetadata(newCameras, PS_LIST_HEAD, newName, PS_META_REPLACE, NULL, oldCam); 474 486 psFree(newName); 475 487 return true; … … 477 489 478 490 psMetadata *new = psMetadataCopy(NULL, camera); // Copy of the camera description 479 bool mdok; // Status of MD lookups480 491 481 492 // ** Fix up the contents of the FPA description to match the mosaicked camera ** … … 849 860 // New camera MUST go to the head of the metadata, so that it will be recognised first 850 861 // The old camera doesn't contain the PSMOSAIC header, so it will match anything! 862 psTrace("psModules.config", 6, "Generated new camera configuration for %s.", newName); 851 863 psMetadataAddMetadata(newCameras, PS_LIST_HEAD, newName, PS_META_REPLACE, 852 864 "Automatically generated", new); -
branches/simtest_nebulous_branches/psModules/src/config/pmConfigDump.c
r23753 r27840 14 14 #include "pmFPAfile.h" 15 15 #include "pmConfigCamera.h" 16 #include "pmErrorCodes.h" 16 17 17 18 #include "pmConfigDump.h" … … 55 56 56 57 if (!configCull(config->recipes, keep)) { 57 psError( PS_ERR_UNKNOWN, false, "Unable to cull system recipes.");58 psError(psErrorCodeLast(), false, "Unable to cull system recipes."); 58 59 psFree(keep); 59 60 return false; … … 64 65 psMetadata *cameras = psMetadataLookupMetadata(NULL, config->system, "CAMERAS"); // Known cameras 65 66 if (!cameras) { 66 psError(P S_ERR_UNEXPECTED_NULL, false, "Unable to find CAMERAS in the system configuration.\n");67 psError(PM_ERR_CONFIG, false, "Unable to find CAMERAS in the system configuration.\n"); 67 68 return false; 68 69 } … … 80 81 } 81 82 if (!configCull(recipes, keep)) { 82 psError( PS_ERR_UNKNOWN, false, "Unable to cull recipes for camera %s", item->name);83 psError(psErrorCodeLast(), false, "Unable to cull recipes for camera %s", item->name); 83 84 psFree(iter); 84 85 psFree(keep); … … 98 99 psMetadata *cameras = psMetadataLookupMetadata(NULL, config->system, "CAMERAS"); // Known cameras 99 100 if (!cameras) { 100 psError(P S_ERR_UNEXPECTED_NULL, false, "Unable to find CAMERAS in the system configuration.\n");101 psError(PM_ERR_CONFIG, false, "Unable to find CAMERAS in the system configuration.\n"); 101 102 return NULL; 102 103 } … … 144 145 145 146 psString resolved = pmConfigConvertFilename(filename, config, true, false); // Resolved filename 147 if (!resolved) { 148 psError(psErrorCodeLast(), false, "Unable to create file for configuration dump: %s", filename); 149 return false; 150 } 146 151 147 152 if (!psMetadataConfigWrite(config->user, resolved)) { 148 psError( PS_ERR_IO, false, "Unable to dump configuration to %s", filename);153 psError(psErrorCodeLast(), false, "Unable to dump configuration to %s", filename); 149 154 psFree(resolved); 150 155 return false; -
branches/simtest_nebulous_branches/psModules/src/config/pmConfigMask.c
r23498 r27840 16 16 { "BLANK", "DETECTOR", 0x01, true }, // Pixel doesn't contain valid data 17 17 { "CTE", "DETECTOR", 0x01, true }, // Pixel has poor CTE 18 { "BURNTOOL", NULL, 0x04, false }, // Pixel has been touched by burntool 18 19 // Invalid signal ranges 19 20 { "SAT", NULL, 0x02, true }, // Pixel is saturated or non-linear … … 22 23 // Non-astronomical structures 23 24 { "CR", NULL, 0x08, true }, // Pixel contains a cosmic ray 24 { "SPIKE", NULL, 0x08, true }, // Pixel contains a diffraction spike25 { "GHOST", NULL, 0x08, true }, // Pixel contains an optical ghost26 { "STREAK", NULL, 0x08, true }, // Pixel contains streak data27 { "STARCORE", NULL, 0x08, true }, // Pixel contains a bright star core25 { "SPIKE", NULL, 0x08, false }, // Pixel contains a diffraction spike 26 { "GHOST", NULL, 0x08, false }, // Pixel contains an optical ghost 27 { "STREAK", NULL, 0x08, false }, // Pixel contains streak data 28 { "STARCORE", NULL, 0x08, false }, // Pixel contains a bright star core 28 29 // Effects of convolution and interpolation 29 30 { "CONV.BAD", NULL, 0x02, true }, // Pixel is bad after convolution with a bad pixel -
branches/simtest_nebulous_branches/psModules/src/config/pmConfigRun.c
r23748 r27840 160 160 psArray *files = configRunFileGet(config, name, "FILES.INPUT"); // Files from RUN metadata 161 161 if (!files) { 162 configRunFileGet(config, name, "FILES.OUTPUT");162 files = configRunFileGet(config, name, "FILES.OUTPUT"); 163 163 } 164 164 -
branches/simtest_nebulous_branches/psModules/src/detrend/Makefile.am
r24891 r27840 17 17 pmDark.c \ 18 18 pmRemnance.c \ 19 pmPattern.c 19 pmPattern.c \ 20 pmPatternIO.c 20 21 21 22 # pmSkySubtract.c … … 35 36 pmDark.h \ 36 37 pmRemnance.h \ 37 pmPattern.h 38 pmPattern.h \ 39 pmPatternIO.h 38 40 39 41 # pmSkySubtract.h -
branches/simtest_nebulous_branches/psModules/src/detrend/pmDark.c
r24869 r27840 38 38 if (!item) { 39 39 pmChip *chip = cell->parent; // Parent chip 40 psAssert(chip, "cell is missing chip \n");40 psAssert(chip, "cell is missing chip \n"); 41 41 42 42 item = psMetadataLookup(chip->concepts, name); 43 43 if (!item) { 44 44 pmFPA *fpa = chip->parent; // Parent FPA 45 psAssert(fpa, "chip is missing fpa \n");45 psAssert(fpa, "chip is missing fpa \n"); 46 46 47 47 item = psMetadataLookup(fpa->concepts, name); … … 68 68 69 69 psArray *words = psStringSplitArray(rule, " ", false); 70 70 71 71 // we should have a rule of the form (concept) OP (concept) OP (concept) ... 72 72 // for now, the only allowed OP is * (eventually, we can steal code from opihi for a better … … 74 74 75 75 if (words->n % 2 == 0) { 76 psError(PM_ERR_CONFIG, true, "syntax error in DARK.ORDINATE %s rule %s\n", name, rule);77 psFree(words);78 return false;76 psError(PM_ERR_CONFIG, true, "syntax error in DARK.ORDINATE %s rule %s\n", name, rule); 77 psFree(words); 78 return false; 79 79 } 80 80 81 81 for (int i = 1; i < words->n; i+=2) { 82 if (strcmp((char *)words->data[i], "*")) {83 psError(PM_ERR_CONFIG, true, "syntax error in DARK.ORDINATE %s rule %s\n", name, rule);84 psFree(words);85 return false;86 }87 } 88 82 if (strcmp((char *)words->data[i], "*")) { 83 psError(PM_ERR_CONFIG, true, "syntax error in DARK.ORDINATE %s rule %s\n", name, rule); 84 psFree(words); 85 return false; 86 } 87 } 88 89 89 if (!ordinateParseConcept(value, readout, words->data[0])) { 90 psError(PM_ERR_CONFIG, false, "syntax error in DARK.ORDINATE %s rule %s\n", name, rule);91 psFree(words);92 return false;90 psError(PM_ERR_CONFIG, false, "syntax error in DARK.ORDINATE %s rule %s\n", name, rule); 91 psFree(words); 92 return false; 93 93 } 94 94 95 95 double value2 = 0.0; 96 96 for (int i = 2; i < words->n; i+=2) { 97 if (!ordinateParseConcept(&value2, readout, words->data[i])) {98 psError(PM_ERR_CONFIG, false, "syntax error in DARK.ORDINATE %s rule %s\n", name, rule);99 psFree(words);100 return false;101 }102 *value *= value2;97 if (!ordinateParseConcept(&value2, readout, words->data[i])) { 98 psError(PM_ERR_CONFIG, false, "syntax error in DARK.ORDINATE %s rule %s\n", name, rule); 99 psFree(words); 100 return false; 101 } 102 *value *= value2; 103 103 } 104 104 psFree(words); … … 123 123 124 124 if (rule) { 125 if (!ordinateParseRule(value, readout, name, rule)) {126 psError(PM_ERR_CONFIG, false, "trouble parsing rule %s for DARK.ORDINATE %s", rule, name);127 return false;128 }125 if (!ordinateParseRule(value, readout, name, rule)) { 126 psError(PM_ERR_CONFIG, false, "trouble parsing rule %s for DARK.ORDINATE %s", rule, name); 127 return false; 128 } 129 129 } else { 130 if (!ordinateParseConcept(value, readout, name)) {131 psError(PM_ERR_CONFIG, false, "trouble parsing rule %s for DARK.ORDINATE %s", rule, name);132 return false;133 }130 if (!ordinateParseConcept(value, readout, name)) { 131 psError(PM_ERR_CONFIG, false, "trouble parsing rule %s for DARK.ORDINATE %s", rule, name); 132 return false; 133 } 134 134 } 135 135 … … 188 188 double normValue; // Normalisation value 189 189 if (!ordinateLookup(&normValue, &inRange, normConcept, NULL, false, NAN, NAN, readout)) { 190 psError(PM_ERR_CONFIG, false, "problem finding concept %s for DARK.NORM", normConcept);191 return false;192 }193 if (!isfinite(normValue)) {190 psError(PM_ERR_CONFIG, false, "problem finding concept %s for DARK.NORM", normConcept); 191 return false; 192 } 193 if (!isfinite(normValue)) { 194 194 psWarning("Unable to find acceptable value of %s for readout %d", normConcept, i); 195 195 roMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff; … … 231 231 double value = NAN; // Value of ordinate 232 232 if (!ordinateLookup(&value, &inRange, ord->name, ord->rule, ord->scale, ord->min, ord->max, readout)) { 233 psError(PM_ERR_CONFIG, false, "problem finding rule for DARK.ORDINATE %s", ord->name);234 return false;235 }236 if (!isfinite(value)) {237 psWarning("Unable to find acceptable value of DARK.ORDINATE %s for readout %d", ord->name, i);233 psError(PM_ERR_CONFIG, false, "problem finding rule for DARK.ORDINATE %s", ord->name); 234 return false; 235 } 236 if (!isfinite(value)) { 237 psWarning("Unable to find acceptable value of DARK.ORDINATE %s for readout %d", ord->name, i); 238 238 roMask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xff; 239 239 val->data.F32[i] = NAN; … … 242 242 } 243 243 if (!inRange) { 244 psWarning("Value of DARK.ORDINATE %s for readout %d is out of range", ord->name, i);244 psWarning("Value of DARK.ORDINATE %s for readout %d is out of range", ord->name, i); 245 245 roMask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xff; 246 246 val->data.F32[i] = NAN; … … 349 349 PS_ASSERT_INT_NONNEGATIVE(iter, false); 350 350 PS_ASSERT_FLOAT_LARGER_THAN(rej, 0.0, false); 351 352 pthread_t id = pthread_self();353 char name[64];354 sprintf (name, "%x", (unsigned int) id);355 psTimerStart (name);356 351 357 352 bool mdok = false; … … 433 428 } 434 429 435 pmDarkVisualPixelFit(pixels, mask);436 pmDarkVisualPixelModel(poly, values);430 pmDarkVisualPixelFit(pixels, mask); 431 pmDarkVisualPixelModel(poly, values); 437 432 438 433 for (int k = 0; k < poly->coeff->n; k++) { … … 537 532 return false; 538 533 } 539 if (!isfinite(value)) {534 if (!isfinite(value)) { 540 535 psError(PS_ERR_UNKNOWN, true, "Value for DARK.ORDINATE %s is NAN", ord->name); 541 536 psFree(values); 542 537 return false; 543 }538 } 544 539 values->data.F32[i] = value; 545 540 } … … 792 787 psMetadataAddStr(row, PS_LIST_TAIL, PM_DARK_FITS_NAME, 0, "DARK.ORDINATE name", ord->name); 793 788 794 // XXX write a dummy value if ord->rule == NULL? (eg, NONE)795 if (ord->rule) {796 psMetadataAddStr(row, PS_LIST_TAIL, PM_DARK_FITS_RULE, 0, "DARK.ORDINATE rule", ord->rule);797 } else {798 psMetadataAddStr(row, PS_LIST_TAIL, PM_DARK_FITS_RULE, 0, "DARK.ORDINATE rule", "NONE");799 }789 // XXX write a dummy value if ord->rule == NULL? (eg, NONE) 790 if (ord->rule) { 791 psMetadataAddStr(row, PS_LIST_TAIL, PM_DARK_FITS_RULE, 0, "DARK.ORDINATE rule", ord->rule); 792 } else { 793 psMetadataAddStr(row, PS_LIST_TAIL, PM_DARK_FITS_RULE, 0, "DARK.ORDINATE rule", "NONE"); 794 } 800 795 801 796 psMetadataAddS32(row, PS_LIST_TAIL, PM_DARK_FITS_ORDER, 0, "Polynomial order", ord->order); … … 975 970 ord->max = psMetadataLookupF32(NULL, row, PM_DARK_FITS_MAX); 976 971 977 // load the ordinate rule; it is not an error if this field is missing or NULL978 // a NULL rule means 'use the name as the single concept'972 // load the ordinate rule; it is not an error if this field is missing or NULL 973 // a NULL rule means 'use the name as the single concept' 979 974 const char *rule = psMetadataLookupStr(&mdok, row, PM_DARK_FITS_RULE); 980 if (!rule || !strcasecmp(rule, "NONE")) {981 ord->rule = NULL;982 } else {983 ord->rule = psStringCopy(rule);984 }975 if (!rule || !strcasecmp(rule, "NONE")) { 976 ord->rule = NULL; 977 } else { 978 ord->rule = psStringCopy(rule); 979 } 985 980 ordinates->data[i] = ord; 986 981 } … … 1009 1004 // this init function only gets the ordinates for the first readout... 1010 1005 bool pmDarkVisualInit(psArray *values) { 1011 1006 1012 1007 if (!pmVisualIsVisual()) return true; 1013 1008 … … 1018 1013 int nOrders = 0; 1019 1014 for (int i = 0; i < values->n; i++) { 1020 psVector *vect = values->data[i];1021 if (!nOrders) {1022 nOrders = vect->n;1023 } else {1024 psAssert (nOrders == vect->n, "mismatch in order vector lengths");1025 }1015 psVector *vect = values->data[i]; 1016 if (!nOrders) { 1017 nOrders = vect->n; 1018 } else { 1019 psAssert (nOrders == vect->n, "mismatch in order vector lengths"); 1020 } 1026 1021 } 1027 1022 xVectors = psArrayAlloc(nOrders); 1028 1023 for (int i = 0; i < nOrders; i++) { 1029 xVectors->data[i] = psVectorAlloc(values->n, PS_TYPE_F32);1024 xVectors->data[i] = psVectorAlloc(values->n, PS_TYPE_F32); 1030 1025 } 1031 1026 1032 1027 for (int i = 0; i < values->n; i++) { 1033 psVector *vect = values->data[i];1034 for (int j = 0; j < vect->n; j++) {1035 psVector *xVec = xVectors->data[j];1036 xVec->data.F32[i] = vect->data.F32[j];1037 }1028 psVector *vect = values->data[i]; 1029 for (int j = 0; j < vect->n; j++) { 1030 psVector *xVec = xVectors->data[j]; 1031 xVec->data.F32[i] = vect->data.F32[j]; 1032 } 1038 1033 } 1039 1034 … … 1041 1036 1042 1037 kapa = psAlloc(nKapa*sizeof(int)); 1043 1038 1044 1039 for (int i = 0; i < nKapa; i++) { 1045 kapa[i] = -1;1046 pmVisualInitWindow(&kapa[i], "ppmerge");1040 kapa[i] = -1; 1041 pmVisualInitWindow(&kapa[i], "ppmerge"); 1047 1042 } 1048 1043 return true; … … 1063 1058 1064 1059 for (int i = 0; i < xVectors->n; i++) { 1065 psVector *x = xVectors->data[i];1066 1067 // generate vectors of the unmasked values1068 int nSub = 0;1069 for (int j = 0; j < pixels->n; j++) {1070 if (mask && mask->data.PS_TYPE_VECTOR_MASK_DATA[j]) continue;1071 xSub->data.F32[nSub] = x->data.F32[j];1072 ySub->data.F32[nSub] = pixels->data.F32[j];1073 nSub ++;1074 }1075 xSub->n = ySub->n = nSub;1076 1077 // plot the unmasked values1078 pmVisualScaleGraphdata (&graphdata, xSub, ySub, false);1079 KapaSetGraphData(kapa[i], &graphdata);1080 KapaSetLimits(kapa[i], &graphdata);1081 KapaClearPlots (kapa[i]);1082 1083 KapaSetFont (kapa[i], "courier", 14);1084 KapaBox (kapa[i], &graphdata);1085 KapaSendLabel (kapa[i], "ordinate", KAPA_LABEL_XM);1086 KapaSendLabel (kapa[i], "pixel values", KAPA_LABEL_YM);1087 1088 graphdata.color = KapaColorByName("black");1089 graphdata.style = 2;1090 graphdata.ptype = 2;1091 KapaPrepPlot (kapa[i], xSub->n, &graphdata);1092 KapaPlotVector(kapa[i], xSub->n, xSub->data.F32, "x");1093 KapaPlotVector(kapa[i], xSub->n, ySub->data.F32, "y");1060 psVector *x = xVectors->data[i]; 1061 1062 // generate vectors of the unmasked values 1063 int nSub = 0; 1064 for (int j = 0; j < pixels->n; j++) { 1065 if (mask && mask->data.PS_TYPE_VECTOR_MASK_DATA[j]) continue; 1066 xSub->data.F32[nSub] = x->data.F32[j]; 1067 ySub->data.F32[nSub] = pixels->data.F32[j]; 1068 nSub ++; 1069 } 1070 xSub->n = ySub->n = nSub; 1071 1072 // plot the unmasked values 1073 pmVisualScaleGraphdata (&graphdata, xSub, ySub, false); 1074 KapaSetGraphData(kapa[i], &graphdata); 1075 KapaSetLimits(kapa[i], &graphdata); 1076 KapaClearPlots (kapa[i]); 1077 1078 KapaSetFont (kapa[i], "courier", 14); 1079 KapaBox (kapa[i], &graphdata); 1080 KapaSendLabel (kapa[i], "ordinate", KAPA_LABEL_XM); 1081 KapaSendLabel (kapa[i], "pixel values", KAPA_LABEL_YM); 1082 1083 graphdata.color = KapaColorByName("black"); 1084 graphdata.style = 2; 1085 graphdata.ptype = 2; 1086 KapaPrepPlot (kapa[i], xSub->n, &graphdata); 1087 KapaPlotVector(kapa[i], xSub->n, xSub->data.F32, "x"); 1088 KapaPlotVector(kapa[i], xSub->n, ySub->data.F32, "y"); 1094 1089 } 1095 1090 pmVisualAskUser (&plotFlag); … … 1110 1105 1111 1106 for (int i = 0; i < values->n; i++) { 1112 psVector *coord = values->data[i];1113 yFit->data.F32[i] = psPolynomialMDEval (poly, coord);1107 psVector *coord = values->data[i]; 1108 yFit->data.F32[i] = psPolynomialMDEval (poly, coord); 1114 1109 } 1115 1110 1116 1111 for (int i = 0; i < xVectors->n; i++) { 1117 psVector *xFit = xVectors->data[i];1118 1119 KapaGetGraphData(kapa[i], &graphdata);1120 graphdata.color = KapaColorByName("red");1121 graphdata.style = 2;1122 graphdata.ptype = 7;1123 KapaPrepPlot (kapa[i], xFit->n, &graphdata);1124 KapaPlotVector(kapa[i], xFit->n, xFit->data.F32, "x");1125 KapaPlotVector(kapa[i], xFit->n, yFit->data.F32, "y");1112 psVector *xFit = xVectors->data[i]; 1113 1114 KapaGetGraphData(kapa[i], &graphdata); 1115 graphdata.color = KapaColorByName("red"); 1116 graphdata.style = 2; 1117 graphdata.ptype = 7; 1118 KapaPrepPlot (kapa[i], xFit->n, &graphdata); 1119 KapaPlotVector(kapa[i], xFit->n, xFit->data.F32, "x"); 1120 KapaPlotVector(kapa[i], xFit->n, yFit->data.F32, "y"); 1126 1121 } 1127 1122 pmVisualAskUser (&plotFlag); … … 1132 1127 1133 1128 for (int i = 0; i < nKapa; i++) { 1134 KapaClose(kapa[i]);1129 KapaClose(kapa[i]); 1135 1130 } 1136 1131 psFree (kapa); -
branches/simtest_nebulous_branches/psModules/src/detrend/pmFringeStats.c
r24912 r27840 11 11 #include "pmFPA.h" 12 12 #include "pmFringeStats.h" 13 14 #include "psPolynomialMD.h" 15 #include "psMinimizePolyFit.h" 16 #include "psVector.h" 17 13 18 14 19 // Future optimisations for speed: … … 331 336 dfPt[i] = 1.0 / medianSd->sampleStdev; 332 337 333 psTrace("psModules.detrend", 7, "[%d:%d,%d:%d]: %f %f \n", (int)region.x0, (int)region.x1,334 (int)region.y0, (int)region.y1, fPt[i], dfPt[i] );338 psTrace("psModules.detrend", 7, "[%d:%d,%d:%d]: %f %f : %s\n", (int)region.x0, (int)region.x1, 339 (int)region.y0, (int)region.y1, fPt[i], dfPt[i], readout->parent->hdu->extname); 335 340 } 336 341 psFree(sky); … … 840 845 } 841 846 } 842 B->data.F64[i] = vector;847 B->data.F64[i] = vector; 843 848 } 844 849 … … 966 971 } 967 972 } 973 968 974 } 969 975 … … 988 994 psTrace("psModules.detrend", 9, "Masking region %d because not finite in fringe %d.\n", j, i); 989 995 } 990 } 991 } 992 996 else if (fabs(fringe->f->data.F32[j]) > 0.1) { 997 mask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 1; 998 psTrace("psModules.detrend", 9, "Masking region %d because too large fringe %d.\n", j, i); 999 } 1000 // Mask bad points in the science data as well. 1001 if ((i == 0) && (!isfinite(science->f->data.F32[j]))) { 1002 mask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 1; 1003 psTrace("psModules.detrend", 9, "Masking region %d because not finite in science fringe %d.\n", j, i); 1004 } 1005 psTrace("psModules.detrend", 7, "F %f %f %f %d\n", 1006 fringe->f->data.F32[j], science->f->data.F32[j], 1007 1 / science->df->data.F32[j],(int) mask->data.PS_TYPE_VECTOR_MASK_DATA[j]); 1008 } 1009 } 1010 1011 /* // Begin switch from old outlier removal and fitting code. */ 1012 1013 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, 1); 1014 1015 pmFringeStats *fringe = fringes->data[0]; 1016 psVector *errors = psVectorAlloc(science->df->n,PS_TYPE_F32); 1017 for (int j = 0; j < errors->n; j++) { 1018 errors->data.F32[j] = 1 / science->df->data.F32[j]; 1019 } 1020 psVectorFitPolynomial1D(poly,mask,0xff,science->f,errors,fringe->f); 1021 1022 for (int i = 0; i <= poly->nX; i++) { 1023 scale->coeff->data.F32[i] = poly->coeff[i]; 1024 psTrace("psModules.detrend",7,"COEFFS: %d %g %g %g\n",i,scale->coeff->data.F32[i],poly->coeff[i],poly->coeffErr[i]); 1025 } 1026 1027 psFree(poly); 1028 // psFree(fringe); 1029 psFree(errors); 1030 1031 psFree(median); 1032 psFree(diff); 1033 return scale; 1034 // End switch from old code. 1035 1036 1037 993 1038 # if (0) 994 1039 // Write fringe data to file for a test … … 1019 1064 } 1020 1065 scale->coeff->data.F32[0] -= median->sampleMedian; 1021 scale->coeff->data.F32[i] = 0.0; 1066 if (i != 0) { 1067 scale->coeff->data.F32[i] = 0.0; 1068 } 1022 1069 } 1023 1070 psFree(median); … … 1051 1098 1052 1099 return scale; 1100 //# endif 1053 1101 } 1054 1102 -
branches/simtest_nebulous_branches/psModules/src/detrend/pmMaskBadPixels.c
r24113 r27840 266 266 } 267 267 } 268 psFree(histo); 268 269 269 270 // Since the mode is most likely zero, we add one to get something realistic. Then "thresh" is -
branches/simtest_nebulous_branches/psModules/src/detrend/pmPattern.c
r24905 r27840 1 1 #include <stdio.h> 2 #include <string.h> 2 3 #include <pslib.h> 3 4 … … 9 10 // Mask a row as bad 10 11 static void patternMaskRow(pmReadout *ro, // Readout to mask 11 int y, // Row to mask12 int y, // Row to mask 12 13 psImageMaskType bad // Mask value to give 13 14 ) … … 17 18 psAssert(y < image->numRows, "Row not in image"); 18 19 19 int numCols = image->numCols; // Size of image20 int numCols = image->numCols; // Number of columns 20 21 for (int x = 0; x < numCols; x++) { 21 22 image->data.F32[y][x] = NAN; … … 29 30 return; 30 31 } 32 33 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 34 // Measurement and application 35 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 31 36 32 37 bool pmPatternRow(pmReadout *ro, int order, int iter, float rej, float thresh, … … 63 68 float lower = stats->robustMedian - thresh * stats->robustStdev; // Lower bound for data 64 69 float upper = stats->robustMedian + thresh * stats->robustStdev; // Upper bound for data 70 float background = stats->robustMedian; 65 71 psFree(stats); 66 72 psFree(rng); … … 79 85 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, order); // Polynomial to fit 80 86 psVector *data = psVectorAlloc(numCols, PS_TYPE_F32); // Data to fit 87 88 psImage *corr = psImageAlloc(order + 1, numRows, PS_TYPE_F64); // Corrections applied 89 psImageInit(corr, NAN); 81 90 82 91 for (int y = 0; y < numRows; y++) { … … 104 113 continue; 105 114 } 115 116 poly->coeff[0] -= background; 117 memcpy(corr->data.F64[y], poly->coeff, (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 106 118 psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector 107 119 if (!solution) { … … 117 129 psFree(solution); 118 130 } 131 132 psMetadataAddImage(ro->analysis, PS_LIST_TAIL, PM_PATTERN_ROW_CORRECTION, PS_META_REPLACE, 133 "Pattern row correction", corr); 134 psFree(corr); 119 135 120 136 psFree(indices); … … 126 142 return true; 127 143 } 144 145 bool pmPatternRowApply(pmReadout *ro, psImageMaskType maskBad) 146 { 147 PM_ASSERT_READOUT_NON_NULL(ro, false); 148 PM_ASSERT_READOUT_IMAGE(ro, false); 149 150 bool mdok; // Status of MD lookup 151 psImage *corr = psMetadataLookupPtr(&mdok, ro->analysis, PM_PATTERN_ROW_CORRECTION); // Correction 152 if (!mdok) { 153 // No correction to apply 154 return true; 155 } 156 157 psImage *image = ro->image; // Image of interest 158 int numCols = image->numCols, numRows = image->numRows; // Size of image 159 160 if (corr->numRows != numRows) { 161 psError(PS_ERR_BAD_PARAMETER_SIZE, true, 162 "Number of rows of image (%d) does not match number of rows of pattern correction (%d)\n", 163 numRows, corr->numRows); 164 return false; 165 } 166 167 int order = corr->numCols - 1; // Polynomial order 168 psPolynomial1D *poly = psPolynomial1DAlloc(PS_POLYNOMIAL_ORD, order); // Polynomial to apply 169 psVector *indices = psVectorAlloc(numCols, PS_TYPE_F32); // Indices for polynomial 170 float norm = 2.0 / (float)numCols; // Normalisation for indices 171 for (int x = 0; x < numCols; x++) { 172 indices->data.F32[x] = x * norm - 1.0; 173 } 174 175 for (int y = 0; y < numRows; y++) { 176 memcpy(poly->coeff, corr->data.F64[y], (order + 1) * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 177 psVector *solution = psPolynomial1DEvalVector(poly, indices); // Solution vector 178 if (!solution) { 179 psWarning("Unable to evaluate polynomial for row %d", y); 180 psErrorClear(); 181 patternMaskRow(ro, y, maskBad); 182 continue; 183 } 184 185 for (int x = 0; x < numCols; x++) { 186 image->data.F32[y][x] -= solution->data.F32[x]; 187 } 188 psFree(solution); 189 } 190 191 psFree(poly); 192 psFree(indices); 193 194 return true; 195 } 196 197 198 bool pmPatternCell(pmChip *chip, const psVector *tweak, psStatsOptions bgStat, psStatsOptions cellStat, 199 psImageMaskType maskVal, psImageMaskType maskBad) 200 { 201 PS_ASSERT_PTR_NON_NULL(chip, false); 202 PS_ASSERT_VECTOR_NON_NULL(tweak, false); 203 PS_ASSERT_VECTOR_SIZE(tweak, chip->cells->n, false); 204 PS_ASSERT_VECTOR_TYPE(tweak, PS_TYPE_U8, false); 205 206 int numCells = tweak->n; // Number of cells 207 208 psVector *mean = psVectorAlloc(numCells, PS_TYPE_F32); // Mean for each cell 209 psVector *meanMask = psVectorAlloc(numCells, PS_TYPE_VECTOR_MASK); // Mask for means 210 psVectorInit(mean, NAN); 211 psVectorInit(meanMask, 0); 212 213 // Mask bits 214 enum { 215 PM_PATTERN_IGNORE = 0x01, // Ignore this cell 216 PM_PATTERN_TWEAK = 0x02, // Tweak this cell 217 PM_PATTERN_ERROR = 0x04, // Error in calculating background 218 PM_PATTERN_ALL = 0xFF, // All causes 219 }; 220 221 // Count number of cells to tweak 222 int numTweak = 0; // Number of cells to tweak 223 int numIgnore = 0; // Number of cells to ignore 224 for (int i = 0; i < numCells; i++) { 225 pmCell *cell = chip->cells->data[i]; // Cell of interest 226 if (!cell || !cell->data_exists || !cell->process || 227 cell->readouts->n == 0 || cell->readouts->n > 1 || !cell->readouts->data[0]) { 228 numIgnore++; 229 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PM_PATTERN_IGNORE; 230 continue; 231 } 232 if (tweak->data.U8[i]) { 233 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PM_PATTERN_TWEAK; 234 numTweak++; 235 } 236 } 237 if (numTweak == 0) { 238 // Nothing to do 239 psFree(mean); 240 psFree(meanMask); 241 return true; 242 } 243 if (numTweak >= numCells - numIgnore) { 244 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Cannot pattern-correct all cells within a chip."); 245 psFree(mean); 246 psFree(meanMask); 247 return false; 248 } 249 250 // Measure mean of each cell 251 // This is not really the perfect thing to do, which would be to take a common mean for the set of cells 252 // which aren't being tweaked (because some cells will be heavily masked, so shouldn't be weighted the 253 // same as pure cells), but it's simple and fast. 254 psStats *bgStats = psStatsAlloc(bgStat); // Statistics on background 255 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 256 for (int i = 0; i < numCells; i++) { 257 if (meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PM_PATTERN_IGNORE) { 258 continue; 259 } 260 pmCell *cell = chip->cells->data[i]; // Cell of interest 261 pmReadout *ro = cell->readouts->data[0]; // Readout of interest 262 263 psStatsInit(bgStats); 264 #if 1 265 if (!psImageBackground(bgStats, NULL, ro->image, ro->mask, maskVal, rng)) { 266 psWarning("Unable to measure background for cell %d\n", i); 267 psErrorClear(); 268 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PM_PATTERN_ERROR; 269 continue; 270 } 271 #else 272 if (!psImageStats(bgStats, ro->image, ro->mask, maskVal)) { 273 psWarning("Unable to measure background for cell %d\n", i); 274 psErrorClear(); 275 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PM_PATTERN_ERROR; 276 continue; 277 } 278 #endif 279 mean->data.F32[i] = psStatsGetValue(bgStats, bgStat); 280 if (!isfinite(mean->data.F32[i])) { 281 psWarning("Non-finite background for cell %d\n", i); 282 psErrorClear(); 283 meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PM_PATTERN_ERROR; 284 continue; 285 } 286 } 287 psFree(bgStats); 288 psFree(rng); 289 290 psStats *cellStats = psStatsAlloc(cellStat); // Statistics on cells 291 if (!psVectorStats(cellStats, mean, NULL, meanMask, PM_PATTERN_ALL)) { 292 // an error in psVectorStats implies a programming error 293 psError(PS_ERR_UNKNOWN, false, "Unable to calculate mean cell background."); 294 psFree(mean); 295 psFree(meanMask); 296 psFree(cellStats); 297 return false; 298 } 299 300 float background = psStatsGetValue(cellStats, cellStat); // Background value for chip 301 psFree(cellStats); 302 if (!isfinite(background)) { 303 // this can happen if all data in the image is bad -- in this case, do not correct, but 304 // do not treat this as an error (other functions are responsible for check data validity) 305 psLogMsg("psModules.detrend", PS_LOG_DETAIL, "Non-finite mean cell background -- skipping correction (data probabaly bad)."); 306 psFree(mean); 307 psFree(meanMask); 308 return true; 309 } 310 311 psLogMsg("psModules.detrend", PS_LOG_DETAIL, "Mean chip background is %f", background); 312 313 for (int i = 0; i < numCells; i++) { 314 if (meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PM_PATTERN_IGNORE) { 315 continue; 316 } 317 if (!(meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PM_PATTERN_TWEAK)) { 318 continue; 319 } 320 pmCell *cell = chip->cells->data[i]; // Cell of interest 321 pmReadout *ro = cell->readouts->data[0]; // Readout of interest 322 if (meanMask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PM_PATTERN_ERROR) { 323 psImageInit(ro->image, NAN); 324 psBinaryOp(ro->mask, ro->mask, "|", psScalarAlloc(maskBad, PS_TYPE_IMAGE_MASK)); 325 psMetadataAddF32(ro->analysis, PS_LIST_TAIL, PM_PATTERN_CELL_CORRECTION, PS_META_REPLACE, 326 "Pattern cell correction solution", NAN); 327 continue; 328 } 329 float correction = background - mean->data.F32[i]; // Correction to apply 330 const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); // Name of cell 331 psLogMsg("psModules.detrend", PS_LOG_DETAIL, "Correcting background of cell %s by %f", 332 cellName, correction); 333 psBinaryOp(ro->image, ro->image, "+", psScalarAlloc(correction, PS_TYPE_F32)); 334 psMetadataAddF32(ro->analysis, PS_LIST_TAIL, PM_PATTERN_CELL_CORRECTION, PS_META_REPLACE, 335 "Pattern cell correction solution", correction); 336 } 337 338 psFree(mean); 339 psFree(meanMask); 340 341 return true; 342 } 343 344 bool pmPatternCellApply(pmReadout *ro, psImageMaskType maskBad) 345 { 346 PM_ASSERT_READOUT_NON_NULL(ro, false); 347 PM_ASSERT_READOUT_IMAGE(ro, false); 348 349 bool mdok; // Status of MD lookup 350 float corr = psMetadataLookupF32(&mdok, ro->analysis, PM_PATTERN_CELL_CORRECTION); // Correction to apply 351 if (!mdok) { 352 // No correction to apply 353 return true; 354 } 355 356 psImage *image = ro->image, *mask = ro->mask; // Image and mask of interest 357 int numCols = image->numCols, numRows = image->numRows; // Size of image 358 359 if (!isfinite(corr)) { 360 for (int y = 0; y < numRows; y++) { 361 for (int x = 0; x < numCols; x++) { 362 image->data.F32[y][x] = NAN; 363 } 364 } 365 if (mask) { 366 for (int y = 0; y < numRows; y++) { 367 for (int x = 0; x < numCols; x++) { 368 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= maskBad; 369 } 370 } 371 } 372 } else { 373 for (int y = 0; y < numRows; y++) { 374 for (int x = 0; x < numCols; x++) { 375 image->data.F32[y][x] += corr; 376 } 377 } 378 } 379 380 return true; 381 } 382 383 -
branches/simtest_nebulous_branches/psModules/src/detrend/pmPattern.h
r24903 r27840 18 18 /// @{ 19 19 20 #define PM_PATTERN_ROW_CORRECTION "PATTERN.ROW.CORRECTION" // Pattern row correction on analysis metadata 21 #define PM_PATTERN_CELL_CORRECTION "PATTERN.CELL.CORRECTION" // Pattern cell correction on analysis metadata 22 20 23 /// Fit and remove pattern noise over rows 21 24 bool pmPatternRow( … … 31 34 ); 32 35 36 /// Apply previously measured row pattern correction 37 bool pmPatternRowApply(pmReadout *ro, ///< Readout to correct 38 psImageMaskType maskBad ///< Mask value to give bad pixels 39 ); 40 41 /// Fix the background on cells known to be troublesome 42 bool pmPatternCell( 43 pmChip *chip, ///< Chip to correct 44 const psVector *tweak, ///< U8 vector indicating whether to tweak the corresponding cell 45 psStatsOptions bgStat, ///< Statistic to use for background measurement 46 psStatsOptions cellStat, ///< Statistic to use for combination of cell background measurements 47 psImageMaskType maskVal, ///< Mask value to use 48 psImageMaskType maskBad ///< Mask value to give bad pixels 49 ); 50 51 /// Apply previously measured cell pattern correction 52 bool pmPatternCellApply(pmReadout *ro, ///< Readout to correct 53 psImageMaskType maskBad ///< Mask value to give bad pixels 54 ); 55 56 33 57 /// @} 34 58 #endif -
branches/simtest_nebulous_branches/psModules/src/detrend/pmShutterCorrection.c
r23989 r27840 1015 1015 1016 1016 pmShutterCorrection *corr = pmShutterCorrectionFullFit(newtimes, newcounts, newerrors, guess); // The actual correction 1017 psTrace("psModules.detrend", 5, "Shutter correction fit: scale: %f, offset: %f, offref: %f\n", corr->scale, corr->offset, corr->offref); 1018 1019 if (corr && isfinite(corr->offref) && corr->valid) { 1020 psTrace("psModules.detrend", 5, "Sample reference value: %f\n", corr->offref); 1021 meanRef += corr->offref; 1022 numGood++; 1023 } 1017 1018 if (corr) { 1019 psTrace("psModules.detrend", 5, "Shutter correction fit: scale: %f, offset: %f, offref: %f\n", corr->scale, corr->offset, corr->offref); 1020 if (isfinite(corr->offref) && corr->valid) { 1021 psTrace("psModules.detrend", 5, "Sample reference value: %f\n", corr->offref); 1022 meanRef += corr->offref; 1023 numGood++; 1024 } 1025 } else { 1026 psTrace("psModules.detrend", 5, "failed Shutter correction fit\n"); 1027 } 1024 1028 1025 1029 psFree(corr); -
branches/simtest_nebulous_branches/psModules/src/extras/Makefile.am
r24880 r27840 17 17 pmKapaPlots.h \ 18 18 pmVisual.h \ 19 ippDiffMode.h \ 19 20 ippStages.h 20 21 -
branches/simtest_nebulous_branches/psModules/src/extras/ippStages.h
r24880 r27840 1 /* @file psVisual.h1 /* @file ippStages.h 2 2 * @brief some macro defintions for the stages of the pipeline 3 3 * @author Bill Sweeney, IfA -
branches/simtest_nebulous_branches/psModules/src/extras/pmVisual.c
r23989 r27840 22 22 #include "pmSubtractionStamps.h" 23 23 #include "pmTrend2D.h" 24 #include "pmPSF.h" 25 #include "pmPSFtry.h" 26 #include "pmSource.h" 24 27 #include "pmFPAExtent.h" 25 28 … … 86 89 { 87 90 char key[10]; 88 fprintf (stdout, "[c]ontinue? [s]kip the rest of these plots? [a]bort all visual plots?"); 91 if (plotFlag) { 92 fprintf (stdout, "[c]ontinue? [s]kip the rest of these plots? [a]bort all visual plots? (c) "); 93 } else { 94 fprintf (stdout, "[c]ontinue? [a]bort all visual plots? (c) "); 95 } 89 96 if (!fgets(key, 8, stdin)) { 90 97 psWarning("Unable to read option"); 91 98 } 92 if ( key[0] == 's') {99 if (plotFlag && (key[0] == 's')) { 93 100 *plotFlag = false; 94 101 } -
branches/simtest_nebulous_branches/psModules/src/imcombine/Makefile.am
r23242 r27840 13 13 pmSubtractionIO.c \ 14 14 pmSubtractionKernels.c \ 15 pmSubtractionHermitian.c \ 16 pmSubtractionDeconvolve.c \ 15 17 pmSubtractionMask.c \ 16 18 pmSubtractionMatch.c \ … … 32 34 pmSubtractionIO.h \ 33 35 pmSubtractionKernels.h \ 36 pmSubtractionHermitian.h \ 37 pmSubtractionDeconvolve.h \ 34 38 pmSubtractionMask.h \ 35 39 pmSubtractionMatch.h \ -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmImageCombine.c
r23989 r27840 118 118 psImage *mask = masks->data[i]; // Mask of interest 119 119 pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[i] = (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal); 120 } 121 // Set the pixel error data, if necessary120 } 121 // Set the pixel error data, if necessary 122 122 if (errors) { 123 123 psImage *error = errors->data[i]; // Error image of interest … … 132 132 // Combine all the pixels, using the specified stat. 133 133 if (!psVectorStats(stats, pixelData, pixelErrors, pixelMasks, 0xff)) { 134 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");135 return false;136 }137 if (isnan(stats->sampleMean)) {134 psError(PS_ERR_UNKNOWN, false, "failure to measure stats"); 135 return false; 136 } 137 if (isnan(stats->sampleMean)) { 138 138 combine->data.F32[y][x] = NAN; 139 139 psFree(buffer); … … 141 141 } 142 142 float combinedPixel = stats->sampleMean; // Value of the combination 143 143 144 144 if (iter == 0) { 145 145 // Save the value produced with no rejection, since it may be useful later … … 369 369 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN); 370 370 if (!psVectorStats(stats, pixels, NULL, mask, 1)) { 371 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");371 psError(PS_ERR_UNKNOWN, false, "failure to measure stats"); 372 372 } 373 373 float median = stats->sampleMedian; … … 640 640 (psPlaneTransform * )outToIn->data[otherImg], 641 641 outCoords); 642 psS32 xPix = (int)(inCoords->x +0.5);643 psS32 yPix = (int)(inCoords->y +0.5);642 psS32 xPix = (int)(inCoords->x - 0.5); 643 psS32 yPix = (int)(inCoords->y - 0.5); 644 644 if ((xPix >= 0) && (xPix <= ((psImage*)(images->data[otherImg]))->numCols - 1) && 645 645 (yPix >= 0) && (yPix <= ((psImage*)(images->data[otherImg]))->numRows - 1)) { -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmPSFEnvelope.c
r24622 r27840 34 34 35 35 // #define TESTING // Enable test output 36 // #define PEAK_NORM // Normalise peaks? 36 37 #define PEAK_FLUX 1.0e4 // Peak flux for each source 37 38 #define SKY_VALUE 0.0e0 // Sky value for fake image … … 64 65 int radius, // Radius of each PSF 65 66 const char *modelName,// Name of PSF model to use 66 int xOrder, int yOrder // Order for PSF variation fit 67 int xOrder, int yOrder, // Order for PSF variation fit 68 psImageMaskType maskVal 67 69 ) 68 70 { … … 122 124 continue; 123 125 } 126 127 if (psTraceGetLevel("psModules.imcombine") >= 1) { 128 psString string = NULL; // String with values 129 psStringAppend(&string, "PSF %d: ", i); 130 float x = numCols / 2.0, y = numRows / 2.0; // Coordinates of interest 131 for (int j = 4; j < psf->params->n; j++) { 132 pmTrend2D *trend = psf->params->data[j]; // Trend of interest 133 double val = pmTrend2DEval(trend, x, y); 134 double err; 135 switch (trend->mode) { 136 case PM_TREND_POLY_ORD: 137 case PM_TREND_POLY_CHEB: 138 err = NAN; 139 break; 140 case PM_TREND_MAP: 141 err = psImageUnbinPixel(x, y, trend->map->error, trend->map->binning); 142 break; 143 default: 144 psAbort("Unsupported mode: %x", trend->mode); 145 } 146 psStringAppend(&string, "%lf %lf ", val, err); 147 } 148 psTrace("psModules.imcombine", 1, "%s\n", string); 149 psFree(string); 150 } 151 152 // Test PSF 153 { 154 bool goodPSF = false; // Is there a PSF that we can use? 155 int xNum = PS_MAX(psf->trendNx, 1), yNum = PS_MAX(psf->trendNy, 1); // Number of positions to check 156 for (int j = 0; j < yNum && !goodPSF; j++) { 157 float y = ((float)j + 0.5) / (float)yNum * numRows; // Position on image 158 for (int i = 0; i < xNum && !goodPSF; i++) { 159 float x = ((float)i + 0.5) / (float)xNum * numCols; // Position on image 160 pmModelClassSetLimits(PM_MODEL_LIMITS_IGNORE); 161 pmModel *model = pmModelFromPSFforXY(psf, x, y, PEAK_FLUX); // Test model 162 if (!model) { 163 continue; 164 } 165 model->modelSetLimits(PM_MODEL_LIMITS_MODERATE); 166 bool limits = true; // Model within limits? 167 for (int j = 0; j < model->params->n && limits; j++) { 168 if (!model->modelLimits(PS_MINIMIZE_PARAM_MIN, j, model->params->data.F32, NULL) || 169 !model->modelLimits(PS_MINIMIZE_PARAM_MAX, j, model->params->data.F32, NULL)) { 170 limits = false; 171 } 172 } 173 psFree(model); 174 if (limits) { 175 goodPSF = true; 176 } 177 } 178 } 179 if (!goodPSF) { 180 psWarning("PSF %d is completely bad --- not including in envelope calculation.", i); 181 continue; 182 } 183 } 184 124 185 pmResiduals *resid = psf->residuals;// PSF residuals 125 186 psf->residuals = NULL; 126 if (!pmReadoutFakeFromSources(fakeRO, fakeSize, fakeSize, fakes, xOffset, yOffset, psf, 127 NAN, radius, true, true)) { 187 pmModelClassSetLimits(PM_MODEL_LIMITS_MODERATE); 188 if (!pmReadoutFakeFromSources(fakeRO, fakeSize, fakeSize, fakes, 0, xOffset, yOffset, psf, 189 NAN, radius, true, false)) { 128 190 psError(PS_ERR_UNKNOWN, false, "Unable to generate fake readout."); 129 191 psFree(envelope); … … 144 206 float y = source->peak->yf + yOffset->data.S32[j]; // y coordinate of source 145 207 146 double flux = fakeRO->image->data.F32[(int)y][(int)x]; 208 #ifdef PEAK_NORM 209 // Perhaps I'm being paranoid, but specify a range to check 210 int uMax = PS_MIN(x + radius, numCols - 1), uMin = PS_MAX(x - radius, 0); 211 int vMax = PS_MIN(y + radius, numRows - 1), vMin = PS_MAX(y - radius, 0); 212 213 double flux = -INFINITY; // Peak flux 214 for (int v = vMin; v <= vMax; v++) { 215 for (int u = uMin; u <= uMax; u++) { 216 if (fakeRO->image->data.F32[v][u] > flux) { 217 flux = fakeRO->image->data.F32[v][u]; 218 } 219 } 220 } 147 221 if (!isfinite(flux) || flux < 0) { 148 222 continue; 149 223 } 150 224 float norm = PEAK_FLUX / flux; // Normalisation for source 225 #endif 151 226 psRegion region = psRegionSet(x - radius, x + radius, y - radius, y + radius); // PSF region 152 227 psImage *subImage = psImageSubset(fakeRO->image, region); // Subimage of fake PSF 153 228 psImage *subEnv = psImageSubset(envelope, region); // Subimage of envelope 229 #ifdef PEAK_NORM 154 230 psBinaryOp(subImage, subImage, "*", psScalarAlloc(norm, PS_TYPE_F32)); 231 #endif 155 232 psBinaryOp(subEnv, subEnv, "MAX", subImage); 156 233 psFree(subImage); … … 163 240 } 164 241 float srcRadius = model->modelRadius(model->params, PS_SQR(VARIANCE_VAL)); // Radius for source 242 psFree(model); 165 243 if (srcRadius == 0) { 166 244 continue; … … 298 376 } 299 377 300 // measure the source moments: tophat windowing, no pixel S/N cutoff 301 if (!pmSourceMoments(source, maxRadius, 0.0, 1.0)) { 378 // measure the source moments: tophat windowing, no pixel S/N cutoff 379 // XXX probably should be passing the maskVal to this function so we can pass it along here... 380 if (!pmSourceMoments(source, maxRadius, 0.0, 1.0, maskVal)) { 302 381 // Can't do anything about it; limp along as best we can 303 382 psErrorClear(); … … 320 399 options->poissonErrorsParams = true; 321 400 options->stats = psStatsAlloc(PSF_STATS); 322 options->radius = maxRadius; 401 options->fitRadius = maxRadius; 402 options->apRadius = maxRadius; // XXX need to decide if aperture mags need a different radius 323 403 options->psfTrendMode = PM_TREND_MAP; 324 404 options->psfTrendNx = xOrder; … … 331 411 332 412 pmSourceFitModelInit(SOURCE_FIT_ITERATIONS, 0.01, VARIANCE_VAL, true); 413 pmModelClassSetLimits(PM_MODEL_LIMITS_STRICT); // Important for getting a good stack target PSF 333 414 334 415 pmPSFtry *try = pmPSFtryModel(fakes, modelName, options, 0, 0xff); … … 343 424 pmPSF *psf = psMemIncrRefCounter(try->psf); // Output PSF 344 425 psFree(try); 426 427 if (psTraceGetLevel("psModules.imcombine") >= 1) { 428 psString string = NULL; // String with values 429 psStringAppend(&string, "Envelope PSF: "); 430 float x = numCols / 2.0, y = numRows / 2.0; // Coordinates of interest 431 for (int j = 4; j < psf->params->n; j++) { 432 pmTrend2D *trend = psf->params->data[j]; // Trend of interest 433 double val = pmTrend2DEval(trend, x, y); 434 double err; 435 switch (trend->mode) { 436 case PM_TREND_POLY_ORD: 437 case PM_TREND_POLY_CHEB: 438 err = NAN; 439 break; 440 case PM_TREND_MAP: 441 err = psImageUnbinPixel(x, y, trend->map->error, trend->map->binning); 442 break; 443 default: 444 psAbort("Unsupported mode: %x", trend->mode); 445 } 446 psStringAppend(&string, "%lf %lf ", val, err); 447 } 448 psTrace("psModules.imcombine", 1, "%s\n", string); 449 psFree(string); 450 } 345 451 346 452 #ifdef TESTING … … 357 463 358 464 pmReadout *generated = pmReadoutAlloc(NULL); // Generated image 359 pmReadoutFakeFromSources(generated, numCols, numRows, fakes, NULL, NULL, psf, NAN, radius,465 pmReadoutFakeFromSources(generated, numCols, numRows, fakes, 0, NULL, NULL, psf, NAN, radius, 360 466 false, true); 361 467 { -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmPSFEnvelope.h
r15837 r27840 17 17 int radius, // Radius of each PSF 18 18 const char *modelName, // Name of PSF model to use 19 int xOrder, int yOrder // Order for PSF variation 19 int xOrder, int yOrder, // Order for PSF variation 20 psImageMaskType maskVal 20 21 ); 21 22 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmStack.c
r23775 r27840 30 30 #define PIXEL_LIST_BUFFER 100 // Number of entries to add to pixel list at a time 31 31 #define PIXEL_MAP_BUFFER 2 // Number of entries to add to pixel map at a time 32 #define ADD_VARIANCE // Allow additional variance (besides variance factor)?32 //#define ADD_VARIANCE // Allow additional variance (besides variance factor)? 33 33 #define NUM_DIRECT_STDEV 5 // For less than this number of values, measure stdev directly 34 34 35 35 36 //#define TESTING // Enable test output 36 //#define TEST_X 1085 // x coordinate to examine 37 //#define TEST_Y 3371 // y coordinate to examine 37 //#define TEST_X 843-1 // x coordinate to examine 38 //#define TEST_Y 813-1 // y coordinate to examine 39 //#define TEST_RADIUS 0 // Radius to examine 38 40 39 41 … … 42 44 typedef struct { 43 45 psVector *pixels; // Pixel values 44 psVector *masks; // Pixel masks45 46 psVector *variances; // Pixel variances 46 47 psVector *weights; // Pixel weightings 48 psVector *exps; // Pixel exposures 47 49 psVector *sources; // Pixel sources (which image did they come from?) 48 50 psVector *limits; // Rejection limits 51 psVector *suspects; // Pixel is suspect? 49 52 psVector *sort; // Buffer for sorting (to get a robust estimator of the standard dev) 50 53 } combineBuffer; … … 53 56 { 54 57 psFree(buffer->pixels); 55 psFree(buffer->masks);56 58 psFree(buffer->variances); 57 59 psFree(buffer->weights); 60 psFree(buffer->exps); 58 61 psFree(buffer->sources); 59 62 psFree(buffer->limits); 63 psFree(buffer->suspects); 60 64 psFree(buffer->sort); 61 65 return; … … 69 73 70 74 buffer->pixels = psVectorAlloc(numImages, PS_TYPE_F32); 71 buffer->masks = psVectorAlloc(numImages, PS_TYPE_VECTOR_MASK);72 75 buffer->variances = psVectorAlloc(numImages, PS_TYPE_F32); 73 76 buffer->weights = psVectorAlloc(numImages, PS_TYPE_F32); 77 buffer->exps = psVectorAlloc(numImages, PS_TYPE_F32); 74 78 buffer->sources = psVectorAlloc(numImages, PS_TYPE_U16); 75 79 buffer->limits = psVectorAlloc(numImages, PS_TYPE_F32); 80 buffer->suspects = psVectorAlloc(numImages, PS_TYPE_U8); 76 81 buffer->sort = psVectorAlloc(numImages, PS_TYPE_F32); 77 82 return buffer; … … 93 98 static bool combinationMeanVariance(float *mean, // Mean value, to return 94 99 float *var, // Variance value, to return 100 float *exp, // Exposure time, to return 101 float *expWeight, // Weighted exposure time, to return 95 102 const psVector *values, // Values to combine 96 103 const psVector *variances, // Pixel variances to combine 104 const psVector *exps, // Exposure times to combine 97 105 const psVector *weights // Weights to apply 98 106 ) … … 119 127 float sumVarianceWeight = 0.0; // Sum of the pixel variances multiplied by the global weights 120 128 float sumWeight = 0.0; // Sum of the image weights 129 float sumExp = 0.0; // Sum of the exposure time 130 float sumExpWeight = 0.0; // Sum of the exposure time multiplied by the global weights 131 int numGood = 0; // Number of good exposures 121 132 for (int i = 0; i < values->n; i++) { 122 133 sumValueWeight += values->data.F32[i] * weights->data.F32[i]; … … 125 136 sumVarianceWeight += variances->data.F32[i] * PS_SQR(weights->data.F32[i]); 126 137 } 138 if (exps) { 139 sumExp += exps->data.F32[i]; 140 sumExpWeight += exps->data.F32[i] * weights->data.F32[i]; 141 numGood++; 142 } 127 143 } 128 144 … … 134 150 if (var) { 135 151 *var = sumVarianceWeight / PS_SQR(sumWeight); 152 } 153 if (exp) { 154 *exp = sumExp; 155 } 156 if (expWeight) { 157 *expWeight = sumExpWeight; 136 158 } 137 159 return true; … … 143 165 float *stdev, // Standard deviation value, to return 144 166 const psVector *values, // Values to combine 145 const psVector *masks, // Mask to apply146 167 psVector *sortBuffer // Buffer for sorting 147 168 ) 148 169 { 149 170 assert(values); 150 assert(!masks || values->n == masks->n);151 171 assert(values->type.type == PS_TYPE_F32); 152 assert(!masks || masks->type.type == PS_TYPE_VECTOR_MASK);153 172 assert(sortBuffer && sortBuffer->nalloc >= values->n && sortBuffer->type.type == PS_TYPE_F32); 154 173 155 // Need to filter out clipped values 156 int num = 0; // Number of valid values 157 for (int i = 0; i < values->n; i++) { 158 if (!masks || !masks->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 159 sortBuffer->data.F32[num++] = values->data.F32[i]; 160 } 161 } 162 sortBuffer->n = num; 163 if (!psVectorSortInPlace(sortBuffer)) { 174 int num = values->n; // Number of values 175 sortBuffer = psVectorSortIndex(sortBuffer, values); 176 if (!sortBuffer) { 177 *median = NAN; 178 *stdev = NAN; 164 179 return false; 165 180 } … … 167 182 if (num == 3) { 168 183 // Attempt to measure standard deviation with only three values (and one of those possibly corrupted) 169 *median = sortBuffer->data.F32[1];184 *median = values->data.F32[sortBuffer->data.S32[1]]; 170 185 if (stdev) { 171 float diff1 = sortBuffer->data.F32[0] - *median;172 float diff2 = sortBuffer->data.F32[2] - *median;186 float diff1 = values->data.F32[sortBuffer->data.S32[0]] - *median; 187 float diff2 = values->data.F32[sortBuffer->data.S32[2]] - *median; 173 188 // This factor of sqrt(2) might not be exact, but it's about right 174 189 *stdev = M_SQRT2 * PS_MIN(fabsf(diff1), fabsf(diff2)); 175 190 } 176 191 } else { 177 *median = num % 2 ? sortBuffer->data.F32[num / 2] : 178 (sortBuffer->data.F32[num / 2 - 1] + sortBuffer->data.F32[num / 2]) / 2.0; 192 *median = num % 2 ? values->data.F32[sortBuffer->data.S32[num / 2]] : 193 (values->data.F32[sortBuffer->data.S32[num / 2 - 1]] + 194 values->data.F32[sortBuffer->data.S32[num / 2]]) / 2.0; 179 195 if (stdev) { 180 196 if (num <= NUM_DIRECT_STDEV) { … … 182 198 double sum = 0.0; 183 199 for (int i = 0; i < num; i++) { 184 sum += PS_SQR( sortBuffer->data.F32[i] - *median);200 sum += PS_SQR(values->data.F32[sortBuffer->data.S32[i]] - *median); 185 201 } 186 202 *stdev = sqrt(sum / (double)(num - 1)); 187 203 } else { 188 204 // Standard deviation from the interquartile range 189 *stdev = 0.74 * ( sortBuffer->data.F32[(int)(0.75 * num)] -190 sortBuffer->data.F32[(int)(0.25 * num)]);205 *stdev = 0.74 * (values->data.F32[sortBuffer->data.S32[(int)(0.75 * num)]] - 206 values->data.F32[sortBuffer->data.S32[(int)(0.25 * num)]]); 191 207 } 192 208 } … … 195 211 return true; 196 212 } 197 198 #if 0199 // Return the weighted median for the pixels200 // This does not appear to produce as clean images as the weighted Olympic mean201 static float combinationWeightedMedian(const psVector *values, // Values to combine202 const psVector *weights, // Weights to combine203 const psVector *masks, // Mask to apply204 psVector *sortBuffer // Buffer for sorting205 )206 {207 double sumWeight = 0.0; // Sum of weights208 for (int j = 0; j < values->n; j++) {209 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {210 continue;211 }212 sumWeight += weights->data.F32[j];213 }214 215 sortBuffer = psVectorSortIndex(sortBuffer, values);216 double target = sumWeight / 2.0; // Target weight217 218 int dominant = -1; // Index of dominant value, if any219 double cumulativeWeight = 0.0; // Sum of weights220 for (int j = 0; j < values->n; j++) {221 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {222 continue;223 }224 int index = sortBuffer->data.S32[j]; // Index of value of interest225 float weight = weights->data.F32[index]; // Weight for value of interest226 if (weight >= target) {227 // Get the weighted median of the rest228 dominant = index;229 sumWeight -= weight;230 target = sumWeight / 2.0;231 continue;232 }233 cumulativeWeight += weight;234 if (cumulativeWeight >= target) {235 float median = values->data.F32[index]; // Weighted median median236 if (dominant != -1) {237 // In the case that a single value contains a disproportionate weight compared to the rest,238 // we use a weighted mean between that dominant value and the weighted median of the rest.239 return (values->data.F32[dominant] * weights->data.F32[dominant] + median * sumWeight) /240 (weights->data.F32[dominant] + sumWeight);241 }242 return median;243 }244 }245 246 return NAN;247 }248 #endif249 213 250 214 // Return the weighted Olympic mean for the pixels 251 215 static float combinationWeightedOlympic(const psVector *values, // Values to combine 252 216 const psVector *weights, // Weights to combine 253 const psVector *masks, // Mask to apply254 217 float frac, // Fraction to discard 255 218 psVector *sortBuffer // Buffer for sorting 256 219 ) 257 220 { 258 int numGood = 0; // Number of good values 259 for (int i = 0; i < values->n; i++) { 260 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 261 continue; 262 } 263 numGood++; 264 } 221 int numGood = values->n; // Number of good values 265 222 266 223 int numBad = frac * numGood + 0.5; // Number of bad values … … 272 229 for (int i = 0, j = 0; i < values->n; i++) { 273 230 int index = sortBuffer->data.S32[i]; // Index of interest 274 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[index]) {275 continue;276 }277 231 j++; 278 232 if (j > high) { … … 290 244 291 245 // Mark a pixel for inspection 292 static inline void combineInspect(const psArray *inputs, // Stack data 293 int x, int y, // Pixel 294 int source // Source image index 295 ) 296 { 246 // Value in pixel doesn't seem to agree with the stack, so need to look closer 247 static inline void combineMarkInspect(const psArray *inputs, // Stack data 248 int x, int y, // Pixel 249 int source // Source image index 250 ) 251 { 252 #ifdef TESTING 253 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 254 fprintf(stderr, "Marking image %d, pixel %d,%d for inspection\n", source, x, y); 255 } 256 #endif 297 257 pmStackData *data = inputs->data[source]; // Stack data of interest 298 258 if (!data) { … … 304 264 } 305 265 306 // Given a stack of images, combine with optional rejection. 307 // Pixels in the stack that are rejected are marked for subsequent inspection 308 static void combinePixels(psImage *image, // Combined image, for output 309 psImage *mask, // Combined mask, for output 310 psImage *variance, // Combined variance map, for output 311 const psArray *inputs, // Stack data 312 const psVector *weights, // Global (single value) weights for data, or NULL 313 const psVector *addVariance, // Additional variance for data 314 const psVector *reject, // Indices of pixels to reject, or NULL 315 int x, int y, // Coordinates of interest; frame of output image 316 psImageMaskType maskVal, // Value to mask 317 psImageMaskType bad, // Value to give bad pixels 318 int numIter, // Number of rejection iterations 319 float rej, // Number of standard deviations at which to reject 320 float sys, // Relative systematic error 321 float discard,// Fraction of values to discard (Olympic weighted mean) 322 bool useVariance, // Use variance for rejection when combining? 323 bool safe, // Combine safely? 324 bool rejectInspect, // Reject values marked for inspection from combination? 325 combineBuffer *buffer // Buffer for combination; to avoid multiple allocations 326 ) 266 // Mark a pixel for rejection 267 // Cannot possibly inspect this pixel and confirm that it's good. 268 // e.g., Only a single input 269 static inline void combineMarkReject(const psArray *inputs, // Stack data 270 int x, int y, // Pixel 271 int source // Source image index 272 ) 273 { 274 #ifdef TESTING 275 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 276 fprintf(stderr, "Marking pixel image %d, pixel %d,%d for rejection\n", source, x, y); 277 } 278 #endif 279 pmStackData *data = inputs->data[source]; // Stack data of interest 280 if (!data) { 281 psWarning("Can't find input data for source %d", source); 282 return; 283 } 284 data->reject = psPixelsAdd(data->reject, data->reject->nalloc, x, y); 285 return; 286 } 287 288 289 // Extract vectors for simple combination/rejection operations 290 static void combineExtract(int *num, // Number of good pixels 291 bool *suspect, // Any suspect pixels? 292 combineBuffer *buffer, // Buffer with vectors 293 psImage *image, // Combined image, for output 294 psImage *mask, // Combined mask, for output 295 psImage *variance, // Combined variance map, for output 296 const psArray *inputs, // Stack data 297 const psVector *weights, // Global (single value) weights for data, or NULL 298 const psVector *exps, // Exposures for data, or NULL 299 const psVector *addVariance, // Additional variance for data 300 const psVector *reject, // Indices of pixels to reject, or NULL 301 int x, int y, // Coordinates of interest; frame of output image 302 psImageMaskType maskVal, // Value to mask 303 psImageMaskType maskSuspect // Value to suspect 304 ) 327 305 { 328 306 // Rudimentary error checking 307 assert(buffer); 329 308 assert(image); 330 309 assert(mask); 331 310 assert(inputs); 332 assert(numIter >= 0);333 assert(buffer);334 assert(addVariance);335 assert((useVariance && variance) || !useVariance);336 311 337 312 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 338 psVector *pixelMasks = buffer->masks; // Masks for the pixel of interest339 313 psVector *pixelVariances = variance ? buffer->variances : NULL; // Variances for the pixel of interest 340 314 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 315 psVector *pixelExps = buffer->exps; // Exposure times 341 316 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 342 317 psVector *pixelLimits = buffer->limits; // Limits for the pixel of interest 343 psVector *sort = buffer->sort; // Sort buffer 318 psVector *pixelSuspects = buffer->suspects; // Is the pixel suspect? 319 320 if (suspect) { 321 *suspect = false; 322 } 344 323 345 324 // Extract the pixel and mask data 346 int num = 0; // Number of good images325 int numGood = 0; // Number of good pixels 347 326 for (int i = 0, j = 0; i < inputs->n; i++) { 348 327 // Check if this pixel has been rejected. Assumes that the rejection pixel list is sorted --- it … … 364 343 } 365 344 345 pixelSuspects->data.U8[numGood] = mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & maskSuspect ? 346 true : false; 347 366 348 psImage *image = data->readout->image; // Image of interest 367 349 psImage *variance = data->readout->variance; // Variance map of interest 368 pixelData->data.F32[num ] = image->data.F32[yIn][xIn];350 pixelData->data.F32[numGood] = image->data.F32[yIn][xIn]; 369 351 if (variance) { 370 pixelVariances->data.F32[num] = variance->data.F32[yIn][xIn] * addVariance->data.F32[i]; 371 } 372 pixelWeights->data.F32[num] = data->weight; 373 pixelSources->data.U16[num] = i; 374 num++; 375 } 376 pixelData->n = num; 352 pixelVariances->data.F32[numGood] = variance->data.F32[yIn][xIn] * addVariance->data.F32[i]; 353 } 354 pixelWeights->data.F32[numGood] = data->weight; 355 pixelExps->data.F32[numGood] = data->exp; 356 pixelSources->data.U16[numGood] = i; 357 numGood++; 358 } 359 pixelData->n = numGood; 377 360 if (variance) { 378 pixelVariances->n = num; 379 } 380 pixelWeights->n = num; 381 pixelSources->n = num; 382 pixelLimits->n = num; 383 384 #ifdef TESTING 385 if (x == TEST_X && y == TEST_Y) { 386 for (int i = 0; i < num; i++) { 387 fprintf(stderr, "Input %d (%" PRIu16 "): %f %f %f\n", 388 i, pixelSources->data.U16[i], pixelData->data.F32[i], pixelVariances->data.F32[i], 389 pixelWeights->data.F32[i]); 390 } 391 } 392 #endif 393 394 // The sensible thing to do varies according to how many good pixels there are. 361 pixelVariances->n = numGood; 362 } 363 pixelWeights->n = numGood; 364 pixelSources->n = numGood; 365 pixelLimits->n = numGood; 366 pixelSuspects->n = numGood; 367 *num = numGood; 368 369 #ifdef TESTING 370 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 371 for (int i = 0; i < numGood; i++) { 372 fprintf(stderr, "Input %d, pixel %d,%d (%" PRIu16 "): %f %f (%f) %f %f %d\n", 373 i, x, y, pixelSources->data.U16[i], pixelData->data.F32[i], pixelVariances->data.F32[i], 374 addVariance->data.F32[i], pixelWeights->data.F32[i], pixelExps->data.F32[i], 375 pixelSuspects->data.U8[i]); 376 } 377 } 378 #endif 379 380 return; 381 } 382 383 384 // Combine pixels 385 static void combinePixels(psImage *image, // Combined image, for output 386 psImage *mask, // Combined mask, for output 387 psImage *variance, // Combined variance map, for output 388 psImage *exp, // Exposure map (time), for output 389 psImage *expnum, // Exposure map (number) for output 390 psImage *expweight, // Exposure map (weighted time) for output 391 int num, // Number of good pixels 392 combineBuffer *buffer, // Buffer with vectors 393 int x, int y, // Coordinates of interest; frame of output image 394 psImageMaskType bad, // Value for bad pixels 395 bool safe, // Safe combination? 396 float invTotalWeight // Inverse of total weight for all inputs 397 ) 398 { 399 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 400 psVector *pixelVariances = variance ? buffer->variances : NULL; // Variances for the pixel of interest 401 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 402 psVector *pixelExps = buffer->exps; // Exposure times 403 395 404 // Default option is that the pixel is bad 396 405 float imageValue = NAN, varianceValue = NAN; // Value for combined image and variance map 397 406 psImageMaskType maskValue = bad; // Value for combined mask 407 float expValue = 0.0, expWeightValue = NAN; // Exposure value (straight, and weighted) 408 398 409 switch (num) { 399 case 0: 400 // Nothing to combine: it's bad 401 #ifdef TESTING 402 if (x == TEST_X && y == TEST_Y) { 403 fprintf(stderr, "No inputs to combine, pixel is bad.\n"); 404 } 405 #endif 406 break; 410 case 0: { 411 // Nothing to combine: it's bad 412 #ifdef TESTING 413 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 414 fprintf(stderr, "No inputs to combine, pixel %d,%d is bad.\n", x, y); 415 } 416 #endif 417 break; 418 } 407 419 case 1: { 408 420 // Accept the single pixel unless we have to be safe 409 421 if (!safe) { 410 #ifdef TESTING411 if (x == TEST_X && y == TEST_Y) {412 fprintf(stderr, "Single input to combine, safety off.\n");413 }414 #endif415 422 imageValue = pixelData->data.F32[0]; 416 423 if (variance) { 417 424 varianceValue = pixelVariances->data.F32[0]; 418 425 } 426 if (exp) { 427 expValue = pixelExps->data.F32[0]; 428 expWeightValue = pixelExps->data.F32[0]; 429 } 419 430 maskValue = 0; 431 #ifdef TESTING 432 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 433 fprintf(stderr, "Single input to combine, safety off, pixel %d,%d --> %f\n", 434 x, y, imageValue); 435 } 436 #endif 420 437 } 421 438 #ifdef TESTING 422 else if ( x == TEST_X && y == TEST_Y) {423 fprintf(stderr, "Single input to combine, safety on, pixel is bad.\n");439 else if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 440 fprintf(stderr, "Single input to combine, safety on, pixel %d,%d is bad.\n", x, y); 424 441 } 425 442 #endif … … 427 444 } 428 445 case 2: { 429 // Accept the mean of the pixels only if we're going to reject based on the variance, or we're not 430 // playing safe 431 if (useVariance || !safe) { 432 float mean, var; // Mean and variance from combination 433 if (combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { 434 imageValue = mean; 435 varianceValue = var; 446 // Automatically accept the mean of the pixels only if we're not playing safe 447 if (!safe) { 448 if (combinationMeanVariance(&imageValue, &varianceValue, &expValue, &expWeightValue, 449 pixelData, pixelVariances, pixelExps, pixelWeights)) { 436 450 maskValue = 0; 437 451 #ifdef TESTING 438 if ( x == TEST_X && y == TEST_Y) {439 fprintf(stderr, "Two inputs to combine using variance/unsafe--> %f %f\n",440 mean, var);452 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 453 fprintf(stderr, "Two inputs to combine using unsafe, pixel %d,%d --> %f %f\n", 454 x, y, imageValue, varianceValue); 441 455 } 442 456 #endif 443 457 } 444 458 } 445 if (useVariance && numIter > 0) { 446 // Use variance to check that the two are consistent 447 float diff = 0.5 * (pixelData->data.F32[0] - pixelData->data.F32[1]); // Mean flux difference 448 float var1 = pixelVariances->data.F32[0]; // Variance of first 449 float var2 = pixelVariances->data.F32[1]; // Variance of second 450 // Systematic error contributes to the rejection level 451 var1 += PS_SQR(sys * pixelData->data.F32[0]); 452 var2 += PS_SQR(sys * pixelData->data.F32[1]); 453 454 float sigma2 = var1 + var2; // Combined variance 455 if (PS_SQR(diff) > PS_SQR(rej) * sigma2) { 456 // Not consistent: mark both for inspection 457 if (rejectInspect) { 458 imageValue = NAN; 459 varianceValue = NAN; 460 maskValue = bad; 461 } else { 462 combineInspect(inputs, x, y, pixelSources->data.U16[0]); 463 combineInspect(inputs, x, y, pixelSources->data.U16[1]); 464 } 465 #ifdef TESTING 466 if (x == TEST_X && y == TEST_Y) { 467 fprintf(stderr, "Both pixels marked for inspection (%f > %f x %f\n)", 468 diff, rej, sqrtf(sigma2)); 469 } 470 #endif 459 #ifdef TESTING 460 else { 461 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 462 fprintf(stderr, "Two inputs to combine, safety on, pixel %d,%d is bad\n", x, y); 471 463 } 472 464 } 465 #endif 473 466 break; 474 467 } 475 468 default: { 476 // Record the value derived with no clipping, because pixels rejected using the harsh clipping 477 // applied in the first pass might later be accepted. 478 float mean, var; // Mean and variance of the combination 479 if (!combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { 469 // Can combine without too much worrying 470 if (!combinationMeanVariance(&imageValue, &varianceValue, &expValue, &expWeightValue, 471 pixelData, pixelVariances, pixelExps, pixelWeights)) { 480 472 break; 481 473 } 482 imageValue = mean;483 varianceValue = var;484 474 maskValue = 0; 485 475 #ifdef TESTING 486 if ( x == TEST_X && y == TEST_Y) {487 fprintf(stderr, "Combined inputs : %f %f\n", mean, var);476 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 477 fprintf(stderr, "Combined inputs, pixel %d,%d --> %f %f\n", x, y, imageValue, varianceValue); 488 478 } 489 479 #endif 490 491 // Prepare for clipping iteration492 if (numIter > 0) {493 pixelMasks->n = num;494 psVectorInit(pixelMasks, 0);495 if (useVariance) {496 // Convert to rejection limits --- saves doing it later.497 // Using squared rejection limit because it's cheaper than sqrts498 float rej2 = PS_SQR(rej); // Rejection level squared499 double sumWeights = 0.0;500 for (int i = 0; i < num; i++) {501 sumWeights += pixelWeights->data.F32[i];502 }503 for (int i = 0; i < num; i++) {504 // Systematic error contributes to the rejection level505 float sysVar = PS_SQR(sys * pixelData->data.F32[i]);506 #ifdef TESTING507 // Correct variance for comparison against weighted mean including itself508 float compare = 1.0 - pixelWeights->data.F32[i] / sumWeights;509 if (x == TEST_X && y == TEST_Y) {510 fprintf(stderr, "Variance %d (%d): %f %f %f\n", i, pixelSources->data.U16[i],511 pixelVariances->data.F32[i], sysVar, compare);512 }513 #endif514 515 pixelLimits->data.F32[i] = rej2 * (pixelVariances->data.F32[i] + sysVar);516 }517 }518 }519 520 // The clipping that follows is solely to identify suspect pixels.521 // These suspect pixels will be inspected in more detail by other functions.522 int numClipped = INT_MAX; // Number of pixels clipped per iteration523 int totalClipped = 0; // Total number of pixels clipped524 for (int i = 0; i < numIter && numClipped > 0 && num - totalClipped > 2; i++) {525 numClipped = 0;526 float median = NAN; // Middle of distribution527 float limit = NAN; // Rejection limit528 if (!useVariance) {529 float stdev; // Median and stdev of the combination, for rejection530 if (!combinationMedianStdev(&median, useVariance ? NULL : &stdev,531 pixelData, pixelMasks, sort)) {532 psWarning("Bad median/stdev at %d,%d", x, y);533 break;534 }535 limit = rej * stdev;536 #ifdef TESTING537 if (x == TEST_X && y == TEST_Y) {538 fprintf(stderr, "Rejecting without variance; rejection limit: %f\n", limit);539 }540 #endif541 } else {542 #ifdef TESTING543 if (x == TEST_X && y == TEST_Y) {544 fprintf(stderr, "Rejecting with variance...\n");545 }546 #endif547 median = combinationWeightedOlympic(pixelData, pixelWeights, pixelMasks, discard, sort);548 }549 550 #ifdef TESTING551 if (x == TEST_X && y == TEST_Y) {552 fprintf(stderr, "Median: %f\n", median);553 }554 #endif555 556 557 // Mask a pixel for inspection558 #define MASK_PIXEL_FOR_INSPECTION() \559 pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xff; \560 if (!rejectInspect) { \561 combineInspect(inputs, x, y, pixelSources->data.U16[j]); \562 } \563 numClipped++; \564 totalClipped++;565 566 for (int j = 0; j < num; j++) {567 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {568 continue;569 }570 float diff = pixelData->data.F32[j] - median; // Difference from expected571 if (useVariance) {572 // Comparing squares --- cheaper than lots of sqrts573 // pixelVariances includes the rejection limit, from above574 if (PS_SQR(diff) > pixelLimits->data.F32[j]) {575 MASK_PIXEL_FOR_INSPECTION();576 #ifdef TESTING577 if (x == TEST_X && y == TEST_Y) {578 fprintf(stderr, "Rejecting input %d based on variance: %f > %f\n",579 j, diff, sqrtf(pixelLimits->data.F32[j]));580 }581 #endif582 }583 } else if (fabsf(diff) > limit) {584 MASK_PIXEL_FOR_INSPECTION();585 #ifdef TESTING586 if (x == TEST_X && y == TEST_Y) {587 fprintf(stderr, "Rejecting input %d based on distribution: %f > %f\n",588 j, diff, limit);589 }590 #endif591 }592 }593 }594 595 if (rejectInspect && totalClipped > 0) {596 // Get rid of the masked values597 // The alternative to this is to make combinationMeanVariance() accept a mask598 int good = 0; // Index of good value599 for (int i = 0; i < num; i++) {600 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[i]) {601 continue;602 }603 if (i != good) {604 pixelData->data.F32[good] = pixelData->data.F32[i];605 pixelVariances->data.F32[good] = pixelVariances->data.F32[i];606 pixelWeights->data.F32[good] = pixelWeights->data.F32[i];607 pixelData->data.F32[good] = pixelData->data.F32[i];608 }609 good++;610 }611 pixelData->n = good;612 pixelVariances->n = good;613 pixelWeights->n = good;614 if (combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) {615 imageValue = mean;616 varianceValue = var;617 maskValue = 0;618 } else {619 imageValue = NAN;620 varianceValue = NAN;621 maskValue = bad;622 }623 }624 625 480 break; 626 481 } … … 632 487 variance->data.F32[y][x] = varianceValue; 633 488 } 489 if (exp) { 490 exp->data.F32[y][x] = expValue; 491 } 492 if (expnum) { 493 expnum->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = num; 494 } 495 if (expweight) { 496 expweight->data.F32[y][x] = expWeightValue * invTotalWeight; 497 } 634 498 635 499 return; 500 } 501 502 503 // Test pixels to be combined 504 // Returns false to repeat without suspect pixels 505 static bool combineTest(int num, // Number of good pixels 506 bool suspect, // Does the stack contain suspect pixels? 507 psArray *inputs, // Original inputs (for flagging) 508 combineBuffer *buffer, // Buffer with vectors 509 int x, int y, // Coordinates of interest; frame of output image 510 float iter, // Number of rejection iterations per input 511 float rej, // Number of standard deviations at which to reject 512 float sys, // Relative systematic error 513 float olympic,// Fraction of values to discard (Olympic weighted mean) 514 bool useVariance, // Use variance for rejection when combining? 515 bool safe // Combine safely? 516 ) 517 { 518 if (iter <= 0) { 519 return true; 520 } 521 522 int numIter = PS_MAX(iter * num, 1); // Number of iterations 523 524 #ifdef TESTING 525 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 526 fprintf(stderr, "Testing pixel %d,%d: %d %f %f %f %d %d\n", 527 x, y, numIter, rej, sys, olympic, useVariance, safe); 528 } 529 #endif 530 531 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 532 psVector *pixelWeights = buffer->weights; // Is the pixel suspect? 533 psVector *pixelVariances = buffer->variances; // Variances for the pixel of interest 534 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 535 psVector *pixelSuspects = buffer->suspects; // Is the pixel suspect? 536 psVector *pixelLimits = buffer->limits; // Is the pixel suspect? 537 538 // Set up rejection limits 539 float rej2 = PS_SQR(rej); // Rejection level squared 540 if (num > 2 && useVariance) { 541 // Convert rejection limits --- saves doing it later multiple times 542 // Using squared rejection limit because it's cheaper than sqrts 543 double sumWeights = 0.0; 544 for (int i = 0; i < num; i++) { 545 sumWeights += pixelWeights->data.F32[i]; 546 } 547 for (int i = 0; i < num; i++) { 548 // Systematic error contributes to the rejection level 549 float sysVar = PS_SQR(sys * pixelData->data.F32[i]); 550 #ifdef TESTING 551 // Correct variance for comparison against weighted mean including itself 552 float compare = 1.0 - pixelWeights->data.F32[i] / sumWeights; 553 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 554 fprintf(stderr, "Variance %d (%d), pixel %d,%d: %f %f %f\n", i, pixelSources->data.U16[i], 555 x, y, pixelVariances->data.F32[i], sysVar, compare); 556 } 557 #endif 558 pixelLimits->data.F32[i] = rej2 * (pixelVariances->data.F32[i] + sysVar); 559 } 560 } 561 562 int maskIndex = 0; // Index of pixel to mask 563 int totalClipped = 0; // Total number of pixels clipped 564 for (int i = 0; i < numIter && maskIndex >= 0; i++) { 565 maskIndex = -1; // Nothing to reject 566 567 switch (num) { 568 case 0: 569 break; 570 case 1: 571 if (i == 0 && safe) { 572 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 573 } 574 break; 575 case 2: { 576 if (useVariance) { 577 // Use variance to check that the two are consistent 578 float diff = 0.5 * (pixelData->data.F32[0] - pixelData->data.F32[1]); // Mean flux difference 579 float var1 = pixelVariances->data.F32[0]; // Variance of first 580 float var2 = pixelVariances->data.F32[1]; // Variance of second 581 // Systematic error contributes to the rejection level 582 var1 += PS_SQR(sys * pixelData->data.F32[0]); 583 var2 += PS_SQR(sys * pixelData->data.F32[1]); 584 585 float sigma2 = var1 + var2; // Combined variance 586 if (PS_SQR(diff) > rej2 * sigma2) { 587 // Not consistent: don't believe either! 588 if (i == 0 && suspect) { 589 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 590 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 591 } else { 592 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 593 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 594 } 595 #ifdef TESTING 596 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 597 fprintf(stderr, "Flagged both inputs for pixel %d,%d (%f > %f x %f\n)", 598 x, y, diff, rej, sqrtf(sigma2)); 599 } 600 #endif 601 } 602 } else if (i == 0 && safe) { 603 // Can't test them, and we want to be safe, so reject 604 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 605 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 606 } 607 break; 608 } 609 #if 0 610 case 3: { 611 // Want to be a bit careful on the rejection than for a larger number of inputs 612 if (!useVariance) { 613 return combineTestGeneral(num, suspect, inputs, buffer, x, y, numIter, rej, sys, 614 olympic, useVariance, safe, allowSuspect); 615 } 616 617 // Differences between pixel values 618 float diff01 = pixelData->data.F32[0] - pixelData->data.F32[1]; 619 float diff12 = pixelData->data.F32[1] - pixelData->data.F32[2]; 620 float diff20 = pixelData->data.F32[2] - pixelData->data.F32[0]; 621 // Variance for each pixel 622 float var0 = pixelVariances->data.F32[0] + PS_SQR(sys * pixelData->data.F32[0]); 623 float var1 = pixelVariances->data.F32[1] + PS_SQR(sys * pixelData->data.F32[1]); 624 float var2 = pixelVariances->data.F32[2] + PS_SQR(sys * pixelData->data.F32[2]); 625 // Errors in pixel differences 626 float err01 = var0 + var1; 627 float err12 = var1 + var2; 628 float err20 = var2 + var0; 629 630 #ifdef TESTING 631 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 632 fprintf(stderr, "Diff 0-1: %f %f\n", diff01, err01); 633 fprintf(stderr, "Diff 1-2: %f %f\n", diff12, err12); 634 fprintf(stderr, "Diff 2-0: %f %f\n", diff20, err20); 635 } 636 #endif 637 638 int badPairs = 0; // Number of bad pairs 639 bool bad01 = false, bad12 = false, bad20 = false; // Pair is bad? 640 if (PS_SQR(diff01) > rej2 * err01) { 641 bad01 = true; 642 badPairs++; 643 } 644 if (PS_SQR(diff12) > rej2 * err12) { 645 bad12 = true; 646 badPairs++; 647 } 648 if (PS_SQR(diff20) > rej2 * err20) { 649 bad20 = true; 650 badPairs++; 651 } 652 653 if (badPairs > 0 && allowSuspect && suspect) { 654 return false; 655 } 656 657 switch (badPairs) { 658 case 0: 659 // Nothing to worry about! 660 break; 661 case 1: 662 // Can't tell which image is bad, so be sure to get it 663 if (bad01) { 664 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 665 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 666 break; 667 } 668 if (bad12) { 669 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 670 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 671 break; 672 } 673 if (bad20) { 674 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 675 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 676 break; 677 } 678 psAbort("Should never get here"); 679 case 2: 680 if (bad01 && bad12) { 681 // 2 and 0 are good 682 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 683 break; 684 } 685 if (bad12 && bad20) { 686 // 0 and 1 are good 687 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 688 break; 689 } 690 if (bad20 && bad01) { 691 // 1 and 2 are good 692 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 693 break; 694 } 695 psAbort("Should never get here"); 696 case 3: 697 // Everything's bad 698 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 699 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 700 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 701 break; 702 } 703 break; 704 } 705 #endif 706 default: { 707 if (useVariance) { 708 float median = combinationWeightedOlympic(pixelData, pixelWeights, 709 olympic, buffer->sort); // Median for stack 710 #ifdef TESTING 711 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 712 fprintf(stderr, "Flag with variance pixel %d,%d: median = %f\n", x, y, median); 713 } 714 #endif 715 float worst = -INFINITY; // Largest deviation 716 for (int j = 0; j < num; j++) { 717 float diff = pixelData->data.F32[j] - median; // Difference from expected 718 #ifdef TESTING 719 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 720 fprintf(stderr, "Testing input %d for pixel %d,%d: %f\n", j, x, y, diff); 721 } 722 #endif 723 724 // Comparing squares --- cheaper than lots of sqrts 725 // pixelVariances includes the rejection limit, from above 726 float diff2 = PS_SQR(diff); // Square difference 727 if (diff2 > pixelLimits->data.F32[j]) { 728 float dev = diff2 / pixelLimits->data.F32[j]; // Deviation 729 if (dev > worst) { 730 worst = dev; 731 maskIndex = j; 732 } 733 } 734 } 735 } else { 736 float median = NAN, stdev = NAN; // Median and stdev of the combination, for rejection 737 combinationMedianStdev(&median, &stdev, pixelData, buffer->sort); 738 float limit = rej * stdev; // Rejection limit 739 #ifdef TESTING 740 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 741 fprintf(stderr, 742 "Flag without variance pixel %d,%d; median = %f, stdev = %f, limit = %f\n", 743 x, y, median, stdev, limit); 744 } 745 #endif 746 float worst = -INFINITY; // Largest deviation 747 for (int j = 0; j < num; j++) { 748 float diff = fabsf(pixelData->data.F32[j] - median); // Difference from expected 749 750 if (diff > limit) { 751 float dev = diff / limit; // Deviation 752 if (dev > worst) { 753 worst = dev; 754 maskIndex = j; 755 } 756 } 757 } 758 } 759 } 760 } 761 762 // Do the actual rejection of the pixel 763 if (maskIndex >= 0) { 764 if (suspect) { 765 #ifdef TESTING 766 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 767 fprintf(stderr, "Throwing out all suspect pixels for %d,%d\n", x, y); 768 } 769 #endif 770 // Throw out all suspect pixels 771 int numGood = 0; // Number of good pixels 772 for (int j = 0; j < num; j++) { 773 if (pixelSuspects->data.U8[j]) { 774 combineMarkReject(inputs, x, y, pixelSources->data.U16[j]); 775 continue; 776 } 777 if (numGood == j) { 778 numGood++; 779 continue; 780 } 781 pixelData->data.F32[numGood] = pixelData->data.F32[j]; 782 pixelWeights->data.F32[numGood] = pixelWeights->data.F32[j]; 783 pixelSources->data.U16[numGood] = pixelSources->data.U16[j]; 784 pixelLimits->data.F32[numGood] = pixelLimits->data.F32[j]; 785 pixelVariances->data.F32[numGood] = pixelVariances->data.F32[j]; 786 numGood++; 787 } 788 pixelData->n = numGood; 789 pixelWeights->n = numGood; 790 pixelSources->n = numGood; 791 pixelLimits->n = numGood; 792 pixelVariances->n = numGood; 793 totalClipped += num - numGood; 794 num = numGood; 795 suspect = false; 796 } else { 797 // Throw out masked pixel 798 #ifdef TESTING 799 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 800 fprintf(stderr, "Throwing out input %d for pixel %d,%d\n", maskIndex, x, y); 801 } 802 #endif 803 combineMarkInspect(inputs, x, y, pixelSources->data.U16[maskIndex]); 804 int numGood = 0; // Number of good pixels 805 for (int j = 0; j < num; j++) { 806 if (j == maskIndex) { 807 continue; 808 } 809 if (numGood == j) { 810 numGood++; 811 continue; 812 } 813 pixelData->data.F32[numGood] = pixelData->data.F32[j]; 814 pixelWeights->data.F32[numGood] = pixelWeights->data.F32[j]; 815 pixelSources->data.U16[numGood] = pixelSources->data.U16[j]; 816 pixelLimits->data.F32[numGood] = pixelLimits->data.F32[j]; 817 pixelVariances->data.F32[numGood] = pixelVariances->data.F32[j]; 818 numGood++; 819 } 820 pixelData->n = numGood; 821 pixelWeights->n = numGood; 822 pixelSources->n = numGood; 823 pixelLimits->n = numGood; 824 pixelVariances->n = numGood; 825 totalClipped++; 826 num--; 827 } 828 } 829 } 830 831 return true; 636 832 } 637 833 … … 639 835 // Ensure the input array of pmStackData is valid, and get some details out of it 640 836 static bool validateInputData(bool *haveVariances, // Do we have variance maps in the sky images? 641 bool *haveRejects, // Do we have lists of rejected pixels?642 837 int *num, // Number of inputs 643 838 int *numCols, int *numRows, // Size of (sky) images 644 psArray *input // Input array of pmStackData to validate 839 const psArray *input, // Input array of pmStackData to validate 840 const pmReadout *output, // Output readout 841 const pmReadout *exp // Exposure map 645 842 ) 646 843 { … … 668 865 PS_ASSERT_IMAGE_TYPE(data->readout->variance, PS_TYPE_F32, false); 669 866 } 670 *haveRejects = (data->reject != NULL);867 bool haveRejects = (data->reject != NULL); // Do we have rejected pixels? 671 868 672 869 // Make sure the rest correspond with the first … … 681 878 return false; 682 879 } 683 if (( *haveRejects && !data->reject) || (data->reject && !*haveRejects)) {880 if ((haveRejects && !data->reject) || (data->reject && !haveRejects)) { 684 881 psError(PS_ERR_UNEXPECTED_NULL, true, 685 882 "The rejected pixels are specified in some but not all inputs."); … … 696 893 PS_ASSERT_IMAGES_SIZE_EQUAL(data->readout->image, data->readout->variance, false); 697 894 PS_ASSERT_IMAGE_TYPE(data->readout->variance, PS_TYPE_F32, false); 895 } 896 } 897 898 PM_ASSERT_READOUT_NON_NULL(output, false); 899 if (output->image) { 900 PS_ASSERT_IMAGE_NON_NULL(output->image, false); 901 PS_ASSERT_IMAGE_TYPE(output->image, PS_TYPE_F32, false); 902 PS_ASSERT_IMAGE_NON_NULL(output->mask, false); 903 PS_ASSERT_IMAGE_TYPE(output->mask, PS_TYPE_IMAGE_MASK, false); 904 PS_ASSERT_IMAGES_SIZE_EQUAL(output->image, output->mask, false); 905 } 906 907 if (exp) { 908 PM_ASSERT_READOUT_NON_NULL(exp, false); 909 if (exp->image) { 910 PS_ASSERT_IMAGES_SIZE_EQUAL(exp->image, output->image, false); 911 } 912 if (exp->mask) { 913 PS_ASSERT_IMAGES_SIZE_EQUAL(exp->mask, output->image, false); 698 914 } 699 915 } … … 767 983 768 984 /// Constructor 769 pmStackData *pmStackDataAlloc(pmReadout *readout, float weight, float addVariance)985 pmStackData *pmStackDataAlloc(pmReadout *readout, float weight, float exp, float addVariance) 770 986 { 771 987 pmStackData *data = psAlloc(sizeof(pmStackData)); // Stack data, to return … … 776 992 data->inspect = NULL; 777 993 data->weight = weight; 994 data->exp = exp; 778 995 data->addVariance = addVariance; 779 996 … … 782 999 783 1000 /// Stack input images 784 bool pmStackCombine(pmReadout *combined, psArray *input, psImageMaskType maskVal, psImageMaskType bad, 785 int kernelSize, int numIter, float rej, float sys, float discard, 786 bool entire, bool useVariance, bool safe, bool rejectInspect) 787 { 788 PS_ASSERT_PTR_NON_NULL(combined, false); 1001 bool pmStackCombine(pmReadout *combined, pmReadout *expmaps, psArray *input, 1002 psImageMaskType maskVal, psImageMaskType maskSuspect, 1003 psImageMaskType bad, int kernelSize, 1004 float iter, float rej, float sys, float olympic, 1005 bool useVariance, bool safe, bool rejection) 1006 { 789 1007 bool haveVariances; // Do we have the variance maps? 790 bool haveRejects; // Do we have lists of rejected pixels?791 1008 int num; // Number of inputs 792 1009 int numCols, numRows; // Size of (sky) images 793 if (!validateInputData(&haveVariances, & haveRejects, &num, &numCols, &numRows, input)) {1010 if (!validateInputData(&haveVariances, &num, &numCols, &numRows, input, combined, expmaps)) { 794 1011 return false; 795 1012 } 796 1013 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 797 1014 PS_ASSERT_INT_POSITIVE(bad, false); 798 PS_ASSERT_INT_NONNEGATIVE(numIter, false);799 1015 if (isnan(rej)) { 800 PS_ASSERT_ INT_EQUAL(numIter, 0, false);1016 PS_ASSERT_FLOAT_EQUAL(iter, 0, false); 801 1017 } else { 1018 PS_ASSERT_FLOAT_LARGER_THAN(iter, 0, false); 802 1019 PS_ASSERT_FLOAT_LARGER_THAN(rej, 0.0, false); 803 }804 if (haveRejects) {805 // This is a subsequent combination, so expect that the image and mask already exist806 PS_ASSERT_IMAGE_NON_NULL(combined->image, false);807 PS_ASSERT_IMAGE_TYPE(combined->image, PS_TYPE_F32, false);808 PS_ASSERT_IMAGE_NON_NULL(combined->mask, false);809 PS_ASSERT_IMAGE_TYPE(combined->mask, PS_TYPE_IMAGE_MASK, false);810 PS_ASSERT_IMAGES_SIZE_EQUAL(combined->image, combined->mask, false);811 1020 } 812 1021 if (useVariance && !haveVariances) { … … 817 1026 psVector *addVariance = psVectorAlloc(num, PS_TYPE_F32); // Additional variance for each image 818 1027 psVector *weights = psVectorAlloc(num, PS_TYPE_F32); // Relative weighting for each image 1028 psVector *exps = psVectorAlloc(num, PS_TYPE_F32); // Exposure times for each image 819 1029 psArray *stack = psArrayAlloc(num); // Stack of readouts 1030 float totalExpWeight = 0.0; // Total value of all weighted exposure times 1031 float totalExp = 0.0; // Total exposure time 820 1032 for (int i = 0; i < num; i++) { 821 1033 pmStackData *data = input->data[i]; // Stack data for this input 822 1034 if (!data) { 823 1035 weights->data.F32[i] = 0.0; 1036 exps->data.F32[i] = NAN; 824 1037 continue; 825 1038 } 826 1039 weights->data.F32[i] = data->weight; 1040 exps->data.F32[i] = data->exp; 1041 totalExp += exps->data.F32[i]; 1042 totalExpWeight += exps->data.F32[i] * weights->data.F32[i]; 827 1043 pmReadout *ro = data->readout; // Readout of interest 828 1044 stack->data[i] = psMemIncrRefCounter(ro); … … 833 1049 } 834 1050 #endif 835 if (!haveRejects && !data->inspect) { 836 data->inspect = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 837 } 838 } 1051 if (!rejection) { 1052 // Ensure pixels can be put on the appropriate list 1053 if (!data->inspect) { 1054 data->inspect = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 1055 } 1056 if (!data->reject) { 1057 data->reject = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 1058 } 1059 } 1060 } 1061 totalExpWeight = totalExp / totalExpWeight; // Convert to inverse 839 1062 840 1063 int minInputCols, maxInputCols, minInputRows, maxInputRows; // Smallest and largest values to combine … … 842 1065 if (!pmReadoutStackValidate(&minInputCols, &maxInputCols, &minInputRows, &maxInputRows, &xSize, &ySize, 843 1066 stack)) { 844 psError( PS_ERR_UNKNOWN, false, "Input stack is not valid.");1067 psError(psErrorCodeLast(), false, "Input stack is not valid."); 845 1068 psFree(stack); 846 1069 return false; … … 863 1086 combineBuffer *buffer = combineBufferAlloc(num); 864 1087 865 if (haveRejects) { 866 psImage *combinedImage = combined->image; // Combined image 867 psImage *combinedMask = combined->mask; // Combined mask 868 psImage *combinedVariance = combined->variance; // Combined variance map 869 870 psArray *pixelMap = pixelMapGenerate(input, minInputCols, maxInputCols, 871 minInputRows, maxInputRows); // Map of pixels to source 872 psPixels *pixels = NULL; // Total list of pixels, with no duplicates 1088 // Pull the products out, allocate if necessary 1089 psImage *combinedImage = combined->image; // Combined image 1090 if (!combinedImage) { 1091 combined->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1092 combinedImage = combined->image; 1093 } 1094 psImage *combinedMask = combined->mask; // Combined mask 1095 if (!combinedMask) { 1096 combined->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 1097 combinedMask = combined->mask; 1098 } 1099 1100 psImage *combinedVariance = combined->variance; // Combined variance map 1101 if (haveVariances && !combinedVariance) { 1102 combined->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1103 combinedVariance = combined->variance; 1104 } 1105 1106 psImage *exp = NULL, *expnum = NULL, *expweight = NULL; // Exposure map and exposure number 1107 if (expmaps) { 1108 if (!expmaps->image) { 1109 expmaps->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1110 } 1111 exp = expmaps->image; 1112 1113 if (!expmaps->mask) { 1114 expmaps->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 1115 } 1116 expnum = expmaps->mask; 1117 1118 if (!expmaps->variance) { 1119 expmaps->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1120 } 1121 expweight = expmaps->variance; 1122 } 1123 1124 // Set up rejection list 1125 psArray *pixelMap = NULL; // Map of pixels to source 1126 if (rejection) { 1127 pixelMap = pixelMapGenerate(input, minInputCols, maxInputCols, minInputRows, maxInputRows); 1128 } 1129 1130 // Combine each pixel 1131 for (int y = minInputRows; y < maxInputRows; y++) { 1132 for (int x = minInputCols; x < maxInputCols; x++) { 1133 #ifdef TESTING 1134 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 1135 fprintf(stderr, "Combining pixel %d,%d: %x %x %f %f %f %f %d %d %d\n", 1136 x, y, maskVal, bad, iter, rej, sys, olympic, useVariance, safe, rejection); 1137 } 1138 #endif 1139 psVector *reject = NULL; // Images to reject for this pixel 1140 if (rejection) { 1141 reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, x, y); 1142 #ifdef TESTING 1143 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 1144 fprintf(stderr, "Rejected inputs for pixel %d,%d: ", x, y); 1145 if (!reject) { 1146 fprintf(stderr, "<none>\n"); 1147 } else { 1148 for (int i = 0; i < reject->n; i++) { 1149 fprintf(stderr, "%d ", reject->data.U16[i]); 1150 } 1151 fprintf(stderr, "\n"); 1152 } 1153 } 1154 #endif 1155 } 1156 1157 int num; // Number of good pixels 1158 bool suspect; // Suspect pixels in stack? 1159 combineExtract(&num, &suspect, buffer, combinedImage, combinedMask, combinedVariance, 1160 input, weights, exps, addVariance, reject, x, y, maskVal, maskSuspect); 1161 combinePixels(combinedImage, combinedMask, combinedVariance, exp, expnum, expweight, 1162 num, buffer, x, y, bad, safe, totalExpWeight); 1163 1164 if (iter > 0) { 1165 combineTest(num, suspect, input, buffer, x, y, iter, rej, sys, olympic, 1166 useVariance, safe); 1167 } 1168 } 1169 } 1170 1171 psFree(pixelMap); 1172 psFree(weights); 1173 psFree(buffer); 1174 psFree(addVariance); 1175 1176 1177 #ifndef PS_NO_TRACE 1178 if (!rejection && psTraceGetLevel("psModules.imcombine") >= 5) { 873 1179 for (int i = 0; i < num; i++) { 874 pmStackData *data = input->data[i]; // Stack ing data; contains the list of pixels875 if (!data ) {1180 pmStackData *data = input->data[i]; // Stack data for this input 1181 if (!data || !data->inspect) { 876 1182 continue; 877 1183 } 878 pixels = psPixelsConcatenate(pixels, data->reject); 879 } 880 pixels = psPixelsDuplicates(pixels, pixels); 881 882 if (entire) { 883 // Combine entire image 884 for (int y = minInputRows; y < maxInputRows; y++) { 885 for (int x = minInputCols; x < maxInputCols; x++) { 886 psVector *reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, 887 x, y); // Reject these images 888 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 889 addVariance, reject, x, y, maskVal, bad, numIter, rej, sys, discard, 890 useVariance, safe, rejectInspect, buffer); 891 } 892 } 893 } else { 894 // Only combine previously rejected pixels 895 for (int i = 0; i < pixels->n; i++) { 896 // Pixel coordinates are in the frame of the original image 897 int x = pixels->data[i].x, y = pixels->data[i].y; // Coordinates of interest 898 if (x < minInputCols || x >= maxInputCols || y < minInputRows || y >= maxInputRows) { 899 continue; 900 } 901 psVector *reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, 902 x, y); // Reject these images 903 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 904 addVariance, reject, x, y, maskVal, bad, numIter, rej, sys, discard, 905 useVariance, safe, rejectInspect, buffer); 906 } 907 } 908 psFree(pixels); 909 psFree(pixelMap); 910 } else { 911 // Pull the products out, allocate if necessary 912 psImage *combinedImage = combined->image; // Combined image 913 if (!combinedImage) { 914 combined->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 915 combinedImage = combined->image; 916 } 917 psImage *combinedMask = combined->mask; // Combined mask 918 if (!combinedMask) { 919 combined->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 920 combinedMask = combined->mask; 921 } 922 923 psImage *combinedVariance = combined->variance; // Combined variance map 924 if (haveVariances && !combinedVariance) { 925 combined->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 926 combinedVariance = combined->variance; 927 } 928 929 for (int y = minInputRows; y < maxInputRows; y++) { 930 for (int x = minInputCols; x < maxInputCols; x++) { 931 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 932 addVariance, NULL, x, y, maskVal, bad, numIter, rej, sys, discard, 933 useVariance, safe, rejectInspect, buffer); 934 } 935 } 936 937 #ifndef PS_NO_TRACE 938 if (psTraceGetLevel("psModules.imcombine") >= 5) { 939 for (int i = 0; i < num; i++) { 940 pmStackData *data = input->data[i]; // Stack data for this input 941 if (!data || !data->inspect) { 942 continue; 943 } 944 psTrace("psModules.imcombine", 5, "Image %d: %ld pixels to inspect.\n", i, data->inspect->n); 945 } 946 } 947 #endif 948 } 949 950 psFree(weights); 951 psFree(buffer); 1184 psTrace("psModules.imcombine", 5, "Image %d: %ld pixels to inspect.\n", i, data->inspect->n); 1185 } 1186 } 1187 #endif 952 1188 953 1189 return true; -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmStack.h
r23577 r27840 31 31 psPixels *inspect; ///< Pixels to inspect 32 32 float weight; ///< Relative weighting for image 33 float exp; ///< Exposure time 33 34 float addVariance; ///< Additional variance when rejecting 34 35 } pmStackData; … … 37 38 pmStackData *pmStackDataAlloc(pmReadout *readout, ///< Warped readout (sky cell) 38 39 float weight, ///< Weight to apply 40 float exp, ///< Exposure time 39 41 float addVariance ///< Additional variance when rejecting 40 42 ); … … 42 44 /// Stack input images 43 45 bool pmStackCombine(pmReadout *combined,///< Combined readout (output) 46 pmReadout *expmaps, ///< Exposure maps (output) 44 47 psArray *input, ///< Input array of pmStackData 45 48 psImageMaskType maskVal, ///< Mask value of bad pixels 49 psImageMaskType suspect, ///< Mask value of suspect pixels 46 50 psImageMaskType bad, ///< Mask value to give rejected pixels 47 51 int kernelSize, ///< Half-size of the convolution kernel 48 int numIter, ///< Number of iterations52 float iter, ///< Number of iterations per input 49 53 float rej, ///< Rejection limit (standard deviations) 50 54 float sys, ///< Relative systematic error 51 55 float discard, ///< Fraction of values to discard for Olympic weighted mean 52 bool entire, ///< Combine entire image even if rejection lists provided?53 56 bool useVariance, ///< Use variance values for rejection? 54 57 bool safe, ///< Play safe with small numbers of input pixels (mask if N <= 2)? -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmStackReject.c
r21351 r27840 10 10 #include "pmSubtractionThreads.h" 11 11 #include "pmSubtractionKernels.h" 12 13 #include "pmStackReject.h" 12 14 13 15 #define PIXEL_LIST_BUFFER 100 // Number of pixels to add to list at a time … … 35 37 { 36 38 int size = kernels->size; // Half-size of convolution kernel 37 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 38 xMin + size + 1, yMin + size + 1); // Polynomial 39 int x = PS_MIN(xMin + size + 1, kernels->xMax); // x coordinate of interest 40 int y = PS_MIN(yMin + size + 1, kernels->yMax); // y coordinate of interest 41 42 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, x, y); // Polynomial 39 43 int box = p_pmSubtractionBadRadius(NULL, kernels, polyValues, false, poorFrac); // Radius of bad box 40 44 psTrace("psModules.imcombine", 10, "Growing by %d", box); … … 43 47 if (box > 0) { 44 48 // Convolve a subimage, then stick it in the target 45 // XXX if (threaded) {46 // XXX psMutexLock(source);47 // XXX }48 49 psImage *mask = psImageSubset(source, psRegionSet(xMin - box, xMax + box, 49 50 yMin - box, yMax + box)); // Mask to convolve 50 // XXX if (threaded) {51 // XXX psMutexUnlock(source);52 // XXX }53 51 psImage *convolved = psImageConvolveMask(NULL, mask, PM_STACK_MASK_BAD, PM_STACK_MASK_CONVOLVE, 54 52 -box, box, -box, box); // Convolved mask 55 // XXX if (threaded) {56 // XXX psMutexLock(source);57 // XXX }58 53 psFree(mask); 59 // XXX if (threaded) {60 // XXX psMutexUnlock(source);61 // XXX }62 54 63 55 int numBytes = (xMax - xMin) * PSELEMTYPE_SIZEOF(PS_TYPE_IMAGE_MASK); // Number of bytes to copy … … 111 103 112 104 if (!pmSubtractionThreaded()) { 113 pmSubtractionThreadsInit( NULL, NULL);105 pmSubtractionThreadsInit(); 114 106 } 115 107 … … 125 117 126 118 127 psPixels *pmStackReject(const psPixels *in, int numCols, int numRows, float threshold, float poorFrac,128 int stride,const psArray *subRegions, const psArray *subKernels)119 psPixels *pmStackReject(const psPixels *in, int numCols, int numRows, float threshold, int stride, 120 const psArray *subRegions, const psArray *subKernels) 129 121 { 130 122 PS_ASSERT_PIXELS_NON_NULL(in, NULL); … … 162 154 pmReadout *inRO = pmReadoutAlloc(NULL); // Readout with input image 163 155 inRO->image = image; 164 // XXX if (threaded) { 165 // XXX psMutexInit(image); 166 // XXX } 156 convRO->image = psImageAlloc(image->numCols, image->numRows, PS_TYPE_F32); 167 157 for (int i = 0; i < numRegions; i++) { 168 158 psRegion *region = subRegions->data[i]; // Region of interest 169 159 pmSubtractionKernels *kernels = subKernels->data[i]; // Kernel of interest 170 if (!pmSubtractionConvolve( convRO, NULL, inRO, NULL, NULL, stride, 0, 0, 1.0, 0.0,160 if (!pmSubtractionConvolve(NULL, convRO, NULL, inRO, NULL, stride, 0, 0, 1.0, 0.0, 0.0, 171 161 region, kernels, false, true)) { 172 psError( PS_ERR_UNKNOWN, false, "Unable to convolve mask image in region %d.", i);162 psError(psErrorCodeLast(), false, "Unable to convolve mask image in region %d.", i); 173 163 psFree(convRO); 174 164 psFree(inRO); … … 180 170 181 171 // Image of the kernel at the centre of the region 182 float xNorm = (region->x0 + 0.5 * (region->x1 - region->x0) - kernels->numCols/2.0) / 183 (float)kernels->numCols; 184 float yNorm = (region->y0 + 0.5 * (region->y1 - region->y0) - kernels->numRows/2.0) / 185 (float)kernels->numRows; 186 psImage *kernel = pmSubtractionKernelImage(kernels, xNorm, yNorm, false); 172 psImage *kernel = pmSubtractionKernelImage(kernels, 0.5, 0.5, false); 187 173 if (!kernel) { 188 psError( PS_ERR_UNKNOWN, false, "Unable to generate kernel image.");174 psError(psErrorCodeLast(), false, "Unable to generate kernel image."); 189 175 psFree(convRO); 190 176 psFree(inRO); … … 211 197 } 212 198 } 213 // XXX if (threaded) {214 // XXX psMutexDestroy(image);215 // XXX }216 199 psFree(inRO); 217 200 psImage *convolved = psMemIncrRefCounter(convRO->image); … … 241 224 } 242 225 psTrace("psModules.imcombine", 7, "Found %ld bad pixels", bad->n); 243 244 // Now, grow the mask to include everything that touches a bad pixel in the convolution 245 psImage *source = psPixelsToMask(NULL, bad, psRegionSet(0, numCols - 1, 0, numRows - 1), 226 psFree(convolved); 227 228 return bad; 229 } 230 231 232 psPixels *pmStackRejectGrow(const psPixels *in, int numCols, int numRows, float poorFrac, 233 const psArray *subRegions, const psArray *subKernels) 234 { 235 PS_ASSERT_PIXELS_NON_NULL(in, NULL); 236 PS_ASSERT_ARRAY_NON_NULL(subRegions, NULL); 237 PS_ASSERT_ARRAY_NON_NULL(subKernels, NULL); 238 PS_ASSERT_ARRAYS_SIZE_EQUAL(subRegions, subKernels, NULL); 239 240 psImage *source = psPixelsToMask(NULL, in, psRegionSet(0, numCols - 1, 0, numRows - 1), 246 241 PM_STACK_MASK_BAD); // Mask image to grow 247 242 … … 262 257 bool oldThreads = psImageConvolveSetThreads(false); // Old value of threading for psImageColvolve 263 258 264 psImage *target = psImage Recycle(convolved,numCols, numRows, PS_TYPE_IMAGE_MASK); // Grown image259 psImage *target = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); // Grown image 265 260 psImageInit(target, 0); 266 // XXX if (threaded) {267 // XXX psMutexInit(source);268 // XXX }269 261 for (int i = 0; i < subRegions->n; i++) { 270 262 psRegion *region = subRegions->data[i]; // Subtraction region … … 287 279 psArray *args = job->args; // Job arguments 288 280 psArrayAdd(args, 1, target); 289 // XXX psMutexLock(source);290 281 psArrayAdd(args, 1, source); 291 // XXX psMutexUnlock(source);292 282 psArrayAdd(args, 1, kernels); 293 283 PS_ARRAY_ADD_SCALAR(args, numCols, PS_TYPE_S32); … … 307 297 } else if (!stackRejectGrow(target, source, kernels, numCols, numRows, 308 298 i, xSubMax, j, ySubMax, poorFrac)) { 309 psError( PS_ERR_UNKNOWN, false, "Unable to grow bad pixels.");299 psError(psErrorCodeLast(), false, "Unable to grow bad pixels."); 310 300 psFree(source); 311 301 psFree(target); … … 317 307 318 308 if (!psThreadPoolWait(false)) { 319 psError( PS_ERR_UNKNOWN, false, "Unable to grow bad pixels.");309 psError(psErrorCodeLast(), false, "Unable to grow bad pixels."); 320 310 psFree(source); 321 311 psFree(target); … … 332 322 } 333 323 334 // XXX psMutexDestroy(source);335 324 } 336 325 … … 351 340 352 341 psFree(source); 353 bad = psPixelsFromMask(bad, target, PM_STACK_MASK_ALL); 342 psPixels *bad = psPixelsFromMask(NULL, target, PM_STACK_MASK_ALL); // All bad pixels 343 psFree(target); 354 344 psTrace("psModules.imcombine", 7, "Total %ld bad pixels", bad->n); 355 345 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmStackReject.h
r20568 r27840 12 12 int numCols, int numRows, ///< Size of image of interest 13 13 float threshold, ///< Threshold on convolved image, 0..1 14 float poorFrac, ///< Fraction for "poor"15 14 int stride, ///< Size of convolution patches 16 15 const psArray *regions, ///< Array of image regions for image 17 16 const psArray *kernels ///< Array of kernel parameters for each region 17 ); 18 19 /// Given a list of pixels from the convolved image, we grow them by convolution to get the list of all pixels 20 /// which should be rejected. 21 psPixels *pmStackRejectGrow(const psPixels *in, ///< List of pixels in the convolved image 22 int numCols, int numRows, ///< Size of image of interest 23 float poorFrac, ///< Fraction for "poor" 24 const psArray *regions, ///< Array of image regions for image 25 const psArray *kernels ///< Array of kernel parameters for each region 18 26 ); 19 27 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtraction.c
r24298 r27840 17 17 #include <pslib.h> 18 18 19 #include "pmErrorCodes.h" 19 20 #include "pmHDU.h" // Required for pmFPA.h 20 21 #include "pmFPA.h" 21 22 #include "pmSubtractionStamps.h" 22 23 #include "pmSubtractionEquation.h" 24 #include "pmSubtractionVisual.h" 23 25 #include "pmSubtractionThreads.h" 24 26 … … 29 31 #define PIXEL_LIST_BUFFER 100 // Number of entries to add to pixel list at a time 30 32 #define MIN_SAMPLE_STATS 7 // Minimum number to use sample statistics; otherwise use quartiles 33 #define USE_KERNEL_ERR // Use kernel error image? 31 34 32 35 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 36 39 // Generate the kernel to apply to the variance from the normal kernel 37 40 static psKernel *varianceKernel(psKernel *out, // Output kernel 38 psKernel *normalKernel // Normal kernel41 const psKernel *normalKernel // Normal kernel 39 42 ) 40 43 { … … 48 51 49 52 // Take the square of the normal kernel 50 double sum Normal = 0.0, sumVariance = 0.0; // Sum of the normal andvariance kernels53 double sumVariance = 0.0; // Sum of the variance kernels 51 54 for (int v = yMin; v <= yMax; v++) { 52 55 for (int u = xMin; u <= xMax; u++) { 53 float value = normalKernel->kernel[v][u]; // Value of interest 54 float value2 = PS_SQR(value); // Value squared 55 sumNormal += value; 56 sumVariance += value2; 57 out->kernel[v][u] = value2; 56 sumVariance += out->kernel[v][u] = PS_SQR(normalKernel->kernel[v][u]); 58 57 } 59 58 } … … 65 64 return out; 66 65 } 66 67 // Contribute to an image of the solved kernel component using the preCalculated image 68 static void solvedKernelPreCalc(psKernel *kernel, // Kernel, updated 69 const pmSubtractionKernels *kernels, // Kernel basis functions 70 float value, // Normalisation value for basis function 71 int index // Index of basis function of interest 72 ) 73 { 74 int size = kernels->size; // Kernel half-size 75 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated values 76 #if 0 77 // Iterating over the kernel 78 for (int y = 0, v = -size; v <= size; y++, v++) { 79 float yValue = value * preCalc->yKernel->data.F32[y]; 80 for (int x = 0, u = -size; u <= size; x++, u++) { 81 kernel->kernel[v][u] += yValue * preCalc->xKernel->data.F32[x]; 82 } 83 } 84 // Photometric scaling for even kernels only 85 if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) { 86 kernel->kernel[0][0] -= value; 87 } 88 #else 89 for (int v = -size; v <= size; v++) { 90 for (int u = -size; u <= size; u++) { 91 kernel->kernel[v][u] += value * preCalc->kernel->kernel[v][u]; 92 } 93 } 94 #endif 95 96 return; 97 } 98 67 99 68 100 // Generate an image of the solved kernel … … 70 102 const pmSubtractionKernels *kernels, // Kernel basis functions 71 103 const psImage *polyValues, // Spatial polynomial values 104 bool normalise, // Add normalisation? 72 105 bool wantDual // Want the dual (second) kernel? 73 106 ) … … 85 118 for (int i = 0; i < numKernels; i++) { 86 119 double value = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, wantDual); // Polynomial value 120 if (wantDual) { 121 // The model is built with the dual convolution terms added, so to produce zero residual the 122 // equation results in negative coefficients which we must undo. 123 value *= -1.0; 124 } 87 125 88 126 switch (kernels->type) { … … 115 153 case PM_SUBTRACTION_KERNEL_GUNK: { 116 154 if (i < kernels->inner) { 117 // Using pre-calculated function 118 psKernel *preCalc = kernels->preCalc->data[i]; // Precalculated values 119 // Iterating over the kernel 120 for (int v = -size; v <= size; v++) { 121 for (int u = -size; u <= size; u++) { 122 kernel->kernel[v][u] += preCalc->kernel[v][u] * value; 123 // Photometric scaling is built into the preCalc kernel --- no subtraction! 124 } 125 } 155 solvedKernelPreCalc(kernel, kernels, value, i); 126 156 } else { 127 157 // Using delta function … … 133 163 break; 134 164 } 135 case PM_SUBTRACTION_KERNEL_ISIS: { 136 psArray *preCalc = kernels->preCalc->data[i]; // Precalculated values 137 psVector *xKernel = preCalc->data[0]; // Kernel in x 138 psVector *yKernel = preCalc->data[1]; // Kernel in y 139 // Iterating over the kernel 140 for (int y = 0, v = -size; v <= size; y++, v++) { 141 for (int x = 0, u = -size; u <= size; x++, u++) { 142 kernel->kernel[v][u] += value * xKernel->data.F32[x] * yKernel->data.F32[y]; 143 } 144 } 145 // Photometric scaling for even kernels only 146 if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) { 147 kernel->kernel[0][0] -= value; 148 } 165 case PM_SUBTRACTION_KERNEL_ISIS: 166 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 167 case PM_SUBTRACTION_KERNEL_HERM: 168 case PM_SUBTRACTION_KERNEL_DECONV_HERM: { 169 solvedKernelPreCalc(kernel, kernels, value, i); 149 170 break; 150 171 } 151 172 case PM_SUBTRACTION_KERNEL_RINGS: { 152 psArray *preCalc = kernels->preCalc->data[i]; // Precalculated data 153 psVector *uCoords = preCalc->data[0]; // u coordinates 154 psVector *vCoords = preCalc->data[1]; // v coordinates 155 psVector *poly = preCalc->data[2]; // Polynomial values 156 int num = uCoords->n; // Number of pixels 173 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Precalculated kernels 174 int num = preCalc->uCoords->n; // Number of pixels 157 175 158 176 for (int j = 0; j < num; j++) { 159 int u = uCoords->data.S32[j], v = vCoords->data.S32[j]; // Kernel coordinates 160 kernel->kernel[v][u] += poly->data.F32[j] * value; 177 int u = preCalc->uCoords->data.S32[j]; 178 int v = preCalc->vCoords->data.S32[j]; // Kernel coordinates 179 kernel->kernel[v][u] += preCalc->poly->data.F32[j] * value; 161 180 } 162 181 // Photometric scaling is built into the kernel --- no subtraction! … … 168 187 } 169 188 170 // Put in the normalisation component 171 kernel->kernel[0][0] += (wantDual ? 1.0 : p_pmSubtractionSolutionNorm(kernels)); 189 if (normalise) { 190 // Put in the normalisation component 191 kernel->kernel[0][0] += (wantDual ? 1.0 : p_pmSubtractionSolutionNorm(kernels)); 192 } 172 193 173 194 return kernel; … … 250 271 static void convolveVarianceFFT(psImage *target,// Place the result in here 251 272 psImage *variance, // Variance map to convolve 252 psImage * sys, // Systematicerror image273 psImage *kernelErr, // Kernel error image 253 274 psImage *mask, // Mask image 254 275 psImageMaskType maskVal, // Value to mask … … 262 283 263 284 psImage *subVariance = variance ? psImageSubset(variance, border) : NULL; // Variance map 264 psImage *sub Sys = sys ? psImageSubset(sys, border) : NULL; // Systematicerror image285 psImage *subKE = kernelErr ? psImageSubset(kernelErr, border) : NULL; // Kernel error image 265 286 psImage *subMask = mask ? psImageSubset(mask, border) : NULL; // Mask 266 287 267 288 // XXX Can trim this a little by combining the convolution: only have to take the FFT of the kernel once 268 289 psImage *convVariance = psImageConvolveFFT(NULL, subVariance, subMask, maskVal, kernel); // Convolved variance 269 psImage *conv Sys = subSys ? psImageConvolveFFT(NULL, subSys, subMask, maskVal, kernel) : NULL; // Conv sys290 psImage *convKE = subKE ? psImageConvolveFFT(NULL, subKE, subMask, maskVal, kernel) : NULL; // Conv KE 270 291 271 292 psFree(subVariance); 272 psFree(sub Sys);293 psFree(subKE); 273 294 psFree(subMask); 274 295 275 296 // Now, we have to stick it in where it belongs 276 297 int xMin = region.x0, xMax = region.x1, yMin = region.y0, yMax = region.y1; // Bounds of region 277 if (conv Sys) {298 if (convKE) { 278 299 for (int yTarget = yMin, ySource = size; yTarget < yMax; yTarget++, ySource++) { 279 300 for (int xTarget = xMin, xSource = size; xTarget < xMax; xTarget++, xSource++) { 280 301 target->data.F32[yTarget][xTarget] = convVariance->data.F32[ySource][xSource] + 281 conv Sys->data.F32[ySource][xSource];302 convKE->data.F32[ySource][xSource]; 282 303 } 283 304 } … … 290 311 291 312 psFree(convVariance); 292 psFree(conv Sys);313 psFree(convKE); 293 314 294 315 return; … … 326 347 psImage *image, // Image to convolve 327 348 psImage *variance, // Variance map to convolve, or NULL 328 psImage * sys, // Systematicerror image, or NULL349 psImage *kernelErr, // Kernel error image, or NULL 329 350 psImage *subMask, // Subtraction mask 330 351 const pmSubtractionKernels *kernels, // Kernels … … 339 360 ) 340 361 { 341 *kernelImage = solvedKernel(*kernelImage, kernels, polyValues, wantDual);362 *kernelImage = solvedKernel(*kernelImage, kernels, polyValues, true, wantDual); 342 363 if (variance || subMask) { 343 364 *kernelVariance = varianceKernel(*kernelVariance, *kernelImage); … … 363 384 convolveFFT(convImage, image, subMask, subBad, *kernelImage, region, background, kernels->size); 364 385 if (variance) { 365 convolveVarianceFFT(convVariance, variance, sys, subMask, subBad, *kernelVariance, region, kernels->size); 386 convolveVarianceFFT(convVariance, variance, kernelErr, subMask, subBad, *kernelVariance, 387 region, kernels->size); 366 388 } 367 389 } else { … … 373 395 } 374 396 375 // Convolve the mask for bad pixels397 // Convolve the mask for bad/poor pixels 376 398 if (subMask && convMask) { 377 399 int box = p_pmSubtractionBadRadius(*kernelImage, kernels, polyValues, 378 400 wantDual, poorFrac); // Size of bad box 401 psAssert(box >= 0, "Bad radius must be >= 0"); 402 403 int colMin = region.x0, colMax = region.x1, rowMin = region.y0, rowMax = region.y1; // Bounds 404 psImage *convolved = NULL; // Convolved subtraction mask 379 405 if (box > 0) { 380 int colMin = region.x0, colMax = region.x1, rowMin = region.y0, rowMax = region.y1; // Bounds 381 psRegion region = psRegionSet(colMin - box, colMax + box, 382 rowMin - box, rowMax + box); // Region to convolve 383 384 psImage *image = subMask ? psImageSubset(subMask, region) : NULL; // Mask to convolve 385 386 psImage *convolved = psImageConvolveMask(NULL, image, subBad, subConvBad, 387 -box, box, -box, box); // Convolved subtraction mask 388 406 psRegion maskRegion = psRegionSet(colMin - box, colMax + box, 407 rowMin - box, rowMax + box); // Region to convolve 408 psImage *image = subMask ? psImageSubset(subMask, maskRegion) : NULL; // Mask to convolve 409 convolved = psImageConvolveMask(NULL, image, subBad, subConvBad, -box, box, -box, box); 389 410 psFree(image); 390 391 psAssert(convolved->numCols - 2 * box == colMax - colMin, "Bad number of columns"); 392 psAssert(convolved->numRows - 2 * box == rowMax - rowMin, "Bad number of rows"); 393 394 for (int yTarget = rowMin, ySource = box; yTarget < rowMax; yTarget++, ySource++) { 395 // Dereference images 396 psImageMaskType *target = &convMask->data.PS_TYPE_IMAGE_MASK_DATA[yTarget][colMin]; // Target values 397 psImageMaskType *source = &convolved->data.PS_TYPE_IMAGE_MASK_DATA[ySource][box]; // Source values 398 for (int xTarget = colMin; xTarget < colMax; xTarget++, target++, source++) { 399 if (*source & subConvBad) { 400 *target |= maskBad; 401 } else if (*source & subConvPoor) { 402 *target |= maskPoor; 403 } 411 } else { 412 convolved = psImageSubset(subMask, region); 413 } 414 415 psAssert(convolved->numCols - 2 * box == colMax - colMin, "Bad number of columns"); 416 psAssert(convolved->numRows - 2 * box == rowMax - rowMin, "Bad number of rows"); 417 418 for (int yTarget = rowMin, ySource = box; yTarget < rowMax; yTarget++, ySource++) { 419 // Dereference images 420 psImageMaskType *target = &convMask->data.PS_TYPE_IMAGE_MASK_DATA[yTarget][colMin]; // Target values 421 psImageMaskType *source = &convolved->data.PS_TYPE_IMAGE_MASK_DATA[ySource][box]; // Source values 422 for (int xTarget = colMin; xTarget < colMax; xTarget++, target++, source++) { 423 if (*source & subConvBad) { 424 *target |= maskBad; 425 } else if (*source & subConvPoor) { 426 *target &= ~maskBad; 427 *target |= maskPoor; 428 } else { 429 *target &= ~maskBad & ~maskPoor; 404 430 } 405 431 } 406 407 // No need to lock: we own this 408 psFree(convolved); 409 } 432 } 433 434 psFree(convolved); 410 435 } 411 436 … … 413 438 } 414 439 415 // Generate an image that can be used to track systematic errors 416 static psImage *subtractionSysErrImage(const psImage *image, // Image from which to make sys err image 417 float sysError // Relative systematic error 418 ) 419 { 420 if (!isfinite(sysError) || sysError == 0.0) { 440 #ifdef USE_KERNEL_ERR 441 // Generate an image that can be used to track systematic errors in the kernel 442 static psImage *subtractionKernelErrImage(const psImage *image, // Image from which to make kernel error image 443 float kernelError // Relative systematic error in kernel 444 ) 445 { 446 if (!isfinite(kernelError) || kernelError == 0.0) { 421 447 return NULL; 422 448 } 423 449 424 450 int numCols = image->numCols, numRows = image->numRows; // Size of image 425 psImage * sys = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Systematicerror image426 427 float sysError2 = PS_SQR(sysError); // Square of the systematicerror451 psImage *kernelErr = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Kernel error image 452 453 float kernelError2 = PS_SQR(kernelError); // Square of the kernel error 428 454 for (int y = 0; y < numRows; y++) { 429 455 for (int x = 0; x < numCols; x++) { 430 sys->data.F32[y][x] = PS_SQR(image->data.F32[y][x]) * sysError2; 431 } 432 } 433 434 return sys; 456 kernelErr->data.F32[y][x] = PS_SQR(image->data.F32[y][x]) * kernelError2; 457 } 458 } 459 460 return kernelErr; 461 } 462 #endif 463 464 // Convolve a stamp using a pre-calculated kernel basis function 465 static psKernel *convolveStampPreCalc(const psKernel *image, // Image to convolve 466 const pmSubtractionKernels *kernels, // Kernel basis functions 467 int index, // Index of basis function of interest 468 int footprint // Half-size of stamp 469 ) 470 { 471 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated data 472 #if 0 473 // Convolving using separable convolution 474 int size = kernels->size; // Size of kernel 475 476 // Convolve in x 477 // Need to convolve a bit more than the footprint, for the y convolution 478 int yMin = -size - footprint, yMax = size + footprint; // Range for y 479 psKernel *temp = psKernelAlloc(yMin, yMax, 480 -footprint, footprint); // Temporary convolution; NOTE: wrong way! 481 for (int y = yMin; y <= yMax; y++) { 482 for (int x = -footprint; x <= footprint; x++) { 483 float value = 0.0; // Value of convolved pixel 484 int uMin = x - size, uMax = x + size; // Range for u 485 psF32 *xKernelData = &preCalc->xKernel->data.F32[xKernel->n - 1]; // Kernel values 486 psF32 *imageData = &image->kernel[y][uMin]; // Image values 487 for (int u = uMin; u <= uMax; u++, xKernelData--, imageData++) { 488 value += *xKernelData * *imageData; 489 } 490 temp->kernel[x][y] = value; // NOTE: putting in wrong way! 491 } 492 } 493 494 // Convolve in y 495 psKernel *convolved = psKernelAlloc(-footprint, footprint, -footprint, footprint);// Convolved image 496 for (int x = -footprint; x <= footprint; x++) { 497 for (int y = -footprint; y <= footprint; y++) { 498 float value = 0.0; // Value of convolved pixel 499 int vMin = y - size, vMax = y + size; // Range for v 500 psF32 *yKernelData = &preCalc->yKernel->data.F32[yKernel->n - 1]; // Kernel values 501 psF32 *imageData = &temp->kernel[x][vMin]; // Image values; NOTE: wrong way! 502 for (int v = vMin; v <= vMax; v++, yKernelData--, imageData++) { 503 value += *yKernelData * *imageData; 504 } 505 convolved->kernel[y][x] = value; 506 } 507 } 508 psFree(temp); 509 510 // Photometric scaling for even kernels only 511 if (kernels->u->data.S32[index] % 2 == 0 && kernels->v->data.S32[index] % 2 == 0) { 512 convolveSub(convolved, image, footprint); 513 } 514 return convolved; 515 #else 516 // Convolving using precalculated kernel 517 return p_pmSubtractionConvolveStampPrecalc(image, preCalc->kernel); 518 #endif 435 519 } 436 520 … … 447 531 int x0 = - image->xMin, y0 = - image->yMin; // Position of centre of convolved image 448 532 psKernel *convolved = psKernelAllocFromImage(conv, x0, y0); // Kernel version 533 534 // pmSubtractionVisualShowSubtraction(image->image, kernel->image, conv); 535 449 536 psFree(conv); 450 537 return convolved; … … 456 543 psKernel *kernel; // Kernel to use 457 544 if (!preKernel) { 458 kernel = solvedKernel(NULL, kernels, polyValues, wantDual);545 kernel = solvedKernel(NULL, kernels, polyValues, true, wantDual); 459 546 } else { 460 547 kernel = psMemIncrRefCounter(preKernel); … … 491 578 } 492 579 580 void p_pmSubtractionPolynomialNormCoords(float *xOut, float *yOut, float xIn, float yIn, 581 int xMin, int xMax, int yMin, int yMax) 582 { 583 float xNormSize = xMax - xMin, yNormSize = yMax - yMin; // Size to use for normalisation 584 *xOut = 2.0 * (float)(xIn - xMin - xNormSize/2.0) / xNormSize; 585 *yOut = 2.0 * (float)(yIn - yMin - yNormSize/2.0) / yNormSize; 586 return; 587 } 588 493 589 psImage *p_pmSubtractionPolynomialFromCoords(psImage *output, const pmSubtractionKernels *kernels, 494 int numCols, int numRows, intx, int y)590 int x, int y) 495 591 { 496 592 assert(kernels); 497 assert(numCols > 0 && numRows > 0); 498 499 // Size to use when calculating normalised coordinates (different from actual size when convolving 500 // subimage) 501 int xNormSize = (kernels->numCols > 0 ? kernels->numCols : numCols); 502 int yNormSize = (kernels->numRows > 0 ? kernels->numRows : numRows); 503 504 // Normalised coordinates 505 float yNorm = 2.0 * (float)(y - yNormSize/2.0) / (float)yNormSize; 506 float xNorm = 2.0 * (float)(x - xNormSize/2.0) / (float)xNormSize; 507 593 594 float xNorm, yNorm; // Normalised coordinates 595 p_pmSubtractionPolynomialNormCoords(&xNorm, &yNorm, x, y, 596 kernels->xMin, kernels->xMax, kernels->yMin, kernels->yMax); 508 597 return p_pmSubtractionPolynomial(output, kernels->spatialOrder, xNorm, yNorm); 509 598 } … … 586 675 if (index < kernels->inner) { 587 676 // Photometric scaling is already built in to the precalculated kernel 588 return p_pmSubtractionConvolveStampPrecalc(image, kernels->preCalc->data[index]);677 return convolveStampPreCalc(image, kernels, index, footprint); 589 678 } 590 679 // Using delta function … … 595 684 return convolved; 596 685 } 597 case PM_SUBTRACTION_KERNEL_ISIS: { 598 psArray *preCalc = kernels->preCalc->data[index]; // Precalculated values 599 psVector *xKernel = preCalc->data[0]; // Kernel in x 600 psVector *yKernel = preCalc->data[1]; // Kernel in y 601 int size = kernels->size; // Size of kernel 602 603 // Convolve in x 604 // Need to convolve a bit more than the footprint, for the y convolution 605 int yMin = -size - footprint, yMax = size + footprint; // Range for y 606 psKernel *temp = psKernelAlloc(yMin, yMax, 607 -footprint, footprint); // Temporary convolution; NOTE: wrong way! 608 for (int y = yMin; y <= yMax; y++) { 609 for (int x = -footprint; x <= footprint; x++) { 610 float value = 0.0; // Value of convolved pixel 611 int uMin = x - size, uMax = x + size; // Range for u 612 psF32 *xKernelData = &xKernel->data.F32[xKernel->n - 1]; // Kernel values 613 psF32 *imageData = &image->kernel[y][uMin]; // Image values 614 for (int u = uMin; u <= uMax; u++, xKernelData--, imageData++) { 615 value += *xKernelData * *imageData; 616 } 617 temp->kernel[x][y] = value; // NOTE: putting in wrong way! 618 } 619 } 620 621 // Convolve in y 622 psKernel *convolved = psKernelAlloc(-footprint, footprint, -footprint, footprint);// Convolved image 623 for (int x = -footprint; x <= footprint; x++) { 624 for (int y = -footprint; y <= footprint; y++) { 625 float value = 0.0; // Value of convolved pixel 626 int vMin = y - size, vMax = y + size; // Range for v 627 psF32 *yKernelData = &yKernel->data.F32[yKernel->n - 1]; // Kernel values 628 psF32 *imageData = &temp->kernel[x][vMin]; // Image values; NOTE: wrong way! 629 for (int v = vMin; v <= vMax; v++, yKernelData--, imageData++) { 630 value += *yKernelData * *imageData; 631 } 632 convolved->kernel[y][x] = value; 633 } 634 } 635 psFree(temp); 636 637 // Photometric scaling for even kernels only 638 if (kernels->u->data.S32[index] % 2 == 0 && kernels->v->data.S32[index] % 2 == 0) { 639 convolveSub(convolved, image, footprint); 640 } 641 return convolved; 642 } 686 case PM_SUBTRACTION_KERNEL_ISIS: 687 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 688 case PM_SUBTRACTION_KERNEL_HERM: 689 case PM_SUBTRACTION_KERNEL_DECONV_HERM: { 690 return convolveStampPreCalc(image, kernels, index, footprint); 691 } 643 692 case PM_SUBTRACTION_KERNEL_RINGS: { 644 psKernel *convolved = psKernelAlloc(-footprint, footprint, 645 -footprint, footprint); // Convolved image 646 psArray *preCalc = kernels->preCalc->data[index]; // Precalculated data 647 psVector *uCoords = preCalc->data[0]; // u coordinates 648 psVector *vCoords = preCalc->data[1]; // v coordinates 649 psVector *poly = preCalc->data[2]; // Polynomial values 650 int num = uCoords->n; // Number of pixels 651 psS32 *uData = uCoords->data.S32, *vData = vCoords->data.S32; // Dereference u,v coordinates 652 psF32 *polyData = poly->data.F32; // Dereference polynomial values 693 psKernel *convolved = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Convolved image 694 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[index]; // Precalculated data 695 696 int num = preCalc->uCoords->n; // Number of pixels 697 psS32 *uData = preCalc->uCoords->data.S32; // Dereference v coordinate 698 psS32 *vData = preCalc->vCoords->data.S32; // Dereference u coordinate 699 psF32 *polyData = preCalc->poly->data.F32; // Dereference polynomial values 653 700 psF32 **imageData = image->kernel; // Dereference image 654 701 psF32 **convData = convolved->kernel; // Dereference convolved image … … 706 753 707 754 if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE) { 708 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Stamp not marked for calculation.");755 psError(PM_ERR_PROG, true, "Stamp not marked for calculation."); 709 756 return false; 710 757 } … … 730 777 731 778 732 733 734 779 int pmSubtractionRejectStamps(pmSubtractionKernels *kernels, pmSubtractionStampList *stamps, 735 const psVector *deviations, psImage *subMask, float sigmaRej , int footprint)780 const psVector *deviations, psImage *subMask, float sigmaRej) 736 781 { 737 782 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); … … 764 809 765 810 if (numStamps == 0) { 766 psError(P S_ERR_UNKNOWN, true, "No good stamps found.");811 psError(PM_ERR_STAMPS, true, "No good stamps found."); 767 812 psFree(mask); 768 813 return -1; … … 772 817 PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_QUARTILE); // Statistics for deviatns 773 818 if (!psVectorStats(stats, deviations, NULL, mask, 0xff)) { 774 psError(P S_ERR_UNKNOWN, false, "Unable to measure statistics for deviations.");819 psError(PM_ERR_DATA, false, "Unable to measure statistics for deviations."); 775 820 psFree(stats); 776 821 psFree(mask); … … 821 866 ds9num++; 822 867 868 int footprint = stamps->footprint; // Half-size of stamp region of interest 823 869 int numRejected = 0; // Number of stamps rejected 824 870 int numGood = 0; // Number of good stamps 825 871 double newMean = 0.0; // New mean 872 psString log = NULL; // Log message 873 psStringAppend(&log, "Rejecting stamps, mean = %f, threshold = %f\n", mean, limit); 826 874 for (int i = 0; i < stamps->num; i++) { 827 875 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest … … 836 884 // Mask out the stamp in the image so you it's not found again 837 885 psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i, 838 (int)(stamp->x + 0.5), (int)(stamp->y + 0.5)); 886 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 887 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", i, 888 (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), 889 fabsf(deviations->data.F32[i] - mean)); 839 890 numRejected++; 840 891 for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) { … … 857 908 psFree(stamp->image1); 858 909 psFree(stamp->image2); 859 psFree(stamp->variance); 860 stamp->image1 = stamp->image2 = stamp->variance = NULL; 861 psFree(stamp->matrix1); 862 psFree(stamp->matrix2); 863 psFree(stamp->matrixX); 864 stamp->matrix1 = stamp->matrix2 = stamp->matrixX = NULL; 865 psFree(stamp->vector1); 866 psFree(stamp->vector2); 867 stamp->vector1 = stamp->vector2 = NULL; 910 psFree(stamp->weight); 911 stamp->image1 = stamp->image2 = stamp->weight = NULL; 912 psFree(stamp->matrix); 913 stamp->matrix = NULL; 914 psFree(stamp->vector); 915 stamp->vector = NULL; 868 916 } else { 869 917 numGood++; … … 874 922 } 875 923 newMean /= numGood; 924 925 if (numRejected == 0) { 926 psStringAppend(&log, "<none>\n"); 927 } 928 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "%s", log); 929 psFree(log); 876 930 877 931 if (ds9) { … … 900 954 901 955 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, x, y); // Solved polynomial 902 psKernel *kernel = solvedKernel(NULL, kernels, polyValues, wantDual); // The appropriate kernel956 psKernel *kernel = solvedKernel(NULL, kernels, polyValues, true, wantDual); // The appropriate kernel 903 957 psFree(polyValues); 904 958 … … 931 985 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, x, y); 932 986 933 psKernel *kernel = solvedKernel(NULL, kernels, polyValues, wantDual); // The appropriate kernel987 psKernel *kernel = solvedKernel(NULL, kernels, polyValues, true, wantDual); // The appropriate kernel 934 988 psFree(polyValues); 935 989 … … 948 1002 } 949 1003 950 #if 01004 #if 1 951 1005 psArray *pmSubtractionKernelSolutions(const pmSubtractionKernels *kernels, float x, float y, bool wantDual) 952 1006 { … … 956 1010 PS_ASSERT_FLOAT_WITHIN_RANGE(y, -1.0, 1.0, NULL); 957 1011 958 psArray *images = psArrayAlloc(solution->n - 1); // Images of each kernel to return 959 psVector *fakeSolution = psVectorAlloc(solution->n, PS_TYPE_F64); // Fake solution vector 960 psVectorInit(fakeSolution, 0.0); 961 962 for (int i = 0; i < solution->n - 1; i++) { 963 fakeSolution->data.F64[i] = solution->data.F64[i]; 964 images->data[i] = pmSubtractionKernelImage(kernels, x, y, wantDual); 965 fakeSolution->data.F64[i] = 0.0; 966 } 967 968 psFree(fakeSolution); 1012 psVector *solution = wantDual ? kernels->solution2 : kernels->solution1; // Solution of interest 1013 psVector *backup = psVectorCopy(NULL, solution, PS_TYPE_F64); // Backup version 1014 1015 int num = kernels->num; // Number of kernel basis functions 1016 1017 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, x, y); // Solved polynomial 1018 psArray *images = psArrayAlloc(num + 1); // Images of each kernel to return 1019 1020 // The whole kernel 1021 { 1022 psKernel *kernel = solvedKernel(NULL, kernels, polyValues, true, wantDual); // The appropriate kernel 1023 images->data[0] = psMemIncrRefCounter(kernel->image); 1024 psFree(kernel); 1025 } 1026 1027 // The parts 1028 psVectorInit(solution, 0.0); 1029 for (int i = 0; i < num; i++) { 1030 solution->data.F64[i] = backup->data.F64[i]; 1031 psKernel *kernel = solvedKernel(NULL, kernels, polyValues, false, wantDual); // The appropriate kernel 1032 #if 0 1033 int size = kernels->size; 1034 double sum = 0.0; 1035 for (int v = -size; v <= size; v++) { 1036 for (int u = -size; u <= size; u++) { 1037 sum += kernel->kernel[v][u]; 1038 } 1039 } 1040 fprintf(stderr, "Kernel %d: %lf\n", i, sum); 1041 #endif 1042 images->data[i + 1] = psMemIncrRefCounter(kernel->image); 1043 psFree(kernel); 1044 solution->data.F64[i] = 0.0; 1045 } 1046 psFree(polyValues); 1047 psVectorCopy(solution, backup, PS_TYPE_F64); 1048 psFree(backup); 969 1049 970 1050 return images; … … 979 1059 psImage *convMask, // Output convolved mask 980 1060 const pmReadout *ro1, const pmReadout *ro2, // Input readouts 981 psImage * sys1, psImage *sys2, // Systematicerror images1061 psImage *kernelErr1, psImage *kernelErr2, // Kernel error images 982 1062 psImage *subMask, // Input subtraction mask 983 1063 psImageMaskType maskBad, // Mask value to give bad pixels … … 998 1078 // Only generate polynomial values every kernel footprint, since we have already assumed 999 1079 // (with the stamps) that it does not vary rapidly on this scale. 1000 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 1001 xMin + x0 + size + 1, 1002 yMin + y0 + size + 1); 1080 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, xMin + x0 + size + 1, 1081 yMin + y0 + size + 1); // Polynomial 1003 1082 float background = doBG ? p_pmSubtractionSolutionBackground(kernels, polyValues) : 0.0; // Background term 1004 1083 1005 1084 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1006 convolveRegion(out1->image, out1->variance, convMask, &kernelImage, &kernelVariance,1007 ro1->image, ro1->variance, sys1, subMask, kernels, polyValues, background, *region,1008 maskBad, maskPoor, poorFrac, useFFT, false);1085 convolveRegion(out1->image, out1->variance, out1->mask, &kernelImage, &kernelVariance, 1086 ro1->image, ro1->variance, kernelErr1, subMask, kernels, polyValues, background, 1087 *region, maskBad, maskPoor, poorFrac, useFFT, false); 1009 1088 } 1010 1089 if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1011 convolveRegion(out2->image, out2->variance, convMask, &kernelImage, &kernelVariance, 1012 ro2->image, ro2->variance, sys2, subMask, kernels, polyValues, background, *region, 1013 maskBad, maskPoor, poorFrac, useFFT, kernels->mode == PM_SUBTRACTION_MODE_DUAL); 1090 convolveRegion(out2->image, out2->variance, out2->mask, &kernelImage, &kernelVariance, 1091 ro2->image, ro2->variance, kernelErr2, subMask, kernels, polyValues, background, 1092 *region, maskBad, maskPoor, poorFrac, useFFT, 1093 kernels->mode == PM_SUBTRACTION_MODE_DUAL); 1014 1094 } 1015 1095 … … 1019 1099 1020 1100 if ((kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) && ro1->mask) { 1021 psImageMaskType **target = convMask->data.PS_TYPE_IMAGE_MASK_DATA; // Target mask1101 psImageMaskType **target = out1->mask->data.PS_TYPE_IMAGE_MASK_DATA; // Target mask 1022 1102 psImageMaskType **source = ro1->mask->data.PS_TYPE_IMAGE_MASK_DATA; // Source mask 1023 1103 … … 1029 1109 } 1030 1110 if ((kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) && ro2->mask) { 1031 psImageMaskType **target = convMask->data.PS_TYPE_IMAGE_MASK_DATA; // Target mask1111 psImageMaskType **target = out2->mask->data.PS_TYPE_IMAGE_MASK_DATA; // Target mask 1032 1112 psImageMaskType **source = ro2->mask->data.PS_TYPE_IMAGE_MASK_DATA; // Source mask 1033 1113 … … 1056 1136 const pmReadout *ro1 = args->data[7]; // Input readout 1 1057 1137 const pmReadout *ro2 = args->data[8]; // Input readout 2 1058 psImage * sys1 = args->data[9]; // Systematicerror image 11059 psImage * sys2 = args->data[10]; // Systematicerror image 21138 psImage *kernelErr1 = args->data[9]; // Kernel error image 1 1139 psImage *kernelErr2 = args->data[10]; // Kernel error image 2 1060 1140 psImage *subMask = args->data[11]; // Subtraction mask 1061 1141 psImageMaskType maskBad = PS_SCALAR_VALUE(args->data[12], PS_TYPE_IMAGE_MASK_DATA); // Output mask value for bad pixels … … 1067 1147 bool useFFT = PS_SCALAR_VALUE(args->data[18], U8); // Use FFT for convolution? 1068 1148 1069 return subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2, sys1, sys2, 1070 subMask, maskBad, maskPoor, poorFrac, region, kernels, doBG, useFFT); 1149 return subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2, kernelErr1, 1150 kernelErr2, subMask, maskBad, maskPoor, poorFrac, region, kernels, 1151 doBG, useFFT); 1071 1152 } 1072 1153 1073 1154 bool pmSubtractionConvolve(pmReadout *out1, pmReadout *out2, const pmReadout *ro1, const pmReadout *ro2, 1074 1155 psImage *subMask, int stride, psImageMaskType maskBad, psImageMaskType maskPoor, 1075 float poorFrac, float sysError, const psRegion *region,1156 float poorFrac, float kernelError, float covarFrac, const psRegion *region, 1076 1157 const pmSubtractionKernels *kernels, bool doBG, bool useFFT) 1077 1158 { … … 1082 1163 PM_ASSERT_READOUT_NON_NULL(ro1, false); 1083 1164 PM_ASSERT_READOUT_IMAGE(ro1, false); 1165 PM_ASSERT_READOUT_IMAGE(out1, false); 1084 1166 numCols = ro1->image->numCols; 1085 1167 numRows = ro1->image->numRows; … … 1091 1173 PM_ASSERT_READOUT_NON_NULL(ro2, false); 1092 1174 PM_ASSERT_READOUT_IMAGE(ro2, false); 1175 PM_ASSERT_READOUT_IMAGE(out2, false); 1093 1176 if (numCols == 0 && numRows == 0) { 1094 1177 numCols = ro2->image->numCols; … … 1111 1194 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(poorFrac, 0.0, false); 1112 1195 PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(poorFrac, 1.0, false); 1113 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(sysError, 0.0, false); 1114 PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(sysError, 1.0, false); 1196 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(kernelError, 0.0, false); 1197 PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(kernelError, 1.0, false); 1198 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(covarFrac, 0.0, false); 1199 PS_ASSERT_FLOAT_LESS_THAN(covarFrac, 1.0, false); 1115 1200 if (region && psRegionIsNaN(*region)) { 1116 1201 psString string = psRegionToString(*region); 1117 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Input region (%s) contains NAN values", string);1202 psError(PM_ERR_PROG, true, "Input region (%s) contains NAN values", string); 1118 1203 psFree(string); 1119 1204 return false; … … 1124 1209 bool threaded = pmSubtractionThreaded(); // Running threaded? 1125 1210 1126 // Outputs1127 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {1128 if (!out1->image) {1129 out1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);1130 // XXX if (threaded) {1131 // XXX psMutexInit(out1->image);1132 // XXX }1133 }1134 if (ro1->variance) {1135 if (!out1->variance) {1136 out1->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32);1137 // XXX if (threaded) {1138 // XXX psMutexInit(out1->variance);1139 // XXX }1140 }1141 psImageInit(out1->variance, 0.0);1142 }1143 }1144 if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {1145 if (!out2->image) {1146 out2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);1147 // XXX if (threaded) {1148 // XXX psMutexInit(out2->image);1149 // XXX }1150 }1151 if (ro2->variance) {1152 if (!out2->variance) {1153 out2->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32);1154 // XXX if (threaded) {1155 // XXX psMutexInit(out2->variance);1156 // XXX }1157 }1158 psImageInit(out2->variance, 0.0);1159 }1160 }1161 1211 psImage *convMask = NULL; // Convolved mask image (common to inputs 1 and 2) 1162 1212 if (subMask) { 1163 // XXX if (threaded) {1164 // XXX psMutexInit(subMask);1165 // XXX }1166 1213 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1167 if (!out1->mask) {1168 out1->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);1169 }1170 1214 convMask = out1->mask; 1171 1215 } 1172 1216 if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1173 if (convMask) { 1174 if (out2->mask) { 1175 psFree(out2->mask); 1176 } 1177 out2->mask = psMemIncrRefCounter(convMask); 1178 } else { 1179 if (!out2->mask) { 1180 out2->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 1181 } 1217 if (!convMask) { 1182 1218 convMask = out2->mask; 1183 1219 } 1184 1220 } 1185 psImageInit(convMask, 0);1186 } 1187 1188 psImage *sys1 = NULL, *sys2 = NULL; // Systematic error images 1221 } 1222 1223 psImage *kernelErr1 = NULL, *kernelErr2 = NULL; // Kernel error images 1224 #ifdef USE_KERNEL_ERR 1189 1225 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1190 sys1 = subtractionSysErrImage(ro1->image, sysError); 1191 // XXX if (threaded && sys1) { 1192 // XXX psMutexInit(sys1); 1193 // XXX } 1226 kernelErr1 = subtractionKernelErrImage(ro1->image, kernelError); 1194 1227 } 1195 1228 if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1196 sys2 = subtractionSysErrImage(ro2->image, sysError); 1197 // XXX if (threaded && sys2) { 1198 // XXX psMutexInit(sys2); 1199 // XXX } 1200 } 1229 kernelErr2 = subtractionKernelErrImage(ro2->image, kernelError); 1230 } 1231 #endif 1201 1232 1202 1233 int size = kernels->size; // Half-size of kernel 1203 1234 1204 1235 // Get region for convolution: [xMin:xMax,yMin:yMax] 1205 int xMin = size, xMax = numCols- size;1206 int yMin = size, yMax = numRows- size;1236 int xMin = kernels->xMin + size, xMax = kernels->xMax - size; 1237 int yMin = kernels->yMin + size, yMax = kernels->yMax - size; 1207 1238 if (region) { 1208 1239 xMin = PS_MAX(region->x0, xMin); … … 1247 1278 psArrayAdd(args, 1, (pmReadout*)ro1); // Casting away const 1248 1279 psArrayAdd(args, 1, (pmReadout*)ro2); // Casting away const 1249 // Since adding to the array can impact the reference count, we need to lock 1250 // XXX if (sys1) { 1251 // XXX psMutexLock(sys1); 1252 // XXX } 1253 psArrayAdd(args, 1, sys1); 1254 // XXX if (sys1) { 1255 // XXX psMutexUnlock(sys1); 1256 // XXX } 1257 // XXX if (sys2) { 1258 // XXX psMutexLock(sys2); 1259 // XXX } 1260 psArrayAdd(args, 1, sys2); 1261 // XXX if (sys2) { 1262 // XXX psMutexUnlock(sys2); 1263 // XXX } 1264 // XXX if (subMask) { 1265 // XXX psMutexLock(subMask); 1266 // XXX } 1280 psArrayAdd(args, 1, kernelErr1); 1281 psArrayAdd(args, 1, kernelErr2); 1267 1282 psArrayAdd(args, 1, subMask); 1268 // XXX if (subMask) {1269 // XXX psMutexUnlock(subMask);1270 // XXX }1271 1283 PS_ARRAY_ADD_SCALAR(args, maskBad, PS_TYPE_IMAGE_MASK); 1272 1284 PS_ARRAY_ADD_SCALAR(args, maskPoor, PS_TYPE_IMAGE_MASK); … … 1283 1295 psFree(job); 1284 1296 } else { 1285 subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2, sys1, sys2,1286 subMask, maskBad, maskPoor, poorFrac, subRegion, kernels, doBG,1287 useFFT);1297 subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2, 1298 kernelErr1, kernelErr2, subMask, maskBad, maskPoor, poorFrac, 1299 subRegion, kernels, doBG, useFFT); 1288 1300 } 1289 1301 psFree(subRegion); … … 1292 1304 1293 1305 if (!psThreadPoolWait(false)) { 1294 psError( PS_ERR_UNKNOWN, false, "Error waiting for threads.");1306 psError(psErrorCodeLast(), false, "Error waiting for threads."); 1295 1307 return false; 1296 1308 } … … 1307 1319 psFree(job); 1308 1320 } 1309 1310 // XXX if (subMask) {1311 // XXX psMutexDestroy(subMask);1312 // XXX }1313 // XXX if (sys1) {1314 // XXX psMutexDestroy(sys1);1315 // XXX }1316 // XXX if (sys2) {1317 // XXX psMutexDestroy(sys2);1318 // XXX }1319 1321 } 1320 1322 psImageConvolveSetThreads(oldThreads); 1321 1323 1322 psFree( sys1);1323 psFree( sys2);1324 psFree(kernelErr1); 1325 psFree(kernelErr2); 1324 1326 1325 1327 // Calculate covariances 1326 // This can take a while, so we only do it for a single instance 1327 // XXX psImageCovarianceCalculate could be multithreaded 1328 // This can be fairly involved, so we only do it for a single instance 1329 // Enable threads for covariance calculation, since we're not threading on top of it. 1330 oldThreads = psImageCovarianceSetThreads(true); 1328 1331 if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 1329 1332 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, false); // Convolution kernel 1333 psKernelTruncate(kernel, covarFrac); 1330 1334 out1->covariance = psImageCovarianceCalculate(kernel, ro1->covariance); 1331 1335 psFree(kernel); … … 1334 1338 psKernel *kernel = pmSubtractionKernel(kernels, 0.0, 0.0, 1335 1339 kernels->mode == PM_SUBTRACTION_MODE_DUAL); // Conv. kernel 1340 psKernelTruncate(kernel, covarFrac); 1336 1341 out2->covariance = psImageCovarianceCalculate(kernel, ro2->covariance); 1337 1342 psFree(kernel); 1338 1343 } 1344 psImageCovarianceSetThreads(oldThreads); 1339 1345 1340 1346 // Copy anything that wasn't convolved … … 1376 1382 } 1377 1383 1378 1379 1384 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Convolve image: %f sec", 1380 1385 psTimerClear("pmSubtractionConvolve")); -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtraction.h
r21363 r27840 68 68 const psVector *deviations, ///< Deviations for each stamp 69 69 psImage *subMask, ///< Subtraction mask 70 float sigmaRej, ///< Number of RMS deviations above zero at which to reject 71 int footprint ///< Half-size of stamp 70 float sigmaRej ///< Number of RMS deviations above zero at which to reject 72 71 ); 73 72 … … 94 93 95 94 /// Generate images of the convolution kernel elements 96 psArray *pmSubtractionKernelSolutions(const p sVector *solution, ///< Solution vector97 const pmSubtractionKernels *kernels, ///< Kernel parameters98 float x, float y ///< Normalised position [-1,1] for images95 psArray *pmSubtractionKernelSolutions(const pmSubtractionKernels *kernels, ///< Kernel parameters 96 float x, float y, ///< Normalised position [-1,1] for images 97 bool wantDual ///< Calculate for the dual kernel? 99 98 ); 99 100 100 101 101 /// Execute a thread job to convolve a patch of the image … … 113 113 psImageMaskType maskPoor, ///< Mask value to give poor pixels 114 114 float poorFrac, ///< Fraction for "poor" 115 float sysError, ///< Relative systematic error 115 float kernelError, ///< Relative systematic error in kernel 116 float covarFrac, ///< Truncation fraction for kernel before covariance calculation 116 117 const psRegion *region, ///< Region to convolve (or NULL) 117 118 const pmSubtractionKernels *kernels, ///< Kernel parameters … … 127 128 ); 128 129 130 /// Return normalised coordinates 131 void p_pmSubtractionPolynomialNormCoords( 132 float *xOut, float *yOut, ///< Normalised coordinates, returned 133 float xIn, float yIn, ///< Input coordinates 134 int xMin, int xMax, int yMin, int yMax ///< Bounds of validity 135 ); 136 129 137 /// Given (normalised) coordinates (x,y), generate a matrix where the elements (i,j) are x^i * y^j 130 138 psImage *p_pmSubtractionPolynomial(psImage *output, ///< Output matrix, or NULL … … 138 146 psImage *p_pmSubtractionPolynomialFromCoords(psImage *output, ///< Output matrix, or NULL 139 147 const pmSubtractionKernels *kernels, ///< Kernel parameters 140 int numCols, int numRows, ///< Size of image of interest141 148 int x, int y ///< Position of interest 142 149 ); -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionAnalysis.c
r25060 r27840 16 16 #define KERNEL_MOSAIC 2 // Half-number of kernel instances in the mosaic image 17 17 18 //#define TESTING 18 19 19 20 bool pmSubtractionAnalysis(psMetadata *analysis, psMetadata *header, … … 42 43 psFree(subRegion); 43 44 44 psMetadataAddPtr(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_REGION, 45 PS_DATA_REGION | PS_META_DUPLICATE_OK, 45 psMetadataAddStr(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_REGION, PS_META_DUPLICATE_OK, 46 46 "Region over which subtraction was performed", string); 47 47 psFree(string); … … 74 74 false); // Image of the kernel 75 75 if (!kernel) { 76 psError( PS_ERR_UNKNOWN, false, "Unable to generate kernel image.");76 psError(psErrorCodeLast(), false, "Unable to generate kernel image."); 77 77 psFree(convKernels); 78 78 return false; … … 81 81 if (psImageOverlaySection(convKernels, kernel, (i + KERNEL_MOSAIC) * fullSize, 82 82 (j + KERNEL_MOSAIC) * fullSize, "=") == 0) { 83 psError( PS_ERR_UNKNOWN, false, "Unable to overlay kernel image.");83 psError(psErrorCodeLast(), false, "Unable to overlay kernel image."); 84 84 psFree(kernel); 85 85 psFree(convKernels); … … 93 93 true); // Image of the kernel 94 94 if (!kernel) { 95 psError( PS_ERR_UNKNOWN, false, "Unable to generate kernel image.");95 psError(psErrorCodeLast(), false, "Unable to generate kernel image."); 96 96 psFree(convKernels); 97 97 return false; … … 101 101 (2 * KERNEL_MOSAIC + 1 + i + KERNEL_MOSAIC) * fullSize + 4, 102 102 (j + KERNEL_MOSAIC) * fullSize, "=") == 0) { 103 psError( PS_ERR_UNKNOWN, false, "Unable to overlay kernel image.");103 psError(psErrorCodeLast(), false, "Unable to overlay kernel image."); 104 104 psFree(kernel); 105 105 psFree(convKernels); … … 117 117 } 118 118 119 120 #if 0 119 // sample difference images 120 { 121 psMetadataAddArray(analysis, PS_LIST_TAIL, "SUBTRACTION.SAMPLE.STAMP.SET", PS_META_DUPLICATE_OK, "Sample Difference Stamps", kernels->sampleStamps); 122 } 123 124 #ifdef TESTING 121 125 // Generate images of the kernel components 122 126 { 123 127 psMetadata *header = psMetadataAlloc(); // Header 124 for (int i = 0; i < solution->n; i++) {128 for (int i = 0; i < kernels->solution1->n; i++) { 125 129 psString name = NULL; // Header keyword 126 130 psStringAppend(&name, "SOLN%04d", i); 127 psMetadataAddF64(header, PS_LIST_TAIL, name, 0, NULL, solution->data.F64[i]);131 psMetadataAddF64(header, PS_LIST_TAIL, name, 0, NULL, kernels->solution1->data.F64[i]); 128 132 psFree(name); 129 133 } 130 psArray *kernelImages = pmSubtractionKernelSolutions( solution, kernels, 0.0, 0.0);131 psFits *kernelFile = psFitsOpen("kernels .fits", "w");134 psArray *kernelImages = pmSubtractionKernelSolutions(kernels, 0.0, 0.0, false); 135 psFits *kernelFile = psFitsOpen("kernels1.fits", "w"); 132 136 (void)psFitsWriteImageCube(kernelFile, header, kernelImages, NULL); 133 137 psFitsClose(kernelFile); … … 135 139 psFree(header); 136 140 } 141 if (kernels->solution2) { 142 psMetadata *header = psMetadataAlloc(); // Header 143 for (int i = 0; i < kernels->solution2->n; i++) { 144 psString name = NULL; // Header keyword 145 psStringAppend(&name, "SOLN%04d", i); 146 psMetadataAddF64(header, PS_LIST_TAIL, name, 0, NULL, kernels->solution2->data.F64[i]); 147 psFree(name); 148 } 149 psArray *kernelImages = pmSubtractionKernelSolutions(kernels, 0.0, 0.0, true); 150 psFits *kernelFile = psFitsOpen("kernels2.fits", "w"); 151 (void)psFitsWriteImageCube(kernelFile, header, kernelImages, NULL); 152 psFitsClose(kernelFile); 153 psFree(kernelImages); 154 psFree(header); 155 } 137 156 #endif 138 157 … … 142 161 psImage *image = pmSubtractionKernelImage(kernels, 0.5, 0.5, false); // Image of the kernel 143 162 if (!image) { 144 psError( PS_ERR_UNKNOWN, false, "Unable to generate image of kernel.");163 psError(psErrorCodeLast(), false, "Unable to generate image of kernel."); 145 164 return false; 146 165 } … … 197 216 psImage *image = pmSubtractionKernelImage(kernels, 0.5, 0.5, false); // Image of the kernel 198 217 if (!image) { 199 psError( PS_ERR_UNKNOWN, false, "Unable to generate image of kernel.");218 psError(psErrorCodeLast(), false, "Unable to generate image of kernel."); 200 219 return false; 201 220 } … … 254 273 // Difference in background 255 274 { 256 psImage *polyValues = p_pmSubtractionPolynomialFromCoords(NULL, kernels, numCols, numRows, 257 numCols / 2.0, numRows / 2.0); // Polynomial 275 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, 0.0, 0.0); // Polynomial 258 276 float bg = p_pmSubtractionSolutionBackground(kernels, polyValues); // Background difference 259 277 … … 280 298 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_DEV_RMS, 0, "RMS stamp deviation", 281 299 kernels->rms); 300 301 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 302 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 303 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 304 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 305 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 306 psMetadataAddF32(analysis, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 307 308 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 309 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 310 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 311 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 312 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResMean); 313 psMetadataAddF32(header, PS_LIST_TAIL, PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV, 0, "Mean Fractional Sigma of Residuals", kernels->fSigResStdev); 282 314 } 283 315 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionAnalysis.h
r25060 r27840 24 24 #define PM_SUBTRACTION_ANALYSIS_DECONV_MAX "SUBTRACTION.DECONV.MAX" // Maximum deconvolution fraction 25 25 26 #define PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_MEAN "SUBTRACTION.RES.FSIGMA.MEAN" // RMS stamp deviation 27 #define PM_SUBTRACTION_ANALYSIS_FSIGMA_RES_STDEV "SUBTRACTION.RES.FSIGMA.STDEV" // RMS stamp deviation 28 #define PM_SUBTRACTION_ANALYSIS_FMIN_RES_MEAN "SUBTRACTION.RES.FMIN.MEAN" // RMS stamp deviation 29 #define PM_SUBTRACTION_ANALYSIS_FMIN_RES_STDEV "SUBTRACTION.RES.FMIN.STDEV" // RMS stamp deviation 30 #define PM_SUBTRACTION_ANALYSIS_FMAX_RES_MEAN "SUBTRACTION.RES.FMAX.MEAN" // RMS stamp deviation 31 #define PM_SUBTRACTION_ANALYSIS_FMAX_RES_STDEV "SUBTRACTION.RES.FMAX.STDEV" // RMS stamp deviation 32 26 33 // Derive QA information about the subtraction 27 34 bool pmSubtractionAnalysis( -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionEquation.c
r24844 r27840 7 7 #include <pslib.h> 8 8 9 #include "pmErrorCodes.h" 9 10 #include "pmSubtraction.h" 10 11 #include "pmSubtractionKernels.h" … … 15 16 #include "pmSubtractionVisual.h" 16 17 17 // #define TESTING // TESTING output for debugging; may not work with threads! 18 19 #define USE_VARIANCE // Include variance in equation? 18 //#define TESTING // TESTING output for debugging; may not work with threads! 19 20 //#define USE_WEIGHT // Include weight (1/variance) in equation? 21 //#define USE_WINDOW // Include weight (1/variance) in equation? 22 20 23 21 24 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 23 26 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 24 27 25 // Calculate the sum over a stamp product 26 static inline double calculateSumProduct(const psKernel *image1, // First image in multiplication 27 const psKernel *image2, // Second image in multiplication 28 const psKernel *variance, // Variance image 29 int footprint // (Half-)Size of stamp 30 ) 28 // Calculate the least-squares matrix and vector 29 static bool calculateMatrixVector(psImage *matrix, // Least-squares matrix, updated 30 psVector *vector, // Least-squares vector, updated 31 double *norm, // Normalisation, updated 32 const psKernel *input, // Input image (target) 33 const psKernel *reference, // Reference image (convolution source) 34 const psKernel *weight, // Weight image 35 const psKernel *window, // Window image 36 const psArray *convolutions, // Convolutions for each kernel 37 const pmSubtractionKernels *kernels, // Kernels 38 const psImage *polyValues, // Spatial polynomial values 39 int footprint, // (Half-)Size of stamp 40 int normWindow, // Window (half-)size for normalisation measurement 41 const pmSubtractionEquationCalculationMode mode 42 ) 31 43 { 32 double sum = 0.0; // Sum of the image products 44 // (I - R * sum_i a_i k_i - g) (R * k_j) = 0 45 // I C_j = sum_i C_i C_j 46 47 // Background: C_i = 1.0 48 // Normalisation: C_i = R 49 50 int numKernels = kernels->num; // Number of kernels 51 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 52 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 53 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 54 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 55 double poly[numPoly]; // Polynomial terms 56 double poly2[numPoly][numPoly]; // Polynomial-polynomial values 57 58 // Evaluate polynomial-polynomial terms 59 // XXX we can skip this if we are not calculating kernel coeffs 60 for (int iyOrder = 0, iIndex = 0; iyOrder <= spatialOrder; iyOrder++) { 61 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex++) { 62 double iPoly = polyValues->data.F64[iyOrder][ixOrder]; // Value of polynomial 63 poly[iIndex] = iPoly; 64 for (int jyOrder = 0, jIndex = 0; jyOrder <= spatialOrder; jyOrder++) { 65 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; jxOrder++, jIndex++) { 66 double jPoly = polyValues->data.F64[jyOrder][jxOrder]; 67 poly2[iIndex][jIndex] = iPoly * jPoly; 68 } 69 } 70 } 71 } 72 73 // initialize the matrix and vector for NOP on all coeffs. we only fill in the coeffs we 74 // choose to calculate 75 psImageInit(matrix, 0.0); 76 psVectorInit(vector, 1.0); 77 for (int i = 0; i < matrix->numCols; i++) { 78 matrix->data.F64[i][i] = 1.0; 79 } 80 81 // the order of the elements in the matrix and vector is: 82 // [kernel 0, x^0 y^0][kernel 1 x^0 y^0]...[kernel N, x^0 y^0] 83 // [kernel 0, x^1 y^0][kernel 1 x^1 y^0]...[kernel N, x^1 y^0] 84 // [kernel 0, x^n y^m][kernel 1 x^n y^m]...[kernel N, x^n y^m] 85 // normalization 86 // bg 0, bg 1, bg 2 (only 0 is currently used?) 87 88 for (int i = 0; i < numKernels; i++) { 89 psKernel *iConv = convolutions->data[i]; // Convolution for index i 90 for (int j = i; j < numKernels; j++) { 91 psKernel *jConv = convolutions->data[j]; // Convolution for index j 92 93 double sumCC = 0.0; // Sum of convolution products 94 for (int y = - footprint; y <= footprint; y++) { 95 for (int x = - footprint; x <= footprint; x++) { 96 double cc = iConv->kernel[y][x] * jConv->kernel[y][x]; 97 if (weight) { 98 cc *= weight->kernel[y][x]; 99 } 100 if (window) { 101 cc *= window->kernel[y][x]; 102 } 103 sumCC += cc; 104 } 105 } 106 107 // Spatial variation of kernel coeffs 108 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 109 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 110 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 111 double value = sumCC * poly2[iTerm][jTerm]; 112 matrix->data.F64[iIndex][jIndex] = value; 113 matrix->data.F64[jIndex][iIndex] = value; 114 } 115 } 116 } 117 } 118 119 double sumRC = 0.0; // Sum of the reference-convolution products 120 double sumIC = 0.0; // Sum of the input-convolution products 121 double sumC = 0.0; // Sum of the convolution 122 for (int y = - footprint; y <= footprint; y++) { 123 for (int x = - footprint; x <= footprint; x++) { 124 float conv = iConv->kernel[y][x]; 125 float in = input->kernel[y][x]; 126 float ref = reference->kernel[y][x]; 127 double ic = in * conv; 128 double rc = ref * conv; 129 double c = conv; 130 if (weight) { 131 float wtVal = weight->kernel[y][x]; 132 ic *= wtVal; 133 rc *= wtVal; 134 c *= wtVal; 135 } 136 if (window) { 137 float winVal = window->kernel[y][x]; 138 ic *= winVal; 139 rc *= winVal; 140 c *= winVal; 141 } 142 sumIC += ic; 143 sumRC += rc; 144 sumC += c; 145 } 146 } 147 // Spatial variation 148 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 149 double normTerm = sumRC * poly[iTerm]; 150 double bgTerm = sumC * poly[iTerm]; 151 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 152 matrix->data.F64[iIndex][normIndex] = normTerm; 153 matrix->data.F64[normIndex][iIndex] = normTerm; 154 } 155 if ((mode & PM_SUBTRACTION_EQUATION_BG) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 156 matrix->data.F64[iIndex][bgIndex] = bgTerm; 157 matrix->data.F64[bgIndex][iIndex] = bgTerm; 158 } 159 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 160 vector->data.F64[iIndex] = sumIC * poly[iTerm]; 161 if (!(mode & PM_SUBTRACTION_EQUATION_NORM)) { 162 // subtract norm * sumRC * poly[iTerm] 163 psAssert (kernels->solution1, "programming error: define solution first!"); 164 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 165 double norm = fabs(kernels->solution1->data.F64[normIndex]); // Normalisation 166 vector->data.F64[iIndex] -= norm * normTerm; 167 } 168 } 169 } 170 } 171 172 double sumRR = 0.0; // Sum of the reference product 173 double sumIR = 0.0; // Sum of the input-reference product 174 double sum1 = 0.0; // Sum of the background 175 double sumR = 0.0; // Sum of the reference 176 double sumI = 0.0; // Sum of the input 177 double normI1 = 0.0, normI2 = 0.0; // Sum of I_1 and I_2 within the normalisation window 33 178 for (int y = - footprint; y <= footprint; y++) { 34 179 for (int x = - footprint; x <= footprint; x++) { 35 double value = image1->kernel[y][x] * image2->kernel[y][x]; 36 #ifdef USE_VARIANCE 37 value /= variance->kernel[y][x]; 38 #endif 39 sum += value; 40 } 41 } 42 return sum; 43 } 44 45 // Calculate a single element of the least-squares matrix, with the polynomial expansions in one direction 46 static inline bool calculateMatrixElement1(psImage *matrix, // Matrix to calculate 47 int i, int j, // Coordinates of element 48 const psKernel *image1, // First image in multiplication 49 const psKernel *image2, // Second image in multiplication 50 const psKernel *variance, // Variance image 51 const psImage *polyValues, // Spatial polynomial values 52 int numKernels, // Number of kernel basis functions 53 int footprint, // (Half-)Size of stamp 54 int spatialOrder, // Maximum order of spatial variation 55 bool symmetric // Is the matrix symmetric? 56 ) 180 double in = input->kernel[y][x]; 181 double ref = reference->kernel[y][x]; 182 double ir = in * ref; 183 double rr = PS_SQR(ref); 184 double one = 1.0; 185 186 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow)) { 187 normI1 += ref; 188 normI2 += in; 189 } 190 191 if (weight) { 192 float wtVal = weight->kernel[y][x]; 193 rr *= wtVal; 194 ir *= wtVal; 195 in *= wtVal; 196 ref *= wtVal; 197 one *= wtVal; 198 } 199 if (window) { 200 float winVal = window->kernel[y][x]; 201 rr *= winVal; 202 ir *= winVal; 203 in *= winVal; 204 ref *= winVal; 205 one *= winVal; 206 } 207 sumRR += rr; 208 sumIR += ir; 209 sumR += ref; 210 sumI += in; 211 sum1 += one; 212 } 213 } 214 215 *norm = normI2 / normI1; 216 217 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 218 matrix->data.F64[normIndex][normIndex] = sumRR; 219 vector->data.F64[normIndex] = sumIR; 220 // subtract sum over kernels * kernel solution 221 } 222 if (mode & PM_SUBTRACTION_EQUATION_BG) { 223 matrix->data.F64[bgIndex][bgIndex] = sum1; 224 vector->data.F64[bgIndex] = sumI; 225 } 226 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_BG)) { 227 matrix->data.F64[normIndex][bgIndex] = sumR; 228 matrix->data.F64[bgIndex][normIndex] = sumR; 229 } 230 231 // check for any NAN values in the result, skip if found: 232 for (int iy = 0; iy < matrix->numRows; iy++) { 233 for (int ix = 0; ix < matrix->numCols; ix++) { 234 if (!isfinite(matrix->data.F64[iy][ix])) { 235 fprintf (stderr, "WARNING: NAN in matrix\n"); 236 return false; 237 } 238 } 239 } 240 for (int ix = 0; ix < vector->n; ix++) { 241 if (!isfinite(vector->data.F64[ix])) { 242 fprintf (stderr, "WARNING: NAN in vector\n"); 243 return false; 244 } 245 } 246 247 return true; 248 } 249 250 251 // Calculate the least-squares matrix and vector for dual convolution 252 static bool calculateDualMatrixVector(psImage *matrix, // Least-squares matrix, updated 253 psVector *vector, // Least-squares vector, updated 254 double *norm, // Normalisation, updated 255 const psKernel *image1, // Image 1 256 const psKernel *image2, // Image 2 257 const psKernel *weight, // Weight image 258 const psKernel *window, // Window image 259 const psArray *convolutions1, // Convolutions of image 1 for each kernel 260 const psArray *convolutions2, // Convolutions of image 2 for each kernel 261 const pmSubtractionKernels *kernels, // Kernels 262 const psImage *polyValues, // Spatial polynomial values 263 int footprint, // (Half-)Size of stamp 264 int normWindow, // Window (half-)size for normalisation measurement 265 const pmSubtractionEquationCalculationMode mode 266 ) 57 267 { 58 double sum = calculateSumProduct(image1, image2, variance, footprint); // Sum of the image products 59 if (!isfinite(sum)) { 60 return false; 61 } 62 63 // Generate the pseudo-convolutions from the spatial polynomial terms 64 for (int iyOrder = 0, iIndex = i; iyOrder <= spatialOrder; iyOrder++) { 65 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex += numKernels) { 66 double convPoly = sum * polyValues->data.F64[iyOrder][ixOrder]; 67 68 assert(iIndex < matrix->numRows && j < matrix->numCols); 69 70 matrix->data.F64[iIndex][j] = convPoly; 71 if (symmetric) { 72 73 assert(iIndex < matrix->numCols && j < matrix->numRows); 74 75 matrix->data.F64[j][iIndex] = convPoly; 76 } 77 } 78 } 79 return true; 80 } 81 82 // Calculate a single element of the least-squares matrix, with the polynomial expansions in both directions 83 static inline bool calculateMatrixElement2(psImage *matrix, // Matrix to calculate 84 int i, int j, // Coordinates of element 85 const psKernel *image1, // First image in multiplication 86 const psKernel *image2, // Second image in multiplication 87 const psKernel *variance, // Variance image 88 const psImage *polyValues, // Spatial polynomial values 89 int numKernels, // Number of kernel basis functions 90 int footprint, // (Half-)Size of stamp 91 int spatialOrder, // Maximum order of spatial variation 92 bool symmetric // Is the matrix symmetric? 93 ) 94 { 95 double sum = calculateSumProduct(image1, image2, variance, footprint); // Sum of the image products 96 if (!isfinite(sum)) { 97 return false; 98 } 99 100 // Generate the pseudo-convolutions from the spatial polynomial terms 101 for (int iyOrder = 0, iIndex = i; iyOrder <= spatialOrder; iyOrder++) { 102 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex += numKernels) { 268 int numKernels = kernels->num; // Number of kernels 269 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 270 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 271 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 272 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 273 double poly[numPoly]; // Polynomial terms 274 double poly2[numPoly][numPoly]; // Polynomial-polynomial values 275 276 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 277 int numParams = numKernels * numPoly + 1 + numBackground; // Number of regular parameters 278 int numParams2 = numKernels * numPoly; // Number of additional parameters for dual 279 int numDual = numParams + numParams2; // Total number of parameters for dual 280 281 psAssert(matrix && 282 matrix->type.type == PS_TYPE_F64 && 283 matrix->numCols == numDual && 284 matrix->numRows == numDual, 285 "Least-squares matrix is bad."); 286 psAssert(vector && 287 vector->type.type == PS_TYPE_F64 && 288 vector->n == numDual, 289 "Least-squares vector is bad."); 290 291 // Evaluate polynomial-polynomial terms 292 for (int iyOrder = 0, iIndex = 0; iyOrder <= spatialOrder; iyOrder++) { 293 for (int ixOrder = 0; ixOrder <= spatialOrder - iyOrder; ixOrder++, iIndex++) { 103 294 double iPoly = polyValues->data.F64[iyOrder][ixOrder]; // Value of polynomial 104 for (int jyOrder = 0, jIndex = j; jyOrder <= spatialOrder; jyOrder++) { 105 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; jxOrder++, jIndex += numKernels) { 106 double convPoly = sum * iPoly * polyValues->data.F64[jyOrder][jxOrder]; 107 108 assert(iIndex < matrix->numRows && jIndex < matrix->numCols); 109 110 matrix->data.F64[iIndex][jIndex] = convPoly; 111 if (symmetric) { 112 113 assert(iIndex < matrix->numCols && jIndex < matrix->numRows); 114 115 matrix->data.F64[jIndex][iIndex] = convPoly; 116 } 117 } 118 } 119 } 120 } 121 return true; 122 } 123 124 // Calculate the square part of the matrix derived from multiplying convolutions 125 static bool calculateMatrixSquare(psImage *matrix, // Matrix to calculate 126 const psArray *convolutions1, // Convolutions for element 1 127 const psArray *convolutions2, // Convolutions for element 2 128 const psKernel *variance, // Variance image 129 const psImage *polyValues, // Polynomial values 130 int numKernels, // Number of kernel basis functions 131 int spatialOrder, // Order of spatial variation 132 int footprint // Half-size of stamp 133 ) 134 { 135 bool symmetric = (convolutions1 == convolutions2 ? true : false); // Is matrix symmetric? 295 poly[iIndex] = iPoly; 296 for (int jyOrder = 0, jIndex = 0; jyOrder <= spatialOrder; jyOrder++) { 297 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder; jxOrder++, jIndex++) { 298 double jPoly = polyValues->data.F64[jyOrder][jxOrder]; 299 poly2[iIndex][jIndex] = iPoly * jPoly; 300 } 301 } 302 } 303 } 304 305 306 // initialize the matrix and vector for NOP on all coeffs. we only fill in the coeffs we 307 // choose to calculate 308 psImageInit(matrix, 0.0); 309 psVectorInit(vector, 1.0); 310 for (int i = 0; i < matrix->numCols; i++) { 311 matrix->data.F64[i][i] = 1.0; 312 } 136 313 137 314 for (int i = 0; i < numKernels; i++) { 138 psKernel *iConv = convolutions1->data[i]; // Convolution for i-th element 139 140 for (int j = (symmetric ? i : 0); j < numKernels; j++) { 141 psKernel *jConv = convolutions2->data[j]; // Convolution for j-th element 142 143 if (!calculateMatrixElement2(matrix, i, j, iConv, jConv, variance, polyValues, numKernels, 144 footprint, spatialOrder, symmetric)) { 145 psTrace("psModules.imcombine", 2, "Bad sumCC at %d, %d", i, j); 146 return false; 147 } 148 } 149 } 150 151 return true; 152 } 153 154 // Calculate least-squares matrix and vector 155 static bool calculateMatrix(psImage *matrix, // Matrix to calculate 156 const pmSubtractionKernels *kernels, // Kernel components 157 const psArray *convolutions, // Convolutions of source with kernels 158 const psKernel *input, // Input stamp, or NULL 159 const psKernel *variance, // Variance stamp 160 const psImage *polyValues, // Spatial polynomial values 161 int footprint, // (Half-)Size of stamp 162 bool normAndBG // Calculate normalisation and background terms? 163 ) 164 { 165 int numKernels = kernels->num; // Number of kernel components 166 int spatialOrder = kernels->spatialOrder; // Maximum order of spatial variation 167 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial variation terms 168 int bgOrder = kernels->bgOrder; // Maximum order of background fit 169 int numBackground = normAndBG ? PM_SUBTRACTION_POLYTERMS(bgOrder) : 0; // Number of background terms 170 int numTerms = numKernels * numSpatial + (normAndBG ? 1 + numBackground : 0); // Total number of terms 171 assert(matrix); 172 assert(matrix->numCols == matrix->numRows); 173 assert(matrix->numCols == numTerms); 174 assert(convolutions && convolutions->n == numKernels); 175 assert(polyValues); 176 assert(!normAndBG || input); // If we want the normalisation and BG, then we need the input image 177 178 // Square part of the matrix (convolution-convolution products) 179 if (!calculateMatrixSquare(matrix, convolutions, convolutions, variance, polyValues, numKernels, 180 spatialOrder, footprint)) { 181 return false; 182 } 183 184 // XXX To support higher-order background model than simply constant, the below code needs to be updated. 185 if (normAndBG) { 186 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 187 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 188 189 for (int i = 0; i < numKernels; i++) { 190 psKernel *conv = convolutions->data[i]; // Convolution for i-th element 191 192 // Normalisation-convolution terms 193 if (!calculateMatrixElement1(matrix, i, normIndex, conv, input, variance, polyValues, numKernels, 194 footprint, spatialOrder, true)) { 195 psTrace("psModules.imcombine", 2, "Bad sumIC at %d", i); 196 return false; 197 } 198 199 // Background-convolution terms 200 double sumC = 0.0; // Sum of the convolution 315 psKernel *iConv1 = convolutions1->data[i]; // Convolution 1 for index i 316 psKernel *iConv2 = convolutions2->data[i]; // Convolution 2 for index i 317 for (int j = i; j < numKernels; j++) { 318 psKernel *jConv1 = convolutions1->data[j]; // Convolution 1 for index j 319 psKernel *jConv2 = convolutions2->data[j]; // Convolution 2 for index j 320 321 double sumAA = 0.0; // Sum of convolution products between image 1 322 double sumBB = 0.0; // Sum of convolution products between image 2 323 double sumAB = 0.0; // Sum of convolution products across images 1 and 2 201 324 for (int y = - footprint; y <= footprint; y++) { 202 325 for (int x = - footprint; x <= footprint; x++) { 203 double value = conv->kernel[y][x]; 204 #ifdef USE_VARIANCE 205 value /= variance->kernel[y][x]; 206 #endif 207 sumC += value; 208 } 209 } 210 if (!isfinite(sumC)) { 211 psTrace("psModules.imcombine", 2, "Bad sumC at %d", i); 212 return false; 213 } 214 215 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) { 216 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) { 217 double value = sumC * polyValues->data.F64[yOrder][xOrder]; 218 matrix->data.F64[index][bgIndex] = value; 219 matrix->data.F64[bgIndex][index] = value; 220 } 221 } 222 } 223 224 // Background only, normalisation only, and background-normalisation terms 225 double sum1 = 0.0; // Sum of the weighting 226 double sumI = 0.0; // Sum of the input 227 double sumII = 0.0; // Sum of the input squared 326 double aa = iConv1->kernel[y][x] * jConv1->kernel[y][x]; 327 double bb = iConv2->kernel[y][x] * jConv2->kernel[y][x]; 328 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x]; 329 if (weight) { 330 float wtVal = weight->kernel[y][x]; 331 aa *= wtVal; 332 bb *= wtVal; 333 ab *= wtVal; 334 } 335 if (window) { 336 float wtVal = window->kernel[y][x]; 337 aa *= wtVal; 338 bb *= wtVal; 339 ab *= wtVal; 340 } 341 sumAA += aa; 342 sumBB += bb; 343 sumAB += ab; 344 } 345 } 346 347 // Spatial variation of kernel coeffs 348 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 349 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 350 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 351 double aa = sumAA * poly2[iTerm][jTerm]; 352 double bb = sumBB * poly2[iTerm][jTerm]; 353 double ab = sumAB * poly2[iTerm][jTerm]; 354 355 matrix->data.F64[iIndex][jIndex] = aa; 356 matrix->data.F64[jIndex][iIndex] = aa; 357 358 matrix->data.F64[iIndex + numParams][jIndex + numParams] = bb; 359 matrix->data.F64[jIndex + numParams][iIndex + numParams] = bb; 360 361 matrix->data.F64[iIndex][jIndex + numParams] = ab; 362 matrix->data.F64[jIndex + numParams][iIndex] = ab; 363 } 364 } 365 } 366 } 367 for (int j = 0; j < i; j++) { 368 psKernel *jConv2 = convolutions2->data[j]; // Convolution 2 for index j 369 double sumAB = 0.0; // Sum of convolution products for matrix C 370 for (int y = - footprint; y <= footprint; y++) { 371 for (int x = - footprint; x <= footprint; x++) { 372 double ab = iConv1->kernel[y][x] * jConv2->kernel[y][x]; 373 if (weight) { 374 ab *= weight->kernel[y][x]; 375 } 376 if (window) { 377 ab *= window->kernel[y][x]; 378 } 379 sumAB += ab; 380 } 381 } 382 383 // Spatial variation of kernel coeffs 384 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 385 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 386 for (int jTerm = 0, jIndex = j; jTerm < numPoly; jTerm++, jIndex += numKernels) { 387 double ab = sumAB * poly2[iTerm][jTerm]; 388 matrix->data.F64[iIndex][jIndex + numParams] = ab; 389 matrix->data.F64[jIndex + numParams][iIndex] = ab; 390 } 391 } 392 } 393 } 394 395 double sumAI2 = 0.0; // Sum of A.I_2 products (for vector) 396 double sumBI2 = 0.0; // Sum of B.I_2 products (for vector) 397 double sumAI1 = 0.0; // Sum of A.I_1 products (for matrix, normalisation) 398 double sumA = 0.0; // Sum of A (for matrix, background) 399 double sumBI1 = 0.0; // Sum of B.I_1 products (for matrix, normalisation) 400 double sumB = 0.0; // Sum of B products (for matrix, background) 401 double sumI2 = 0.0; // Sum of I_2 (for vector, background) 228 402 for (int y = - footprint; y <= footprint; y++) { 229 403 for (int x = - footprint; x <= footprint; x++) { 230 double invNoise2 = 1.0; 231 #ifdef USE_VARIANCE 232 invNoise2 /= variance->kernel[y][x]; 233 #endif 234 double value = input->kernel[y][x] * invNoise2; 235 sumI += value; 236 sumII += value * input->kernel[y][x]; 237 sum1 += invNoise2; 238 } 239 } 240 if (!isfinite(sumI)) { 241 psTrace("psModules.imcombine", 2, "Bad sumI detected"); 404 double a = iConv1->kernel[y][x]; 405 double b = iConv2->kernel[y][x]; 406 float i1 = image1->kernel[y][x]; 407 float i2 = image2->kernel[y][x]; 408 409 double ai2 = a * i2; 410 double bi2 = b * i2; 411 double ai1 = a * i1; 412 double bi1 = b * i1; 413 414 if (weight) { 415 float wtVal = weight->kernel[y][x]; 416 ai2 *= wtVal; 417 bi2 *= wtVal; 418 ai1 *= wtVal; 419 bi1 *= wtVal; 420 a *= wtVal; 421 b *= wtVal; 422 i2 *= wtVal; 423 } 424 if (window) { 425 float wtVal = window->kernel[y][x]; 426 ai2 *= wtVal; 427 bi2 *= wtVal; 428 ai1 *= wtVal; 429 bi1 *= wtVal; 430 a *= wtVal; 431 b *= wtVal; 432 i2 *= wtVal; 433 } 434 sumAI2 += ai2; 435 sumBI2 += bi2; 436 sumAI1 += ai1; 437 sumA += a; 438 sumBI1 += bi1; 439 sumB += b; 440 sumI2 += i2; 441 } 442 } 443 // Spatial variation 444 for (int iTerm = 0, iIndex = i; iTerm < numPoly; iTerm++, iIndex += numKernels) { 445 double ai2 = sumAI2 * poly[iTerm]; 446 double bi2 = sumBI2 * poly[iTerm]; 447 double ai1 = sumAI1 * poly[iTerm]; 448 double a = sumA * poly[iTerm]; 449 double bi1 = sumBI1 * poly[iTerm]; 450 double b = sumB * poly[iTerm]; 451 452 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 453 matrix->data.F64[iIndex][normIndex] = ai1; 454 matrix->data.F64[normIndex][iIndex] = ai1; 455 matrix->data.F64[iIndex + numParams][normIndex] = bi1; 456 matrix->data.F64[normIndex][iIndex + numParams] = bi1; 457 } 458 if ((mode & PM_SUBTRACTION_EQUATION_BG) && (mode & PM_SUBTRACTION_EQUATION_KERNELS)) { 459 matrix->data.F64[iIndex][bgIndex] = a; 460 matrix->data.F64[bgIndex][iIndex] = a; 461 matrix->data.F64[iIndex + numParams][bgIndex] = b; 462 matrix->data.F64[bgIndex][iIndex + numParams] = b; 463 } 464 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 465 vector->data.F64[iIndex] = ai2; 466 vector->data.F64[iIndex + numParams] = bi2; 467 if (!(mode & PM_SUBTRACTION_EQUATION_NORM)) { 468 // subtract norm * sumRC * poly[iTerm] 469 psAssert (kernels->solution1, "programming error: define solution first!"); 470 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 471 double norm = fabs(kernels->solution1->data.F64[normIndex]); // Normalisation 472 vector->data.F64[iIndex] -= norm * ai1; 473 vector->data.F64[iIndex + numParams] -= norm * bi1; 474 } 475 } 476 } 477 } 478 479 double sumI1 = 0.0; // Sum of I_1 (for matrix, background-normalisation) 480 double sumI1I1 = 0.0; // Sum of I_1^2 (for matrix, normalisation-normalisation) 481 double sum1 = 0.0; // Sum of 1 (for matrix, background-background) 482 double sumI2 = 0.0; // Sum of I_2 (for vector, background) 483 double sumI1I2 = 0.0; // Sum of I_1.I_2 (for vector, normalisation) 484 double normI1 = 0.0, normI2 = 0.0; // Sum of I_1 and I_2 within the normalisation window 485 for (int y = - footprint; y <= footprint; y++) { 486 for (int x = - footprint; x <= footprint; x++) { 487 double i1 = image1->kernel[y][x]; 488 double i2 = image2->kernel[y][x]; 489 490 double i1i1 = i1 * i1; 491 double one = 1.0; 492 double i1i2 = i1 * i2; 493 494 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow)) { 495 normI1 += i1; 496 normI2 += i2; 497 } 498 499 if (weight) { 500 float wtVal = weight->kernel[y][x]; 501 i1 *= wtVal; 502 i1i1 *= wtVal; 503 one *= wtVal; 504 i2 *= wtVal; 505 i1i2 *= wtVal; 506 } 507 if (window) { 508 float wtVal = window->kernel[y][x]; 509 i1 *= wtVal; 510 i1i1 *= wtVal; 511 one *= wtVal; 512 i2 *= wtVal; 513 i1i2 *= wtVal; 514 } 515 sumI1 += i1; 516 sumI1I1 += i1i1; 517 sum1 += one; 518 sumI2 += i2; 519 sumI1I2 += i1i2; 520 } 521 } 522 523 *norm = normI2 / normI1; 524 525 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 526 matrix->data.F64[normIndex][normIndex] = sumI1I1; 527 vector->data.F64[normIndex] = sumI1I2; 528 } 529 if (mode & PM_SUBTRACTION_EQUATION_BG) { 530 matrix->data.F64[bgIndex][bgIndex] = sum1; 531 vector->data.F64[bgIndex] = sumI2; 532 } 533 if ((mode & PM_SUBTRACTION_EQUATION_NORM) && (mode & PM_SUBTRACTION_EQUATION_BG)) { 534 matrix->data.F64[bgIndex][normIndex] = sumI1; 535 matrix->data.F64[normIndex][bgIndex] = sumI1; 536 } 537 538 // check for any NAN values in the result, skip if found: 539 for (int iy = 0; iy < matrix->numRows; iy++) { 540 for (int ix = 0; ix < matrix->numCols; ix++) { 541 if (!isfinite(matrix->data.F64[iy][ix])) { 542 fprintf (stderr, "WARNING: NAN in matrix\n"); 543 return false; 544 } 545 } 546 } 547 for (int ix = 0; ix < vector->n; ix++) { 548 if (!isfinite(vector->data.F64[ix])) { 549 fprintf (stderr, "WARNING: NAN in vector\n"); 242 550 return false; 243 551 } 244 if (!isfinite(sumII)) { 245 psTrace("psModules.imcombine", 2, "Bad sumII detected"); 246 return false; 247 } 248 if (!isfinite(sum1)) { 249 psTrace("psModules.imcombine", 2, "Bad sum1 detected"); 250 return false; 251 } 252 matrix->data.F64[normIndex][normIndex] = sumII; 253 matrix->data.F64[bgIndex][bgIndex] = sum1; 254 matrix->data.F64[normIndex][bgIndex] = sumI; 255 matrix->data.F64[bgIndex][normIndex] = sumI; 256 } 552 } 553 257 554 258 555 return true; 259 556 } 260 557 261 262 // Calculate least-squares matrix and vector 263 static bool calculateVector(psVector *vector, // Vector to calculate, or NULL 264 const pmSubtractionKernels *kernels, // Kernel components 265 const psArray *convolutions, // Convolutions of source with kernels 266 const psKernel *input, // Input stamp, or NULL if !normAndBG 267 const psKernel *target, // Target stamp 268 const psKernel *variance, // Variance stamp 269 const psImage *polyValues, // Spatial polynomial values 270 int footprint, // (Half-)Size of stamp 271 bool normAndBG // Calculate normalisation and background terms? 272 ) 273 { 274 int numKernels = kernels->num; // Number of kernel components 275 int spatialOrder = kernels->spatialOrder; // Maximum order of spatial variation 276 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial variation terms 277 int bgOrder = kernels->bgOrder; // Maximum order of background fit 278 int numBackground = normAndBG ? PM_SUBTRACTION_POLYTERMS(bgOrder) : 0; // Number of background terms 279 int numTerms = numKernels * numSpatial + (normAndBG ? 1 + numBackground : 0); // Total number of terms 280 assert(vector && vector->n == numTerms); 281 assert(convolutions && convolutions->n == numKernels); 282 assert(target); 283 assert(polyValues); 284 assert(!normAndBG || input); // If we want the normalisation and BG, then we need the input image 285 286 // Convolution terms 287 for (int i = 0; i < numKernels; i++) { 288 psKernel *conv = convolutions->data[i]; // Convolution for i-th element 289 double sumTC = 0.0; // Sum of the target and convolution 290 for (int y = - footprint; y <= footprint; y++) { 291 for (int x = - footprint; x <= footprint; x++) { 292 double value = target->kernel[y][x] * conv->kernel[y][x]; 293 #ifdef USE_VARIANCE 294 value /= variance->kernel[y][x]; 295 #endif 296 sumTC += value; 297 } 298 } 299 if (!isfinite(sumTC)) { 300 psTrace("psModules.imcombine", 2, "Bad sumTC at %d", i); 301 return false; 302 } 303 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) { 304 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) { 305 vector->data.F64[index] = sumTC * polyValues->data.F64[yOrder][xOrder]; 306 } 307 } 308 } 309 310 if (normAndBG) { 311 // Background terms 312 double sumT = 0.0; // Sum of the target 313 double sumIT = 0.0; // Sum of the input-target product 314 for (int y = - footprint; y <= footprint; y++) { 315 for (int x = - footprint; x <= footprint; x++) { 316 double value = target->kernel[y][x]; 317 #ifdef USE_VARIANCE 318 value /= variance->kernel[y][x]; 319 #endif 320 sumIT += value * input->kernel[y][x]; 321 sumT += value; 322 } 323 } 324 if (!isfinite(sumT)) { 325 psTrace("psModules.imcombine", 2, "Bad sumI detected"); 326 return false; 327 } 328 if (!isfinite(sumIT)) { 329 psTrace("psModules.imcombine", 2, "Bad sumIT detected"); 330 return false; 331 } 332 333 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation term 334 vector->data.F64[normIndex] = sumIT; 335 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background term 336 vector->data.F64[bgIndex] = sumT; 337 } 338 339 return true; 340 } 341 342 343 344 // Calculate the cross-matrix, composed of convolutions of each image 345 // Note that the cross-matrix is NOT square 346 static bool calculateMatrixCross(psImage *matrix, // Matrix to calculate 347 const pmSubtractionKernels *kernels, // Kernel components 348 const psArray *convolutions1, // Convolutions of image 1 349 const psArray *convolutions2, // Convolutions of image 2 350 const psKernel *image1, // Image 1 stamp 351 const psKernel *variance, // Variance stamp 352 const psImage *polyValues, // Spatial polynomial values 353 int footprint // (Half-)Size of stamp 354 ) 355 { 356 assert(matrix); 357 int numKernels = kernels->num; // Number of kernel components 358 int spatialOrder = kernels->spatialOrder; // Maximum order of spatial variation 359 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial polynomial terms 360 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 361 int numCols = numKernels * numSpatial + 1 + numBackground; // Number of columns 362 int numRows = numKernels * numSpatial; // Number of rows 363 assert(matrix->numCols == numCols && matrix->numRows == numRows); 364 assert(convolutions1 && convolutions1->n == numKernels); 365 assert(convolutions2 && convolutions2->n == numKernels); 366 367 int normIndex, bgIndex; // Indices in matrix for normalisation and background terms 368 PM_SUBTRACTION_INDICES(normIndex, bgIndex, kernels); 369 370 if (!calculateMatrixSquare(matrix, convolutions1, convolutions2, variance, polyValues, numKernels, 371 spatialOrder, footprint)) { 372 return false; 373 } 374 375 for (int i = 0; i < numKernels; i++) { 376 // Normalisation 377 psKernel *conv = convolutions2->data[i]; // Convolution 378 if (!calculateMatrixElement1(matrix, i, normIndex, conv, image1, variance, polyValues, numKernels, 379 footprint, spatialOrder, false)) { 380 psTrace("psModules.imcombine", 2, "Bad sumIC at %d", i); 381 return false; 382 } 383 384 // Background 385 double sumC = 0.0; // Sum of the weighting 386 for (int y = - footprint; y <= footprint; y++) { 387 for (int x = - footprint; x <= footprint; x++) { 388 double value = conv->kernel[y][x]; 389 #ifdef USE_VARIANCE 390 value /= variance->kernel[y][x]; 391 #endif 392 sumC += value; 393 } 394 } 395 if (!isfinite(sumC)) { 396 psTrace("psModules.imcombine", 2, "Bad sumC detected at %d", i); 397 return false; 398 } 399 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) { 400 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) { 401 matrix->data.F64[index][bgIndex] = sumC * polyValues->data.F64[yOrder][xOrder]; 402 } 403 } 404 } 405 406 return true; 407 } 408 409 558 #if 1 410 559 // Add in penalty term to least-squares vector 411 static bool calculatePenalty(psVector *vector, // Vector to which to add in penalty term 412 const pmSubtractionKernels *kernels // Kernel parameters 560 bool calculatePenalty(psImage *matrix, // Matrix to which to add in penalty term 561 psVector *vector, // Vector to which to add in penalty term 562 const pmSubtractionKernels *kernels, // Kernel parameters 563 float norm // Normalisation 413 564 ) 414 565 { … … 420 571 int spatialOrder = kernels->spatialOrder; // Order of spatial variations 421 572 int numKernels = kernels->num; // Number of kernel components 573 int numSpatial = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of spatial variations 574 int numParams = numKernels * numSpatial; // Number of kernel parameters 575 576 // order is : 577 // [p_0,x_0,y_0 p_1,x_0,y_0, p_2,x_0,y_0] 578 // [p_0,x_1,y_0 p_1,x_1,y_0, p_2,x_1,y_0] 579 // [p_0,x_0,y_1 p_1,x_0,y_1, p_2,x_0,y_1] 580 // [norm] 581 // [bg] 582 // [q_0,x_0,y_0 q_1,x_0,y_0, q_2,x_0,y_0] 583 // [q_0,x_1,y_0 q_1,x_1,y_0, q_2,x_1,y_0] 584 // [q_0,x_0,y_1 q_1,x_0,y_1, q_2,x_0,y_1] 585 422 586 for (int i = 0; i < numKernels; i++) { 423 587 for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) { 424 588 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) { 425 vector->data.F64[index] -= penalties->data.F32[i]; 589 // Contribution to chi^2: a_i^2 P_i 590 psAssert(isfinite(penalties->data.F32[i]), "Invalid penalty"); 591 matrix->data.F64[index][index] += norm * penalties->data.F32[i]; 592 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 593 matrix->data.F64[index + numParams + 2][index + numParams + 2] += norm * penalties->data.F32[i]; 594 // matrix[i][i] is ~ (k_i * I_1)(k_i * I_1) 595 // penalties scale with second moments 596 // 597 } 426 598 } 427 599 } … … 430 602 return true; 431 603 } 604 # endif 432 605 433 606 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 439 612 // Calculate the value of a polynomial, specified by coefficients and polynomial values 440 613 double p_pmSubtractionCalculatePolynomial(const psVector *coeff, // Coefficients 441 const psImage *polyValues, // Polynomial values442 int order, // Order of polynomials443 int index, // Index at which to begin444 int step // Step between subsequent indices445 )614 const psImage *polyValues, // Polynomial values 615 int order, // Order of polynomials 616 int index, // Index at which to begin 617 int step // Step between subsequent indices 618 ) 446 619 { 447 620 double sum = 0.0; // Value of the polynomial sum … … 458 631 459 632 double p_pmSubtractionSolutionCoeff(const pmSubtractionKernels *kernels, const psImage *polyValues, 460 int index, bool wantDual)633 int index, bool wantDual) 461 634 { 462 635 #if 0 … … 511 684 const pmSubtractionKernels *kernels = job->args->data[1]; // Kernels 512 685 int index = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index 513 514 return pmSubtractionCalculateEquationStamp(stamps, kernels, index); 686 pmSubtractionEquationCalculationMode mode = PS_SCALAR_VALUE(job->args->data[3], S32); // calculation model 687 688 return pmSubtractionCalculateEquationStamp(stamps, kernels, index, mode); 515 689 } 516 690 517 691 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels, 518 int index )692 int index, const pmSubtractionEquationCalculationMode mode) 519 693 { 520 694 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 529 703 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 530 704 705 // numKernels is the number of unique kernel images (one for each Gaussian modified by a specific polynomial). 706 // = \sum_i^N_Gaussians [(order + 1) * (order + 2) / 2], eg for 1 Gauss and 1st order, numKernels = 3 707 531 708 // Total number of parameters to solve for: coefficient of each kernel basis function, multipled by the 532 709 // number of coefficients for the spatial polynomial, normalisation and a constant background offset. 533 710 int numParams = numKernels * numSpatial + 1 + numBackground; 711 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 712 // An additional image is convolved 713 numParams += numKernels * numSpatial; 714 } 534 715 535 716 pmSubtractionStamp *stamp = stamps->stamps->data[index]; // Stamp of interest 536 717 psAssert(stamp->status == PM_SUBTRACTION_STAMP_CALCULATE, "We only operate on stamps with this state."); 537 718 538 // Generate convolutions 719 // Generate convolutions: these are generated once and saved 539 720 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint)) { 540 psError( PS_ERR_UNKNOWN, false, "Unable to convolve stamp %d.", index);721 psError(psErrorCodeLast(), false, "Unable to convolve stamp %d.", index); 541 722 return NULL; 542 723 } … … 566 747 #endif 567 748 749 // XXX visualize the set of convolved stamps 750 568 751 psImage *polyValues = p_pmSubtractionPolynomial(NULL, spatialOrder, 569 752 stamp->xNorm, stamp->yNorm); // Polynomial terms 570 753 571 bool new = stamp->vector 1? false : true; // Is this a new run?754 bool new = stamp->vector ? false : true; // Is this a new run? 572 755 if (new) { 573 stamp->matrix 1= psImageAlloc(numParams, numParams, PS_TYPE_F64);574 stamp->vector 1= psVectorAlloc(numParams, PS_TYPE_F64);756 stamp->matrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); 757 stamp->vector = psVectorAlloc(numParams, PS_TYPE_F64); 575 758 } 576 759 #ifdef TESTING 577 psImageInit(stamp->matrix 1, NAN);578 psVectorInit(stamp->vector 1, NAN);760 psImageInit(stamp->matrix, NAN); 761 psVectorInit(stamp->vector, NAN); 579 762 #endif 580 763 581 764 bool status; // Status of least-squares matrix/vector calculation 765 766 psKernel *weight = NULL; 767 psKernel *window = NULL; 768 769 #ifdef USE_WEIGHT 770 weight = stamp->weight; 771 #endif 772 #ifdef USE_WINDOW 773 window = stamps->window; 774 #endif 775 582 776 switch (kernels->mode) { 583 777 case PM_SUBTRACTION_MODE_1: 584 status = calculateMatrix(stamp->matrix1, kernels, stamp->convolutions1, stamp->image1, 585 stamp->variance, polyValues, footprint, true); 586 status &= calculateVector(stamp->vector1, kernels, stamp->convolutions1, stamp->image1, 587 stamp->image2, stamp->variance, polyValues, footprint, true); 778 status = calculateMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, stamp->image2, stamp->image1, 779 weight, window, stamp->convolutions1, kernels, 780 polyValues, footprint, stamps->normWindow, mode); 588 781 break; 589 782 case PM_SUBTRACTION_MODE_2: 590 status = calculateMatrix(stamp->matrix1, kernels, stamp->convolutions2, stamp->image2, 591 stamp->variance, polyValues, footprint, true); 592 status &= calculateVector(stamp->vector1, kernels, stamp->convolutions2, stamp->image2, 593 stamp->image1, stamp->variance, polyValues, footprint, true); 783 status = calculateMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, stamp->image1, stamp->image2, 784 weight, window, stamp->convolutions2, kernels, 785 polyValues, footprint, stamps->normWindow, mode); 594 786 break; 595 787 case PM_SUBTRACTION_MODE_DUAL: 596 if (new) { 597 stamp->matrix2 = psImageAlloc(numKernels * numSpatial, numKernels * numSpatial, PS_TYPE_F64); 598 stamp->matrixX = psImageAlloc(numParams, numKernels * numSpatial, PS_TYPE_F64); 599 stamp->vector2 = psVectorAlloc(numKernels * numSpatial, PS_TYPE_F64); 600 } 601 #ifdef TESTING 602 psImageInit(stamp->matrix2, NAN); 603 psImageInit(stamp->matrixX, NAN); 604 psVectorInit(stamp->vector2, NAN); 605 #endif 606 status = calculateMatrix(stamp->matrix1, kernels, stamp->convolutions1, stamp->image1, 607 stamp->variance, polyValues, footprint, true); 608 status &= calculateMatrix(stamp->matrix2, kernels, stamp->convolutions2, NULL, 609 stamp->variance, polyValues, footprint, false); 610 status &= calculateMatrixCross(stamp->matrixX, kernels, stamp->convolutions1, 611 stamp->convolutions2, stamp->image1, stamp->variance, polyValues, 612 footprint); 613 status &= calculateVector(stamp->vector1, kernels, stamp->convolutions1, stamp->image1, 614 stamp->image2, stamp->variance, polyValues, footprint, true); 615 status &= calculateVector(stamp->vector2, kernels, stamp->convolutions2, NULL, 616 stamp->image2, stamp->variance, polyValues, footprint, false); 788 status = calculateDualMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, 789 stamp->image1, stamp->image2, 790 weight, window, stamp->convolutions1, stamp->convolutions2, 791 kernels, polyValues, footprint, stamps->normWindow, mode); 617 792 break; 618 793 default: … … 623 798 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 624 799 psWarning("Rejecting stamp %d (%d,%d) because of bad equation", 625 index, (int)(stamp->x + 0.5), (int)(stamp->y +0.5));800 index, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 626 801 } else { 627 802 stamp->status = PM_SUBTRACTION_STAMP_USED; … … 629 804 630 805 #ifdef TESTING 631 if (psTraceGetLevel("psModules.imcombine.equation") >= 10){806 { 632 807 psString matrixName = NULL; 633 psStringAppend(&matrixName, "matrix 1_%d.fits", index);808 psStringAppend(&matrixName, "matrix_%d.fits", index); 634 809 psFits *matrixFile = psFitsOpen(matrixName, "w"); 635 810 psFree(matrixName); 636 psFitsWriteImage(matrixFile, NULL, stamp->matrix 1, 0, NULL);811 psFitsWriteImage(matrixFile, NULL, stamp->matrix, 0, NULL); 637 812 psFitsClose(matrixFile); 638 813 639 814 matrixName = NULL; 640 psStringAppend(&matrixName, "vector 1_%d.fits", index);641 psImage *dummy = psImageAlloc(stamp->vector 1->n, 1, PS_TYPE_F64);642 memcpy(dummy->data.F64[0], stamp->vector 1->data.F64,643 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector 1->n);815 psStringAppend(&matrixName, "vector_%d.fits", index); 816 psImage *dummy = psImageAlloc(stamp->vector->n, 1, PS_TYPE_F64); 817 memcpy(dummy->data.F64[0], stamp->vector->data.F64, 818 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector->n); 644 819 matrixFile = psFitsOpen(matrixName, "w"); 645 820 psFree(matrixName); … … 647 822 psFree(dummy); 648 823 psFitsClose(matrixFile); 649 650 if (stamp->vector2) {651 matrixName = NULL;652 psStringAppend(&matrixName, "vector2_%d.fits", index);653 dummy = psImageAlloc(stamp->vector2->n, 1, PS_TYPE_F64);654 memcpy(dummy->data.F64[0], stamp->vector2->data.F64,655 PSELEMTYPE_SIZEOF(PS_TYPE_F64) * stamp->vector2->n);656 matrixFile = psFitsOpen(matrixName, "w");657 psFree(matrixName);658 psFitsWriteImage(matrixFile, NULL, dummy, 0, NULL);659 psFree(dummy);660 psFitsClose(matrixFile);661 }662 663 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {664 matrixName = NULL;665 psStringAppend(&matrixName, "matrix2_%d.fits", index);666 matrixFile = psFitsOpen(matrixName, "w");667 psFree(matrixName);668 psFitsWriteImage(matrixFile, NULL, stamp->matrix2, 0, NULL);669 psFitsClose(matrixFile);670 671 matrixName = NULL;672 psStringAppend(&matrixName, "matrixX_%d.fits", index);673 matrixFile = psFitsOpen(matrixName, "w");674 psFree(matrixName);675 psFitsWriteImage(matrixFile, NULL, stamp->matrixX, 0, NULL);676 psFitsClose(matrixFile);677 }678 824 } 679 825 #endif … … 684 830 } 685 831 686 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels) 832 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels, 833 const pmSubtractionEquationCalculationMode mode) 687 834 { 688 835 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 699 846 } 700 847 848 if ((stamp->x <= 0.0) && (stamp->y <= 0.0)) { 849 psAbort ("bad stamp"); 850 } 851 if (!isfinite(stamp->x) && !isfinite(stamp->y)) { 852 psAbort ("bad stamp"); 853 } 854 701 855 if (pmSubtractionThreaded()) { 702 856 psThreadJob *job = psThreadJobAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION"); … … 704 858 psArrayAdd(job->args, 1, (pmSubtractionKernels*)kernels); // Casting away const to put on array 705 859 PS_ARRAY_ADD_SCALAR(job->args, i, PS_TYPE_S32); 860 PS_ARRAY_ADD_SCALAR(job->args, mode, PS_TYPE_S32); 706 861 if (!psThreadJobAddPending(job)) { 707 862 psFree(job); … … 710 865 psFree(job); 711 866 } else { 712 pmSubtractionCalculateEquationStamp(stamps, kernels, i );867 pmSubtractionCalculateEquationStamp(stamps, kernels, i, mode); 713 868 } 714 869 } 715 870 716 871 if (!psThreadPoolWait(true)) { 717 psError( PS_ERR_UNKNOWN, false, "Error waiting for threads.");872 psError(psErrorCodeLast(), false, "Error waiting for threads."); 718 873 return false; 719 874 } 720 875 721 876 pmSubtractionVisualPlotLeastSquares(stamps); 877 pmSubtractionVisualShowKernels((pmSubtractionKernels *)kernels); 878 pmSubtractionVisualShowBasis(stamps); 722 879 723 880 psLogMsg("psModules.imcombine", PS_LOG_INFO, "Calculate equation: %f sec", … … 728 885 } 729 886 730 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) 887 // private functions used on pmSubtractionSolveEquation 888 bool psVectorWriteFile (char *filename, const psVector *vector); 889 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header); 890 891 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U); 892 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt); 893 894 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask); 895 896 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B); 897 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB); 898 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB); 899 900 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x); 901 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y); 902 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 903 904 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w); 905 906 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps); 907 908 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, 909 const pmSubtractionStampList *stamps, 910 const pmSubtractionEquationCalculationMode mode) 731 911 { 732 912 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false); … … 734 914 735 915 // Check inputs 736 int numParams = -1; // Number of parameters 737 int numParams2 = 0; // Number of parameters for part solution (DUAL mode) 916 int numKernels = kernels->num; // Number of kernel basis functions 917 int numSpatial = PM_SUBTRACTION_POLYTERMS(kernels->spatialOrder); // Number of spatial variations 918 int numBackground = PM_SUBTRACTION_POLYTERMS(kernels->bgOrder); // Number of background terms 919 int numParams = numKernels * numSpatial + 1 + numBackground; // Number of parameters being solved for 920 int numSolution1 = numParams, numSolution2 = 0; // Number of parameters for each solution 921 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 922 // An additional image is convolved 923 numSolution2 = numKernels * numSpatial; 924 numParams += numSolution2; 925 } 926 738 927 for (int i = 0; i < stamps->num; i++) { 739 928 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest … … 743 932 } 744 933 745 PS_ASSERT_VECTOR_NON_NULL(stamp->vector1, false); 746 if (numParams == -1) { 747 numParams = stamp->vector1->n; 748 } 749 PS_ASSERT_VECTOR_SIZE(stamp->vector1, (long)numParams, false); 750 PS_ASSERT_VECTOR_TYPE(stamp->vector1, PS_TYPE_F64, false); 751 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix1, false); 752 PS_ASSERT_IMAGE_SIZE(stamp->matrix1, numParams, numParams, false); 753 PS_ASSERT_IMAGE_TYPE(stamp->matrix1, PS_TYPE_F64, false); 754 755 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { 756 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix2, false); 757 PS_ASSERT_IMAGE_NON_NULL(stamp->matrixX, false); 758 if (numParams2 == 0) { 759 numParams2 = stamp->matrix2->numCols; 760 } 761 PS_ASSERT_IMAGE_SIZE(stamp->matrix2, numParams2, numParams2, false); 762 PS_ASSERT_IMAGE_SIZE(stamp->matrixX, numParams, numParams2, false); 763 PS_ASSERT_IMAGE_TYPE(stamp->matrix2, PS_TYPE_F64, false); 764 PS_ASSERT_IMAGE_TYPE(stamp->matrixX, PS_TYPE_F64, false); 765 PS_ASSERT_VECTOR_NON_NULL(stamp->vector2, false); 766 PS_ASSERT_VECTOR_SIZE(stamp->vector2, (long)numParams2, false); 767 PS_ASSERT_VECTOR_TYPE(stamp->vector2, PS_TYPE_F64, false); 768 } 769 } 770 if (numParams == -1) { 771 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "No suitable stamps found."); 772 return NULL; 934 PS_ASSERT_VECTOR_NON_NULL(stamp->vector, false); 935 PS_ASSERT_VECTOR_SIZE(stamp->vector, (long)numParams, false); 936 PS_ASSERT_VECTOR_TYPE(stamp->vector, PS_TYPE_F64, false); 937 PS_ASSERT_IMAGE_NON_NULL(stamp->matrix, false); 938 PS_ASSERT_IMAGE_SIZE(stamp->matrix, numParams, numParams, false); 939 PS_ASSERT_IMAGE_TYPE(stamp->matrix, PS_TYPE_F64, false); 773 940 } 774 941 … … 786 953 psVectorInit(sumVector, 0.0); 787 954 psImageInit(sumMatrix, 0.0); 955 956 psVector *norms = psVectorAllocEmpty(stamps->num, PS_TYPE_F64); // Normalisations 957 788 958 int numStamps = 0; // Number of good stamps 789 959 for (int i = 0; i < stamps->num; i++) { 790 960 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 791 792 961 if (stamp->status == PM_SUBTRACTION_STAMP_USED) { 793 794 #ifdef TESTING 795 // XXX double-check for NAN in data: 796 for (int iy = 0; iy < stamp->matrix1->numRows; iy++) { 797 for (int ix = 0; ix < stamp->matrix1->numCols; ix++) { 798 if (!isfinite(stamp->matrix1->data.F64[iy][ix])) { 799 fprintf (stderr, "WARNING: NAN in matrix1\n"); 800 } 801 } 802 } 803 for (int ix = 0; ix < stamp->vector1->n; ix++) { 804 if (!isfinite(stamp->vector1->data.F64[ix])) { 805 fprintf (stderr, "WARNING: NAN in vector1\n"); 806 } 807 } 808 #endif 809 810 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix1); 811 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector1); 962 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix); 963 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector); 964 psVectorAppend(norms, stamp->norm); 812 965 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 813 966 numStamps++; … … 817 970 } 818 971 972 #if 0 973 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 974 calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[bgIndex][bgIndex]); 975 #endif 976 977 psVector *solution = NULL; // Solution to equation! 978 solution = psVectorAlloc(numParams, PS_TYPE_F64); 979 psVectorInit(solution, 0); 980 981 #if 0 982 // Regular, straight-forward solution 983 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 984 #else 985 { 986 // Solve normalisation and background separately 987 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 988 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 989 990 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for norm 991 if (!psVectorStats(stats, norms, NULL, NULL, 0)) { 992 psError(PM_ERR_DATA, false, "Unable to determine median normalisation"); 993 psFree(stats); 994 psFree(sumMatrix); 995 psFree(sumVector); 996 psFree(norms); 997 return false; 998 } 999 1000 double normValue = stats->robustMedian; 1001 // double bgValue = 0.0; 1002 1003 psFree(stats); 1004 819 1005 #ifdef TESTING 820 for (int ix = 0; ix < sumVector->n; ix++) { 821 if (!isfinite(sumVector->data.F64[ix])) { 822 fprintf (stderr, "WARNING: NAN in vector1\n"); 823 } 824 } 825 #endif 826 827 calculatePenalty(sumVector, kernels); 828 829 #ifdef TESTING 830 for (int ix = 0; ix < sumVector->n; ix++) { 831 if (!isfinite(sumVector->data.F64[ix])) { 832 fprintf (stderr, "WARNING: NAN in vector1\n"); 833 } 834 } 835 { 836 psImage *inverse = psMatrixInvert(NULL, sumMatrix, NULL); 837 psFits *fits = psFitsOpen("matrixInv.fits", "w"); 838 psFitsWriteImage(fits, NULL, inverse, 0, NULL); 839 psFitsClose(fits); 840 psFree(inverse); 841 } 842 { 843 psImage *X = psMatrixInvert(NULL, sumMatrix, NULL); 844 psImage *Xt = psMatrixTranspose(NULL, X); 845 psImage *XtX = psMatrixMultiply(NULL, Xt, X); 846 psFits *fits = psFitsOpen("matrixErr.fits", "w"); 847 psFitsWriteImage(fits, NULL, XtX, 0, NULL); 848 psFitsClose(fits); 849 psFree(X); 850 psFree(Xt); 851 psFree(XtX); 852 } 853 #endif 854 855 psVector *permutation = NULL; // Permutation vector, required for LU decomposition 856 psImage *luMatrix = psMatrixLUDecomposition(NULL, &permutation, sumMatrix); 1006 fprintf(stderr, "Norm: %lf\n", normValue); 1007 #endif 1008 // Solve kernel components 1009 for (int i = 0; i < numSolution1; i++) { 1010 sumVector->data.F64[i] -= normValue * sumMatrix->data.F64[normIndex][i]; 1011 1012 sumMatrix->data.F64[i][normIndex] = 0.0; 1013 sumMatrix->data.F64[normIndex][i] = 0.0; 1014 } 1015 sumVector->data.F64[bgIndex] -= normValue * sumMatrix->data.F64[normIndex][bgIndex]; 1016 sumMatrix->data.F64[bgIndex][normIndex] = 0.0; 1017 sumMatrix->data.F64[normIndex][bgIndex] = 0.0; 1018 1019 sumMatrix->data.F64[normIndex][normIndex] = 1.0; 1020 sumVector->data.F64[normIndex] = 0.0; 1021 1022 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1023 1024 solution->data.F64[normIndex] = normValue; 1025 } 1026 # endif 1027 1028 if (!kernels->solution1) { 1029 kernels->solution1 = psVectorAlloc(sumVector->n, PS_TYPE_F64); 1030 psVectorInit(kernels->solution1, 0.0); 1031 } 1032 1033 // only update the solutions that we chose to calculate: 1034 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 1035 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1036 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 1037 } 1038 if (mode & PM_SUBTRACTION_EQUATION_BG) { 1039 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1040 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 1041 } 1042 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 1043 int numKernels = kernels->num; 1044 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 1045 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 1046 for (int i = 0; i < numKernels * numPoly; i++) { 1047 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1048 } 1049 } 1050 1051 psFree(norms); 1052 psFree(solution); 1053 psFree(sumVector); 857 1054 psFree(sumMatrix); 858 if (!luMatrix) {859 psError(PS_ERR_UNKNOWN, true, "LU Decomposition of least-squares matrix failed.\n");860 psFree(sumVector);861 psFree(luMatrix);862 psFree(permutation);863 return NULL;864 }865 kernels->solution1 = psMatrixLUSolution(kernels->solution1, luMatrix, sumVector, permutation);866 1055 867 1056 #ifdef TESTING … … 869 1058 for (int ix = 0; ix < kernels->solution1->n; ix++) { 870 1059 if (!isfinite(kernels->solution1->data.F64[ix])) { 871 fprintf (stderr, "WARNING: NAN in vector1\n"); 872 } 873 } 874 #endif 875 876 psFree(sumVector); 877 psFree(luMatrix); 878 psFree(permutation); 879 if (!kernels->solution1) { 880 psError(PS_ERR_UNKNOWN, true, "Failed to solve the least-squares system.\n"); 881 return NULL; 882 } 1060 fprintf (stderr, "WARNING: NAN in vector\n"); 1061 } 1062 } 1063 #endif 1064 883 1065 } else { 884 1066 // Dual convolution solution 885 1067 886 1068 // Accumulation of stamp matrices/vectors 887 psImage *sumMatrix1 = psImageAlloc(numParams, numParams, PS_TYPE_F64); 888 psImage *sumMatrix2 = psImageAlloc(numParams2, numParams2, PS_TYPE_F64); 889 psImage *sumMatrixX = psImageAlloc(numParams, numParams2, PS_TYPE_F64); 890 psVector *sumVector1 = psVectorAlloc(numParams, PS_TYPE_F64); 891 psVector *sumVector2 = psVectorAlloc(numParams, PS_TYPE_F64); 892 psImageInit(sumMatrix1, 0.0); 893 psImageInit(sumMatrix2, 0.0); 894 psImageInit(sumMatrixX, 0.0); 895 psVectorInit(sumVector1, 0.0); 896 psVectorInit(sumVector2, 0.0); 1069 psImage *sumMatrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); 1070 psVector *sumVector = psVectorAlloc(numParams, PS_TYPE_F64); 1071 psImageInit(sumMatrix, 0.0); 1072 psVectorInit(sumVector, 0.0); 1073 1074 psVector *norms = psVectorAllocEmpty(stamps->num, PS_TYPE_F64); // Normalisations 897 1075 898 1076 int numStamps = 0; // Number of good stamps … … 900 1078 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 901 1079 if (stamp->status == PM_SUBTRACTION_STAMP_USED) { 902 (void)psBinaryOp(sumMatrix 1, sumMatrix1, "+", stamp->matrix1);903 (void)psBinaryOp(sum Matrix2, sumMatrix2, "+", stamp->matrix2);904 (void)psBinaryOp(sumMatrixX, sumMatrixX, "+", stamp->matrixX); 905 (void)psBinaryOp(sumVector1, sumVector1, "+", stamp->vector1);906 (void)psBinaryOp(sumVector2, sumVector2, "+", stamp->vector2); 1080 (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix); 1081 (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector); 1082 1083 psVectorAppend(norms, stamp->norm); 1084 907 1085 pmSubtractionStampPrint(ds9, stamp->x, stamp->y, stamps->footprint, "green"); 908 1086 numStamps++; 909 1087 } 910 1088 } 911 calculatePenalty(sumVector1, kernels); 912 calculatePenalty(sumVector2, kernels); 913 914 // Pure matrix operations 915 916 // A * a = Ct * b + d 917 // C * a = B * b + e 918 // 919 // a = (Ct * Bi * C - A)i (Ct * Bi * e - d) 920 // b = Bi * (C * a - e) 921 psVector *a = psVectorRecycle(kernels->solution1, numParams, PS_TYPE_F64); 922 psVector *b = psVectorRecycle(kernels->solution2, numParams2, PS_TYPE_F64); 1089 923 1090 #ifdef TESTING 924 psVectorInit(a, NAN); 925 psVectorInit(b, NAN); 926 #endif 927 psImage *A = sumMatrix1; 928 psImage *B = sumMatrix2; 929 psImage *C = sumMatrixX; 930 psVector *d = sumVector1; 931 psVector *e = sumVector2; 932 933 assert(a->n == numParams); 934 assert(b->n == numParams2); 935 assert(A->numRows == numParams && A->numCols == numParams); 936 assert(B->numRows == numParams2 && B->numCols == numParams2); 937 assert(C->numRows == numParams2 && C->numCols == numParams); 938 assert(d->n == numParams); 939 assert(e->n == numParams2); 940 941 psImage *Bi = psMatrixInvert(NULL, B, NULL); 942 assert(Bi->numRows == numParams2 && Bi->numCols == numParams2); 943 psImage *Ct = psMatrixTranspose(NULL, C); 944 assert(Ct->numRows == numParams && Ct->numCols == numParams2); 945 946 psImage *BiC = psMatrixMultiply(NULL, Bi, C); 947 assert(BiC->numRows == numParams2 && BiC->numCols == numParams); 948 psImage *CtBi = psMatrixMultiply(NULL, Ct, Bi); 949 assert(CtBi->numRows == numParams && CtBi->numCols == numParams2); 950 951 psImage *CtBiC = psMatrixMultiply(NULL, Ct, BiC); 952 assert(CtBiC->numRows == numParams && CtBiC->numCols == numParams); 953 954 psImage *F = (psImage*)psBinaryOp(NULL, CtBiC, "-", A); 955 assert(F->numRows == numParams && F->numCols == numParams); 956 float det = 0.0; 957 psImage *Fi = psMatrixInvert(NULL, F, &det); 958 assert(Fi->numRows == numParams && Fi->numCols == numParams); 959 psTrace("psModules.imcombine", 4, "Determinant of F: %f\n", det); 960 961 psVector *g = psVectorAlloc(numParams, PS_TYPE_F64); 1091 psFitsWriteImageSimple ("sumMatrix.fits", sumMatrix, NULL); 1092 psVectorWriteFile("sumVector.dat", sumVector); 1093 #endif 1094 1095 #if 1 1096 // int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 1097 // calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[bgIndex][bgIndex]); 1098 1099 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1100 calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[normIndex][normIndex] / 1000.0); 1101 #endif 1102 1103 psVector *solution = NULL; // Solution to equation! 1104 solution = psVectorAlloc(numParams, PS_TYPE_F64); 1105 psVectorInit(solution, 0); 1106 1107 #if 0 1108 // Regular, straight-forward solution 1109 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1110 #else 1111 { 1112 // Solve normalisation and background separately 1113 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1114 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index for background 1115 1116 #if 0 1117 psImage *normMatrix = psImageAlloc(2, 2, PS_TYPE_F64); 1118 psVector *normVector = psVectorAlloc(2, PS_TYPE_F64); 1119 1120 normMatrix->data.F64[0][0] = sumMatrix->data.F64[normIndex][normIndex]; 1121 normMatrix->data.F64[1][1] = sumMatrix->data.F64[bgIndex][bgIndex]; 1122 normMatrix->data.F64[0][1] = normMatrix->data.F64[1][0] = sumMatrix->data.F64[normIndex][bgIndex]; 1123 1124 normVector->data.F64[0] = sumVector->data.F64[normIndex]; 1125 normVector->data.F64[1] = sumVector->data.F64[bgIndex]; 1126 1127 psVector *normSolution = psMatrixSolveSVD(NULL, normMatrix, normVector, NAN); 1128 1129 double normValue = normSolution->data.F64[0]; 1130 double bgValue = normSolution->data.F64[1]; 1131 1132 psFree(normMatrix); 1133 psFree(normVector); 1134 psFree(normSolution); 1135 #endif 1136 1137 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for norm 1138 if (!psVectorStats(stats, norms, NULL, NULL, 0)) { 1139 psError(PM_ERR_DATA, false, "Unable to determine median normalisation"); 1140 psFree(stats); 1141 psFree(sumMatrix); 1142 psFree(sumVector); 1143 psFree(norms); 1144 return false; 1145 } 1146 1147 double normValue = stats->robustMedian; 1148 1149 psFree(stats); 1150 962 1151 #ifdef TESTING 963 psVectorInit(g, NAN); 964 #endif 965 assert(CtBi->numRows == numParams && CtBi->numCols == numParams2); 966 assert(e->n == numParams2); 967 assert(d->n == numParams); 968 for (int i = 0; i < numParams; i++) { 969 double value = 0.0; 970 for (int j = 0; j < numParams2; j++) { 971 value += CtBi->data.F64[i][j] * e->data.F64[j]; 972 } 973 g->data.F64[i] = value - d->data.F64[i]; 974 } 975 976 assert(Fi->numRows == numParams && Fi->numCols == numParams); 977 assert(g->n == numParams); 978 for (int i = 0; i < numParams; i++) { 979 double value = 0.0; 980 for (int j = 0; j < numParams; j++) { 981 value += Fi->data.F64[i][j] * g->data.F64[j]; 982 } 983 a->data.F64[i] = value; 984 } 985 986 psVector *h = psVectorAlloc(numParams2, PS_TYPE_F64); 1152 fprintf(stderr, "Norm: %lf\n", normValue); 1153 #endif 1154 1155 // Solve kernel components 1156 for (int i = 0; i < numSolution2; i++) { 1157 sumVector->data.F64[i] -= normValue * sumMatrix->data.F64[normIndex][i]; 1158 sumVector->data.F64[i + numSolution1] -= normValue * sumMatrix->data.F64[normIndex][i + numSolution1]; 1159 1160 sumMatrix->data.F64[i][normIndex] = 0.0; 1161 sumMatrix->data.F64[normIndex][i] = 0.0; 1162 1163 sumMatrix->data.F64[i + numSolution1][normIndex] = 0.0; 1164 sumMatrix->data.F64[normIndex][i + numSolution1] = 0.0; 1165 } 1166 sumVector->data.F64[bgIndex] -= normValue * sumMatrix->data.F64[normIndex][bgIndex]; 1167 sumMatrix->data.F64[bgIndex][normIndex] = 0.0; 1168 sumMatrix->data.F64[normIndex][bgIndex] = 0.0; 1169 1170 sumMatrix->data.F64[normIndex][normIndex] = 1.0; 1171 1172 sumVector->data.F64[normIndex] = 0.0; 1173 1174 solution = psMatrixSolveSVD(solution, sumMatrix, sumVector, NAN); 1175 1176 solution->data.F64[normIndex] = normValue; 1177 } 1178 #endif 1179 1180 987 1181 #ifdef TESTING 988 psVectorInit(h, NAN); 989 #endif 990 assert(C->numRows == numParams2 && C->numCols == numParams); 991 assert(a->n == numParams); 992 assert(e->n == numParams2); 993 for (int i = 0; i < numParams2; i++) { 994 double value = 0.0; 995 for (int j = 0; j < numParams; j++) { 996 value += C->data.F64[i][j] * a->data.F64[j]; 997 } 998 h->data.F64[i] = value - e->data.F64[i]; 999 } 1000 1001 assert(Bi->numRows == numParams2 && Bi->numCols == numParams2); 1002 assert(h->n == numParams2); 1003 for (int i = 0; i < numParams2; i++) { 1004 double value = 0.0; 1005 for (int j = 0; j < numParams2; j++) { 1006 value += Bi->data.F64[i][j] * h->data.F64[j]; 1007 } 1008 b->data.F64[i] = value; 1009 } 1010 1011 1012 #if 0 1013 for (int i = 0; i < numParams; i++) { 1014 double aVal1 = 0.0, bVal1 = 0.0; 1015 for (int j = 0; j < numParams2; j++) { 1016 aVal1 += A->data.F64[i][j] * a->data.F64[j]; 1017 bVal1 += Ct->data.F64[i][j] * b->data.F64[j]; 1018 } 1019 bVal1 += d->data.F64[i]; 1020 for (int j = numParams2; j < numParams; j++) { 1021 aVal1 += A->data.F64[i][j] * a->data.F64[j]; 1022 } 1023 printf("%d: %lf\n", i, aVal1 - bVal1); 1024 } 1025 1026 for (int i = 0; i < numParams2; i++) { 1027 double aVal2 = 0.0, bVal2 = 0.0; 1028 for (int j = 0; j < numParams2; j++) { 1029 aVal2 += C->data.F64[i][j] * a->data.F64[j]; 1030 bVal2 += B->data.F64[i][j] * b->data.F64[j]; 1031 } 1032 bVal2 += e->data.F64[i]; 1033 for (int j = numParams2; j < numParams; j++) { 1034 aVal2 += C->data.F64[i][j] * a->data.F64[j]; 1035 } 1036 printf("%d: %lf\n", i, aVal2 - bVal2); 1037 } 1038 #endif 1039 1040 #ifdef TESTING 1041 { 1042 psFits *fits = psFitsOpen("sumMatrix1.fits", "w"); 1043 psFitsWriteImage(fits, NULL, sumMatrix1, 0, NULL); 1044 psFitsClose(fits); 1045 } 1046 { 1047 psFits *fits = psFitsOpen("sumMatrix2.fits", "w"); 1048 psFitsWriteImage(fits, NULL, sumMatrix2, 0, NULL); 1049 psFitsClose(fits); 1050 } 1051 { 1052 psFits *fits = psFitsOpen("sumMatrixX.fits", "w"); 1053 psFitsWriteImage(fits, NULL, sumMatrixX, 0, NULL); 1054 psFitsClose(fits); 1055 } 1056 { 1057 psFits *fits = psFitsOpen("sumFinverse.fits", "w"); 1058 psFitsWriteImage(fits, NULL, Fi, 0, NULL); 1059 psFitsClose(fits); 1060 } 1061 #endif 1062 1063 kernels->solution1 = a; 1064 kernels->solution2 = b; 1065 1066 // XXXXX Free temporary matrices and vectors 1182 for (int i = 0; i < solution->n; i++) { 1183 fprintf(stderr, "Dual solution %d: %lf\n", i, solution->data.F64[i]); 1184 } 1185 #endif 1186 1187 psFree(sumMatrix); 1188 psFree(sumVector); 1189 1190 psFree(norms); 1191 1192 if (!kernels->solution1) { 1193 kernels->solution1 = psVectorAlloc(numSolution1, PS_TYPE_F64); 1194 psVectorInit (kernels->solution1, 0.0); 1195 } 1196 if (!kernels->solution2) { 1197 kernels->solution2 = psVectorAlloc(numSolution2, PS_TYPE_F64); 1198 psVectorInit (kernels->solution2, 0.0); 1199 } 1200 1201 // only update the solutions that we chose to calculate: 1202 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 1203 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 1204 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 1205 } 1206 if (mode & PM_SUBTRACTION_EQUATION_BG) { 1207 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1208 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 1209 } 1210 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 1211 int numKernels = kernels->num; 1212 for (int i = 0; i < numKernels * numSpatial; i++) { 1213 // XXX fprintf (stderr, "keep\n"); 1214 kernels->solution1->data.F64[i] = solution->data.F64[i]; 1215 kernels->solution2->data.F64[i] = solution->data.F64[i + numSolution1]; 1216 } 1217 } 1218 1219 1220 memcpy(kernels->solution1->data.F64, solution->data.F64, 1221 numSolution1 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1222 memcpy(kernels->solution2->data.F64, &solution->data.F64[numSolution1], 1223 numSolution2 * PSELEMTYPE_SIZEOF(PS_TYPE_F64)); 1224 1225 psFree(solution); 1067 1226 1068 1227 } … … 1083 1242 } 1084 1243 1085 pmSubtractionVisualPlotLeastSquares((pmSubtractionStampList *) stamps); //casting away const1244 // pmSubtractionVisualPlotLeastSquares((pmSubtractionStampList *) stamps); //casting away const 1086 1245 return true; 1087 1246 } 1088 1247 1248 bool pmSubtractionResidualStats(psVector *fSigRes, psVector *fMaxRes, psVector *fMinRes, psKernel *target, psKernel *source, psKernel *residual, double norm, int footprint) { 1249 1250 // XXX measure some useful stats on the residuals 1251 float sum = 0.0; 1252 float peak = 0.0; 1253 for (int y = - footprint; y <= footprint; y++) { 1254 for (int x = - footprint; x <= footprint; x++) { 1255 sum += 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm); 1256 peak = PS_MAX(peak, 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm)); 1257 } 1258 } 1259 1260 // only count pixels with more than X% of the source flux 1261 // calculate stdev(dflux) 1262 float dflux1 = 0.0; 1263 float dflux2 = 0.0; 1264 int npix = 0; 1265 1266 float dmax = 0.0; 1267 float dmin = 0.0; 1268 1269 for (int y = - footprint; y <= footprint; y++) { 1270 for (int x = - footprint; x <= footprint; x++) { 1271 float dflux = 0.5*(target->kernel[y][x] + source->kernel[y][x] * norm); 1272 if (dflux < 0.02*sum) continue; 1273 dflux1 += residual->kernel[y][x]; 1274 dflux2 += PS_SQR(residual->kernel[y][x]); 1275 dmax = PS_MAX(residual->kernel[y][x], dmax); 1276 dmin = PS_MIN(residual->kernel[y][x], dmin); 1277 npix ++; 1278 } 1279 } 1280 float sigma = sqrt(dflux2 / npix - PS_SQR(dflux1/npix)); 1281 if (!isfinite(sum)) return false; 1282 if (!isfinite(dmax)) return false; 1283 if (!isfinite(dmin)) return false; 1284 if (!isfinite(peak)) return false; 1285 1286 // fprintf (stderr, "sum: %f, peak: %f, sigma: %f, fsigma: %f, fmax: %f, fmin: %f\n", sum, peak, sigma, sigma/sum, dmax/peak, dmin/peak); 1287 psVectorAppend(fSigRes, sigma/sum); 1288 psVectorAppend(fMaxRes, dmax/peak); 1289 psVectorAppend(fMinRes, dmin/peak); 1290 return true; 1291 } 1292 1089 1293 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, 1090 constpmSubtractionKernels *kernels)1294 pmSubtractionKernels *kernels) 1091 1295 { 1092 1296 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL); … … 1103 1307 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1104 1308 1309 // set up holding images for the visualization 1310 pmSubtractionVisualShowFitInit (stamps); 1311 1312 psVector *fSigRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1313 psVector *fMinRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1314 psVector *fMaxRes = psVectorAllocEmpty(stamps->num, PS_TYPE_F32); 1315 1316 // we want to save the residual images for the 9 brightest stamps. 1317 // identify the 9 brightest stamps 1318 psVector *keepStamps = psVectorAlloc(stamps->num, PS_TYPE_S32); 1319 psVectorInit (keepStamps, 0); 1320 { 1321 psVector *flux = psVectorAlloc(stamps->num, PS_TYPE_F32); 1322 psVectorInit (flux, 0.0); 1323 1324 for (int i = 0; i < stamps->num; i++) { 1325 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1326 if (!isfinite(stamp->flux)) continue; 1327 flux->data.F32[i] = stamp->flux; 1328 } 1329 1330 psVector *index = psVectorSortIndex(NULL, flux); 1331 for (int i = 0; (i < stamps->num) && (i < 9); i++) { 1332 int n = stamps->num - i - 1; 1333 keepStamps->data.S32[index->data.S32[n]] = 1; 1334 } 1335 psFree (flux); 1336 psFree (index); 1337 1338 // this function is called multiple times in the iteration, but 1339 // we only know after the interation is done if we will try again. 1340 // therefore we must save the sample each time, and blow away the old one 1341 // if it exists. 1342 psFree (kernels->sampleStamps); 1343 kernels->sampleStamps = psArrayAllocEmpty(9); 1344 } 1345 1346 psString log = psStringCopy("Deviations:\n"); // Log message with deviations 1105 1347 for (int i = 0; i < stamps->num; i++) { 1106 1348 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest … … 1116 1358 1117 1359 // Calculate residuals 1118 psKernel * variance = stamp->variance; // Variancepostage stamp1360 psKernel *weight = stamp->weight; // Weight postage stamp 1119 1361 psImageInit(residual->image, 0.0); 1120 1362 if (kernels->mode != PM_SUBTRACTION_MODE_DUAL) { … … 1133 1375 false); // Kernel image 1134 1376 if (!image) { 1135 psError( PS_ERR_UNKNOWN, false, "Unable to generate image of kernel.");1377 psError(psErrorCodeLast(), false, "Unable to generate image of kernel."); 1136 1378 return false; 1137 1379 } … … 1162 1404 for (int y = - footprint; y <= footprint; y++) { 1163 1405 for (int x = - footprint; x <= footprint; x++) { 1164 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient;1406 residual->kernel[y][x] += convolution->kernel[y][x] * coefficient; 1165 1407 } 1166 1408 } 1167 1409 } 1410 1411 // XXX visualize the target, source, convolution and residual 1412 pmSubtractionVisualShowFitAddStamp (target, source, residual, background, norm, i); 1413 1168 1414 for (int y = - footprint; y <= footprint; y++) { 1169 1415 for (int x = - footprint; x <= footprint; x++) { 1170 residual->kernel[y][x] += target->kernel[y][x] - background - source->kernel[y][x] * norm; 1171 } 1172 } 1416 residual->kernel[y][x] += background + source->kernel[y][x] * norm - target->kernel[y][x]; 1417 } 1418 } 1419 1420 if (keepStamps->data.S32[i]) { 1421 psImage *sample = psImageCopy(NULL, residual->image, PS_TYPE_F32); 1422 psArrayAdd (kernels->sampleStamps, 9, sample); 1423 psFree (sample); 1424 } 1425 1426 pmSubtractionResidualStats(fSigRes, fMaxRes, fMinRes, target, source, residual, norm, footprint); 1427 1173 1428 } else { 1174 1429 // Dual convolution … … 1186 1441 for (int y = - footprint; y <= footprint; y++) { 1187 1442 for (int x = - footprint; x <= footprint; x++) { 1188 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 -conv1->kernel[y][x] * coeff1;1443 residual->kernel[y][x] += conv2->kernel[y][x] * coeff2 + conv1->kernel[y][x] * coeff1; 1189 1444 } 1190 1445 } 1191 1446 } 1447 1448 // XXX visualize the target, source, convolution and residual 1449 pmSubtractionVisualShowFitAddStamp (image2, image1, residual, background, norm, i); 1450 1192 1451 for (int y = - footprint; y <= footprint; y++) { 1193 1452 for (int x = - footprint; x <= footprint; x++) { 1194 residual->kernel[y][x] += image2->kernel[y][x] - background - image1->kernel[y][x] * norm; 1195 } 1196 } 1453 residual->kernel[y][x] += background + image1->kernel[y][x] * norm - image2->kernel[y][x]; 1454 } 1455 } 1456 if (keepStamps->data.S32[i]) { 1457 psImage *sample = psImageCopy(NULL, residual->image, PS_TYPE_F32); 1458 psArrayAdd (kernels->sampleStamps, 9, sample); 1459 psFree (sample); 1460 } 1461 1462 pmSubtractionResidualStats(fSigRes, fMaxRes, fMinRes, image1, image2, residual, norm, footprint); 1197 1463 } 1198 1464 … … 1200 1466 for (int y = - footprint; y <= footprint; y++) { 1201 1467 for (int x = - footprint; x <= footprint; x++) { 1202 double dev = PS_SQR(residual->kernel[y][x]) / variance->kernel[y][x];1468 double dev = PS_SQR(residual->kernel[y][x]) * weight->kernel[y][x]; 1203 1469 deviation += dev; 1204 1470 #ifdef TESTING … … 1209 1475 deviations->data.F32[i] = devNorm * deviation; 1210 1476 psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n", 1211 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]); 1477 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]); 1478 psStringAppend(&log, "Stamp %d (%d,%d): %f\n", 1479 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5), deviations->data.F32[i]); 1212 1480 if (!isfinite(deviations->data.F32[i])) { 1213 1481 stamp->status = PM_SUBTRACTION_STAMP_REJECTED; 1214 1482 psTrace("psModules.imcombine", 5, 1215 1483 "Rejecting stamp %d (%d,%d) because of non-finite deviation\n", 1216 i, (int)(stamp->x + 0.5), (int)(stamp->y +0.5));1484 i, (int)(stamp->x - 0.5), (int)(stamp->y - 0.5)); 1217 1485 continue; 1218 1486 } … … 1243 1511 psFitsClose(fits); 1244 1512 } 1245 if (stamp-> variance) {1513 if (stamp->weight) { 1246 1514 psString filename = NULL; 1247 psStringAppend(&filename, "stamp_ variance_%03d.fits", i);1515 psStringAppend(&filename, "stamp_weight_%03d.fits", i); 1248 1516 psFits *fits = psFitsOpen(filename, "w"); 1249 1517 psFree(filename); 1250 psFitsWriteImage(fits, NULL, stamp-> variance->image, 0, NULL);1518 psFitsWriteImage(fits, NULL, stamp->weight->image, 0, NULL); 1251 1519 psFitsClose(fits); 1252 1520 } … … 1254 1522 1255 1523 } 1524 1525 psFree(keepStamps); 1526 1527 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "%s", log); 1528 psFree(log); 1529 1530 // calculate and report the normalization and background for the image center 1531 { 1532 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, 0.0, 0.0); 1533 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1534 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1535 psLogMsg("psModules.imcombine", PS_LOG_INFO, "normalization: %f, background: %f", norm, background); 1536 1537 pmSubtractionVisualShowFit(norm); 1538 pmSubtractionVisualPlotFit(kernels); 1539 1540 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 1541 psVectorStats (stats, fSigRes, NULL, NULL, 0); 1542 kernels->fSigResMean = stats->robustMedian; 1543 kernels->fSigResStdev = stats->robustStdev; 1544 1545 psStatsInit (stats); 1546 psVectorStats (stats, fMaxRes, NULL, NULL, 0); 1547 kernels->fMaxResMean = stats->robustMedian; 1548 kernels->fMaxResStdev = stats->robustStdev; 1549 1550 psStatsInit (stats); 1551 psVectorStats (stats, fMinRes, NULL, NULL, 0); 1552 kernels->fMinResMean = stats->robustMedian; 1553 kernels->fMinResStdev = stats->robustStdev; 1554 1555 // XXX save these values somewhere 1556 psLogMsg("psModules.imcombine", PS_LOG_INFO, "fSigma: %f +/- %f, fMaxRes: %f +/- %f, fMinRes: %f +/- %f", 1557 kernels->fSigResMean, kernels->fSigResStdev, 1558 kernels->fMaxResMean, kernels->fMaxResStdev, 1559 kernels->fMinResMean, kernels->fMinResStdev); 1560 1561 psFree (fSigRes); 1562 psFree (fMaxRes); 1563 psFree (fMinRes); 1564 psFree (stats); 1565 } 1566 1256 1567 psFree(residual); 1257 1568 psFree(polyValues); 1258 1569 1570 1259 1571 return deviations; 1260 1572 } 1573 1574 // we are supplied U, not Ut; w represents a diagonal matrix (also, we apply 1/w instead of w) 1575 psImage *p_pmSubSolve_wUt (psVector *w, psImage *U) { 1576 1577 psAssert (w->n == U->numCols, "w and U dimensions do not match"); 1578 1579 // wUt has dimensions transposed relative to Ut. 1580 psImage *wUt = psImageAlloc (U->numRows, U->numCols, PS_TYPE_F64); 1581 psImageInit (wUt, 0.0); 1582 1583 for (int i = 0; i < wUt->numCols; i++) { 1584 for (int j = 0; j < wUt->numRows; j++) { 1585 if (!isfinite(w->data.F64[j])) continue; 1586 if (w->data.F64[j] == 0.0) continue; 1587 wUt->data.F64[j][i] = U->data.F64[i][j] / w->data.F64[j]; 1588 } 1589 } 1590 return wUt; 1591 } 1592 1593 // XXX this is just standard matrix multiplication: use psMatrixMultiply? 1594 psImage *p_pmSubSolve_VwUt (psImage *V, psImage *wUt) { 1595 1596 psAssert (V->numCols == wUt->numRows, "matrix dimensions do not match"); 1597 1598 psImage *Ainv = psImageAlloc (wUt->numCols, V->numRows, PS_TYPE_F64); 1599 1600 for (int i = 0; i < Ainv->numCols; i++) { 1601 for (int j = 0; j < Ainv->numRows; j++) { 1602 double sum = 0.0; 1603 for (int k = 0; k < V->numCols; k++) { 1604 sum += V->data.F64[j][k] * wUt->data.F64[k][i]; 1605 } 1606 Ainv->data.F64[j][i] = sum; 1607 } 1608 } 1609 return Ainv; 1610 } 1611 1612 // we are supplied U, not Ut 1613 bool p_pmSubSolve_UtB (psVector **UtB, psImage *U, psVector *B) { 1614 1615 psAssert (U->numRows == B->n, "U and B dimensions do not match"); 1616 1617 UtB[0] = psVectorRecycle (UtB[0], U->numCols, PS_TYPE_F64); 1618 1619 for (int i = 0; i < U->numCols; i++) { 1620 double sum = 0.0; 1621 for (int j = 0; j < U->numRows; j++) { 1622 sum += B->data.F64[j] * U->data.F64[j][i]; 1623 } 1624 UtB[0]->data.F64[i] = sum; 1625 } 1626 return true; 1627 } 1628 1629 // w is diagonal 1630 bool p_pmSubSolve_wUtB (psVector **wUtB, psVector *w, psVector *UtB) { 1631 1632 psAssert (w->n == UtB->n, "w and UtB dimensions do not match"); 1633 1634 // wUt has dimensions transposed relative to Ut. 1635 wUtB[0] = psVectorRecycle (wUtB[0], w->n, PS_TYPE_F64); 1636 psVectorInit (wUtB[0], 0.0); 1637 1638 for (int i = 0; i < w->n; i++) { 1639 if (!isfinite(w->data.F64[i])) continue; 1640 if (w->data.F64[i] == 0.0) continue; 1641 wUtB[0]->data.F64[i] = UtB->data.F64[i] / w->data.F64[i]; 1642 } 1643 return true; 1644 } 1645 1646 // this is basically matrix * vector 1647 bool p_pmSubSolve_VwUtB (psVector **VwUtB, psImage *V, psVector *wUtB) { 1648 1649 psAssert (V->numCols == wUtB->n, "V and wUtB dimensions do not match"); 1650 1651 VwUtB[0] = psVectorRecycle (*VwUtB, V->numRows, PS_TYPE_F64); 1652 1653 for (int j = 0; j < V->numRows; j++) { 1654 double sum = 0.0; 1655 for (int i = 0; i < V->numCols; i++) { 1656 sum += V->data.F64[j][i] * wUtB->data.F64[i]; 1657 } 1658 VwUtB[0]->data.F64[j] = sum; 1659 } 1660 return true; 1661 } 1662 1663 // this is basically matrix * vector 1664 bool p_pmSubSolve_Ax (psVector **B, psImage *A, psVector *x) { 1665 1666 psAssert (A->numCols == x->n, "A and x dimensions do not match"); 1667 1668 B[0] = psVectorRecycle (*B, A->numRows, PS_TYPE_F64); 1669 1670 for (int j = 0; j < A->numRows; j++) { 1671 double sum = 0.0; 1672 for (int i = 0; i < A->numCols; i++) { 1673 sum += A->data.F64[j][i] * x->data.F64[i]; 1674 } 1675 B[0]->data.F64[j] = sum; 1676 } 1677 return true; 1678 } 1679 1680 // this is basically Vector * vector 1681 bool p_pmSubSolve_VdV (double *value, psVector *x, psVector *y) { 1682 1683 psAssert (x->n == y->n, "x and y dimensions do not match"); 1684 1685 double sum = 0.0; 1686 for (int i = 0; i < x->n; i++) { 1687 sum += x->data.F64[i] * y->data.F64[i]; 1688 } 1689 *value = sum; 1690 return true; 1691 } 1692 1693 bool p_pmSubSolve_y2 (double *y2, pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) { 1694 1695 int footprint = stamps->footprint; // Half-size of stamps 1696 1697 double sum = 0.0; 1698 for (int i = 0; i < stamps->num; i++) { 1699 1700 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1701 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 1702 1703 psKernel *weight = NULL; 1704 psKernel *window = NULL; 1705 psKernel *input = NULL; 1706 1707 #ifdef USE_WEIGHT 1708 weight = stamp->weight; 1709 #endif 1710 #ifdef USE_WINDOW 1711 window = stamps->window; 1712 #endif 1713 1714 switch (kernels->mode) { 1715 // MODE_1 : convolve image 1 to match image 2 (and vice versa) 1716 case PM_SUBTRACTION_MODE_1: 1717 input = stamp->image2; 1718 break; 1719 case PM_SUBTRACTION_MODE_2: 1720 input = stamp->image1; 1721 break; 1722 default: 1723 psAbort ("programming error"); 1724 } 1725 1726 for (int y = - footprint; y <= footprint; y++) { 1727 for (int x = - footprint; x <= footprint; x++) { 1728 double in = input->kernel[y][x]; 1729 double value = in*in; 1730 if (weight) { 1731 float wtVal = weight->kernel[y][x]; 1732 value *= wtVal; 1733 } 1734 if (window) { 1735 float winVal = window->kernel[y][x]; 1736 value *= winVal; 1737 } 1738 sum += value; 1739 } 1740 } 1741 } 1742 *y2 = sum; 1743 return true; 1744 } 1745 1746 double p_pmSubSolve_ChiSquare (pmSubtractionKernels *kernels, const pmSubtractionStampList *stamps) { 1747 1748 int footprint = stamps->footprint; // Half-size of stamps 1749 int numKernels = kernels->num; // Number of kernels 1750 1751 double sum = 0.0; 1752 1753 psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint); // Residual image 1754 psImageInit(residual->image, 0.0); 1755 1756 psImage *polyValues = NULL; // Polynomial values 1757 1758 for (int i = 0; i < stamps->num; i++) { 1759 1760 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 1761 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 1762 1763 psKernel *weight = NULL; 1764 psKernel *window = NULL; 1765 psKernel *target = NULL; 1766 psKernel *source = NULL; 1767 1768 psArray *convolutions = NULL; 1769 1770 #ifdef USE_WEIGHT 1771 weight = stamp->weight; 1772 #endif 1773 #ifdef USE_WINDOW 1774 window = stamps->window; 1775 #endif 1776 1777 switch (kernels->mode) { 1778 // MODE_1 : convolve image 1 to match image 2 (and vice versa) 1779 case PM_SUBTRACTION_MODE_1: 1780 target = stamp->image2; 1781 source = stamp->image1; 1782 convolutions = stamp->convolutions1; 1783 break; 1784 case PM_SUBTRACTION_MODE_2: 1785 target = stamp->image1; 1786 source = stamp->image2; 1787 convolutions = stamp->convolutions2; 1788 break; 1789 default: 1790 psAbort ("programming error"); 1791 } 1792 1793 // Calculate coefficients of the kernel basis functions 1794 polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, stamp->xNorm, stamp->yNorm); 1795 double norm = p_pmSubtractionSolutionNorm(kernels); // Normalisation 1796 double background = p_pmSubtractionSolutionBackground(kernels, polyValues);// Difference in background 1797 1798 psImageInit(residual->image, 0.0); 1799 for (int j = 0; j < numKernels; j++) { 1800 psKernel *convolution = convolutions->data[j]; // Convolution 1801 double coefficient = p_pmSubtractionSolutionCoeff(kernels, polyValues, j, false); // Coefficient 1802 for (int y = - footprint; y <= footprint; y++) { 1803 for (int x = - footprint; x <= footprint; x++) { 1804 residual->kernel[y][x] -= convolution->kernel[y][x] * coefficient; 1805 } 1806 } 1807 } 1808 1809 for (int y = - footprint; y <= footprint; y++) { 1810 for (int x = - footprint; x <= footprint; x++) { 1811 double resid = target->kernel[y][x] - background - source->kernel[y][x] * norm + residual->kernel[y][x]; 1812 double value = PS_SQR(resid); 1813 if (weight) { 1814 float wtVal = weight->kernel[y][x]; 1815 value *= wtVal; 1816 } 1817 if (window) { 1818 float winVal = window->kernel[y][x]; 1819 value *= winVal; 1820 } 1821 sum += value; 1822 } 1823 } 1824 } 1825 psFree (polyValues); 1826 psFree (residual); 1827 1828 return sum; 1829 } 1830 1831 bool p_pmSubSolve_SetWeights (psVector *wApply, psVector *w, psVector *wMask) { 1832 1833 for (int i = 0; i < w->n; i++) { 1834 wApply->data.F64[i] = wMask->data.U8[i] ? 0.0 : w->data.F64[i]; 1835 } 1836 return true; 1837 } 1838 1839 // we are supplied V and w; w represents a diagonal matrix (also, we apply 1/w instead of w) 1840 psImage *p_pmSubSolve_Xvar (psImage *V, psVector *w) { 1841 1842 psAssert (w->n == V->numCols, "w and U dimensions do not match"); 1843 1844 psImage *Vn = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64); 1845 psImageInit (Vn, 0.0); 1846 1847 // generate Vn = V * w^{-1} 1848 for (int j = 0; j < Vn->numRows; j++) { 1849 for (int i = 0; i < Vn->numCols; i++) { 1850 if (!isfinite(w->data.F64[i])) continue; 1851 if (w->data.F64[i] == 0.0) continue; 1852 Vn->data.F64[j][i] = V->data.F64[j][i] / w->data.F64[i]; 1853 } 1854 } 1855 1856 psImage *Xvar = psImageAlloc (V->numCols, V->numRows, PS_TYPE_F64); 1857 psImageInit (Xvar, 0.0); 1858 1859 // generate Xvar = Vn * Vn^T 1860 for (int j = 0; j < Vn->numRows; j++) { 1861 for (int i = 0; i < Vn->numCols; i++) { 1862 double sum = 0.0; 1863 for (int k = 0; k < Vn->numCols; k++) { 1864 sum += Vn->data.F64[k][i]*Vn->data.F64[k][j]; 1865 } 1866 Xvar->data.F64[j][i] = sum; 1867 } 1868 } 1869 return Xvar; 1870 } 1871 1872 // I get confused by the index values between the image vs matrix usage: In terms 1873 // of the elements of an image A(x,y) = A->data.F64[y][x] = A_x,y, a matrix 1874 // multiplication is: A_k,j * B_i,k = C_i,j 1875 1876 1877 bool psFitsWriteImageSimple (char *filename, psImage *image, psMetadata *header) { 1878 1879 psFits *fits = psFitsOpen(filename, "w"); 1880 psFitsWriteImage(fits, header, image, 0, NULL); 1881 psFitsClose(fits); 1882 1883 return true; 1884 } 1885 1886 bool psVectorWriteFile (char *filename, const psVector *vector) { 1887 1888 FILE *f = fopen (filename, "w"); 1889 int fd = fileno(f); 1890 p_psVectorPrint (fd, vector, "unnamed"); 1891 fclose (f); 1892 1893 return true; 1894 } 1895 1896 1897 # if 0 1898 1899 #ifdef TESTING 1900 psFitsWriteImageSimple("A.fits", sumMatrix, NULL); 1901 psVectorWriteFile ("B.dat", sumVector); 1902 #endif 1903 1904 # define SVD_ANALYSIS 0 1905 # define COEFF_SIG 0.0 1906 # define SVD_TOL 0.0 1907 1908 // Use SVD to determine the kernel coeffs (and validate) 1909 if (SVD_ANALYSIS) { 1910 1911 // We have sumVector and sumMatrix. we are trying to solve the following equation: 1912 // sumMatrix * x = sumVector. 1913 1914 // we can use any standard matrix inversion to solve this. However, the basis 1915 // functions in general have substantial correlation, so that the solution may be 1916 // somewhat poorly determined or unstable. If not numerically ill-conditioned, the 1917 // system of equations may be statistically ill-conditioned. Noise in the image 1918 // will drive insignificant, but correlated, terms in the solution. To avoid these 1919 // problems, we can use SVD to identify numerically unconstrained values and to 1920 // avoid statistically badly determined value. 1921 1922 // A = sumMatrix, B = sumVector 1923 // SVD: A = U w V^T -> A^{-1} = V (1/w) U^T 1924 // x = V (1/w) (U^T B) 1925 // \sigma_x = sqrt(diag(A^{-1})) 1926 // solve for x and A^{-1} to get x & dx 1927 // identify the elements of (1/w) that are nan (1/0.0) -> set to 0.0 1928 // identify the elements of x that are insignificant (x / dx < 1.0? < 0.5?) -> set to 0.0 1929 1930 // If I use the SVD trick to re-condition the matrix, I need to break out the 1931 // kernel and normalization terms from the background term. 1932 // XXX is this true? or was this due to an error in the analysis? 1933 1934 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 1935 1936 // now pull out the kernel elements into their own square matrix 1937 psImage *kernelMatrix = psImageAlloc (sumMatrix->numCols - 1, sumMatrix->numRows - 1, PS_TYPE_F64); 1938 psVector *kernelVector = psVectorAlloc (sumMatrix->numCols - 1, PS_TYPE_F64); 1939 1940 for (int ix = 0, kx = 0; ix < sumMatrix->numCols; ix++) { 1941 if (ix == bgIndex) continue; 1942 for (int iy = 0, ky = 0; iy < sumMatrix->numRows; iy++) { 1943 if (iy == bgIndex) continue; 1944 kernelMatrix->data.F64[ky][kx] = sumMatrix->data.F64[iy][ix]; 1945 ky++; 1946 } 1947 kernelVector->data.F64[kx] = sumVector->data.F64[ix]; 1948 kx++; 1949 } 1950 1951 psImage *U = NULL; 1952 psImage *V = NULL; 1953 psVector *w = NULL; 1954 if (!psMatrixSVD (&U, &w, &V, kernelMatrix)) { 1955 psError(psErrorCodeLast(), false, "failed to perform SVD on sumMatrix\n"); 1956 return NULL; 1957 } 1958 1959 // calculate A_inverse: 1960 // Ainv = V * w * U^T 1961 psImage *wUt = p_pmSubSolve_wUt (w, U); 1962 psImage *Ainv = p_pmSubSolve_VwUt (V, wUt); 1963 psImage *Xvar = NULL; 1964 psFree (wUt); 1965 1966 # ifdef TESTING 1967 // kernel terms: 1968 for (int i = 0; i < w->n; i++) { 1969 fprintf (stderr, "w: %f\n", w->data.F64[i]); 1970 } 1971 # endif 1972 // loop over w adding in more and more of the values until chisquare is no longer 1973 // dropping significantly. 1974 // XXX this does not seem to work very well: we seem to need all terms even for 1975 // simple cases... 1976 1977 psVector *Xsvd = NULL; 1978 { 1979 psVector *Ax = NULL; 1980 psVector *UtB = NULL; 1981 psVector *wUtB = NULL; 1982 1983 psVector *wApply = psVectorAlloc(w->n, PS_TYPE_F64); 1984 psVector *wMask = psVectorAlloc(w->n, PS_TYPE_U8); 1985 psVectorInit (wMask, 1); // start by masking everything 1986 1987 double chiSquareLast = NAN; 1988 int maxWeight = 0; 1989 1990 double Axx, Bx, y2; 1991 1992 // XXX this is an attempt to exclude insignificant modes. 1993 // it was not successful with the ISIS kernel set: removing even 1994 // the least significant mode leaves additional ringing / noise 1995 // because the terms are so coupled. 1996 for (int k = 0; false && (k < w->n); k++) { 1997 1998 // unmask the k-th weight 1999 wMask->data.U8[k] = 0; 2000 p_pmSubSolve_SetWeights(wApply, w, wMask); 2001 2002 // solve for x: 2003 // x = V * w * (U^T * B) 2004 p_pmSubSolve_UtB (&UtB, U, kernelVector); 2005 p_pmSubSolve_wUtB (&wUtB, wApply, UtB); 2006 p_pmSubSolve_VwUtB (&Xsvd, V, wUtB); 2007 2008 // chi-square for this system of equations: 2009 // chi-square = sum over terms of: (Ax - B)*x - b*x - y^2 2010 // y^2 = \sum_stamps \sum_pixels input->kernel[y][x]^2 2011 p_pmSubSolve_Ax (&Ax, kernelMatrix, Xsvd); 2012 p_pmSubSolve_VdV (&Axx, Ax, Xsvd); 2013 p_pmSubSolve_VdV (&Bx, kernelVector, Xsvd); 2014 p_pmSubSolve_y2 (&y2, kernels, stamps); 2015 2016 // apparently, this works (compare with the brute force value below 2017 double chiSquare = Axx - 2.0*Bx + y2; 2018 double deltaChi = (k == 0) ? chiSquare : chiSquareLast - chiSquare; 2019 chiSquareLast = chiSquare; 2020 2021 // fprintf (stderr, "chi square = %f, delta: %f\n", chiSquare, deltaChi); 2022 if (k && !maxWeight && (deltaChi < 1.0)) { 2023 maxWeight = k; 2024 } 2025 } 2026 2027 // keep all terms or we get extra ringing 2028 maxWeight = w->n; 2029 psVectorInit (wMask, 1); 2030 for (int k = 0; k < maxWeight; k++) { 2031 wMask->data.U8[k] = 0; 2032 } 2033 p_pmSubSolve_SetWeights(wApply, w, wMask); 2034 2035 // solve for x: 2036 // x = V * w * (U^T * B) 2037 p_pmSubSolve_UtB (&UtB, U, kernelVector); 2038 p_pmSubSolve_wUtB (&wUtB, wApply, UtB); 2039 p_pmSubSolve_VwUtB (&Xsvd, V, wUtB); 2040 2041 // chi-square for this system of equations: 2042 // chi-square = sum over terms of: (Ax - B)*x - b*x - y^2 2043 // y^2 = \sum_stamps \sum_pixels input->kernel[y][x]^2 2044 p_pmSubSolve_Ax (&Ax, kernelMatrix, Xsvd); 2045 p_pmSubSolve_VdV (&Axx, Ax, Xsvd); 2046 p_pmSubSolve_VdV (&Bx, kernelVector, Xsvd); 2047 p_pmSubSolve_y2 (&y2, kernels, stamps); 2048 2049 // apparently, this works (compare with the brute force value below 2050 double chiSquare = Axx - 2.0*Bx + y2; 2051 psLogMsg ("psModules.imcombine", PS_LOG_INFO, "model kernel with %d terms; chi square = %f\n", maxWeight, chiSquare); 2052 2053 // re-calculate A^{-1} to get new variances: 2054 // Ainv = V * w * U^T 2055 // XXX since we keep all terms, this is identical to Ainv 2056 psImage *wUt = p_pmSubSolve_wUt (wApply, U); 2057 Xvar = p_pmSubSolve_VwUt (V, wUt); 2058 psFree (wUt); 2059 2060 psFree (Ax); 2061 psFree (UtB); 2062 psFree (wUtB); 2063 psFree (wApply); 2064 psFree (wMask); 2065 } 2066 2067 // copy the kernel solutions to the full solution vector: 2068 solution = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2069 solutionErr = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2070 2071 for (int ix = 0, kx = 0; ix < sumVector->n; ix++) { 2072 if (ix == bgIndex) { 2073 solution->data.F64[ix] = 0; 2074 solutionErr->data.F64[ix] = 0.001; 2075 continue; 2076 } 2077 solutionErr->data.F64[ix] = sqrt(Ainv->data.F64[kx][kx]); 2078 solution->data.F64[ix] = Xsvd->data.F64[kx]; 2079 kx++; 2080 } 2081 2082 psFree (kernelMatrix); 2083 psFree (kernelVector); 2084 2085 psFree (U); 2086 psFree (V); 2087 psFree (w); 2088 2089 psFree (Ainv); 2090 psFree (Xsvd); 2091 } else { 2092 psVector *permutation = NULL; // Permutation vector, required for LU decomposition 2093 psImage *luMatrix = psMatrixLUDecomposition(NULL, &permutation, sumMatrix); 2094 if (!luMatrix) { 2095 psError(PM_ERR_DATA, true, "LU Decomposition of least-squares matrix failed.\n"); 2096 psFree(solution); 2097 psFree(sumVector); 2098 psFree(sumMatrix); 2099 psFree(luMatrix); 2100 psFree(permutation); 2101 return NULL; 2102 } 2103 2104 solution = psMatrixLUSolution(NULL, luMatrix, sumVector, permutation); 2105 psFree(luMatrix); 2106 psFree(permutation); 2107 if (!solution) { 2108 psError(PM_ERR_DATA, true, "Failed to solve the least-squares system.\n"); 2109 psFree(solution); 2110 psFree(sumVector); 2111 psFree(sumMatrix); 2112 return NULL; 2113 } 2114 2115 // XXX LUD does not provide A^{-1}? fake the error for now 2116 solutionErr = psVectorAlloc(sumVector->n, PS_TYPE_F64); 2117 for (int ix = 0; ix < sumVector->n; ix++) { 2118 solutionErr->data.F64[ix] = 0.1*solution->data.F64[ix]; 2119 } 2120 } 2121 2122 if (!kernels->solution1) { 2123 kernels->solution1 = psVectorAlloc (sumVector->n, PS_TYPE_F64); 2124 psVectorInit (kernels->solution1, 0.0); 2125 } 2126 2127 // only update the solutions that we chose to calculate: 2128 if (mode & PM_SUBTRACTION_EQUATION_NORM) { 2129 int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation 2130 kernels->solution1->data.F64[normIndex] = solution->data.F64[normIndex]; 2131 } 2132 if (mode & PM_SUBTRACTION_EQUATION_BG) { 2133 int bgIndex = PM_SUBTRACTION_INDEX_BG(kernels); // Index in matrix for background 2134 kernels->solution1->data.F64[bgIndex] = solution->data.F64[bgIndex]; 2135 } 2136 if (mode & PM_SUBTRACTION_EQUATION_KERNELS) { 2137 int numKernels = kernels->num; 2138 int spatialOrder = kernels->spatialOrder; // Order of spatial variation 2139 int numPoly = PM_SUBTRACTION_POLYTERMS(spatialOrder); // Number of polynomial terms 2140 for (int i = 0; i < numKernels * numPoly; i++) { 2141 // XXX fprintf (stderr, "%f +/- %f (%f) -> ", solution->data.F64[i], solutionErr->data.F64[i], fabs(solution->data.F64[i]/solutionErr->data.F64[i])); 2142 if (fabs(solution->data.F64[i] / solutionErr->data.F64[i]) < COEFF_SIG) { 2143 // XXX fprintf (stderr, "drop\n"); 2144 kernels->solution1->data.F64[i] = 0.0; 2145 } else { 2146 // XXX fprintf (stderr, "keep\n"); 2147 kernels->solution1->data.F64[i] = solution->data.F64[i]; 2148 } 2149 } 2150 } 2151 // double chiSquare = p_pmSubSolve_ChiSquare (kernels, stamps); 2152 // fprintf (stderr, "chi square Brute = %f\n", chiSquare); 2153 2154 psFree(solution); 2155 psFree(sumVector); 2156 psFree(sumMatrix); 2157 # endif 2158 2159 #ifdef TESTING 2160 // XXX double-check for NAN in data: 2161 for (int iy = 0; iy < stamp->matrix->numRows; iy++) { 2162 for (int ix = 0; ix < stamp->matrix->numCols; ix++) { 2163 if (!isfinite(stamp->matrix->data.F64[iy][ix])) { 2164 fprintf (stderr, "WARNING: NAN in matrix\n"); 2165 } 2166 } 2167 } 2168 for (int ix = 0; ix < stamp->vector->n; ix++) { 2169 if (!isfinite(stamp->vector->data.F64[ix])) { 2170 fprintf (stderr, "WARNING: NAN in vector\n"); 2171 } 2172 } 2173 #endif 2174 2175 #ifdef TESTING 2176 for (int ix = 0; ix < sumVector->n; ix++) { 2177 if (!isfinite(sumVector->data.F64[ix])) { 2178 fprintf (stderr, "WARNING: NAN in vector\n"); 2179 } 2180 } 2181 #endif 2182 2183 #ifdef TESTING 2184 for (int ix = 0; ix < sumVector->n; ix++) { 2185 if (!isfinite(sumVector->data.F64[ix])) { 2186 fprintf (stderr, "WARNING: NAN in vector\n"); 2187 } 2188 } 2189 { 2190 psImage *inverse = psMatrixInvert(NULL, sumMatrix, NULL); 2191 psFitsWriteImageSimple("matrixInv.fits", inverse, NULL); 2192 psFree(inverse); 2193 } 2194 { 2195 psImage *X = psMatrixInvert(NULL, sumMatrix, NULL); 2196 psImage *Xt = psMatrixTranspose(NULL, X); 2197 psImage *XtX = psMatrixMultiply(NULL, Xt, X); 2198 psFitsWriteImageSimple("matrixErr.fits", XtX, NULL); 2199 psFree(X); 2200 psFree(Xt); 2201 psFree(XtX); 2202 } 2203 #endif 2204 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionEquation.h
r19299 r27840 4 4 #include "pmSubtractionStamps.h" 5 5 #include "pmSubtractionKernels.h" 6 7 typedef enum { 8 PM_SUBTRACTION_EQUATION_NONE = 0x00, 9 PM_SUBTRACTION_EQUATION_NORM = 0x01, 10 PM_SUBTRACTION_EQUATION_BG = 0x02, 11 PM_SUBTRACTION_EQUATION_KERNELS = 0x04, 12 PM_SUBTRACTION_EQUATION_ALL = 0x07, // value should be NORM | BG | KERNELS 13 } pmSubtractionEquationCalculationMode; 6 14 7 15 /// Execute a thread job to calculate the least-squares equation for a stamp … … 12 20 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, ///< Stamps 13 21 const pmSubtractionKernels *kernels, ///< Kernel parameters 14 int index ///< Index of stamp 15 ); 22 int index, ///< Index of stamp 23 const pmSubtractionEquationCalculationMode mode 24 ); 16 25 17 26 /// Calculate the least-squares equation to match the image quality 18 27 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, ///< Stamps 19 const pmSubtractionKernels *kernels ///< Kernel parameters 20 ); 28 const pmSubtractionKernels *kernels, ///< Kernel parameters 29 const pmSubtractionEquationCalculationMode mode 30 ); 21 31 22 32 /// Solve the least-squares equation to match the image quality 23 33 bool pmSubtractionSolveEquation(pmSubtractionKernels *kernels, ///< Kernel parameters 24 const pmSubtractionStampList *stamps ///< Stamps 34 const pmSubtractionStampList *stamps, ///< Stamps 35 const pmSubtractionEquationCalculationMode mode 25 36 ); 26 37 27 38 /// Calculate deviations 28 39 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, ///< Stamps 29 constpmSubtractionKernels *kernels ///< Kernel parameters40 pmSubtractionKernels *kernels ///< Kernel parameters 30 41 ); 31 42 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionIO.c
r23378 r27840 3 3 #include <string.h> 4 4 5 #include "pmErrorCodes.h" 5 6 #include "pmHDU.h" 6 7 #include "pmHDUUtils.h" … … 66 67 } 67 68 if (regions->n == 0) { 68 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "No subtraction regions found.");69 // We wrote everything we could find 69 70 psFree(regions); 70 return false;71 return true; 71 72 } 72 73 … … 80 81 while ((item = psMetadataGetAndIncrement(iter))) { 81 82 assert(item->type == PS_DATA_UNKNOWN); 82 // Set the normalisation dimensions, since these will be otherwise unavailable when reading the83 // images by scans.84 83 pmSubtractionKernels *kernel = item->data.V; // Kernel used in subtraction 85 kernel->numCols = ro->image->numCols;86 kernel->numRows = ro->image->numRows;87 88 84 kernels = psArrayAdd(kernels, ARRAY_BUFFER, kernel); 89 85 } … … 92 88 93 89 if (regions->n != kernels->n) { 94 psError(P S_ERR_BAD_PARAMETER_SIZE, true, "Number of regions (%ld) and kernels (%ld) don't match.\n",90 psError(PM_ERR_PROG, true, "Number of regions (%ld) and kernels (%ld) don't match.\n", 95 91 regions->n, kernels->n); 96 92 psFree(regions); … … 103 99 psArray *rows = psArrayAlloc(num); // Array of FITS table rows 104 100 for (int i = 0; i < num; i++) { 105 psMetadata *row = psMetadataAlloc(); // Row of interest 106 rows->data[i] = psMemIncrRefCounter(row); 101 psMetadata *row = rows->data[i] = psMetadataAlloc(); // Row of interest 107 102 108 103 psRegion *region = regions->data[i]; // Region of interest … … 126 121 kernel->bgOrder); 127 122 psMetadataAddS32(row, PS_LIST_TAIL, NAME_MODE, 0, "Matching mode (enum)", kernel->mode); 128 psMetadataAddS32(row, PS_LIST_TAIL, NAME_COLS, 0, "Number of columns", kernel->numCols);129 psMetadataAddS32(row, PS_LIST_TAIL, NAME_ROWS, 0, "Number of rows", kernel->numRows);130 123 if (kernel->mode == PM_SUBTRACTION_MODE_1 || kernel->mode == PM_SUBTRACTION_MODE_2) { 131 124 psMetadataAddVector(row, PS_LIST_TAIL, NAME_SOL1, 0, "Solution vector 1", kernel->solution1); … … 172 165 173 166 if (!psFitsWriteTable(fits, header, rows, EXTNAME_KERNEL)) { 174 psError( PS_ERR_IO, false, "Unable to write subtraction kernel to FITS table.");167 psError(psErrorCodeLast(), false, "Unable to write subtraction kernel to FITS table."); 175 168 psFree(header); 176 169 psFree(rows); … … 182 175 183 176 if (image && !psFitsWriteImage(fits, header, image, 0, EXTNAME_IMAGE)) { 184 psError( PS_ERR_IO, false, "Unable to write subtraction kernel image.");177 psError(psErrorCodeLast(), false, "Unable to write subtraction kernel image."); 185 178 psFree(header); 186 179 psFree(rows); … … 208 201 thisView->readout = i; 209 202 if (!pmReadoutWriteSubtractionKernels(readout, file->fits)) { 210 psError( PS_ERR_IO, false, "Failed to write %dth readout", i);203 psError(psErrorCodeLast(), false, "Failed to write %dth readout", i); 211 204 psFree(thisView); 212 205 return false; … … 231 224 thisView->cell = i; 232 225 if (!pmCellWriteSubtractionKernels(cell, thisView, file, config)) { 233 psError( PS_ERR_IO, false, "Failed to write %dth cell", i);226 psError(psErrorCodeLast(), false, "Failed to write %dth cell", i); 234 227 psFree(thisView); 235 228 return false; … … 254 247 thisView->chip = i; 255 248 if (!pmChipWriteSubtractionKernels(chip, thisView, file, config)) { 256 psError( PS_ERR_IO, false, "Failed to write %dth chip", i);249 psError(psErrorCodeLast(), false, "Failed to write %dth chip", i); 257 250 psFree(thisView); 258 251 return false; … … 272 265 273 266 if (!psFitsMoveExtName(fits, EXTNAME_KERNEL)) { 274 psError( PS_ERR_IO, false, "Unable to move to subtraction kernel table.");267 psError(psErrorCodeLast(), false, "Unable to move to subtraction kernel table."); 275 268 return false; 276 269 } … … 278 271 psArray *table = psFitsReadTable(fits); // Table of interest 279 272 if (!table) { 280 psError( PS_ERR_IO, false, "Unable to read FITS table");273 psError(psErrorCodeLast(), false, "Unable to read FITS table"); 281 274 return false; 282 275 } … … 289 282 TARGET = psMetadataLookup##SUFFIX(&mdok, row, NAME); \ 290 283 if (!mdok) { \ 291 psError(P S_ERR_UNKNOWN, false, "Unable to find column %s in subtraction kernel table.", NAME); \284 psError(PM_ERR_PROG, false, "Unable to find column %s in subtraction kernel table.", NAME); \ 292 285 psFree(table); \ 293 286 return false; \ … … 318 311 319 312 TABLE_LOOKUP(int, S32, bg, NAME_BG); 320 TABLE_LOOKUP(int, S32, numCols, NAME_COLS);321 TABLE_LOOKUP(int, S32, numRows, NAME_ROWS);322 313 323 314 TABLE_LOOKUP(float, F32, mean, NAME_MEAN); … … 325 316 TABLE_LOOKUP(int, S32, numStamps, NAME_NUMSTAMPS); 326 317 327 pmSubtractionKernels *kernels = pmSubtractionKernelsFromDescription(description, bg, mode); 328 kernels->numCols = numCols; 329 kernels->numRows = numRows; 318 pmSubtractionKernels *kernels = pmSubtractionKernelsFromDescription(description, bg, *region, mode); 330 319 kernels->mean = mean; 331 320 kernels->rms = rms; … … 336 325 kernels->solution1 = psMemIncrRefCounter(psMetadataLookupPtr(&mdok, row, NAME_SOL1)); 337 326 if (!mdok) { 338 psError(P S_ERR_UNKNOWN, false, "Unable to find column %s in subtraction kernel table.",327 psError(PM_ERR_PROG, false, "Unable to find column %s in subtraction kernel table.", 339 328 NAME_SOL1); 340 329 psFree(kernels); … … 346 335 kernels->solution1 = psMemIncrRefCounter(psMetadataLookupPtr(&mdok, row, NAME_SOL1)); 347 336 if (!mdok) { 348 psError(P S_ERR_UNKNOWN, false, "Unable to find column %s in subtraction kernel table.",337 psError(PM_ERR_PROG, false, "Unable to find column %s in subtraction kernel table.", 349 338 NAME_SOL1); 350 339 psFree(kernels); … … 354 343 kernels->solution2 = psMemIncrRefCounter(psMetadataLookupPtr(&mdok, row, NAME_SOL2)); 355 344 if (!mdok) { 356 psError(P S_ERR_UNKNOWN, false, "Unable to find column %s in subtraction kernel table.",345 psError(PM_ERR_PROG, false, "Unable to find column %s in subtraction kernel table.", 357 346 NAME_SOL2); 358 347 psFree(kernels); … … 390 379 pmReadout *readout = cell->readouts->data[i]; 391 380 thisView->readout = i; 392 pmReadoutReadSubtractionKernels(readout, file->fits); 381 if (!pmReadoutReadSubtractionKernels(readout, file->fits)) { 382 psError(psErrorCodeLast(), false, "Unable to read subtraction kernels from cell"); 383 psFree(thisView); 384 return false; 385 } 393 386 if (!readout->data_exists) { 394 387 continue; … … 421 414 pmCell *cell = chip->cells->data[i]; 422 415 thisView->cell = i; 423 pmCellReadSubtractionKernels(cell, thisView, file, config); 424 if (!cell->data_exists) { 416 if (!pmCellReadSubtractionKernels(cell, thisView, file, config)) { 417 psError(psErrorCodeLast(), false, "Unable to read subtraction kernels from cell"); 418 psFree(thisView); 419 return false; 420 } 421 if (!cell->data_exists) { 425 422 continue; 426 423 } … … 430 427 431 428 if (!pmConceptsReadChip(chip, PM_CONCEPT_SOURCE_HEADER, true, true, NULL)) { 432 psError( PS_ERR_IO, false, "Failed to read concepts for chip.\n");429 psError(psErrorCodeLast(), false, "Failed to read concepts for chip.\n"); 433 430 return false; 434 431 } … … 451 448 pmChip *chip = fpa->chips->data[i]; 452 449 thisView->chip = i; 453 pmChipReadSubtractionKernels(chip, thisView, file, config); 450 if (!pmChipReadSubtractionKernels(chip, thisView, file, config)) { 451 psError(psErrorCodeLast(), false, "Unable to read subtraction kernels from chip"); 452 psFree(thisView); 453 return false; 454 } 454 455 } 455 456 psFree(thisView); 456 457 457 458 if (!pmConceptsReadFPA(fpa, PM_CONCEPT_SOURCE_HEADER, true, NULL)) { 458 psError( PS_ERR_IO, false, "Failed to read concepts for fpa.\n");459 psError(psErrorCodeLast(), false, "Failed to read concepts for fpa.\n"); 459 460 return false; 460 461 } … … 475 476 if (view->chip == -1) { 476 477 if (!pmFPAWriteSubtractionKernels(fpa, view, file, config)) { 477 psError( PS_ERR_IO, false, "Failed to write subtraction kernels from fpa");478 psError(psErrorCodeLast(), false, "Failed to write subtraction kernels from fpa"); 478 479 psFree(fpa); 479 480 return false; … … 484 485 485 486 if (view->chip >= fpa->chips->n) { 486 psError(P S_ERR_UNKNOWN, false, "Writing chip == %d (>= chips->n == %ld)", view->chip, fpa->chips->n);487 psError(PM_ERR_PROG, true, "Writing chip == %d (>= chips->n == %ld)", view->chip, fpa->chips->n); 487 488 psFree(fpa); 488 489 return false; … … 492 493 if (view->cell == -1) { 493 494 if (!pmChipWriteSubtractionKernels(chip, view, file, config)) { 494 psError( PS_ERR_IO, false, "Failed to write objects from chip");495 psError(psErrorCodeLast(), false, "Failed to write objects from chip"); 495 496 psFree(fpa); 496 497 return false; … … 501 502 502 503 if (view->cell >= chip->cells->n) { 503 psError(P S_ERR_UNKNOWN, false, "Writing cell == %d (>= cells->n == %ld)",504 psError(PM_ERR_PROG, true, "Writing cell == %d (>= cells->n == %ld)", 504 505 view->cell, chip->cells->n); 505 506 psFree(fpa); … … 510 511 if (view->readout == -1) { 511 512 if (!pmCellWriteSubtractionKernels(cell, view, file, config)) { 512 psError( PS_ERR_IO, false, "Failed to write objects from cell");513 psError(psErrorCodeLast(), false, "Failed to write objects from cell"); 513 514 psFree(fpa); 514 515 return false; … … 519 520 520 521 if (view->readout >= cell->readouts->n) { 521 psError(P S_ERR_UNKNOWN, false, "Writing readout == %d (>= readouts->n == %ld)",522 psError(PM_ERR_PROG, true, "Writing readout == %d (>= readouts->n == %ld)", 522 523 view->readout, cell->readouts->n); 523 524 psFree(fpa); … … 527 528 528 529 if (!pmReadoutWriteSubtractionKernels(readout, file->fits)) { 529 psError( PS_ERR_IO, false, "Failed to write objects from readout %d", view->readout);530 psError(psErrorCodeLast(), false, "Failed to write objects from readout %d", view->readout); 530 531 psFree(fpa); 531 532 return false; -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionKernels.c
r24296 r27840 10 10 #include "pmSubtraction.h" 11 11 #include "pmSubtractionKernels.h" 12 #include "pmSubtractionHermitian.h" 13 #include "pmSubtractionDeconvolve.h" 14 #include "pmSubtractionVisual.h" 12 15 13 16 #define RINGS_BUFFER 10 // Buffer size for RINGS data 14 15 17 16 18 // Free function for pmSubtractionKernels … … 27 29 psFree(kernels->solution1); 28 30 psFree(kernels->solution2); 31 psFree(kernels->sampleStamps); 32 } 33 34 // Free function for pmSubtractionPreCalcKernel 35 static void pmSubtractionKernelPreCalcFree(pmSubtractionKernelPreCalc *kernel) 36 { 37 psFree(kernel->xKernel); 38 psFree(kernel->yKernel); 39 psFree(kernel->kernel); 40 41 psFree(kernel->uCoords); 42 psFree(kernel->vCoords); 43 psFree(kernel->poly); 29 44 } 30 45 … … 45 60 46 61 // Generate 1D convolution kernel for ISIS 47 static psVector *subtractionKernelISIS(float sigma, // Gaussian width62 psVector *pmSubtractionKernelISIS(float sigma, // Gaussian width 48 63 int order, // Polynomial order 49 64 int size // Kernel half-size … … 57 72 for (int i = 0, x = -size; x <= size; i++, x++) { 58 73 kernel->data.F32[i] = norm * power(x, order) * expf(expNorm * PS_SQR(x)); 74 } 75 76 return kernel; 77 } 78 79 // Generate 1D convolution kernel for HERM (normalized for 2D) 80 psVector *pmSubtractionKernelHERM(float sigma, // Gaussian width 81 int order, // Polynomial order 82 int size // Kernel half-size 83 ) 84 { 85 int fullSize = 2 * size + 1; // Full size of kernel 86 psVector *kernel = psVectorAlloc(fullSize, PS_TYPE_F32); // Kernel to return 87 88 // for now, we are only allowing equal orders and sigmas in X and Y 89 float nf = exp(lgamma(order + 1)); 90 float norm = 1.0 / sqrt(nf*sigma*sqrt(M_2_PI)); 91 92 for (int i = 0, x = -size; x <= size; i++, x++) { 93 float xf = x / sigma; 94 float z = -0.25*xf*xf; 95 kernel->data.F32[i] = norm * p_pmSubtractionHermitianPolynomial(xf, order) * exp(z); 96 } 97 98 return kernel; 99 } 100 101 // Generate 1D convolution kernel for HERM (normalized for 2D) 102 psKernel *pmSubtractionKernelHERM_RADIAL(float sigma, // Gaussian width 103 int order, // Polynomial order 104 int size // Kernel half-size 105 ) 106 { 107 psKernel *kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel 108 109 // for now, we are only allowing equal orders and sigmas in X and Y 110 float nf = exp(lgamma(order + 1)); 111 float norm = 1.0 / sqrt(nf*sigma*sqrt(M_2_PI)); 112 113 // generate 2D radial hermitian 114 for (int v = -size; v <= size; v++) { 115 for (int u = -size; u <= size; u++) { 116 float r = hypot(u, v) / sigma; 117 float z = -0.25*r*r; 118 kernel->kernel[v][u] = norm * p_pmSubtractionHermitianPolynomial(r, order) * exp(z); 119 } 59 120 } 60 121 … … 81 142 kernels->penalties = psVectorRealloc(kernels->penalties, start + numNew); 82 143 kernels->inner = start; 144 kernels->num += numNew; 83 145 84 146 // Generate a set of kernels for each (u,v) … … 94 156 kernels->v->data.S32[index] = v; 95 157 kernels->preCalc->data[index] = NULL; 96 kernels->penalties->data.F32[index] = kernels->penalty * (PS_SQR(u) + PS_SQR(v));97 158 kernels->penalties->data.F32[index] = kernels->penalty * PS_SQR(PS_SQR(u) + PS_SQR(v)); 159 psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty"); 98 160 psTrace("psModules.imcombine", 7, "Kernel %d: %d %d\n", index, u, v); 99 161 } 100 162 } 101 163 164 kernels->widths->n = start + numNew; 165 kernels->u->n = start + numNew; 166 kernels->v->n = start + numNew; 167 kernels->preCalc->n = start + numNew; 168 kernels->penalties->n = start + numNew; 169 102 170 return true; 103 171 } 104 172 173 bool pmSubtractionKernelPreCalcNormalize(pmSubtractionKernels *kernels, pmSubtractionKernelPreCalc *preCalc, 174 int index, int size, int uOrder, int vOrder, float fwhm, 175 bool AlardLuptonStyle, bool forceZeroNull) 176 { 177 // we have 4 cases here: 178 // 1) for odd functions, normalize the kernel by the maximum swing / Npix 179 // 2) for even functions, normalize the kernel to unity 180 // 3) for alard-lupton style normalization, subtract 1 from the 0,0 pixel for all even functions 181 // 4) for deconvolved hermitians, subtract 1 from the 0,0 pixel for the 0,0 function(s) 182 183 // Calculate moments 184 double penalty = 0.0; // Moment, for penalty 185 double sum = 0.0, sum2 = 0.0; // Sum of kernel component 186 float min = INFINITY, max = -INFINITY; // Minimum and maximum kernel value 187 for (int v = -size; v <= size; v++) { 188 for (int u = -size; u <= size; u++) { 189 double value = preCalc->kernel->kernel[v][u]; 190 double value2 = PS_SQR(value); 191 sum += value; 192 sum2 += value2; 193 penalty += value2 * PS_SQR((PS_SQR(u) + PS_SQR(v))); 194 min = PS_MIN(value, min); 195 max = PS_MAX(value, max); 196 } 197 } 198 199 #if 0 200 fprintf(stderr, "%d raw: %lf, null: %f, min: %lf, max: %lf, moment: %lf\n", index, sum, preCalc->kernel->kernel[0][0], min, max, penalty); 201 #endif 202 203 bool zeroNull = false; // Zero out using the null position? 204 float scale2D = NAN; // Scaling for 2-D kernels 205 206 if (AlardLuptonStyle) { 207 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 208 // Even functions: normalise to unit sum and subtract null pixel so that sum is zero 209 scale2D = 1.0 / fabs(sum); 210 zeroNull = true; 211 } else { 212 // Odd functions: choose normalisation so that parameters have about the same strength as for even 213 // functions, no subtraction of null pixel because the sum is already (near) zero 214 scale2D = 1.0 / sqrt(sum2); 215 zeroNull = false; 216 } 217 } 218 219 if (!AlardLuptonStyle && (uOrder == 0 && vOrder == 0)) { 220 zeroNull = true; 221 } 222 if (forceZeroNull) { 223 // Force rescaling and subtraction of null pixel even though the order doesn't indicate it's even 224 scale2D = 1.0 / fabs(sum); 225 zeroNull = true; 226 } 227 if (!forceZeroNull && ((uOrder % 2) || (vOrder % 2))) { 228 // Odd function 229 scale2D = 1.0 / sqrt(sum2); 230 } 231 232 float scale1D = sqrtf(scale2D); // Scaling for 1-D kernels 233 if (preCalc->xKernel) { 234 psBinaryOp(preCalc->xKernel, preCalc->xKernel, "*", psScalarAlloc(scale1D, PS_TYPE_F32)); 235 } 236 if (preCalc->yKernel) { 237 psBinaryOp(preCalc->yKernel, preCalc->yKernel, "*", psScalarAlloc(scale1D, PS_TYPE_F32)); 238 } 239 240 psBinaryOp(preCalc->kernel->image, preCalc->kernel->image, "*", psScalarAlloc(scale2D, PS_TYPE_F32)); 241 penalty *= 1.0 / sum2; 242 243 if (zeroNull) { 244 preCalc->kernel->kernel[0][0] -= 1.0; 245 } 246 247 #if 0 248 { 249 double sum = 0.0; // Sum of kernel component 250 float min = INFINITY, max = -INFINITY; // Minimum and maximum kernel value 251 for (int v = -size; v <= size; v++) { 252 for (int u = -size; u <= size; u++) { 253 sum += preCalc->kernel->kernel[v][u]; 254 min = PS_MIN(preCalc->kernel->kernel[v][u], min); 255 max = PS_MAX(preCalc->kernel->kernel[v][u], max); 256 } 257 } 258 fprintf(stderr, "%d mod: %lf, null: %f, min: %lf, max: %lf, scale: %f\n", index, sum, preCalc->kernel->kernel[0][0], min, max, scale2D); 259 } 260 #endif 261 262 kernels->widths->data.F32[index] = fwhm; 263 kernels->u->data.S32[index] = uOrder; 264 kernels->v->data.S32[index] = vOrder; 265 if (kernels->preCalc->data[index]) { 266 psFree(kernels->preCalc->data[index]); 267 } 268 kernels->preCalc->data[index] = preCalc; 269 kernels->penalties->data.F32[index] = kernels->penalty * penalty; 270 psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty"); 271 psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index, fwhm, uOrder, vOrder, penalty); 272 273 return true; 274 } 275 105 276 pmSubtractionKernels *p_pmSubtractionKernelsRawISIS(int size, int spatialOrder, 106 const psVector *fwhms , const psVector *orders,107 float penalty, p mSubtractionMode mode)108 { 109 PS_ASSERT_VECTOR_NON_NULL(fwhms , NULL);110 PS_ASSERT_VECTOR_TYPE(fwhms , PS_TYPE_F32, NULL);111 PS_ASSERT_VECTOR_NON_NULL(orders , NULL);112 PS_ASSERT_VECTOR_TYPE(orders , PS_TYPE_S32, NULL);113 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhms , orders, NULL);277 const psVector *fwhmsIN, const psVector *ordersIN, 278 float penalty, psRegion bounds, pmSubtractionMode mode) 279 { 280 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 281 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 282 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 283 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 284 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 114 285 PS_ASSERT_INT_POSITIVE(size, NULL); 115 286 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 287 288 // check the requested fwhm values: any values <= 0.0 should be dropped 289 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 290 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 291 for (int i = 0; i < fwhmsIN->n; i++) { 292 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 293 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 294 psVectorAppend(orders, ordersIN->data.S32[i]); 295 } 116 296 117 297 int numGaussians = fwhms->n; // Number of Gaussians … … 126 306 127 307 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS, size, 128 spatialOrder, penalty, mode); // The kernels308 spatialOrder, penalty, bounds, mode); // Kernels 129 309 psStringAppend(&kernels->description, "ISIS(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 130 310 … … 134 314 135 315 // Set the kernel parameters 136 int fullSize = 2 * size + 1; // Full size of kernels137 316 for (int i = 0, index = 0; i < numGaussians; i++) { 138 317 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma … … 140 319 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 141 320 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 142 psArray *preCalc = psArrayAlloc(2); // Array to hold precalculated values 143 psVector *xKernel = preCalc->data[0] = subtractionKernelISIS(sigma, uOrder, size); // x Kernel 144 psVector *yKernel = preCalc->data[1] = subtractionKernelISIS(sigma, vOrder, size); // y Kernel 145 146 // Calculate moments 147 double moment = 0.0; // Moment, for penalty 148 for (int v = -size, y = 0; v <= size; v++, y++) { 149 for (int u = -size, x = 0; u <= size; u++, x++) { 150 double value = xKernel->data.F32[x] * yKernel->data.F32[y]; // Value of kernel 151 moment += value * (PS_SQR(u) + PS_SQR(v)); 152 } 321 322 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values 323 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 324 // pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], false, false); 325 } 326 } 327 } 328 329 psFree(orders); 330 psFree(fwhms); 331 332 return kernels; 333 } 334 335 pmSubtractionKernels *pmSubtractionKernelsISIS_RADIAL(int size, int spatialOrder, 336 const psVector *fwhmsIN, const psVector *ordersIN, 337 float penalty, psRegion bounds, pmSubtractionMode mode) 338 { 339 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 340 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 341 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 342 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 343 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 344 PS_ASSERT_INT_POSITIVE(size, NULL); 345 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 346 347 // check the requested fwhm values: any values <= 0.0 should be dropped 348 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 349 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 350 for (int i = 0; i < fwhmsIN->n; i++) { 351 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 352 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 353 psVectorAppend(orders, ordersIN->data.S32[i]); 354 } 355 356 int numGaussians = fwhms->n; // Number of Gaussians 357 358 int num = 0; // Number of basis functions 359 psString params = NULL; // List of parameters 360 for (int i = 0; i < numGaussians; i++) { 361 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 362 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 363 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 364 num += (11 - gaussOrder - 1); // include all higher order radial terms 365 } 366 367 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS_RADIAL, size, 368 spatialOrder, penalty, bounds, mode); // Kernels 369 psStringAppend(&kernels->description, "ISIS_RADIAL(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 370 371 psLogMsg("psModules.imcombine", PS_LOG_INFO, "ISIS_RADIAL kernel: %s,%d --> %d elements", params, spatialOrder, num); 372 psFree(params); 373 374 // Set the kernel parameters 375 for (int i = 0, index = 0; i < numGaussians; i++) { 376 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 377 // Iterate over (u,v) order 378 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 379 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 380 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values 381 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 382 } 383 } 384 for (int order = orders->data.S32[i] + 1; order < 11; order ++, index ++) { 385 // XXX modify size for hermitians to account for sqrt(2) in Hermitian definition (relative to ISIS Gaussian) 386 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS_RADIAL, order, order, size, sigma / sqrt(2.0)); // structure to hold precalculated values 387 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, order, order, fwhms->data.F32[i], true, true); 388 } 389 } 390 return kernels; 391 } 392 393 pmSubtractionKernels *pmSubtractionKernelsHERM(int size, int spatialOrder, 394 const psVector *fwhmsIN, const psVector *ordersIN, 395 float penalty, psRegion bounds, pmSubtractionMode mode) 396 { 397 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 398 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 399 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 400 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 401 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 402 PS_ASSERT_INT_POSITIVE(size, NULL); 403 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 404 405 // check the requested fwhm values: any values <= 0.0 should be dropped 406 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 407 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 408 for (int i = 0; i < fwhmsIN->n; i++) { 409 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 410 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 411 psVectorAppend(orders, ordersIN->data.S32[i]); 412 } 413 414 int numGaussians = fwhms->n; // Number of Gaussians 415 416 int num = 0; // Number of basis functions 417 psString params = NULL; // List of parameters 418 for (int i = 0; i < numGaussians; i++) { 419 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 420 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 421 num += (gaussOrder + 1) * (gaussOrder + 2) / 2; 422 } 423 424 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_HERM, size, 425 spatialOrder, penalty, bounds, mode); // Kernels 426 psStringAppend(&kernels->description, "HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 427 428 psLogMsg("psModules.imcombine", PS_LOG_INFO, "HERM kernel: %s,%d --> %d elements", 429 params, spatialOrder, num); 430 psFree(params); 431 432 // Set the kernel parameters 433 for (int i = 0, index = 0; i < numGaussians; i++) { 434 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 435 // Iterate over (u,v) order 436 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 437 for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) { 438 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values 439 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 440 } 441 } 442 } 443 444 return kernels; 445 } 446 447 pmSubtractionKernels *pmSubtractionKernelsDECONV_HERM(int size, int spatialOrder, 448 const psVector *fwhmsIN, const psVector *ordersIN, 449 float penalty, psRegion bounds, pmSubtractionMode mode) 450 { 451 PS_ASSERT_VECTOR_NON_NULL(fwhmsIN, NULL); 452 PS_ASSERT_VECTOR_TYPE(fwhmsIN, PS_TYPE_F32, NULL); 453 PS_ASSERT_VECTOR_NON_NULL(ordersIN, NULL); 454 PS_ASSERT_VECTOR_TYPE(ordersIN, PS_TYPE_S32, NULL); 455 PS_ASSERT_VECTORS_SIZE_EQUAL(fwhmsIN, ordersIN, NULL); 456 PS_ASSERT_INT_POSITIVE(size, NULL); 457 PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL); 458 459 // check the requested fwhm values: any values <= 0.0 should be dropped 460 psVector *fwhms = psVectorAllocEmpty (fwhmsIN->n, PS_TYPE_F32); 461 psVector *orders = psVectorAllocEmpty (ordersIN->n, PS_TYPE_S32); 462 for (int i = 0; i < fwhmsIN->n; i++) { 463 if (fwhmsIN->data.F32[i] <= FLT_EPSILON) continue; 464 psVectorAppend(fwhms, fwhmsIN->data.F32[i]); 465 psVectorAppend(orders, ordersIN->data.S32[i]); 466 } 467 468 int numGaussians = fwhms->n; // Number of Gaussians 469 470 int num = 0; // Number of basis functions 471 psString params = NULL; // List of parameters 472 for (int i = 0; i < numGaussians; i++) { 473 int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian 474 psStringAppend(¶ms, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]); 475 num += PS_SQR(gaussOrder + 1); 476 } 477 478 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_DECONV_HERM, size, 479 spatialOrder, penalty, bounds, mode); // Kernels 480 psStringAppend(&kernels->description, "DECONV_HERM(%d,%s,%d,%.2e)", size, params, spatialOrder, penalty); 481 482 psLogMsg("psModules.imcombine", PS_LOG_INFO, "DECONVOLVED HERM kernel: %s,%d --> %d elements", params, spatialOrder, num); 483 psFree(params); 484 485 // XXXXX hard-wired reference sigma for now of 1.7 pix (== 4.0 pix fwhm == 1.0 arcsec in simtest) 486 // generate the Gaussian deconvolution kernel 487 # define DECONV_SIGMA 1.6 488 psKernel *kernelGauss = pmSubtractionDeconvolveGauss (size, DECONV_SIGMA); 489 490 # if 1 491 psArray *deconKernels = psArrayAllocEmpty(100); 492 # endif 493 494 // Set the kernel parameters 495 for (int i = 0, index = 0; i < numGaussians; i++) { 496 float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma 497 // Iterate over (u,v) order 498 for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) { 499 for (int vOrder = 0; vOrder <= orders->data.S32[i]; vOrder++, index++) { 500 501 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values 502 503 // save the generated 2D kernel as the target, deconvolve it by Gaussian, replacing the generated 2D kernel 504 psKernel *kernelTarget = preCalc->kernel; 505 preCalc->kernel = pmSubtractionDeconvolveKernel(kernelTarget, kernelGauss); // Kernel 506 507 // XXX do we use Alard-Lupton normalization (last param true) or not? 508 pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false); 509 510 // XXXX test demo that deconvolved kernel is valid 511 # if 1 512 psImage *kernelConv = psImageConvolveFFT(NULL, preCalc->kernel->image, NULL, 0, kernelGauss); 513 psArrayAdd (deconKernels, 100, kernelConv); 514 psFree (kernelConv); 515 516 if (!uOrder && !vOrder){ 517 pmSubtractionVisualShowSubtraction (kernelTarget->image, preCalc->kernel->image, kernelConv); 153 518 } 154 155 // Normalise sum of kernel component to unity for even functions 156 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 157 double sum = 0.0; // Sum of kernel component 158 for (int v = 0; v < fullSize; v++) { 159 for (int u = 0; u < fullSize; u++) { 160 sum += xKernel->data.F32[u] * yKernel->data.F32[v]; 161 } 162 } 163 sum = 1.0 / sqrt(sum); 164 psBinaryOp(xKernel, xKernel, "*", psScalarAlloc(sum, PS_TYPE_F32)); 165 psBinaryOp(yKernel, yKernel, "*", psScalarAlloc(sum, PS_TYPE_F32)); 166 moment *= PS_SQR(sum); 519 # endif 520 } 521 } 522 } 523 524 # if 1 525 psImage *dot = psImageAlloc(deconKernels->n, deconKernels->n, PS_TYPE_F32); 526 for (int i = 0; i < deconKernels->n; i++) { 527 for (int j = 0; j <= i; j++) { 528 psImage *t1 = deconKernels->data[i]; 529 psImage *t2 = deconKernels->data[j]; 530 531 double sum = 0.0; 532 for (int iy = 0; iy < t1->numRows; iy++) { 533 for (int ix = 0; ix < t1->numCols; ix++) { 534 sum += t1->data.F32[iy][ix] * t2->data.F32[iy][ix]; 167 535 } 168 169 kernels->widths->data.F32[index] = fwhms->data.F32[i];170 kernels->u->data.S32[index] = uOrder;171 kernels->v->data.S32[index] = vOrder;172 if (kernels->preCalc->data[index]) {173 psFree(kernels->preCalc->data[index]);174 }175 kernels->preCalc->data[index] = preCalc;176 kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment);177 178 psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index,179 fwhms->data.F32[i], uOrder, vOrder, fabsf(moment));180 536 } 181 } 182 } 537 dot->data.F32[j][i] = sum; 538 dot->data.F32[i][j] = sum; 539 } 540 } 541 pmSubtractionVisualShowSubtraction (dot, NULL, NULL); 542 psFree (dot); 543 psFree (deconKernels); 544 # endif 183 545 184 546 return kernels; … … 190 552 191 553 pmSubtractionKernels *pmSubtractionKernelsAlloc(int numBasisFunctions, pmSubtractionKernelsType type, 192 int size, int spatialOrder, float penalty, 554 int size, int spatialOrder, float penalty, psRegion bounds, 193 555 pmSubtractionMode mode) 194 556 { … … 202 564 kernels->v = psVectorAlloc(numBasisFunctions, PS_TYPE_S32); 203 565 kernels->widths = psVectorAlloc(numBasisFunctions, PS_TYPE_F32); 566 kernels->uStop = NULL; 567 kernels->vStop = NULL; 568 kernels->xMin = bounds.x0; 569 kernels->xMax = bounds.x1; 570 kernels->yMin = bounds.y0; 571 kernels->yMax = bounds.y1; 204 572 kernels->preCalc = psArrayAlloc(numBasisFunctions); 205 573 kernels->penalty = penalty; 206 574 kernels->penalties = psVectorAlloc(numBasisFunctions, PS_TYPE_F32); 207 kernels->uStop = NULL;208 kernels->vStop = NULL;209 575 kernels->size = size; 210 576 kernels->inner = 0; … … 212 578 kernels->bgOrder = 0; 213 579 kernels->mode = mode; 214 kernels->numCols = 0;215 kernels->numRows = 0;216 580 kernels->solution1 = NULL; 217 581 kernels->solution2 = NULL; 582 kernels->mean = NAN; 583 kernels->rms = NAN; 584 kernels->numStamps = 0; 585 kernels->sampleStamps = NULL; 586 587 kernels->fSigResMean = NAN; 588 kernels->fSigResStdev = NAN; 589 kernels->fMaxResMean = NAN; 590 kernels->fMaxResStdev = NAN; 591 kernels->fMinResMean = NAN; 592 kernels->fMinResStdev = NAN; 218 593 219 594 return kernels; 220 595 } 221 596 222 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty, 597 pmSubtractionKernelPreCalc *pmSubtractionKernelPreCalcAlloc(pmSubtractionKernelsType type, int uOrder, int vOrder, int size, float sigma) { 598 599 pmSubtractionKernelPreCalc *preCalc = psAlloc(sizeof(pmSubtractionKernelPreCalc)); // Kernels, to return 600 psMemSetDeallocator(preCalc, (psFreeFunc)pmSubtractionKernelPreCalcFree); 601 602 // 1D kernel realizations: 603 switch (type) { 604 case PM_SUBTRACTION_KERNEL_ISIS: 605 preCalc->xKernel = pmSubtractionKernelISIS(sigma, uOrder, size); 606 preCalc->yKernel = pmSubtractionKernelISIS(sigma, vOrder, size); 607 preCalc->uCoords = NULL; 608 preCalc->vCoords = NULL; 609 preCalc->poly = NULL; 610 break; 611 case PM_SUBTRACTION_KERNEL_HERM: 612 preCalc->xKernel = pmSubtractionKernelHERM(sigma, uOrder, size); 613 preCalc->yKernel = pmSubtractionKernelHERM(sigma, vOrder, size); 614 preCalc->uCoords = NULL; 615 preCalc->vCoords = NULL; 616 preCalc->poly = NULL; 617 break; 618 case PM_SUBTRACTION_KERNEL_RINGS: 619 // the RINGS kernel uses the uCoords, vCoords, and poly elements of the structure 620 // we allocate these vectors here, but leave the kernel generation to the main function 621 preCalc->xKernel = NULL; 622 preCalc->yKernel = NULL; 623 preCalc->kernel = NULL; 624 preCalc->uCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // u coords 625 preCalc->vCoords = psVectorAllocEmpty(size, PS_TYPE_S32); // v coords 626 preCalc->poly = psVectorAllocEmpty(size, PS_TYPE_F32); // Polynomial 627 return preCalc; 628 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 629 preCalc->kernel = pmSubtractionKernelHERM_RADIAL(sigma, uOrder, size); 630 preCalc->xKernel = NULL; 631 preCalc->yKernel = NULL; 632 preCalc->uCoords = NULL; 633 preCalc->vCoords = NULL; 634 preCalc->poly = NULL; 635 return preCalc; 636 default: 637 psAbort("programming error: invalid type for PreCalc kernel"); 638 } 639 640 preCalc->kernel = psKernelAlloc(-size, size, -size, size); // 2D Kernel 641 642 // generate 2D kernel from 1D realizations 643 for (int v = -size, y = 0; v <= size; v++, y++) { 644 for (int u = -size, x = 0; u <= size; u++, x++) { 645 preCalc->kernel->kernel[v][u] = preCalc->xKernel->data.F32[x] * preCalc->yKernel->data.F32[y]; // Value of kernel 646 } 647 } 648 649 return preCalc; 650 } 651 652 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, float penalty, psRegion bounds, 223 653 pmSubtractionMode mode) 224 654 { … … 228 658 int num = PS_SQR(2 * size + 1) - 1; // Number of basis functions 229 659 230 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc( num, PM_SUBTRACTION_KERNEL_POIS, size,231 spatialOrder, penalty, mode); // The kernels660 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(0, PM_SUBTRACTION_KERNEL_POIS, size, 661 spatialOrder, penalty, bounds, mode); // Kernels 232 662 psStringAppend(&kernels->description, "POIS(%d,%d,%.2e)", size, spatialOrder, penalty); 233 663 psLogMsg("psModules.imcombine", PS_LOG_INFO, "POIS kernel: %d,%d --> %d elements", … … 244 674 pmSubtractionKernels *pmSubtractionKernelsISIS(int size, int spatialOrder, 245 675 const psVector *fwhms, const psVector *orders, 246 float penalty, p mSubtractionMode mode)676 float penalty, psRegion bounds, pmSubtractionMode mode) 247 677 { 248 678 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 249 penalty, mode); // Kernels679 penalty, bounds, mode); // Kernels 250 680 if (!kernels) { 251 681 return NULL; … … 256 686 257 687 pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, int spatialOrder, int inner, int binning, 258 float penalty, p mSubtractionMode mode)688 float penalty, psRegion bounds, pmSubtractionMode mode) 259 689 { 260 690 PS_ASSERT_INT_POSITIVE(size, NULL); … … 277 707 278 708 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM, size, 279 spatialOrder, penalty, mode); // The kernels709 spatialOrder, penalty, bounds, mode); // Kernels 280 710 kernels->inner = inner; 281 711 psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d,%.2e)", size, inner, binning, spatialOrder, … … 348 778 349 779 pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, int spatialOrder, int inner, float penalty, 350 p mSubtractionMode mode)780 psRegion bounds, pmSubtractionMode mode) 351 781 { 352 782 PS_ASSERT_INT_POSITIVE(size, NULL); … … 375 805 376 806 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES, size, 377 spatialOrder, penalty, mode); // The kernels807 spatialOrder, penalty, bounds, mode); // Kernels 378 808 kernels->inner = inner; 379 809 psStringAppend(&kernels->description, "FRIES(%d,%d,%d,%.2e)", size, inner, spatialOrder, penalty); … … 441 871 } 442 872 443 // Grid United with Normal Kernel 873 // Grid United with Normal Kernel [description: GUNK=ISIS(...)+POIS(...)] 444 874 pmSubtractionKernels *pmSubtractionKernelsGUNK(int size, int spatialOrder, const psVector *fwhms, 445 875 const psVector *orders, int inner, float penalty, 446 p mSubtractionMode mode)876 psRegion bounds, pmSubtractionMode mode) 447 877 { 448 878 PS_ASSERT_INT_POSITIVE(size, NULL); … … 456 886 PS_ASSERT_INT_LESS_THAN(inner, size, NULL); 457 887 458 // XXX GUNK doesn't seem to work --- doesn't add the POIS components, or at least, they're not noticed459 460 888 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 461 penalty, mode); // Kernels 889 penalty, bounds, mode); // Kernels 890 kernels->type = PM_SUBTRACTION_KERNEL_GUNK; 462 891 psStringPrepend(&kernels->description, "GUNK="); 463 892 psStringAppend(&kernels->description, "+POIS(%d,%d)", inner, spatialOrder); … … 474 903 // RINGS --- just what it says 475 904 pmSubtractionKernels *pmSubtractionKernelsRINGS(int size, int spatialOrder, int inner, int ringsOrder, 476 float penalty, p mSubtractionMode mode)905 float penalty, psRegion bounds, pmSubtractionMode mode) 477 906 { 478 907 PS_ASSERT_INT_POSITIVE(size, NULL); … … 505 934 506 935 pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS, size, 507 spatialOrder, penalty, mode); // The kernels936 spatialOrder, penalty, bounds, mode); // Kernels 508 937 kernels->inner = inner; 509 938 psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d,%.2e)", size, inner, ringsOrder, spatialOrder, … … 545 974 for (int vOrder = 0; vOrder <= (i == 0 ? 0 : ringsOrder - uOrder); vOrder++, index++) { 546 975 547 psArray *data = psArrayAlloc(3); // Container for data 548 psVector *uCoords = data->data[0] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // u coords 549 psVector *vCoords = data->data[1] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_S32); // v coords 550 psVector *poly = data->data[2] = psVectorAllocEmpty(RINGS_BUFFER, PS_TYPE_F32); // Polynomial 976 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc (PM_SUBTRACTION_KERNEL_RINGS, 0, 0, RINGS_BUFFER, 0.0); 551 977 double moment = 0.0; // Moment, for penalty 552 978 553 979 if (i == 0) { 554 980 // Central pixel is easy 555 uCoords->data.S32[0] = vCoords->data.S32[0] = 0; 556 poly->data.F32[0] = 1.0; 557 uCoords->n = vCoords->n = poly->n = 1; 981 preCalc->uCoords->data.S32[0] = 0; 982 preCalc->vCoords->data.S32[0] = 0; 983 preCalc->poly->data.F32[0] = 1.0; 984 preCalc->uCoords->n = 1; 985 preCalc->vCoords->n = 1; 986 preCalc->poly->n = 1; 558 987 radiusLast = 0; 559 988 moment = 0.0; … … 573 1002 float polyVal = uPoly * vPoly; // Value of polynomial 574 1003 if (polyVal != 0) { // No point adding it otherwise 575 uCoords->data.S32[j] = u;576 vCoords->data.S32[j] = v;577 p oly->data.F32[j] = polyVal;1004 preCalc->uCoords->data.S32[j] = u; 1005 preCalc->vCoords->data.S32[j] = v; 1006 preCalc->poly->data.F32[j] = polyVal; 578 1007 norm += polyVal; 579 moment += polyVal *(PS_SQR(u) + PS_SQR(v));580 581 psVectorExtend( uCoords, RINGS_BUFFER, 1);582 psVectorExtend( vCoords, RINGS_BUFFER, 1);583 psVectorExtend(p oly, RINGS_BUFFER, 1);1008 moment += PS_SQR(polyVal) * PS_SQR(PS_SQR(u) + PS_SQR(v)); 1009 1010 psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1); 1011 psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1); 1012 psVectorExtend(preCalc->poly, RINGS_BUFFER, 1); 584 1013 psTrace("psModules.imcombine", 9, "u = %d, v = %d, poly = %f\n", 585 u, v, p oly->data.F32[j]);1014 u, v, preCalc->poly->data.F32[j]); 586 1015 j++; 587 1016 } … … 591 1020 // Normalise kernel component to unit sum 592 1021 if (uOrder % 2 == 0 && vOrder % 2 == 0) { 593 psBinaryOp(p oly,poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));1022 psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32)); 594 1023 // Add subtraction of 0,0 component to preserve photometric scaling 595 uCoords->data.S32[j] = 0;596 vCoords->data.S32[j] = 0;597 p oly->data.F32[j] = -1.0;598 psVectorExtend( uCoords, RINGS_BUFFER, 1);599 psVectorExtend( vCoords, RINGS_BUFFER, 1);600 psVectorExtend(p oly, RINGS_BUFFER, 1);1024 preCalc->uCoords->data.S32[j] = 0; 1025 preCalc->vCoords->data.S32[j] = 0; 1026 preCalc->poly->data.F32[j] = -1.0; 1027 psVectorExtend(preCalc->uCoords, RINGS_BUFFER, 1); 1028 psVectorExtend(preCalc->vCoords, RINGS_BUFFER, 1); 1029 psVectorExtend(preCalc->poly, RINGS_BUFFER, 1); 601 1030 } else { 602 1031 norm = powf(size, uOrder) * powf(size, vOrder); 603 psBinaryOp(p oly,poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32));1032 psBinaryOp(preCalc->poly, preCalc->poly, "*", psScalarAlloc(1.0 / norm, PS_TYPE_F32)); 604 1033 } 605 // moment /= norm;1034 moment /= PS_SQR(norm); 606 1035 } 607 1036 608 psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", uCoords->n);609 610 kernels->preCalc->data[index] = data;1037 psTrace("psModules.imcombine", 8, "%ld pixels in kernel\n", preCalc->uCoords->n); 1038 1039 kernels->preCalc->data[index] = preCalc; 611 1040 kernels->u->data.S32[index] = uOrder; 612 1041 kernels->v->data.S32[index] = vOrder; 613 1042 kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment); 1043 if (!isfinite(kernels->penalties->data.F32[index])) { 1044 psAbort ("invalid penalty"); 1045 } 614 1046 615 1047 psTrace("psModules.imcombine", 7, "Kernel %d: %d %d %d\n", index, … … 624 1056 pmSubtractionKernels *pmSubtractionKernelsGenerate(pmSubtractionKernelsType type, int size, int spatialOrder, 625 1057 const psVector *fwhms, const psVector *orders, int inner, 626 int binning, int ringsOrder, float penalty, 1058 int binning, int ringsOrder, float penalty, psRegion bounds, 627 1059 pmSubtractionMode mode) 628 1060 { 629 1061 switch (type) { 630 1062 case PM_SUBTRACTION_KERNEL_POIS: 631 return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, mode);1063 return pmSubtractionKernelsPOIS(size, spatialOrder, penalty, bounds, mode); 632 1064 case PM_SUBTRACTION_KERNEL_ISIS: 633 return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, mode); 1065 return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1066 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 1067 return pmSubtractionKernelsISIS_RADIAL(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1068 case PM_SUBTRACTION_KERNEL_HERM: 1069 return pmSubtractionKernelsHERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 1070 case PM_SUBTRACTION_KERNEL_DECONV_HERM: 1071 return pmSubtractionKernelsDECONV_HERM(size, spatialOrder, fwhms, orders, penalty, bounds, mode); 634 1072 case PM_SUBTRACTION_KERNEL_SPAM: 635 return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, mode);1073 return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, penalty, bounds, mode); 636 1074 case PM_SUBTRACTION_KERNEL_FRIES: 637 return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, mode);1075 return pmSubtractionKernelsFRIES(size, spatialOrder, inner, penalty, bounds, mode); 638 1076 case PM_SUBTRACTION_KERNEL_GUNK: 639 return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, mode);1077 return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, penalty, bounds, mode); 640 1078 case PM_SUBTRACTION_KERNEL_RINGS: 641 return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, mode);1079 return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, penalty, bounds, mode); 642 1080 default: 643 1081 psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unknown kernel type: %x", type); … … 675 1113 676 1114 pmSubtractionKernels *pmSubtractionKernelsFromDescription(const char *description, int bgOrder, 677 p mSubtractionMode mode)1115 psRegion bounds, pmSubtractionMode mode) 678 1116 { 679 1117 PS_ASSERT_STRING_NON_EMPTY(description, NULL); … … 694 1132 float penalty = 0.0; // Penalty for wideness 695 1133 696 if (strncmp(description, "ISIS", 4) == 0) { 697 // XXX Support for GUNK 698 if (strstr(description, "+POIS")) { 699 type = PM_SUBTRACTION_KERNEL_GUNK; 700 psAbort("Deciphering GUNK kernels (%s) is not currently supported.", description); 701 } else { 702 type = PM_SUBTRACTION_KERNEL_ISIS; 703 char *ptr = (char*)description + 5; // Eat "ISIS(" 704 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 705 706 // Count the number of Gaussians 707 int numGauss = 0; 708 for (char *string = ptr; string; string = strchr(string + 1, '(')) { 709 numGauss++; 710 } 711 712 fwhms = psVectorAlloc(numGauss, PS_TYPE_F32); 713 orders = psVectorAlloc(numGauss, PS_TYPE_S32); 714 715 for (int i = 0; i < numGauss; i++) { 716 ptr++; // Eat the '(' 717 PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234," 718 PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt); // Eat "3)" 719 } 720 721 ptr++; // Eat ',' 722 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 723 penalty = parseStringFloat(ptr); 724 } 725 } else if (strncmp(description, "RINGS", 5) == 0) { 726 type = PM_SUBTRACTION_KERNEL_RINGS; 727 char *ptr = (char*)description + 6; 1134 // currently known descriptions: 1135 // ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...), SPAM(...), 1136 // FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...), 1137 // the descriptive name is the set of characters before the ( 1138 1139 type = pmSubtractionKernelsTypeFromString (description); 1140 char *ptr = strchr(description, '(') + 1; 1141 psAssert (ptr, "description is missing kernel parameters"); 1142 1143 switch (type) { 1144 case PM_SUBTRACTION_KERNEL_ISIS: 1145 case PM_SUBTRACTION_KERNEL_ISIS_RADIAL: 1146 case PM_SUBTRACTION_KERNEL_HERM: 1147 case PM_SUBTRACTION_KERNEL_DECONV_HERM: 1148 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 1149 1150 // Count the number of Gaussians 1151 int numGauss = 0; 1152 for (char *string = ptr; string; string = strchr(string + 1, '(')) { 1153 numGauss++; 1154 } 1155 1156 fwhms = psVectorAlloc(numGauss, PS_TYPE_F32); 1157 orders = psVectorAlloc(numGauss, PS_TYPE_S32); 1158 1159 for (int i = 0; i < numGauss; i++) { 1160 ptr++; // Eat the '(' 1161 PARSE_STRING_NUMBER(fwhms->data.F32[i], ptr, ',', parseStringFloat); // Eat "1.234," 1162 PARSE_STRING_NUMBER(orders->data.S32[i], ptr, ')', parseStringInt); // Eat "3)" 1163 } 1164 1165 ptr++; // Eat ',' 1166 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 1167 penalty = parseStringFloat(ptr); 1168 break; 1169 case PM_SUBTRACTION_KERNEL_RINGS: 728 1170 PARSE_STRING_NUMBER(size, ptr, ',', parseStringInt); 729 1171 PARSE_STRING_NUMBER(inner, ptr, ',', parseStringInt); … … 731 1173 PARSE_STRING_NUMBER(spatialOrder, ptr, ',', parseStringInt); 732 1174 PARSE_STRING_NUMBER(penalty, ptr, ')', parseStringInt); 733 } else { 734 psAbort("Deciphering kernels other than ISIS and RINGS is not currently supported."); 735 } 736 737 738 return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders, 739 inner, binning, ringsOrder, penalty, mode); 740 } 741 742 1175 break; 1176 default: 1177 psAbort("Deciphering kernels other than ISIS, HERM, DECONV_HERM or RINGS is not currently supported."); 1178 } 1179 1180 return pmSubtractionKernelsGenerate(type, size, spatialOrder, fwhms, orders, inner, binning, 1181 ringsOrder, penalty, bounds, mode); 1182 } 1183 1184 1185 // the input string can either be just the name or the description string. Currently known 1186 // descriptions: ISIS(...), ISIS_RADIAL(...), HERM(...), DECONV_HERM(...), POIS(...), 1187 // SPAM(...), FRIES(...), GUNK=ISIS(...)+POIS(...), RINGS(...), 743 1188 pmSubtractionKernelsType pmSubtractionKernelsTypeFromString(const char *type) 744 1189 { 745 if (strcasecmp(type, "POIS") == 0) { 1190 // for a bare name (ISIS, HERM), use the full string length. 1191 // otherwise, use the length up to the first '(' 1192 int nameLength = strlen(type); 1193 char *ptr = strchr(type, '('); 1194 if (ptr) { 1195 nameLength = ptr - type; 1196 } 1197 1198 if (strncasecmp(type, "POIS", nameLength) == 0) { 746 1199 return PM_SUBTRACTION_KERNEL_POIS; 747 1200 } 748 if (str casecmp(type, "ISIS") == 0) {1201 if (strncasecmp(type, "ISIS", nameLength) == 0) { 749 1202 return PM_SUBTRACTION_KERNEL_ISIS; 750 1203 } 751 if (strcasecmp(type, "SPAM") == 0) { 1204 if (strncasecmp(type, "ISIS_RADIAL", nameLength) == 0) { 1205 return PM_SUBTRACTION_KERNEL_ISIS_RADIAL; 1206 } 1207 if (strncasecmp(type, "HERM", nameLength) == 0) { 1208 return PM_SUBTRACTION_KERNEL_HERM; 1209 } 1210 if (strncasecmp(type, "DECONV_HERM", nameLength) == 0) { 1211 return PM_SUBTRACTION_KERNEL_DECONV_HERM; 1212 } 1213 if (strncasecmp(type, "SPAM", nameLength) == 0) { 752 1214 return PM_SUBTRACTION_KERNEL_SPAM; 753 1215 } 754 if (str casecmp(type, "FRIES") == 0) {1216 if (strncasecmp(type, "FRIES", nameLength) == 0) { 755 1217 return PM_SUBTRACTION_KERNEL_FRIES; 756 1218 } 757 if (str casecmp(type, "GUNK") == 0) {1219 if (strncasecmp(type, "GUNK", nameLength) == 0) { 758 1220 return PM_SUBTRACTION_KERNEL_GUNK; 759 1221 } 760 if (strcasecmp(type, "RINGS") == 0) { 1222 // note that GUNK has a somewhat different description 1223 if (strncasecmp(type, "GUNK=ISIS", nameLength) == 0) { 1224 return PM_SUBTRACTION_KERNEL_GUNK; 1225 } 1226 if (strncasecmp(type, "RINGS", nameLength) == 0) { 761 1227 return PM_SUBTRACTION_KERNEL_RINGS; 762 1228 } … … 765 1231 return PM_SUBTRACTION_KERNEL_NONE; 766 1232 } 1233 1234 pmSubtractionKernels *pmSubtractionKernelsCopy(const pmSubtractionKernels *in) 1235 { 1236 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(in, NULL); 1237 1238 pmSubtractionKernels *out = psAlloc(sizeof(pmSubtractionKernels)); // Kernels, to return 1239 psMemSetDeallocator(out, (psFreeFunc)subtractionKernelsFree); 1240 1241 out->type = in->type; 1242 out->description = psMemIncrRefCounter(in->description); 1243 out->num = in->num; 1244 out->u = psMemIncrRefCounter(in->u); 1245 out->v = psMemIncrRefCounter(in->v); 1246 out->widths = psMemIncrRefCounter(in->widths); 1247 out->preCalc = psMemIncrRefCounter(in->preCalc); 1248 out->penalty = in->penalty; 1249 out->penalties = psMemIncrRefCounter(in->penalties); 1250 out->uStop = psMemIncrRefCounter(in->uStop); 1251 out->vStop = psMemIncrRefCounter(in->vStop); 1252 out->size = in->size; 1253 out->inner = in->inner; 1254 out->spatialOrder = in->spatialOrder; 1255 out->bgOrder = in->bgOrder; 1256 out->mode = in->mode; 1257 out->xMin = in->xMin; 1258 out->xMax = in->xMax; 1259 out->yMin = in->yMin; 1260 out->yMax = in->yMax; 1261 out->solution1 = in->solution1 ? psVectorCopy(NULL, in->solution1, PS_TYPE_F64) : NULL; 1262 out->solution2 = in->solution2 ? psVectorCopy(NULL, in->solution2, PS_TYPE_F64) : NULL; 1263 out->sampleStamps = psMemIncrRefCounter(in->sampleStamps); 1264 1265 return out; 1266 } -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionKernels.h
r20049 r27840 10 10 PM_SUBTRACTION_KERNEL_POIS, ///< Pan-STARRS Optimal Image Subtraction --- delta functions 11 11 PM_SUBTRACTION_KERNEL_ISIS, ///< Traditional kernel --- gaussians modified by polynomials 12 PM_SUBTRACTION_KERNEL_ISIS_RADIAL, ///< ISIS + higher-order radial Hermitians 13 PM_SUBTRACTION_KERNEL_HERM, ///< Hermitian polynomial kernels 14 PM_SUBTRACTION_KERNEL_DECONV_HERM, ///< Deconvolved Hermitian polynomial kernels 12 15 PM_SUBTRACTION_KERNEL_SPAM, ///< Summed Pixels for Advanced Matching --- summed delta functions 13 16 PM_SUBTRACTION_KERNEL_FRIES, ///< Fibonacci Radius Increases Excellence of Subtraction … … 29 32 pmSubtractionKernelsType type; ///< Type of kernels --- allowing the use of multiple kernels 30 33 psString description; ///< Description of the kernel parameters 34 int xMin, xMax, yMin, yMax; ///< Bounds of image (for normalisation) 31 35 long num; ///< Number of kernel components (not including the spatial ones) 32 psVector *u, *v; ///< Offset (for POIS) or polynomial order (for ISIS )33 psVector *widths; ///< Gaussian FWHMs (ISIS )36 psVector *u, *v; ///< Offset (for POIS) or polynomial order (for ISIS, HERM or DECONV_HERM) 37 psVector *widths; ///< Gaussian FWHMs (ISIS, HERM or DECONV_HERM) 34 38 psVector *uStop, *vStop; ///< Width of kernel element (SPAM,FRIES only) 35 psArray *preCalc; ///< Array of images containing pre-calculated kernel (for ISIS )39 psArray *preCalc; ///< Array of images containing pre-calculated kernel (for ISIS, HERM or DECONV_HERM) 36 40 float penalty; ///< Penalty for wideness 37 41 psVector *penalties; ///< Penalty for each kernel component … … 41 45 int bgOrder; ///< The order for the background fitting 42 46 pmSubtractionMode mode; ///< Mode for subtraction 43 int numCols, numRows; ///< Size of image (for normalisation), or zero to use image provided44 47 psVector *solution1, *solution2; ///< Solution for the PSF matching 45 48 // Quality information 46 49 float mean, rms; ///< Mean and RMS of chi^2 from stamps 47 50 int numStamps; ///< Number of good stamps 51 float fSigResMean; ///< mean fractional stdev of residuals 52 float fSigResStdev; ///< stdev of fractional stdev of residuals 53 float fMaxResMean; ///< mean fractional positive swing in residuals 54 float fMaxResStdev; ///< stdev of fractional positive swing in residuals 55 float fMinResMean; ///< mean fractional negative swing in residuals 56 float fMinResStdev; ///< stdev of fractional negative swing in residuals 57 psArray *sampleStamps; ///< array of brightest set of stamps for output visualizations 48 58 } pmSubtractionKernels; 59 60 // pmSubtractionKernels->preCalc is an array of pmSubtractionKernelPreCalc structures 61 typedef struct { 62 psVector *uCoords; // used by RINGS 63 psVector *vCoords; // used by RINGS 64 psVector *poly; // used by RINGS 65 66 psVector *xKernel; // used by ISIS, HERM, DECONV_HERM 67 psVector *yKernel; // used by ISIS, HERM, DECONV_HERM 68 psKernel *kernel; // used by ISIS, HERM, DECONV_HERM 69 } pmSubtractionKernelPreCalc; 49 70 50 71 // Assertion to check pmSubtractionKernels … … 52 73 PS_ASSERT_PTR_NON_NULL(KERNELS, RETURNVALUE); \ 53 74 PS_ASSERT_STRING_NON_EMPTY((KERNELS)->description, RETURNVALUE); \ 54 PS_ASSERT_INT_ POSITIVE((KERNELS)->num, RETURNVALUE); \75 PS_ASSERT_INT_NONNEGATIVE((KERNELS)->num, RETURNVALUE); \ 55 76 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->u, RETURNVALUE); \ 56 77 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->v, RETURNVALUE); \ … … 60 81 PS_ASSERT_VECTOR_SIZE((KERNELS)->v, (KERNELS)->num, RETURNVALUE); \ 61 82 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_ISIS) { \ 83 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 84 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 85 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 86 } \ 87 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_ISIS_RADIAL) { \ 88 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 89 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 90 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 91 } \ 92 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_HERM) { \ 93 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 94 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ 95 PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \ 96 } \ 97 if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_DECONV_HERM) { \ 62 98 PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \ 63 99 PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \ … … 99 135 } 100 136 137 // Generate 1D convolution kernel for ISIS 138 psVector *pmSubtractionKernelISIS(float sigma, // Gaussian width 139 int order, // Polynomial order 140 int size // Kernel half-size 141 ); 142 143 // Generate 1D convolution kernel for HERM (normalized for 2D) 144 psVector *pmSubtractionKernelHERM(float sigma, // Gaussian width 145 int order, // Polynomial order 146 int size // Kernel half-size 147 ); 148 101 149 /// Generate a delta-function grid for subtraction kernels (like the POIS kernel) 102 150 bool p_pmSubtractionKernelsAddGrid(pmSubtractionKernels *kernels, ///< The subtraction kernels to append to … … 114 162 int spatialOrder, ///< Order of spatial variations 115 163 float penalty, ///< Penalty for wideness 164 psRegion bounds, ///< Bounds for validity 116 165 pmSubtractionMode mode ///< Mode for subtraction 117 166 ); 167 168 /// Allocator for pre-calculated kernel data structure 169 pmSubtractionKernelPreCalc *pmSubtractionKernelPreCalcAlloc( 170 pmSubtractionKernelsType type, ///< type of kernel to allocate (not all can be pre-calculated) 171 int uOrder, ///< order in x-direction 172 int vOrder, ///< order in x-direction 173 int size, ///< Half-size of the kernel 174 float sigma ///< sigma of gaussian kernel 175 ); 176 118 177 119 178 /// Generate POIS kernels … … 121 180 int spatialOrder, ///< Order of spatial variations 122 181 float penalty, ///< Penalty for wideness 182 psRegion bounds, ///< Bounds for validity 123 183 pmSubtractionMode mode ///< Mode for subtraction 124 184 ); … … 130 190 const psVector *orders, ///< Polynomial order of gaussians 131 191 float penalty, ///< Penalty for wideness 192 psRegion bounds, ///< Bounds for validity 132 193 pmSubtractionMode mode ///< Mode for subtraction 133 194 ); … … 139 200 const psVector *orders, ///< Polynomial order of gaussians 140 201 float penalty, ///< Penalty for wideness 202 psRegion bounds, ///< Bounds for validity 141 203 pmSubtractionMode mode ///< Mode for subtraction 142 204 ); 205 206 /// Generate ISIS + RADIAL_HERM kernels 207 pmSubtractionKernels *pmSubtractionKernelsISIS_RADIAL(int size, ///< Half-size of the kernel 208 int spatialOrder, ///< Order of spatial variations 209 const psVector *fwhms, ///< Gaussian FWHMs 210 const psVector *orders, ///< Polynomial order of gaussians 211 float penalty, ///< Penalty for wideness 212 psRegion bounds, ///< Bounds for validity 213 pmSubtractionMode mode ///< Mode for subtraction 214 ); 215 216 /// Generate HERM kernels 217 pmSubtractionKernels *pmSubtractionKernelsHERM(int size, ///< Half-size of the kernel 218 int spatialOrder, ///< Order of spatial variations 219 const psVector *fwhms, ///< Gaussian FWHMs 220 const psVector *orders, ///< order of hermitian polynomials 221 float penalty, ///< Penalty for wideness 222 psRegion bounds, ///< Bounds for validity 223 pmSubtractionMode mode ///< Mode for subtraction 224 ); 225 226 /// Generate DECONV_HERM kernels 227 pmSubtractionKernels *pmSubtractionKernelsDECONV_HERM(int size, ///< Half-size of the kernel 228 int spatialOrder, ///< Order of spatial variations 229 const psVector *fwhms, ///< Gaussian FWHMs 230 const psVector *orders, ///< order of hermitian polynomials 231 float penalty, ///< Penalty for wideness 232 psRegion bounds, ///< Bounds for validity 233 pmSubtractionMode mode ///< Mode for subtraction 234 ); 143 235 144 236 /// Generate SPAM kernels … … 148 240 int binning, ///< Kernel binning factor 149 241 float penalty, ///< Penalty for wideness 242 psRegion bounds, ///< Bounds for validity 150 243 pmSubtractionMode mode ///< Mode for subtraction 151 244 ); … … 156 249 int inner, ///< Inner radius to preserve unbinned 157 250 float penalty, ///< Penalty for wideness 251 psRegion bounds, ///< Bounds for validity 158 252 pmSubtractionMode mode ///< Mode for subtraction 159 253 ); … … 166 260 int inner, ///< Inner radius containing grid of delta functions 167 261 float penalty, ///< Penalty for wideness 262 psRegion bounds, ///< Bounds for validity 168 263 pmSubtractionMode mode ///< Mode for subtraction 169 264 ); … … 175 270 int ringsOrder, ///< Polynomial order 176 271 float penalty, ///< Penalty for wideness 272 psRegion bounds, ///< Bounds for validity 177 273 pmSubtractionMode mode ///< Mode for subtraction 178 274 ); … … 189 285 int ringsOrder, ///< Polynomial order for RINGS 190 286 float penalty, ///< Penalty for wideness 287 psRegion bounds, ///< Bounds for validity 191 288 pmSubtractionMode mode ///< Mode for subtraction 192 289 ); … … 196 293 const char *description, ///< Description of kernel 197 294 int bgOrder, ///< Polynomial order for background fitting 295 psRegion bounds, ///< Bounds for validity 198 296 pmSubtractionMode mode ///< Mode for subtraction 199 297 ); … … 203 301 ); 204 302 303 /// Copy kernels 304 /// 305 /// A deep copy is performed on the solution only; the other components are merely pointers. 306 pmSubtractionKernels *pmSubtractionKernelsCopy( 307 const pmSubtractionKernels *in // Kernels to copy 308 ); 309 205 310 206 311 #endif -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionMask.c
r24257 r27840 38 38 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// 39 39 40 psImage *pmSubtractionMask(const psImage *mask1, const psImage *mask2, psImageMaskType maskVal, 41 int size, int footprint, float badFrac, pmSubtractionMode mode) 42 { 43 PS_ASSERT_IMAGE_NON_NULL(mask1, NULL); 44 PS_ASSERT_IMAGE_TYPE(mask1, PS_TYPE_IMAGE_MASK, NULL); 45 if (mask2) { 46 PS_ASSERT_IMAGE_NON_NULL(mask2, NULL); 47 PS_ASSERT_IMAGE_TYPE(mask2, PS_TYPE_IMAGE_MASK, NULL); 48 PS_ASSERT_IMAGES_SIZE_EQUAL(mask2, mask1, NULL); 49 } 40 psImage *pmSubtractionMask(psRegion *bounds, const pmReadout *ro1, const pmReadout *ro2, 41 psImageMaskType maskVal, int size, int footprint, float badFrac, 42 pmSubtractionMode mode) 43 { 44 int numCols = 0, numRows = 0; // Size of the images 45 if (ro1) { 46 PM_ASSERT_READOUT_NON_NULL(ro1, NULL); 47 PM_ASSERT_READOUT_IMAGE(ro1, NULL); 48 PM_ASSERT_READOUT_MASK(ro1, NULL); 49 numCols = ro1->image->numCols; 50 numRows = ro1->image->numRows; 51 } 52 if (ro2) { 53 PM_ASSERT_READOUT_NON_NULL(ro2, NULL); 54 PM_ASSERT_READOUT_IMAGE(ro2, NULL); 55 PM_ASSERT_READOUT_MASK(ro2, NULL); 56 numCols = ro2->image->numCols; 57 numRows = ro2->image->numRows; 58 } 59 if (ro1 && ro2) { 60 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, NULL); 61 } 62 if (!ro1 && !ro2) { 63 psError(PS_ERR_UNEXPECTED_NULL, true, "No image provided."); 64 return false; 65 } 66 psAssert(numCols > 0 && numRows > 0, "There should be an image provided"); 50 67 PS_ASSERT_INT_NONNEGATIVE(size, NULL); 51 68 PS_ASSERT_INT_NONNEGATIVE(footprint, NULL); … … 55 72 } 56 73 57 int numCols = mask1->numCols, numRows = mask1->numRows; // Size of the images58 59 74 // Dereference inputs for convenience 60 psImageMaskType **data1 = mask1->data.PS_TYPE_IMAGE_MASK_DATA; 61 psImageMaskType **data2 = NULL; 62 if (mask2) { 63 data2 = mask2->data.PS_TYPE_IMAGE_MASK_DATA; 64 } 75 psF32 **imageData1 = ro1 ? ro1->image->data.F32 : NULL; 76 psF32 **imageData2 = ro2 ? ro2->image->data.F32 : NULL; 77 psImageMaskType **maskData1 = ro1 ? ro1->mask->data.PS_TYPE_IMAGE_MASK_DATA : NULL; 78 psImageMaskType **maskData2 = ro2 ? ro2->mask->data.PS_TYPE_IMAGE_MASK_DATA : NULL; 65 79 66 80 // First, a pass through to determine the fraction of bad pixels 67 if (isfinite(badFrac) && badFrac != 1.0) { 81 if (bounds || (isfinite(badFrac) && badFrac != 1.0)) { 82 int xMin = numCols, xMax = 0, yMin = numRows, yMax = 0; // Bounds of good pixels 68 83 int numBad = 0; // Number of bad pixels 69 84 for (int y = 0; y < numRows; y++) { 70 85 for (int x = 0; x < numCols; x++) { 71 if ( data1[y][x] & maskVal) {86 if (ro1 && ((maskData1[y][x] & maskVal) || !isfinite(imageData1[y][x]))) { 72 87 numBad++; 73 88 continue; 74 89 } 75 if ( data2 && data2[y][x] & maskVal) {90 if (ro2 && ((maskData2[y][x] & maskVal) || !isfinite(imageData2[y][x]))) { 76 91 numBad++; 92 continue; 77 93 } 78 } 79 } 80 if (numBad > badFrac * numCols * numRows) { 94 xMin = PS_MIN(xMin, x); 95 xMax = PS_MAX(xMax, x); 96 yMin = PS_MIN(yMin, y); 97 yMax = PS_MAX(yMax, y); 98 } 99 } 100 if (bounds) { 101 bounds->x0 = xMin; 102 bounds->x1 = xMax; 103 bounds->y0 = yMin; 104 bounds->y1 = yMax; 105 } 106 if (isfinite(badFrac) && badFrac != 1.0 && numBad > badFrac * numCols * numRows) { 81 107 psError(PM_ERR_SMALL_AREA, true, 82 108 "Fraction of bad pixels (%d/%d=%f) exceeds limit (%f)\n", … … 117 143 for (int y = 0; y < numRows; y++) { 118 144 for (int x = 0; x < numCols; x++) { 119 if ( data1[y][x] & maskVal) {145 if (ro1 && maskData1[y][x] & maskVal) { 120 146 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_1; 121 147 } 122 if ( data2 && data2[y][x] & maskVal) {148 if (ro2 && maskData2[y][x] & maskVal) { 123 149 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_2; 124 150 } … … 133 159 134 160 // Pixels that will be bad (or poor) if we convolve with a bad reference pixel 135 if ( !psImageConvolveMask(mask, mask, PM_SUBTRACTION_MASK_BAD_1, PM_SUBTRACTION_MASK_CONVOLVE_1,136 -size, size, -size, size)) {137 psError( PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 1.");161 if (ro1 && !psImageConvolveMask(mask, mask, PM_SUBTRACTION_MASK_BAD_1, PM_SUBTRACTION_MASK_CONVOLVE_1, 162 -size, size, -size, size)) { 163 psError(psErrorCodeLast(), false, "Unable to convolve bad pixels from mask 1."); 138 164 psFree(mask); 139 165 return NULL; 140 166 } 141 if ( !psImageConvolveMask(mask, mask, PM_SUBTRACTION_MASK_BAD_2, PM_SUBTRACTION_MASK_CONVOLVE_2,142 -size, size, -size, size)) {143 psError( PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 2.");167 if (ro2 && !psImageConvolveMask(mask, mask, PM_SUBTRACTION_MASK_BAD_2, PM_SUBTRACTION_MASK_CONVOLVE_2, 168 -size, size, -size, size)) { 169 psError(psErrorCodeLast(), false, "Unable to convolve bad pixels from mask 2."); 144 170 psFree(mask); 145 171 return NULL; … … 163 189 psAbort("Unsupported subtraction mode: %x", mode); 164 190 } 165 if ( !psImageConvolveMask(mask, mask, maskRej, PM_SUBTRACTION_MASK_REJ,166 -footprint, footprint, -footprint, footprint)) {167 psError( PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels.");191 if (ro1 && ro2 && !psImageConvolveMask(mask, mask, maskRej, PM_SUBTRACTION_MASK_REJ, 192 -footprint, footprint, -footprint, footprint)) { 193 psError(psErrorCodeLast(), false, "Unable to convolve bad pixels."); 168 194 psFree(mask); 169 195 return NULL; -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionMask.h
r23851 r27840 5 5 6 6 /// Generate a mask for use in the subtraction process 7 psImage *pmSubtractionMask(const psImage *refMask, ///< Mask for the reference image (will be convolved) 8 const psImage *inMask, ///< Mask for the input image, or NULL 9 psImageMaskType maskVal, ///< Value to mask out 10 int size, ///< Half-size of the kernel (pmSubtractionKernels.size) 11 int footprint, ///< Half-size of the kernel footprint 12 float badFrac, ///< Maximum fraction of bad input pixels to accept 13 pmSubtractionMode mode ///< Subtraction mode 7 psImage *pmSubtractionMask( 8 psRegion *bounds, ///< Bounds of valid pixels (or NULL), returned 9 const pmReadout *ro1, ///< Readout 1 10 const pmReadout *ro2, ///< Readout 2 11 psImageMaskType maskVal, ///< Value to mask out 12 int size, ///< Half-size of the kernel (pmSubtractionKernels.size) 13 int footprint, ///< Half-size of the kernel footprint 14 float badFrac, ///< Maximum fraction of bad input pixels to accept 15 pmSubtractionMode mode ///< Subtraction mode 14 16 ); 15 17 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionMatch.c
r25060 r27840 28 28 static bool useFFT = true; // Do convolutions using FFT 29 29 30 # define SEPARATE 0 31 # if (SEPARATE) 32 # define SUBMODE PM_SUBTRACTION_EQUATION_NORM 33 # else 34 # define SUBMODE PM_SUBTRACTION_EQUATION_ALL 35 # endif 30 36 31 37 //#define TESTING … … 64 70 const psImage *subMask, // Mask for subtraction, or NULL 65 71 psImage *variance, // Variance map 66 const psRegion *region, // Region of interest , or NULL72 const psRegion *region, // Region of interest 67 73 float thresh1, // Threshold for stamp finding on readout 1 68 74 float thresh2, // Threshold for stamp finding on readout 2 69 75 float stampSpacing, // Spacing between stamps 76 float normFrac, // Fraction of flux in window for normalisation window 77 float sysError, // Relative systematic error in images 78 float skyError, // Relative systematic error in images 70 79 int size, // Kernel half-size 71 80 int footprint, // Convolution footprint for stamps … … 73 82 ) 74 83 { 84 PS_ASSERT_PTR_NON_NULL(stamps, false); 85 PM_ASSERT_READOUT_NON_NULL(ro1, false); 86 PM_ASSERT_READOUT_NON_NULL(ro2, false); 87 PS_ASSERT_IMAGE_NON_NULL(subMask, false); 88 PS_ASSERT_IMAGE_NON_NULL(variance, false); 89 PS_ASSERT_PTR_NON_NULL(region, false); 90 75 91 psTrace("psModules.imcombine", 3, "Finding stamps...\n"); 76 92 … … 78 94 79 95 *stamps = pmSubtractionStampsFind(*stamps, image1, image2, subMask, region, thresh1, thresh2, 80 size, footprint, stampSpacing, mode);96 size, footprint, stampSpacing, normFrac, sysError, skyError, mode); 81 97 if (!*stamps) { 82 98 psError(psErrorCodeLast(), false, "Unable to find stamps."); … … 87 103 88 104 psTrace("psModules.imcombine", 3, "Extracting stamps...\n"); 89 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2 ? ro2->image : NULL, variance, size)) {90 psError( PS_ERR_UNKNOWN, false, "Unable to extract stamps.");105 if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2->image, variance, size, *region)) { 106 psError(psErrorCodeLast(), false, "Unable to extract stamps."); 91 107 return false; 92 108 } … … 101 117 const pmReadout *ro1, const pmReadout *ro2, // Input images 102 118 int stride, // Size for convolution patches 103 float sysError, // Relative systematic error 119 float normFrac, // Fraction of window for normalisation window 120 float sysError, // Systematic error in images 121 float skyError, // Systematic error in images 122 float kernelError, // Systematic error in kernel 123 float covarFrac, // Fraction for kernel truncation before covariance 104 124 psImageMaskType maskVal, // Value to mask for input 105 125 psImageMaskType maskBad, // Mask for output bad pixels … … 112 132 if (subMode != PM_SUBTRACTION_MODE_2) { 113 133 PM_ASSERT_READOUT_NON_NULL(conv1, false); 134 PM_ASSERT_READOUT_NON_NULL(ro1, false); 135 PM_ASSERT_READOUT_IMAGE(ro1, false); 114 136 if (conv1->image) { 115 137 psFree(conv1->image); … … 127 149 if (subMode != PM_SUBTRACTION_MODE_1) { 128 150 PM_ASSERT_READOUT_NON_NULL(conv2, false); 151 PM_ASSERT_READOUT_NON_NULL(ro2, false); 152 PM_ASSERT_READOUT_IMAGE(ro2, false); 129 153 if (conv2->image) { 130 154 psFree(conv2->image); … … 141 165 } 142 166 143 PM_ASSERT_READOUT_NON_NULL(ro1, false); 144 PM_ASSERT_READOUT_NON_NULL(ro2, false); 145 PM_ASSERT_READOUT_IMAGE(ro1, false); 146 PM_ASSERT_READOUT_IMAGE(ro2, false); 147 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, false); 167 if (ro1 && ro2) { 168 PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, false); 169 } 148 170 PS_ASSERT_INT_NONNEGATIVE(stride, false); 171 if (isfinite(normFrac)) { 172 PS_ASSERT_FLOAT_LARGER_THAN(normFrac, 0.0, false); 173 PS_ASSERT_FLOAT_LESS_THAN(normFrac, 1.0, false); 174 } 149 175 if (isfinite(sysError)) { 150 176 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(sysError, 0.0, false); 151 177 PS_ASSERT_FLOAT_LESS_THAN(sysError, 1.0, false); 152 178 } 179 if (isfinite(sysError)) { 180 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(skyError, 0.0, false); 181 } 182 if (isfinite(kernelError)) { 183 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(kernelError, 0.0, false); 184 PS_ASSERT_FLOAT_LESS_THAN(kernelError, 1.0, false); 185 } 186 PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(covarFrac, 0.0, false); 187 PS_ASSERT_FLOAT_LESS_THAN(covarFrac, 1.0, false); 153 188 // Don't care about maskVal 154 189 // Don't care about maskBad … … 164 199 } 165 200 201 202 /// Allocate images, as required 203 static void subtractionMatchAlloc(pmReadout *conv1, pmReadout *conv2, // Output readouts 204 const pmReadout *ro1, const pmReadout *ro2, // Input readouts 205 const psImage *subMask, // Subtraction mask 206 psImageMaskType maskBad, // Mask value for bad pixels 207 pmSubtractionMode subMode, // Subtraction mode 208 int numCols, int numRows // Size of image 209 ) 210 { 211 if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_UNSURE || 212 subMode == PM_SUBTRACTION_MODE_DUAL) { 213 if (!conv1->image) { 214 conv1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 215 } 216 psImageInit(conv1->image, NAN); 217 if (ro1->variance) { 218 if (!conv1->variance) { 219 conv1->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 220 } 221 psImageInit(conv1->variance, NAN); 222 } 223 if (subMask) { 224 if (!conv1->mask) { 225 conv1->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 226 } 227 psImageInit(conv1->mask, maskBad); 228 } 229 } 230 if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_UNSURE || 231 subMode == PM_SUBTRACTION_MODE_DUAL) { 232 if (!conv2->image) { 233 conv2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 234 } 235 psImageInit(conv2->image, NAN); 236 if (ro2->variance) { 237 if (!conv2->variance) { 238 conv2->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 239 } 240 psImageInit(conv2->variance, NAN); 241 } 242 if (subMask) { 243 if (!conv2->mask) { 244 conv2->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 245 } 246 psImageInit(conv2->mask, maskBad); 247 } 248 } 249 250 return; 251 } 252 253 166 254 static void subtractionAnalysisUpdate(pmReadout *conv1, pmReadout *conv2, // Convolved images 167 255 const psMetadata *analysis, // Analysis metadata … … 192 280 } 193 281 282 bool pmSubtractionMaskInvalid (const pmReadout *readout, psImageMaskType maskVal) { 283 284 if (!readout) return true; 285 286 psImage *image = readout->image; 287 psImage *mask = readout->mask; 288 psImage *variance = readout->variance; 289 for (int y = 0; y < image->numRows; y++) { 290 for (int x = 0; x < image->numCols; x++) { 291 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) continue; 292 bool valid = false; 293 valid = isfinite(image->data.F32[y][x]); 294 if (variance) { 295 valid &= isfinite(variance->data.F32[y][x]); 296 } 297 if (valid) continue; 298 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = maskVal; 299 } 300 } 301 302 return true; 303 } 194 304 195 305 bool pmSubtractionMatchPrecalc(pmReadout *conv1, pmReadout *conv2, const pmReadout *ro1, const pmReadout *ro2, 196 psMetadata *analysis, int stride, float sysError,306 psMetadata *analysis, int stride, float kernelError, float covarFrac, 197 307 psImageMaskType maskVal, psImageMaskType maskBad, psImageMaskType maskPoor, 198 308 float poorFrac, float badFrac) … … 210 320 while ((item = psMetadataGetAndIncrement(iter))) { 211 321 if (item->type != PS_DATA_UNKNOWN) { 212 psError(P S_ERR_BAD_PARAMETER_TYPE, true, "Unexpected type for kernel.");322 psError(PM_ERR_PROG, true, "Unexpected type for kernel."); 213 323 psFree(iter); 214 324 psFree(kernelList); … … 230 340 } 231 341 if (psListLength(kernelList) == 0) { 232 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Unable to find kernels");342 psError(PM_ERR_PROG, true, "Unable to find kernels"); 233 343 psFree(kernelList); 234 344 return false; … … 245 355 while ((item = psMetadataGetAndIncrement(iter))) { 246 356 if (item->type != PS_DATA_REGION) { 247 psError(P S_ERR_BAD_PARAMETER_TYPE, true, "Unexpected type for region.");357 psError(PM_ERR_PROG, true, "Unexpected type for region."); 248 358 psFree(iter); 249 359 psFree(kernels); … … 257 367 } 258 368 if (regions->n != kernels->n) { 259 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Differing number of kernels (%ld) and regions (%ld)",369 psError(PM_ERR_PROG, true, "Differing number of kernels (%ld) and regions (%ld)", 260 370 kernels->n, regions->n); 261 371 psFree(regions); … … 264 374 } 265 375 266 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, sysError, maskVal, maskBad, maskPoor,267 poorFrac, badFrac, mode)) {376 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, NAN, NAN, NAN, kernelError, covarFrac, 377 maskVal, maskBad, maskPoor, poorFrac, badFrac, mode)) { 268 378 psFree(kernels); 269 379 psFree(regions); … … 271 381 } 272 382 273 psImage *subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskVal, size, 0, 383 int numCols, numRows; // Size of image 384 if (ro1) { 385 numCols = ro1->image->numCols; 386 numRows = ro1->image->numRows; 387 } else if (ro2) { 388 numCols = ro2->image->numCols; 389 numRows = ro2->image->numRows; 390 } else { 391 psAbort("No input image provided."); 392 } 393 394 pmSubtractionMaskInvalid(ro1, maskVal); 395 pmSubtractionMaskInvalid(ro2, maskVal); 396 397 // General background subtraction, since this is done in pmSubtractionMatch 398 { 399 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 400 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for background 401 if (ro1) { 402 psStatsInit(bg); 403 if (!psImageBackground(bg, NULL, ro1->image, ro1->mask, maskVal, rng)) { 404 psError(PM_ERR_DATA, false, "Unable to measure background statistics."); 405 psFree(bg); 406 psFree(rng); 407 return false; 408 } 409 psBinaryOp(ro1->image, ro1->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32)); 410 } 411 if (ro2) { 412 psStatsInit(bg); 413 if (!psImageBackground(bg, NULL, ro2->image, ro2->mask, maskVal, rng)) { 414 psError(PM_ERR_DATA, false, "Unable to measure background statistics."); 415 psFree(bg); 416 psFree(rng); 417 return false; 418 } 419 psBinaryOp(ro2->image, ro2->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32)); 420 } 421 psFree(bg); 422 psFree(rng); 423 } 424 425 psRegion bounds = psRegionSet(NAN, NAN, NAN, NAN); // Bounds of valid pixels 426 427 psImage *subMask = pmSubtractionMask(&bounds, ro1, ro2, maskVal, size, 0, 274 428 badFrac, mode); // Subtraction mask 275 429 if (!subMask) { … … 283 437 psMetadata *outHeader = psMetadataAlloc(); // Output header values 284 438 439 subtractionMatchAlloc(conv1, conv2, ro1, ro2, subMask, maskBad, mode, numCols, numRows); 440 285 441 psTrace("psModules.imcombine", 2, "Convolving...\n"); 286 442 for (int i = 0; i < kernels->n; i++) { … … 288 444 psRegion *region = regions->data[i]; // Region of interest 289 445 290 if (!pmSubtractionAnalysis(outAnalysis, outHeader, kernel, region, 291 ro1->image->numCols, ro1->image->numRows)) { 292 psError(PS_ERR_UNKNOWN, false, "Unable to generate QA data"); 446 if (!pmSubtractionAnalysis(outAnalysis, outHeader, kernel, region, numCols, numRows)) { 447 psError(psErrorCodeLast(), false, "Unable to generate QA data"); 293 448 psFree(outAnalysis); 294 449 psFree(outHeader); … … 300 455 301 456 if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac, 302 sysError, region, kernel, true, useFFT)) {303 psError( PS_ERR_UNKNOWN, false, "Unable to convolve image.");457 kernelError, covarFrac, region, kernel, true, useFFT)) { 458 psError(psErrorCodeLast(), false, "Unable to convolve image."); 304 459 psFree(outAnalysis); 305 460 psFree(outHeader); … … 330 485 int inner, int ringsOrder, int binning, float penalty, 331 486 bool optimum, const psVector *optFWHMs, int optOrder, float optThreshold, 332 int iter, float rej, float sysError, psImageMaskType maskVal, psImageMaskType maskBad, 487 int iter, float rej, float normFrac, float sysError, float skyError, 488 float kernelError, float covarFrac, psImageMaskType maskVal, psImageMaskType maskBad, 333 489 psImageMaskType maskPoor, float poorFrac, float badFrac, pmSubtractionMode subMode) 334 490 { 335 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, sysError, maskVal, maskBad, maskPoor,336 poorFrac, badFrac, subMode)) {491 if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, normFrac, sysError, skyError, kernelError, 492 covarFrac, maskVal, maskBad, maskPoor, poorFrac, badFrac, subMode)) { 337 493 return false; 338 494 } 495 496 // We need both inputs 497 PM_ASSERT_READOUT_NON_NULL(ro1, false); 498 PM_ASSERT_READOUT_NON_NULL(ro2, false); 339 499 340 500 PS_ASSERT_INT_NONNEGATIVE(footprint, false); … … 392 552 // Putting important variable declarations here, since they are freed after a "goto" if there is an error. 393 553 psImage *subMask = NULL; // Mask for subtraction 394 psRegion *region = NULL;// Iso-kernel region554 psRegion *region = psRegionAlloc(NAN, NAN, NAN, NAN); // Iso-kernel region 395 555 psString regionString = NULL; // String for region 396 556 pmSubtractionStampList *stamps = NULL; // Stamps for matching PSF … … 405 565 memCheck("start"); 406 566 407 subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskVal, size, footprint, 408 badFrac, subMode); 567 pmSubtractionMaskInvalid(ro1, maskVal); 568 pmSubtractionMaskInvalid(ro2, maskVal); 569 570 psRegion bounds = psRegionSet(NAN, NAN, NAN, NAN); // Bounds of valid pixels 571 572 subMask = pmSubtractionMask(&bounds, ro1, ro2, maskVal, size, footprint, badFrac, subMode); 409 573 if (!subMask) { 410 574 psError(psErrorCodeLast(), false, "Unable to generate subtraction mask."); … … 416 580 // Get region of interest 417 581 int xRegions = 1, yRegions = 1; // Number of iso-kernel regions 418 float xRegionSize = 0, yRegionSize = 0; // Size of iso-kernel regions582 float xRegionSize = NAN, yRegionSize = NAN; // Size of iso-kernel regions 419 583 if (isfinite(regionSize) && regionSize != 0.0) { 420 xRegions = numCols / regionSize + 1; 421 yRegions = numRows / regionSize + 1; 422 xRegionSize = (float)numCols / (float)xRegions; 423 yRegionSize = (float)numRows / (float)yRegions; 424 region = psRegionAlloc(NAN, NAN, NAN, NAN); 425 } 426 584 xRegions = (bounds.x1 - bounds.x0) / regionSize + 1; 585 yRegions = (bounds.y1 - bounds.y0) / regionSize + 1; 586 xRegionSize = (float)(bounds.x1 - bounds.x0) / (float)xRegions; 587 yRegionSize = (float)(bounds.y1 - bounds.y0) / (float)yRegions; 588 } else { 589 xRegionSize = bounds.x1 - bounds.x0; 590 yRegionSize = bounds.y1 - bounds.y0; 591 } 592 593 // General background subtraction and measurement of stamp threshold 427 594 float stampThresh1 = NAN, stampThresh2 = NAN; // Stamp thresholds for images 428 595 { 429 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for backgroun 596 psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for background 430 597 if (ro1) { 598 psStatsInit(bg); 431 599 if (!psImageBackground(bg, NULL, ro1->image, ro1->mask, maskVal, rng)) { 432 psError(P S_ERR_UNKNOWN, false, "Unable to measure background statistics.");600 psError(PM_ERR_DATA, false, "Unable to measure background statistics."); 433 601 psFree(bg); 434 602 goto MATCH_ERROR; 435 603 } 436 stampThresh1 = bg->robustMedian + threshold * bg->robustStdev; 604 stampThresh1 = threshold * bg->robustStdev; 605 psBinaryOp(ro1->image, ro1->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32)); 437 606 } 438 607 if (ro2) { 608 psStatsInit(bg); 439 609 if (!psImageBackground(bg, NULL, ro2->image, ro2->mask, maskVal, rng)) { 440 psError(P S_ERR_UNKNOWN, false, "Unable to measure background statistics.");610 psError(PM_ERR_DATA, false, "Unable to measure background statistics."); 441 611 psFree(bg); 442 612 goto MATCH_ERROR; 443 613 } 444 stampThresh2 = bg->robustMedian + threshold * bg->robustStdev; 614 stampThresh2 = threshold * bg->robustStdev; 615 psBinaryOp(ro2->image, ro2->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32)); 445 616 } 446 617 psFree(bg); 447 618 } 619 620 subtractionMatchAlloc(conv1, conv2, ro1, ro2, subMask, maskBad, subMode, numCols, numRows); 448 621 449 622 // Iterate over iso-kernel regions … … 452 625 psTrace("psModules.imcombine", 1, "Subtracting region %d of %d...\n", 453 626 j * xRegions + i + 1, xRegions * yRegions); 454 if (region) {455 *region = psRegionSet((int)(i * xRegionSize),(int)((i + 1) * xRegionSize),456 (int)(j * yRegionSize), (int)((j + 1) * yRegionSize));457 psFree(regionString);458 regionString = psRegionToString(*region);459 psTrace("psModules.imcombine", 3, "Iso-kernel region: %s out of %d,%d\n",460 regionString, numCols, numRows);461 }627 *region = psRegionSet(bounds.x0 + (int)(i * xRegionSize), 628 bounds.x0 + (int)((i + 1) * xRegionSize), 629 bounds.y0 + (int)(j * yRegionSize), 630 bounds.y0 + (int)((j + 1) * yRegionSize)); 631 psFree(regionString); 632 regionString = psRegionToString(*region); 633 psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Iso-kernel region: %s out of %d,%d\n", 634 regionString, numCols, numRows); 462 635 463 636 if (stampsName && strlen(stampsName) > 0) { 464 637 stamps = pmSubtractionStampsSetFromFile(stampsName, ro1->image, subMask, region, size, 465 footprint, stampSpacing, subMode); 638 footprint, stampSpacing, normFrac, 639 sysError, skyError, subMode); 466 640 } else if (sources) { 467 641 stamps = pmSubtractionStampsSetFromSources(sources, ro1->image, subMask, region, size, 468 footprint, stampSpacing, subMode); 642 footprint, stampSpacing, normFrac, 643 sysError, skyError, subMode); 469 644 } 470 645 471 646 // We get the stamps here; we will also attempt to get stamps at the first iteration, but it 472 647 // doesn't matter. 473 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, NULL, stampThresh1, stampThresh2,474 stampSpacing, size, footprint, subMode)) {648 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2, 649 stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) { 475 650 goto MATCH_ERROR; 476 651 } 477 652 653 654 // generate the window function from the set of stamps 655 if (!pmSubtractionStampsGetWindow(stamps, size)) { 656 psError(psErrorCodeLast(), false, "Unable to get stamp window."); 657 goto MATCH_ERROR; 658 } 659 660 // Define kernel basis functions 661 if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) { 662 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, 663 optFWHMs, optOrder, stamps, footprint, 664 optThreshold, penalty, bounds, subMode); 665 if (!kernels) { 666 psErrorClear(); 667 psWarning("Unable to derive optimum ISIS kernel --- switching to default."); 668 } 669 } 670 if (kernels == NULL) { 671 // Not an ISIS/GUNK kernel, or the optimum kernel search failed 672 kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders, 673 inner, binning, ringsOrder, penalty, bounds, subMode); 674 // pmSubtractionVisualShowKernels(kernels); 675 } 676 677 memCheck("kernels"); 678 478 679 if (subMode == PM_SUBTRACTION_MODE_UNSURE) { 680 #if 0 479 681 // Get backgrounds 480 682 psStats *bgStats = psStatsAlloc(BG_STAT); // Statistics for background 481 683 psVector *buffer = NULL;// Buffer for stats 482 684 if (!psImageBackground(bgStats, &buffer, ro1->image, ro1->mask, maskVal, rng)) { 483 psError(P S_ERR_UNKNOWN, false, "Unable to measure background of image 1.");685 psError(PM_ERR_DATA, false, "Unable to measure background of image 1."); 484 686 psFree(bgStats); 485 687 psFree(buffer); … … 488 690 float bg1 = psStatsGetValue(bgStats, BG_STAT); // Background for image 1 489 691 if (!psImageBackground(bgStats, &buffer, ro2->image, ro2->mask, maskVal, rng)) { 490 psError(P S_ERR_UNKNOWN, false, "Unable to measure background of image 2.");692 psError(PM_ERR_DATA, false, "Unable to measure background of image 2."); 491 693 psFree(bgStats); 492 694 psFree(buffer); … … 498 700 499 701 pmSubtractionMode newMode = pmSubtractionOrder(stamps, bg1, bg2); // Subtraction mode to use 702 #endif 703 pmSubtractionMode newMode = pmSubtractionBestMode(&stamps, &kernels, subMask, rej); 500 704 switch (newMode) { 501 705 case PM_SUBTRACTION_MODE_1: … … 506 710 break; 507 711 default: 508 psError( PS_ERR_UNKNOWN, false, "Unable to determine subtraction order.");712 psError(psErrorCodeLast(), false, "Unable to determine subtraction order."); 509 713 goto MATCH_ERROR; 510 714 } 511 715 subMode = newMode; 512 716 } 513 514 // Define kernel basis functions515 if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) {516 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, optFWHMs, optOrder,517 stamps, footprint, optThreshold, penalty, subMode);518 if (!kernels) {519 psErrorClear();520 psWarning("Unable to derive optimum ISIS kernel --- switching to default.");521 }522 }523 if (kernels == NULL) {524 // Not an ISIS/GUNK kernel, or the optimum kernel search failed525 kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders,526 inner, binning, ringsOrder, penalty, subMode);527 }528 529 memCheck("kernels");530 717 531 718 int numRejected = -1; // Number of rejected stamps in each iteration … … 534 721 535 722 if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, 536 stampThresh1, stampThresh2, stampSpacing, 537 size, footprint, subMode)) { 538 goto MATCH_ERROR; 539 } 540 541 psTrace("psModules.imcombine", 3, "Calculating equation...\n"); 542 if (!pmSubtractionCalculateEquation(stamps, kernels)) { 543 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 544 goto MATCH_ERROR; 545 } 546 723 stampThresh1, stampThresh2, stampSpacing, normFrac, 724 sysError, skyError, size, footprint, subMode)) { 725 goto MATCH_ERROR; 726 } 727 728 // generate the window function from the set of stamps 729 if (!pmSubtractionStampsGetWindow(stamps, size)) { 730 psError(psErrorCodeLast(), false, "Unable to get stamps window."); 731 goto MATCH_ERROR; 732 } 733 734 // XXX step 1: calculate normalization 735 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 736 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 737 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 738 goto MATCH_ERROR; 739 } 740 741 psTrace("psModules.imcombine", 3, "Solving equation for normalization...\n"); 742 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 743 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 744 goto MATCH_ERROR; 745 } 746 memCheck(" solve equation"); 747 748 # if (SEPARATE) 749 // set USED -> CALCULATE 750 pmSubtractionStampsResetStatus (stamps); 751 752 // XXX step 2: calculate kernel parameters 753 psTrace("psModules.imcombine", 3, "Calculating equation for kernels...\n"); 754 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 755 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 756 goto MATCH_ERROR; 757 } 547 758 memCheck(" calculate equation"); 548 759 549 psTrace("psModules.imcombine", 3, "Solving equation...\n"); 550 551 if (!pmSubtractionSolveEquation(kernels, stamps)) { 552 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 553 goto MATCH_ERROR; 554 } 555 760 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 761 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 762 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 763 goto MATCH_ERROR; 764 } 556 765 memCheck(" solve equation"); 557 766 # endif 558 767 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 559 768 if (!deviations) { 560 psError( PS_ERR_UNKNOWN, false, "Unable to calculate deviations.");769 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 561 770 goto MATCH_ERROR; 562 771 } … … 565 774 566 775 psTrace("psModules.imcombine", 3, "Rejecting stamps...\n"); 567 numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej , footprint);776 numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej); 568 777 if (numRejected < 0) { 569 psError( PS_ERR_UNKNOWN, false, "Unable to reject stamps.");778 psError(psErrorCodeLast(), false, "Unable to reject stamps."); 570 779 psFree(deviations); 571 780 goto MATCH_ERROR; … … 576 785 } 577 786 787 // if we hit the max number of iterations and we have rejected stamps, re-solve 578 788 if (numRejected > 0) { 579 psTrace("psModules.imcombine", 3, "Solving equation...\n"); 580 if (!pmSubtractionSolveEquation(kernels, stamps)) { 581 psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation."); 582 goto MATCH_ERROR; 583 } 789 // XXX step 1: calculate normalization 790 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 791 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 792 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 793 goto MATCH_ERROR; 794 } 795 796 // solve normalization 797 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 798 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 799 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 800 goto MATCH_ERROR; 801 } 802 803 # if (SEPARATE) 804 // set USED -> CALCULATE 805 pmSubtractionStampsResetStatus (stamps); 806 807 // XXX step 2: calculate kernel parameters 808 psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n"); 809 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 810 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 811 goto MATCH_ERROR; 812 } 813 814 // solve kernel parameters 815 psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n"); 816 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 817 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 818 goto MATCH_ERROR; 819 } 820 memCheck(" solve equation"); 821 # endif 584 822 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 585 823 if (!deviations) { 586 psError( PS_ERR_UNKNOWN, false, "Unable to calculate deviations.");587 goto MATCH_ERROR; 588 } 589 pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN , footprint);824 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 825 goto MATCH_ERROR; 826 } 827 pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN); 590 828 psFree(deviations); 591 829 } … … 596 834 597 835 if (!pmSubtractionAnalysis(analysis, header, kernels, region, numCols, numRows)) { 598 psError( PS_ERR_UNKNOWN, false, "Unable to generate QA data");836 psError(psErrorCodeLast(), false, "Unable to generate QA data"); 599 837 goto MATCH_ERROR; 600 838 } … … 604 842 psTrace("psModules.imcombine", 2, "Convolving...\n"); 605 843 if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac, 606 sysError, region, kernels, true, useFFT)) {607 psError( PS_ERR_UNKNOWN, false, "Unable to convolve image.");844 kernelError, covarFrac, region, kernels, true, useFFT)) { 845 psError(psErrorCodeLast(), false, "Unable to convolve image."); 608 846 goto MATCH_ERROR; 609 847 } … … 624 862 variance = NULL; 625 863 626 if (!pmSubtractionBorder(conv1->image, conv1->variance, conv1->mask, size, maskBad)) { 627 psError(PS_ERR_UNKNOWN, false, "Unable to set border of convolved image."); 864 if (conv1 && !pmSubtractionBorder(conv1->image, conv1->variance, conv1->mask, size, maskBad)) { 865 psError(psErrorCodeLast(), false, "Unable to set border of convolved image."); 866 goto MATCH_ERROR; 867 } 868 if (conv2 && !pmSubtractionBorder(conv2->image, conv2->variance, conv2->mask, size, maskBad)) { 869 psError(psErrorCodeLast(), false, "Unable to set border of convolved image."); 628 870 goto MATCH_ERROR; 629 871 } … … 824 1066 } else { 825 1067 if (!pmSubtractionOrderStamp(ratios, mask, stamps, models, modelSums, i, bg1, bg2)) { 826 psError( PS_ERR_UNKNOWN, false, "Unable to measure PSF width for stamp %d", i);1068 psError(psErrorCodeLast(), false, "Unable to measure PSF width for stamp %d", i); 827 1069 psFree(models); 828 1070 psFree(modelSums); … … 835 1077 836 1078 if (!psThreadPoolWait(true)) { 837 psError( PS_ERR_UNKNOWN, false, "Error waiting for threads.");1079 psError(psErrorCodeLast(), false, "Error waiting for threads."); 838 1080 psFree(models); 839 1081 psFree(modelSums); … … 848 1090 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); 849 1091 if (!psVectorStats(stats, ratios, NULL, mask, 0xff)) { 850 psError( PS_ERR_UNKNOWN, false, "Unable to calculate statistics for moments ratio.");1092 psError(psErrorCodeLast(), false, "Unable to calculate statistics for moments ratio."); 851 1093 psFree(mask); 852 1094 psFree(ratios); … … 869 1111 return mode; 870 1112 } 1113 1114 1115 // Test a subtraction mode by performing a single iteration 1116 static bool subtractionModeTest(pmSubtractionStampList *stamps, // Stamps to use to find best mode 1117 pmSubtractionKernels *kernels, // Kernel description 1118 const char *description, // Description for trace 1119 psImage *subMask, // Subtraction mask 1120 float rej // Rejection threshold 1121 ) 1122 { 1123 assert(stamps); 1124 assert(kernels); 1125 1126 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1127 if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) { 1128 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1129 return false; 1130 } 1131 1132 psTrace("psModules.imcombine", 3, "Solving %s normalization equation...\n", description); 1133 if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) { 1134 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1135 return false; 1136 } 1137 1138 # if (SEPARATE) 1139 // set USED -> CALCULATE 1140 pmSubtractionStampsResetStatus (stamps); 1141 1142 psTrace("psModules.imcombine", 3, "Calculating %s kernel coeffs equation...\n", description); 1143 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 1144 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1145 return false; 1146 } 1147 1148 psTrace("psModules.imcombine", 3, "Solving %s kernel coeffs equation...\n", description); 1149 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 1150 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1151 return false; 1152 } 1153 # endif 1154 1155 psTrace("psModules.imcombine", 3, "Calculate %s deviations...\n", description); 1156 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 1157 if (!deviations) { 1158 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 1159 return false; 1160 } 1161 1162 psTrace("psModules.imcombine", 3, "Rejecting %s stamps...\n", description); 1163 long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej); 1164 if (numRejected < 0) { 1165 psError(psErrorCodeLast(), false, "Unable to reject stamps."); 1166 psFree(deviations); 1167 return false; 1168 } 1169 psFree(deviations); 1170 1171 if (numRejected > 0) { 1172 // Allow re-fit with reduced stamps set 1173 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1174 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_ALL)) { 1175 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1176 return false; 1177 } 1178 1179 psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description); 1180 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_ALL)) { 1181 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1182 return false; 1183 } 1184 psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description); 1185 1186 # if (SEPARATE) 1187 // set USED -> CALCULATE 1188 pmSubtractionStampsResetStatus (stamps); 1189 1190 psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description); 1191 if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) { 1192 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1193 return false; 1194 } 1195 1196 psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description); 1197 if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) { 1198 psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation."); 1199 return false; 1200 } 1201 psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description); 1202 # endif 1203 1204 psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations 1205 if (!deviations) { 1206 psError(psErrorCodeLast(), false, "Unable to calculate deviations."); 1207 return false; 1208 } 1209 psTrace("psModules.imcombine", 3, "Measuring %s quality...\n", description); 1210 long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN); 1211 if (numRejected < 0) { 1212 psError(psErrorCodeLast(), false, "Unable to reject stamps."); 1213 psFree(deviations); 1214 return false; 1215 } 1216 psFree(deviations); 1217 } 1218 1219 return true; 1220 } 1221 1222 1223 pmSubtractionMode pmSubtractionBestMode(pmSubtractionStampList **stamps, pmSubtractionKernels **kernels, 1224 const psImage *subMask, float rej) 1225 { 1226 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(*stamps, PM_SUBTRACTION_MODE_ERR); 1227 PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(*kernels, PM_SUBTRACTION_MODE_ERR); 1228 1229 // Copies of the inputs 1230 pmSubtractionStampList *stamps1 = pmSubtractionStampListCopy(*stamps); 1231 pmSubtractionKernels *kernels1 = pmSubtractionKernelsCopy(*kernels); 1232 psImage *subMask1 = psImageCopy(NULL, subMask, subMask->type.type); 1233 kernels1->mode = PM_SUBTRACTION_MODE_1; 1234 1235 if (!subtractionModeTest(stamps1, kernels1, "convolve 1", subMask1, rej)) { 1236 psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 1"); 1237 psFree(stamps1); 1238 psFree(kernels1); 1239 psFree(subMask1); 1240 return PM_SUBTRACTION_MODE_ERR; 1241 } 1242 psFree(subMask1); 1243 1244 // Copies of the inputs 1245 pmSubtractionStampList *stamps2 = pmSubtractionStampListCopy(*stamps); 1246 pmSubtractionKernels *kernels2 = pmSubtractionKernelsCopy(*kernels); 1247 psImage *subMask2 = psImageCopy(NULL, subMask, subMask->type.type); 1248 kernels2->mode = PM_SUBTRACTION_MODE_2; 1249 1250 if (!subtractionModeTest(stamps2, kernels2, "convolve 2", subMask2, rej)) { 1251 psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 2"); 1252 psFree(stamps2); 1253 psFree(kernels2); 1254 psFree(subMask2); 1255 psFree(stamps1); 1256 psFree(kernels1); 1257 return PM_SUBTRACTION_MODE_ERR; 1258 } 1259 psFree(subMask2); 1260 1261 1262 pmSubtractionStampList *bestStamps = NULL; // Best choice for stamps 1263 pmSubtractionKernels *bestKernels = NULL; // Best choice for kernels 1264 psLogMsg("psModules.imcombine", PS_LOG_INFO, 1265 "Image 1: %f +/- %f from %d stamps\nImage 2: %f +/- %f from %d stamps\n", 1266 kernels1->mean, kernels1->rms, kernels1->numStamps, 1267 kernels2->mean, kernels2->rms, kernels2->numStamps); 1268 1269 if (kernels1->mean < kernels2->mean) { 1270 bestStamps = stamps1; 1271 bestKernels = kernels1; 1272 } else { 1273 bestStamps = stamps2; 1274 bestKernels = kernels2; 1275 } 1276 1277 psFree(*stamps); 1278 psFree(*kernels); 1279 *stamps = psMemIncrRefCounter(bestStamps); 1280 *kernels = psMemIncrRefCounter(bestKernels); 1281 1282 psFree(stamps1); 1283 psFree(stamps2); 1284 psFree(kernels1); 1285 psFree(kernels2); 1286 1287 return bestKernels->mode; 1288 } 1289 1290 1291 bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths, 1292 float fwhm1, float fwhm2, float scaleRef, float scaleMin, float scaleMax) 1293 { 1294 PS_ASSERT_PTR_NON_NULL(kernelSize, false); 1295 PS_ASSERT_PTR_NON_NULL(stampSize, false); 1296 PS_ASSERT_VECTOR_NON_NULL(widths, false); 1297 PS_ASSERT_VECTOR_TYPE(widths, PS_TYPE_F32, false); 1298 PS_ASSERT_FLOAT_LARGER_THAN(fwhm1, 0.0, false); 1299 PS_ASSERT_FLOAT_LARGER_THAN(fwhm2, 0.0, false); 1300 PS_ASSERT_FLOAT_LARGER_THAN(scaleRef, 0.0, false); 1301 PS_ASSERT_FLOAT_LARGER_THAN(scaleMin, 0.0, false); 1302 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, 0.0, false); 1303 PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, scaleMin, false); 1304 1305 // float diff = sqrtf(PS_SQR(PS_MAX(fwhm1, fwhm2)) - PS_SQR(PS_MIN(fwhm1, fwhm2))); // Difference 1306 float scale = PS_MAX(fwhm1, fwhm2) / scaleRef; // Scaling factor 1307 1308 if (isfinite(scaleMin) && scale < scaleMin) { 1309 scale = scaleMin; 1310 } 1311 if (isfinite(scaleMax) && scale > scaleMax) { 1312 scale = scaleMax; 1313 } 1314 1315 for (int i = 0; i < widths->n; i++) { 1316 widths->data.F32[i] *= scale; 1317 } 1318 *kernelSize = *kernelSize * scale + 0.5; 1319 *stampSize = *stampSize * scale + 0.5; 1320 1321 psLogMsg("psModules.imcombine", PS_LOG_INFO, 1322 "Scaling kernel parameters by %f: %d %d", scale, *kernelSize, *stampSize); 1323 1324 return true; 1325 } -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionMatch.h
r23308 r27840 39 39 int iter, ///< Rejection iterations 40 40 float rej, ///< Rejection threshold 41 float sysError, ///< Relative systematic error 41 float normFrac, ///< Fraction of flux in window for normalisation window 42 float sysError, ///< Relative systematic error in images 43 float skyError, ///< Relative systematic error in images 44 float kernelError, ///< Relative systematic error in kernel 45 float covarFrac, ///< Fraction for kernel truncation before covariance calculation 42 46 psImageMaskType maskVal, ///< Value to mask for input 43 47 psImageMaskType maskBad, ///< Mask for output bad pixels … … 55 59 psMetadata *analysis, ///< Analysis metadata with pre-calculated kernel, region 56 60 int stride, ///< Size for convolution patches 57 float sysError, ///< Relative systematic error 61 float kernelError, ///< Relative systematic error in kernel 62 float covarFrac, ///< Fraction for kernel truncation before covariance calc. 58 63 psImageMaskType maskVal, ///< Value to mask for input 59 64 psImageMaskType maskBad, ///< Mask for output bad pixels … … 83 88 ); 84 89 90 /// Determine best subtraction mode to use 91 /// 92 /// Subtractions are attempted each way, and the mode with the lower residual is taken to be the best 93 pmSubtractionMode pmSubtractionBestMode( 94 pmSubtractionStampList **stamps, ///< Stamps to use for solution 95 pmSubtractionKernels **kernels, ///< Kernels to use for solution 96 const psImage *subMask, ///< Subtraction mask 97 float rej ///< Rejection threshold for stamps 98 ); 99 100 101 /// Scale subtraction parameters according to the FWHMs of the inputs 102 bool pmSubtractionParamsScale( 103 int *kernelSize, ///< Half-size of the kernel 104 int *stampSize, ///< Half-size of the stamp (footprint) 105 psVector *widths, ///< ISIS widths 106 float fwhm1, float fwhm2, ///< FWHMs for inputs 107 float scaleRef, ///< Reference width for scaling 108 float scaleMin, ///< Minimum scaling ratio, or NAN 109 float scaleMax ///< Maximum scaling ratio, or NAN 110 ); 111 85 112 86 113 #endif -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionParams.c
r21363 r27840 8 8 #include <pslib.h> 9 9 10 #include "pmErrorCodes.h" 10 11 #include "pmSubtractionStamps.h" 11 12 #include "pmSubtraction.h" … … 71 72 double *sumII, // Sum of I(x)^2/sigma(x)^2 72 73 double *sumIC, // Sum of I(x)conv(x)/sigma(x)^2 73 const pmSubtractionStamp *stamp, // Stamp with variance74 const pmSubtractionStamp *stamp, // Stamp 74 75 const psKernel *target, // Target stamp 75 76 int kernelIndex, // Index for kernel component … … 78 79 ) 79 80 { 80 psKernel * variance = stamp->variance; // Variance, sigma(x)^281 psKernel *weight = stamp->weight; // Weight image 81 82 psKernel *convolution = selectConvolution(stamp, kernelIndex, mode); // Convolution of interest 82 83 83 84 for (int y = -footprint; y <= footprint; y++) { 84 85 psF32 *in = &target->kernel[y][-footprint]; // Dereference input 85 psF32 *wt = & variance->kernel[y][-footprint]; // Dereference variance86 psF32 *wt = &weight->kernel[y][-footprint]; // Dereference weight 86 87 psF32 *conv = &convolution->kernel[y][-footprint]; // Dereference convolution 87 88 for (int x = -footprint; x <= footprint; x++, in++, wt++, conv++) { 88 double temp = *in /*wt; // Temporary product89 double temp = *in * *wt; // Temporary product 89 90 *sumI += temp; 90 91 *sumII += *in * temp; … … 98 99 static void accumulateConvolutions(double *sumC, // Sum of conv(x)/sigma(x)^2 99 100 double *sumCC, // Sum of conv(x)^2/sigma(x)^2 100 const pmSubtractionStamp *stamp, // Stamp with input and variance101 const pmSubtractionStamp *stamp, // Stamp with input and weight 101 102 int kernelIndex, // Index for kernel component 102 103 int footprint, // Size of region of interest … … 104 105 ) 105 106 { 106 psKernel * variance = stamp->variance; // Variance, sigma(x)^2107 psKernel *weight = stamp->weight; // Weight image 107 108 psKernel *convolution = selectConvolution(stamp, kernelIndex, mode); // Convolution of interest 108 109 109 110 for (int y = -footprint; y <= footprint; y++) { 110 psF32 *wt = & variance->kernel[y][-footprint]; // Dereference variance111 psF32 *wt = &weight->kernel[y][-footprint]; // Dereference weight 111 112 psF32 *conv = &convolution->kernel[y][-footprint]; // Dereference convolution 112 113 for (int x = -footprint; x <= footprint; x++, wt++, conv++) { 113 double convNoise = *conv /*wt; // Temporary product114 double convNoise = *conv * *wt; // Temporary product 114 115 *sumC += convNoise; 115 116 *sumCC += *conv * convNoise; … … 120 121 121 122 static double accumulateChi2(const psKernel *target, // Target stamp 122 pmSubtractionStamp *stamp, // Stamp with variance123 pmSubtractionStamp *stamp, // Stamp with weight 123 124 int kernelIndex, // Index for kernel component 124 125 double coeff, // Coefficient of convolution … … 129 130 { 130 131 double chi2 = 0.0; 131 psKernel * variance = stamp->variance; // Variance, sigma(x)^2132 psKernel *weight = stamp->weight; // Weight image 132 133 psKernel *convolution = selectConvolution(stamp, kernelIndex, mode); // Convolution of interest 133 134 134 135 for (int y = -footprint; y <= footprint; y++) { 135 136 psF32 *in = &target->kernel[y][-footprint]; // Dereference input 136 psF32 *wt = & variance->kernel[y][-footprint]; // Dereference variance137 psF32 *wt = &weight->kernel[y][-footprint]; // Dereference weight 137 138 psF32 *conv = &convolution->kernel[y][-footprint]; // Dereference convolution 138 139 for (int x = -footprint; x <= footprint; x++, in++, wt++, conv++) { 139 chi2 += PS_SQR(*in - bg - coeff * *conv) /*wt;140 chi2 += PS_SQR(*in - bg - coeff * *conv) * *wt; 140 141 } 141 142 } … … 146 147 // Return the initial value of chi^2 147 148 static double initialChi2(const psKernel *target, // Target stamp 148 const pmSubtractionStamp *stamp, // Stamp with variance149 const pmSubtractionStamp *stamp, // Stamp 149 150 int footprint, // Size of convolution 150 151 pmSubtractionMode mode // Mode of subtraction 151 152 ) 152 153 { 153 psKernel * variance = stamp->variance; // Variance map154 psKernel *weight = stamp->weight; // Weight image 154 155 psKernel *source; // Source stamp 155 156 switch (mode) { … … 167 168 for (int y = -footprint; y <= footprint; y++) { 168 169 psF32 *in = &target->kernel[y][-footprint]; // Dereference input 169 psF32 *wt = & variance->kernel[y][-footprint]; // Dereference variance170 psF32 *wt = &weight->kernel[y][-footprint]; // Dereference weight 170 171 psF32 *ref = &source->kernel[y][-footprint]; // Derference reference 171 172 for (int x = -footprint; x <= footprint; x++, in++, wt++, ref++) { 172 173 float diff = *in - *ref; // Temporary value 173 chi2 += PS_SQR(diff) /*wt;174 chi2 += PS_SQR(diff) * *wt; 174 175 } 175 176 } … … 180 181 // Subtract a convolution from the input 181 182 static void subtractConvolution(psKernel *target, // Target stamp 182 const pmSubtractionStamp *stamp, // Stamp with variance183 const pmSubtractionStamp *stamp, // Stamp 183 184 int kernelIndex, // Index for kernel component 184 185 float coeff, // Coefficient of subtraction … … 204 205 int spatialOrder, const psVector *fwhms, int maxOrder, 205 206 const pmSubtractionStampList *stamps, int footprint, 206 float tolerance, float penalty, pmSubtractionMode mode) 207 float tolerance, float penalty, psRegion bounds, 208 pmSubtractionMode mode) 207 209 { 208 210 if (type != PM_SUBTRACTION_KERNEL_ISIS && type != PM_SUBTRACTION_KERNEL_GUNK) { … … 232 234 psVectorInit(orders, maxOrder); 233 235 pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder, fwhms, orders, 234 penalty, mode); // Kernels236 penalty, bounds, mode); // Kernels 235 237 psFree(orders); 236 238 psFree(kernels->description); … … 280 282 } 281 283 if (!pmSubtractionConvolveStamp(stamp, kernels, footprint)) { 282 psError( PS_ERR_UNKNOWN, false, "Unable to convolve stamp %d.", i);284 psError(psErrorCodeLast(), false, "Unable to convolve stamp %d.", i); 283 285 psFree(targets); 284 286 psFree(kernels); … … 288 290 289 291 // This sum is invariant to the kernel 290 psKernel * variance = stamp->variance; // Variance map for stamp292 psKernel *weight = stamp->weight; // Weight image 291 293 for (int v = -footprint; v <= footprint; v++) { 292 psF32 *wt = & variance->kernel[v][-footprint]; // Dereference variance map294 psF32 *wt = &weight->kernel[v][-footprint]; // Dereference weight 293 295 for (int u = -footprint; u <= footprint; u++, wt++) { 294 sum1 += 1.0 /*wt;296 sum1 += 1.0 * *wt; 295 297 } 296 298 } 297 299 if (!isfinite(sum1)) { 298 psError(P S_ERR_BAD_PARAMETER_VALUE, true,300 psError(PM_ERR_DATA, true, 299 301 "Sum of 1/sigma^2 is non-finite for stamp %d (%d,%d)\n", 300 302 i, (int)stamp->x, (int)stamp->y); … … 368 370 369 371 if (bestIndex == -1) { 370 psError(P S_ERR_UNKNOWN, false, "Unable to find best kernel component in round %d.", iter);372 psError(PM_ERR_DATA, true, "Unable to find best kernel component in round %d.", iter); 371 373 psFree(targets); 372 374 psFree(sumC); … … 407 409 408 410 if (cutIndex < 0) { 409 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Unable to converge to tolerance %g\n", tolerance);411 psError(PM_ERR_DATA, true, "Unable to converge to tolerance %g\n", tolerance); 410 412 psFree(ranking); 411 413 psFree(kernels); … … 482 484 // Maintain photometric scaling 483 485 if (type == PM_SUBTRACTION_KERNEL_ISIS) { 484 psKernel *subtract = kernels->preCalc->data[0]; // Kernel to subtract from the rest 486 487 // XXX in r26035, this code was just wrong. we had: 488 489 // psKernel *subtract = kernels->preCalc->data[0] 490 491 // but, kernels->preCalc was an array of psArray, not an array of kernels. It is now 492 // an array of pmSubtractionKernelPreCalc. 493 494 pmSubtractionKernelPreCalc *subtract = kernels->preCalc->data[0]; // Kernel to subtract from the rest 495 485 496 for (int i = 1; i < newSize; i++) { 486 497 if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) { 487 p sKernel *kernel= kernels->preCalc->data[i]; // Kernel of interest488 psBinaryOp( kernel->image, kernel->image, "-", subtract->image);498 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Kernel of interest 499 psBinaryOp(preCalc->kernel->image, preCalc->kernel->image, "-", subtract->kernel->image); 489 500 } 490 501 } … … 495 506 for (int i = 0; i < newSize; i++) { 496 507 if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) { 497 p sKernel *kernel= kernels->preCalc->data[i]; // Kernel of interest498 kernel->kernel[0][0] -= 1.0;508 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; // Kernel of interest 509 preCalc->kernel->kernel[0][0] -= 1.0; 499 510 } 500 511 } -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionParams.h
r18287 r27840 17 17 float tolerance, ///< Maximum difference in chi^2 18 18 float penalty, ///< Penalty for wideness 19 pmSubtractionMode mode // Mode for subtraction 19 psRegion bounds, ///< Bounds of validity 20 pmSubtractionMode mode ///< Mode for subtraction 20 21 ); 21 22 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionStamps.c
r24066 r27840 46 46 psFree(list->y); 47 47 psFree(list->flux); 48 psFree(list->window); 48 49 } 49 50 … … 54 55 psFree(stamp->image1); 55 56 psFree(stamp->image2); 56 psFree(stamp-> variance);57 psFree(stamp->weight); 57 58 psFree(stamp->convolutions1); 58 59 psFree(stamp->convolutions2); 59 60 psFree(stamp->matrix1); 61 psFree(stamp->matrix2); 62 psFree(stamp->matrixX); 63 psFree(stamp->vector1); 64 psFree(stamp->vector2); 65 60 psFree(stamp->matrix); 61 psFree(stamp->vector); 66 62 } 67 63 … … 80 76 81 77 // Search a region for a suitable stamp 82 bool stampSearch( int *xStamp, int *yStamp, // Coordinates of stamp, to return78 bool stampSearch(float *xStamp, float *yStamp, // Coordinates of stamp, to return 83 79 float *fluxStamp, // Flux of stamp, to return 84 80 const psImage *image1, const psImage *image2, // Images to search … … 93 89 *fluxStamp = -INFINITY; // Flux of best stamp 94 90 91 // fprintf (stderr, "xMin, xMax: %d, %d -> ", xMin, xMax); 92 95 93 // Ensure we're not going to go outside the bounds of the image 96 94 xMin = PS_MAX(border, xMin); … … 99 97 yMax = PS_MIN(numRows - border - 1, yMax); 100 98 99 if (xMax < xMin) return false; 100 if (yMax < yMin) return false; 101 102 psAssert (xMin <= xMax, "x mismatch?"); 103 psAssert (yMin <= yMax, "y mismatch?"); 104 101 105 for (int y = yMin; y <= yMax; y++) { 102 106 for (int x = xMin; x <= xMax; x++) { … … 115 119 ((image1) ? image1->data.F32[y][x] : image2->data.F32[y][x]); // Flux at pixel 116 120 if (flux > *fluxStamp) { 117 *xStamp = x ;118 *yStamp = y ;121 *xStamp = x + 0.5; 122 *yStamp = y + 0.5; 119 123 *fluxStamp = flux; 120 124 found = true; … … 180 184 181 185 pmSubtractionStampList *pmSubtractionStampListAlloc(int numCols, int numRows, const psRegion *region, 182 int footprint, float spacing) 186 int footprint, float spacing, float normFrac, 187 float sysErr, float skyErr) 183 188 { 184 189 pmSubtractionStampList *list = psAlloc(sizeof(pmSubtractionStampList)); // Stamp list to return … … 220 225 list->y = NULL; 221 226 list->flux = NULL; 227 list->window = NULL; 228 list->normFrac = normFrac; 229 list->normWindow = 0; 222 230 list->footprint = footprint; 231 list->sysErr = sysErr; 232 list->skyErr = skyErr; 223 233 224 234 return list; 235 } 236 237 pmSubtractionStampList *pmSubtractionStampListCopy(const pmSubtractionStampList *in) 238 { 239 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(in, NULL); 240 241 pmSubtractionStampList *out = psAlloc(sizeof(pmSubtractionStampList)); // Copied stamp list to return 242 psMemSetDeallocator(out, (psFreeFunc)subtractionStampListFree); 243 244 int num = out->num = in->num; // Number of stamps 245 out->stamps = psArrayAlloc(num); 246 out->regions = psArrayAlloc(num); 247 out->x = NULL; 248 out->y = NULL; 249 out->flux = NULL; 250 out->window = psMemIncrRefCounter(in->window); 251 out->footprint = in->footprint; 252 out->normWindow = in->normWindow; 253 254 for (int i = 0; i < num; i++) { 255 psRegion *inRegion = in->regions->data[i]; // Input region 256 out->regions->data[i] = psRegionAlloc(inRegion->x0, inRegion->x1, inRegion->y0, inRegion->y1); 257 258 pmSubtractionStamp *inStamp = in->stamps->data[i]; // Input stamp 259 pmSubtractionStamp *outStamp = psAlloc(sizeof(pmSubtractionStamp)); 260 psMemSetDeallocator(outStamp, (psFreeFunc)subtractionStampFree); 261 outStamp->x = inStamp->x; 262 outStamp->y = inStamp->y; 263 outStamp->flux = inStamp->flux; 264 outStamp->xNorm = inStamp->xNorm; 265 outStamp->yNorm = inStamp->yNorm; 266 outStamp->status = inStamp->status; 267 268 outStamp->image1 = inStamp->image1 ? psKernelCopy(inStamp->image1) : NULL; 269 outStamp->image2 = inStamp->image2 ? psKernelCopy(inStamp->image2) : NULL; 270 outStamp->weight = inStamp->weight ? psKernelCopy(inStamp->weight) : NULL; 271 272 if (inStamp->convolutions1) { 273 int size = inStamp->convolutions1->n; // Size of array 274 outStamp->convolutions1 = psArrayAlloc(size); 275 for (int j = 0; j < size; j++) { 276 psKernel *conv = inStamp->convolutions1->data[j]; // Convolution 277 outStamp->convolutions1->data[j] = conv ? psKernelCopy(conv) : NULL; 278 } 279 } else { 280 outStamp->convolutions1 = NULL; 281 } 282 if (inStamp->convolutions2) { 283 int size = inStamp->convolutions2->n; // Size of array 284 outStamp->convolutions2 = psArrayAlloc(size); 285 for (int j = 0; j < size; j++) { 286 psKernel *conv = inStamp->convolutions2->data[j]; // Convolution 287 outStamp->convolutions2->data[j] = conv ? psKernelCopy(conv) : NULL; 288 } 289 } else { 290 outStamp->convolutions2 = NULL; 291 } 292 293 outStamp->matrix = inStamp->matrix ? psImageCopy(NULL, inStamp->matrix, PS_TYPE_F64) : NULL; 294 outStamp->vector = inStamp->vector ? psVectorCopy(NULL, inStamp->vector, PS_TYPE_F64) : NULL; 295 296 out->stamps->data[i] = outStamp; 297 } 298 299 return out; 225 300 } 226 301 … … 239 314 stamp->image1 = NULL; 240 315 stamp->image2 = NULL; 241 stamp-> variance= NULL;316 stamp->weight = NULL; 242 317 stamp->convolutions1 = NULL; 243 318 stamp->convolutions2 = NULL; 244 319 245 stamp->matrix1 = NULL; 246 stamp->matrix2 = NULL; 247 stamp->matrixX = NULL; 248 stamp->vector1 = NULL; 249 stamp->vector2 = NULL; 320 stamp->matrix = NULL; 321 stamp->vector = NULL; 322 stamp->norm = NAN; 250 323 251 324 return stamp; … … 256 329 const psImage *image2, const psImage *subMask, 257 330 const psRegion *region, float thresh1, float thresh2, 258 int size, int footprint, float spacing, 259 pmSubtractionMode mode)331 int size, int footprint, float spacing, float normFrac, 332 float sysErr, float skyErr, pmSubtractionMode mode) 260 333 { 261 334 if (!image1 && !image2) { … … 296 369 if (psRegionIsNaN(*region)) { 297 370 psString string = psRegionToString(*region); 298 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Input region (%s) contains NAN values", string);371 psError(PM_ERR_PROG, true, "Input region (%s) contains NAN values", string); 299 372 psFree(string); 300 373 return false; … … 303 376 region->y0 < 0 || region->y1 > numRows) { 304 377 psString string = psRegionToString(*region); 305 psError(P S_ERR_BAD_PARAMETER_VALUE, true, "Input region (%s) does not fit in image (%dx%d)",378 psError(PM_ERR_PROG, true, "Input region (%s) does not fit in image (%dx%d)", 306 379 string, numCols, numRows); 307 380 psFree(string); … … 313 386 314 387 if (!stamps) { 315 stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing); 388 stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing, 389 normFrac, sysErr, skyErr); 316 390 } 317 391 … … 335 409 numSearch++; 336 410 337 int xStamp = 0, yStamp =0; // Coordinates of stamp411 float xStamp = 0.0, yStamp = 0.0; // Coordinates of stamp 338 412 float fluxStamp = -INFINITY; // Flux of stamp 339 413 bool goodStamp = false; // Found a good stamp? … … 347 421 // Take stamps off the top of the (sorted) list 348 422 for (int j = xList->n - 1; j >= 0 && !goodStamp; j--) { 349 int xCentre = xList->data.F32[j] + 0.5, yCentre = yList->data.F32[j] + 0.5;// Stamp centre350 351 423 // Chop off the top of the list 352 424 xList->n = j; … … 354 426 fluxList->n = j; 355 427 428 #if 0 356 429 // Fish around a bit to see if we can find a pixel that isn't masked 430 // This is not a good idea if we're using the window feature 357 431 psTrace("psModules.imcombine", 7, "Searching for stamp %d around %d,%d\n", 358 432 i, xCentre, yCentre); 359 433 360 434 // Search bounds 435 int xCentre = xList->data.F32[j] - 0.5, yCentre = yList->data.F32[j] - 0.5;// Stamp centre 361 436 int search = footprint - size; // Search radius 362 437 int xMin = PS_MAX(border, xCentre - search); … … 367 442 goodStamp = stampSearch(&xStamp, &yStamp, &fluxStamp, image1, image2, thresh1, thresh2, 368 443 subMask, xMin, xMax, yMin, yMax, numCols, numRows, border); 444 // fprintf (stderr, "find: %d %d ==> %5.1f %5.1f (\n", xCentre, yCentre, xStamp, yStamp); 445 #else 446 // Only search the exact centre pixel 447 goodStamp = stampSearch(&xStamp, &yStamp, &fluxStamp, image1, image2, thresh1, thresh2, 448 subMask, xList->data.F32[j], xList->data.F32[j], 449 yList->data.F32[j], yList->data.F32[j], numCols, numRows, border); 450 #endif 451 if (0 && goodStamp) { 452 fprintf (stderr, "find: %6.1f < %6.1f < %6.1f, %6.1f < %6.1f %6.1f\n", 453 region->x0 + size, xStamp, region->x1 - size, 454 region->y0 + size, yStamp, region->y1 - size); 455 } 369 456 } 370 457 } else { … … 386 473 psFree(stamp->image1); 387 474 psFree(stamp->image2); 388 psFree(stamp-> variance);475 psFree(stamp->weight); 389 476 psFree(stamp->convolutions1); 390 477 psFree(stamp->convolutions2); 391 stamp->image1 = stamp->image2 = stamp-> variance= NULL;478 stamp->image1 = stamp->image2 = stamp->weight = NULL; 392 479 stamp->convolutions1 = stamp->convolutions2 = NULL; 393 480 … … 421 508 const psImage *image, const psImage *subMask, 422 509 const psRegion *region, int size, int footprint, 423 float spacing, pmSubtractionMode mode) 510 float spacing, float normFrac, float sysErr, float skyErr, 511 pmSubtractionMode mode) 424 512 425 513 { … … 441 529 int numStars = x->n; // Number of stars 442 530 pmSubtractionStampList *stamps = pmSubtractionStampListAlloc(subMask->numCols, subMask->numRows, 443 region, footprint, spacing); // Stamp list 531 region, footprint, spacing, 532 normFrac, sysErr, skyErr); // Stamp list 444 533 int numStamps = stamps->num; // Number of stamps 445 534 … … 448 537 psStringAppend(&ds9name, "stamps_all_%d.ds9", ds9num); 449 538 FILE *ds9 = pmSubtractionStampsFile(stamps, ds9name, "all stamps"); // ds9 region file 539 psFree(ds9name); 450 540 ds9num++; 451 541 … … 463 553 for (int i = 0; i < numStars; i++) { 464 554 float xStamp = x->data.F32[i], yStamp = y->data.F32[i]; // Coordinates of stamp 465 int xPix = xStamp + 0.5, yPix = yStamp +0.5; // Pixel coordinate of stamp555 int xPix = xStamp - 0.5, yPix = yStamp - 0.5; // Pixel coordinate of stamp 466 556 if (!checkStampRegion(xPix, yPix, region)) { 467 557 // It's not in the big region … … 471 561 continue; 472 562 } 563 564 // fprintf (stderr, "stamp: %5.1f %5.1f == %d %d\n", xStamp, yStamp, xPix, yPix); 473 565 474 566 bool found = false; … … 539 631 540 632 633 bool pmSubtractionStampsGetWindow(pmSubtractionStampList *stamps, int kernelSize) 634 { 635 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); 636 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 637 638 int size = stamps->footprint; // Size of postage stamps 639 640 psFree (stamps->window); 641 stamps->window = psKernelAlloc(-size, size, -size, size); 642 psImageInit(stamps->window->image, 0.0); 643 644 // generate normalizations for each stamp 645 psVector *norm1 = psVectorAlloc(stamps->num, PS_TYPE_F32); 646 psVector *norm2 = psVectorAlloc(stamps->num, PS_TYPE_F32); 647 for (int i = 0; i < stamps->num; i++) { 648 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 649 if (!stamp) continue; 650 if (!stamp->image1) continue; 651 if (!stamp->image2) continue; 652 653 float sum1 = 0.0; 654 float sum2 = 0.0; 655 for (int y = -size; y <= size; y++) { 656 for (int x = -size; x <= size; x++) { 657 sum1 += stamp->image1->kernel[y][x]; 658 sum2 += stamp->image2->kernel[y][x]; 659 } 660 } 661 norm1->data.F32[i] = sum1; 662 norm2->data.F32[i] = sum2; 663 } 664 665 // storage vector for flux data 666 psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 667 psVector *flux1 = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32); 668 psVector *flux2 = psVectorAllocEmpty(2*stamps->num, PS_TYPE_F32); 669 670 // generate the window pixels 671 double sum = 0.0; // Sum inside the window 672 float maxValue = 0.0; // Maximum value, for normalisation 673 for (int y = -size; y <= size; y++) { 674 for (int x = -size; x <= size; x++) { 675 676 flux1->n = 0; 677 flux2->n = 0; 678 for (int i = 0; i < stamps->num; i++) { 679 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 680 if (!stamp) continue; 681 if (!stamp->image1) continue; 682 if (!stamp->image2) continue; 683 684 psVectorAppend(flux1, stamp->image1->kernel[y][x] / norm1->data.F32[i]); 685 psVectorAppend(flux2, stamp->image2->kernel[y][x] / norm2->data.F32[i]); 686 } 687 688 psStatsInit (stats); 689 if (!psVectorStats (stats, flux1, NULL, NULL, 0)) { 690 psAbort ("failed to generate stats"); 691 } 692 float f1 = stats->robustMedian; 693 psStatsInit (stats); 694 if (!psVectorStats (stats, flux2, NULL, NULL, 0)) { 695 psAbort ("failed to generate stats"); 696 } 697 float f2 = stats->robustMedian; 698 699 stamps->window->kernel[y][x] = f1 + f2; 700 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(size)) { 701 sum += stamps->window->kernel[y][x]; 702 } 703 maxValue = PS_MAX(maxValue, stamps->window->kernel[y][x]); 704 } 705 } 706 707 psTrace("psModules.imcombine", 3, "Window total: %f, threshold: %f\n", 708 sum, (1.0 - stamps->normFrac) * sum); 709 bool done = false; 710 for (int radius = 1; radius <= size && !done; radius++) { 711 double within = 0.0; 712 for (int y = -radius; y <= radius; y++) { 713 for (int x = -radius; x <= radius; x++) { 714 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) { 715 within += stamps->window->kernel[y][x]; 716 } 717 } 718 } 719 psTrace("psModules.imcombine", 5, "Radius %d: %f\n", radius, within); 720 if (within > (1.0 - stamps->normFrac) * sum) { 721 stamps->normWindow = radius; 722 done = true; 723 } 724 } 725 726 psTrace("psModules.imcombine", 3, "Normalisation window radius set to %d\n", stamps->normWindow); 727 if (stamps->normWindow == 0 || stamps->normWindow >= size) { 728 psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size."); 729 return false; 730 } 731 732 // re-normalize so chisquare values are sensible 733 for (int y = -size; y <= size; y++) { 734 for (int x = -size; x <= size; x++) { 735 stamps->window->kernel[y][x] /= maxValue; 736 } 737 } 738 739 #if 0 740 { 741 psFits *fits = psFitsOpen ("window.fits", "w"); 742 psFitsWriteImage (fits, NULL, stamps->window->image, 0, NULL); 743 psFitsClose (fits); 744 } 745 #endif 746 747 psFree (stats); 748 psFree (flux1); 749 psFree(flux2); 750 psFree (norm1); 751 psFree (norm2); 752 return true; 753 } 754 541 755 bool pmSubtractionStampsExtract(pmSubtractionStampList *stamps, psImage *image1, psImage *image2, 542 psImage *variance, int kernelSize )756 psImage *variance, int kernelSize, psRegion bounds) 543 757 { 544 758 PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false); … … 550 764 PS_ASSERT_IMAGE_TYPE(image2, PS_TYPE_F32, false); 551 765 } 552 PS_ASSERT_IMAGE_NON_NULL(variance, false); 553 PS_ASSERT_IMAGES_SIZE_EQUAL(variance, image1, false); 554 PS_ASSERT_IMAGE_TYPE(variance, PS_TYPE_F32, false); 555 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 556 557 int numCols = image1->numCols, numRows = image1->numRows; // Size of images 766 if (variance) { 767 PS_ASSERT_IMAGE_NON_NULL(variance, false); 768 PS_ASSERT_IMAGES_SIZE_EQUAL(variance, image1, false); 769 PS_ASSERT_IMAGE_TYPE(variance, PS_TYPE_F32, false); 770 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 771 } 772 558 773 int size = kernelSize + stamps->footprint; // Size of postage stamps 559 774 … … 564 779 } 565 780 566 if (isnan(stamp->xNorm)) { 567 stamp->xNorm = 2.0 * (stamp->x - (float)numCols/2.0) / (float)numCols; 568 } 569 if (isnan(stamp->yNorm)) { 570 stamp->yNorm = 2.0 * (stamp->y - (float)numRows/2.0) / (float)numRows; 571 } 572 573 int x = stamp->x + 0.5, y = stamp->y + 0.5; // Stamp coordinates 574 if (x < size || x > numCols - size || y < size || y > numRows - size) { 575 psError(PS_ERR_UNKNOWN, false, "Stamp %d (%d,%d) is within the image border.\n", i, x, y); 781 p_pmSubtractionPolynomialNormCoords(&stamp->xNorm, &stamp->yNorm, stamp->x, stamp->y, 782 bounds.x0, bounds.x1, bounds.y0, bounds.y1); 783 784 int x = stamp->x - 0.5, y = stamp->y - 0.5; // Stamp coordinates 785 // fprintf (stderr, "stamp: %5.1f %5.1f == %d %d (size: %d)\n", stamp->x, stamp->y, x, y, size); 786 787 if (x < bounds.x0 + size || x > bounds.x1 - size || y < bounds.y0 + size || y > bounds.y1 - size) { 788 psError(PM_ERR_PROG, false, "Stamp %d (%d,%d) is within the region border.\n", i, x, y); 576 789 return false; 577 790 } … … 580 793 assert(stamp->image1 == NULL); 581 794 assert(stamp->image2 == NULL); 582 assert(stamp-> variance== NULL);795 assert(stamp->weight == NULL); 583 796 584 797 psRegion region = psRegionSet(x - size, x + size + 1, y - size, y + size + 1); // Region of interest … … 594 807 } 595 808 596 psImage *wtSub = psImageSubset(variance, region); // Subimage with stamp 597 stamp->variance = psKernelAllocFromImage(wtSub, size, size); 598 psFree(wtSub); // Drop reference 809 psKernel *weight = stamp->weight = psKernelAlloc(-size, size, -size, size); // Weight = 1/variance 810 if (variance) { 811 psImage *varSub = psImageSubset(variance, region); // Subimage with stamp 812 psKernel *var = psKernelAllocFromImage(varSub, size, size); // Variance postage stamp 813 814 if ((isfinite(stamps->skyErr) && (stamps->skyErr > 0)) || 815 (isfinite(stamps->sysErr) && (stamps->sysErr > 0))) { 816 float sysErr = 0.25 * PS_SQR(stamps->sysErr); // Systematic error 817 float skyErr = stamps->skyErr; 818 psKernel *image1 = stamp->image1, *image2 = stamp->image2; // Input images 819 for (int y = -size; y <= size; y++) { 820 for (int x = -size; x <= size; x++) { 821 float additional = image1->kernel[y][x] + image2->kernel[y][x]; 822 weight->kernel[y][x] = 1.0 / (skyErr + var->kernel[y][x] + sysErr * PS_SQR(additional)); 823 } 824 } 825 } else { 826 for (int y = -size; y <= size; y++) { 827 for (int x = -size; x <= size; x++) { 828 weight->kernel[y][x] = 1.0 / var->kernel[y][x]; 829 } 830 } 831 } 832 psFree(var); 833 psFree(varSub); 834 } else { 835 psImageInit(weight->image, 1.0); 836 } 599 837 600 838 stamp->status = PM_SUBTRACTION_STAMP_CALCULATE; … … 607 845 const psImage *subMask, const psRegion *region, 608 846 int size, int footprint, float spacing, 847 float normFrac, float sysErr, float skyErr, 609 848 pmSubtractionMode mode) 610 849 { … … 630 869 y->data.F32[numOut] = source->peak->yf; 631 870 } 871 // fprintf (stderr, "stamp: %5.1f %5.1f\n", x->data.F32[numOut], y->data.F32[numOut]); 632 872 numOut++; 633 873 } … … 636 876 637 877 pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, image, subMask, region, size, 638 footprint, spacing, mode); // Stamps to return 878 footprint, spacing, normFrac, 879 sysErr, skyErr, mode); // Stamps 639 880 psFree(x); 640 881 psFree(y); 641 882 642 883 if (!stamps) { 643 psError( PS_ERR_UNKNOWN, false, "Unable to set stamps from sources.");884 psError(psErrorCodeLast(), false, "Unable to set stamps from sources."); 644 885 } 645 886 … … 650 891 pmSubtractionStampList *pmSubtractionStampsSetFromFile(const char *filename, const psImage *image, 651 892 const psImage *subMask, const psRegion *region, 652 int size, int footprint, float spacing, 653 pmSubtractionMode mode)893 int size, int footprint, float spacing, float normFrac, 894 float sysErr, float skyErr, pmSubtractionMode mode) 654 895 { 655 896 PS_ASSERT_STRING_NON_EMPTY(filename, NULL); … … 658 899 psArray *data = psVectorsReadFromFile(filename, "%f %f"); 659 900 if (!data) { 660 psError( PS_ERR_IO, false, "Unable to read stamps file %s", filename);901 psError(psErrorCodeLast(), false, "Unable to read stamps file %s", filename); 661 902 return NULL; 662 903 } … … 668 909 669 910 pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, image, subMask, region, size, footprint, 670 spacing, mode);911 spacing, normFrac, sysErr, skyErr, mode); 671 912 psFree(data); 672 913 … … 674 915 675 916 } 917 918 919 bool pmSubtractionStampsResetStatus (pmSubtractionStampList *stamps) { 920 921 for (int i = 0; i < stamps->num; i++) { 922 pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest 923 if (!stamp) continue; 924 if (stamp->status != PM_SUBTRACTION_STAMP_USED) continue; 925 stamp->status = PM_SUBTRACTION_STAMP_CALCULATE; 926 } 927 return true; 928 } 929 -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionStamps.h
r23937 r27840 24 24 psArray *flux; ///< Fluxes for possible stamps (or NULL) 25 25 int footprint; ///< Half-size of stamps 26 psKernel *window; ///< window function generated from ensemble of stamps 27 float normFrac; ///< Fraction of flux in window for normalisation window 28 int normWindow; ///< Size of window for measuring normalisation 29 float sysErr; ///< Systematic error 30 float skyErr; ///< increase effective readnoise 26 31 } pmSubtractionStampList; 27 32 28 33 /// Allocate a list of stamps 29 pmSubtractionStampList *pmSubtractionStampListAlloc(int numCols, // Number of columns in image 30 int numRows, // Number of rows in image 31 const psRegion *region, // Region for stamps, or NULL 32 int footprint, // Half-size of stamps 33 float spacing // Rough average spacing between stamps 34 pmSubtractionStampList *pmSubtractionStampListAlloc( 35 int numCols, // Number of columns in image 36 int numRows, // Number of rows in image 37 const psRegion *region, // Region for stamps, or NULL 38 int footprint, // Half-size of stamps 39 float spacing, // Rough average spacing between stamps 40 float normFrac, // Fraction of flux in window for normalisation window 41 float sysErr, // Relative systematic error or NAN 42 float skyErr // Relative systematic error or NAN 34 43 ); 35 44 … … 53 62 } 54 63 64 /// Copy a list of stamps 65 /// 66 /// A deep copy is performed of the stamp list and the component stamps 67 pmSubtractionStampList *pmSubtractionStampListCopy( 68 const pmSubtractionStampList *in // Stamp list to copy 69 ); 70 71 55 72 /// A stamp for image subtraction 56 73 typedef struct { … … 60 77 psKernel *image1; ///< Reference image postage stamp 61 78 psKernel *image2; ///< Input image postage stamp 62 psKernel * variance; ///< Variance imagepostage stamp, or NULL79 psKernel *weight; ///< Weight image (1/variance) postage stamp, or NULL 63 80 psArray *convolutions1; ///< Convolutions of image 1 for each kernel component, or NULL 64 81 psArray *convolutions2; ///< Convolutions of image 2 for each kernel component, or NULL 65 psImage *matrix 1, *matrix2; ///< Least-squares matrices for each image, or NULL66 ps Image *matrixX; ///< Cross-matrix (for mode DUAL), or NULL67 psVector *vector1, *vector2; ///< Least-squares vectors for each image, or NULL82 psImage *matrix; ///< Least-squares matrix, or NULL 83 psVector *vector; ///< Least-squares vector, or NULL 84 double norm; ///< Normalisation difference 68 85 pmSubtractionStampStatus status; ///< Status of stamp 69 86 } pmSubtractionStamp; … … 73 90 74 91 /// Find stamps on an image 75 pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps, ///< Output stamps, or NULL 76 const psImage *image1, ///< Image for which to find stamps 77 const psImage *image2, ///< Image for which to find stamps 78 const psImage *mask, ///< Mask, or NULL 79 const psRegion *region, ///< Region to search, or NULL 80 float thresh1, ///< Threshold for stamps in image 1 81 float thresh2, ///< Threshold for stamps in image 2 82 int size, ///< Kernel half-size 83 int footprint, ///< Half-size for stamps 84 float spacing, ///< Rough spacing for stamps 85 pmSubtractionMode mode ///< Mode for subtraction 92 pmSubtractionStampList *pmSubtractionStampsFind( 93 pmSubtractionStampList *stamps, ///< Output stamps, or NULL 94 const psImage *image1, ///< Image for which to find stamps 95 const psImage *image2, ///< Image for which to find stamps 96 const psImage *mask, ///< Mask, or NULL 97 const psRegion *region, ///< Region to search, or NULL 98 float thresh1, ///< Threshold for stamps in image 1 99 float thresh2, ///< Threshold for stamps in image 2 100 int size, ///< Kernel half-size 101 int footprint, ///< Half-size for stamps 102 float spacing, ///< Rough spacing for stamps 103 float normFrac, // Fraction of flux in window for normalisation window 104 float sysErr, ///< Relative systematic error in images 105 float skyErr, ///< Relative systematic error in images 106 pmSubtractionMode mode ///< Mode for subtraction 86 107 ); 87 108 88 109 /// Set stamps based on a list of x,y 89 pmSubtractionStampList *pmSubtractionStampsSet(const psVector *x, ///< x coordinates for each stamp 90 const psVector *y, ///< y coordinates for each stamp 91 const psImage *image, ///< Image for flux of stamp 92 const psImage *mask, ///< Mask, or NULL 93 const psRegion *region, ///< Region to search, or NULL 94 int size, ///< Kernel half-size 95 int footprint, ///< Half-size for stamps 96 float spacing, ///< Rough spacing for stamps 97 pmSubtractionMode mode ///< Mode for subtraction 110 pmSubtractionStampList *pmSubtractionStampsSet( 111 const psVector *x, ///< x coordinates for each stamp 112 const psVector *y, ///< y coordinates for each stamp 113 const psImage *image, ///< Image for flux of stamp 114 const psImage *mask, ///< Mask, or NULL 115 const psRegion *region, ///< Region to search, or NULL 116 int size, ///< Kernel half-size 117 int footprint, ///< Half-size for stamps 118 float spacing, ///< Rough spacing for stamps 119 float normFrac, // Fraction of flux in window for normalisation window 120 float sysErr, ///< Systematic error in images 121 float skyErr, ///< Systematic error in images 122 pmSubtractionMode mode ///< Mode for subtraction 98 123 ); 99 124 … … 107 132 int footprint, ///< Half-size for stamps 108 133 float spacing, ///< Rough spacing for stamps 134 float normFrac, // Fraction of flux in window for normalisation window 135 float sysErr, ///< Systematic error in images 136 float skyErr, ///< Systematic error in images 109 137 pmSubtractionMode mode ///< Mode for subtraction 110 138 ); … … 119 147 int footprint, ///< Half-size for stamps 120 148 float spacing, ///< Rough spacing for stamps 149 float normFrac, // Fraction of flux in window for normalisation window 150 float sysErr, ///< Systematic error in images 151 float skyErr, ///< Systematic error in images 121 152 pmSubtractionMode mode ///< Mode for subtraction 153 ); 154 155 /// Calculate the window and normalisation window from the stamps 156 bool pmSubtractionStampsGetWindow( 157 pmSubtractionStampList *stamps, ///< List of stamps 158 int kernelSize ///< Half-size of kernel 122 159 ); 123 160 … … 127 164 psImage *image2, ///< Input image (or NULL) 128 165 psImage *variance, ///< Variance map 129 int kernelSize ///< Kernel half-size 166 int kernelSize, ///< Kernel half-size 167 psRegion bounds ///< Bounds of validity 130 168 ); 131 169 … … 154 192 ); 155 193 194 195 bool pmSubtractionStampsResetStatus (pmSubtractionStampList *stamps); 196 156 197 #endif -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionThreads.c
r21363 r27840 17 17 } 18 18 19 // Initialise a mutex in each of the input 20 static void subtractionMutexInit(pmReadout *ro) 21 { 22 if (!ro) { 23 return; 24 } 25 26 // XXX if (ro->image) { 27 // XXX psMutexInit(ro->image); 28 // XXX } 29 // XXX if (ro->variance) { 30 // XXX psMutexInit(ro->variance); 31 // XXX } 32 33 return; 34 } 35 36 static void subtractionMutexDestroy(pmReadout *ro) 37 { 38 if (!ro) { 39 return; 40 } 41 42 // XXX if (ro->image) { 43 // XXX psMutexDestroy(ro->image); 44 // XXX } 45 // XXX if (ro->variance) { 46 // XXX psMutexDestroy(ro->variance); 47 // XXX } 48 49 return; 50 } 51 52 void pmSubtractionThreadsInit(pmReadout *in1, pmReadout *in2) 19 void pmSubtractionThreadsInit(void) 53 20 { 54 21 if (threaded) { … … 57 24 58 25 threaded = true; 59 60 subtractionMutexInit(in1);61 subtractionMutexInit(in2);62 26 63 27 { … … 69 33 70 34 { 71 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 3);35 psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CALCULATE_EQUATION", 4); 72 36 task->function = &pmSubtractionCalculateEquationThread; 73 37 psThreadTaskAdd(task); … … 86 50 87 51 88 void pmSubtractionThreadsFinalize( pmReadout *in1, pmReadout *in2)52 void pmSubtractionThreadsFinalize(void) 89 53 { 90 54 if (!threaded) { … … 97 61 psThreadTaskRemove("PSMODULES_SUBTRACTION_CONVOLVE"); 98 62 99 subtractionMutexDestroy(in1);100 subtractionMutexDestroy(in1);101 63 return; 102 64 } -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionThreads.h
r19340 r27840 7 7 /// Set up threading for image matching 8 8 /// 9 /// Sets up thread tasks, and initialises mutexes in readouts 10 void pmSubtractionThreadsInit(pmReadout *in1, pmReadout *in2 // Input readouts 11 ); 9 /// Sets up thread tasks 10 void pmSubtractionThreadsInit(void); 12 11 13 12 14 13 /// Take down threading for image matching 15 14 /// 16 /// Destroys thread tasks , and initialises mutexes in readouts17 void pmSubtractionThreadsFinalize( pmReadout *in1, pmReadout *in2);15 /// Destroys thread tasks 16 void pmSubtractionThreadsFinalize(void); 18 17 19 18 #endif -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionVisual.c
r23487 r27840 16 16 17 17 #include "pmKapaPlots.h" 18 #include "pmSubtraction.h" 18 19 #include "pmSubtractionStamps.h" 20 #include "pmSubtractionEquation.h" 19 21 20 22 #include "pmVisual.h" … … 32 34 static bool plotLeastSquares = true; 33 35 static bool plotImage = true; 36 34 37 // variables to store plotting window indices 35 static int kapa = -1;38 static int kapa1 = -1; 36 39 static int kapa2 = -1; 40 static int kapa3 = -1; 37 41 38 42 /** function prototypes*/ … … 46 50 bool pmSubtractionVisualClose(void) 47 51 { 48 if(kapa != -1) 49 KiiClose(kapa); 50 if(kapa2 != -1) 51 KiiClose(kapa2); 52 if(kapa1 != -1) KiiClose(kapa1); 53 if(kapa2 != -1) KiiClose(kapa2); 52 54 return true; 53 55 } … … 60 62 bool pmSubtractionVisualPlotConvKernels(psImage *convKernels) { 61 63 if (!pmVisualIsVisual() || !plotConvKernels) return true; 62 if (!pmVisualInitWindow(&kapa , "ppSub:Images")) {63 return false; 64 } 65 pmVisualScaleImage(kapa , convKernels, "Convolution_Kernels", 0, true);64 if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) { 65 return false; 66 } 67 pmVisualScaleImage(kapa1, convKernels, "Convolution_Kernels", 0, true); 66 68 pmVisualAskUser(&plotConvKernels); 67 69 return true; … … 74 76 bool pmSubtractionVisualPlotStamps(pmSubtractionStampList *stamps, pmReadout *ro) { 75 77 if (!pmVisualIsVisual() || !plotStamps) return true; 76 if (!pmVisualInitWindow (&kapa , "ppSub:Images")) {78 if (!pmVisualInitWindow (&kapa1, "ppSub:Images")) { 77 79 return false; 78 80 } … … 134 136 stampNum++; 135 137 } 136 pmVisualScaleImage(kapa , canvas, "Subtraction_Stamps", 0, true);138 pmVisualScaleImage(kapa1, canvas, "Subtraction_Stamps", 0, true); 137 139 138 140 pmVisualAskUser(&plotStamps); … … 144 146 145 147 if (!pmVisualIsVisual() || !plotLeastSquares) return true; 146 if (!pmVisualInitWindow (&kapa , "PPSub:Images")) {148 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 147 149 return false; 148 150 } … … 157 159 if (stamp == NULL) continue; 158 160 159 psImage *im = stamp->matrix1; 160 if (im == NULL) im = stamp->matrix2; 161 if (im == NULL) im = stamp->matrixX; 161 psImage *im = stamp->matrix; 162 162 if (im == NULL) continue; 163 163 … … 187 187 if (stamp == NULL) continue; 188 188 189 psImage *im = stamp->matrix1; 190 if (im == NULL) im = stamp->matrix2; 191 if (im == NULL) im = stamp->matrixX; 189 psImage *im = stamp->matrix; 192 190 if (im == NULL) continue; 193 191 … … 197 195 198 196 psImage *canvas32 = pmVisualImageToFloat(canvas); 199 pmVisualScaleImage(kapa , canvas32, "Least_Squares", 0, true);197 pmVisualScaleImage(kapa1, canvas32, "Least_Squares", 0, true); 200 198 201 199 pmVisualAskUser(&plotLeastSquares); … … 207 205 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) { 208 206 if (!pmVisualIsVisual() || !plotImage) return true; 209 if (!pmVisualInitWindow (&kapa, "PPSub:Images")) { 210 return false; 211 } 212 213 pmVisualScaleImage(kapa, image, "Image", 0, true); 214 pmVisualScaleImage(kapa, ref, "Reference", 1, true); 215 pmVisualScaleImage(kapa, sub, "Subtraction", 2, true); 207 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 208 return false; 209 } 210 211 pmVisualScaleImage(kapa1, image, "Image", 0, true); 212 pmVisualScaleImage(kapa1, ref, "Reference", 1, true); 213 pmVisualScaleImage(kapa1, sub, "Subtraction", 2, true); 214 pmVisualAskUser(&plotImage); 215 return true; 216 } 217 218 bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels) { 219 220 if (!pmVisualIsVisual()) return true; 221 if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) { 222 return false; 223 } 224 225 // get the kernel sizes 226 int footprint = kernels->size; 227 228 // output image is a grid of NXsub by NYsub sub-images 229 int NXsub = sqrt(kernels->num); 230 int NYsub = kernels->num / NXsub; 231 if (kernels->num % NXsub) NYsub++; 232 233 int NXpix = NXsub * (2*footprint + 1 + 3); 234 int NYpix = NYsub * (2*footprint + 1 + 3); 235 236 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 237 psImageInit (output, 0.0); 238 239 for (int i = 0; i < kernels->num; i++) { 240 pmSubtractionKernelPreCalc *preCalc = kernels->preCalc->data[i]; 241 psKernel *kernel = preCalc->kernel; 242 243 int xSub = i % NXsub; 244 int ySub = i / NXsub; 245 246 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 247 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 248 249 double sum = 0.0; 250 for (int y = -footprint; y <= footprint; y++) { 251 for (int x = -footprint; x <= footprint; x++) { 252 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 253 sum += kernel->kernel[y][x]; 254 } 255 } 256 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 257 } 258 259 pmVisualScaleImage(kapa1, output, "Image", 0, true); 260 pmVisualAskUser(&plotImage); 261 return true; 262 } 263 264 bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps) { 265 266 if (!pmVisualIsVisual()) return true; 267 if (!pmVisualInitWindow (&kapa2, "ppSub:StampMasterImage")) { 268 return false; 269 } 270 271 // get the kernel sizes 272 int footprint = stamps->footprint; 273 274 // choose the brightest stamp 275 pmSubtractionStamp *maxStamp = NULL; 276 float maxFlux = NAN; 277 for (int i = 0; i < stamps->num; i++) { 278 pmSubtractionStamp *stamp = stamps->stamps->data[i]; 279 if (!isfinite(stamp->flux)) continue; 280 if (!stamp->convolutions1 && !stamp->convolutions2) continue; 281 if (!maxStamp) { 282 maxFlux = stamp->flux; 283 maxStamp = stamp; 284 continue; 285 } 286 if (stamp->flux > maxFlux) { 287 maxFlux = stamp->flux; 288 maxStamp = stamp; 289 } 290 } 291 292 if (!isfinite(maxStamp->flux)) { 293 fprintf (stderr, "no valid stamps?\n"); 294 } 295 296 int nKernels = 0; 297 298 if (maxStamp->convolutions1) { 299 // output image is a grid of NXsub by NYsub sub-images 300 nKernels = maxStamp->convolutions1->n; 301 int NXsub = sqrt(nKernels); 302 int NYsub = nKernels / NXsub; 303 if (nKernels % NXsub) NYsub++; 304 305 int NXpix = NXsub * (2*footprint + 1 + 3); 306 int NYpix = NYsub * (2*footprint + 1 + 3); 307 308 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 309 psImageInit (output, 0.0); 310 311 for (int i = 0; i < nKernels; i++) { 312 psKernel *kernel = maxStamp->convolutions1->data[i]; 313 314 int xSub = i % NXsub; 315 int ySub = i / NXsub; 316 317 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 318 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 319 320 double sum = 0.0; 321 for (int y = -footprint; y <= footprint; y++) { 322 for (int x = -footprint; x <= footprint; x++) { 323 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 324 sum += kernel->kernel[y][x]; 325 } 326 } 327 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 328 } 329 pmVisualScaleImage(kapa2, output, "Image", 0, true); 330 } 331 332 if (maxStamp->convolutions2) { 333 // output image is a grid of NXsub by NYsub sub-images 334 nKernels = maxStamp->convolutions2->n; 335 int NXsub = sqrt(nKernels); 336 int NYsub = nKernels / NXsub; 337 if (nKernels % NXsub) NYsub++; 338 339 int NXpix = NXsub * (2*footprint + 1 + 3); 340 int NYpix = NYsub * (2*footprint + 1 + 3); 341 342 psImage *output = psImageAlloc(NXpix, NYpix, PS_TYPE_F32); 343 psImageInit (output, 0.0); 344 345 for (int i = 0; i < nKernels; i++) { 346 psKernel *kernel = maxStamp->convolutions2->data[i]; 347 348 int xSub = i % NXsub; 349 int ySub = i / NXsub; 350 351 int xPix = xSub * (2*footprint + 1 + 3) + footprint; 352 int yPix = ySub * (2*footprint + 1 + 3) + footprint; 353 354 double sum = 0.0; 355 for (int y = -footprint; y <= footprint; y++) { 356 for (int x = -footprint; x <= footprint; x++) { 357 output->data.F32[y + yPix][x + xPix] = kernel->kernel[y][x]; 358 sum += kernel->kernel[y][x]; 359 } 360 } 361 fprintf (stderr, "kernel %d, sum %f\n", i, sum); 362 } 363 pmVisualScaleImage(kapa2, output, "Image", 1, true); 364 } 365 216 366 pmVisualAskUser(&plotImage); 217 367 return true; … … 240 390 241 391 overlay[Noverlay].type = KII_OVERLAY_BOX; 392 if ((stamp->x < 1.0) && (stamp->y < 1.0)) { 393 // fprintf (stderr, "stamp zero: %f %f\n", stamp->x, stamp->y); 394 continue; 395 } 396 if (!isfinite(stamp->x) && !isfinite(stamp->y)) { 397 // fprintf (stderr, "stamp nan: %f %f\n", stamp->x, stamp->y); 398 continue; 399 } 242 400 overlay[Noverlay].x = stamp->x; 243 401 overlay[Noverlay].y = stamp->y; … … 255 413 } 256 414 415 static int footprint = 0; 416 static int NX = 0; 417 static int NY = 0; 418 static psImage *sourceImage = NULL; 419 static psImage *targetImage = NULL; 420 static psImage *residualImage = NULL; 421 static psImage *fresidualImage = NULL; 422 static psImage *differenceImage = NULL; 423 static psImage *convolutionImage = NULL; 424 425 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) { 426 427 if (!pmVisualIsVisual()) return true; 428 429 // generate 4 storage images large enough to hold the N stamps: 430 431 footprint = stamps->footprint; 432 433 float NXf = sqrt(stamps->num); 434 NX = (int) NXf == NXf ? NXf : NXf + 1.0; 435 436 float NYf = stamps->num / NX; 437 NY = (int) NYf == NY ? NYf : NYf + 1.0; 438 439 int NXpix = (2*footprint + 1) * NX; 440 NXpix += (NX > 1) ? 3 * NX : 0; 441 442 int NYpix = (2*footprint + 1) * NY; 443 NYpix += (NY > 1) ? 3 * NY : 0; 444 445 sourceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 446 targetImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 447 residualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 448 fresidualImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 449 differenceImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 450 convolutionImage = psImageAlloc (NXpix, NYpix, PS_TYPE_F32); 451 452 psImageInit (sourceImage, 0.0); 453 psImageInit (targetImage, 0.0); 454 psImageInit (residualImage, 0.0); 455 psImageInit (fresidualImage, 0.0); 456 psImageInit (differenceImage, 0.0); 457 psImageInit (convolutionImage, 0.0); 458 459 return true; 460 } 461 462 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) { 463 464 if (!pmVisualIsVisual()) return true; 465 466 double sum; 467 468 int NXoff = index % NX; 469 int NYoff = index / NX; 470 471 int NXpix = NXoff * (2*footprint + 1 + 3) + footprint; 472 int NYpix = NYoff * (2*footprint + 1 + 3) + footprint; 473 474 // insert the (target) kernel into the (target) image: 475 sum = 0.0; 476 for (int y = -footprint; y <= footprint; y++) { 477 for (int x = -footprint; x <= footprint; x++) { 478 targetImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x]; 479 sum += targetImage->data.F32[y + NYpix][x + NXpix]; 480 } 481 } 482 targetImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 483 484 // insert the (source) kernel into the (source) image: 485 sum = 0.0; 486 for (int y = -footprint; y <= footprint; y++) { 487 for (int x = -footprint; x <= footprint; x++) { 488 sourceImage->data.F32[y + NYpix][x + NXpix] = source->kernel[y][x]; 489 sum += sourceImage->data.F32[y + NYpix][x + NXpix]; 490 } 491 } 492 sourceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 493 494 // insert the (convolution) kernel into the (convolution) image: 495 sum = 0.0; 496 for (int y = -footprint; y <= footprint; y++) { 497 for (int x = -footprint; x <= footprint; x++) { 498 convolutionImage->data.F32[y + NYpix][x + NXpix] = -convolution->kernel[y][x]; 499 sum += convolutionImage->data.F32[y + NYpix][x + NXpix]; 500 } 501 } 502 convolutionImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 503 504 // insert the (difference) kernel into the (difference) image: 505 sum = 0.0; 506 for (int y = -footprint; y <= footprint; y++) { 507 for (int x = -footprint; x <= footprint; x++) { 508 differenceImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm; 509 sum += differenceImage->data.F32[y + NYpix][x + NXpix]; 510 } 511 } 512 differenceImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 513 514 // insert the (residual) kernel into the (residual) image: 515 sum = 0.0; 516 for (int y = -footprint; y <= footprint; y++) { 517 for (int x = -footprint; x <= footprint; x++) { 518 residualImage->data.F32[y + NYpix][x + NXpix] = target->kernel[y][x] - background - source->kernel[y][x] * norm - convolution->kernel[y][x]; 519 sum += residualImage->data.F32[y + NYpix][x + NXpix]; 520 } 521 } 522 residualImage->data.F32[footprint + 1 + NYpix][NXpix] = sum; 523 524 // insert the (fresidual) kernel into the (fresidual) image: 525 for (int y = -footprint; y <= footprint; y++) { 526 for (int x = -footprint; x <= footprint; x++) { 527 fresidualImage->data.F32[y + NYpix][x + NXpix] = residualImage->data.F32[y + NYpix][x + NXpix] / sqrt(PS_MAX(target->kernel[y][x], 100.0)); 528 } 529 } 530 return true; 531 } 532 533 bool pmSubtractionVisualShowFit(double norm) { 534 535 // for testing, dump the residual image and exit 536 if (0) { 537 psMetadata *header = psMetadataAlloc(); 538 psMetadataAddF32 (header, PS_LIST_TAIL, "NORM", 0, "Normalization", norm); 539 psFits *fits = psFitsOpen("resid.fits", "w"); 540 psFitsWriteImage(fits, header, residualImage, 0, NULL); 541 psFitsClose(fits); 542 // exit (0); 543 } 544 545 if (!pmVisualIsVisual()) return true; 546 if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) return false; 547 if (!pmVisualInitWindow(&kapa2, "ppSub:Misc")) return false; 548 549 KiiEraseOverlay (kapa1, "red"); 550 KiiEraseOverlay (kapa2, "red"); 551 552 pmVisualScaleImage(kapa1, targetImage, "Target Stamps", 0, true); 553 pmVisualScaleImage(kapa1, sourceImage, "Source Stamps", 1, true); 554 pmVisualScaleImage(kapa1, convolutionImage, "Convolution Stamps", 2, true); 555 KiiCenter (kapa1, 0.5*targetImage->numCols, 0.5*targetImage->numRows, 1); 556 557 pmVisualScaleImage(kapa2, fresidualImage, "Frac Residual Stamps", 2, true); 558 pmVisualScaleImage(kapa2, differenceImage, "Difference Stamps", 0, true); 559 560 if (1) { 561 KiiImage image; 562 KapaImageData data; 563 Coords coords; 564 strcpy (coords.ctype, "RA---TAN"); 565 566 image.data2d = residualImage->data.F32; 567 image.Nx = residualImage->numCols; 568 image.Ny = residualImage->numRows; 569 strcpy (data.name, "Residual Stamps"); 570 strcpy (data.file, "Residual Stamps"); 571 572 data.zero = -300.0; 573 data.range = +600.0; 574 data.logflux = 0; 575 576 KiiSetChannel (kapa2, 1); 577 KiiNewPicture2D (kapa2, &image, &data, &coords); 578 } else { 579 pmVisualScaleImage(kapa2, residualImage, "Residual Stamps", 1, true); 580 } 581 582 KiiCenter (kapa2, 0.5*residualImage->numCols, 0.5*residualImage->numRows, 1); 583 584 pmVisualAskUser(NULL); 585 586 psFree(targetImage); 587 psFree(sourceImage); 588 psFree(convolutionImage); 589 psFree(differenceImage); 590 psFree(residualImage); 591 psFree(fresidualImage); 592 593 targetImage = NULL; 594 sourceImage = NULL; 595 convolutionImage = NULL; 596 differenceImage = NULL; 597 residualImage = NULL; 598 fresidualImage = NULL; 599 600 return true; 601 } 602 603 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels) { 604 605 Graphdata graphdata; 606 607 if (!pmVisualIsVisual()) return true; 608 if (!pmVisualInitWindow(&kapa3, "ppSub:plots")) return false; 609 610 KapaClearSections (kapa3); 611 KapaInitGraph (&graphdata); 612 613 psVector *x = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 614 psVector *y = psVectorAllocEmpty (kernels->num, PS_TYPE_F32); 615 616 graphdata.xmin = -1.0; 617 graphdata.xmax = kernels->num + 1.0; 618 graphdata.ymin = +32.0; 619 graphdata.ymax = -32.0; 620 621 psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, 0.0, 0.0); 622 623 // construct the plot vectors 624 for (int i = 0; i < kernels->num; i++) { 625 x->data.F32[i] = i; 626 y->data.F32[i] = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, false); 627 graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[i]); 628 graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[i]); 629 } 630 x->n = y->n = kernels->num; 631 632 float range; 633 range = graphdata.xmax - graphdata.xmin; 634 graphdata.xmax += 0.05*range; 635 graphdata.xmin -= 0.05*range; 636 range = graphdata.ymax - graphdata.ymin; 637 graphdata.ymax += 0.05*range; 638 graphdata.ymin -= 0.05*range; 639 640 KapaSetLimits (kapa3, &graphdata); 641 642 KapaSetFont (kapa3, "helvetica", 14); 643 KapaBox (kapa3, &graphdata); 644 KapaSendLabel (kapa3, "kernel number", KAPA_LABEL_XM); 645 KapaSendLabel (kapa3, "coeff", KAPA_LABEL_YM); 646 647 graphdata.color = KapaColorByName ("black"); 648 graphdata.ptype = 2; 649 graphdata.size = 0.5; 650 graphdata.style = 2; 651 652 KapaPrepPlot (kapa3, x->n, &graphdata); 653 KapaPlotVector (kapa3, x->n, x->data.F32, "x"); 654 KapaPlotVector (kapa3, x->n, y->data.F32, "y"); 655 656 psFree (x); 657 psFree (y); 658 659 pmVisualAskUser(NULL); 660 return true; 661 } 662 257 663 #else 258 664 bool pmSubtractionVisualClose(void) {return true;} … … 261 667 bool pmSubtractionVisualPlotLeastSquares(pmSubtractionStampList *stamps) {return true;} 262 668 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) {return true;} 669 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) {return true;} 670 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) {return true;} 671 bool pmSubtractionVisualShowFit() {return true;} 672 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels); 263 673 #endif -
branches/simtest_nebulous_branches/psModules/src/imcombine/pmSubtractionVisual.h
r23487 r27840 7 7 bool pmSubtractionVisualPlotLeastSquares(pmSubtractionStampList *stamps); 8 8 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub); 9 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps); 10 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index); 11 bool pmSubtractionVisualShowFit(double norm); 12 bool pmSubtractionVisualPlotFit(const pmSubtractionKernels *kernels); 13 bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels); 14 bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps); 9 15 10 16 #endif -
branches/simtest_nebulous_branches/psModules/src/objects/Makefile.am
r24875 r27840 12 12 pmFootprintCullPeaks.c \ 13 13 pmFootprintFind.c \ 14 pmFootprintSpans.c \ 14 15 pmFootprintFindAtPoint.c \ 15 16 pmFootprintIDs.c \ … … 20 21 pmModelUtils.c \ 21 22 pmSource.c \ 23 pmPhotObj.c \ 22 24 pmSourceMasks.c \ 23 25 pmSourceMoments.c \ 26 pmSourceDiffStats.c \ 24 27 pmSourceExtendedPars.c \ 25 28 pmSourceUtils.c \ … … 40 43 pmSourceIO_CMF_PS1_V1.c \ 41 44 pmSourceIO_CMF_PS1_V2.c \ 45 pmSourceIO_CMF_PS1_DV1.c \ 42 46 pmSourceIO_MatchedRefs.c \ 43 47 pmSourcePlots.c \ … … 50 54 pmPSF_IO.c \ 51 55 pmPSFtry.c \ 56 pmPSFtryModel.c \ 57 pmPSFtryFitEXT.c \ 58 pmPSFtryMakePSF.c \ 59 pmPSFtryFitPSF.c \ 60 pmPSFtryMetric.c \ 52 61 pmTrend2D.c \ 53 62 pmGrowthCurveGenerate.c \ 54 63 pmGrowthCurve.c \ 55 pmSourceMatch.c 56 57 EXTRA_DIST =\64 pmSourceMatch.c \ 65 pmDetEff.c \ 66 pmSourceGroups.c \ 58 67 models/pmModel_GAUSS.c \ 59 68 models/pmModel_PGAUSS.c \ 69 models/pmModel_PS1_V1.c \ 60 70 models/pmModel_QGAUSS.c \ 61 models/pmModel_SGAUSS.c \62 71 models/pmModel_RGAUSS.c \ 63 72 models/pmModel_SERSIC.c … … 67 76 pmSpan.h \ 68 77 pmFootprint.h \ 78 pmFootprintSpans.h \ 69 79 pmPeaks.h \ 70 80 pmMoments.h \ … … 73 83 pmModelUtils.h \ 74 84 pmSource.h \ 85 pmPhotObj.h \ 75 86 pmSourceMasks.h \ 87 pmSourceDiffStats.h \ 76 88 pmSourceExtendedPars.h \ 77 89 pmSourceUtils.h \ … … 90 102 pmTrend2D.h \ 91 103 pmGrowthCurve.h \ 92 pmSourceMatch.h 104 pmSourceMatch.h \ 105 pmDetEff.h \ 106 pmSourceGroups.h \ 107 models/pmModel_GAUSS.h \ 108 models/pmModel_PGAUSS.h \ 109 models/pmModel_PS1_V1.h \ 110 models/pmModel_QGAUSS.h \ 111 models/pmModel_RGAUSS.h \ 112 models/pmModel_SERSIC.h 93 113 94 114 CLEANFILES = *~ -
branches/simtest_nebulous_branches/psModules/src/objects/models/pmModel_GAUSS.c
r20001 r27840 1 1 /****************************************************************************** 2 2 * this file defines the GAUSS source shape model. Note that these model functions are loaded 3 * by pmModel Group.c using 'include', and thus need no 'include' statements of their own. The3 * by pmModelClass.c using 'include', and thus need no 'include' statements of their own. The 4 4 * models use a psVector to represent the set of parameters, with the sequence used to specify 5 5 * the meaning of the parameter. The meaning of the parameters may thus vary depending on the 6 * specifics of the model. All models which are used a PSF representations share a few6 * specifics of the model. All models which are used as a PSF representations share a few 7 7 * parameters, for which # define names are listed in pmModel.h: 8 8 … … 19 19 *****************************************************************************/ 20 20 21 #include <stdio.h> 22 #include <pslib.h> 23 24 #include "pmMoments.h" 25 #include "pmPeaks.h" 26 #include "pmSource.h" 27 #include "pmModel.h" 28 #include "pmModel_GAUSS.h" 29 21 30 # define PM_MODEL_FUNC pmModelFunc_GAUSS 22 31 # define PM_MODEL_FLUX pmModelFlux_GAUSS … … 27 36 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_GAUSS 28 37 # define PM_MODEL_FIT_STATUS pmModelFitStatus_GAUSS 38 # define PM_MODEL_SET_LIMITS pmModelSetLimits_GAUSS 39 40 // Lax parameter limits 41 static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0 }; 42 static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0 }; 43 44 // Moderate parameter limits 45 static float *paramsMinModerate = paramsMinLax; 46 static float *paramsMaxModerate = paramsMaxLax; 47 48 // Strict parameter limits 49 static float *paramsMinStrict = paramsMinLax; 50 static float *paramsMaxStrict = paramsMaxLax; 51 52 // Parameter limits to use 53 static float *paramsMinUse = paramsMinLax; 54 static float *paramsMaxUse = paramsMaxLax; 55 static float betaUse[] = { 1000, 3e6, 5, 5, 2.0, 2.0, 0.5 }; 56 57 static bool limitsApply = true; // Apply limits? 29 58 30 59 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y) 60 // 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords 61 // values need to be pixel coords 31 62 psF32 PM_MODEL_FUNC(psVector *deriv, 32 63 const psVector *params, … … 68 99 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta) 69 100 { 70 float beta_lim = 0, params_min = 0, params_max = 0; 71 float f1 = 0, f2 = 0, q1 = 0, q2 = 0; 101 if (!limitsApply) { 102 return true; 103 } 104 psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds"); 72 105 73 106 // we need to calculate the limits for SXY specially 107 float q2 = NAN; 74 108 if (nParam == PM_PAR_SXY) { 75 f 1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);76 f 2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);77 q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);78 q1 = PS_MAX (0.0, q1);109 float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]); 110 float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]); 111 float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2); 112 q1 = (q1 < 0.0) ? 0.0 : q1; 79 113 // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg.. Saturate at that 80 114 // angle and let f2,f1 fight it out 81 q2 = 0.5*sqrt(q1);115 q2 = 0.5*sqrtf(q1); 82 116 } 83 117 84 118 switch (mode) { 85 case PS_MINIMIZE_BETA_LIMIT: 86 switch (nParam) { 87 case PM_PAR_SKY: 88 beta_lim = 1000; 89 break; 90 case PM_PAR_I0: 91 beta_lim = 3e6; 92 break; 93 case PM_PAR_XPOS: 94 beta_lim = 5; 95 break; 96 case PM_PAR_YPOS: 97 beta_lim = 5; 98 break; 99 case PM_PAR_SXX: 100 beta_lim = 2.0; 101 break; 102 case PM_PAR_SYY: 103 beta_lim = 2.0; 104 break; 105 case PM_PAR_SXY: 106 beta_lim = 0.5*q2; 107 break; 108 default: 109 psAbort("invalid parameter %d for beta test", nParam); 110 } 111 if (fabs(beta[nParam]) > fabs(beta_lim)) { 112 beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim); 113 psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 114 nParam, beta[nParam], beta_lim); 115 return false; 116 } 117 return true; 118 case PS_MINIMIZE_PARAM_MIN: 119 switch (nParam) { 120 case PM_PAR_SKY: 121 params_min = -1000; 122 break; 123 case PM_PAR_I0: 124 params_min = 0.01; 125 break; 126 case PM_PAR_XPOS: 127 params_min = -100; 128 break; 129 case PM_PAR_YPOS: 130 params_min = -100; 131 break; 132 case PM_PAR_SXX: 133 params_min = 0.5; 134 break; 135 case PM_PAR_SYY: 136 params_min = 0.5; 137 break; 138 case PM_PAR_SXY: 139 params_min = -q2; 140 break; 141 default: 142 psAbort("invalid parameter %d for param min test", nParam); 143 } 144 if (params[nParam] < params_min) { 145 params[nParam] = params_min; 146 psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 147 nParam, params[nParam], params_min); 148 return false; 149 } 150 return true; 151 case PS_MINIMIZE_PARAM_MAX: 152 switch (nParam) { 153 case PM_PAR_SKY: 154 params_max = 1e5; 155 break; 156 case PM_PAR_I0: 157 params_max = 1e8; 158 break; 159 case PM_PAR_XPOS: 160 params_max = 1e4; 161 break; 162 case PM_PAR_YPOS: 163 params_max = 1e4; 164 break; 165 case PM_PAR_SXX: 166 params_max = 100; 167 break; 168 case PM_PAR_SYY: 169 params_max = 100; 170 break; 171 case PM_PAR_SXY: 172 params_max = +q2; 173 break; 174 default: 175 psAbort("invalid parameter %d for param max test", nParam); 176 } 177 if (params[nParam] > params_max) { 178 params[nParam] = params_max; 179 psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 180 nParam, params[nParam], params_max); 181 return false; 182 } 183 return true; 119 case PS_MINIMIZE_BETA_LIMIT: { 120 psAssert(beta, "Require beta to limit beta"); 121 float limit = betaUse[nParam]; 122 if (nParam == PM_PAR_SXY) { 123 limit *= q2; 124 } 125 if (fabs(beta[nParam]) > fabs(limit)) { 126 beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit); 127 psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 128 nParam, beta[nParam], limit); 129 return false; 130 } 131 return true; 132 } 133 case PS_MINIMIZE_PARAM_MIN: { 134 psAssert(params, "Require parameters to limit parameters"); 135 psAssert(paramsMinUse, "Require parameter limits to limit parameters"); 136 float limit = paramsMinUse[nParam]; 137 if (nParam == PM_PAR_SXY) { 138 limit *= q2; 139 } 140 if (params[nParam] < limit) { 141 params[nParam] = limit; 142 psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 143 nParam, params[nParam], limit); 144 return false; 145 } 146 return true; 147 } 148 case PS_MINIMIZE_PARAM_MAX: { 149 psAssert(params, "Require parameters to limit parameters"); 150 psAssert(paramsMaxUse, "Require parameter limits to limit parameters"); 151 float limit = paramsMaxUse[nParam]; 152 if (nParam == PM_PAR_SXY) { 153 limit *= q2; 154 } 155 if (params[nParam] > limit) { 156 params[nParam] = limit; 157 psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 158 nParam, params[nParam], limit); 159 return false; 160 } 161 return true; 162 } 184 163 default: 185 164 psAbort("invalid choice for limits"); … … 190 169 191 170 // make an initial guess for parameters 171 // 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters 192 172 bool PM_MODEL_GUESS (pmModel *model, pmSource *source) 193 173 { … … 205 185 psEllipseShape shape = psEllipseAxesToShape (axes); 206 186 207 PAR[PM_PAR_SKY] = moments->Sky;187 PAR[PM_PAR_SKY] = 0.0; 208 188 PAR[PM_PAR_I0] = peak->flux; 209 189 PAR[PM_PAR_XPOS] = peak->xf; … … 257 237 psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0); 258 238 psF64 radius = axes.major * sqrt (2.0 * log(PAR[PM_PAR_I0] / flux)); 239 psAssert (isfinite(radius), "fix this code: radius should not be nan for %f", PAR[PM_PAR_I0]); 240 259 241 return (radius); 260 242 } … … 367 349 bool PM_MODEL_FIT_STATUS (pmModel *model) 368 350 { 369 psF32 dP;370 351 bool status; 371 352 … … 373 354 psF32 *dPAR = model->dparams->data.F32; 374 355 375 dP = 0;376 dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);377 dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);378 dP = sqrt (dP);379 380 356 status = true; 381 status &= (dP < 0.5);382 357 status &= (PAR[PM_PAR_I0] > 0); 383 358 status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5); 384 359 385 if (status) 386 return true; 387 return false; 360 return status; 361 } 362 363 void PM_MODEL_SET_LIMITS(pmModelLimitsType type) 364 { 365 switch (type) { 366 case PM_MODEL_LIMITS_NONE: 367 paramsMinUse = NULL; 368 paramsMaxUse = NULL; 369 limitsApply = true; 370 break; 371 case PM_MODEL_LIMITS_IGNORE: 372 paramsMinUse = NULL; 373 paramsMaxUse = NULL; 374 limitsApply = false; 375 break; 376 case PM_MODEL_LIMITS_LAX: 377 paramsMinUse = paramsMinLax; 378 paramsMaxUse = paramsMaxLax; 379 limitsApply = true; 380 break; 381 case PM_MODEL_LIMITS_MODERATE: 382 paramsMinUse = paramsMinModerate; 383 paramsMaxUse = paramsMaxModerate; 384 limitsApply = true; 385 break; 386 case PM_MODEL_LIMITS_STRICT: 387 paramsMinUse = paramsMinStrict; 388 paramsMaxUse = paramsMaxStrict; 389 limitsApply = true; 390 break; 391 default: 392 psAbort("Unrecognised model limits type: %x", type); 393 } 394 return; 388 395 } 389 396 … … 396 403 # undef PM_MODEL_PARAMS_FROM_PSF 397 404 # undef PM_MODEL_FIT_STATUS 405 # undef PM_MODEL_SET_LIMITS -
branches/simtest_nebulous_branches/psModules/src/objects/models/pmModel_PGAUSS.c
r20001 r27840 1 1 /****************************************************************************** 2 2 * this file defines the PGAUSS source shape model. Note that these model functions are loaded 3 * by pmModel Group.c using 'include', and thus need no 'include' statements of their own. The3 * by pmModelClass.c using 'include', and thus need no 'include' statements of their own. The 4 4 * models use a psVector to represent the set of parameters, with the sequence used to specify 5 5 * the meaning of the parameter. The meaning of the parameters may thus vary depending on the 6 * specifics of the model. All models which are used a PSF representations share a few6 * specifics of the model. All models which are used as a PSF representations share a few 7 7 * parameters, for which # define names are listed in pmModel.h: 8 8 … … 19 19 *****************************************************************************/ 20 20 21 #include <stdio.h> 22 #include <pslib.h> 23 24 #include "pmMoments.h" 25 #include "pmPeaks.h" 26 #include "pmSource.h" 27 #include "pmModel.h" 28 #include "pmModel_PGAUSS.h" 29 21 30 # define PM_MODEL_FUNC pmModelFunc_PGAUSS 22 31 # define PM_MODEL_FLUX pmModelFlux_PGAUSS … … 27 36 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_PGAUSS 28 37 # define PM_MODEL_FIT_STATUS pmModelFitStatus_PGAUSS 38 # define PM_MODEL_SET_LIMITS pmModelSetLimits_PGAUSS 39 40 // Lax parameter limits 41 static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0 }; 42 static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0 }; 43 44 // Moderate parameter limits 45 static float *paramsMinModerate = paramsMinLax; 46 static float *paramsMaxModerate = paramsMaxLax; 47 48 // Strict parameter limits 49 static float *paramsMinStrict = paramsMinLax; 50 static float *paramsMaxStrict = paramsMaxLax; 51 52 // Parameter limits to use 53 static float *paramsMinUse = paramsMinLax; 54 static float *paramsMaxUse = paramsMaxLax; 55 static float betaUse[] = { 1000, 3e6, 5, 5, 2.0, 2.0, 0.5 }; 56 57 static bool limitsApply = true; // Apply limits? 29 58 30 59 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y) 60 // 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords 61 // values need to be pixel coords 31 62 psF32 PM_MODEL_FUNC(psVector *deriv, 32 63 const psVector *params, … … 69 100 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta) 70 101 { 71 float beta_lim = 0, params_min = 0, params_max = 0; 72 float f1 = 0, f2 = 0, q1 = 0, q2 = 0; 102 if (!limitsApply) { 103 return true; 104 } 105 psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds"); 73 106 74 107 // we need to calculate the limits for SXY specially 108 float q2 = NAN; 75 109 if (nParam == PM_PAR_SXY) { 76 f 1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);77 f 2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);78 q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);79 q1 = PS_MAX (0.0, q1);110 float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]); 111 float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]); 112 float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2); 113 q1 = (q1 < 0.0) ? 0.0 : q1; 80 114 // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg.. Saturate at that 81 115 // angle and let f2,f1 fight it out 82 q2 = 0.5*sqrt(q1);116 q2 = 0.5*sqrtf(q1); 83 117 } 84 118 85 119 switch (mode) { 86 case PS_MINIMIZE_BETA_LIMIT: 87 switch (nParam) { 88 case PM_PAR_SKY: 89 beta_lim = 1000; 90 break; 91 case PM_PAR_I0: 92 beta_lim = 3e6; 93 break; 94 case PM_PAR_XPOS: 95 beta_lim = 5; 96 break; 97 case PM_PAR_YPOS: 98 beta_lim = 5; 99 break; 100 case PM_PAR_SXX: 101 beta_lim = 2.0; 102 break; 103 case PM_PAR_SYY: 104 beta_lim = 2.0; 105 break; 106 case PM_PAR_SXY: 107 beta_lim = 0.5*q2; 108 break; 109 default: 110 psAbort("invalid parameter %d for beta test", nParam); 111 } 112 if (fabs(beta[nParam]) > fabs(beta_lim)) { 113 beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim); 114 psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 115 nParam, beta[nParam], beta_lim); 116 return false; 117 } 118 return true; 119 case PS_MINIMIZE_PARAM_MIN: 120 switch (nParam) { 121 case PM_PAR_SKY: 122 params_min = -1000; 123 break; 124 case PM_PAR_I0: 125 params_min = 0.01; 126 break; 127 case PM_PAR_XPOS: 128 params_min = -100; 129 break; 130 case PM_PAR_YPOS: 131 params_min = -100; 132 break; 133 case PM_PAR_SXX: 134 params_min = 0.5; 135 break; 136 case PM_PAR_SYY: 137 params_min = 0.5; 138 break; 139 case PM_PAR_SXY: 140 params_min = -q2; 141 break; 142 default: 143 psAbort("invalid parameter %d for param min test", nParam); 144 } 145 if (params[nParam] < params_min) { 146 params[nParam] = params_min; 147 psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 148 nParam, params[nParam], params_min); 149 return false; 150 } 151 return true; 152 case PS_MINIMIZE_PARAM_MAX: 153 switch (nParam) { 154 case PM_PAR_SKY: 155 params_max = 1e5; 156 break; 157 case PM_PAR_I0: 158 params_max = 1e8; 159 break; 160 case PM_PAR_XPOS: 161 params_max = 1e4; 162 break; 163 case PM_PAR_YPOS: 164 params_max = 1e4; 165 break; 166 case PM_PAR_SXX: 167 params_max = 100; 168 break; 169 case PM_PAR_SYY: 170 params_max = 100; 171 break; 172 case PM_PAR_SXY: 173 params_max = +q2; 174 break; 175 default: 176 psAbort("invalid parameter %d for param max test", nParam); 177 } 178 if (params[nParam] > params_max) { 179 params[nParam] = params_max; 180 psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 181 nParam, params[nParam], params_max); 182 return false; 183 } 184 return true; 185 default: 120 case PS_MINIMIZE_BETA_LIMIT: { 121 psAssert(beta, "Require beta to limit beta"); 122 float limit = betaUse[nParam]; 123 if (nParam == PM_PAR_SXY) { 124 limit *= q2; 125 } 126 if (fabs(beta[nParam]) > fabs(limit)) { 127 beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit); 128 psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 129 nParam, beta[nParam], limit); 130 return false; 131 } 132 return true; 133 } 134 case PS_MINIMIZE_PARAM_MIN: { 135 psAssert(params, "Require parameters to limit parameters"); 136 psAssert(paramsMinUse, "Require parameter limits to limit parameters"); 137 float limit = paramsMinUse[nParam]; 138 if (nParam == PM_PAR_SXY) { 139 limit *= q2; 140 } 141 if (params[nParam] < limit) { 142 params[nParam] = limit; 143 psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 144 nParam, params[nParam], limit); 145 return false; 146 } 147 return true; 148 } 149 case PS_MINIMIZE_PARAM_MAX: { 150 psAssert(params, "Require parameters to limit parameters"); 151 psAssert(paramsMaxUse, "Require parameter limits to limit parameters"); 152 float limit = paramsMaxUse[nParam]; 153 if (nParam == PM_PAR_SXY) { 154 limit *= q2; 155 } 156 if (params[nParam] > limit) { 157 params[nParam] = limit; 158 psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 159 nParam, params[nParam], limit); 160 return false; 161 } 162 return true; 163 } 164 default: 186 165 psAbort("invalid choice for limits"); 187 166 } … … 190 169 } 191 170 171 192 172 // make an initial guess for parameters 173 // 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters 193 174 bool PM_MODEL_GUESS (pmModel *model, pmSource *source) 194 175 { … … 205 186 psEllipseShape shape = psEllipseAxesToShape (axes); 206 187 207 PAR[PM_PAR_SKY] = moments->Sky;188 PAR[PM_PAR_SKY] = 0.0; 208 189 PAR[PM_PAR_I0] = peak->flux; 209 190 PAR[PM_PAR_XPOS] = peak->xf; … … 255 236 psF64 PM_MODEL_RADIUS (const psVector *params, psF64 flux) 256 237 { 257 psF64 z , f;238 psF64 z; 258 239 int Nstep = 0; 259 240 psEllipseShape shape; … … 284 265 // choose a z value guaranteed to be beyond our limit 285 266 float z0 = pow((1.0 / limit), (1.0 / 3.0)); 267 psAssert (isfinite(z0), "fix this code: z0 should not be nan for %f", PAR[PM_PAR_I0]); 286 268 float z1 = (1.0 / limit); 269 psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_I0]); 287 270 z1 = PS_MAX (z0, z1); 288 271 z0 = 0.0; 289 272 290 // perform a type of bisection to find the value 291 float f0 = 1.0 / (1 + z0 + z0*z0/2.0 + z0*z0*z0/6.0); 292 float f1 = 1.0 / (1 + z1 + z1*z1/2.0 + z1*z1*z1/6.0); 293 while ((Nstep < 10) && (fabs(z1 - z0) > 0.5)) { 294 z = 0.5*(z0 + z1); 295 f = 1.0 / (1 + z + z*z/2.0 + z*z*z/6.0); 296 if (f > limit) { 297 z0 = z; 298 f0 = f; 299 } else { 300 z1 = z; 301 f1 = f; 302 } 303 Nstep ++; 304 } 273 // starting guess: 274 z = 0.5*(z0 + z1); 275 float dz = 1.0; 276 277 for (int i = 0; (i < 10) && (fabs(dz) > 0.0001); i++) { 278 // use Newton-Raphson to minimize f(z) - limit = 0 279 float dqdz = (1.0 + z + z*z/2.0); 280 float q = (dqdz + z*z*z/6.0); 281 282 float f = 1.0 / q; 283 float dfdz = -dqdz * f / q; 284 285 dz = (f - limit) / dfdz; 286 287 // fprintf (stderr, "%f %f %f : %f %f\n", f, z, dz, dfdz, q); 288 z -= dz; 289 z = PS_MAX(z, 0.0); 290 } 291 305 292 psF64 radius = sigma * sqrt (2.0 * z); 306 293 … … 415 402 bool PM_MODEL_FIT_STATUS (pmModel *model) 416 403 { 417 psF32 dP;418 404 bool status; 419 405 … … 421 407 psF32 *dPAR = model->dparams->data.F32; 422 408 423 dP = 0;424 dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);425 dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);426 dP = sqrt (dP);427 428 409 status = true; 429 status &= (dP < 0.5);430 410 status &= (PAR[PM_PAR_I0] > 0); 431 411 status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5); 432 412 433 413 return status; 414 } 415 416 417 void PM_MODEL_SET_LIMITS(pmModelLimitsType type) 418 { 419 switch (type) { 420 case PM_MODEL_LIMITS_NONE: 421 paramsMinUse = NULL; 422 paramsMaxUse = NULL; 423 limitsApply = true; 424 break; 425 case PM_MODEL_LIMITS_IGNORE: 426 paramsMinUse = NULL; 427 paramsMaxUse = NULL; 428 limitsApply = false; 429 break; 430 case PM_MODEL_LIMITS_LAX: 431 paramsMinUse = paramsMinLax; 432 paramsMaxUse = paramsMaxLax; 433 limitsApply = true; 434 break; 435 case PM_MODEL_LIMITS_MODERATE: 436 paramsMinUse = paramsMinModerate; 437 paramsMaxUse = paramsMaxModerate; 438 limitsApply = true; 439 break; 440 case PM_MODEL_LIMITS_STRICT: 441 paramsMinUse = paramsMinStrict; 442 paramsMaxUse = paramsMaxStrict; 443 limitsApply = true; 444 break; 445 default: 446 psAbort("Unrecognised model limits type: %x", type); 447 } 448 return; 434 449 } 435 450 … … 442 457 # undef PM_MODEL_PARAMS_FROM_PSF 443 458 # undef PM_MODEL_FIT_STATUS 459 # undef PM_MODEL_SET_LIMITS -
branches/simtest_nebulous_branches/psModules/src/objects/models/pmModel_PS1_V1.c
r23962 r27840 1 1 /****************************************************************************** 2 * this file defines the PS1_V1 source shape model (XXX need a better name!). Note that these3 * model functions are loaded by pmModelGroup.c using 'include', and thus need no 'include'4 * statements of their own. The models use a psVector to represent the set of parameters, with5 * the sequence used to specify the meaning of the parameter. The meaning of the parameters6 * may thus vary depending on the specifics of the model. All models which are used a PSF7 * representations share a fewparameters, for which # define names are listed in pmModel.h:2 * this file defines the PS1_V1 source shape model. Note that these model functions are loaded 3 * by pmModelClass.c using 'include', and thus need no 'include' statements of their own. The 4 * models use a psVector to represent the set of parameters, with the sequence used to specify 5 * the meaning of the parameter. The meaning of the parameters may thus vary depending on the 6 * specifics of the model. All models which are used as a PSF representations share a few 7 * parameters, for which # define names are listed in pmModel.h: 8 8 9 9 power-law with fitted linear term … … 20 20 *****************************************************************************/ 21 21 22 #include <stdio.h> 23 #include <pslib.h> 24 25 #include "pmMoments.h" 26 #include "pmPeaks.h" 27 #include "pmSource.h" 28 #include "pmModel.h" 29 #include "pmModel_PS1_V1.h" 30 22 31 # define PM_MODEL_FUNC pmModelFunc_PS1_V1 23 32 # define PM_MODEL_FLUX pmModelFlux_PS1_V1 … … 28 37 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_PS1_V1 29 38 # define PM_MODEL_FIT_STATUS pmModelFitStatus_PS1_V1 39 # define PM_MODEL_SET_LIMITS pmModelSetLimits_PS1_V1 30 40 31 41 # define ALPHA 1.666 32 42 # define ALPHA_M 0.666 43 44 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y) 45 // 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords 46 // values need to be pixel coords 47 48 // Lax parameter limits 49 static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, -1.0 }; 50 static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 }; 51 52 // Moderate parameter limits 53 // Tolerate a small divot (k < 0) 54 static float paramsMinModerate[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, -0.05 }; 55 static float paramsMaxModerate[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 }; 56 57 // Strict parameter limits 58 // k = PAR_7 < 0 is very undesirable (big divot in the middle) 59 static float paramsMinStrict[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, 0.0 }; 60 static float paramsMaxStrict[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 }; 61 62 // Parameter limits to use 63 static float *paramsMinUse = paramsMinLax; 64 static float *paramsMaxUse = paramsMaxLax; 65 static float betaUse[] = { 1000, 3e6, 5, 5, 1.0, 1.0, 0.5, 2.0 }; 66 67 static bool limitsApply = true; // Apply limits? 33 68 34 69 psF32 PM_MODEL_FUNC (psVector *deriv, … … 84 119 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta) 85 120 { 86 float beta_lim = 0, params_min = 0, params_max = 0; 87 float f1 = 0, f2 = 0, q1 = 0, q2 = 0; 121 if (!limitsApply) { 122 return true; 123 } 124 psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds"); 88 125 89 126 // we need to calculate the limits for SXY specially 127 float q2 = NAN; 90 128 if (nParam == PM_PAR_SXY) { 91 f 1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);92 f 2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);93 q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);129 float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]); 130 float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]); 131 float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2); 94 132 q1 = (q1 < 0.0) ? 0.0 : q1; 95 133 // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg.. Saturate at that 96 134 // angle and let f2,f1 fight it out 97 q2 = 0.5*sqrt(q1);135 q2 = 0.5*sqrtf(q1); 98 136 } 99 137 100 138 switch (mode) { 101 case PS_MINIMIZE_BETA_LIMIT: 102 switch (nParam) { 103 case PM_PAR_SKY: 104 beta_lim = 1000; 105 break; 106 case PM_PAR_I0: 107 beta_lim = 3e6; 108 break; 109 case PM_PAR_XPOS: 110 beta_lim = 5; 111 break; 112 case PM_PAR_YPOS: 113 beta_lim = 5; 114 break; 115 case PM_PAR_SXX: 116 beta_lim = 1.0; 117 break; 118 case PM_PAR_SYY: 119 beta_lim = 1.0; 120 break; 121 case PM_PAR_SXY: 122 beta_lim = 0.5*q2; 123 break; 124 case PM_PAR_7: 125 beta_lim = 2.0; 126 break; 127 default: 128 psAbort("invalid parameter %d for beta test", nParam); 129 } 130 if (fabs(beta[nParam]) > fabs(beta_lim)) { 131 beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim); 132 psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 133 nParam, beta[nParam], beta_lim); 134 return false; 135 } 136 return true; 137 case PS_MINIMIZE_PARAM_MIN: 138 switch (nParam) { 139 case PM_PAR_SKY: 140 params_min = -1000; 141 break; 142 case PM_PAR_I0: 143 params_min = 0.01; 144 break; 145 case PM_PAR_XPOS: 146 params_min = -100; 147 break; 148 case PM_PAR_YPOS: 149 params_min = -100; 150 break; 151 case PM_PAR_SXX: 152 params_min = 0.5; 153 break; 154 case PM_PAR_SYY: 155 params_min = 0.5; 156 break; 157 case PM_PAR_SXY: 158 params_min = -q2; 159 break; 160 case PM_PAR_7: 161 params_min = -1.0; 162 break; 163 default: 164 psAbort("invalid parameter %d for param min test", nParam); 165 } 166 if (params[nParam] < params_min) { 167 params[nParam] = params_min; 168 psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 169 nParam, params[nParam], params_min); 170 return false; 171 } 172 return true; 173 case PS_MINIMIZE_PARAM_MAX: 174 switch (nParam) { 175 case PM_PAR_SKY: 176 params_max = 1e5; 177 break; 178 case PM_PAR_I0: 179 params_max = 1e8; 180 break; 181 case PM_PAR_XPOS: 182 params_max = 1e4; 183 break; 184 case PM_PAR_YPOS: 185 params_max = 1e4; 186 break; 187 case PM_PAR_SXX: 188 params_max = 100; 189 break; 190 case PM_PAR_SYY: 191 params_max = 100; 192 break; 193 case PM_PAR_SXY: 194 params_max = +q2; 195 break; 196 case PM_PAR_7: 197 params_max = 20.0; 198 break; 199 default: 200 psAbort("invalid parameter %d for param max test", nParam); 201 } 202 if (params[nParam] > params_max) { 203 params[nParam] = params_max; 204 psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 205 nParam, params[nParam], params_max); 206 return false; 207 } 208 return true; 209 default: 139 case PS_MINIMIZE_BETA_LIMIT: { 140 psAssert(beta, "Require beta to limit beta"); 141 float limit = betaUse[nParam]; 142 if (nParam == PM_PAR_SXY) { 143 limit *= q2; 144 } 145 if (fabs(beta[nParam]) > fabs(limit)) { 146 beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit); 147 psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 148 nParam, beta[nParam], limit); 149 return false; 150 } 151 return true; 152 } 153 case PS_MINIMIZE_PARAM_MIN: { 154 psAssert(params, "Require parameters to limit parameters"); 155 psAssert(paramsMinUse, "Require parameter limits to limit parameters"); 156 float limit = paramsMinUse[nParam]; 157 if (nParam == PM_PAR_SXY) { 158 limit *= q2; 159 } 160 if (params[nParam] < limit) { 161 params[nParam] = limit; 162 psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 163 nParam, params[nParam], limit); 164 return false; 165 } 166 return true; 167 } 168 case PS_MINIMIZE_PARAM_MAX: { 169 psAssert(params, "Require parameters to limit parameters"); 170 psAssert(paramsMaxUse, "Require parameter limits to limit parameters"); 171 float limit = paramsMaxUse[nParam]; 172 if (nParam == PM_PAR_SXY) { 173 limit *= q2; 174 } 175 if (params[nParam] > limit) { 176 params[nParam] = limit; 177 psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 178 nParam, params[nParam], limit); 179 return false; 180 } 181 return true; 182 } 183 default: 210 184 psAbort("invalid choice for limits"); 211 185 } … … 216 190 217 191 // make an initial guess for parameters 192 // 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters 218 193 bool PM_MODEL_GUESS (pmModel *model, pmSource *source) 219 194 { … … 240 215 if (!isfinite(shape.sxy)) return false; 241 216 242 // XXX turn this off here for now PAR[PM_PAR_SKY] = moments->Sky;243 217 PAR[PM_PAR_SKY] = 0.0; 244 218 PAR[PM_PAR_I0] = peak->flux; … … 293 267 psF64 PM_MODEL_RADIUS (const psVector *params, psF64 flux) 294 268 { 295 psF64 z , f;269 psF64 z; 296 270 int Nstep = 0; 297 271 psEllipseShape shape; … … 299 273 psF32 *PAR = params->data.F32; 300 274 301 if (flux <= 0) 302 return (1.0); 303 if (PAR[PM_PAR_I0] <= 0) 304 return (1.0); 305 if (flux >= PAR[PM_PAR_I0]) 306 return (1.0); 275 if (flux <= 0) return 1.0; 276 if (PAR[PM_PAR_I0] <= 0) return 1.0; 277 if (flux >= PAR[PM_PAR_I0]) return 1.0; 278 if (PAR[PM_PAR_7] == 0.0) return powf(PAR[PM_PAR_I0] / flux - 1.0, 1.0 / ALPHA); 307 279 308 280 shape.sx = PAR[PM_PAR_SXX] / M_SQRT2; … … 320 292 321 293 // choose a z value guaranteed to be beyond our limit 322 float z0 = pow((1.0 / limit), (1.0 / ALPHA)); 323 float z1 = (1.0 / limit) / PAR[PM_PAR_7]; 324 z1 = PS_MAX (z0, z1); 325 z0 = 0.0; 326 327 // perform a type of bisection to find the value 328 float f0 = 1.0 / (1 + PAR[PM_PAR_7]*z0 + pow(z0, ALPHA)); 329 float f1 = 1.0 / (1 + PAR[PM_PAR_7]*z1 + pow(z1, ALPHA)); 330 while ((Nstep < 10) && (fabs(z1 - z0) > 0.5)) { 331 z = 0.5*(z0 + z1); 332 f = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA)); 333 if (f > limit) { 334 z0 = z; 335 f0 = f; 336 } else { 337 z1 = z; 338 f1 = f; 339 } 340 Nstep ++; 294 float z0 = 0.0; 295 float z1 = pow((1.0 / limit), (1.0 / ALPHA)); 296 psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]); 297 if (PAR[PM_PAR_7] < 0.0) z1 *= 2.0; 298 299 // starting guess: 300 z = 0.5*(z0 + z1); 301 float dz = 1.0; 302 303 // use Newton-Raphson to minimize f(z) - limit = 0 304 for (int i = 0; (i < 10) && (fabs(dz) > 0.0001); i++) { 305 float q = (1.0 + PAR[PM_PAR_7]*z + pow(z, ALPHA)); 306 float dqdz = (PAR[PM_PAR_7] + ALPHA*pow(z, ALPHA - 1.0)); 307 308 float f = 1.0 / q; 309 float dfdz = -dqdz * f / q; 310 311 dz = (f - limit) / dfdz; 312 313 // fprintf (stderr, "%f %f %f : %f %f\n", f, z, dz, dfdz, q); 314 z -= dz; 315 z = PS_MAX(z, 0.0); 341 316 } 342 317 psF64 radius = sigma * sqrt (2.0 * z); … … 370 345 // convert to shape terms (SXX,SYY,SXY) 371 346 if (!pmPSF_FitToModel (out, 0.1)) { 372 // psError(PM_ERR_PSF, false, "Failed to fit object at (r,c) = (%.1f,%.1f)", in[PM_PAR_YPOS], in[PM_PAR_XPOS]);373 347 psTrace("psModules.objects", 5, "Failed to fit object at (r,c) = (%.1f,%.1f)", in[PM_PAR_YPOS], in[PM_PAR_XPOS]); 374 348 return false; … … 448 422 bool PM_MODEL_FIT_STATUS (pmModel *model) 449 423 { 450 451 psF32 dP;452 424 bool status; 453 425 … … 455 427 psF32 *dPAR = model->dparams->data.F32; 456 428 457 dP = 0;458 dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);459 dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);460 dP = sqrt (dP);461 462 429 status = true; 463 // status &= (dP < 0.5);464 430 status &= (PAR[PM_PAR_I0] > 0); 465 431 status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5); 466 432 467 433 return status; 434 } 435 436 437 void PM_MODEL_SET_LIMITS(pmModelLimitsType type) 438 { 439 switch (type) { 440 case PM_MODEL_LIMITS_NONE: 441 paramsMinUse = NULL; 442 paramsMaxUse = NULL; 443 limitsApply = true; 444 break; 445 case PM_MODEL_LIMITS_IGNORE: 446 paramsMinUse = NULL; 447 paramsMaxUse = NULL; 448 limitsApply = false; 449 break; 450 case PM_MODEL_LIMITS_LAX: 451 paramsMinUse = paramsMinLax; 452 paramsMaxUse = paramsMaxLax; 453 limitsApply = true; 454 break; 455 case PM_MODEL_LIMITS_MODERATE: 456 paramsMinUse = paramsMinModerate; 457 paramsMaxUse = paramsMaxModerate; 458 limitsApply = true; 459 break; 460 case PM_MODEL_LIMITS_STRICT: 461 paramsMinUse = paramsMinStrict; 462 paramsMaxUse = paramsMaxStrict; 463 limitsApply = true; 464 break; 465 default: 466 psAbort("Unrecognised model limits type: %x", type); 467 } 468 return; 468 469 } 469 470 … … 476 477 # undef PM_MODEL_PARAMS_FROM_PSF 477 478 # undef PM_MODEL_FIT_STATUS 479 # undef PM_MODEL_SET_LIMITS 478 480 # undef ALPHA 479 481 # undef ALPHA_M -
branches/simtest_nebulous_branches/psModules/src/objects/models/pmModel_QGAUSS.c
r20001 r27840 1 1 /****************************************************************************** 2 2 * this file defines the QGAUSS source shape model (XXX need a better name!). Note that these 3 * model functions are loaded by pmModel Group.c using 'include', and thus need no 'include'3 * model functions are loaded by pmModelClass.c using 'include', and thus need no 'include' 4 4 * statements of their own. The models use a psVector to represent the set of parameters, with 5 5 * the sequence used to specify the meaning of the parameter. The meaning of the parameters … … 20 20 *****************************************************************************/ 21 21 22 #include <stdio.h> 23 #include <pslib.h> 24 25 #include "pmMoments.h" 26 #include "pmPeaks.h" 27 #include "pmSource.h" 28 #include "pmModel.h" 29 #include "pmModel_QGAUSS.h" 30 22 31 # define PM_MODEL_FUNC pmModelFunc_QGAUSS 23 32 # define PM_MODEL_FLUX pmModelFlux_QGAUSS … … 28 37 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_QGAUSS 29 38 # define PM_MODEL_FIT_STATUS pmModelFitStatus_QGAUSS 39 # define PM_MODEL_SET_LIMITS pmModelSetLimits_QGAUSS 40 41 # define ALPHA 2.250 42 # define ALPHA_M 1.250 43 44 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y) 45 // 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords 46 // values need to be pixel coords 47 48 // Lax parameter limits 49 static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, -1.0 }; 50 static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 }; 51 52 // Moderate parameter limits 53 // Tolerate a small divot (k < 0) 54 static float paramsMinModerate[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, -0.05 }; 55 static float paramsMaxModerate[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 }; 56 57 // Strict parameter limits 58 // k = PAR_7 < 0 is very undesirable (big divot in the middle) 59 static float paramsMinStrict[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, 0.0 }; 60 static float paramsMaxStrict[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 }; 61 62 // Parameter limits to use 63 static float *paramsMinUse = paramsMinLax; 64 static float *paramsMaxUse = paramsMaxLax; 65 static float betaUse[] = { 1000, 3e6, 5, 5, 1.0, 1.0, 0.5, 2.0 }; 66 67 static bool limitsApply = true; // Apply limits? 30 68 31 69 psF32 PM_MODEL_FUNC (psVector *deriv, … … 48 86 assert (z >= 0); 49 87 50 psF32 zp = pow(z, 1.25);88 psF32 zp = pow(z,ALPHA_M); 51 89 psF32 r = 1.0 / (1 + PAR[PM_PAR_7]*z + z*zp); 52 90 … … 59 97 // note difference from a pure gaussian: q = params->data.F32[PM_PAR_I0]*r 60 98 psF32 t = r1*r; 61 psF32 q = t*(PAR[PM_PAR_7] + 2.25*zp);99 psF32 q = t*(PAR[PM_PAR_7] + ALPHA*zp); 62 100 63 101 dPAR[PM_PAR_SKY] = +1.0; … … 79 117 # define AR_MAX 20.0 80 118 # define AR_RATIO 0.99 119 81 120 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta) 82 121 { 83 float beta_lim = 0, params_min = 0, params_max = 0; 84 float f1 = 0, f2 = 0, q1 = 0, q2 = 0; 122 if (!limitsApply) { 123 return true; 124 } 125 psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds"); 85 126 86 127 // we need to calculate the limits for SXY specially 128 float q2 = NAN; 87 129 if (nParam == PM_PAR_SXY) { 88 f 1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);89 f 2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);90 q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);130 float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]); 131 float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]); 132 float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2); 91 133 q1 = (q1 < 0.0) ? 0.0 : q1; 92 134 // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg.. Saturate at that 93 135 // angle and let f2,f1 fight it out 94 q2 = 0.5*sqrt(q1);136 q2 = 0.5*sqrtf(q1); 95 137 } 96 138 97 139 switch (mode) { 98 case PS_MINIMIZE_BETA_LIMIT: 99 switch (nParam) { 100 case PM_PAR_SKY: 101 beta_lim = 1000; 102 break; 103 case PM_PAR_I0: 104 beta_lim = 3e6; 105 break; 106 case PM_PAR_XPOS: 107 beta_lim = 5; 108 break; 109 case PM_PAR_YPOS: 110 beta_lim = 5; 111 break; 112 case PM_PAR_SXX: 113 beta_lim = 1.0; 114 break; 115 case PM_PAR_SYY: 116 beta_lim = 1.0; 117 break; 118 case PM_PAR_SXY: 119 beta_lim = 0.5*q2; 120 break; 121 case PM_PAR_7: 122 beta_lim = 2.0; 123 break; 124 default: 125 psAbort("invalid parameter %d for beta test", nParam); 126 } 127 if (fabs(beta[nParam]) > fabs(beta_lim)) { 128 beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim); 129 psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 130 nParam, beta[nParam], beta_lim); 131 return false; 132 } 133 return true; 134 case PS_MINIMIZE_PARAM_MIN: 135 switch (nParam) { 136 case PM_PAR_SKY: 137 params_min = -1000; 138 break; 139 case PM_PAR_I0: 140 params_min = 0.01; 141 break; 142 case PM_PAR_XPOS: 143 params_min = -100; 144 break; 145 case PM_PAR_YPOS: 146 params_min = -100; 147 break; 148 case PM_PAR_SXX: 149 params_min = 0.5; 150 break; 151 case PM_PAR_SYY: 152 params_min = 0.5; 153 break; 154 case PM_PAR_SXY: 155 params_min = -q2; 156 break; 157 case PM_PAR_7: 158 params_min = 0.1; 159 break; 160 default: 161 psAbort("invalid parameter %d for param min test", nParam); 162 } 163 if (params[nParam] < params_min) { 164 params[nParam] = params_min; 165 psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 166 nParam, params[nParam], params_min); 167 return false; 168 } 169 return true; 170 case PS_MINIMIZE_PARAM_MAX: 171 switch (nParam) { 172 case PM_PAR_SKY: 173 params_max = 1e5; 174 break; 175 case PM_PAR_I0: 176 params_max = 1e8; 177 break; 178 case PM_PAR_XPOS: 179 params_max = 1e4; 180 break; 181 case PM_PAR_YPOS: 182 params_max = 1e4; 183 break; 184 case PM_PAR_SXX: 185 params_max = 100; 186 break; 187 case PM_PAR_SYY: 188 params_max = 100; 189 break; 190 case PM_PAR_SXY: 191 params_max = +q2; 192 break; 193 case PM_PAR_7: 194 params_max = 20.0; 195 break; 196 default: 197 psAbort("invalid parameter %d for param max test", nParam); 198 } 199 if (params[nParam] > params_max) { 200 params[nParam] = params_max; 201 psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 202 nParam, params[nParam], params_max); 203 return false; 204 } 205 return true; 140 case PS_MINIMIZE_BETA_LIMIT: { 141 psAssert(beta, "Require beta to limit beta"); 142 float limit = betaUse[nParam]; 143 if (nParam == PM_PAR_SXY) { 144 limit *= q2; 145 } 146 if (fabs(beta[nParam]) > fabs(limit)) { 147 beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit); 148 psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 149 nParam, beta[nParam], limit); 150 return false; 151 } 152 return true; 153 } 154 case PS_MINIMIZE_PARAM_MIN: { 155 psAssert(params, "Require parameters to limit parameters"); 156 psAssert(paramsMinUse, "Require parameter limits to limit parameters"); 157 float limit = paramsMinUse[nParam]; 158 if (nParam == PM_PAR_SXY) { 159 limit *= q2; 160 } 161 if (params[nParam] < limit) { 162 params[nParam] = limit; 163 psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 164 nParam, params[nParam], limit); 165 return false; 166 } 167 return true; 168 } 169 case PS_MINIMIZE_PARAM_MAX: { 170 psAssert(params, "Require parameters to limit parameters"); 171 psAssert(paramsMaxUse, "Require parameter limits to limit parameters"); 172 float limit = paramsMaxUse[nParam]; 173 if (nParam == PM_PAR_SXY) { 174 limit *= q2; 175 } 176 if (params[nParam] > limit) { 177 params[nParam] = limit; 178 psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 179 nParam, params[nParam], limit); 180 return false; 181 } 182 return true; 183 } 206 184 default: 207 185 psAbort("invalid choice for limits"); … … 213 191 214 192 // make an initial guess for parameters 193 // 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters 215 194 bool PM_MODEL_GUESS (pmModel *model, pmSource *source) 216 195 { … … 237 216 if (!isfinite(shape.sxy)) return false; 238 217 239 // XXX turn this off here for now PAR[PM_PAR_SKY] = moments->Sky;240 218 PAR[PM_PAR_SKY] = 0.0; 241 219 PAR[PM_PAR_I0] = peak->flux; … … 273 251 float f1, f2; 274 252 for (z = DZ; z < 50; z += DZ) { 275 f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, 2.25));253 f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA)); 276 254 z += DZ; 277 f2 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, 2.25));255 f2 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, ALPHA)); 278 256 norm += f0 + 4*f1 + f2; 279 257 f0 = f2; … … 290 268 psF64 PM_MODEL_RADIUS (const psVector *params, psF64 flux) 291 269 { 292 psF64 z , f;270 psF64 z; 293 271 int Nstep = 0; 294 272 psEllipseShape shape; … … 296 274 psF32 *PAR = params->data.F32; 297 275 298 if (flux <= 0) 299 return (1.0); 300 if (PAR[PM_PAR_I0] <= 0) 301 return (1.0); 302 if (flux >= PAR[PM_PAR_I0]) 303 return (1.0); 276 if (flux <= 0) return 1.0; 277 if (PAR[PM_PAR_I0] <= 0) return 1.0; 278 if (flux >= PAR[PM_PAR_I0]) return 1.0; 279 if (PAR[PM_PAR_7] == 0.0) return powf(PAR[PM_PAR_I0] / flux - 1.0, 1.0 / ALPHA); 304 280 305 281 shape.sx = PAR[PM_PAR_SXX] / M_SQRT2; … … 317 293 318 294 // choose a z value guaranteed to be beyond our limit 319 float z0 = pow((1.0 / limit), (1.0 / 2.25)); 320 float z1 = (1.0 / limit) / PAR[PM_PAR_7]; 321 z1 = PS_MAX (z0, z1); 322 z0 = 0.0; 323 324 // perform a type of bisection to find the value 325 float f0 = 1.0 / (1 + PAR[PM_PAR_7]*z0 + pow(z0, 2.25)); 326 float f1 = 1.0 / (1 + PAR[PM_PAR_7]*z1 + pow(z1, 2.25)); 327 while ((Nstep < 10) && (fabs(z1 - z0) > 0.5)) { 328 z = 0.5*(z0 + z1); 329 f = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, 2.25)); 330 if (f > limit) { 331 z0 = z; 332 f0 = f; 333 } else { 334 z1 = z; 335 f1 = f; 336 } 337 Nstep ++; 295 float z0 = 0.0; 296 float z1 = pow((1.0 / limit), (1.0 / ALPHA)); 297 psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]); 298 if (PAR[PM_PAR_7] < 0.0) z1 *= 2.0; 299 300 // starting guess: 301 z = 0.5*(z0 + z1); 302 float dz = 1.0; 303 304 // use Newton-Raphson to minimize f(z) - limit = 0 305 for (int i = 0; (i < 10) && (fabs(dz) > 0.0001); i++) { 306 float q = (1.0 + PAR[PM_PAR_7]*z + pow(z, ALPHA)); 307 float dqdz = (PAR[PM_PAR_7] + ALPHA*pow(z, ALPHA - 1.0)); 308 309 float f = 1.0 / q; 310 float dfdz = -dqdz * f / q; 311 312 dz = (f - limit) / dfdz; 313 314 // fprintf (stderr, "%f %f %f : %f %f\n", f, z, dz, dfdz, q); 315 z -= dz; 316 z = PS_MAX(z, 0.0); 338 317 } 339 318 psF64 radius = sigma * sqrt (2.0 * z); … … 444 423 bool PM_MODEL_FIT_STATUS (pmModel *model) 445 424 { 446 447 psF32 dP;448 425 bool status; 449 426 … … 451 428 psF32 *dPAR = model->dparams->data.F32; 452 429 453 dP = 0;454 dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);455 dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);456 dP = sqrt (dP);457 458 430 status = true; 459 // status &= (dP < 0.5);460 431 status &= (PAR[PM_PAR_I0] > 0); 461 432 status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5); 462 433 463 434 return status; 435 } 436 437 438 void PM_MODEL_SET_LIMITS(pmModelLimitsType type) 439 { 440 switch (type) { 441 case PM_MODEL_LIMITS_NONE: 442 paramsMinUse = NULL; 443 paramsMaxUse = NULL; 444 limitsApply = true; 445 break; 446 case PM_MODEL_LIMITS_IGNORE: 447 paramsMinUse = NULL; 448 paramsMaxUse = NULL; 449 limitsApply = false; 450 break; 451 case PM_MODEL_LIMITS_LAX: 452 paramsMinUse = paramsMinLax; 453 paramsMaxUse = paramsMaxLax; 454 limitsApply = true; 455 break; 456 case PM_MODEL_LIMITS_MODERATE: 457 paramsMinUse = paramsMinModerate; 458 paramsMaxUse = paramsMaxModerate; 459 limitsApply = true; 460 break; 461 case PM_MODEL_LIMITS_STRICT: 462 paramsMinUse = paramsMinStrict; 463 paramsMaxUse = paramsMaxStrict; 464 limitsApply = true; 465 break; 466 default: 467 psAbort("Unrecognised model limits type: %x", type); 468 } 469 return; 464 470 } 465 471 … … 472 478 # undef PM_MODEL_PARAMS_FROM_PSF 473 479 # undef PM_MODEL_FIT_STATUS 480 # undef PM_MODEL_SET_LIMITS 481 # undef ALPHA 482 # undef ALPHA_M -
branches/simtest_nebulous_branches/psModules/src/objects/models/pmModel_RGAUSS.c
r20001 r27840 1 1 /****************************************************************************** 2 2 * this file defines the RGAUSS source shape model (XXX need a better name!). Note that these 3 * model functions are loaded by pmModel Group.c using 'include', and thus need no 'include'3 * model functions are loaded by pmModelClass.c using 'include', and thus need no 'include' 4 4 * statements of their own. The models use a psVector to represent the set of parameters, with 5 5 * the sequence used to specify the meaning of the parameter. The meaning of the parameters 6 * may thus vary depending on the specifics of the model. All models which are used a PSF6 * may thus vary depending on the specifics of the model. All models which are used as a PSF 7 7 * representations share a few parameters, for which # define names are listed in pmModel.h: 8 8 … … 20 20 *****************************************************************************/ 21 21 22 #include <stdio.h> 23 #include <pslib.h> 24 25 #include "pmMoments.h" 26 #include "pmPeaks.h" 27 #include "pmSource.h" 28 #include "pmModel.h" 29 #include "pmModel_RGAUSS.h" 30 22 31 # define PM_MODEL_FUNC pmModelFunc_RGAUSS 23 32 # define PM_MODEL_FLUX pmModelFlux_RGAUSS … … 28 37 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_RGAUSS 29 38 # define PM_MODEL_FIT_STATUS pmModelFitStatus_RGAUSS 39 # define PM_MODEL_SET_LIMITS pmModelSetLimits_RGAUSS 40 41 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y) 42 // 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords 43 // values need to be pixel coords 44 45 // Lax parameter limits 46 static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, 1.25 }; 47 static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 4.0 }; 48 49 // Moderate parameter limits 50 static float *paramsMinModerate = paramsMinLax; 51 static float *paramsMaxModerate = paramsMaxLax; 52 53 // Strict parameter limits 54 static float *paramsMinStrict = paramsMinLax; 55 static float *paramsMaxStrict = paramsMaxLax; 56 57 // Parameter limits to use 58 static float *paramsMinUse = paramsMinLax; 59 static float *paramsMaxUse = paramsMaxLax; 60 static float betaUse[] = { 1000, 3e6, 5, 5, 0.5, 0.5, 0.5, 0.5 }; 61 62 static bool limitsApply = true; // Apply limits? 30 63 31 64 psF32 PM_MODEL_FUNC (psVector *deriv, … … 62 95 dPAR[PM_PAR_SXY] = -q*X*Y; 63 96 64 // this model derivative is undefined at z = 0.0, but is actually0.097 // this model derivative is undefined at z = 0.0, but the limit is zero as z -> 0.0 65 98 dPAR[PM_PAR_7] = (z == 0.0) ? 0.0 : -5.0*t*log(z)*p*z; 66 99 } … … 73 106 # define AR_MAX 20.0 74 107 # define AR_RATIO 0.99 108 75 109 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta) 76 110 { 77 float beta_lim = 0, params_min = 0, params_max = 0; 78 float f1 = 0, f2 = 0, q1 = 0, q2 = 0; 111 if (!limitsApply) { 112 return true; 113 } 114 psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds"); 79 115 80 116 // we need to calculate the limits for SXY specially 117 float q2 = NAN; 81 118 if (nParam == PM_PAR_SXY) { 82 f 1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);83 f 2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);84 q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);119 float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]); 120 float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]); 121 float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2); 85 122 q1 = (q1 < 0.0) ? 0.0 : q1; 86 123 // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg.. Saturate at that 87 124 // angle and let f2,f1 fight it out 88 q2 = 0.5*sqrt(q1);125 q2 = 0.5*sqrtf(q1); 89 126 } 90 127 91 128 switch (mode) { 92 case PS_MINIMIZE_BETA_LIMIT: 93 switch (nParam) { 94 case PM_PAR_SKY: 95 beta_lim = 1000; 96 break; 97 case PM_PAR_I0: 98 beta_lim = 3e6; 99 break; 100 case PM_PAR_XPOS: 101 beta_lim = 5; 102 break; 103 case PM_PAR_YPOS: 104 beta_lim = 5; 105 break; 106 case PM_PAR_SXX: 107 beta_lim = 0.5; 108 break; 109 case PM_PAR_SYY: 110 beta_lim = 0.5; 111 break; 112 case PM_PAR_SXY: 113 beta_lim = 0.5*q2; 114 break; 115 case PM_PAR_7: 116 beta_lim = 0.5; 117 break; 118 default: 119 psAbort("invalid parameter %d for beta test", nParam); 120 } 121 if (fabs(beta[nParam]) > fabs(beta_lim)) { 122 beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim); 123 psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 124 nParam, beta[nParam], beta_lim); 125 return false; 126 } 127 return true; 128 case PS_MINIMIZE_PARAM_MIN: 129 switch (nParam) { 130 case PM_PAR_SKY: 131 params_min = -1000; 132 break; 133 case PM_PAR_I0: 134 params_min = 0.01; 135 break; 136 case PM_PAR_XPOS: 137 params_min = -100; 138 break; 139 case PM_PAR_YPOS: 140 params_min = -100; 141 break; 142 case PM_PAR_SXX: 143 params_min = 0.5; 144 break; 145 case PM_PAR_SYY: 146 params_min = 0.5; 147 break; 148 case PM_PAR_SXY: 149 params_min = -q2; 150 break; 151 case PM_PAR_7: 152 params_min = 1.25; 153 break; 154 default: 155 psAbort("invalid parameter %d for param min test", nParam); 156 } 157 if (params[nParam] < params_min) { 158 params[nParam] = params_min; 159 psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 160 nParam, params[nParam], params_min); 161 return false; 162 } 163 return true; 164 case PS_MINIMIZE_PARAM_MAX: 165 switch (nParam) { 166 case PM_PAR_SKY: 167 params_max = 1e5; 168 break; 169 case PM_PAR_I0: 170 params_max = 1e8; 171 break; 172 case PM_PAR_XPOS: 173 params_max = 1e4; 174 break; 175 case PM_PAR_YPOS: 176 params_max = 1e4; 177 break; 178 case PM_PAR_SXX: 179 params_max = 100; 180 break; 181 case PM_PAR_SYY: 182 params_max = 100; 183 break; 184 case PM_PAR_SXY: 185 params_max = +q2; 186 break; 187 case PM_PAR_7: 188 params_max = 4.0; 189 break; 190 default: 191 psAbort("invalid parameter %d for param max test", nParam); 192 } 193 if (params[nParam] > params_max) { 194 params[nParam] = params_max; 195 psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 196 nParam, params[nParam], params_max); 197 return false; 198 } 199 return true; 200 default: 129 case PS_MINIMIZE_BETA_LIMIT: { 130 psAssert(beta, "Require beta to limit beta"); 131 float limit = betaUse[nParam]; 132 if (nParam == PM_PAR_SXY) { 133 limit *= q2; 134 } 135 if (fabs(beta[nParam]) > fabs(limit)) { 136 beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit); 137 psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 138 nParam, beta[nParam], limit); 139 return false; 140 } 141 return true; 142 } 143 case PS_MINIMIZE_PARAM_MIN: { 144 psAssert(params, "Require parameters to limit parameters"); 145 psAssert(paramsMinUse, "Require parameter limits to limit parameters"); 146 float limit = paramsMinUse[nParam]; 147 if (nParam == PM_PAR_SXY) { 148 limit *= q2; 149 } 150 if (params[nParam] < limit) { 151 params[nParam] = limit; 152 psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 153 nParam, params[nParam], limit); 154 return false; 155 } 156 return true; 157 } 158 case PS_MINIMIZE_PARAM_MAX: { 159 psAssert(params, "Require parameters to limit parameters"); 160 psAssert(paramsMaxUse, "Require parameter limits to limit parameters"); 161 float limit = paramsMaxUse[nParam]; 162 if (nParam == PM_PAR_SXY) { 163 limit *= q2; 164 } 165 if (params[nParam] > limit) { 166 params[nParam] = limit; 167 psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 168 nParam, params[nParam], limit); 169 return false; 170 } 171 return true; 172 } 173 default: 201 174 psAbort("invalid choice for limits"); 202 175 } … … 205 178 } 206 179 180 207 181 // make an initial guess for parameters 182 // 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters 208 183 bool PM_MODEL_GUESS (pmModel *model, pmSource *source) 209 184 { … … 230 205 if (!isfinite(shape.sxy)) return false; 231 206 232 PAR[PM_PAR_SKY] = moments->Sky;207 PAR[PM_PAR_SKY] = 0.0; 233 208 PAR[PM_PAR_I0] = peak->flux; 234 209 PAR[PM_PAR_XPOS] = peak->xf; … … 282 257 psF64 PM_MODEL_RADIUS (const psVector *params, psF64 flux) 283 258 { 284 psF64 z , f;259 psF64 z; 285 260 int Nstep = 0; 286 261 psEllipseShape shape; … … 310 285 // choose a z value guaranteed to be beyond our limit 311 286 float z0 = pow((1.0 / limit), (1.0 / PAR[PM_PAR_7])); 287 psAssert (isfinite(z0), "fix this code: z0 should not be nan for %f", PAR[PM_PAR_7]); 312 288 float z1 = (1.0 / limit); 289 psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]); 313 290 z1 = PS_MAX (z0, z1); 314 291 z0 = 0.0; 315 292 316 // perform a type of bisection to find the value 317 float f0 = 1.0 / (1 + z0 + pow(z0, PAR[PM_PAR_7])); 318 float f1 = 1.0 / (1 + z1 + pow(z1, PAR[PM_PAR_7])); 319 while ((Nstep < 10) && (fabs(z1 - z0) > 0.5)) { 320 z = 0.5*(z0 + z1); 321 f = 1.0 / (1 + z + pow(z, PAR[PM_PAR_7])); 322 if (f > limit) { 323 z0 = z; 324 f0 = f; 325 } else { 326 z1 = z; 327 f1 = f; 328 } 329 Nstep ++; 330 } 293 // starting guess: 294 z = 0.5*(z0 + z1); 295 float dz = 1.0; 296 297 for (int i = 0; (i < 10) && (fabs(dz) > 0.0001); i++) { 298 // use Newton-Raphson to minimize f(z) - limit = 0 299 float q = (1 + z + pow(z,PAR[PM_PAR_7])); 300 float dqdz = (1.0 + PAR[PM_PAR_7]*pow(z,PAR[PM_PAR_7] - 1.0)); 301 302 float f = 1.0 / q; 303 float dfdz = -dqdz * f / q; 304 305 dz = (f - limit) / dfdz; 306 307 // fprintf (stderr, "%f %f %f : %f %f\n", f, z, dz, dfdz, q); 308 z -= dz; 309 z = PS_MAX(z, 0.0); 310 } 311 331 312 psF64 radius = sigma * sqrt (2.0 * z); 332 313 … … 436 417 bool PM_MODEL_FIT_STATUS (pmModel *model) 437 418 { 438 439 psF32 dP;440 419 bool status; 441 420 … … 443 422 psF32 *dPAR = model->dparams->data.F32; 444 423 445 dP = 0;446 dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);447 dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);448 dP = sqrt (dP);449 450 424 status = true; 451 status &= (dP < 0.5);452 425 status &= (PAR[PM_PAR_I0] > 0); 453 426 status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5); 454 427 455 428 return status; 429 } 430 431 432 void PM_MODEL_SET_LIMITS(pmModelLimitsType type) 433 { 434 switch (type) { 435 case PM_MODEL_LIMITS_NONE: 436 paramsMinUse = NULL; 437 paramsMaxUse = NULL; 438 limitsApply = true; 439 break; 440 case PM_MODEL_LIMITS_IGNORE: 441 paramsMinUse = NULL; 442 paramsMaxUse = NULL; 443 limitsApply = false; 444 break; 445 case PM_MODEL_LIMITS_LAX: 446 paramsMinUse = paramsMinLax; 447 paramsMaxUse = paramsMaxLax; 448 limitsApply = true; 449 break; 450 case PM_MODEL_LIMITS_MODERATE: 451 paramsMinUse = paramsMinModerate; 452 paramsMaxUse = paramsMaxModerate; 453 limitsApply = true; 454 break; 455 case PM_MODEL_LIMITS_STRICT: 456 paramsMinUse = paramsMinStrict; 457 paramsMaxUse = paramsMaxStrict; 458 limitsApply = true; 459 break; 460 default: 461 psAbort("Unrecognised model limits type: %x", type); 462 } 463 return; 456 464 } 457 465 … … 464 472 # undef PM_MODEL_PARAMS_FROM_PSF 465 473 # undef PM_MODEL_FIT_STATUS 474 # undef PM_MODEL_SET_LIMITS -
branches/simtest_nebulous_branches/psModules/src/objects/models/pmModel_SERSIC.c
r20001 r27840 1 1 /****************************************************************************** 2 2 * this file defines the SERSIC source shape model. Note that these model functions are loaded 3 * by pmModel Group.c using 'include', and thus need no 'include' statements of their own. The3 * by pmModelClass.c using 'include', and thus need no 'include' statements of their own. The 4 4 * models use a psVector to represent the set of parameters, with the sequence used to specify 5 5 * the meaning of the parameter. The meaning of the parameters may thus vary depending on the 6 * specifics of the model. All models which are used a PSF representations share a few6 * specifics of the model. All models which are used as a PSF representations share a few 7 7 * parameters, for which # define names are listed in pmModel.h: 8 8 … … 23 23 *****************************************************************************/ 24 24 25 #include <stdio.h> 26 #include <pslib.h> 27 28 #include "pmMoments.h" 29 #include "pmPeaks.h" 30 #include "pmSource.h" 31 #include "pmModel.h" 32 #include "pmModel_SERSIC.h" 33 25 34 # define PM_MODEL_FUNC pmModelFunc_SERSIC 26 35 # define PM_MODEL_FLUX pmModelFlux_SERSIC … … 31 40 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_SERSIC 32 41 # define PM_MODEL_FIT_STATUS pmModelFitStatus_SERSIC 42 # define PM_MODEL_SET_LIMITS pmModelSetLimits_SERSIC 43 44 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y) 45 // 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords 46 // values need to be pixel coords 47 48 // Lax parameter limits 49 static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.05, 0.05, -1.0, 0.05 }; 50 static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 4.0 }; 51 52 // Moderate parameter limits 53 static float *paramsMinModerate = paramsMinLax; 54 static float *paramsMaxModerate = paramsMaxLax; 55 56 // Strict parameter limits 57 static float *paramsMinStrict = paramsMinLax; 58 static float *paramsMaxStrict = paramsMaxLax; 59 60 // Parameter limits to use 61 static float *paramsMinUse = paramsMinLax; 62 static float *paramsMaxUse = paramsMaxLax; 63 static float betaUse[] = { 1000, 3e6, 5, 5, 1.0, 1.0, 0.5, 2.0 }; 64 65 static bool limitsApply = true; // Apply limits? 33 66 34 67 psF32 PM_MODEL_FUNC (psVector *deriv, … … 91 124 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta) 92 125 { 93 float beta_lim = 0, params_min = 0, params_max = 0; 94 float f1 = 0, f2 = 0, q1 = 0, q2 = 0; 126 if (!limitsApply) { 127 return true; 128 } 129 psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds"); 95 130 96 131 // we need to calculate the limits for SXY specially 132 float q2 = NAN; 97 133 if (nParam == PM_PAR_SXY) { 98 f 1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);99 f 2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);100 q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);134 float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]); 135 float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]); 136 float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2); 101 137 q1 = (q1 < 0.0) ? 0.0 : q1; 102 138 // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg.. Saturate at that 103 139 // angle and let f2,f1 fight it out 104 q2 = 0.5*sqrt(q1);140 q2 = 0.5*sqrtf(q1); 105 141 } 106 142 107 143 switch (mode) { 108 case PS_MINIMIZE_BETA_LIMIT: 109 switch (nParam) { 110 case PM_PAR_SKY: 111 beta_lim = 1000; 112 break; 113 case PM_PAR_I0: 114 beta_lim = 3e6; 115 break; 116 case PM_PAR_XPOS: 117 beta_lim = 5; 118 break; 119 case PM_PAR_YPOS: 120 beta_lim = 5; 121 break; 122 case PM_PAR_SXX: 123 beta_lim = 1.0; 124 break; 125 case PM_PAR_SYY: 126 beta_lim = 1.0; 127 break; 128 case PM_PAR_SXY: 129 beta_lim = 0.5*q2; 130 break; 131 case PM_PAR_7: 132 beta_lim = 2.0; 133 break; 134 default: 135 psAbort("invalid parameter %d for beta test", nParam); 136 } 137 if (fabs(beta[nParam]) > fabs(beta_lim)) { 138 beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim); 139 psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 140 nParam, beta[nParam], beta_lim); 141 return false; 142 } 143 return true; 144 case PS_MINIMIZE_PARAM_MIN: 145 switch (nParam) { 146 case PM_PAR_SKY: 147 params_min = -1000; 148 break; 149 case PM_PAR_I0: 150 params_min = 0.01; 151 break; 152 case PM_PAR_XPOS: 153 params_min = -100; 154 break; 155 case PM_PAR_YPOS: 156 params_min = -100; 157 break; 158 case PM_PAR_SXX: 159 params_min = 0.05; 160 break; 161 case PM_PAR_SYY: 162 params_min = 0.05; 163 break; 164 case PM_PAR_SXY: 165 params_min = -q2; 166 break; 167 case PM_PAR_7: 168 params_min = 0.05; 169 break; 170 default: 171 psAbort("invalid parameter %d for param min test", nParam); 172 } 173 if (params[nParam] < params_min) { 174 params[nParam] = params_min; 175 psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 176 nParam, params[nParam], params_min); 177 return false; 178 } 179 return true; 180 case PS_MINIMIZE_PARAM_MAX: 181 switch (nParam) { 182 case PM_PAR_SKY: 183 params_max = 1e5; 184 break; 185 case PM_PAR_I0: 186 params_max = 1e8; 187 break; 188 case PM_PAR_XPOS: 189 params_max = 1e4; 190 break; 191 case PM_PAR_YPOS: 192 params_max = 1e4; 193 break; 194 case PM_PAR_SXX: 195 params_max = 100; 196 break; 197 case PM_PAR_SYY: 198 params_max = 100; 199 break; 200 case PM_PAR_SXY: 201 params_max = +q2; 202 break; 203 case PM_PAR_7: 204 params_max = 4.0; 205 break; 206 default: 207 psAbort("invalid parameter %d for param max test", nParam); 208 } 209 if (params[nParam] > params_max) { 210 params[nParam] = params_max; 211 psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 212 nParam, params[nParam], params_max); 213 return false; 214 } 215 return true; 216 default: 144 case PS_MINIMIZE_BETA_LIMIT: { 145 psAssert(beta, "Require beta to limit beta"); 146 float limit = betaUse[nParam]; 147 if (nParam == PM_PAR_SXY) { 148 limit *= q2; 149 } 150 if (fabs(beta[nParam]) > fabs(limit)) { 151 beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit); 152 psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g", 153 nParam, beta[nParam], limit); 154 return false; 155 } 156 return true; 157 } 158 case PS_MINIMIZE_PARAM_MIN: { 159 psAssert(params, "Require parameters to limit parameters"); 160 psAssert(paramsMinUse, "Require parameter limits to limit parameters"); 161 float limit = paramsMinUse[nParam]; 162 if (nParam == PM_PAR_SXY) { 163 limit *= q2; 164 } 165 if (params[nParam] < limit) { 166 params[nParam] = limit; 167 psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g", 168 nParam, params[nParam], limit); 169 return false; 170 } 171 return true; 172 } 173 case PS_MINIMIZE_PARAM_MAX: { 174 psAssert(params, "Require parameters to limit parameters"); 175 psAssert(paramsMaxUse, "Require parameter limits to limit parameters"); 176 float limit = paramsMaxUse[nParam]; 177 if (nParam == PM_PAR_SXY) { 178 limit *= q2; 179 } 180 if (params[nParam] > limit) { 181 params[nParam] = limit; 182 psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g", 183 nParam, params[nParam], limit); 184 return false; 185 } 186 return true; 187 } 188 default: 217 189 psAbort("invalid choice for limits"); 218 190 } … … 221 193 } 222 194 223 224 195 // make an initial guess for parameters 196 // 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters 225 197 bool PM_MODEL_GUESS (pmModel *model, pmSource *source) 226 198 { … … 247 219 if (!isfinite(shape.sxy)) return false; 248 220 249 // XXX PAR[PM_PAR_SKY] = moments->Sky;250 221 PAR[PM_PAR_SKY] = 0.0; 251 222 PAR[PM_PAR_I0] = peak->flux; … … 321 292 322 293 psF64 z = pow (-log(limit), (1.0 / PAR[PM_PAR_7])); 294 psAssert (isfinite(z), "fix this code: z should not be nan for %f", PAR[PM_PAR_7]); 323 295 324 296 psF64 radius = sigma * sqrt (2.0 * z); 297 psAssert (isfinite(radius), "fix this code: radius should not be nan for %f, %f", PAR[PM_PAR_7], sigma); 325 298 326 299 if (isnan(radius)) … … 429 402 bool PM_MODEL_FIT_STATUS (pmModel *model) 430 403 { 431 432 psF32 dP;433 404 bool status; 434 405 … … 436 407 psF32 *dPAR = model->dparams->data.F32; 437 408 438 dP = 0;439 dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);440 dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);441 dP = sqrt (dP);442 443 409 status = true; 444 // status &= (dP < 0.5);445 410 status &= (PAR[PM_PAR_I0] > 0); 446 411 status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5); 447 412 448 fprintf (stderr, "SERSIC status pars: dP: %f, I0: %f, S/N: %f\n",449 dP, PAR[PM_PAR_I0], (dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]));450 451 413 return status; 414 } 415 416 417 void PM_MODEL_SET_LIMITS(pmModelLimitsType type) 418 { 419 switch (type) { 420 case PM_MODEL_LIMITS_NONE: 421 paramsMinUse = NULL; 422 paramsMaxUse = NULL; 423 limitsApply = true; 424 break; 425 case PM_MODEL_LIMITS_IGNORE: 426 paramsMinUse = NULL; 427 paramsMaxUse = NULL; 428 limitsApply = false; 429 break; 430 case PM_MODEL_LIMITS_LAX: 431 paramsMinUse = paramsMinLax; 432 paramsMaxUse = paramsMaxLax; 433 limitsApply = true; 434 break; 435 case PM_MODEL_LIMITS_MODERATE: 436 paramsMinUse = paramsMinModerate; 437 paramsMaxUse = paramsMaxModerate; 438 limitsApply = true; 439 break; 440 case PM_MODEL_LIMITS_STRICT: 441 paramsMinUse = paramsMinStrict; 442 paramsMaxUse = paramsMaxStrict; 443 limitsApply = true; 444 break; 445 default: 446 psAbort("Unrecognised model limits type: %x", type); 447 } 448 return; 452 449 } 453 450 … … 460 457 # undef PM_MODEL_PARAMS_FROM_PSF 461 458 # undef PM_MODEL_FIT_STATUS 459 # undef PM_MODEL_SET_LIMITS -
branches/simtest_nebulous_branches/psModules/src/objects/pmDetections.c
r23487 r27840 26 26 psFree (detections->peaks); 27 27 psFree (detections->oldPeaks); 28 psFree (detections->oldFootprints); 29 30 psFree (detections->newSources); 31 psFree (detections->allSources); 28 32 return; 29 33 } … … 35 39 psMemSetDeallocator(detections, (psFreeFunc) pmDetectionsFree); 36 40 37 detections->footprints = NULL; 38 detections->peaks = NULL; 39 detections->oldPeaks = NULL; 40 detections->last = 0; 41 detections->footprints = NULL; 42 detections->peaks = NULL; 43 detections->oldPeaks = NULL; 44 detections->oldFootprints = NULL; 45 detections->newSources = NULL; 46 detections->allSources = NULL; 47 detections->last = 0; 41 48 42 49 return (detections); -
branches/simtest_nebulous_branches/psModules/src/objects/pmDetections.h
r23487 r27840 21 21 typedef struct { 22 22 psArray *footprints; // collection of footprints in the image 23 psArray *oldFootprints; // collection of footprints previously found 23 24 psArray *peaks; // collection of all peaks contained by the footprints 24 25 psArray *oldPeaks; // collection of all peaks previously found 26 psArray *newSources; // collection of sources 27 psArray *allSources; // collection of sources 25 28 int last; 26 29 } pmDetections; -
branches/simtest_nebulous_branches/psModules/src/objects/pmFootprint.c
r23187 r27840 53 53 assert(nspan >= 0); 54 54 footprint->npix = 0; 55 footprint->nspans = 0; // we may allocate more spans than we set -- this is the number of active spans 55 56 footprint->spans = psArrayAllocEmpty(nspan); 56 57 footprint->peaks = psArrayAlloc(0); … … 73 74 } 74 75 76 bool pmFootprintAllocEmptySpans (pmFootprint *footprint, int nSpans) { 77 78 psArrayRealloc (footprint->spans, nSpans); 79 for (int i = 0; i < nSpans; i++) { 80 footprint->spans->data[i] = pmSpanAlloc(-1, -1, -1); 81 } 82 footprint->spans->n = nSpans; 83 return true; 84 } 85 86 // reset the footprint containers 87 bool pmFootprintInit(pmFootprint *footprint) { 88 89 footprint->bbox.x0 = footprint->bbox.y0 = 0; 90 footprint->bbox.x1 = footprint->bbox.y1 = -1; 91 footprint->nspans = 0; 92 return true; 93 } 94 75 95 bool pmFootprintTest(const psPtr ptr) { 76 96 return (psMemGetDeallocator(ptr) == (psFreeFunc)footprintFree); … … 103 123 psArrayAdd(fp->spans, 1, sp); 104 124 psFree(sp); 105 125 126 fp->nspans ++; 127 106 128 fp->npix += x1 - x0 + 1; 107 129 108 if (fp-> spans->n== 1) {130 if (fp->nspans == 1) { 109 131 fp->bbox.x0 = x0; 110 132 fp->bbox.x1 = x1; … … 121 143 } 122 144 145 146 // Set the next available elements of the nSpan entry in footprint->spans 147 pmSpan *pmFootprintSetSpan(pmFootprint *fp, // the footprint to add to 148 const int y, // row to add 149 int x0, // range of 150 int x1) { // columns 151 152 if (x1 < x0) { 153 int tmp = x0; 154 x0 = x1; 155 x1 = tmp; 156 } 157 158 int N = fp->nspans; 159 if (N == fp->spans->n) { 160 // if we need more space, extend fp->spans as needed 161 int Nalloc = fp->spans->n + 100; 162 psArrayRealloc(fp->spans, Nalloc); 163 fp->spans->n = Nalloc; 164 for (int i = N; i < fp->spans->n; i++) { 165 fp->spans->data[i] = pmSpanAlloc(-1, -1, -1); 166 } 167 } 168 169 pmSpan *span = fp->spans->data[N]; 170 span->y = y; 171 span->x0 = x0; 172 span->x1 = x1; 173 174 fp->nspans ++; 175 176 fp->npix += x1 - x0 + 1; 177 178 if (fp->nspans == 1) { 179 fp->bbox.x0 = x0; 180 fp->bbox.x1 = x1; 181 fp->bbox.y0 = y; 182 fp->bbox.y1 = y; 183 } else { 184 if (x0 < fp->bbox.x0) fp->bbox.x0 = x0; 185 if (x1 > fp->bbox.x1) fp->bbox.x1 = x1; 186 if (y < fp->bbox.y0) fp->bbox.y0 = y; 187 if (y > fp->bbox.y1) fp->bbox.y1 = y; 188 } 189 190 return span; 191 } 192 123 193 void pmFootprintSetBBox(pmFootprint *fp) { 124 194 assert (fp != NULL); 125 if (fp-> spans->n== 0) {195 if (fp->nspans == 0) { 126 196 return; 127 197 } … … 132 202 int y1 = sp->y; 133 203 134 for (int i = 1; i < fp-> spans->n; i++) {204 for (int i = 1; i < fp->nspans; i++) { 135 205 sp = fp->spans->data[i]; 136 206 … … 150 220 assert (fp != NULL); 151 221 int npix = 0; 152 for (int i = 0; i < fp-> spans->n; i++) {222 for (int i = 0; i < fp->nspans; i++) { 153 223 pmSpan *span = fp->spans->data[i]; 154 224 npix += span->x1 - span->x0 + 1; -
branches/simtest_nebulous_branches/psModules/src/objects/pmFootprint.h
r24875 r27840 13 13 #include <pslib.h> 14 14 #include "pmSpan.h" 15 15 #include "pmFootprintSpans.h" 16 16 17 17 typedef struct { 18 18 const int id; //!< unique ID 19 19 int npix; //!< number of pixels in this pmFootprint 20 psArray *spans; //!< the pmSpans 20 int nspans; 21 psArray *spans; //!< the allocated pmSpans 21 22 psRegion bbox; //!< the pmFootprint's bounding box 22 23 psArray *peaks; //!< the peaks lying in this footprint … … 26 27 27 28 pmFootprint *pmFootprintAlloc(int nspan, const psImage *img); 29 bool pmFootprintInit(pmFootprint *footprint); 28 30 bool pmFootprintTest(const psPtr ptr); 31 32 bool pmFootprintAllocEmptySpans (pmFootprint *footprint, int nSpans); 29 33 30 34 pmFootprint *pmFootprintNormalize(pmFootprint *fp); … … 37 41 int x1); // columns 38 42 43 pmSpan *pmFootprintSetSpan(pmFootprint *fp, // the footprint to add to 44 const int y, // row to add 45 int x0, // range of 46 int x1); // columns 47 39 48 psArray *pmFootprintsFind(const psImage *img, const float threshold, const int npixMin); 40 pmFootprint *pmFootprintsFindAtPoint(const psImage *img, 41 const float threshold, 42 const psArray *peaks, 43 int row, int col); 49 50 bool pmFootprintsFindAtPoint(pmFootprint *fp, 51 pmFootprintSpans *fpSpans, 52 const psImage *img, // image to search 53 psImage *mask, 54 const float threshold, // Threshold 55 const psArray *peaks, // array of peaks; finding one terminates search for footprint 56 int row, int col); 57 58 // pmFootprint *pmFootprintsFindAtPoint(const psImage *img, 59 // const float threshold, 60 // const psArray *peaks, 61 // int row, int col); 62 63 bool pmFootprintSpansBuild(pmFootprint *fp, // the footprint that we're building 64 pmFootprintSpans *fpSpans, 65 const psImage *img, // the psImage we're working on 66 psImage *mask, // the associated masks 67 const float threshold // Threshold 68 ); 44 69 45 70 psArray *pmFootprintArrayGrow(const psArray *footprints, int r); -
branches/simtest_nebulous_branches/psModules/src/objects/pmFootprintCullPeaks.c
r24888 r27840 20 20 #include "pmSpan.h" 21 21 #include "pmFootprint.h" 22 #include "pmFootprintSpans.h" 22 23 #include "pmPeaks.h" 24 25 bool dumpfootprints (pmFootprint *fp, pmFootprintSpans *fpSp); 23 26 24 27 /* … … 29 32 */ 30 33 31 # define IN_PEAK 1 34 # define IN_PEAK 1 32 35 psErrorCode pmFootprintCullPeaks(const psImage *img, // the image wherein lives the footprint 33 const psImage *weight,// corresponding variance image34 pmFootprint *fp, // Footprint containing mortal peaks35 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive36 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance37 const float min_threshold) { // minimum permitted coll height36 const psImage *weight, // corresponding variance image 37 pmFootprint *fp, // Footprint containing mortal peaks 38 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive 39 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance 40 const float min_threshold) { // minimum permitted coll height 38 41 assert (img != NULL); assert (img->type.type == PS_TYPE_F32); 39 42 assert (weight != NULL); assert (weight->type.type == PS_TYPE_F32); … … 42 45 43 46 if (fp->peaks == NULL || fp->peaks->n == 0) { // nothing to do 44 return PS_ERR_NONE;47 return PS_ERR_NONE; 45 48 } 46 49 47 psRegion subRegion; // desired subregion; 1 larger than bounding box (grr)50 psRegion subRegion; // desired subregion; 1 larger than bounding box (grr) 48 51 subRegion.x0 = fp->bbox.x0; subRegion.x1 = fp->bbox.x1 + 1; 49 52 subRegion.y0 = fp->bbox.y0; subRegion.y1 = fp->bbox.y1 + 1; … … 55 58 psImage *idImg = psImageAlloc(subImg->numCols, subImg->numRows, PS_TYPE_S32); 56 59 57 // We need a psArray of peaks brighter than the current peak. 60 // We need a psArray of peaks brighter than the current peak. 58 61 // We reject peaks which either: 59 62 // 1) are below the local threshold … … 65 68 psArrayAdd (brightPeaks, 128, fp->peaks->data[0]); 66 69 70 // allocate the peakFootprint and peakFPSpans containers -- these are re-used by pmFootprintsFindAtPoint to minimize allocs in this function 71 pmFootprint *peakFootprint = pmFootprintAlloc(fp->nspans, subImg); 72 pmFootprintSpans *peakFPSpans = pmFootprintSpansAlloc(2*fp->nspans); 73 74 // allocate empty spans for the footprints 75 pmFootprintAllocEmptySpans(peakFootprint, fp->nspans); 76 77 psImage *subMask = psImageCopy(NULL, subImg, PS_TYPE_IMAGE_MASK); 78 67 79 // The brightest peak is always safe; go through other peaks trying to cull them 68 80 for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop 69 const pmPeak *peak = fp->peaks->data[i];70 int x = peak->x - subImg->col0;71 int y = peak->y - subImg->row0;72 //73 // Find the level nsigma below the peak that must separate the peak74 // from any of its friends75 //76 assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows);81 const pmPeak *peak = fp->peaks->data[i]; 82 int x = peak->x - subImg->col0; 83 int y = peak->y - subImg->row0; 84 // 85 // Find the level nsigma below the peak that must separate the peak 86 // from any of its friends 87 // 88 assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows); 77 89 78 // const float stdev = sqrt(subWt->data.F32[y][x]);79 // float threshold = subImg->data.F32[y][x] - nsigma_delta*stdev;90 // const float stdev = sqrt(subWt->data.F32[y][x]); 91 // float threshold = subImg->data.F32[y][x] - nsigma_delta*stdev; 80 92 81 const float stdev = sqrt(subWt->data.F32[y][x]);82 const float flux = subImg->data.F32[y][x];83 const float fStdev = fabs(stdev/flux);84 const float stdev_pad = fabs(flux * hypot(fStdev, fPadding));85 // if flux is negative, careful with fStdev93 const float stdev = sqrt(subWt->data.F32[y][x]); 94 const float flux = subImg->data.F32[y][x]; 95 const float fStdev = fabs(stdev/flux); 96 const float stdev_pad = fabs(flux * hypot(fStdev, fPadding)); 97 // if flux is negative, careful with fStdev 86 98 87 float threshold = flux - nsigma_delta*stdev_pad; 88 89 if (isnan(threshold) || threshold < min_threshold) { 90 // min_threshold is assumed to be below the detection threshold, 91 // so all the peaks are pmFootprint, and this isn't the brightest 99 float threshold = flux - nsigma_delta*stdev_pad; 100 101 if (isnan(threshold) || threshold < min_threshold) { 102 // min_threshold is assumed to be below the detection threshold, 103 // so all the peaks are pmFootprint, and this isn't the brightest 104 continue; 105 } 106 107 // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true? 108 if (threshold > subImg->data.F32[y][x]) { 109 threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON; 110 } 111 112 // init peakFootprint here? 113 pmFootprintsFindAtPoint(peakFootprint, peakFPSpans, subImg, subMask, threshold, brightPeaks, peak->y, peak->x); 114 if (peakFPSpans->nStartSpans > 2000) { 115 // dumpfootprints(peakFootprint, peakFPSpans); 116 // fprintf (stderr, "big footprint %d : %d\n", peakFootprint->nspans, peakFPSpans->nStartSpans); 117 fprintf (stderr, "big test footprint: %f %f to %f %f (%d pix)\n", peakFootprint->bbox.x0, peakFootprint->bbox.y0, peakFootprint->bbox.x1, peakFootprint->bbox.y1, peakFootprint->npix); 118 } 119 120 // at this point brightPeaks only has the peaks brighter than the current 121 122 // we set the IDs to either 1 (in peak) or 0 (not in peak) 123 pmSetFootprintID (idImg, peakFootprint, IN_PEAK); 124 125 // If this peak has not already been assigned to a source, then we can look for any 126 // brighter peaks within its footprint. Check if any of the previous (brighter) peaks 127 // are within the footprint of this peak If so, the current peak is bogus; drop it. 128 bool keep = true; 129 for (int j = 0; keep && !peak->assigned && (j < brightPeaks->n); j++) { 130 const pmPeak *peak2 = fp->peaks->data[j]; 131 int x2 = peak2->x - subImg->col0; 132 int y2 = peak2->y - subImg->row0; 133 if (idImg->data.S32[y2][x2] == IN_PEAK) { 134 // There's a brighter peak within the footprint above threshold; so cull our initial peak 135 keep = false; 136 } 137 } 138 if (!keep) { 139 psAssert (!peak->assigned, "logic error: trying to drop a previously-assigned peak"); // we should not drop any already assigned peaks. 92 140 continue; 93 141 } 94 142 95 // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true? 96 if (threshold > subImg->data.F32[y][x]) { 97 threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON; 98 } 99 100 // XXX this is a bit expensive: psImageAlloc for every peak contained in this footprint 101 // perhaps this should alloc a single ID image above and pass it in to be set. 102 103 // XXX optionally use the faster pmFootprintsFind if the subimage size is large (eg, M31) 104 105 // XXX this is not quite there yet: 106 // pmFootprint *peakFootprint = NULL; 107 // int area = subImg->numCols * subImg->numRows; 108 // if (area > 30000) { 109 110 pmFootprint *peakFootprint = pmFootprintsFindAtPoint(subImg, threshold, brightPeaks, peak->y, peak->x); 111 112 // at this point brightPeaks only has the peaks brighter than the current 113 114 // XXX need to supply the image here 115 // we set the IDs to either 1 (in peak) or 0 (not in peak) 116 pmSetFootprintID (idImg, peakFootprint, IN_PEAK); 117 psFree(peakFootprint); 118 119 // Check if any of the previous (brighter) peaks are within the footprint of this peak 120 // If so, the current peak is bogus; drop it. 121 bool keep = true; 122 for (int j = 0; keep && (j < brightPeaks->n); j++) { 123 const pmPeak *peak2 = fp->peaks->data[j]; 124 int x2 = peak2->x - subImg->col0; 125 int y2 = peak2->y - subImg->row0; 126 if (idImg->data.S32[y2][x2] == IN_PEAK) 127 // There's a brighter peak within the footprint above threshold; so cull our initial peak 128 keep = false; 129 } 130 if (!keep) continue; 131 132 psArrayAdd (brightPeaks, 128, fp->peaks->data[i]); 143 psArrayAdd (brightPeaks, 128, fp->peaks->data[i]); 133 144 } 134 145 … … 139 150 psFree(subImg); 140 151 psFree(subWt); 152 psFree(subMask); 153 psFree(peakFootprint); 154 psFree(peakFPSpans); 141 155 142 156 return PS_ERR_NONE; … … 144 158 145 159 146 /* 147 * Examine the peaks in a pmFootprint, and throw away the ones that are not sufficiently 148 * isolated. More precisely, for each peak find the highest coll that you'd have to traverse 149 * to reach a still higher peak --- and if that coll's more than nsigma DN below your 150 * starting point, discard the peak. 151 */ 152 psErrorCode pmFootprintCullPeaks_OLD(const psImage *img, // the image wherein lives the footprint 153 const psImage *weight, // corresponding variance image 154 pmFootprint *fp, // Footprint containing mortal peaks 155 const float nsigma_delta, // how many sigma above local background a peak needs to be to survive 156 const float fPadding, // fractional padding added to stdev since bright peaks have unreasonably high significance 157 const float min_threshold) { // minimum permitted coll height 158 assert (img != NULL); assert (img->type.type == PS_TYPE_F32); 159 assert (weight != NULL); assert (weight->type.type == PS_TYPE_F32); 160 assert (img->row0 == weight->row0 && img->col0 == weight->col0); 161 assert (fp != NULL); 160 bool dumpfootprints (pmFootprint *fp, pmFootprintSpans *fpSp) { 162 161 163 if (fp->peaks == NULL || fp->peaks->n == 0) { // nothing to do 164 return PS_ERR_NONE; 162 FILE *f1 = fopen ("fp.dat", "w"); 163 if (!f1) return false; 164 165 for (int i = 0; i < fp->nspans; i++) { 166 pmSpan *sp = fp->spans->data[i]; 167 fprintf (f1, "%d - %d : %d\n", sp->x0, sp->x1, sp->y); 165 168 } 169 fclose (f1); 166 170 167 psRegion subRegion; // desired subregion; 1 larger than bounding box (grr) 168 subRegion.x0 = fp->bbox.x0; subRegion.x1 = fp->bbox.x1 + 1; 169 subRegion.y0 = fp->bbox.y0; subRegion.y1 = fp->bbox.y1 + 1; 170 const psImage *subImg = psImageSubset((psImage *)img, subRegion); 171 const psImage *subWt = psImageSubset((psImage *)weight, subRegion); 172 assert (subImg != NULL && subWt != NULL); 173 // 174 // We need a psArray of peaks brighter than the current peak. We'll fake this 175 // by reusing the fp->peaks but lying about n. 176 // 177 // We do this for efficiency (otherwise I'd need two peaks lists), and we are 178 // rather too chummy with psArray in consequence. But it works. 179 // 180 psArray *brightPeaks = psArrayAlloc(0); 181 psFree(brightPeaks->data); 182 brightPeaks->data = psMemIncrRefCounter(fp->peaks->data);// use the data from fp->peaks 183 // 184 // The brightest peak is always safe; go through other peaks trying to cull them 185 // 186 for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop 187 const pmPeak *peak = fp->peaks->data[i]; 188 int x = peak->x - subImg->col0; 189 int y = peak->y - subImg->row0; 190 // 191 // Find the level nsigma below the peak that must separate the peak 192 // from any of its friends 193 // 194 assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows); 171 FILE *f2 = fopen ("fpSp.dat", "w"); 172 if (!f2) return false; 195 173 196 // stdev ~ sqrt(flux) : for bright regions (f ~ 1e6, sqrt(f) = 1e3 -- unrealistically small deviations) 197 // add additional padding in quadrature: 198 199 const float stdev = sqrt(subWt->data.F32[y][x]); 200 const float flux = subImg->data.F32[y][x]; 201 const float fStdev = stdev/flux; 202 const float stdev_pad = flux * hypot(fStdev, fPadding); 203 float threshold = flux - nsigma_delta*stdev_pad; 204 205 if (isnan(threshold) || threshold < min_threshold) { 206 #if 1 // min_threshold is assumed to be below the detection threshold, 207 // so all the peaks are pmFootprint, and this isn't the brightest 208 // XXX mark peak to be dropped 209 (void)psArrayRemoveIndex(fp->peaks, i); 210 i--; // we moved everything down one 211 continue; 212 #else 213 #error n.b. We will be running LOTS of checks at this threshold, so only find the footprint once 214 threshold = min_threshold; 215 #endif 216 } 217 218 // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true? 219 if (threshold > subImg->data.F32[y][x]) { 220 threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON; 221 } 222 223 // XXX this is a bit expensive: psImageAlloc for every peak contained in this footprint 224 // perhaps this should alloc a single ID image above and pass it in to be set. 225 226 const int peak_id = 1; // the ID for the peak of interest 227 brightPeaks->n = i; // only stop at a peak brighter than we are 228 229 // XXX optionally use the faster pmFootprintsFind if the subimage size is large (eg, M31) 230 231 pmFootprint *peakFootprint = pmFootprintsFindAtPoint(subImg, threshold, brightPeaks, peak->y, peak->x); 232 brightPeaks->n = 0; // don't double free 233 psImage *idImg = pmSetFootprintID(NULL, peakFootprint, peak_id); 234 psFree(peakFootprint); 235 236 // Check if any of the previous (brighter) peaks are within the footprint of this peak 237 // If so, the current peak is bogus; drop it. 238 int j; 239 for (j = 0; j < i; j++) { 240 const pmPeak *peak2 = fp->peaks->data[j]; 241 int x2 = peak2->x - subImg->col0; 242 int y2 = peak2->y - subImg->row0; 243 const int peak2_id = idImg->data.S32[y2][x2]; // the ID for some other peak 244 245 if (peak2_id == peak_id) { // There's a brighter peak within the footprint above 246 ; // threshold; so cull our initial peak 247 (void)psArrayRemoveIndex(fp->peaks, i); 248 i--; // we moved everything down one 249 break; 250 } 251 } 252 if (j == i) { 253 j++; 254 } 255 256 psFree(idImg); 174 for (int i = 0; i < fpSp->nStartSpans; i++) { 175 pmStartSpan *sp = fpSp->startspans->data[i]; 176 if (!sp->span) continue; 177 fprintf (f2, "%d - %d : %d\n", sp->span->x0, sp->span->x1, sp->span->y); 257 178 } 258 259 brightPeaks->n = 0; psFree(brightPeaks); 260 psFree((psImage *)subImg); 261 psFree((psImage *)subWt); 262 263 return PS_ERR_NONE; 179 fclose (f2); 180 return true; 264 181 } 265 -
branches/simtest_nebulous_branches/psModules/src/objects/pmFootprintFindAtPoint.c
r21183 r27840 21 21 #include "pmFootprint.h" 22 22 #include "pmPeaks.h" 23 24 /* 25 * A data structure to hold the starting point for a search for pixels above threshold, 26 * used by pmFootprintsFindAtPoint 27 * 28 * We don't want to find this span again --- it's already part of the footprint --- 29 * so we set appropriate mask bits 30 * 31 * EAM : these function were confusingly using "startspan" and "spartspan" 32 * I've rationalized them all to 'startspan' 33 */ 34 35 // 36 // An enum for what we should do with a Startspan 37 // 38 typedef enum {PM_SSPAN_DOWN = 0, // scan down from this span 39 PM_SSPAN_UP, // scan up from this span 40 PM_SSPAN_RESTART, // restart scanning from this span 41 PM_SSPAN_DONE // this span is processed 42 } PM_SSPAN_DIR; // How to continue searching 43 // 44 // An enum for mask's pixel values. We're looking for pixels that are above threshold, and 45 // we keep extra book-keeping information in the PM_SSPAN_STOP plane. It's simpler to be 46 // able to check for 47 // 48 enum { 49 PM_SSPAN_INITIAL = 0x0, // initial state of pixels. 50 PM_SSPAN_DETECTED = 0x1, // we've seen this pixel 51 PM_SSPAN_STOP = 0x2 // you may stop searching when you see this pixel 52 }; 53 // 54 // The struct that remembers how to [re-]start scanning the image for pixels 55 // 56 typedef struct { 57 const pmSpan *span; // save the pixel range 58 PM_SSPAN_DIR direction; // How to continue searching 59 bool stop; // should we stop searching? 60 } Startspan; 61 62 static void startspanFree(Startspan *sspan) { 63 psFree((void *)sspan->span); 64 } 65 66 static Startspan * 67 StartspanAlloc(const pmSpan *span, // The span in question 68 psImage *mask, // Pixels that we've already detected 69 const PM_SSPAN_DIR dir // Should we continue searching towards the top of the image? 70 ) { 71 Startspan *sspan = psAlloc(sizeof(Startspan)); 72 psMemSetDeallocator(sspan, (psFreeFunc)startspanFree); 73 74 sspan->span = psMemIncrRefCounter((void *)span); 75 sspan->direction = dir; 76 sspan->stop = false; 77 78 if (mask != NULL) { // remember that we've detected these pixels 79 psImageMaskType *mpix = &mask->data.PS_TYPE_IMAGE_MASK_DATA[span->y - mask->row0][span->x0 - mask->col0]; 80 81 for (int i = 0; i <= span->x1 - span->x0; i++) { 82 mpix[i] |= PM_SSPAN_DETECTED; 83 if (mpix[i] & PM_SSPAN_STOP) { 84 sspan->stop = true; 85 } 86 } 87 } 88 89 return sspan; 90 } 91 92 // 93 // Add a new Startspan to an array of Startspans. Iff we see a stop bit, return true 94 // 95 static bool add_startspan(psArray *startspans, // the saved Startspans 96 const pmSpan *sp, // the span in question 97 psImage *mask, // mask of detected/stop pixels 98 const PM_SSPAN_DIR dir) { // the desired direction to search 99 if (dir == PM_SSPAN_RESTART) { 100 if (add_startspan(startspans, sp, mask, PM_SSPAN_UP) || 101 add_startspan(startspans, sp, NULL, PM_SSPAN_DOWN)) { 102 return true; 103 } 104 } else { 105 Startspan *sspan = StartspanAlloc(sp, mask, dir); 106 if (sspan->stop) { // we detected a stop bit 107 psFree(sspan); // don't allocate new span 108 109 return true; 110 } else { 111 psArrayAdd(startspans, 1, sspan); 112 psFree(sspan); // as it's now owned by startspans 113 } 114 } 115 116 return false; 117 } 23 #include "pmFootprintSpans.h" 118 24 119 25 /************************************************************************************************************/ 120 26 /* 121 * Search the image for pixels above threshold, starting at a single Startspan.27 * Search the image for pixels above threshold, starting at a single pmStartSpan. 122 28 * We search the array looking for one to process; it'd be better to move the 123 29 * ones that we're done with to the end, but it probably isn't worth it for … … 126 32 * This is the guts of pmFootprintsFindAtPoint 127 33 */ 128 static bool do_startspan(pmFootprint *fp, // the footprint that we're building 129 const psImage *img, // the psImage we're working on 130 psImage *mask, // the associated masks 131 const float threshold, // Threshold 132 psArray *startspans) { // specify which span to process next 133 bool F32 = false; // is this an F32 image? 34 bool pmFootprintSpansBuild(pmFootprint *fp, // the footprint that we're building 35 pmFootprintSpans *fpSpans, 36 const psImage *img, // the psImage we're working on 37 psImage *mask, // the associated masks 38 const float threshold // Threshold 39 ) { 40 bool F32 = false; // is this an F32 image? 41 if (img->type.type == PS_TYPE_F32) { 42 F32 = true; 43 } else if (img->type.type == PS_TYPE_S32) { 44 F32 = false; 45 } else { // N.b. You can't trivially add more cases here; F32 is just a bool 46 psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type); 47 return NULL; 48 } 49 50 psF32 *imgRowF32 = NULL; // row pointer if F32 51 psS32 *imgRowS32 = NULL; // " " " " !F32 52 psImageMaskType *maskRow = NULL; // masks's row pointer 53 54 const int row0 = img->row0; 55 const int col0 = img->col0; 56 const int numRows = img->numRows; 57 const int numCols = img->numCols; 58 59 /********************************************************************************************************/ 60 61 pmStartSpan *startspan = NULL; 62 for (int i = 0; i < fpSpans->nStartSpans; i++) { 63 startspan = fpSpans->startspans->data[i]; 64 if (startspan->direction != PM_STARTSPAN_DONE) { 65 break; 66 } 67 if (startspan->stop) { 68 break; 69 } 70 } 71 if (startspan == NULL || startspan->direction == PM_STARTSPAN_DONE) { // no more pmStartSpans to process 72 return false; 73 } 74 if (startspan->stop) { // they don't want any more spans processed 75 return false; 76 } 77 78 /* 79 * Work 80 */ 81 const PM_STARTSPAN_DIR dir = startspan->direction; 82 /* 83 * Set initial span to the startspan 84 */ 85 int x0 = startspan->span->x0 - col0, x1 = startspan->span->x1 - col0; 86 /* 87 * Go through image identifying objects 88 */ 89 int nx0, nx1 = -1; // new values of x0, x1 90 const int di = (dir == PM_STARTSPAN_UP) ? 1 : -1; // how much i changes to get to the next row 91 bool stop = false; // should I stop searching for spans? 92 93 for (int i = startspan->span->y - row0 + di; i < numRows && i >= 0; i += di) { 94 imgRowF32 = img->data.F32[i]; // only one of 95 imgRowS32 = img->data.S32[i]; // these is valid! 96 maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[i]; 97 // 98 // Search left from the pixel diagonally to the left of (i - di, x0). If there's 99 // a connected span there it may need to grow up and/or down, so push it onto 100 // the stack for later consideration 101 // 102 nx0 = -1; 103 for (int j = x0 - 1; j >= -1; j--) { 104 double pixVal = (j < 0) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 105 if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) { 106 if (j < x0 - 1) { // we found some pixels above threshold 107 nx0 = j + 1; 108 } 109 break; 110 } 111 } 112 113 if (nx0 < 0) { // no span to the left 114 nx1 = x0 - 1; // we're going to resume searching at nx1 + 1 115 } else { 116 // 117 // Search right in leftmost span 118 // 119 for (int j = nx0 + 1; j <= numCols; j++) { 120 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 121 if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) { 122 nx1 = j - 1; 123 break; 124 } 125 } 126 127 pmSpan *sp = pmFootprintSetSpan(fp, i + row0, nx0 + col0, nx1 + col0); 128 bool status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_RESTART); 129 // fprintf (stderr, "set 1: %d vs %d\n", fp->nspans, fpSpans->nStartSpans); 130 if (status) { 131 stop = true; 132 break; 133 } 134 } 135 // 136 // Now look for spans connected to the old span. The first of these we'll 137 // simply process, but others will have to be deferred for later consideration. 138 // 139 // In fact, if the span overhangs to the right we'll have to defer the overhang 140 // until later too, as it too can grow in both directions 141 // 142 // Note that column numCols exists virtually, and always ends the last span; this 143 // is why we claim below that sx1 is always set 144 // 145 bool first = false; // is this the first new span detected? 146 for (int j = nx1 + 1; j <= x1 + 1; j++) { 147 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 148 if (!(maskRow[j] & PM_STARTSPAN_DETECTED) && pixVal >= threshold) { 149 int sx0 = j++; // span that we're working on is sx0:sx1 150 int sx1 = -1; // We know that if we got here, we'll also set sx1 151 for (; j <= numCols; j++) { 152 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 153 if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) { // end of span 154 sx1 = j; 155 break; 156 } 157 } 158 assert (sx1 >= 0); 159 160 pmSpan *sp; 161 if (first) { 162 if (sx1 <= x1) { 163 sp = pmFootprintSetSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1); 164 bool status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_DONE); 165 // fprintf (stderr, "set 2: %d vs %d\n", fp->nspans, fpSpans->nStartSpans); 166 if (status) { 167 stop = true; 168 break; 169 } 170 } else { // overhangs to right 171 sp = pmFootprintSetSpan(fp, i + row0, sx0 + col0, x1 + col0); 172 bool status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_DONE); 173 // fprintf (stderr, "set 3: %d vs %d\n", fp->nspans, fpSpans->nStartSpans); 174 if (status) { 175 stop = true; 176 break; 177 } 178 sp = pmFootprintSetSpan(fp, i + row0, x1 + 1 + col0, sx1 + col0 - 1); 179 status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_RESTART); 180 // fprintf (stderr, "set 4: %d vs %d\n", fp->nspans, fpSpans->nStartSpans); 181 if (status) { 182 stop = true; 183 break; 184 } 185 } 186 first = false; 187 } else { 188 sp = pmFootprintSetSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1); 189 bool status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_RESTART); 190 // fprintf (stderr, "set 5: %d vs %d\n", fp->nspans, fpSpans->nStartSpans); 191 if (status) { 192 stop = true; 193 break; 194 } 195 } 196 } 197 } 198 199 if (stop || first == false) { // we're done 200 break; 201 } 202 203 x0 = nx0; x1 = nx1; 204 } 205 /* 206 * Cleanup 207 */ 208 209 startspan->direction = PM_STARTSPAN_DONE; 210 return stop ? false : true; 211 } 212 213 /* 214 * Go through an image, starting at (row, col) and assembling all the pixels 215 * that are connected to that point (in a chess kings-move sort of way) into 216 * a pmFootprint. 217 * 218 * This is much slower than pmFootprintsFind if you want to find lots of 219 * footprints, but if you only want a small region about a given point it 220 * can be much faster 221 * 222 * N.b. The returned pmFootprint is not in "normal form"; that is the pmSpans 223 * are not sorted by increasing y, x0, x1. If this matters to you, call 224 * pmFootprintNormalize() 225 * 226 * The calling function must supply a footprint allocated with a reasonable amount of space 227 * 228 */ 229 230 bool pmFootprintsFindAtPoint(pmFootprint *fp, 231 pmFootprintSpans *fpSpans, 232 const psImage *img, // image to search 233 psImage *mask, 234 const float threshold, // Threshold 235 const psArray *peaks, // array of peaks; finding one terminates search for footprint 236 int row, int col) { // starting position (in img's parent's coordinate system) 237 psAssert(img, "image must be supplied"); 238 psAssert(fp, "footprint must be supplied"); 239 psAssert(fpSpans, "footprint spans must be supplied"); 240 241 bool F32 = false; // is this an F32 image? 134 242 if (img->type.type == PS_TYPE_F32) { 135 243 F32 = true; 136 244 } else if (img->type.type == PS_TYPE_S32) { 137 245 F32 = false; 138 } else { // N.b. You can't trivially add more cases here; F32 is just a bool246 } else { // N.b. You can't trivially add more cases here; F32 is just a bool 139 247 psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type); 140 return NULL; 141 } 142 143 psF32 *imgRowF32 = NULL; // row pointer if F32 144 psS32 *imgRowS32 = NULL; // " " " " !F32 145 psImageMaskType *maskRow = NULL; // masks's row pointer 146 248 return false; 249 } 250 psF32 *imgRowF32 = NULL; // row pointer if F32 251 psS32 *imgRowS32 = NULL; // " " " " !F32 252 147 253 const int row0 = img->row0; 148 254 const int col0 = img->col0; 149 255 const int numRows = img->numRows; 150 256 const int numCols = img->numCols; 151 152 /********************************************************************************************************/ 153 154 Startspan *sspan = NULL; 155 for (int i = 0; i < startspans->n; i++) { 156 sspan = startspans->data[i]; 157 if (sspan->direction != PM_SSPAN_DONE) { 158 break; 257 258 /* 259 * Is point in image, and above threshold? 260 */ 261 row -= row0; col -= col0; 262 if (row < 0 || row >= numRows || 263 col < 0 || col >= numCols) { 264 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 265 "row/col == (%d, %d) are out of bounds [%d--%d, %d--%d]", 266 row + row0, col + col0, row0, row0 + numRows - 1, col0, col0 + numCols - 1); 267 return false; 268 } 269 270 double pixVal = F32 ? img->data.F32[row][col] : img->data.S32[row][col]; 271 if (pixVal < threshold) { 272 return true; 273 } 274 275 /* 276 * We need a mask for two purposes; to indicate which pixels are already detected, 277 * and to store the "stop" pixels --- those that, once reached, should stop us 278 * looking for the rest of the pmFootprint. These are generally set from peaks. 279 */ 280 281 pmFootprintInit(fp); 282 pmFootprintSpansInit(fpSpans); 283 psImageInit(mask, PM_STARTSPAN_INITIAL); 284 285 // fprintf (stderr, "init: %d vs %d\n", fp->nspans, fpSpans->nStartSpans); 286 287 // 288 // Set stop bits from peaks list 289 // 290 assert (peaks == NULL || peaks->n == 0 || psMemCheckPeak(peaks->data[0])); 291 if (peaks != NULL) { 292 for (int i = 0; i < peaks->n; i++) { 293 pmPeak *peak = peaks->data[i]; 294 mask->data.PS_TYPE_IMAGE_MASK_DATA[peak->y - mask->row0][peak->x - mask->col0] |= PM_STARTSPAN_STOP; 159 295 } 160 if (sspan->stop) { 161 break; 162 } 163 } 164 if (sspan == NULL || sspan->direction == PM_SSPAN_DONE) { // no more Startspans to process 165 return false; 166 } 167 if (sspan->stop) { // they don't want any more spans processed 168 return false; 169 } 170 /* 171 * Work 172 */ 173 const PM_SSPAN_DIR dir = sspan->direction; 174 /* 175 * Set initial span to the startspan 176 */ 177 int x0 = sspan->span->x0 - col0, x1 = sspan->span->x1 - col0; 178 /* 179 * Go through image identifying objects 180 */ 181 int nx0, nx1 = -1; // new values of x0, x1 182 const int di = (dir == PM_SSPAN_UP) ? 1 : -1; // how much i changes to get to the next row 183 bool stop = false; // should I stop searching for spans? 184 185 for (int i = sspan->span->y -row0 + di; i < numRows && i >= 0; i += di) { 186 imgRowF32 = img->data.F32[i]; // only one of 187 imgRowS32 = img->data.S32[i]; // these is valid! 188 maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[i]; 189 // 190 // Search left from the pixel diagonally to the left of (i - di, x0). If there's 191 // a connected span there it may need to grow up and/or down, so push it onto 192 // the stack for later consideration 193 // 194 nx0 = -1; 195 for (int j = x0 - 1; j >= -1; j--) { 196 double pixVal = (j < 0) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 197 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { 198 if (j < x0 - 1) { // we found some pixels above threshold 199 nx0 = j + 1; 200 } 296 } 297 298 /* 299 * Find starting span passing through (row, col) 300 */ 301 imgRowF32 = img->data.F32[row]; // only one of 302 imgRowS32 = img->data.S32[row]; // these is valid! 303 psImageMaskType *maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[row]; 304 { 305 int i; 306 for (i = col; i >= 0; i--) { 307 pixVal = F32 ? imgRowF32[i] : imgRowS32[i]; 308 if ((maskRow[i] & PM_STARTSPAN_DETECTED) || pixVal < threshold) { 201 309 break; 202 310 } 203 311 } 204 205 if (nx0 < 0) { // no span to the left 206 nx1 = x0 - 1; // we're going to resume searching at nx1 + 1 207 } else { 208 // 209 // Search right in leftmost span 210 // 211 //nx1 = 0; // make gcc happy 212 for (int j = nx0 + 1; j <= numCols; j++) { 213 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 214 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { 215 nx1 = j - 1; 216 break; 217 } 218 } 219 220 const pmSpan *sp = pmFootprintAddSpan(fp, i + row0, nx0 + col0, nx1 + col0); 221 222 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) { 223 stop = true; 312 int i0 = i; 313 for (i = col; i < numCols; i++) { 314 pixVal = F32 ? imgRowF32[i] : imgRowS32[i]; 315 if ((maskRow[i] & PM_STARTSPAN_DETECTED) || pixVal < threshold) { 224 316 break; 225 317 } 226 318 } 227 // 228 // Now look for spans connected to the old span. The first of these we'll 229 // simply process, but others will have to be deferred for later consideration. 230 // 231 // In fact, if the span overhangs to the right we'll have to defer the overhang 232 // until later too, as it too can grow in both directions 233 // 234 // Note that column numCols exists virtually, and always ends the last span; this 235 // is why we claim below that sx1 is always set 236 // 237 bool first = false; // is this the first new span detected? 238 for (int j = nx1 + 1; j <= x1 + 1; j++) { 239 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 240 if (!(maskRow[j] & PM_SSPAN_DETECTED) && pixVal >= threshold) { 241 int sx0 = j++; // span that we're working on is sx0:sx1 242 int sx1 = -1; // We know that if we got here, we'll also set sx1 243 for (; j <= numCols; j++) { 244 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]); 245 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { // end of span 246 sx1 = j; 247 break; 248 } 249 } 250 assert (sx1 >= 0); 251 252 const pmSpan *sp; 253 if (first) { 254 if (sx1 <= x1) { 255 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1); 256 if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) { 257 stop = true; 258 break; 259 } 260 } else { // overhangs to right 261 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, x1 + col0); 262 if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) { 263 stop = true; 264 break; 265 } 266 sp = pmFootprintAddSpan(fp, i + row0, x1 + 1 + col0, sx1 + col0 - 1); 267 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) { 268 stop = true; 269 break; 270 } 271 } 272 first = false; 273 } else { 274 sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1); 275 if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) { 276 stop = true; 277 break; 278 } 279 } 280 } 281 } 282 283 if (stop || first == false) { // we're done 284 break; 285 } 286 287 x0 = nx0; x1 = nx1; 288 } 319 int i1 = i; 320 pmSpan *sp = pmFootprintSetSpan(fp, row + row0, i0 + col0 + 1, i1 + col0 - 1); 321 pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_RESTART); 322 // fprintf (stderr, "first: %d vs %d\n", fp->nspans, fpSpans->nStartSpans); 323 } 324 /* 325 * Now workout from those pmStartSpans, searching for pixels above threshold 326 */ 327 while (pmFootprintSpansBuild(fp, fpSpans, img, mask, threshold)) continue; 289 328 /* 290 329 * Cleanup 291 330 */ 292 293 sspan->direction = PM_SSPAN_DONE; 294 return stop ? false : true; 331 // psFree(mask); 332 // psFree(startspans); // restores the image pixel 333 334 return fp; // pmFootprint really 295 335 } 296 297 /*298 * Go through an image, starting at (row, col) and assembling all the pixels299 * that are connected to that point (in a chess kings-move sort of way) into300 * a pmFootprint.301 *302 * This is much slower than pmFootprintsFind if you want to find lots of303 * footprints, but if you only want a small region about a given point it304 * can be much faster305 *306 * N.b. The returned pmFootprint is not in "normal form"; that is the pmSpans307 * are not sorted by increasing y, x0, x1. If this matters to you, call308 * pmFootprintNormalize()309 */310 pmFootprint *311 pmFootprintsFindAtPoint(const psImage *img, // image to search312 const float threshold, // Threshold313 const psArray *peaks, // array of peaks; finding one terminates search for footprint314 int row, int col) { // starting position (in img's parent's coordinate system)315 assert(img != NULL);316 317 bool F32 = false; // is this an F32 image?318 if (img->type.type == PS_TYPE_F32) {319 F32 = true;320 } else if (img->type.type == PS_TYPE_S32) {321 F32 = false;322 } else { // N.b. You can't trivially add more cases here; F32 is just a bool323 psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type);324 return NULL;325 }326 psF32 *imgRowF32 = NULL; // row pointer if F32327 psS32 *imgRowS32 = NULL; // " " " " !F32328 329 const int row0 = img->row0;330 const int col0 = img->col0;331 const int numRows = img->numRows;332 const int numCols = img->numCols;333 /*334 * Is point in image, and above threshold?335 */336 row -= row0; col -= col0;337 if (row < 0 || row >= numRows ||338 col < 0 || col >= numCols) {339 psError(PS_ERR_BAD_PARAMETER_VALUE, true,340 "row/col == (%d, %d) are out of bounds [%d--%d, %d--%d]",341 row + row0, col + col0, row0, row0 + numRows - 1, col0, col0 + numCols - 1);342 return NULL;343 }344 345 double pixVal = F32 ? img->data.F32[row][col] : img->data.S32[row][col];346 if (pixVal < threshold) {347 return pmFootprintAlloc(0, img);348 }349 350 pmFootprint *fp = pmFootprintAlloc(1 + img->numRows/10, img);351 /*352 * We need a mask for two purposes; to indicate which pixels are already detected,353 * and to store the "stop" pixels --- those that, once reached, should stop us354 * looking for the rest of the pmFootprint. These are generally set from peaks.355 */356 psImage *mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);357 P_PSIMAGE_SET_ROW0(mask, row0);358 P_PSIMAGE_SET_COL0(mask, col0);359 psImageInit(mask, PM_SSPAN_INITIAL);360 //361 // Set stop bits from peaks list362 //363 assert (peaks == NULL || peaks->n == 0 || psMemCheckPeak(peaks->data[0]));364 if (peaks != NULL) {365 for (int i = 0; i < peaks->n; i++) {366 pmPeak *peak = peaks->data[i];367 mask->data.PS_TYPE_IMAGE_MASK_DATA[peak->y - mask->row0][peak->x - mask->col0] |= PM_SSPAN_STOP;368 }369 }370 /*371 * Find starting span passing through (row, col)372 */373 psArray *startspans = psArrayAllocEmpty(1); // spans where we have to restart the search374 375 imgRowF32 = img->data.F32[row]; // only one of376 imgRowS32 = img->data.S32[row]; // these is valid!377 psImageMaskType *maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[row];378 {379 int i;380 for (i = col; i >= 0; i--) {381 pixVal = F32 ? imgRowF32[i] : imgRowS32[i];382 if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) {383 break;384 }385 }386 int i0 = i;387 for (i = col; i < numCols; i++) {388 pixVal = F32 ? imgRowF32[i] : imgRowS32[i];389 if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) {390 break;391 }392 }393 int i1 = i;394 const pmSpan *sp = pmFootprintAddSpan(fp, row + row0, i0 + col0 + 1, i1 + col0 - 1);395 396 (void)add_startspan(startspans, sp, mask, PM_SSPAN_RESTART);397 }398 /*399 * Now workout from those Startspans, searching for pixels above threshold400 */401 while (do_startspan(fp, img, mask, threshold, startspans)) continue;402 /*403 * Cleanup404 */405 psFree(mask);406 psFree(startspans); // restores the image pixel407 408 return fp; // pmFootprint really409 } -
branches/simtest_nebulous_branches/psModules/src/objects/pmFootprintIDs.c
r20937 r27840 32 32 const int row0 = fp->region.y0; 33 33 34 for (int j = 0; j < fp-> spans->n; j++) {34 for (int j = 0; j < fp->nspans; j++) { 35 35 const pmSpan *span = fp->spans->data[j]; 36 36 psS32 *imgRow = idImage->data.S32[span->y - row0]; -
branches/simtest_nebulous_branches/psModules/src/objects/pmGrowthCurveGenerate.c
r23989 r27840 65 65 66 66 // use the center of the center pixel of the image 67 // 0.5 PIX: is this offset needed? probably -- the psf model uses 0.5,0.5 as the center, double check 67 68 float xc = (int)(ix*readout->image->numCols + 0.5*readout->image->numCols) + readout->image->col0 + 0.5; 68 69 float yc = (int)(iy*readout->image->numRows + 0.5*readout->image->numRows) + readout->image->row0 + 0.5; … … 156 157 157 158 // measure the fitMag for this model 158 pmSourcePhotometryModel (&fitMag, model);159 pmSourcePhotometryModel (&fitMag, NULL, model); 159 160 growth->fitMag = fitMag; 160 161 … … 195 196 return NULL; 196 197 } 197 psImageKeepCircle (mask, xc, yc, radius, "AND", PS_NOT_IMAGE_MASK(markVal)); 198 psImageMaskPixels (mask, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask 198 199 199 200 // the 'ignore' mode is for testing -
branches/simtest_nebulous_branches/psModules/src/objects/pmModel.c
r23187 r27840 56 56 57 57 tmp->type = type; 58 tmp->chisq = 0.0; 59 tmp->chisqNorm = 0.0; 58 tmp->mag = NAN; 59 tmp->chisq = NAN; 60 tmp->chisqNorm = NAN; 60 61 tmp->nDOF = 0; 61 62 tmp->nPix = 0; 62 63 tmp->nIter = 0; 63 tmp-> radiusFit= 0;64 tmp->fitRadius = 0; 64 65 tmp->flags = PM_MODEL_STATUS_NONE; 65 66 tmp->residuals = NULL; // XXX should the model own this memory? … … 86 87 tmp->modelParamsFromPSF = class->modelParamsFromPSF; 87 88 tmp->modelFitStatus = class->modelFitStatus; 89 tmp->modelSetLimits = class->modelSetLimits; 88 90 89 91 psTrace("psModules.objects", 10, "---- %s() end ----\n", __func__); … … 108 110 new->nIter = model->nIter; 109 111 new->flags = model->flags; 110 new-> radiusFit = model->radiusFit;112 new->fitRadius = model->fitRadius; 111 113 112 114 for (int i = 0; i < new->params->n; i++) { … … 189 191 psVector *params = model->params; 190 192 191 psS32imageCol;192 psS32imageRow;193 psF32pixelValue;193 float imageCol; 194 float imageRow; 195 float pixelValue; 194 196 195 197 // save original values; restore before returning … … 232 234 psF32 **Rx = NULL; 233 235 psF32 **Ry = NULL; 234 p sImageMaskType **Rm = NULL;236 pmResidMaskType **Rm = NULL; 235 237 236 238 if (model->residuals) { … … 240 242 Rx = (model->residuals->Rx) ? model->residuals->Rx->data.F32 : NULL; 241 243 Ry = (model->residuals->Ry) ? model->residuals->Ry->data.F32 : NULL; 242 Rm = (model->residuals->mask) ? model->residuals->mask->data.P S_TYPE_IMAGE_MASK_DATA : NULL;244 Rm = (model->residuals->mask) ? model->residuals->mask->data.PM_TYPE_RESID_MASK_DATA : NULL; 243 245 if (Ro) { 244 246 NX = model->residuals->Ro->numCols; … … 255 257 continue; 256 258 257 // XXX should we use using 0.5 pixel offset?258 // Convert to coordinate in parent image, with offset (dx,dy)259 imageCol = ix + image->col0 - dx;260 imageRow = iy + image->row0 - dy;261 262 x->data.F32[0] = (float)imageCol;263 x->data.F32[1] = (float)imageRow;259 // Convert to coordinate in parent image, with offset (dx,dy) 260 // 0.5 PIX: the model take pixel coordinates so convert the pixel index here 261 imageCol = ix + 0.5 + image->col0 - dx; 262 imageRow = iy + 0.5 + image->row0 - dy; 263 264 x->data.F32[0] = imageCol; 265 x->data.F32[1] = imageRow; 264 266 265 267 pixelValue = 0.0; … … 276 278 float rx = xBin*ix + DX; 277 279 278 int rx0 = rx - 0.5;279 int rx1 = rx + 0.5;280 int ry0 = ry - 0.5;281 int ry1 = ry + 0.5;282 283 if (rx0 < 0) goto skip;284 if (ry0 < 0) goto skip;285 if (rx1 >= NX) goto skip;286 if (ry1 >= NY) goto skip;287 288 // these go from 0.0 to 1.0 between the centers of the pixels 289 float fx = rx - 0.5 - rx0;290 float Fx = 1.0 - fx;291 float fy = ry - 0.5 - ry0;292 float Fy = 1.0 - fy;293 294 // check the residual image mask (if set). give up if any of the 4 pixels are masked.295 if (Rm) {296 if (Rm[ry0][rx0]) goto skip;297 if (Rm[ry0][rx1]) goto skip;298 if (Rm[ry1][rx0]) goto skip;299 if (Rm[ry1][rx1]) goto skip;300 }301 302 // a possible further optimization if we re-use these values303 // XXX allow for masked pixels, and add pixel weights304 float V0 = (Ro[ry0][rx0]*Fx + Ro[ry0][rx1]*fx);305 float V1 = (Ro[ry1][rx0]*Fx + Ro[ry1][rx1]*fx);306 float Vo = V0*Fy + V1*fy;307 if (!isfinite(Vo)) goto skip;308 309 float Vx = 0.0;310 float Vy = 0.0;311 312 // skip Rx,Ry if Ro is masked313 if (Rx && Ry && (mode & PM_MODEL_OP_RES1)) {314 V0 = (Rx[ry0][rx0]*Fx + Rx[ry0][rx1]*fx);315 V1 = (Rx[ry1][rx0]*Fx + Rx[ry1][rx1]*fx);316 Vx = V0*Fy + V1*fy;317 318 V0 = (Ry[ry0][rx0]*Fx + Ry[ry0][rx1]*fx);319 V1 = (Ry[ry1][rx0]*Fx + Ry[ry1][rx1]*fx);320 Vy = V0*Fy + V1*fy;321 }322 if (!isfinite(Vx)) goto skip;323 if (!isfinite(Vy)) goto skip;324 325 // 2D residual variations are set for the true source position326 pixelValue += Io*(Vo + XoSave*Vx + XoSave*Vy);280 int rx0 = rx - 0.5; 281 int rx1 = rx + 0.5; 282 int ry0 = ry - 0.5; 283 int ry1 = ry + 0.5; 284 285 if (rx0 < 0) goto skip; 286 if (ry0 < 0) goto skip; 287 if (rx1 >= NX) goto skip; 288 if (ry1 >= NY) goto skip; 289 290 // these go from 0.0 to 1.0 between the centers of the pixels 291 float fx = rx - 0.5 - rx0; 292 float Fx = 1.0 - fx; 293 float fy = ry - 0.5 - ry0; 294 float Fy = 1.0 - fy; 295 296 // check the residual image mask (if set). give up if any of the 4 pixels are masked. 297 if (Rm) { 298 if (Rm[ry0][rx0]) goto skip; 299 if (Rm[ry0][rx1]) goto skip; 300 if (Rm[ry1][rx0]) goto skip; 301 if (Rm[ry1][rx1]) goto skip; 302 } 303 304 // a possible further optimization if we re-use these values 305 // XXX allow for masked pixels, and add pixel weights 306 float V0 = (Ro[ry0][rx0]*Fx + Ro[ry0][rx1]*fx); 307 float V1 = (Ro[ry1][rx0]*Fx + Ro[ry1][rx1]*fx); 308 float Vo = V0*Fy + V1*fy; 309 if (!isfinite(Vo)) goto skip; 310 311 float Vx = 0.0; 312 float Vy = 0.0; 313 314 // skip Rx,Ry if Ro is masked 315 if (Rx && Ry && (mode & PM_MODEL_OP_RES1)) { 316 V0 = (Rx[ry0][rx0]*Fx + Rx[ry0][rx1]*fx); 317 V1 = (Rx[ry1][rx0]*Fx + Rx[ry1][rx1]*fx); 318 Vx = V0*Fy + V1*fy; 319 320 V0 = (Ry[ry0][rx0]*Fx + Ry[ry0][rx1]*fx); 321 V1 = (Ry[ry1][rx0]*Fx + Ry[ry1][rx1]*fx); 322 Vy = V0*Fy + V1*fy; 323 } 324 if (!isfinite(Vx)) goto skip; 325 if (!isfinite(Vy)) goto skip; 326 327 // 2D residual variations are set for the true source position 328 pixelValue += Io*(Vo + XoSave*Vx + XoSave*Vy); 327 329 } 328 330 329 skip:331 skip: 330 332 // add or subtract the value 331 333 if (add) { -
branches/simtest_nebulous_branches/psModules/src/objects/pmModel.h
r21516 r27840 44 44 } pmModelOpMode; 45 45 46 /// Parameter limit types 47 typedef enum { 48 PM_MODEL_LIMITS_NONE, ///< Apply no limits: suitable for debugging 49 PM_MODEL_LIMITS_IGNORE, ///< Ignore all limits: fit can go to town 50 PM_MODEL_LIMITS_LAX, ///< Lax limits: attempting to reproduce even bad data 51 PM_MODEL_LIMITS_MODERATE, ///< Moderate limits: cope with mildly bad data 52 PM_MODEL_LIMITS_STRICT, ///< Strict limits: insist on good quality data 53 } pmModelLimitsType; 54 46 55 typedef struct pmModel pmModel; 47 56 typedef struct pmSource pmSource; … … 74 83 // This function returns the success / failure status of the given model fit 75 84 typedef bool (*pmModelFitStatusFunc)(pmModel *model); 85 86 // This function sets the parameter limits for the given model 87 typedef bool (*pmModelSetLimitsFunc)(pmModelLimitsType type); 76 88 77 89 /** pmModel data structure … … 96 108 int nIter; ///< number of iterations to reach min 97 109 pmModelStatus flags; ///< model status flags 98 float radiusFit; ///< fit radius actually used110 float fitRadius; ///< fit radius actually used 99 111 pmResiduals *residuals; ///< normalized PSF residuals 100 112 … … 108 120 pmModelParamsFromPSF modelParamsFromPSF; 109 121 pmModelFitStatusFunc modelFitStatus; 122 pmModelSetLimitsFunc modelSetLimits; 110 123 }; 111 124 … … 151 164 pmModel *model, ///< The input pmModel 152 165 pmModelOpMode mode, ///< mode to control how the model is added into the image 153 psImageMaskType maskVal ///< Value to mask166 psImageMaskType maskVal ///< Value to mask 154 167 ); 155 168 … … 169 182 pmModel *model, ///< The input pmModel 170 183 pmModelOpMode mode, ///< mode to control how the model is added into the image 171 psImageMaskType maskVal ///< Value to mask184 psImageMaskType maskVal ///< Value to mask 172 185 ); 173 186 … … 202 215 ); 203 216 217 218 /// Set the model parameter limits for the given model 219 /// 220 /// Wraps the model-specific pmModelSetLimitsFunc function. 221 bool pmModelSetLimits( 222 const pmModel *model, ///< Model of interest 223 pmModelLimits type ///< Type of limits 224 ); 225 226 204 227 /// @} 205 228 # endif /* PM_MODEL_H */ -
branches/simtest_nebulous_branches/psModules/src/objects/pmModelClass.c
r20937 r27840 36 36 #include "pmErrorCodes.h" 37 37 38 // XXX shouldn't these be defined for us in pslib.h ???38 // XXX shouldn't these be defined for us in math.h ??? 39 39 double hypot(double x, double y); 40 40 double sqrt (double x); 41 41 42 # include "models/pmModel_GAUSS. c"43 # include "models/pmModel_PGAUSS. c"44 # include "models/pmModel_QGAUSS. c"45 # include "models/pmModel_PS1_V1. c"46 # include "models/pmModel_RGAUSS. c"47 # include "models/pmModel_SERSIC. c"42 # include "models/pmModel_GAUSS.h" 43 # include "models/pmModel_PGAUSS.h" 44 # include "models/pmModel_QGAUSS.h" 45 # include "models/pmModel_PS1_V1.h" 46 # include "models/pmModel_RGAUSS.h" 47 # include "models/pmModel_SERSIC.h" 48 48 49 49 static pmModelClass defaultModels[] = { 50 {"PS_MODEL_GAUSS", 7, pmModelFunc_GAUSS, pmModelFlux_GAUSS, pmModelRadius_GAUSS, pmModelLimits_GAUSS, pmModelGuess_GAUSS, pmModelFromPSF_GAUSS, pmModelParamsFromPSF_GAUSS, pmModelFitStatus_GAUSS},51 {"PS_MODEL_PGAUSS", 7, pmModelFunc_PGAUSS, pmModelFlux_PGAUSS, pmModelRadius_PGAUSS, pmModelLimits_PGAUSS, pmModelGuess_PGAUSS, pmModelFromPSF_PGAUSS, pmModelParamsFromPSF_PGAUSS, pmModelFitStatus_PGAUSS},52 {"PS_MODEL_QGAUSS", 8, pmModelFunc_QGAUSS, pmModelFlux_QGAUSS, pmModelRadius_QGAUSS, pmModelLimits_QGAUSS, pmModelGuess_QGAUSS, pmModelFromPSF_QGAUSS, pmModelParamsFromPSF_QGAUSS, pmModelFitStatus_QGAUSS},53 {"PS_MODEL_PS1_V1", 8, pmModelFunc_PS1_V1, pmModelFlux_PS1_V1, pmModelRadius_PS1_V1, pmModelLimits_PS1_V1, pmModelGuess_PS1_V1, pmModelFromPSF_PS1_V1, pmModelParamsFromPSF_PS1_V1, pmModelFitStatus_PS1_V1},54 {"PS_MODEL_RGAUSS", 8, pmModelFunc_RGAUSS, pmModelFlux_RGAUSS, pmModelRadius_RGAUSS, pmModelLimits_RGAUSS, pmModelGuess_RGAUSS, pmModelFromPSF_RGAUSS, pmModelParamsFromPSF_RGAUSS, pmModelFitStatus_RGAUSS},55 {"PS_MODEL_SERSIC", 8, pmModelFunc_SERSIC, pmModelFlux_SERSIC, pmModelRadius_SERSIC, pmModelLimits_SERSIC, pmModelGuess_SERSIC, pmModelFromPSF_SERSIC, pmModelParamsFromPSF_SERSIC, pmModelFitStatus_SERSIC}50 {"PS_MODEL_GAUSS", 7, (pmModelFunc)pmModelFunc_GAUSS, (pmModelFlux)pmModelFlux_GAUSS, (pmModelRadius)pmModelRadius_GAUSS, (pmModelLimits)pmModelLimits_GAUSS, (pmModelGuessFunc)pmModelGuess_GAUSS, (pmModelFromPSFFunc)pmModelFromPSF_GAUSS, (pmModelParamsFromPSF)pmModelParamsFromPSF_GAUSS, (pmModelFitStatusFunc)pmModelFitStatus_GAUSS, (pmModelSetLimitsFunc)pmModelSetLimits_GAUSS }, 51 {"PS_MODEL_PGAUSS", 7, (pmModelFunc)pmModelFunc_PGAUSS, (pmModelFlux)pmModelFlux_PGAUSS, (pmModelRadius)pmModelRadius_PGAUSS, (pmModelLimits)pmModelLimits_PGAUSS, (pmModelGuessFunc)pmModelGuess_PGAUSS, (pmModelFromPSFFunc)pmModelFromPSF_PGAUSS, (pmModelParamsFromPSF)pmModelParamsFromPSF_PGAUSS, (pmModelFitStatusFunc)pmModelFitStatus_PGAUSS, (pmModelSetLimitsFunc)pmModelSetLimits_PGAUSS }, 52 {"PS_MODEL_QGAUSS", 8, (pmModelFunc)pmModelFunc_QGAUSS, (pmModelFlux)pmModelFlux_QGAUSS, (pmModelRadius)pmModelRadius_QGAUSS, (pmModelLimits)pmModelLimits_QGAUSS, (pmModelGuessFunc)pmModelGuess_QGAUSS, (pmModelFromPSFFunc)pmModelFromPSF_QGAUSS, (pmModelParamsFromPSF)pmModelParamsFromPSF_QGAUSS, (pmModelFitStatusFunc)pmModelFitStatus_QGAUSS, (pmModelSetLimitsFunc)pmModelSetLimits_QGAUSS }, 53 {"PS_MODEL_PS1_V1", 8, (pmModelFunc)pmModelFunc_PS1_V1, (pmModelFlux)pmModelFlux_PS1_V1, (pmModelRadius)pmModelRadius_PS1_V1, (pmModelLimits)pmModelLimits_PS1_V1, (pmModelGuessFunc)pmModelGuess_PS1_V1, (pmModelFromPSFFunc)pmModelFromPSF_PS1_V1, (pmModelParamsFromPSF)pmModelParamsFromPSF_PS1_V1, (pmModelFitStatusFunc)pmModelFitStatus_PS1_V1, (pmModelSetLimitsFunc)pmModelSetLimits_PS1_V1 }, 54 {"PS_MODEL_RGAUSS", 8, (pmModelFunc)pmModelFunc_RGAUSS, (pmModelFlux)pmModelFlux_RGAUSS, (pmModelRadius)pmModelRadius_RGAUSS, (pmModelLimits)pmModelLimits_RGAUSS, (pmModelGuessFunc)pmModelGuess_RGAUSS, (pmModelFromPSFFunc)pmModelFromPSF_RGAUSS, (pmModelParamsFromPSF)pmModelParamsFromPSF_RGAUSS, (pmModelFitStatusFunc)pmModelFitStatus_RGAUSS, (pmModelSetLimitsFunc)pmModelSetLimits_RGAUSS }, 55 {"PS_MODEL_SERSIC", 8, (pmModelFunc)pmModelFunc_SERSIC, (pmModelFlux)pmModelFlux_SERSIC, (pmModelRadius)pmModelRadius_SERSIC, (pmModelLimits)pmModelLimits_SERSIC, (pmModelGuessFunc)pmModelGuess_SERSIC, (pmModelFromPSFFunc)pmModelFromPSF_SERSIC, (pmModelParamsFromPSF)pmModelParamsFromPSF_SERSIC, (pmModelFitStatusFunc)pmModelFitStatus_SERSIC, (pmModelSetLimitsFunc)pmModelSetLimits_SERSIC } 56 56 }; 57 57 … … 168 168 return (models[type].name); 169 169 } 170 171 172 void pmModelClassSetLimits(pmModelLimitsType type) 173 { 174 if (!models) { 175 pmModelClassInit(); 176 } 177 178 for (int i = 0; i < Nmodels; i++) { 179 if (models[i].modelSetLimits) { 180 models[i].modelSetLimits(type); 181 } 182 } 183 184 } 185 -
branches/simtest_nebulous_branches/psModules/src/objects/pmModelClass.h
r15697 r27840 29 29 # define PM_MODEL_CLASS_H 30 30 31 #include <pmModel.h> 32 31 33 /// @addtogroup Objects Object Detection / Analysis Functions 32 34 /// @{ 33 35 34 typedef struct 35 { 36 typedef struct { 36 37 char *name; 37 38 int nParams; … … 44 45 pmModelParamsFromPSF modelParamsFromPSF; 45 46 pmModelFitStatusFunc modelFitStatus; 47 pmModelSetLimitsFunc modelSetLimits; 46 48 } pmModelClass; 47 49 … … 73 75 pmModelType pmModelClassGetType (const char *name); 74 76 77 /// Set parameter limits for all models 78 void pmModelClassSetLimits(pmModelLimitsType type); 79 80 75 81 /// @} 76 82 # endif /* PM_MODEL_CLASS_H */ -
branches/simtest_nebulous_branches/psModules/src/objects/pmModelUtils.c
r19999 r27840 48 48 return NULL; 49 49 } 50 // XXXnote that model->residuals is just a reference50 // note that model->residuals is just a reference 51 51 modelPSF->residuals = psf->residuals; 52 52 … … 65 65 // set model parameters for this source based on PSF information 66 66 if (!modelPSF->modelParamsFromPSF (modelPSF, psf, Xo, Yo, Io)) { 67 // XXX we do not want to raise an error here, just note that we failed68 // psError(PM_ERR_PSF, false, "Failed to set model params from PSF");69 67 psFree(modelPSF); 70 68 return NULL; 71 69 } 72 70 73 // XXXnote that model->residuals is just a reference71 // note that model->residuals is just a reference 74 72 modelPSF->residuals = psf->residuals; 75 73 -
branches/simtest_nebulous_branches/psModules/src/objects/pmPSF.c
r24206 r27840 42 42 #include "pmErrorCodes.h" 43 43 44 45 #define MAX_AXIS_RATIO 20.0 // Maximum axis ratio for PSF model 46 44 47 /*****************************************************************************/ 45 48 /* FUNCTION IMPLEMENTATION - PUBLIC */ … … 405 408 return psf; 406 409 } 410 411 412 float pmPSFtoFWHM(const pmPSF *psf, float x, float y) 413 { 414 PS_ASSERT_PTR_NON_NULL(psf, NAN); 415 416 pmModel *model = pmModelFromPSFforXY(psf, x, y, 1.0); // Model of source 417 if (!model) { 418 psError(PS_ERR_UNKNOWN, false, "Unable to determine PSF model at %f,%f\n", x, y); 419 return NAN; 420 } 421 psF32 *params = model->params->data.F32; // Model parameters 422 psEllipseAxes axes = pmPSF_ModelToAxes(params, MAX_AXIS_RATIO); // Ellipse axes 423 424 // Curiously, the minor axis can be larger than the major axis, so need to check. 425 float fwhm = 2.355 * PS_MAX(axes.minor, axes.major); // FWHM, converted from sigma 426 427 psFree(model); 428 429 return fwhm; 430 } -
branches/simtest_nebulous_branches/psModules/src/objects/pmPSF.h
r24206 r27840 38 38 * 39 39 */ 40 typedef struct 41 { 40 typedef struct { 42 41 pmModelType type; ///< PSF Model in use 43 42 psArray *params; ///< Model parameters (psPolynomial2D) … … 65 64 pmGrowthCurve *growth; ///< apMag vs Radius 66 65 pmResiduals *residuals; ///< normalized residual image (no spatial variation) 67 } 68 pmPSF; 66 } pmPSF; 69 67 70 68 typedef struct { … … 81 79 bool poissonErrorsPhotLin; ///< use poission errors for linear model fitting 82 80 bool poissonErrorsParams; ///< use poission errors for model parameter fitting 83 float radius; 81 float fitRadius; 82 float apRadius; 84 83 bool chiFluxTrend; // Fit a trend in Chi2 as a function of flux? 85 84 } pmPSFOptions; … … 112 111 psEllipseAxes pmPSF_ModelToAxes (psF32 *modelPar, double maxAR); 113 112 113 /// Calculate FWHM value from a PSF 114 float pmPSFtoFWHM( 115 const pmPSF *psf, // PSF of interest 116 float x, float y // Position of interest 117 ); 118 119 114 120 /// @} 115 121 # endif -
branches/simtest_nebulous_branches/psModules/src/objects/pmPSF_IO.c
r21183 r27840 28 28 #include "pmConfig.h" 29 29 #include "pmDetrendDB.h" 30 #include "pmErrorCodes.h" 30 31 31 32 #include "pmHDU.h" … … 49 50 #include "pmSource.h" 50 51 #include "pmModelClass.h" 52 #include "pmModelUtils.h" 51 53 #include "pmSourceIO.h" 52 54 … … 121 123 if (view->chip == -1) { 122 124 if (!pmPSFmodelWriteFPA(fpa, view, file, config)) { 123 psError( PS_ERR_IO, false, "Failed to write PSF for fpa");125 psError(psErrorCodeLast(), false, "Failed to write PSF for fpa"); 124 126 return false; 125 127 } … … 134 136 if (view->cell == -1) { 135 137 if (!pmPSFmodelWriteChip (chip, view, file, config)) { 136 psError( PS_ERR_IO, false, "Failed to write PSF for chip");138 psError(psErrorCodeLast(), false, "Failed to write PSF for chip"); 137 139 return false; 138 140 } … … 140 142 } 141 143 142 psError(P S_ERR_IO, false, "PSF must be written at the chip level");144 psError(PM_ERR_CONFIG, true, "PSF must be written at the chip level"); 143 145 return false; 144 146 } … … 157 159 thisView->chip = i; 158 160 if (!pmPSFmodelWriteChip (chip, thisView, file, config)) { 159 psError( PS_ERR_IO, false, "Failed to write PSF for %dth chip", i);161 psError(psErrorCodeLast(), false, "Failed to write PSF for %dth chip", i); 160 162 psFree(thisView); 161 163 return false; … … 172 174 PS_ASSERT_PTR_NON_NULL(chip, false); 173 175 174 if (!pmPSFmodelWrite (chip->analysis, view, file, config)) {175 psError( PS_ERR_IO, false, "Failed to write PSF for chip");176 if (!pmPSFmodelWrite(chip->analysis, view, file, config)) { 177 psError(psErrorCodeLast(), false, "Failed to write PSF for chip"); 176 178 return false; 177 179 } … … 196 198 char *headName, *tableName, *residName; 197 199 198 if (!analysis) return false; 200 if (!analysis) { 201 psError(PM_ERR_PROG, true, "No analysis metadata for chip."); 202 return false; 203 } 199 204 200 205 // select the current recipe 201 206 psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, "PSPHOT"); 202 207 if (!recipe) { 203 psError(P S_ERR_UNKNOWN, false, "missing recipe %s", "PSPHOT");208 psError(PM_ERR_CONFIG, false, "missing recipe %s", "PSPHOT"); 204 209 return false; 205 210 } … … 212 217 // get the current header 213 218 pmFPA *fpa = pmFPAfileSuitableFPA(file, view, config, false); // Suitable FPA for writing 219 if (!fpa) { 220 psError(psErrorCodeLast(), false, "Unable to get FPA for writing."); 221 return false; 222 } 214 223 pmHDU *hdu = psMemIncrRefCounter(pmFPAviewThisHDU(view, fpa)); 215 224 psFree(fpa); 216 225 if (!hdu) { 217 psError(P S_ERR_UNKNOWN, false, "Unable to find HDU");226 psError(PM_ERR_CONFIG, false, "Unable to find HDU"); 218 227 return false; 219 228 } … … 233 242 psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES"); 234 243 if (!menu) { 235 psError(P S_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config");244 psError(PM_ERR_CONFIG, true, "missing EXTNAME.RULES in camera.config"); 236 245 psFree(hdu); 237 246 return false; … … 241 250 rule = psMetadataLookupStr(&status, menu, "PSF.HEAD"); 242 251 if (!rule) { 243 psError(P S_ERR_UNKNOWN, false, "missing entry for PSF.HEAD in EXTNAME.RULES in camera.config");252 psError(PM_ERR_CONFIG, false, "missing entry for PSF.HEAD in EXTNAME.RULES in camera.config"); 244 253 psFree(hdu); 245 254 return false; … … 250 259 rule = psMetadataLookupStr(&status, menu, "PSF.TABLE"); 251 260 if (!rule) { 252 psError(P S_ERR_UNKNOWN, false, "missing entry for PSF.TABLE in EXTNAME.RULES in camera.config");261 psError(PM_ERR_CONFIG, false, "missing entry for PSF.TABLE in EXTNAME.RULES in camera.config"); 253 262 psFree (headName); 254 263 psFree(hdu); … … 260 269 rule = psMetadataLookupStr(&status, menu, "PSF.RESID"); 261 270 if (!rule) { 262 psError(P S_ERR_UNKNOWN, false, "missing entry for PSF.RESID in EXTNAME.RULES in camera.config");271 psError(PM_ERR_CONFIG, false, "missing entry for PSF.RESID in EXTNAME.RULES in camera.config"); 263 272 psFree (headName); 264 273 psFree (tableName); … … 267 276 } 268 277 residName = pmFPAfileNameFromRule (rule, file, view); 278 279 // EXTNAME for psf image 280 // rule = psMetadataLookupStr(&status, menu, "PSF.RESID"); 281 // if (!rule) { 282 // psError(PS_ERR_UNKNOWN, false, "missing entry for PSF.RESID in EXTNAME.RULES in camera.config"); 283 // psFree (headName); 284 // psFree (tableName); 285 // psFree(hdu); 286 // return false; 287 // } 288 // residName = pmFPAfileNameFromRule (rule, file, view); 269 289 } 270 290 … … 282 302 } 283 303 284 psFitsWriteBlank (file->fits, hdu->header, headName); 304 if (!psFitsWriteBlank(file->fits, hdu->header, headName)) { 305 psError(psErrorCodeLast(), false, "Unable to write PSF PHU."); 306 psFree(hdu); 307 return false; 308 } 285 309 psTrace ("pmFPAfile", 5, "wrote ext head %s (type: %d)\n", file->filename, file->type); 286 310 file->header = hdu->header; … … 292 316 pmPSF *psf = psMetadataLookupPtr (&status, analysis, "PSPHOT.PSF"); 293 317 if (!psf) { 294 psError(P S_ERR_UNKNOWN, true, "missing PSF for this analysis metadata");318 psError(PM_ERR_PROG, true, "missing PSF for this analysis metadata"); 295 319 psFree (tableName); 296 320 psFree (residName); … … 310 334 psMetadataAddBool (header, PS_LIST_TAIL, "ERR_PAR", 0, "Use Poisson errors in fits?", psf->poissonErrorsParams); 311 335 312 int nPar = pmModelClassParameterCount (psf->type) ;336 int nPar = pmModelClassParameterCount (psf->type); 313 337 psMetadataAdd (header, PS_LIST_TAIL, "PSF_NPAR", PS_DATA_S32, "PSF model parameter count", nPar); 314 338 … … 321 345 pmPSFClump psfClump; 322 346 323 // we now save clump parameters for each region : need to save all of those324 int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");325 psMetadataAddS32 (header, PS_LIST_TAIL, "PSF_CLN", PS_META_REPLACE, "number of psf clump regions", nRegions);326 for (int i = 0; i < nRegions; i++) {327 char regionName[64];328 snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);329 psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);330 331 psfClump.X = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X"); assert (status);332 psfClump.Y = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y"); assert (status);333 psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX"); assert (status);334 psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY"); assert (status);335 336 char key[16];337 snprintf (key, 9, "CLX_%03d", i);338 psMetadataAddF32 (header, PS_LIST_TAIL, key, PS_META_REPLACE, "psf clump center", psfClump.X);339 snprintf (key, 9, "CLY_%03d", i);340 psMetadataAddF32 (header, PS_LIST_TAIL, key, PS_META_REPLACE, "psf clump center", psfClump.Y);341 snprintf (key, 9, "CLDX_%03d", i);342 psMetadataAddF32 (header, PS_LIST_TAIL, key, PS_META_REPLACE, "psf clump size", psfClump.dX);343 snprintf (key, 9, "CLDY_%03d", i);344 psMetadataAddF32 (header, PS_LIST_TAIL, key, PS_META_REPLACE, "psf clump size", psfClump.dY);345 }347 // we now save clump parameters for each region : need to save all of those 348 int nRegions = psMetadataLookupS32 (&status, analysis, "PSF.CLUMP.NREGIONS"); 349 psMetadataAddS32 (header, PS_LIST_TAIL, "PSF_CLN", PS_META_REPLACE, "number of psf clump regions", nRegions); 350 for (int i = 0; i < nRegions; i++) { 351 char regionName[64]; 352 snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i); 353 psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName); 354 355 psfClump.X = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X"); assert (status); 356 psfClump.Y = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y"); assert (status); 357 psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX"); assert (status); 358 psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY"); assert (status); 359 360 char key[16]; 361 snprintf (key, 9, "CLX_%03d", i); 362 psMetadataAddF32 (header, PS_LIST_TAIL, key, PS_META_REPLACE, "psf clump center", psfClump.X); 363 snprintf (key, 9, "CLY_%03d", i); 364 psMetadataAddF32 (header, PS_LIST_TAIL, key, PS_META_REPLACE, "psf clump center", psfClump.Y); 365 snprintf (key, 9, "CLDX_%03d", i); 366 psMetadataAddF32 (header, PS_LIST_TAIL, key, PS_META_REPLACE, "psf clump size", psfClump.dX); 367 snprintf (key, 9, "CLDY_%03d", i); 368 psMetadataAddF32 (header, PS_LIST_TAIL, key, PS_META_REPLACE, "psf clump size", psfClump.dY); 369 } 346 370 347 371 // save the dimensions of each parameter … … 424 448 // write an empty FITS segment if we have no PSF information 425 449 if (psfTable->n == 0) { 426 // XXX this is probably an error (if we have a PSF, how do we have no data?) 427 psFitsWriteBlank (file->fits, header, tableName); 450 psError(PM_ERR_PROG, true, "No PSF data to write."); 451 psFree(tableName); 452 psFree(residName); 453 psFree(psfTable); 454 psFree(header); 455 return false; 428 456 } else { 429 457 psTrace ("pmFPAfile", 5, "writing psf data %s\n", tableName); 430 if (!psFitsWriteTable (file->fits, header, psfTable, tableName)) {431 psError( PS_ERR_IO, false, "writing psf table data %s\n", tableName);458 if (!psFitsWriteTable(file->fits, header, psfTable, tableName)) { 459 psError(psErrorCodeLast(), false, "Error writing psf table data %s\n", tableName); 432 460 psFree (tableName); 433 461 psFree (residName); … … 447 475 if (psf->residuals == NULL) { 448 476 // set some header keywords to make it clear there are no residuals? 449 psFitsWriteBlank (file->fits, header, residName); 477 if (!psFitsWriteBlank(file->fits, header, residName)) { 478 psError(psErrorCodeLast(), false, "Unable to write blank PSF residual image."); 479 psFree(residName); 480 psFree(header); 481 return false; 482 } 450 483 psFree (residName); 451 484 psFree (header); … … 458 491 psMetadataAddS32 (header, PS_LIST_TAIL, "YCENTER", 0, "", psf->residuals->yCenter); 459 492 460 // write the residuals as three planes of the image 461 // this call creates an extension with NAXIS3 = 3 493 // write the residuals as planes of the image 494 psArray *images = psArrayAllocEmpty (1); 495 psArrayAdd (images, 1, psf->residuals->Ro); // z = 0 is Ro 496 462 497 if (psf->residuals->Rx) { 463 // this call creates an extension with NAXIS3 = 3464 psArray *images = psArrayAllocEmpty (3);465 psArrayAdd (images, 1, psf->residuals->Ro);466 498 psArrayAdd (images, 1, psf->residuals->Rx); 467 499 psArrayAdd (images, 1, psf->residuals->Ry); 468 469 psFitsWriteImageCube (file->fits, header, images, residName); 470 psFree (images); 471 } else { 472 // this call creates an extension with NAXIS3 = 1 473 psFitsWriteImage(file->fits, header, psf->residuals->Ro, 0, residName); 474 } 500 } 501 502 // note that all N plane are implicitly of the same type, so we convert the mask 503 if (psf->residuals->mask) { 504 psImage *mask = psImageCopy (NULL, psf->residuals->mask, psf->residuals->Ro->type.type); 505 psArrayAdd (images, 1, mask); 506 psFree (mask); 507 } 508 509 // psFitsWriteImageCube (file->fits, header, images, residName); 510 // psFree (images); 511 512 if (!psFitsWriteImageCube (file->fits, header, images, residName)) { 513 psError(psErrorCodeLast(), false, "Unable to write PSF residuals."); 514 psFree(images); 515 psFree(residName); 516 psFree(header); 517 return false; 518 } 519 psFree (images); 475 520 psFree (residName); 521 psFree (header); 522 } 523 524 // write a representation of the psf model 525 { 526 psMetadata *header = psMetadataAlloc (); 527 528 if (0) { 529 // set some header keywords to make it clear there are no residuals? 530 if (!psFitsWriteBlank (file->fits, header, residName)) { 531 psError(psErrorCodeLast(), false, "Unable to write blank PSF residuals."); 532 psFree(residName); 533 psFree(header); 534 return false; 535 } 536 psFree (residName); 537 psFree (header); 538 return true; 539 } 540 541 int DX = 65; 542 int DY = 65; 543 544 psImage *psfMosaic = psImageAlloc (DX, DY, PS_TYPE_F32); 545 psImageInit (psfMosaic, 0.0); 546 547 pmModel *modelRef = pmModelAlloc(psf->type); 548 549 // use the center of the center pixel of the image 550 float xc = 0.5*psf->fieldNx; 551 float yc = 0.5*psf->fieldNy; 552 553 // assign the x and y coords to the image center 554 // create an object with center intensity of 1000 555 modelRef->params->data.F32[PM_PAR_SKY] = 0; 556 modelRef->params->data.F32[PM_PAR_I0] = 1.000; 557 modelRef->params->data.F32[PM_PAR_XPOS] = xc; 558 modelRef->params->data.F32[PM_PAR_YPOS] = yc; 559 560 // create modelPSF from this model 561 pmModel *model = pmModelFromPSF (modelRef, psf); 562 if (model) { 563 // place the reference object in the image center 564 pmModelAddWithOffset (psfMosaic, NULL, model, PM_MODEL_OP_FULL | PM_MODEL_OP_CENTER, 0, 0.0, 0.0); 565 psFree (model); 566 567 if (false) { 568 // this call creates an extension with NAXIS3 = 3 569 psArray *images = psArrayAllocEmpty (3); 570 psArrayAdd (images, 1, psfMosaic); 571 // psArrayAdd (images, 1, psfModel); 572 // psArrayAdd (images, 1, psfModel); 573 574 if (!psFitsWriteImageCube (file->fits, header, images, "PSF_MODEL")) { 575 psError(psErrorCodeLast(), false, "Unable to write PSF representation."); 576 psFree(images); 577 psFree(psfMosaic); 578 psFree(modelRef); 579 psFree(header); 580 return false; 581 } 582 psFree (images); 583 } else { 584 // this call creates an extension with NAXIS3 = 1 585 // XXX need to replace PSF_MODEL with rule-based name like residName 586 if (!psFitsWriteImage(file->fits, header, psfMosaic, 0, "PSF_MODEL")) { 587 psError(psErrorCodeLast(), false, "Unable to write PSF representation."); 588 psFree(psfMosaic); 589 psFree(modelRef); 590 psFree(header); 591 return false; 592 } 593 } 594 } 595 596 psFree (psfMosaic); 597 psFree (modelRef); 476 598 psFree (header); 477 599 } … … 523 645 // find the FPA phu 524 646 pmFPA *fpa = pmFPAfileSuitableFPA(file, view, config, false); // Suitable FPA for writing 647 if (!fpa) { 648 psError(psErrorCodeLast(), false, "Unable to build FPA to write."); 649 return false; 650 } 525 651 pmHDU *phu = psMemIncrRefCounter(pmFPAviewThisPHU(view, fpa)); 526 652 psFree(fpa); … … 533 659 psMetadataCopy (outhead, phu->header); 534 660 } else { 535 pmConfigConformHeader (outhead, file->format); 661 if (!pmConfigConformHeader (outhead, file->format)) { 662 psError(psErrorCodeLast(), false, "Unable to conform header of PSF PHU."); 663 psFree(phu); 664 return false; 665 } 536 666 } 537 667 psFree(phu); 538 668 539 669 psMetadataAddBool (outhead, PS_LIST_TAIL, "EXTEND", PS_META_REPLACE, "this file has extensions", true); 540 psFitsWriteBlank (file->fits, outhead, ""); 670 if (!psFitsWriteBlank (file->fits, outhead, "")) { 671 psError(psErrorCodeLast(), false, "Unable to write PHU for PSF."); 672 psFree(outhead); 673 return false; 674 } 541 675 file->wrote_phu = true; 542 676 … … 568 702 } 569 703 570 psError(P S_ERR_IO, false, "PSF must be read at the chip level");704 psError(PM_ERR_CONFIG, true, "PSF must be read at the chip level"); 571 705 return false; 572 706 } … … 595 729 596 730 if (!pmPSFmodelRead (chip->analysis, view, file, config)) { 597 psError( PS_ERR_IO, false, "Failed to write PSF for chip");731 psError(psErrorCodeLast(), false, "Failed to write PSF for chip"); 598 732 return false; 599 733 } … … 618 752 psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, "PSPHOT"); 619 753 if (!recipe) { 620 psError(P S_ERR_UNKNOWN, false, "missing recipe %s", "PSPHOT");754 psError(PM_ERR_CONFIG, false, "missing recipe %s", "PSPHOT"); 621 755 return false; 622 756 } … … 625 759 psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES"); 626 760 if (!menu) { 627 psError(P S_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config");761 psError(PM_ERR_CONFIG, true, "missing EXTNAME.RULES in camera.config"); 628 762 return false; 629 763 } … … 631 765 rule = psMetadataLookupStr(&status, menu, "PSF.TABLE"); 632 766 if (!rule) { 633 psError(P S_ERR_UNKNOWN, true, "missing entry for PSF.TABLE in EXTNAME.RULES in camera.config");767 psError(PM_ERR_CONFIG, true, "missing entry for PSF.TABLE in EXTNAME.RULES in camera.config"); 634 768 return false; 635 769 } … … 638 772 rule = psMetadataLookupStr(&status, menu, "PSF.RESID"); 639 773 if (!rule) { 640 psError(P S_ERR_UNKNOWN, true, "missing entry for PSF.RESID in EXTNAME.RULES in camera.config");774 psError(PM_ERR_CONFIG, true, "missing entry for PSF.RESID in EXTNAME.RULES in camera.config"); 641 775 return false; 642 776 } … … 646 780 // advance to the table data extension 647 781 // since we have read the IMAGE header, the TABLE header should exist 648 if (!psFitsMoveExtName (file->fits, tableName)) { 649 psAbort("cannot find data extension %s in %s", tableName, file->filename); 782 if (!psFitsMoveExtName(file->fits, tableName)) { 783 psError(psErrorCodeLast(), false, "cannot find data extension %s in %s", tableName, file->filename); 784 return false; 650 785 } 651 786 652 787 // load the PSF model table header 653 788 header = psFitsReadHeader (NULL, file->fits); 654 if (!header) psAbort("cannot read table header"); 789 if (!header) { 790 psError(psErrorCodeLast(), false, "Cannot read PSF table header."); 791 return false; 792 } 655 793 656 794 pmPSFOptions *options = pmPSFOptionsAlloc(); … … 667 805 int nRegions = psMetadataLookupS32 (&status, header, "PSF_CLN"); 668 806 if (!status) { 669 // read old-style psf clump data670 671 char regionName[64];672 snprintf (regionName, 64, "PSF.CLUMP.REGION.000");673 psMetadataAddS32 (recipe, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS", PS_META_REPLACE, "psf clump regions", 1);674 675 psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);676 if (!regionMD) {677 regionMD = psMetadataAlloc();678 psMetadataAddMetadata (recipe, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);679 psFree (regionMD);680 }681 682 // psf clump data683 pmPSFClump psfClump;684 685 psfClump.X = psMetadataLookupF32 (&status, header, "PSF_CLX" ); assert(status);686 psfClump.Y = psMetadataLookupF32 (&status, header, "PSF_CLY" ); assert(status);687 psfClump.dX = psMetadataLookupF32 (&status, header, "PSF_CLDX"); assert(status);688 psfClump.dY = psMetadataLookupF32 (&status, header, "PSF_CLDY"); assert(status);689 690 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X", PS_META_REPLACE, "psf clump center", psfClump.X);691 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y", PS_META_REPLACE, "psf clump center", psfClump.Y);692 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);693 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);807 // read old-style psf clump data 808 809 char regionName[64]; 810 snprintf (regionName, 64, "PSF.CLUMP.REGION.000"); 811 psMetadataAddS32 (analysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS", PS_META_REPLACE, "psf clump regions", 1); 812 813 psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName); 814 if (!regionMD) { 815 regionMD = psMetadataAlloc(); 816 psMetadataAddMetadata (analysis, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD); 817 psFree (regionMD); 818 } 819 820 // psf clump data 821 pmPSFClump psfClump; 822 823 psfClump.X = psMetadataLookupF32 (&status, header, "PSF_CLX" ); assert(status); 824 psfClump.Y = psMetadataLookupF32 (&status, header, "PSF_CLY" ); assert(status); 825 psfClump.dX = psMetadataLookupF32 (&status, header, "PSF_CLDX"); assert(status); 826 psfClump.dY = psMetadataLookupF32 (&status, header, "PSF_CLDY"); assert(status); 827 828 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X", PS_META_REPLACE, "psf clump center", psfClump.X); 829 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y", PS_META_REPLACE, "psf clump center", psfClump.Y); 830 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX); 831 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY); 694 832 } else { 695 psMetadataAddS32 (recipe, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS", PS_META_REPLACE, "psf clump regions", nRegions);696 697 for (int i = 0; i < nRegions; i++) {698 char key[10];699 char regionName[64];700 snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);701 702 psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);703 if (!regionMD) {704 regionMD = psMetadataAlloc();705 psMetadataAddMetadata (recipe, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);706 psFree (regionMD);707 }708 709 // psf clump data710 pmPSFClump psfClump;711 712 snprintf (key, 9, "CLX_%03d", i);713 psfClump.X = psMetadataLookupF32 (&status, header, key); assert(status);714 snprintf (key, 9, "CLY_%03d", i);715 psfClump.Y = psMetadataLookupF32 (&status, header, key); assert(status);716 snprintf (key, 9, "CLDX_%03d", i);717 psfClump.dX = psMetadataLookupF32 (&status, header, key); assert(status);718 snprintf (key, 9, "CLDY_%03d", i);719 psfClump.dY = psMetadataLookupF32 (&status, header, key); assert(status);720 721 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X", PS_META_REPLACE, "psf clump center", psfClump.X);722 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y", PS_META_REPLACE, "psf clump center", psfClump.Y);723 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);724 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);725 }833 psMetadataAddS32 (analysis, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS", PS_META_REPLACE, "psf clump regions", nRegions); 834 835 for (int i = 0; i < nRegions; i++) { 836 char key[10]; 837 char regionName[64]; 838 snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i); 839 840 psMetadata *regionMD = psMetadataLookupPtr (&status, analysis, regionName); 841 if (!regionMD) { 842 regionMD = psMetadataAlloc(); 843 psMetadataAddMetadata (analysis, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD); 844 psFree (regionMD); 845 } 846 847 // psf clump data 848 pmPSFClump psfClump; 849 850 snprintf (key, 9, "CLX_%03d", i); 851 psfClump.X = psMetadataLookupF32 (&status, header, key); assert(status); 852 snprintf (key, 9, "CLY_%03d", i); 853 psfClump.Y = psMetadataLookupF32 (&status, header, key); assert(status); 854 snprintf (key, 9, "CLDX_%03d", i); 855 psfClump.dX = psMetadataLookupF32 (&status, header, key); assert(status); 856 snprintf (key, 9, "CLDY_%03d", i); 857 psfClump.dY = psMetadataLookupF32 (&status, header, key); assert(status); 858 859 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X", PS_META_REPLACE, "psf clump center", psfClump.X); 860 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y", PS_META_REPLACE, "psf clump center", psfClump.Y); 861 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX); 862 psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY); 863 } 726 864 } 727 865 … … 764 902 char *modeName = psMetadataLookupStr (&status, header, name); 765 903 if (!status) { 766 psError(P S_ERR_UNKNOWN, true, "inconsistent PSF header: NX & NY defined for PAR %d, but not MD", i);904 psError(PM_ERR_PROG, true, "inconsistent PSF header: NX & NY defined for PAR %d, but not MD", i); 767 905 return false; 768 906 } … … 798 936 // read the raw table data 799 937 psArray *table = psFitsReadTable (file->fits); 938 if (!table) { 939 psError(psErrorCodeLast(), false, "Unable to read PSF table."); 940 psFree(header); 941 return false; 942 } 800 943 801 944 // fill in the matching psf->params entries … … 842 985 // since we have read the IMAGE header, the TABLE header should exist 843 986 if (!psFitsMoveExtName (file->fits, imageName)) { 844 psAbort("cannot find data extension %s in %s", imageName, file->filename); 987 psError(psErrorCodeLast(), false, "Cannot find PSF data extension %s in %s", 988 imageName, file->filename); 989 return false; 845 990 } 846 991 847 992 header = psFitsReadHeader (NULL, file->fits); 993 if (!header) { 994 psError(psErrorCodeLast(), false, "Unable to read PSF header."); 995 return false; 996 } 848 997 int Naxis = psMetadataLookupS32 (&status, header, "NAXIS"); 849 998 if (Naxis != 0) { … … 865 1014 866 1015 psRegion fullImage = {0, 0, 0, 0}; 867 psFitsReadImageBuffer(psf->residuals->Ro, file->fits, fullImage, 0); // Desired pixels 868 if (Nz > 1) { 869 assert (Nz == 3); 870 psFitsReadImageBuffer(psf->residuals->Rx, file->fits, fullImage, 1); // Desired pixels 871 psFitsReadImageBuffer(psf->residuals->Ry, file->fits, fullImage, 2); // Desired pixels 872 } 873 // XXX notice that we are not saving the resid->mask 1016 if (!psFitsReadImageBuffer(psf->residuals->Ro, file->fits, fullImage, 0)) { 1017 psError(psErrorCodeLast(), false, "Unable to read PSF residual image."); 1018 return false; 1019 } 1020 1021 // note that all N plane are implicitly of the same type, so we convert the mask 1022 psImage *mask = psImageCopy(NULL, psf->residuals->mask, psf->residuals->Ro->type.type); 1023 psImageInit (psf->residuals->mask, 0); 1024 psImageInit (psf->residuals->Rx, 0.0); 1025 psImageInit (psf->residuals->Ry, 0.0); 1026 switch (Nz) { 1027 case 1: // Ro only 1028 break; 1029 case 2: // Ro and mask 1030 if (!psFitsReadImageBuffer(mask, file->fits, fullImage, 1)) { 1031 psError(psErrorCodeLast(), false, "Unable to read PSF residual image."); 1032 return false; 1033 } 1034 psImageCopy (psf->residuals->mask, mask, PM_TYPE_RESID_MASK); 1035 break; 1036 case 3: // Ro, Rx and Ry, no mask 1037 if (!psFitsReadImageBuffer(psf->residuals->Rx, file->fits, fullImage, 1)) { 1038 psError(psErrorCodeLast(), false, "Unable to read PSF residual image."); 1039 return false; 1040 } 1041 if (!psFitsReadImageBuffer(psf->residuals->Ry, file->fits, fullImage, 2)) { 1042 psError(psErrorCodeLast(), false, "Unable to read PSF residual image."); 1043 return false; 1044 } 1045 break; 1046 case 4: // Ro, Rx, Ry, and mask: 1047 if (!psFitsReadImageBuffer(psf->residuals->Rx, file->fits, fullImage, 1)) { 1048 psError(psErrorCodeLast(), false, "Unable to read PSF residual image."); 1049 return false; 1050 } 1051 if (!psFitsReadImageBuffer(psf->residuals->Ry, file->fits, fullImage, 2)) { 1052 psError(psErrorCodeLast(), false, "Unable to read PSF residual image."); 1053 return false; 1054 } 1055 if (!psFitsReadImageBuffer(mask, file->fits, fullImage, 3)) { 1056 psError(psErrorCodeLast(), false, "Unable to read PSF residual image."); 1057 return false; 1058 } 1059 psImageCopy (psf->residuals->mask, mask, PM_TYPE_RESID_MASK); 1060 break; 1061 } 1062 psFree (mask); 874 1063 } 875 1064 -
branches/simtest_nebulous_branches/psModules/src/objects/pmPSFtry.c
r24206 r27840 37 37 #include "pmSourceVisual.h" 38 38 39 bool printTrendMap (pmTrend2D *trend) {40 41 if (!trend->map) return false;42 if (!trend->map->map) return false;43 44 for (int j = 0; j < trend->map->map->numRows; j++) {45 for (int i = 0; i < trend->map->map->numCols; i++) {46 fprintf (stderr, "%5.2f ", trend->map->map->data.F32[j][i]);47 }48 fprintf (stderr, "\t\t\t");49 for (int i = 0; i < trend->map->map->numCols; i++) {50 fprintf (stderr, "%5.2f ", trend->map->error->data.F32[j][i]);51 }52 fprintf (stderr, "\n");53 }54 return true;55 }56 57 bool psImageMapCleanup (psImageMap *map) {58 59 if ((map->map->numRows == 1) && (map->map->numCols == 1)) return true;60 61 // find the weighted average of all pixels62 float Sum = 0.0;63 float Wt = 0.0;64 for (int j = 0; j < map->map->numRows; j++) {65 for (int i = 0; i < map->map->numCols; i++) {66 if (!isfinite(map->map->data.F32[j][i])) continue;67 Sum += map->map->data.F32[j][i] * map->error->data.F32[j][i];68 Wt += map->error->data.F32[j][i];69 }70 }71 72 float Mean = Sum / Wt;73 74 // do any of the pixels in the map need to be repaired?75 // XXX for now, we are just replacing bad pixels with the Mean76 for (int j = 0; j < map->map->numRows; j++) {77 for (int i = 0; i < map->map->numCols; i++) {78 if (isfinite(map->map->data.F32[j][i]) &&79 (map->error->data.F32[j][i] > 0.0)) continue;80 map->map->data.F32[j][i] = Mean;81 }82 }83 return true;84 }85 86 39 // ******** pmPSFtry functions ************************************************** 87 40 // * pmPSFtry holds a single pmPSF model test, with the input sources, the freely … … 110 63 psMemSetDeallocator(test, (psFreeFunc) pmPSFtryFree); 111 64 112 test->psf = pmPSFAlloc (options);65 test->psf = NULL; 113 66 test->metric = psVectorAlloc (sources->n, PS_TYPE_F32); 114 67 test->metricErr = psVectorAlloc (sources->n, PS_TYPE_F32); … … 136 89 } 137 90 91 float psVectorSystematicError (psVector *residuals, psVector *errors, float clipFraction) { 138 92 139 // build a pmPSFtry for the given model: 140 // - fit each source with the free-floating model 141 // - construct the pmPSF from the collection of models 142 // - fit each source with the PSF-parameter models 143 // - measure the pmPSF quality metric (dApResid) 93 psAssert(residuals, "residuals cannot be NULL"); 94 psAssert(errors, "errors cannot be NULL"); 95 psAssert(residuals->n == errors->n, "residuals and errors must be the same length"); 144 96 145 // sources used in for pmPSFtry may be masked by the analysis 146 // mask values indicate the reason the source was rejected: 97 // given a vector of residuals and their formal errors, calculated the necessary systematic 98 // error needed to yield a reduced chisq of 1.0, after first tossing out the clipFraction 99 // highest chi-square contributors (allowed outliers) 147 100 148 // generate a pmPSFtry with a copy of the test PSF sources 149 pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal) 150 { 151 bool status; 152 int Next = 0; 153 int Npsf = 0; 101 psVector *mask = psVectorAlloc(residuals->n, PS_TYPE_VECTOR_MASK); 102 psVector *chisq = psVectorAlloc(residuals->n, PS_TYPE_F32); 154 103 155 // validate the requested model name 156 options->type = pmModelClassGetType (modelName); 157 if (options->type == -1) { 158 psError (PS_ERR_UNKNOWN, true, "invalid model name %s", modelName); 159 return NULL; 104 // calculate the chisq vector: 105 int Ngood = 0; 106 for (int i = 0; i < residuals->n; i++) { 107 chisq->data.F32[i] = PS_MAX_F32; 108 if (!isfinite(residuals->data.F32[i])) continue; 109 if (!isfinite(errors->data.F32[i])) continue; 110 if (errors->data.F32[i] <= 0.0) continue; 111 chisq->data.F32[i] = PS_SQR(residuals->data.F32[i] / errors->data.F32[i]); 112 Ngood ++; 160 113 } 161 114 162 pmPSFtry *psfTry = pmPSFtryAlloc (sources, options); 163 if (psfTry == NULL) { 164 psError (PS_ERR_UNKNOWN, false, "failed to allocate psf model"); 165 return NULL; 115 psVector *index = psVectorSortIndex(NULL, chisq); 116 117 // toss out the clipFraction highest chisq values 118 for (int i = 0; i < residuals->n; i++) { 119 int n = index->data.S32[i]; 120 if (i < (1.0 - clipFraction)*Ngood) { 121 mask->data.PS_TYPE_VECTOR_MASK_DATA[n] = 0; 122 } else { 123 mask->data.PS_TYPE_VECTOR_MASK_DATA[n] = 1; 124 } 166 125 } 167 126 168 // maskVal is used to test for rejected pixels, and must include markVal 169 maskVal |= markVal; 127 // Ndof ~= Ngood 128 // Chisq_Ndof = sum(residuals_i^2 / error_i^2) / Ndof 129 // choose S2 such than Chisq^sys_Ndof = sum(residuals_i^2 / (error_i^2 + S2)) / Ndof = 1.0 130 131 // use Newton-Raphson to solve for S2: 170 132 171 // stage 1: fit an EXT model to all candidates PSF sources -- this is independent of the modeled 2D variations in the PSF 172 psTimerStart ("psf.fit"); 173 for (int i = 0; i < psfTry->sources->n; i++) { 133 // use median sigma to calculate the initial guess for S2: 134 psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN); 135 psVectorStats (stats, errors, NULL, mask, 1); 136 float errorMedian = stats->sampleMedian; 137 138 float nPts = 0.0; 139 float res2mean = 0.0; 140 float ChiSq = 0.0; 141 for (int i = 0; i < residuals->n; i++) { 142 int n = index->data.S32[i]; 143 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[n]) continue; 144 res2mean += PS_SQR(residuals->data.F32[n]); 145 ChiSq += PS_SQR(residuals->data.F32[n]) / PS_SQR(errors->data.F32[n]); 146 nPts += 1.0; 147 } 148 res2mean /= nPts; 149 ChiSq /= nPts; 150 151 float S2guess = res2mean - PS_SQR(errorMedian); 174 152 175 pmSource *source = psfTry->sources->data[i]; 176 if (!source->moments) { 177 psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL; 178 continue; 179 } 180 if (!source->moments->nPixels) { 181 psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL; 182 continue; 183 } 153 psLogMsg ("psModules", 10, "ChiSquare: %f, Ntotal: %ld, Ngood: %d, Nkeep: %.0f, S2 guess: %f\n", 154 ChiSq, residuals->n, Ngood, nPts, S2guess); 184 155 185 source->modelEXT = pmSourceModelGuess (source, psfTry->psf->type); 186 if (source->modelEXT == NULL) { 187 psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL; 188 psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y); 189 continue; 190 } 156 for (int iter = 0; iter < 10; iter++) { 191 157 192 // set object mask to define valid pixels 193 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "OR", markVal); 158 ChiSq = 0.0; 159 float dRdS = 0.0; 160 for (int i = 0; i < residuals->n; i++) { 161 int n = index->data.S32[i]; 162 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[n]) continue; 163 float error2 = PS_SQR(errors->data.F32[n]) + S2guess; 164 ChiSq += PS_SQR(residuals->data.F32[n]) / error2; 165 dRdS += PS_SQR(residuals->data.F32[n]) / PS_SQR(error2); 166 } 167 ChiSq /= nPts; 168 dRdS /= nPts; 194 169 195 // fit model as EXT, not PSF 196 status = pmSourceFitModel (source, source->modelEXT, PM_SOURCE_FIT_EXT, maskVal); 170 // Note the sign on dS: dRdS above is -1 * dR/dS formally 171 float dS = (ChiSq - 1.0) / dRdS; 172 S2guess += dS; 173 S2guess = PS_MAX(0.0, S2guess); 197 174 198 // clear object mask to define valid pixels 199 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_IMAGE_MASK(markVal)); 200 201 // exclude the poor fits 202 if (!status) { 203 psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL; 204 psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y); 205 continue; 206 } 207 Next ++; 208 } 209 psLogMsg ("psphot.psftry", PS_LOG_MINUTIA, "fit ext: %f sec for %d of %ld sources\n", psTimerMark ("psf.fit"), Next, sources->n); 210 psTrace ("psModules.object", 3, "keeping %d of %ld PSF candidates (EXT)\n", Next, sources->n); 211 212 if (Next == 0) { 213 psError(PS_ERR_UNKNOWN, false, "No sources with good extended fits from which to determine PSF."); 214 psFree(psfTry); 215 return NULL; 175 psLogMsg ("psModules", 10, "ChiSquare: %f, dS: %f, S2 guess: %f\n", ChiSq, dS, S2guess); 216 176 } 217 177 218 // stage 2: construct a psf (pmPSF) from this collection of model fits, including the 2D variation 219 if (!pmPSFFromPSFtry (psfTry)) { 220 psError(PS_ERR_UNKNOWN, false, "failed to construct a psf model from collection of sources"); 221 psFree(psfTry); 222 return NULL; 223 } 178 // free local allocations 179 psFree (mask); 180 psFree (chisq); 181 psFree (stats); 182 psFree (index); 224 183 225 // stage 3: refit with fixed shape parameters 226 psTimerStart ("psf.fit"); 227 for (int i = 0; i < psfTry->sources->n; i++) { 228 229 pmSource *source = psfTry->sources->data[i]; 230 231 // masked for: bad model fit, outlier in parameters 232 if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL) { 233 psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : source is masked\n", i, source->peak->x, source->peak->y); 234 continue; 235 } 236 237 // set shape for this model based on PSF 238 source->modelPSF = pmModelFromPSF (source->modelEXT, psfTry->psf); 239 if (source->modelPSF == NULL) { 240 psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_BAD_MODEL; 241 abort(); 242 continue; 243 } 244 source->modelPSF->radiusFit = options->radius; 245 246 // set object mask to define valid pixels 247 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "OR", markVal); 248 249 // fit the PSF model to the source 250 status = pmSourceFitModel (source, source->modelPSF, PM_SOURCE_FIT_PSF, maskVal); 251 252 // skip poor fits 253 if (!status) { 254 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_IMAGE_MASK(markVal)); 255 psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_PSF_FAIL; 256 psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : failed PSF fit\n", i, source->peak->x, source->peak->y); 257 continue; 258 } 259 260 status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal); 261 if (!status || isnan(source->apMag)) { 262 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_IMAGE_MASK(markVal)); 263 psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_BAD_PHOT; 264 psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : poor photometry\n", i, source->peak->x, source->peak->y); 265 continue; 266 } 267 268 // clear object mask to define valid pixels 269 psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_IMAGE_MASK(markVal)); 270 271 psfTry->fitMag->data.F32[i] = source->psfMag; 272 psfTry->metric->data.F32[i] = source->apMag - source->psfMag; 273 psfTry->metricErr->data.F32[i] = source->errMag; 274 275 psTrace ("psModules.object", 6, "keeping source %d (%d) of %ld\n", i, Npsf, psfTry->sources->n); 276 Npsf ++; 277 } 278 psfTry->psf->nPSFstars = Npsf; 279 280 psLogMsg ("psphot.psftry", PS_LOG_MINUTIA, "fit psf: %f sec for %d of %ld sources\n", psTimerMark ("psf.fit"), Npsf, sources->n); 281 psTrace ("psModules.object", 3, "keeping %d of %ld PSF candidates (PSF)\n", Npsf, sources->n); 282 283 if (Npsf == 0) { 284 psError(PS_ERR_UNKNOWN, false, "No sources with good PSF fits after model is built."); 285 psFree(psfTry); 286 return NULL; 287 } 288 289 // measure the chi-square trend as a function of flux (PAR[PM_PAR_I0]) 290 // this should be linear for Poisson errors and quadratic for constant sky errors 291 psVector *flux = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32); 292 psVector *chisq = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32); 293 psVector *mask = psVectorAlloc (psfTry->sources->n, PS_TYPE_VECTOR_MASK); 294 295 // generate the x and y vectors, and mask missing models 296 for (int i = 0; i < psfTry->sources->n; i++) { 297 pmSource *source = psfTry->sources->data[i]; 298 if (source->modelPSF == NULL) { 299 flux->data.F32[i] = 0.0; 300 chisq->data.F32[i] = 0.0; 301 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff; 302 } else { 303 flux->data.F32[i] = source->modelPSF->params->data.F32[PM_PAR_I0]; 304 chisq->data.F32[i] = source->modelPSF->chisq / source->modelPSF->nDOF; 305 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0; 306 } 307 } 308 309 // use 3hi/3lo sigma clipping on the chisq fit 310 psStats *stats = options->stats; 311 312 // linear clipped fit of chisq trend vs flux 313 if (options->chiFluxTrend) { 314 bool result = psVectorClipFitPolynomial1D(psfTry->psf->ChiTrend, options->stats, 315 mask, 0xff, chisq, NULL, flux); 316 psStatsOptions meanStat = psStatsMeanOption(options->stats->options); // Statistic for mean 317 psStatsOptions stdevStat = psStatsStdevOption(options->stats->options); // Statistic for stdev 318 319 psLogMsg ("pmPSFtry", 4, "chisq vs flux fit: %f +/- %f\n", 320 psStatsGetValue(stats, meanStat), psStatsGetValue(stats, stdevStat)); 321 322 psFree(flux); 323 psFree(mask); 324 psFree(chisq); 325 326 if (!result) { 327 psError(PS_ERR_UNKNOWN, false, "Failed to fit psf->ChiTrend"); 328 psFree(psfTry); 329 return NULL; 330 } 331 } 332 333 for (int i = 0; i < psfTry->psf->ChiTrend->nX + 1; i++) { 334 psLogMsg ("pmPSFtry", 4, "chisq vs flux fit term %d: %f +/- %f\n", i, 335 psfTry->psf->ChiTrend->coeff[i]*pow(10000, i), 336 psfTry->psf->ChiTrend->coeffErr[i]*pow(10000,i)); 337 } 338 339 // XXX this function wants aperture radius for pmSourcePhotometry 340 if (!pmPSFtryMetric (psfTry, options)) { 341 psError(PS_ERR_UNKNOWN, false, "Attempt to fit PSF with model %s failed.", modelName); 342 psFree (psfTry); 343 return NULL; 344 } 345 346 psLogMsg ("psphot.pspsf", 3, "try model %s, ap-fit: %f +/- %f : sky bias: %f\n", 347 modelName, psfTry->psf->ApResid, psfTry->psf->dApResid, psfTry->psf->skyBias); 348 349 return (psfTry); 184 return (sqrt(S2guess)); 350 185 } 351 186 352 bool pmPSFtryMetric (pmPSFtry *psfTry, pmPSFOptions *options)353 {354 PS_ASSERT_PTR_NON_NULL(psfTry, false);355 PS_ASSERT_PTR_NON_NULL(options, false);356 PS_ASSERT_PTR_NON_NULL(psfTry->sources, false);357 358 float RADIUS = options->radius;359 360 // the measured (aperture - fit) magnitudes (dA == psfTry->metric)361 // depend on both the true ap-fit (dAo) and the bias in the sky measurement:362 // dA = dAo + dsky/flux363 // where flux is the flux of the star364 // we fit this trend to find the infinite flux aperture correction (dAo),365 // the nominal sky bias (dsky), and the error on dAo366 // the values of dA are contaminated by stars with close neighbors in the aperture367 // we use an outlier rejection to avoid this bias368 369 // r2rflux = radius^2 * ten(0.4*fitMag);370 psVector *r2rflux = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);371 372 for (int i = 0; i < psfTry->sources->n; i++) {373 if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL)374 continue;375 r2rflux->data.F32[i] = PS_SQR(RADIUS) * pow(10.0, 0.4*psfTry->fitMag->data.F32[i]);376 }377 378 // XXX test dump of aperture residual data379 if (psTraceGetLevel("psModules.objects") >= 5) {380 FILE *f = fopen ("apresid.dat", "w");381 for (int i = 0; i < psfTry->sources->n; i++) {382 int keep = (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL);383 384 pmSource *source = psfTry->sources->data[i];385 float x = source->peak->x;386 float y = source->peak->y;387 388 fprintf (f, "%d %d, %f %f %f %f %f %f \n",389 i, keep, x, y,390 psfTry->fitMag->data.F32[i],391 r2rflux->data.F32[i],392 psfTry->metric->data.F32[i],393 psfTry->metricErr->data.F32[i]);394 }395 fclose (f);396 }397 398 // This analysis of the apResid statistics is only approximate. The fitted magnitudes399 // measured at this point (in the PSF fit) use Poisson errors, and are thus biased as a400 // function of magnitude. We re-measure the apResid statistics later in psphot using the401 // linear, constant-error fitting. Do not reject outliers with excessive vigor here.402 403 // fit ApTrend only to r2rflux, ignore x,y,flux variations for now404 // linear clipped fit of ApResid to r2rflux405 psPolynomial1D *poly = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 1);406 poly->coeffMask[1] = PS_POLY_MASK_SET; // fit only a constant offset (no SKYBIAS)407 408 // XXX replace this with a psVectorStats call? since we are not fitting the trend409 bool result = psVectorClipFitPolynomial1D(poly, options->stats, psfTry->mask, PSFTRY_MASK_ALL,410 psfTry->metric, psfTry->metricErr, r2rflux);411 if (!result) {412 psError(PS_ERR_UNKNOWN, false, "Failed to fit clipped poly");413 414 psFree(poly);415 psFree(r2rflux);416 417 return false;418 }419 psStatsOptions stdevStat = psStatsStdevOption(options->stats->options); // Statistic for stdev420 psLogMsg ("pmPSFtryMetric", 4, "apresid: %f +/- %f; from statistics of %ld psf stars\n", poly->coeff[0],421 psStatsGetValue(options->stats, stdevStat), psfTry->sources->n);422 423 424 425 // XXX test dump of fitted model (dump when tracing?)426 if (psTraceGetLevel("psModules.objects") >= 4) {427 FILE *f = fopen ("resid.dat", "w");428 psVector *apfit = psPolynomial1DEvalVector (poly, r2rflux);429 for (int i = 0; i < psfTry->sources->n; i++) {430 int keep = (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL);431 432 pmSource *source = psfTry->sources->data[i];433 float x = source->peak->x;434 float y = source->peak->y;435 436 fprintf (f, "%d %d, %f %f %f %f %f %f %f\n",437 i, keep, x, y,438 psfTry->fitMag->data.F32[i],439 r2rflux->data.F32[i],440 psfTry->metric->data.F32[i],441 psfTry->metricErr->data.F32[i],442 apfit->data.F32[i]);443 }444 fclose (f);445 psFree (apfit);446 }447 448 // XXX drop the skyBias value, or include above??449 psfTry->psf->skyBias = poly->coeff[1];450 psfTry->psf->ApResid = poly->coeff[0];451 psfTry->psf->dApResid = psStatsGetValue(options->stats, stdevStat);452 453 psFree (r2rflux);454 psFree (poly);455 456 return true;457 }458 459 /*460 (aprMag' - fitMag) = rflux*skyBias + ApTrend(x,y)461 (aprMag - rflux*skyBias) - fitMag = ApTrend(x,y)462 (aprMag - rflux*skyBias) = fitMag + ApTrend(x,y)463 */464 465 /*****************************************************************************466 pmPSFFromPSFtry (psfTry): build a PSF model from a collection of467 source->modelEXT entries. The PSF ignores the first 4 (independent) model468 parameters and constructs a polynomial fit to the remaining as a function of469 image coordinate.470 input: psfTry with fitted source->modelEXT collection, pre-allocated psf471 Note: some of the array entries may be NULL (failed fits); ignore them.472 *****************************************************************************/473 bool pmPSFFromPSFtry (pmPSFtry *psfTry)474 {475 PS_ASSERT_PTR_NON_NULL(psfTry, false);476 PS_ASSERT_PTR_NON_NULL(psfTry->sources, false);477 478 pmPSF *psf = psfTry->psf;479 480 // construct the fit vectors from the collection of objects481 psVector *x = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);482 psVector *y = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);483 psVector *z = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);484 485 // construct the x,y terms486 for (int i = 0; i < psfTry->sources->n; i++) {487 pmSource *source = psfTry->sources->data[i];488 if (source->modelEXT == NULL)489 continue;490 491 x->data.F32[i] = source->modelEXT->params->data.F32[PM_PAR_XPOS];492 y->data.F32[i] = source->modelEXT->params->data.F32[PM_PAR_YPOS];493 }494 495 if (!pmPSFFitShapeParams (psf, psfTry->sources, x, y, psfTry->mask)) {496 psFree(x);497 psFree(y);498 psFree(z);499 return false;500 }501 502 // skip the unfitted parameters (X, Y, Io, Sky) and the shape parameters (SXX, SYY, SXY)503 // apply the values of Nx, Ny determined above for E0,E1,E2 to the remaining parameters504 for (int i = 0; i < psf->params->n; i++) {505 switch (i) {506 case PM_PAR_SKY:507 case PM_PAR_I0:508 case PM_PAR_XPOS:509 case PM_PAR_YPOS:510 case PM_PAR_SXX:511 case PM_PAR_SYY:512 case PM_PAR_SXY:513 continue;514 default:515 break;516 }517 518 // select the per-object fitted data for this parameter519 for (int j = 0; j < psfTry->sources->n; j++) {520 pmSource *source = psfTry->sources->data[j];521 if (source->modelEXT == NULL) continue;522 z->data.F32[j] = source->modelEXT->params->data.F32[i];523 }524 525 psImageBinning *binning = psImageBinningAlloc();526 binning->nXruff = psf->trendNx;527 binning->nYruff = psf->trendNy;528 binning->nXfine = psf->fieldNx;529 binning->nYfine = psf->fieldNy;530 531 if (psf->psfTrendMode == PM_TREND_MAP) {532 psImageBinningSetScale (binning, PS_IMAGE_BINNING_CENTER);533 psImageBinningSetSkipByOffset (binning, psf->fieldXo, psf->fieldYo);534 }535 536 // free existing trend, re-alloc537 psFree (psf->params->data[i]);538 psf->params->data[i] = pmTrend2DNoImageAlloc (psf->psfTrendMode, binning, psf->psfTrendStats);539 psFree (binning);540 541 // fit the collection of measured parameters to the PSF 2D model542 // the mask is carried from previous steps and updated with this operation543 // the weight is either the flux error or NULL, depending on 'psf->poissonErrorParams'544 if (!pmTrend2DFit (psf->params->data[i], psfTry->mask, 0xff, x, y, z, NULL)) {545 psError(PS_ERR_UNKNOWN, false, "failed to build psf model for parameter %d", i);546 psFree(x);547 psFree(y);548 psFree(z);549 return false;550 }551 }552 553 // test dump of star parameters vs position (compare with fitted values)554 if (psTraceGetLevel("psModules.objects") >= 4) {555 FILE *f = fopen ("params.dat", "w");556 557 for (int j = 0; j < psfTry->sources->n; j++) {558 pmSource *source = psfTry->sources->data[j];559 if (source == NULL) continue;560 if (source->modelEXT == NULL) continue;561 562 pmModel *modelPSF = pmModelFromPSF (source->modelEXT, psf);563 564 fprintf (f, "%f %f : ", source->modelEXT->params->data.F32[PM_PAR_XPOS], source->modelEXT->params->data.F32[PM_PAR_YPOS]);565 566 for (int i = 0; i < psf->params->n; i++) {567 if (psf->params->data[i] == NULL) continue;568 fprintf (f, "%f %f : ", source->modelEXT->params->data.F32[i], modelPSF->params->data.F32[i]);569 }570 fprintf (f, "%f %d\n", source->modelEXT->chisq, source->modelEXT->nIter);571 572 psFree(modelPSF);573 }574 fclose (f);575 }576 577 psFree (x);578 psFree (y);579 psFree (z);580 return true;581 }582 583 584 bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask) {585 586 // we are doing a robust fit. after each pass, we drop points which are more deviant than587 // three sigma. mask is currently updated for each pass.588 589 // The shape parameters (SXX, SXY, SYY) are strongly coupled. We have to handle them very590 // carefully. First, we convert them to the Ellipse Polarization terms (E0, E1, E2) for591 // each source and fit this set of parameters. These values are less tightly coupled, but592 // are still inter-related. The fitted values do a good job of constraining the major axis593 // and the position angle, but the minor axis is weakly measured. When we apply the PSF594 // model to construct a source model, we convert the fitted values of E0,E1,E2 to the shape595 // parameters, with the constraint that the minor axis must be greater than a minimum596 // threshold.597 598 // convert the measured source shape paramters to polarization terms599 psVector *e0 = psVectorAlloc (sources->n, PS_TYPE_F32);600 psVector *e1 = psVectorAlloc (sources->n, PS_TYPE_F32);601 psVector *e2 = psVectorAlloc (sources->n, PS_TYPE_F32);602 psVector *mag = psVectorAlloc (sources->n, PS_TYPE_F32);603 604 for (int i = 0; i < sources->n; i++) {605 // skip any masked sources (failed to fit one of the model steps or get a magnitude)606 if (srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue;607 608 pmSource *source = sources->data[i];609 assert (source->modelEXT); // all unmasked sources should have modelEXT610 611 psEllipsePol pol = pmPSF_ModelToFit (source->modelEXT->params->data.F32);612 613 e0->data.F32[i] = pol.e0;614 e1->data.F32[i] = pol.e1;615 e2->data.F32[i] = pol.e2;616 617 float flux = source->modelEXT->params->data.F32[PM_PAR_I0];618 mag->data.F32[i] = (flux > 0.0) ? -2.5*log(flux) : -100.0;619 }620 621 if (psf->psfTrendMode == PM_TREND_MAP) {622 float scatterTotal = 0.0;623 float scatterTotalMin = FLT_MAX;624 int entryMin = -1;625 626 psVector *dz = NULL;627 psVector *mask = psVectorAlloc (sources->n, PS_TYPE_VECTOR_MASK);628 629 // check the fit residuals and increase Nx,Ny until the error is minimized630 // pmPSFParamTrend increases the number along the longer of x or y631 for (int i = 1; i <= PS_MAX (psf->trendNx, psf->trendNy); i++) {632 633 // copy srcMask to mask (we do not want the mask values set in pmPSFFitShapeParamsMap to be sticky)634 for (int i = 0; i < mask->n; i++) {635 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i];636 }637 if (!pmPSFFitShapeParamsMap (psf, i, &scatterTotal, mask, x, y, mag, e0, e1, e2, dz)) {638 break;639 }640 641 // store the resulting scatterTotal values and the scales, redo the best642 if (scatterTotal < scatterTotalMin) {643 scatterTotalMin = scatterTotal;644 entryMin = i;645 }646 }647 if (entryMin == -1) {648 psError (PS_ERR_UNKNOWN, false, "failed to find image map for shape params");649 return false;650 }651 652 // copy srcMask to mask (we do not want the mask values set in pmPSFFitShapeParamsMap to be sticky)653 for (int i = 0; i < mask->n; i++) {654 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i];655 }656 if (!pmPSFFitShapeParamsMap (psf, entryMin, &scatterTotal, mask, x, y, mag, e0, e1, e2, dz)) {657 psAbort ("failed pmPSFFitShapeParamsMap on second pass?");658 }659 660 pmTrend2D *trend = psf->params->data[PM_PAR_E0];661 psf->trendNx = trend->map->map->numCols;662 psf->trendNy = trend->map->map->numRows;663 664 // copy mask back to srcMask665 for (int i = 0; i < mask->n; i++) {666 srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = mask->data.PS_TYPE_VECTOR_MASK_DATA[i];667 }668 669 psFree (mask);670 psFree (dz);671 } else {672 673 // XXX iterate Nx, Ny based on scatter?674 // XXX we force the x & y order to be the same675 // modify the order to correspond to the actual number of matched stars:676 int order = PS_MAX (psf->trendNx, psf->trendNy);677 if ((sources->n < 15) && (order >= 3)) order = 2;678 if ((sources->n < 11) && (order >= 2)) order = 1;679 if ((sources->n < 8) && (order >= 1)) order = 0;680 if ((sources->n < 3)) {681 psError (PS_ERR_UNKNOWN, true, "failed to fit polynomial to shape params");682 return false;683 }684 psf->trendNx = order;685 psf->trendNy = order;686 687 // we run 'clipIter' cycles clipping in each of x and y, with only one iteration each.688 // This way, the parameters masked by one of the fits will be applied to the others689 for (int i = 0; i < psf->psfTrendStats->clipIter; i++) {690 691 psStatsOptions meanOption = psStatsMeanOption(psf->psfTrendStats->options);692 psStatsOptions stdevOption = psStatsStdevOption(psf->psfTrendStats->options);693 694 pmTrend2D *trend = NULL;695 float mean, stdev;696 697 // XXX we are using the same stats structure on each pass: do we need to re-init it?698 bool status = true;699 700 trend = psf->params->data[PM_PAR_E0];701 status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e0, NULL);702 mean = psStatsGetValue (trend->stats, meanOption);703 stdev = psStatsGetValue (trend->stats, stdevOption);704 psTrace ("psModules.objects", 4, "clipped E0 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e0->n);705 pmSourceVisualPSFModelResid (trend, x, y, e0, srcMask);706 707 trend = psf->params->data[PM_PAR_E1];708 status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e1, NULL);709 mean = psStatsGetValue (trend->stats, meanOption);710 stdev = psStatsGetValue (trend->stats, stdevOption);711 psTrace ("psModules.objects", 4, "clipped E1 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e1->n);712 pmSourceVisualPSFModelResid (trend, x, y, e1, srcMask);713 714 trend = psf->params->data[PM_PAR_E2];715 status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e2, NULL);716 mean = psStatsGetValue (trend->stats, meanOption);717 stdev = psStatsGetValue (trend->stats, stdevOption);718 psTrace ("psModules.objects", 4, "clipped E2 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e2->n);719 pmSourceVisualPSFModelResid (trend, x, y, e2, srcMask);720 721 if (!status) {722 psError (PS_ERR_UNKNOWN, true, "failed to fit polynomial to shape params");723 return false;724 }725 }726 }727 728 // test dump of the psf parameters729 if (psTraceGetLevel("psModules.objects") >= 4) {730 FILE *f = fopen ("pol.dat", "w");731 fprintf (f, "# x y : e0obs e1obs e2obs : e0fit e1fit e2fit : mask\n");732 for (int i = 0; i < e0->n; i++) {733 fprintf (f, "%f %f : %f %f %f : %f %f %f : %d\n",734 x->data.F32[i], y->data.F32[i],735 e0->data.F32[i], e1->data.F32[i], e2->data.F32[i],736 pmTrend2DEval (psf->params->data[PM_PAR_E0], x->data.F32[i], y->data.F32[i]),737 pmTrend2DEval (psf->params->data[PM_PAR_E1], x->data.F32[i], y->data.F32[i]),738 pmTrend2DEval (psf->params->data[PM_PAR_E2], x->data.F32[i], y->data.F32[i]),739 srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i]);740 }741 fclose (f);742 }743 744 psFree (e0);745 psFree (e1);746 psFree (e2);747 psFree (mag);748 return true;749 }750 751 // fit the shape variations as a psImageMap for the given scale factor752 bool pmPSFFitShapeParamsMap (pmPSF *psf, int scale, float *scatterTotal, psVector *mask, psVector *x, psVector *y, psVector *mag, psVector *e0obs, psVector *e1obs, psVector *e2obs, psVector *dz) {753 754 int Nx, Ny;755 756 // set the map scale to match the aspect ratio : for a scale of 1, we guarantee757 // that we have a single cell758 if (psf->fieldNx > psf->fieldNy) {759 Nx = scale;760 float AR = psf->fieldNy / (float) psf->fieldNx;761 Ny = (int) (Nx * AR + 0.5);762 Ny = PS_MAX (1, Ny);763 } else {764 Ny = scale;765 float AR = psf->fieldNx / (float) psf->fieldNy;766 Nx = (int) (Ny * AR + 0.5);767 Nx = PS_MAX (1, Nx);768 }769 770 // do we have enough sources for this fine of a grid?771 if (x->n < 10*Nx*Ny) {772 return false;773 }774 775 // XXX check this against the exising type776 pmTrend2DMode psfTrendMode = PM_TREND_MAP;777 778 psImageBinning *binning = psImageBinningAlloc();779 binning->nXruff = Nx;780 binning->nYruff = Ny;781 binning->nXfine = psf->fieldNx;782 binning->nYfine = psf->fieldNy;783 psImageBinningSetScale (binning, PS_IMAGE_BINNING_CENTER);784 psImageBinningSetSkipByOffset (binning, psf->fieldXo, psf->fieldYo);785 786 psFree (psf->params->data[PM_PAR_E0]);787 psFree (psf->params->data[PM_PAR_E1]);788 psFree (psf->params->data[PM_PAR_E2]);789 790 int nIter = psf->psfTrendStats->clipIter;791 psf->psfTrendStats->clipIter = 1;792 psf->params->data[PM_PAR_E0] = pmTrend2DNoImageAlloc (psfTrendMode, binning, psf->psfTrendStats);793 psf->params->data[PM_PAR_E1] = pmTrend2DNoImageAlloc (psfTrendMode, binning, psf->psfTrendStats);794 psf->params->data[PM_PAR_E2] = pmTrend2DNoImageAlloc (psfTrendMode, binning, psf->psfTrendStats);795 psFree (binning);796 797 // if the map is 1x1 (a single value), we measure the resulting ensemble scatter798 799 // if the map is more finely sampled, divide the values into two sets: measure the fit from800 // one set and the scatter from the other set.801 psVector *x_fit = NULL;802 psVector *y_fit = NULL;803 psVector *x_tst = NULL;804 psVector *y_tst = NULL;805 806 psVector *e0obs_fit = NULL;807 psVector *e1obs_fit = NULL;808 psVector *e2obs_fit = NULL;809 psVector *e0obs_tst = NULL;810 psVector *e1obs_tst = NULL;811 psVector *e2obs_tst = NULL;812 813 if (scale == 1) {814 x_fit = psMemIncrRefCounter (x);815 y_fit = psMemIncrRefCounter (y);816 x_tst = psMemIncrRefCounter (x);817 y_tst = psMemIncrRefCounter (y);818 e0obs_fit = psMemIncrRefCounter (e0obs);819 e1obs_fit = psMemIncrRefCounter (e1obs);820 e2obs_fit = psMemIncrRefCounter (e2obs);821 e0obs_tst = psMemIncrRefCounter (e0obs);822 e1obs_tst = psMemIncrRefCounter (e1obs);823 e2obs_tst = psMemIncrRefCounter (e2obs);824 } else {825 x_fit = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);826 y_fit = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);827 x_tst = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);828 y_tst = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);829 e0obs_fit = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);830 e1obs_fit = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);831 e2obs_fit = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);832 e0obs_tst = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);833 e1obs_tst = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);834 e2obs_tst = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);835 for (int i = 0; i < e0obs_fit->n; i++) {836 // e0obs->n == 8 or 9:837 // i = 0, 1, 2, 3 : 2i+0 = 0, 2, 4, 6838 // i = 0, 1, 2, 3 : 2i+1 = 1, 3, 5, 7839 x_fit->data.F32[i] = x->data.F32[2*i+0];840 x_tst->data.F32[i] = x->data.F32[2*i+1];841 y_fit->data.F32[i] = y->data.F32[2*i+0];842 y_tst->data.F32[i] = y->data.F32[2*i+1];843 844 e0obs_fit->data.F32[i] = e0obs->data.F32[2*i+0];845 e0obs_tst->data.F32[i] = e0obs->data.F32[2*i+1];846 e1obs_fit->data.F32[i] = e1obs->data.F32[2*i+0];847 e1obs_tst->data.F32[i] = e1obs->data.F32[2*i+1];848 e2obs_fit->data.F32[i] = e2obs->data.F32[2*i+0];849 e2obs_tst->data.F32[i] = e2obs->data.F32[2*i+1];850 }851 }852 853 // the mask marks the values not used to calculate the ApTrend854 psVector *fitMask = psVectorAlloc (x_fit->n, PS_TYPE_VECTOR_MASK);855 // copy mask values to fitMask as a starting point856 for (int i = 0; i < fitMask->n; i++) {857 fitMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = mask->data.PS_TYPE_VECTOR_MASK_DATA[i];858 }859 860 // we run 'clipIter' cycles clipping in each of x and y, with only one iteration each.861 // This way, the parameters masked by one of the fits will be applied to the others862 for (int i = 0; i < nIter; i++) {863 // XXX we are using the same stats structure on each pass: do we need to re-init it?864 psStatsOptions meanOption = psStatsMeanOption(psf->psfTrendStats->options);865 psStatsOptions stdevOption = psStatsStdevOption(psf->psfTrendStats->options);866 867 pmTrend2D *trend = NULL;868 float mean, stdev;869 870 // XXX we are using the same stats structure on each pass: do we need to re-init it?871 bool status = true;872 873 trend = psf->params->data[PM_PAR_E0];874 status &= pmTrend2DFit (trend, fitMask, 0xff, x_fit, y_fit, e0obs_fit, NULL);875 mean = psStatsGetValue (trend->stats, meanOption);876 stdev = psStatsGetValue (trend->stats, stdevOption);877 psTrace ("psModules.objects", 4, "clipped E0 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e0obs_fit->n);878 // printTrendMap (trend);879 psImageMapCleanup (trend->map);880 // printTrendMap (trend);881 pmSourceVisualPSFModelResid (trend, x, y, e0obs, mask);882 883 trend = psf->params->data[PM_PAR_E1];884 status &= pmTrend2DFit (trend, fitMask, 0xff, x_fit, y_fit, e1obs_fit, NULL);885 mean = psStatsGetValue (trend->stats, meanOption);886 stdev = psStatsGetValue (trend->stats, stdevOption);887 psTrace ("psModules.objects", 4, "clipped E1 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e1obs_fit->n);888 // printTrendMap (trend);889 psImageMapCleanup (trend->map);890 // printTrendMap (trend);891 pmSourceVisualPSFModelResid (trend, x, y, e1obs, mask);892 893 trend = psf->params->data[PM_PAR_E2];894 status &= pmTrend2DFit (trend, fitMask, 0xff, x_fit, y_fit, e2obs_fit, NULL);895 mean = psStatsGetValue (trend->stats, meanOption);896 stdev = psStatsGetValue (trend->stats, stdevOption);897 psTrace ("psModules.objects", 4, "clipped E2 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e2obs->n);898 // printTrendMap (trend);899 psImageMapCleanup (trend->map);900 // printTrendMap (trend);901 pmSourceVisualPSFModelResid (trend, x, y, e2obs, mask);902 }903 psf->psfTrendStats->clipIter = nIter; // restore default setting904 905 // construct the fitted values and the residuals906 psVector *e0fit = pmTrend2DEvalVector (psf->params->data[PM_PAR_E0], fitMask, 0xff, x_tst, y_tst);907 psVector *e1fit = pmTrend2DEvalVector (psf->params->data[PM_PAR_E1], fitMask, 0xff, x_tst, y_tst);908 psVector *e2fit = pmTrend2DEvalVector (psf->params->data[PM_PAR_E2], fitMask, 0xff, x_tst, y_tst);909 910 psVector *e0res = (psVector *) psBinaryOp (NULL, (void *) e0obs_tst, "-", (void *) e0fit);911 psVector *e1res = (psVector *) psBinaryOp (NULL, (void *) e1obs_tst, "-", (void *) e1fit);912 psVector *e2res = (psVector *) psBinaryOp (NULL, (void *) e2obs_tst, "-", (void *) e2fit);913 914 // measure scatter for the unfitted points915 // psTraceSetLevel ("psLib.math.vectorSampleStdev", 10);916 // psTraceSetLevel ("psLib.math.vectorClippedStats", 10);917 pmPSFShapeParamsScatter (scatterTotal, e0res, e1res, e2res, fitMask, 0xff, psStatsStdevOption(psf->psfTrendStats->options));918 // psTraceSetLevel ("psLib.math.vectorSampleStdev", 0);919 // psTraceSetLevel ("psLib.math.vectorClippedStats", 0);920 921 psLogMsg ("psphot.psftry", PS_LOG_INFO, "result of %d x %d grid\n", Nx, Ny);922 psLogMsg ("psphot.psftry", PS_LOG_INFO, "systematic scatter: %f\n", *scatterTotal);923 924 psFree (x_fit);925 psFree (y_fit);926 psFree (x_tst);927 psFree (y_tst);928 929 psFree (e0obs_fit);930 psFree (e1obs_fit);931 psFree (e2obs_fit);932 psFree (e0obs_tst);933 psFree (e1obs_tst);934 psFree (e2obs_tst);935 936 psFree (e0fit);937 psFree (e1fit);938 psFree (e2fit);939 940 psFree (e0res);941 psFree (e1res);942 psFree (e2res);943 944 // XXX copy fitMask values back to mask945 for (int i = 0; i < fitMask->n; i++) {946 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = fitMask->data.PS_TYPE_VECTOR_MASK_DATA[i];947 }948 psFree (fitMask);949 950 return true;951 }952 953 // calculate the scatter of the parameters954 bool pmPSFShapeParamsScatter(float *scatterTotal, psVector *e0res, psVector *e1res, psVector *e2res, psVector *mask, psVectorMaskType maskValue, psStatsOptions stdevOpt)955 {956 957 // psStats *stats = psStatsAlloc(stdevOpt);958 psStats *stats = psStatsAlloc(PS_STAT_CLIPPED_STDEV);959 960 // calculate the root-mean-square of E0, E1, E2961 float dEsquare = 0.0;962 psStatsInit (stats);963 if (!psVectorStats (stats, e0res, NULL, mask, maskValue)) {964 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");965 return false;966 }967 dEsquare += PS_SQR(psStatsGetValue(stats, stdevOpt));968 969 psStatsInit (stats);970 if (!psVectorStats (stats, e1res, NULL, mask, maskValue)) {971 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");972 return false;973 }974 dEsquare += PS_SQR(psStatsGetValue(stats, stdevOpt));975 976 psStatsInit (stats);977 if (!psVectorStats (stats, e2res, NULL, mask, maskValue)) {978 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");979 return false;980 }981 dEsquare += PS_SQR(psStatsGetValue(stats, stdevOpt));982 983 *scatterTotal = sqrtf(dEsquare);984 985 psFree(stats);986 return true;987 }988 989 // calculate the minimum scatter of the parameters990 bool pmPSFShapeParamsErrors(float *errorFloor, psVector *mag, psVector *e0res, psVector *e1res,991 psVector *e2res, psVector *mask, int nGroup, psStatsOptions stdevOpt)992 {993 994 psStats *statsS = psStatsAlloc(stdevOpt);995 996 // measure the trend in bins with 10 values each; if < 10 total, use them all997 int nBin = PS_MAX (mag->n / nGroup, 1);998 999 // use mag to group parameters in sequence1000 psVector *index = psVectorSortIndex (NULL, mag);1001 1002 // subset vectors for mag and dap values within the given range1003 psVector *dE0subset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);1004 psVector *dE1subset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);1005 psVector *dE2subset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);1006 psVector *mkSubset = psVectorAllocEmpty (nGroup, PS_TYPE_VECTOR_MASK);1007 1008 int n = 0;1009 float min = INFINITY; // Minimum error1010 for (int i = 0; i < nBin; i++) {1011 int j;1012 int nValid = 0;1013 for (j = 0; (j < nGroup) && (n < mag->n); j++, n++) {1014 int N = index->data.U32[n];1015 dE0subset->data.F32[j] = e0res->data.F32[N];1016 dE1subset->data.F32[j] = e1res->data.F32[N];1017 dE2subset->data.F32[j] = e2res->data.F32[N];1018 1019 mkSubset->data.PS_TYPE_VECTOR_MASK_DATA[j] = mask->data.PS_TYPE_VECTOR_MASK_DATA[N];1020 if (!mask->data.PS_TYPE_VECTOR_MASK_DATA[N]) nValid ++;1021 }1022 if (nValid < 3) continue;1023 1024 dE0subset->n = j;1025 dE1subset->n = j;1026 dE2subset->n = j;1027 mkSubset->n = j;1028 1029 // calculate the root-mean-square of E0, E1, E21030 float dEsquare = 0.0;1031 psStatsInit (statsS);1032 if (!psVectorStats (statsS, dE0subset, NULL, mkSubset, 0xff)) {1033 }1034 dEsquare += PS_SQR(psStatsGetValue(statsS, stdevOpt));1035 1036 psStatsInit (statsS);1037 if (!psVectorStats (statsS, dE1subset, NULL, mkSubset, 0xff)) {1038 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");1039 return false;1040 }1041 dEsquare += PS_SQR(psStatsGetValue(statsS, stdevOpt));1042 1043 psStatsInit (statsS);1044 if (!psVectorStats (statsS, dE2subset, NULL, mkSubset, 0xff)) {1045 psError(PS_ERR_UNKNOWN, false, "failure to measure stats");1046 return false;1047 }1048 dEsquare += PS_SQR(psStatsGetValue(statsS, stdevOpt));1049 1050 if (isfinite(dEsquare)) {1051 float err = sqrtf(dEsquare);1052 if (err < min) {1053 min = err;1054 }1055 }1056 }1057 *errorFloor = min;1058 1059 psFree (dE0subset);1060 psFree (dE1subset);1061 psFree (dE2subset);1062 psFree (mkSubset);1063 1064 psFree(index);1065 1066 psFree(statsS);1067 1068 return true;1069 } -
branches/simtest_nebulous_branches/psModules/src/objects/pmPSFtry.h
r21183 r27840 89 89 * 90 90 */ 91 pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType mark); 91 pmPSFtry *pmPSFtryModel ( 92 const psArray *sources, ///< PSF sources to use in the pmPSF model analysis 93 const char *modelName, ///< human-readable name of desired model 94 pmPSFOptions *options, 95 psImageMaskType maskVal, 96 psImageMaskType mark 97 ); 98 99 /** fit EXT models to all possible psf sources */ 100 bool pmPSFtryFitEXT (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal); 101 102 bool pmPSFtryMakePSF (pmPSFtry *psfTry); 103 104 bool pmPSFtryFitPSF (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal); 92 105 93 106 /** pmPSFtryMetric() … … 97 110 * 98 111 */ 99 bool pmPSFtryMetric( 100 pmPSFtry *psfTry, ///< Add comment. 101 pmPSFOptions *options ///< PSF fitting options 102 ); 112 bool pmPSFtryMetric(pmPSFtry *psfTry); 103 113 104 114 /** pmPSFtryMetric_Alt() … … 112 122 float RADIUS ///< Add comment. 113 123 ); 124 125 bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask); 126 127 float psVectorSystematicError (psVector *residuals, psVector *errors, float clipFraction); 128 129 /// @} 130 # endif 114 131 115 132 /** … … 125 142 * 126 143 */ 127 bool pmPSFFromPSFtry (pmPSFtry *psfTry);128 144 129 bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask);130 bool pmPSFFitShapeParamsMap (pmPSF *psf, int scale, float *scatterTotal, psVector *mask, psVector *x, psVector *y, psVector *mag, psVector *e0obs, psVector *e1obs, psVector *e2obs, psVector *dz);131 bool pmPSFShapeParamsScatter(float *scatterTotal, psVector *e0res, psVector *e1res, psVector *e2res, psVector *mask, psVectorMaskType maskValue, psStatsOptions stdevOpt);132 bool pmPSFShapeParamsErrors (float *errorFloor, psVector *mag, psVector *e0res, psVector *e1res, psVector *e2res, psVector *mask, int nGroup, psStatsOptions stdevOpt);133 134 /// @}135 # endif -
branches/simtest_nebulous_branches/psModules/src/objects/pmPeaks.c
r24623 r27840 60 60 // if min point is too deviant, use the peak value 61 61 // XXX need to calculate dx, dy correctly 62 // 0.5 PIX: peaks are calculated using the pixel index and converted here to pixel coords 62 63 if ((fabs(min.x) < 1.5) && (fabs(min.y) < 1.5)) { 63 peak->xf = min.x + ix + image->col0 ;64 peak->yf = min.y + iy + image->row0 ;64 peak->xf = min.x + ix + image->col0 + 0.5; 65 peak->yf = min.y + iy + image->row0 + 0.5; 65 66 66 67 // These errors are fractional errors, and should be scaled by the … … 73 74 peak->yf = PS_MAX (PS_MIN (peak->yf, image->numRows - 1), image->row0); 74 75 } else { 75 peak->xf = ix ;76 peak->yf = iy ;76 peak->xf = ix + 0.5; 77 peak->yf = iy + 0.5; 77 78 peak->dx = NAN; 78 79 peak->dy = NAN; … … 374 375 psU32 col = 0; 375 376 psU32 row = 0; 376 psArray *list = NULL;377 psArray *list = psArrayAllocEmpty(100); 377 378 378 379 // Find peaks in row 0 only. … … 415 416 416 417 } else { 417 ps Error(PS_ERR_UNKNOWN, true, "peak specifiedvalid column range.");418 psLogMsg ("psModules.objects", 5, "peak specified outside valid column range."); 418 419 } 419 420 } … … 500 501 } 501 502 } else { 502 psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");503 psLogMsg ("psModules.objects", 5, "peak specified outside valid column range."); 503 504 } 504 505 … … 544 545 } 545 546 } else { 546 ps Error(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");547 psLogMsg ("psModules.objects", 5, "peak specified outside valid column range."); 547 548 } 548 549 } -
branches/simtest_nebulous_branches/psModules/src/objects/pmPeaks.h
r20945 r27840 63 63 bool assigned; ///< is peak assigned to a source? 64 64 pmPeakType type; ///< Description of peak. 65 pmFootprint *footprint; ///< reference to containing footprint65 pmFootprint *footprint; ///< reference to containing footprint 66 66 } 67 67 pmPeak; -
branches/simtest_nebulous_branches/psModules/src/objects/pmSource.c
r24874 r27840 3 3 * Functions to define and manipulate sources on images 4 4 * 5 * @author GLG, MHPCC6 * @author EAM, IfA: significant modifications.5 * @author EAM, IfA 6 * @author GLG, MHPCC (initial code base) 7 7 * 8 8 * @version $Revision: 1.70 $ $Name: not supported by cvs2svn $ 9 9 * @date $Date: 2009-02-16 22:29:59 $ 10 * 11 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii 12 * 10 * Copyright 2009 Institute for Astronomy, University of Hawaii 13 11 */ 14 12 … … 48 46 psFree(tmp->maskView); 49 47 psFree(tmp->modelFlux); 50 psFree(tmp->psf Flux);48 psFree(tmp->psfImage); 51 49 psFree(tmp->moments); 52 50 psFree(tmp->modelPSF); … … 54 52 psFree(tmp->modelFits); 55 53 psFree(tmp->extpars); 54 psFree(tmp->moments); 55 psFree(tmp->diffStats); 56 56 psFree(tmp->blends); 57 57 psTrace("psModules.objects", 10, "---- end ----\n"); … … 70 70 psFree (source->maskView); 71 71 psFree (source->modelFlux); 72 psFree (source->psf Flux);72 psFree (source->psfImage); 73 73 74 74 source->pixels = NULL; … … 77 77 source->maskView = NULL; 78 78 source->modelFlux = NULL; 79 source->psf Flux= NULL;79 source->psfImage = NULL; 80 80 return; 81 81 } … … 105 105 source->maskView = NULL; 106 106 source->modelFlux = NULL; 107 source->psf Flux= NULL;107 source->psfImage = NULL; 108 108 source->moments = NULL; 109 109 source->blends = NULL; … … 115 115 source->tmpFlags = 0; 116 116 source->extpars = NULL; 117 source->diffStats = NULL; 118 117 119 source->region = psRegionSet(NAN, NAN, NAN, NAN); 118 120 psMemSetDeallocator(source, (psFreeFunc) sourceFree); 119 121 120 122 // default values are NAN 121 source->psfMag = NAN; 123 source->psfMag = NAN; 124 source->psfFlux = NAN; 125 source->psfFluxErr = NAN; 122 126 source->extMag = NAN; 123 127 source->errMag = NAN; … … 176 180 source->type = in->type; 177 181 source->mode = in->mode; 182 source->imageID = in->imageID; 178 183 179 184 return(source); … … 261 266 mySource->modelFlux = NULL; 262 267 263 // drop the old psf Fluxpixels and force the user to re-create264 psFree (mySource->psf Flux);265 mySource->psf Flux= NULL;268 // drop the old psfImage pixels and force the user to re-create 269 psFree (mySource->psfImage); 270 mySource->psfImage = NULL; 266 271 } 267 272 return extend; … … 277 282 // psphot-specific function which applies the recipe values 278 283 // only apply selection to sources within specified region 279 pmPSFClump pmSourcePSFClump(ps Region *region, psArray *sources, psMetadata *recipe)284 pmPSFClump pmSourcePSFClump(psImage **savedImage, psRegion *region, psArray *sources, float PSF_SN_LIM, float PSF_CLUMP_GRID_SCALE, psF32 SX_MAX, psF32 SY_MAX, psF32 AR_MAX) 280 285 { 281 286 psTrace("psModules.objects", 10, "---- begin ----\n"); 282 287 283 288 psArray *peaks = NULL; 284 pmPSFClump errorClump = {-1.0, -1.0, 0.0, 0.0 };285 pmPSFClump emptyClump = {+0.0, +0.0, 0.0, 0.0 };289 pmPSFClump errorClump = {-1.0, -1.0, 0.0, 0.0, 0, 0.0}; 290 pmPSFClump emptyClump = {+0.0, +0.0, 0.0, 0.0, 0, 0.0}; 286 291 pmPSFClump psfClump; 287 292 288 293 PS_ASSERT_PTR_NON_NULL(sources, errorClump); 289 PS_ASSERT_PTR_NON_NULL(recipe, errorClump);290 291 bool status = true; // Status of MD lookup292 float PSF_SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM");293 if (!status) {294 PSF_SN_LIM = 0;295 }296 float PSF_CLUMP_GRID_SCALE = psMetadataLookupF32(&status, recipe, "PSF_CLUMP_GRID_SCALE");297 if (!status) {298 PSF_CLUMP_GRID_SCALE = 0.1;299 }300 294 301 295 // find the sigmaX, sigmaY clump 302 296 { 303 psF32 SX_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_SX_MAX");304 if (!status) {305 psWarning("MOMENTS_SX_MAX not set in recipe");306 SX_MAX = 10.0;307 }308 psF32 SY_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_SY_MAX");309 if (!status) {310 psWarning("MOMENTS_SY_MAX not set in recipe");311 SY_MAX = 10.0;312 }313 psF32 AR_MAX = psMetadataLookupF32(&status, recipe, "MOMENTS_AR_MAX");314 if (!status) {315 psWarning("MOMENTS_AR_MAX not set in recipe");316 AR_MAX = 3.0;317 }318 297 psF32 AR_MIN = 1.0 / AR_MAX; 319 298 320 299 // construct a sigma-plane image 321 int numCols = SX_MAX / PSF_CLUMP_GRID_SCALE, numRows = SY_MAX / PSF_CLUMP_GRID_SCALE; // Size of sigma-plane image 300 int numCols = 1 + SX_MAX / PSF_CLUMP_GRID_SCALE; // Size of sigma-plane image 301 int numRows = 1 + SY_MAX / PSF_CLUMP_GRID_SCALE; // Size of sigma-plane image 322 302 psTrace("psModules.objects", 10, "sigma-plane dimensions: %dx%d\n", numCols, numRows); 323 303 psImage *splane = psImageAlloc(numCols, numRows, PS_TYPE_F32); // sigma-plane image … … 332 312 } 333 313 334 int x = src->peak->x, y = src->peak->y; // Coordinates of peak 335 if (x < region->x0 || x > region->x1 || y < region->y0 || y > region->y1) { 336 continue; 337 } 314 if (region) { 315 int x = src->peak->x, y = src->peak->y; // Coordinates of peak 316 if (x < region->x0 || x > region->x1 || y < region->y0 || y > region->y1) { 317 continue; 318 } 319 } 338 320 339 321 if (src->mode & PM_SOURCE_MODE_BLEND) { 340 322 continue; 341 323 } 324 325 if (!src->moments->nPixels) continue; 342 326 343 327 if (src->moments->SN < PSF_SN_LIM) { … … 384 368 385 369 // find the peak in this image 386 psStats *stats = psStatsAlloc (PS_STAT_MAX );370 psStats *stats = psStatsAlloc (PS_STAT_MAX | PS_STAT_SAMPLE_STDEV); 387 371 if (!psImageStats (stats, splane, NULL, 0)) { 388 372 psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n"); … … 394 378 psTrace ("psModules.objects", 2, "clump threshold is %f\n", stats[0].max/2); 395 379 396 const bool keep_psf_clump = psMetadataLookupBool(NULL, recipe, "KEEP_PSF_CLUMP"); 397 if (keep_psf_clump) 398 { 399 psMetadataAdd(recipe, PS_LIST_TAIL, 400 "PSF_CLUMP", PS_DATA_IMAGE, "Image of PSF coefficients", splane); 380 psfClump.nSigma = stats->sampleStdev; 381 382 if (savedImage) { 383 *savedImage = psMemIncrRefCounter(splane); 401 384 } 402 385 psFree (splane); … … 404 387 405 388 // if we failed to find a valid peak, return the empty clump (failure signal) 406 if (peaks == NULL) 389 if (peaks == NULL) { 390 psError(PS_ERR_UNKNOWN, false, "failure in peak analysis for PSF clump.\n"); 391 psFree (peaks); 392 return emptyClump; 393 } 394 395 if (peaks->n == 0) 407 396 { 408 397 psLogMsg ("psphot", 3, "failed to find a peak in the PSF clump image\n"); … … 412 401 psLogMsg ("psphot", 3, "no significant peak\n"); 413 402 } 403 psFree (peaks); 414 404 return (emptyClump); 415 405 } … … 430 420 psTrace ("psModules.objects", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->value); 431 421 422 // XXX store the mean sigma? 423 float meanSigma = psfClump.nSigma; 424 psfClump.nStars = clump->value; 425 psfClump.nSigma = clump->value / meanSigma; 426 432 427 // define section window for clump 433 428 minSx = clump->x * PSF_CLUMP_GRID_SCALE - 2.0*PSF_CLUMP_GRID_SCALE; … … 452 447 continue; 453 448 454 if (tmpSrc->peak->x < region->x0) continue; 455 if (tmpSrc->peak->x > region->x1) continue; 456 if (tmpSrc->peak->y < region->y0) continue; 457 if (tmpSrc->peak->y > region->y1) continue; 449 if (region) { 450 if (tmpSrc->peak->x < region->x0) continue; 451 if (tmpSrc->peak->x > region->x1) continue; 452 if (tmpSrc->peak->y < region->y0) continue; 453 if (tmpSrc->peak->y > region->y1) continue; 454 } 458 455 459 456 if (tmpSrc->moments->Mxx < minSx) … … 511 508 *****************************************************************************/ 512 509 513 bool pmSourceRoughClass(psRegion *region, psArray *sources, psMetadata *recipe, pmPSFClump clump, psImageMaskType maskSat)510 bool pmSourceRoughClass(psRegion *region, psArray *sources, float PSF_SN_LIM, float PSF_CLUMP_NSIGMA, pmPSFClump clump, psImageMaskType maskSat) 514 511 { 515 512 psTrace("psModules.objects", 10, "---- begin ----"); 516 513 517 514 PS_ASSERT_PTR_NON_NULL(sources, false); 518 PS_ASSERT_PTR_NON_NULL(recipe, false);519 515 520 516 int Nsat = 0; … … 529 525 psVector *starsn_peaks = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 530 526 psVector *starsn_moments = psVectorAllocEmpty (sources->n, PS_TYPE_F32); 531 532 // get basic parameters, or set defaults533 bool status;534 float PSF_SN_LIM = psMetadataLookupF32 (&status, recipe, "PSF_SN_LIM");535 if (!status) PSF_SN_LIM = 20.0;536 float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");537 if (!status) PSF_CLUMP_NSIGMA = 1.5;538 539 // float INNER_RADIUS = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");540 527 541 528 pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN; … … 893 880 894 881 // if we already have a cached image, re-use that memory 895 source->psf Flux = psImageCopy (source->psfFlux, source->pixels, PS_TYPE_F32);896 psImageInit (source->psf Flux, 0.0);882 source->psfImage = psImageCopy (source->psfImage, source->pixels, PS_TYPE_F32); 883 psImageInit (source->psfImage, 0.0); 897 884 898 885 // in some places (psphotEnsemble), we need a normalized version 899 886 // in others, we just want the model. which is more commonly used? 900 // psf Fluxalways has unity normalization (I0 = 1.0)901 pmModelAdd (source->psf Flux, source->maskObj, source->modelPSF, PM_MODEL_OP_FULL | PM_MODEL_OP_NORM, maskVal);887 // psfImage always has unity normalization (I0 = 1.0) 888 pmModelAdd (source->psfImage, source->maskObj, source->modelPSF, PM_MODEL_OP_FULL | PM_MODEL_OP_NORM, maskVal); 902 889 return true; 903 890 } … … 918 905 pmModel *model = pmSourceGetModel (NULL, source); 919 906 if (model == NULL) return false; // model must be defined 907 908 bool addNoise = mode & PM_MODEL_OP_NOISE; 920 909 921 910 if (source->modelFlux) { … … 940 929 941 930 psF32 **target = source->pixels->data.F32; 942 if ( mode & PM_MODEL_OP_NOISE) {943 // XXX need to scale by the gain... 931 if (addNoise) { 932 // when adding noise, we assume the shape and Io have been modified 944 933 target = source->variance->data.F32; 945 934 } 946 935 947 // XXX need to respect the source and model masks?948 936 for (int iy = 0; iy < source->modelFlux->numRows; iy++) { 949 937 int oy = iy + dY; … … 959 947 } 960 948 } 949 if (!addNoise) { 950 if (add) { 951 source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED; 952 } else { 953 source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED; 954 } 955 } 961 956 return true; 962 957 } 963 958 964 959 psImage *target = source->pixels; 965 if ( mode & PM_MODEL_OP_NOISE) {960 if (addNoise) { 966 961 target = source->variance; 967 962 } 968 963 969 if (add) { 970 status = pmModelAddWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy); 971 } else { 972 status = pmModelSubWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy); 964 if (!addNoise) { 965 if (add) { 966 status = pmModelAddWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy); 967 source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED; 968 } else { 969 status = pmModelSubWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy); 970 source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED; 971 } 973 972 } 974 973 … … 1060 1059 psF32 fA = (A->peak == NULL) ? 0 : A->peak->y; 1061 1060 psF32 fB = (B->peak == NULL) ? 0 : B->peak->y; 1061 1062 psF32 diff = fA - fB; 1063 if (diff > FLT_EPSILON) return (+1); 1064 if (diff < FLT_EPSILON) return (-1); 1065 return (0); 1066 } 1067 1068 // sort by X (ascending) 1069 int pmSourceSortByX (const void **a, const void **b) 1070 { 1071 pmSource *A = *(pmSource **)a; 1072 pmSource *B = *(pmSource **)b; 1073 1074 psF32 fA = (A->peak == NULL) ? 0 : A->peak->x; 1075 psF32 fB = (B->peak == NULL) ? 0 : B->peak->x; 1062 1076 1063 1077 psF32 diff = fA - fB; -
branches/simtest_nebulous_branches/psModules/src/objects/pmSource.h
r24579 r27840 16 16 #include "pmMoments.h" 17 17 #include "pmSourceExtendedPars.h" 18 #include "pmSourceDiffStats.h" 18 19 19 20 /// @addtogroup Objects Object Detection / Analysis Functions … … 38 39 39 40 typedef enum { 40 PM_SOURCE_TMPF_MODEL_GUESS = 0x0001, 41 PM_SOURCE_TMPF_SUBTRACTED = 0x0002, 41 PM_SOURCE_TMPF_MODEL_GUESS = 0x0001, 42 PM_SOURCE_TMPF_SUBTRACTED = 0x0002, 43 PM_SOURCE_TMPF_SIZE_MEASURED = 0x0004, 44 PM_SOURCE_TMPF_SIZE_CR_CANDIDATE = 0x0008, 45 PM_SOURCE_TMPF_MOMENTS_MEASURED = 0x0010, 42 46 } pmSourceTmpF; 43 47 … … 63 67 psImage *maskView; ///< view into global image mask for this object region 64 68 psImage *modelFlux; ///< cached copy of the best model for this source 65 psImage *psf Flux; ///< cached copy of the psf model for this source69 psImage *psfImage; ///< cached copy of the psf model for this source 66 70 pmMoments *moments; ///< Basic moments measured for the object. 67 71 pmModel *modelPSF; ///< PSF Model fit (parameters and type) … … 73 77 psArray *blends; ///< collection of sources thought to be confused with object 74 78 float psfMag; ///< calculated from flux in modelPSF 79 float psfFlux; ///< calculated from flux in modelPSF 80 float psfFluxErr; ///< calculated from flux in modelPSF 75 81 float extMag; ///< calculated from flux in modelEXT 76 82 float errMag; ///< error in psfMag OR extMag (depending on type) … … 81 87 float extNsigma; ///< Nsigma deviation from PSF to EXT 82 88 float sky, skyErr; ///< The sky and its error at the center of the object 89 float apRadius; 83 90 psRegion region; ///< area on image covered by selected pixels 84 91 pmSourceExtendedPars *extpars; ///< extended source parameters 92 pmSourceDiffStats *diffStats; ///< extra parameters for difference detections 93 int imageID; 85 94 }; 86 95 … … 98 107 float Y; 99 108 float dY; 109 int nStars; 110 float nSigma; 100 111 } 101 112 pmPSFClump; … … 172 183 * 173 184 * The return value indicates the success (TRUE) of the operation. 174 * 175 * XXX: Limit the S/N of the candidate sources (part of Metadata)? (TBD). 176 * XXX: Save the clump parameters on the Metadata (TBD) 177 * 178 */ 185 */ 186 179 187 pmPSFClump pmSourcePSFClump( 188 psImage **savedImage, 180 189 psRegion *region, ///< restrict measurement to specified region 181 190 psArray *source, ///< The input pmSource 182 psMetadata *metadata ///< Contains classification parameters 191 float PSF_SN_LIM, 192 float PSF_CLUMP_GRID_SCALE, 193 psF32 SX_MAX, 194 psF32 SY_MAX, 195 psF32 AR_MAX 183 196 ); 184 197 … … 196 209 psRegion *region, ///< restrict measurement to specified region 197 210 psArray *sources, ///< The input pmSources 198 psMetadata *metadata, ///< Contains classification parameters 211 float PSF_SN_LIM, ///< min S/N for source to be used for PSF model 212 float PSF_CLUMP_NSIGMA, ///< size of region around peak of clump for PSF stars 199 213 pmPSFClump clump, ///< Statistics about the PSF clump 200 214 psImageMaskType maskSat ///< Mask value for saturated pixels … … 216 230 float radius, ///< Use a circle of pixels around the peak 217 231 float sigma, ///< size of Gaussian window function (<= 0.0 -> skip window) 218 float minSN ///< minimum pixel significance 232 float minSN, ///< minimum pixel significance 233 psImageMaskType maskVal 219 234 ); 220 235 … … 232 247 int pmSourceSortBySN (const void **a, const void **b); 233 248 int pmSourceSortByY (const void **a, const void **b); 249 int pmSourceSortByX (const void **a, const void **b); 234 250 int pmSourceSortBySeq (const void **a, const void **b); 235 251 -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceExtendedPars.c
r23487 r27840 17 17 #endif 18 18 19 #include <stdio.h>20 #include <math.h>21 #include <string.h>19 // #include <stdio.h> 20 // #include <math.h> 21 // #include <string.h> 22 22 #include <pslib.h> 23 #include "pmHDU.h" 24 #include "pmFPA.h" 25 #include "pmFPAMaskWeight.h" 26 #include "pmSpan.h" 27 #include "pmFootprint.h" 28 #include "pmPeaks.h" 29 #include "pmMoments.h" 30 #include "pmResiduals.h" 31 #include "pmGrowthCurve.h" 32 #include "pmTrend2D.h" 33 #include "pmPSF.h" 34 #include "pmModel.h" 35 #include "pmSource.h" 36 23 // #include "pmHDU.h" 24 // #include "pmFPA.h" 25 // #include "pmFPAMaskWeight.h" 26 // #include "pmSpan.h" 27 // #include "pmFootprint.h" 28 // #include "pmPeaks.h" 29 // #include "pmMoments.h" 30 // #include "pmResiduals.h" 31 // #include "pmGrowthCurve.h" 32 // #include "pmTrend2D.h" 33 // #include "pmPSF.h" 34 // #include "pmModel.h" 35 // #include "pmSource.h" 36 #include "pmSourceExtendedPars.h" 37 38 // pmSourceRadialFlux carries the raw radial flux information, including angular bins 39 static void pmSourceRadialFluxFree(pmSourceRadialFlux *flux) 40 { 41 if (!flux) return; 42 psFree(flux->radii); 43 psFree(flux->fluxes); 44 psFree(flux->theta); 45 psFree(flux->isophotalRadii); 46 } 47 48 pmSourceRadialFlux *pmSourceRadialFluxAlloc() 49 { 50 pmSourceRadialFlux *flux = (pmSourceRadialFlux *)psAlloc(sizeof(pmSourceRadialFlux)); 51 psMemSetDeallocator(flux, (psFreeFunc) pmSourceRadialFluxFree); 52 53 flux->radii = NULL; 54 flux->fluxes = NULL; 55 flux->theta = NULL; 56 flux->isophotalRadii = NULL; 57 58 return flux; 59 } 60 61 bool psMemCheckSourceRadialFlux(psPtr ptr) 62 { 63 PS_ASSERT_PTR(ptr, false); 64 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceRadialFluxFree); 65 } 66 67 // pmSourceEllipticalFlux carries the elliptical renormalized radial flux info 68 static void pmSourceEllipticalFluxFree(pmSourceEllipticalFlux *flux) 69 { 70 if (!flux) return; 71 psFree(flux->radiusElliptical); 72 psFree(flux->fluxElliptical); 73 } 74 75 pmSourceEllipticalFlux *pmSourceEllipticalFluxAlloc() 76 { 77 pmSourceEllipticalFlux *flux = (pmSourceEllipticalFlux *)psAlloc(sizeof(pmSourceEllipticalFlux)); 78 psMemSetDeallocator(flux, (psFreeFunc) pmSourceEllipticalFluxFree); 79 80 flux->radiusElliptical = NULL; 81 flux->fluxElliptical = NULL; 82 83 return flux; 84 } 85 86 bool psMemCheckSourceEllipticalFlux(psPtr ptr) 87 { 88 PS_ASSERT_PTR(ptr, false); 89 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceEllipticalFluxFree); 90 } 91 92 // pmSourceRadialProfile defines flux information in radial bins 93 static void pmSourceRadialProfileFree(pmSourceRadialProfile *profile) 94 { 95 if (!profile) return; 96 psFree(profile->binSB); 97 psFree(profile->binSBstdev); 98 psFree(profile->binSBerror); 99 psFree(profile->binSum); 100 psFree(profile->binFill); 101 psFree(profile->radialBins); 102 psFree(profile->area); 103 } 104 105 pmSourceRadialProfile *pmSourceRadialProfileAlloc() 106 { 107 pmSourceRadialProfile *profile = (pmSourceRadialProfile *)psAlloc(sizeof(pmSourceRadialProfile)); 108 psMemSetDeallocator(profile, (psFreeFunc) pmSourceRadialProfileFree); 109 110 profile->binSB = NULL; 111 profile->binSBstdev = NULL; 112 profile->binSBerror = NULL; 113 profile->binSum = NULL; 114 profile->binFill = NULL; 115 profile->radialBins = NULL; 116 profile->area = NULL; 117 return profile; 118 } 119 120 bool psMemCheckSourceRadialProfile(psPtr ptr) 121 { 122 PS_ASSERT_PTR(ptr, false); 123 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceRadialProfileFree); 124 } 125 126 # if (0) 127 // pmSourceRadialProfileFreeVectors frees the intermediate data values 128 bool pmSourceRadialProfileFreeVectors(pmSourceRadialProfile *profile) { 129 130 psFree(profile->radii); 131 psFree(profile->fluxes); 132 psFree(profile->theta); 133 psFree(profile->isophotalRadii); 134 135 psFree(profile->radiusElliptical); 136 psFree(profile->fluxElliptical); 137 138 // psFree(profile->binSB); 139 // psFree(profile->binSBstdev); 140 // psFree(profile->binSBerror); 141 142 // psFree(profile->radialBins); 143 psFree(profile->area); 144 145 profile->radii = NULL; 146 profile->fluxes = NULL; 147 profile->theta = NULL; 148 profile->isophotalRadii = NULL; 149 150 profile->radiusElliptical = NULL; 151 profile->fluxElliptical = NULL; 152 153 // profile->binSB = NULL; 154 // profile->binSBstdev = NULL; 155 // profile->binSBerror = NULL; 156 157 // profile->radialBins = NULL; 158 profile->area = NULL; 159 160 return true; 161 } 162 # endif 163 164 // *** pmSourceRadialProfileSortPair is a utility function for sorting a pair of vectors 165 # define COMPARE_INDEX(A,B) (index->data.F32[A] < index->data.F32[B]) 166 # define SWAP_INDEX(TYPE,A,B) { \ 167 float tmp; \ 168 if (A != B) { \ 169 tmp = index->data.F32[A]; \ 170 index->data.F32[A] = index->data.F32[B]; \ 171 index->data.F32[B] = tmp; \ 172 tmp = extra->data.F32[A]; \ 173 extra->data.F32[A] = extra->data.F32[B]; \ 174 extra->data.F32[B] = tmp; \ 175 } \ 176 } 177 178 bool pmSourceRadialProfileSortPair (psVector *index, psVector *extra) { 179 180 // sort the vector set by the radius 181 PSSORT (index->n, COMPARE_INDEX, SWAP_INDEX, NONE); 182 return true; 183 } 184 185 // *** pmSourceExtendedPars describes the possible collection of extended flux measurements for a source 37 186 static void pmSourceExtendedParsFree (pmSourceExtendedPars *pars) { 38 187 if (!pars) return; 39 188 40 psFree(pars->profile); 41 psFree(pars->annuli); 42 psFree(pars->isophot); 43 psFree(pars->petrosian); 44 psFree(pars->kron); 189 psFree(pars->radFlux); 190 psFree(pars->ellipticalFlux); 191 psFree(pars->radProfile); 192 psFree(pars->petProfile); 45 193 return; 46 194 } … … 50 198 psMemSetDeallocator(pars, (psFreeFunc) pmSourceExtendedParsFree); 51 199 52 pars->profile = NULL; 53 pars->annuli = NULL; 54 pars->isophot = NULL; 55 pars->petrosian = NULL; 56 pars->kron = NULL; 57 200 pars->radFlux = NULL; 201 pars->ellipticalFlux = NULL; 202 pars->radProfile = NULL; 203 pars->petProfile = NULL; 204 205 pars->petrosianFlux = NAN; 206 pars->petrosianFluxErr = NAN; 207 pars->petrosianRadius = NAN; 208 pars->petrosianRadiusErr = NAN; 209 pars->petrosianR90 = NAN; 210 pars->petrosianR90Err = NAN; 211 pars->petrosianR50 = NAN; 212 pars->petrosianR50Err = NAN; 58 213 return pars; 59 214 } … … 66 221 67 222 68 static void pmSourceRadialProfileFree (pmSourceRadialProfile *profile) { 69 if (!profile) return; 70 71 psFree(profile->radius); 72 psFree(profile->flux); 73 psFree(profile->variance); 223 // *** pmSourceExtendedFlux describes the flux within an elliptical aperture of some kind 224 static void pmSourceExtendedFluxFree (pmSourceExtendedFlux *flux) { 225 if (!flux) return; 74 226 return; 75 227 } 76 228 77 pmSourceRadialProfile *pmSourceRadialProfileAlloc (void) { 78 79 pmSourceRadialProfile *profile = (pmSourceRadialProfile *) psAlloc(sizeof(pmSourceRadialProfile)); 80 psMemSetDeallocator(profile, (psFreeFunc) pmSourceRadialProfileFree); 81 82 profile->radius = NULL; 83 profile->flux = NULL; 84 profile->variance = NULL; 85 86 return profile; 87 } 88 89 bool psMemCheckSourceRadialProfile(psPtr ptr) 90 { 91 PS_ASSERT_PTR(ptr, false); 92 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceRadialProfileFree); 93 } 94 95 96 static void pmSourceIsophotalValuesFree (pmSourceIsophotalValues *isophot) { 97 if (!isophot) return; 98 return; 99 } 100 101 pmSourceIsophotalValues *pmSourceIsophotalValuesAlloc (void) { 102 103 pmSourceIsophotalValues *isophot = (pmSourceIsophotalValues *) psAlloc(sizeof(pmSourceIsophotalValues)); 104 psMemSetDeallocator(isophot, (psFreeFunc) pmSourceIsophotalValuesFree); 105 106 isophot->mag = 0.0; 107 isophot->magErr = 0.0; 108 isophot->rad = 0.0; 109 isophot->radErr = 0.0; 110 111 return isophot; 112 } 113 114 115 bool psMemCheckSourceIsophotalValues(psPtr ptr) 116 { 117 PS_ASSERT_PTR(ptr, false); 118 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceIsophotalValuesFree); 119 } 120 121 122 static void pmSourcePetrosianValuesFree (pmSourcePetrosianValues *petrosian) { 123 if (!petrosian) return; 124 return; 125 } 126 127 pmSourcePetrosianValues *pmSourcePetrosianValuesAlloc (void) { 128 129 pmSourcePetrosianValues *petrosian = (pmSourcePetrosianValues *) psAlloc(sizeof(pmSourcePetrosianValues)); 130 psMemSetDeallocator(petrosian, (psFreeFunc) pmSourcePetrosianValuesFree); 131 132 petrosian->mag = 0.0; 133 petrosian->magErr = 0.0; 134 petrosian->rad = 0.0; 135 petrosian->radErr = 0.0; 136 137 return petrosian; 138 } 139 140 141 bool psMemCheckSourcePetrosianValues(psPtr ptr) 142 { 143 PS_ASSERT_PTR(ptr, false); 144 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourcePetrosianValuesFree); 145 } 146 147 static void pmSourceKronValuesFree (pmSourceKronValues *kron) { 148 if (!kron) return; 149 return; 150 } 151 152 pmSourceKronValues *pmSourceKronValuesAlloc (void) { 153 154 pmSourceKronValues *kron = (pmSourceKronValues *) psAlloc(sizeof(pmSourceKronValues)); 155 psMemSetDeallocator(kron, (psFreeFunc) pmSourceKronValuesFree); 156 157 kron->mag = 0.0; 158 kron->magErr = 0.0; 159 kron->rad = 0.0; 160 kron->radErr = 0.0; 161 162 return kron; 163 } 164 165 166 bool psMemCheckSourceKronValues(psPtr ptr) 167 { 168 PS_ASSERT_PTR(ptr, false); 169 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceKronValuesFree); 170 } 171 172 173 static void pmSourceAnnuliFree (pmSourceAnnuli *annuli) { 174 if (!annuli) return; 175 176 psFree (annuli->flux); 177 psFree (annuli->fluxErr); 178 psFree (annuli->fluxVar); 179 180 return; 181 } 182 183 pmSourceAnnuli *pmSourceAnnuliAlloc (void) { 184 185 pmSourceAnnuli *annuli = (pmSourceAnnuli *) psAlloc(sizeof(pmSourceAnnuli)); 186 psMemSetDeallocator(annuli, (psFreeFunc) pmSourceAnnuliFree); 187 188 annuli->flux = NULL; 189 annuli->fluxErr = NULL; 190 annuli->fluxVar = NULL; 191 192 return annuli; 193 } 194 195 196 bool psMemCheckSourceAnnuli(psPtr ptr) 197 { 198 PS_ASSERT_PTR(ptr, false); 199 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceAnnuliFree); 200 } 229 pmSourceExtendedFlux *pmSourceExtendedFluxAlloc (void) { 230 231 pmSourceExtendedFlux *flux = (pmSourceExtendedFlux *) psAlloc(sizeof(pmSourceExtendedFlux)); 232 psMemSetDeallocator(flux, (psFreeFunc) pmSourceExtendedFluxFree); 233 234 flux->flux = 0.0; 235 flux->fluxErr = 0.0; 236 flux->radius = 0.0; 237 flux->radiusErr = 0.0; 238 239 return flux; 240 } 241 242 243 bool psMemCheckSourceExtendedFlux(psPtr ptr) 244 { 245 PS_ASSERT_PTR(ptr, false); 246 return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceExtendedFluxFree); 247 } -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceExtendedPars.h
r23487 r27840 15 15 16 16 typedef struct { 17 psVector *radius; 18 psVector *flux; 19 psVector *variance; 17 psArray *radii; // radii for raw radial profiles at evenly-spaced angles 18 psArray *fluxes; // fluxes measured at above radii 19 psVector *theta; // angles corresponding to above radial profiles 20 psVector *isophotalRadii; // isophotal radius for the above angles 21 } pmSourceRadialFlux; 22 23 typedef struct { 24 psVector *radiusElliptical; // normalized radial coordinates for all relevant pixels 25 psVector *fluxElliptical; // flux for the above radial coordinates 26 } pmSourceEllipticalFlux; 27 28 typedef struct { 29 psVector *binSB; // mean surface brightness within radial bins 30 psVector *binSBstdev; // scatter of mean surface brightness within radial bins 31 psVector *binSBerror; // formal error on mean surface brightness within radial bins 32 psVector *binSum; // sum of flux within radial bins 33 psVector *binFill; // fraction of area actually lit 34 psVector *radialBins; // radii corresponding to above binnedFlux 35 psVector *area; // differential area of the non-overlapping radial bins 20 36 } pmSourceRadialProfile; 21 37 22 38 typedef struct { 23 psVector *flux; 24 psVector *fluxErr; 25 psVector *fluxVar; 26 } pmSourceAnnuli; 39 float flux; 40 float fluxErr; 41 float radius; 42 float radiusErr; 43 } pmSourceExtendedFlux; 27 44 28 45 typedef struct { 29 float mag; 30 float magErr; 31 float rad; 32 float radErr; 33 } pmSourceIsophotalValues; 34 35 typedef struct { 36 float mag; 37 float magErr; 38 float rad; 39 float radErr; 40 } pmSourcePetrosianValues; 41 42 typedef struct { 43 float mag; 44 float magErr; 45 float rad; 46 float radErr; 47 } pmSourceKronValues; 48 49 typedef struct { 50 pmSourceRadialProfile *profile; 51 pmSourceAnnuli *annuli; 52 pmSourceIsophotalValues *isophot; 53 pmSourcePetrosianValues *petrosian; 54 pmSourceKronValues *kron; 46 pmSourceRadialFlux *radFlux; // raw radial flux information 47 pmSourceEllipticalFlux *ellipticalFlux; // flux for elliptically-renormalized radii 48 pmSourceRadialProfile *radProfile; // surface brightness profile in specified fixed bins 49 pmSourceRadialProfile *petProfile; // surface brightness profile in petrosian bins 50 psEllipseAxes axes; // shape of elliptical contour 51 float petrosianFlux; 52 float petrosianFluxErr; 53 float petrosianRadius; 54 float petrosianRadiusErr; 55 float petrosianR90; 56 float petrosianR90Err; 57 float petrosianR50; 58 float petrosianR50Err; 55 59 } pmSourceExtendedPars; 56 60 57 pmSourceExtendedPars *pmSourceExtendedParsAlloc(void); 61 pmSourceRadialFlux *pmSourceRadialFluxAlloc(); 62 bool psMemCheckSourceRadialFlux(psPtr ptr); 63 64 pmSourceEllipticalFlux *pmSourceEllipticalFluxAlloc(); 65 bool psMemCheckSourceEllipticalFlux(psPtr ptr); 66 67 // *** pmSourceRadialProfile describes the radial profile of a source in elliptical contours, and 68 // intermediate data used to measure the profile 69 pmSourceRadialProfile *pmSourceRadialProfileAlloc(); 70 bool psMemCheckSourceRadialProfile(psPtr ptr); 71 72 // *** pmSourceExtendedPars describes the possible collection of extended flux measurements for a source 73 pmSourceExtendedPars *pmSourceExtendedParsAlloc (void); 58 74 bool psMemCheckSourceExtendedPars(psPtr ptr); 59 pmSourceRadialProfile *pmSourceRadialProfileAlloc(void); 60 bool psMemCheckSourceRadialProfile(psPtr ptr); 61 pmSourceIsophotalValues *pmSourceIsophotalValuesAlloc(void); 62 bool psMemCheckSourceIsophotalValues(psPtr ptr); 63 pmSourcePetrosianValues *pmSourcePetrosianValuesAlloc(void); 64 bool psMemCheckSourcePetrosianValues(psPtr ptr); 65 pmSourceKronValues *pmSourceKronValuesAlloc(void); 66 bool psMemCheckSourceKronValues(psPtr ptr); 67 pmSourceAnnuli *pmSourceAnnuliAlloc(void); 68 bool psMemCheckSourceAnnuli(psPtr ptr); 75 76 // *** pmSourceExtendedFlux describes the flux within an elliptical aperture of some kind 77 pmSourceExtendedFlux *pmSourceExtendedFluxAlloc(void); 78 bool psMemCheckSourceExtendedFlux(psPtr ptr); 79 80 // *** pmSourceRadialProfileSortPair is a utility function for sorting a pair of vectors 81 bool pmSourceRadialProfileSortPair(psVector *index, psVector *extra); 82 83 69 84 70 85 /// @} -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceFitModel.c
r23989 r27840 93 93 } 94 94 95 // skip nan values in image 96 if (!isfinite(source->variance->data.F32[i][j])) { 97 fprintf (stderr, "impossible! %x vs %x\n", source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[i][j], maskVal); 98 continue; 99 } 100 95 101 psVector *coord = psVectorAlloc(2, PS_TYPE_F32); 96 102 97 103 // Convert i/j to image space: 98 coord->data.F32[0] = (psF32) (j + source->pixels->col0); 99 coord->data.F32[1] = (psF32) (i + source->pixels->row0); 104 // 0.5 PIX: the coordinate values must be in pixel coords, not index 105 coord->data.F32[0] = (psF32) (j + 0.5 + source->pixels->col0); 106 coord->data.F32[1] = (psF32) (i + 0.5 + source->pixels->row0); 100 107 x->data[nPix] = (psPtr *) coord; 101 108 y->data.F32[nPix] = source->pixels->data.F32[i][j]; … … 175 182 continue; 176 183 dparams->data.F32[i] = sqrt(covar->data.F32[i][i]); 177 if (psTraceGetLevel("psModules.objects") >= 4) { 178 fprintf (stderr, "%f +/- %f\n", params->data.F32[i], dparams->data.F32[i]); 179 } 184 psTrace ("psModules.objects", 4, "%f +/- %f", params->data.F32[i], dparams->data.F32[i]); 180 185 } 181 186 psTrace ("psModules.objects", 4, "niter: %d, chisq: %f", myMin->iter, myMin->value); … … 186 191 model->nPix = y->n; 187 192 model->nDOF = y->n - nParams; 193 model->chisqNorm = model->chisq / model->nDOF; 188 194 model->flags |= PM_MODEL_STATUS_FITTED; 189 195 if (!fitStatus) model->flags |= PM_MODEL_STATUS_NONCONVERGE; -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceFitSet.c
r23487 r27840 321 321 322 322 for (int j = 0; j < model->params->n; j++, n++) { 323 if (psTraceGetLevel("psModules.objects") >= 4) {324 fprintf (stderr, "%f ", param->data.F32[n]);325 }326 323 model->params->data.F32[j] = param->data.F32[n]; 327 324 model->dparams->data.F32[j] = dparam->data.F32[n]; 325 psTrace ("psModules.objects", 4, "%f +/- %f", param->data.F32[n], dparam->data.F32[n]); 328 326 } 329 327 psTrace ("psModules.objects", 4, " src %d", i); … … 483 481 484 482 // Convert i/j to image space: 485 coord->data.F32[0] = (psF32) (j + source->pixels->col0); 486 coord->data.F32[1] = (psF32) (i + source->pixels->row0); 483 // 0.5 PIX: the coordinate values must be in pixel coords, not index 484 coord->data.F32[0] = (psF32) (j + 0.5 + source->pixels->col0); 485 coord->data.F32[1] = (psF32) (i + 0.5 + source->pixels->row0); 487 486 x->data[nPix] = (psPtr *) coord; 488 487 y->data.F32[nPix] = source->pixels->data.F32[i][j]; -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO.c
r24694 r27840 40 40 #include "pmPSF.h" 41 41 #include "pmModel.h" 42 #include "pmDetections.h" 42 43 #include "pmSource.h" 43 44 #include "pmModelClass.h" 45 #include "pmDetEff.h" 44 46 #include "pmSourceIO.h" 45 47 46 48 #define BLANK_HEADERS "BLANK.HEADERS" // Name of metadata in camera configuration containing header names 47 49 // for putting values into a blank PHU 50 51 // lookup the EXTNAME values used for table data and image header segments 52 static bool sourceExtensions(psString *headname, // Extension name for header 53 psString *dataname, // Extension name for data 54 psString *deteffname, // Extension name for detection efficiency 55 psString *xsrcname, // Extension name for extended sources 56 psString *xfitname, // Extension name for extended fits 57 const pmFPAfile *file, // File of interest 58 const pmFPAview *view // View to level of interest 59 ) 60 { 61 bool status; // Status of MD lookup 62 63 // Menu of EXTNAME rules 64 psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES"); 65 if (!menu) { 66 psError(PS_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config"); 67 return false; 68 } 69 70 // EXTNAME for image header 71 if (headname) { 72 const char *rule = psMetadataLookupStr(&status, menu, "CMF.HEAD"); 73 if (!rule) { 74 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.HEAD in EXTNAME.RULES in camera.config"); 75 return false; 76 } 77 *headname = pmFPAfileNameFromRule(rule, file, view); 78 } 79 80 // EXTNAME for table data 81 if (dataname) { 82 const char *rule = psMetadataLookupStr(&status, menu, "CMF.DATA"); 83 if (!rule) { 84 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DATA in EXTNAME.RULES in camera.config"); 85 return false; 86 } 87 *dataname = pmFPAfileNameFromRule(rule, file, view); 88 } 89 90 // EXTNAME for detection efficiency 91 if (deteffname) { 92 const char *rule = psMetadataLookupStr(&status, menu, "CMF.DETEFF"); 93 if (!rule) { 94 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DETEFF in EXTNAME.RULES in camera.config"); 95 return false; 96 } 97 *deteffname = pmFPAfileNameFromRule(rule, file, view); 98 } 99 100 // EXTNAME for extended source data table 101 if (xsrcname) { 102 const char *rule = psMetadataLookupStr(&status, menu, "CMF.XSRC"); 103 if (!rule) { 104 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XSRC in EXTNAME.RULES in camera.config"); 105 return false; 106 } 107 *xsrcname = pmFPAfileNameFromRule (rule, file, view); 108 } 109 110 if (xfitname) { 111 // EXTNAME for extended source data table 112 const char *rule = psMetadataLookupStr(&status, menu, "CMF.XFIT"); 113 if (!rule) { 114 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XFIT in EXTNAME.RULES in camera.config"); 115 return false; 116 } 117 *xfitname = pmFPAfileNameFromRule (rule, file, view); 118 } 119 120 return true; 121 } 122 48 123 49 124 // translations between psphot object types and dophot object types … … 268 343 pmHDU *hdu; 269 344 psMetadata *updates; 270 psMetadata *outhead;271 272 char *exttype = NULL;273 char *dataname = NULL;274 char *xsrcname = NULL;275 char *xfitname = NULL;276 char *headname = NULL;277 345 278 346 // if sources is NULL, write out an empty table 279 // input / output sources are stored on the readout->analysis as "PSPHOT.SOURCES" -- a better name might be something like PM_SOURCE_DATA 280 psArray *sources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES"); 347 // input / output sources are stored on the readout->analysis as "PSPHOT.DETECTIONS" 348 349 psArray *sources = NULL; 350 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 351 if (detections) { 352 sources = detections->allSources; 353 } 281 354 if (!sources) { 355 detections = pmDetectionsAlloc(); 282 356 sources = psArrayAlloc(0); 283 psMetadataAddArray(readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_META_REPLACE, "Blank array of sources", sources); 284 psFree(sources); // Held onto by the metadata, so we can continue to use 357 detections->allSources = sources; 358 psMetadataAddPtr(readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_DATA_UNKNOWN | PS_META_REPLACE, "Blank array of sources", detections); 359 psFree(detections); // Held onto by the metadata, so we can continue to use 285 360 } 286 361 … … 298 373 break; 299 374 300 case PM_FPA_FILE_CMP: 301 // a SPLIT format : only one header and object table per file 302 hdu = pmFPAviewThisHDU (view, fpa); 303 if (!hdu) { 304 psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find HDU to write sources."); 305 return false; 306 } 307 308 // copy the header to an output header, add the output header data 309 outhead = psMetadataCopy (NULL, hdu->header); 310 311 // copy over the entries saved by PSPHOT 312 updates = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.HEADER"); 313 if (updates) { 314 psMetadataCopy (outhead, updates); 315 } 316 317 // copy over the entries saved by PSASTRO 318 updates = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.HEADER"); 319 if (updates) { 320 psMetadataCopy (outhead, updates); 321 } 322 323 bool status = pmSourcesWriteCMP (sources, file->filename, outhead); 324 psFree (outhead); 325 326 if (!status) { 327 psError(PS_ERR_IO, false, "Failed to write CMP file\n"); 328 return false; 329 } 330 break; 331 332 case PM_FPA_FILE_CMF: 375 case PM_FPA_FILE_CMP: { 376 // a SPLIT format : only one header and object table per file 377 hdu = pmFPAviewThisHDU (view, fpa); 378 if (!hdu) { 379 psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find HDU to write sources."); 380 return false; 381 } 382 383 // copy the header to an output header, add the output header data 384 psMetadata *outhead = psMetadataCopy (NULL, hdu->header); 385 386 // copy over the entries saved by PSPHOT 387 updates = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.HEADER"); 388 if (updates) { 389 psMetadataCopy (outhead, updates); 390 } 391 392 // copy over the entries saved by PSASTRO 393 updates = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.HEADER"); 394 if (updates) { 395 psMetadataCopy (outhead, updates); 396 } 397 398 bool status = pmSourcesWriteCMP (sources, file->filename, outhead); 399 psFree (outhead); 400 401 if (!status) { 402 psError(PS_ERR_IO, false, "Failed to write CMP file\n"); 403 return false; 404 } 405 break; 406 } 407 408 case PM_FPA_FILE_CMF: 333 409 // write a header? (only if this is the first readout for cell) 334 410 // note that the file->header is set to track the last hdu->header written … … 345 421 psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, "PSPHOT"); 346 422 if (!status) { 347 psError(PS_ERR_UNKNOWN, true, "missing recipe PSPHOT in config data");348 return false;423 psError(PS_ERR_UNKNOWN, true, "missing recipe PSPHOT in config data"); 424 return false; 349 425 } 350 426 … … 354 430 355 431 // define the EXTNAME values for the different data segments: 356 { 357 // lookup the EXTNAME values used for table data and image header segments 358 char *rule = NULL; 359 360 // Menu of EXTNAME rules 361 psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES"); 362 if (!menu) { 363 psError(PS_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config"); 364 return false; 365 } 366 367 // EXTNAME for image header 368 rule = psMetadataLookupStr(&status, menu, "CMF.HEAD"); 369 if (!rule) { 370 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.HEAD in EXTNAME.RULES in camera.config"); 371 return false; 372 } 373 headname = pmFPAfileNameFromRule (rule, file, view); 374 375 // EXTNAME for table data 376 rule = psMetadataLookupStr(&status, menu, "CMF.DATA"); 377 if (!rule) { 378 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DATA in EXTNAME.RULES in camera.config"); 379 return false; 380 } 381 dataname = pmFPAfileNameFromRule (rule, file, view); 382 383 if (XSRC_OUTPUT) { 384 // EXTNAME for extended source data table 385 rule = psMetadataLookupStr(&status, menu, "CMF.XSRC"); 386 if (!rule) { 387 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XSRC in EXTNAME.RULES in camera.config"); 388 return false; 389 } 390 xsrcname = pmFPAfileNameFromRule (rule, file, view); 391 } 392 if (XFIT_OUTPUT) { 393 // EXTNAME for extended source data table 394 rule = psMetadataLookupStr(&status, menu, "CMF.XFIT"); 395 if (!rule) { 396 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XFIT in EXTNAME.RULES in camera.config"); 397 return false; 398 } 399 xfitname = pmFPAfileNameFromRule (rule, file, view); 400 } 432 psString headname = NULL; 433 psString dataname = NULL; 434 psString deteffname = NULL; 435 psString xsrcname = NULL; 436 psString xfitname = NULL; 437 if (!sourceExtensions(&headname, &dataname, &deteffname, 438 XSRC_OUTPUT ? &xsrcname : NULL, 439 XFIT_OUTPUT ? &xfitname : NULL, 440 file, view)) { 441 return false; 401 442 } 402 443 … … 456 497 } 457 498 458 // write out the TABLE data segment499 // write out the Object TABLE data segment(s) 459 500 { 460 501 // create a header to hold the output data 461 outhead = psMetadataAlloc ();462 463 exttype = psMemIncrRefCounter (psMetadataLookupStr(&status, recipe, "OUTPUT.FORMAT"));502 psMetadata *outhead = psMetadataAlloc (); 503 504 char *exttype = psMemIncrRefCounter (psMetadataLookupStr(&status, recipe, "OUTPUT.FORMAT")); 464 505 if (!exttype) { 465 506 exttype = psStringCopy ("SMPDATA"); … … 469 510 psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTHEAD", PS_META_REPLACE, "name of image extension w/", headname); 470 511 psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTTYPE", PS_META_REPLACE, "extension type", exttype); 471 psFree (exttype);472 512 473 513 // if we request XSRC output, add the XSRC name to this header 474 514 if (xsrcname) { 475 psMetadataAddStr (outhead, PS_LIST_TAIL, "XSRCNAME", PS_META_REPLACE, "name of XSRC table extension", xsrcname);515 psMetadataAddStr (outhead, PS_LIST_TAIL, "XSRCNAME", PS_META_REPLACE, "name of XSRC table extension", xsrcname); 476 516 } 477 517 if (xfitname) { 478 psMetadataAddStr (outhead, PS_LIST_TAIL, "XFITNAME", PS_META_REPLACE, "name of XFIT table extension", xfitname);518 psMetadataAddStr (outhead, PS_LIST_TAIL, "XFITNAME", PS_META_REPLACE, "name of XFIT table extension", xfitname); 479 519 } 480 520 481 521 // XXX these are case-sensitive since the EXTYPE is case-sensitive 482 status = false;522 status = true; 483 523 if (!strcmp (exttype, "SMPDATA")) { 484 status = pmSourcesWrite_SMPDATA (file->fits, sources, file->header, outhead, dataname);524 status &= pmSourcesWrite_SMPDATA (file->fits, sources, file->header, outhead, dataname); 485 525 } 486 526 if (!strcmp (exttype, "PS1_DEV_0")) { 487 status = pmSourcesWrite_PS1_DEV_0 (file->fits, sources, file->header, outhead, dataname);527 status &= pmSourcesWrite_PS1_DEV_0 (file->fits, sources, file->header, outhead, dataname); 488 528 } 489 529 if (!strcmp (exttype, "PS1_DEV_1")) { 490 status = pmSourcesWrite_PS1_DEV_1 (file->fits, sources, file->header, outhead, dataname);530 status &= pmSourcesWrite_PS1_DEV_1 (file->fits, sources, file->header, outhead, dataname); 491 531 } 492 532 if (!strcmp (exttype, "PS1_CAL_0")) { 493 status = pmSourcesWrite_PS1_CAL_0 (file->fits, readout, sources, file->header, outhead, dataname);533 status &= pmSourcesWrite_PS1_CAL_0 (file->fits, readout, sources, file->header, outhead, dataname); 494 534 } 495 535 if (!strcmp (exttype, "PS1_V1")) { 496 status = pmSourcesWrite_CMF_PS1_V1 (file->fits, readout, sources, file->header, outhead, dataname);536 status &= pmSourcesWrite_CMF_PS1_V1 (file->fits, readout, sources, file->header, outhead, dataname); 497 537 } 498 538 if (!strcmp (exttype, "PS1_V2")) { 499 status = pmSourcesWrite_CMF_PS1_V2 (file->fits, readout, sources, file->header, outhead, dataname); 500 } 539 status &= pmSourcesWrite_CMF_PS1_V2 (file->fits, readout, sources, file->header, outhead, dataname); 540 } 541 if (!strcmp (exttype, "PS1_DV1")) { 542 status &= pmSourcesWrite_CMF_PS1_DV1 (file->fits, readout, sources, file->header, outhead, dataname); 543 } 544 501 545 if (xsrcname) { 502 if (!strcmp (exttype, "PS1_DEV_1")) { 503 status = pmSourcesWrite_PS1_DEV_1_XSRC (file->fits, sources, xsrcname, recipe); 504 } 505 if (!strcmp (exttype, "PS1_CAL_0")) { 506 status = pmSourcesWrite_PS1_CAL_0_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe); 507 } 508 if (!strcmp (exttype, "PS1_V1")) { 509 status = pmSourcesWrite_CMF_PS1_V1_XSRC (file->fits, sources, xsrcname, recipe); 510 } 511 if (!strcmp (exttype, "PS1_V2")) { 512 status = pmSourcesWrite_CMF_PS1_V2_XSRC (file->fits, sources, xsrcname, recipe); 513 } 546 if (!strcmp (exttype, "PS1_DEV_1")) { 547 status &= pmSourcesWrite_PS1_DEV_1_XSRC (file->fits, sources, xsrcname, recipe); 548 } 549 if (!strcmp (exttype, "PS1_CAL_0")) { 550 status &= pmSourcesWrite_PS1_CAL_0_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe); 551 } 552 if (!strcmp (exttype, "PS1_V1")) { 553 status &= pmSourcesWrite_CMF_PS1_V1_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe); 554 } 555 if (!strcmp (exttype, "PS1_V2")) { 556 status &= pmSourcesWrite_CMF_PS1_V2_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe); 557 } 558 if (!strcmp (exttype, "PS1_DV1")) { 559 status &= pmSourcesWrite_CMF_PS1_DV1_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe); 560 } 514 561 } 515 562 if (xfitname) { 516 if (!strcmp (exttype, "PS1_DEV_1")) { 517 status = pmSourcesWrite_PS1_DEV_1_XFIT (file->fits, sources, xfitname); 518 } 519 if (!strcmp (exttype, "PS1_CAL_0")) { 520 status = pmSourcesWrite_PS1_CAL_0_XFIT (file->fits, readout, sources, file->header, xfitname); 521 } 522 if (!strcmp (exttype, "PS1_V1")) { 523 status = pmSourcesWrite_CMF_PS1_V1_XFIT (file->fits, sources, xfitname); 524 } 525 if (!strcmp (exttype, "PS1_V2")) { 526 status = pmSourcesWrite_CMF_PS1_V2_XFIT (file->fits, sources, xfitname); 527 } 528 } 563 if (!strcmp (exttype, "PS1_DEV_1")) { 564 status &= pmSourcesWrite_PS1_DEV_1_XFIT (file->fits, sources, xfitname); 565 } 566 if (!strcmp (exttype, "PS1_CAL_0")) { 567 status &= pmSourcesWrite_PS1_CAL_0_XFIT (file->fits, readout, sources, file->header, xfitname); 568 } 569 if (!strcmp (exttype, "PS1_V1")) { 570 status &= pmSourcesWrite_CMF_PS1_V1_XFIT (file->fits, readout, sources, xfitname); 571 } 572 if (!strcmp (exttype, "PS1_V2")) { 573 status &= pmSourcesWrite_CMF_PS1_V2_XFIT (file->fits, readout, sources, xfitname); 574 } 575 if (!strcmp (exttype, "PS1_DV1")) { 576 status &= pmSourcesWrite_CMF_PS1_DV1_XFIT (file->fits, readout, sources, xfitname); 577 } 578 } 579 psFree (outhead); 580 psFree (exttype); 581 529 582 if (!status) { 530 583 psError(PS_ERR_IO, false, "writing CMF data to %s with format %s\n", file->filename, exttype); 531 psFree (headname); 532 psFree (dataname); 533 psFree (xsrcname); 534 psFree (xfitname); 535 psFree (outhead); 536 return false; 537 } 538 } 584 goto escape; 585 } 586 } 587 588 589 // write out the detection efficiency TABLE segments 590 if (deteffname) { 591 // create a header to hold the output data 592 psMetadata *outhead = psMetadataAlloc (); 593 psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTHEAD", PS_META_REPLACE, "name of image extension w/", headname); 594 psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTTYPE", PS_META_REPLACE, "extension type", "DETEFF"); 595 596 status = pmReadoutWriteDetEff(file->fits, readout, outhead, deteffname); 597 psFree (outhead); 598 599 if (!status) { 600 psError(PS_ERR_IO, false, "writing DETEFF data to %s\n", file->filename); 601 goto escape; 602 } 603 } 604 psFree (headname); 605 psFree (dataname); 606 psFree (xsrcname); 607 psFree (xfitname); 608 psFree (deteffname); 539 609 540 610 psTrace ("pmFPAfile", 5, "wrote ext data %s (type: %d)\n", file->filename, file->type); 541 542 psFree (headname);543 psFree (dataname);544 psFree (xsrcname);545 psFree (xfitname);546 psFree (outhead);547 611 break; 612 613 escape: 614 psFree (headname); 615 psFree (dataname); 616 psFree (xsrcname); 617 psFree (xfitname); 618 psFree (deteffname); 619 return false; 548 620 549 621 default: … … 552 624 } 553 625 return true; 626 554 627 } 555 628 // a MEF CMF file has: PHU, CELL-HEAD, TABLE, CELL-HEAD, TABLE, TABLE, TABLE... … … 572 645 // not needed if only one chip 573 646 if (file->fpa->chips->n == 1) { 574 pmSourceIO_WriteMatchedRefs (file->fits, file->fpa, config);575 return true;647 pmSourceIO_WriteMatchedRefs (file->fits, file->fpa, config); 648 return true; 576 649 } 577 650 … … 885 958 hdu = pmFPAviewThisHDU (view, file->fpa); 886 959 887 // lookup the EXTNAME values used for table data and image header segments 888 char *rule = NULL; 889 // Menu of EXTNAME rules 890 psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES"); 891 if (!menu) { 892 psError(PS_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config"); 893 return false; 894 } 895 // EXTNAME for image header 896 rule = psMetadataLookupStr(&status, menu, "CMF.HEAD"); 897 if (!rule) { 898 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.HEAD in EXTNAME.RULES in camera.config"); 899 return false; 900 } 901 char *headname = pmFPAfileNameFromRule (rule, file, view); 902 // EXTNAME for table data 903 rule = psMetadataLookupStr(&status, menu, "CMF.DATA"); 904 if (!rule) { 905 psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DATA in EXTNAME.RULES in camera.config"); 906 return false; 907 } 908 char *dataname = pmFPAfileNameFromRule (rule, file, view); 960 // define the EXTNAME values for the different data segments: 961 psString headname = NULL; 962 psString dataname = NULL; 963 psString deteffname = NULL; 964 if (!sourceExtensions(&headname, &dataname, &deteffname, NULL, NULL, file, view)) { 965 return false; 966 } 909 967 910 968 // advance to the IMAGE HEADER extension 911 969 if (hdu->header == NULL) { 912 970 // if the IMAGE header does not exist, we have no data for this view 913 if (!psFitsMoveExtName (file->fits, headname)) {971 if (!psFitsMoveExtNameClean (file->fits, headname)) { 914 972 readout->data_exists = false; 915 973 psFree (headname); 916 974 psFree (dataname); 975 psFree (deteffname); 917 976 return true; 918 977 } … … 938 997 if (!tableHeader) psAbort("cannot read table header"); 939 998 999 char *xtension = psMetadataLookupStr (NULL, tableHeader, "XTENSION"); 1000 if (!xtension) psAbort("cannot read table type"); 1001 if (strcmp (xtension, "BINTABLE")) { 1002 psWarning ("no binary table in extension %s, skipping\n", dataname); 1003 return false; 1004 } 1005 940 1006 char *exttype = psMetadataLookupStr (NULL, tableHeader, "EXTTYPE"); 941 1007 if (!exttype) psAbort("cannot read table type"); … … 958 1024 sources = pmSourcesRead_CMF_PS1_V2 (file->fits, hdu->header); 959 1025 } 1026 if (!strcmp (exttype, "PS1_DV1")) { 1027 sources = pmSourcesRead_CMF_PS1_DV1 (file->fits, hdu->header); 1028 } 1029 1030 if (!pmReadoutReadDetEff(file->fits, readout, deteffname)) { 1031 #if 0 1032 psError(PS_ERR_IO, false, "Unable to read detection efficiency"); 1033 return false; 1034 #else 1035 // No great loss 1036 psErrorClear(); 1037 #endif 1038 } 960 1039 } 961 1040 … … 963 1042 psFree (headname); 964 1043 psFree (dataname); 1044 psFree (deteffname); 965 1045 psFree (tableHeader); 966 1046 break; … … 971 1051 } 972 1052 readout->data_exists = true; 973 status = psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY, "input sources", sources); 974 psFree (sources); 1053 1054 pmDetections *detections = pmDetectionsAlloc(); 1055 detections->allSources = sources; 1056 status = psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_DATA_ARRAY, "input sources", detections); 1057 psFree (detections); 975 1058 return true; 976 1059 } … … 1064 1147 bool status; 1065 1148 1066 // select the psf of interest 1067 pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES"); 1068 if (!psf) return false; 1069 return true; 1070 } 1071 1072 1149 // select the detections of interest 1150 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 1151 if (!detections) return false; 1152 if (!detections->allSources) return false; 1153 return true; 1154 } 1155 1156 -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO.h
r24694 r27840 36 36 37 37 bool pmSourcesWrite_CMF_PS1_V1 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname); 38 bool pmSourcesWrite_CMF_PS1_V1_XSRC (psFits *fits, p sArray *sources, char *extname, psMetadata *recipe);39 bool pmSourcesWrite_CMF_PS1_V1_XFIT (psFits *fits, p sArray *sources, char *extname);38 bool pmSourcesWrite_CMF_PS1_V1_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe); 39 bool pmSourcesWrite_CMF_PS1_V1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname); 40 40 41 41 bool pmSourcesWrite_CMF_PS1_V2 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname); 42 bool pmSourcesWrite_CMF_PS1_V2_XSRC (psFits *fits, psArray *sources, char *extname, psMetadata *recipe); 43 bool pmSourcesWrite_CMF_PS1_V2_XFIT (psFits *fits, psArray *sources, char *extname); 42 bool pmSourcesWrite_CMF_PS1_V2_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe); 43 bool pmSourcesWrite_CMF_PS1_V2_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname); 44 45 bool pmSourcesWrite_CMF_PS1_DV1 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname); 46 bool pmSourcesWrite_CMF_PS1_DV1_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe); 47 bool pmSourcesWrite_CMF_PS1_DV1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname); 44 48 45 49 bool pmSource_CMF_WritePHU (const pmFPAview *view, pmFPAfile *file, pmConfig *config); … … 53 57 psArray *pmSourcesRead_CMF_PS1_V1 (psFits *fits, psMetadata *header); 54 58 psArray *pmSourcesRead_CMF_PS1_V2 (psFits *fits, psMetadata *header); 59 psArray *pmSourcesRead_CMF_PS1_DV1 (psFits *fits, psMetadata *header); 55 60 56 61 bool pmSourcesWritePSFs (psArray *sources, char *filename); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c
r24401 r27840 69 69 float magOffset = NAN; 70 70 float exptime = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE"); 71 float zeropt = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS"); 72 float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR"); 71 float zeropt = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP"); 72 if (!isfinite(zeropt)) { 73 zeropt = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS"); 74 } 73 75 if (status1 && status2 && (exptime > 0.0)) { 74 76 magOffset = zeropt + 2.5*log10(exptime); 75 77 } 78 float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR"); 76 79 77 80 // if the sequence is defined, write these in seq order; otherwise … … 128 131 nDOF = model->nDOF; 129 132 nPix = model->nPix; 130 apRadius = model->radiusFit; // XXX should we really use the fitRadius for aperture Radius?133 apRadius = source->apRadius; 131 134 errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0]; 132 135 } else { … … 213 216 214 217 if (table->n == 0) { 215 psFitsWriteBlank(fits, header, extname); 218 if (!psFitsWriteBlank(fits, header, extname)) { 219 psError(psErrorCodeLast(), false, "Unable to write empty sources file."); 220 psFree(table); 221 psFree(header); 222 return false; 223 } 216 224 psFree(table); 217 225 psFree(header); … … 221 229 psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname); 222 230 if (!psFitsWriteTable(fits, header, table, extname)) { 223 psError( PS_ERR_IO, false, "writing ext data %s\n", extname);231 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname); 224 232 psFree(table); 225 233 psFree(header); … … 308 316 source->crNsigma = psMetadataLookupF32 (&status, row, "CR_NSIGMA"); 309 317 source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA"); 318 source->apRadius = psMetadataLookupS32 (&status, row, "AP_MAG_RADIUS"); 310 319 311 320 // note that some older versions used PSF_PROBABILITY: this was not well defined. … … 313 322 model->nDOF = psMetadataLookupS32 (&status, row, "PSF_NDOF"); 314 323 model->nPix = psMetadataLookupS32 (&status, row, "PSF_NPIX"); 315 model->radiusFit = psMetadataLookupS32 (&status, row, "AP_MAG_RADIUS");316 324 317 325 source->moments = pmMomentsAlloc (); … … 331 339 332 340 // XXX this layout is still the same as PS1_DEV_1 333 bool pmSourcesWrite_CMF_PS1_V1_XSRC (psFits *fits, p sArray *sources, char *extname, psMetadata *recipe)341 bool pmSourcesWrite_CMF_PS1_V1_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe) 334 342 { 335 343 … … 353 361 354 362 // which extended source analyses should we perform? 355 bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");356 bool doIsophotal = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");357 bool doAnnuli = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");358 bool doKron = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");363 // bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN"); 364 // bool doIsophotal = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL"); 365 // bool doAnnuli = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI"); 366 // bool doKron = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON"); 359 367 360 368 psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER"); … … 396 404 psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG", PS_DATA_F32, "Sigma in EXT y coordinate", yErr); 397 405 406 # if (0) 398 407 // Petrosian measurements 399 408 // XXX insert header data: petrosian ref radius, flux ratio … … 476 485 } 477 486 487 # endif 478 488 psArrayAdd (table, 100, row); 479 489 psFree (row); … … 481 491 482 492 if (table->n == 0) { 483 psFitsWriteBlank (fits, outhead, extname); 493 if (!psFitsWriteBlank (fits, outhead, extname)) { 494 psError(psErrorCodeLast(), false, "Unable to write empty sources."); 495 psFree(outhead); 496 psFree(table); 497 return false; 498 } 484 499 psFree (outhead); 485 500 psFree (table); … … 489 504 psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname); 490 505 if (!psFitsWriteTable (fits, outhead, table, extname)) { 491 psError( PS_ERR_IO, false, "writing ext data %s\n", extname);506 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname); 492 507 psFree (outhead); 493 508 psFree(table); … … 501 516 502 517 // XXX this layout is still the same as PS1_DEV_1 503 bool pmSourcesWrite_CMF_PS1_V1_XFIT (psFits *fits, p sArray *sources, char *extname)518 bool pmSourcesWrite_CMF_PS1_V1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname) 504 519 { 505 520 … … 607 622 608 623 if (table->n == 0) { 609 psFitsWriteBlank (fits, outhead, extname); 624 if (!psFitsWriteBlank (fits, outhead, extname)) { 625 psError(psErrorCodeLast(), false, "Unable to write empty sources."); 626 psFree(outhead); 627 psFree(table); 628 return false; 629 } 610 630 psFree (outhead); 611 631 psFree (table); … … 615 635 psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname); 616 636 if (!psFitsWriteTable (fits, outhead, table, extname)) { 617 psError( PS_ERR_IO, false, "writing ext data %s\n", extname);637 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname); 618 638 psFree (outhead); 619 639 psFree(table); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c
r24403 r27840 45 45 // followed by a zero-size matrix, followed by the table data 46 46 47 bool pmSourcesWrite_CMF_PS1_V2 (psFits *fits, pmReadout *readout, psArray *sources, 48 psMetadata *imageHeader, psMetadata *tableHeader, char *extname) 47 bool pmSourcesWrite_CMF_PS1_V2 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname) 49 48 { 50 49 PS_ASSERT_PTR_NON_NULL(fits, false); … … 54 53 psArray *table; 55 54 psMetadata *row; 56 int i;57 55 psF32 *PAR, *dPAR; 58 56 psEllipseAxes axes; … … 69 67 float magOffset = NAN; 70 68 float exptime = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE"); 71 float zeropt = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS"); 72 float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR"); 69 float zeropt = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP"); 70 if (!isfinite(zeropt)) { 71 zeropt = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS"); 72 } 73 73 if (status1 && status2 && (exptime > 0.0)) { 74 74 magOffset = zeropt + 2.5*log10(exptime); 75 75 } 76 float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR"); 76 77 77 78 // if the sequence is defined, write these in seq order; otherwise … … 80 81 pmSource *source = (pmSource *) sources->data[0]; 81 82 if (source->seq == -1) { 82 // let's write these out in S/N order83 sources = psArraySort (sources, pmSourceSortBySN);83 // let's write these out in S/N order 84 sources = psArraySort (sources, pmSourceSortBySN); 84 85 } else { 85 sources = psArraySort (sources, pmSourceSortBySeq);86 sources = psArraySort (sources, pmSourceSortBySeq); 86 87 } 87 88 } … … 91 92 // we write out PSF-fits for all sources, regardless of quality. the source flags tell us the state 92 93 // by the time we call this function, all values should be assigned. let's use asserts to be sure in some cases. 93 for (i = 0; i < sources->n; i++) {94 for (int i = 0; i < sources->n; i++) { 94 95 pmSource *source = (pmSource *) sources->data[i]; 95 96 … … 99 100 // generated on Alloc, and would thus be wrong for read in sources. 100 101 if (source->seq == -1) { 101 source->seq = i;102 source->seq = i; 102 103 } 103 104 … … 111 112 yPos = PAR[PM_PAR_YPOS]; 112 113 if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) { 113 xErr = dPAR[PM_PAR_XPOS];114 yErr = dPAR[PM_PAR_YPOS];114 xErr = dPAR[PM_PAR_XPOS]; 115 yErr = dPAR[PM_PAR_YPOS]; 115 116 } else { 116 // in linear-fit mode, there is no error on the centroid117 xErr = source->peak->dx;118 yErr = source->peak->dy;117 // in linear-fit mode, there is no error on the centroid 118 xErr = source->peak->dx; 119 yErr = source->peak->dy; 119 120 } 120 121 if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) { … … 128 129 nDOF = model->nDOF; 129 130 nPix = model->nPix; 130 apRadius = model->radiusFit; // XXX should we really use the fitRadius for aperture Radius?131 apRadius = source->apRadius; 131 132 errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0]; 132 133 } else { … … 209 210 } 210 211 212 // XXX why do we make a copy here to be supplemented with the masks? why not do this in the calling function? 211 213 psMetadata *header = psMetadataCopy(NULL, tableHeader); 212 214 pmSourceMasksHeader(header); 213 215 214 216 if (table->n == 0) { 215 psFitsWriteBlank(fits, header, extname); 217 if (!psFitsWriteBlank(fits, header, extname)) { 218 psError(psErrorCodeLast(), false, "Unable to write blank sources file."); 219 psFree(table); 220 psFree(header); 221 return false; 222 } 216 223 psFree(table); 217 224 psFree(header); … … 221 228 psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname); 222 229 if (!psFitsWriteTable(fits, header, table, extname)) { 223 psError( PS_ERR_IO, false, "writing ext data %s\n", extname);230 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname); 224 231 psFree(table); 225 232 psFree(header); … … 261 268 for (int i = 0; i < numSources; i++) { 262 269 psMetadata *row = psFitsReadTableRow(fits, i); // Table row 270 if (!row) { 271 psError(psErrorCodeLast(), false, "Unable to read row %d of sources", i); 272 psFree(sources); 273 return NULL; 274 } 263 275 264 276 pmSource *source = pmSourceAlloc (); … … 304 316 source->peak->dx = dPAR[PM_PAR_XPOS]; 305 317 source->peak->dy = dPAR[PM_PAR_YPOS]; 318 source->peak->SN = sqrt(source->peak->flux); // XXX a proxy: various functions sort by peak S/N 306 319 307 320 source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF"); 308 321 source->crNsigma = psMetadataLookupF32 (&status, row, "CR_NSIGMA"); 309 322 source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA"); 323 source->apRadius = psMetadataLookupS32 (&status, row, "AP_MAG_RADIUS"); 310 324 311 325 // note that some older versions used PSF_PROBABILITY: this was not well defined. … … 313 327 model->nDOF = psMetadataLookupS32 (&status, row, "PSF_NDOF"); 314 328 model->nPix = psMetadataLookupS32 (&status, row, "PSF_NPIX"); 315 model->radiusFit = psMetadataLookupS32 (&status, row, "AP_MAG_RADIUS");316 329 317 330 source->moments = pmMomentsAlloc (); … … 330 343 } 331 344 332 // XXX this layout is still the same as PS1_DEV_1 333 bool pmSourcesWrite_CMF_PS1_V2_XSRC (psFits *fits, psArray *sources, char *extname, psMetadata *recipe) 345 bool pmSourcesWrite_CMF_PS1_V2_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe) 334 346 { 335 347 … … 340 352 psF32 xPos, yPos; 341 353 psF32 xErr, yErr; 354 int nRow = -1; 342 355 343 356 // create a header to hold the output data … … 347 360 psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTNAME", PS_META_REPLACE, "xsrc table extension", extname); 348 361 362 pmChip *chip = readout->parent->parent; 363 pmFPA *fpa = chip->parent; 364 365 // zero point corrections 366 bool status1 = false; 367 bool status2 = false; 368 float magOffset = 0.0; 369 float exptime = psMetadataLookupF32(&status1, fpa->concepts, "FPA.EXPOSURE"); 370 float zeropt = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP"); 371 if (!isfinite(zeropt)) { 372 zeropt = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS"); 373 } 374 if (status1 && status2 && (exptime > 0.0)) { 375 magOffset = zeropt + 2.5*log10(exptime); 376 } 377 349 378 // let's write these out in S/N order 350 379 sources = psArraySort (sources, pmSourceSortBySN); … … 353 382 354 383 // which extended source analyses should we perform? 384 bool doAnnuli = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI"); 355 385 bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN"); 356 bool doIsophotal = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL"); 357 bool doAnnuli = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI"); 358 bool doKron = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON"); 359 360 psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER"); 361 psVector *radialBinsUpper = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER"); 362 assert (radialBinsLower->n == radialBinsUpper->n); 386 // bool doIsophotal = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL"); 387 // bool doKron = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON"); 388 389 psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER"); 390 psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER"); 391 psAssert (radMin->n == radMax->n, "inconsistent annular bins"); 392 393 // int nRadialBins = 0; 394 // if (doAnnuli) { 395 // // get the max count of radial bins 396 // for (int i = 0; i < sources->n; i++) { 397 // pmSource *source = sources->data[i]; 398 // if (!source->extpars) continue; 399 // if (!source->extpars->radProfile ) continue; 400 // if (!source->extpars->radProfile->binSB) continue; 401 // nRadialBins = PS_MAX(nRadialBins, source->extpars->radProfile->binSB->n); 402 // } 403 // } 363 404 364 405 // we write out all sources, regardless of quality. the source flags tell us the state … … 396 437 psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG", PS_DATA_F32, "Sigma in EXT y coordinate", yErr); 397 438 439 float AxialRatio = NAN; 440 float AxialTheta = NAN; 441 pmSourceExtendedPars *extpars = source->extpars; 442 if (extpars) { 443 AxialRatio = extpars->axes.minor / extpars->axes.major; 444 AxialTheta = extpars->axes.theta; 445 } 446 psMetadataAdd (row, PS_LIST_TAIL, "F25_ARATIO", PS_DATA_F32, "Axial Ratio of radial profile", AxialRatio); 447 psMetadataAdd (row, PS_LIST_TAIL, "F25_THETA", PS_DATA_F32, "Angle of radial profile ellipse", AxialTheta); 448 398 449 // Petrosian measurements 399 450 // XXX insert header data: petrosian ref radius, flux ratio 451 // XXX check flags to see if Pet was measured 400 452 if (doPetrosian) { 401 pmSourcePetrosianValues *petrosian = source->extpars->petrosian; 402 if (petrosian) { 403 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG", PS_DATA_F32, "Petrosian Magnitude", petrosian->mag); 404 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR", PS_DATA_F32, "Petrosian Magnitude Error", petrosian->magErr); 405 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS", PS_DATA_F32, "Petrosian Radius", petrosian->rad); 406 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error", petrosian->radErr); 453 pmSourceExtendedPars *extpars = source->extpars; 454 if (extpars) { 455 // XXX note that this mag is either calibrated or instrumental depending on existence of zero point 456 float mag = (extpars->petrosianFlux > 0.0) ? -2.5*log10(extpars->petrosianFlux) + magOffset : NAN; // XXX zero point 457 float magErr = (extpars->petrosianFlux > 0.0) ? extpars->petrosianFlux / extpars->petrosianFluxErr : NAN; // XXX zero point 458 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG", PS_DATA_F32, "Petrosian Magnitude", mag); 459 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR", PS_DATA_F32, "Petrosian Magnitude Error", magErr); 460 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS", PS_DATA_F32, "Petrosian Radius (pix)", extpars->petrosianRadius); 461 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error (pix)", extpars->petrosianRadiusErr); 462 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50", PS_DATA_F32, "Petrosian R50 (pix)", extpars->petrosianR50); 463 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50_ERR", PS_DATA_F32, "Petrosian R50 Error (pix)", extpars->petrosianR50Err); 464 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90", PS_DATA_F32, "Petrosian R90 (pix)", extpars->petrosianR90); 465 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90_ERR", PS_DATA_F32, "Petrosian R90 Error (pix)", extpars->petrosianR90Err); 407 466 } else { 408 467 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG", PS_DATA_F32, "Petrosian Magnitude", NAN); … … 410 469 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS", PS_DATA_F32, "Petrosian Radius", NAN); 411 470 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error", NAN); 471 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50", PS_DATA_F32, "Petrosian R50 (pix)", NAN); 472 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50_ERR", PS_DATA_F32, "Petrosian R50 Error (pix)",NAN); 473 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90", PS_DATA_F32, "Petrosian R90 (pix)", NAN); 474 psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90_ERR", PS_DATA_F32, "Petrosian R90 Error (pix)",NAN); 412 475 } 413 476 } 414 477 478 # if (0) 415 479 // Kron measurements 416 480 if (doKron) { … … 445 509 } 446 510 } 447 448 // Flux Annuli 511 # endif 512 513 // Flux Annuli (if we have extended source measurements, we have these. only optionally save them) 449 514 if (doAnnuli) { 450 pmSourceAnnuli *annuli = source->extpars->annuli; 451 if (annuli) { 452 psVector *fluxVal = annuli->flux; 453 psVector *fluxErr = annuli->fluxErr; 454 psVector *fluxVar = annuli->fluxVar; 455 456 for (int j = 0; j < fluxVal->n; j++) { 457 char name[32]; 458 sprintf (name, "FLUX_VAL_R_%02d", j); 459 psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux value in annulus", fluxVal->data.F32[j]); 460 sprintf (name, "FLUX_ERR_R_%02d", j); 461 psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux error in annulus", fluxErr->data.F32[j]); 462 sprintf (name, "FLUX_VAR_R_%02d", j); 463 psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux stdev in annulus", fluxVar->data.F32[j]); 464 } 465 } else { 466 for (int j = 0; j < radialBinsLower->n; j++) { 467 char name[32]; 468 sprintf (name, "FLUX_VAL_R_%02d", j); 469 psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux value in annulus", NAN); 470 sprintf (name, "FLUX_ERR_R_%02d", j); 471 psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux error in annulus", NAN); 472 sprintf (name, "FLUX_VAR_R_%02d", j); 473 psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux stdev in annulus", NAN); 474 } 475 } 476 } 477 478 psArrayAdd (table, 100, row); 479 psFree (row); 480 } 481 515 psVector *radSB = psVectorAlloc(radMin->n, PS_TYPE_F32); 516 psVector *radFlux = psVectorAlloc(radMin->n, PS_TYPE_F32); 517 psVector *radFill = psVectorAlloc(radMin->n, PS_TYPE_F32); 518 psVectorInit (radSB, NAN); 519 psVectorInit (radFlux, NAN); 520 psVectorInit (radFill, NAN); 521 if (!source->extpars) goto empty_annuli; 522 if (!source->extpars->radProfile) goto empty_annuli; 523 if (!source->extpars->radProfile->binSB) goto empty_annuli; 524 psAssert (source->extpars->radProfile->binSum, "programming error"); 525 psAssert (source->extpars->radProfile->binFill, "programming error"); 526 psAssert (source->extpars->radProfile->binSB->n <= radFlux->n, "inconsistent vector lengths"); 527 psAssert (source->extpars->radProfile->binSum->n <= radFlux->n, "inconsistent vector lengths"); 528 psAssert (source->extpars->radProfile->binFill->n <= radFlux->n, "inconsistent vector lengths"); 529 530 // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux 531 for (int j = 0; j < source->extpars->radProfile->binSB->n; j++) { 532 radSB->data.F32[j] = source->extpars->radProfile->binSB->data.F32[j]; 533 radFlux->data.F32[j] = source->extpars->radProfile->binSum->data.F32[j]; 534 radFill->data.F32[j] = source->extpars->radProfile->binFill->data.F32[j]; 535 } 536 537 empty_annuli: 538 psMetadataAdd (row, PS_LIST_TAIL, "PROF_SB", PS_DATA_VECTOR, "mean surface brightness annuli", radSB); 539 psMetadataAdd (row, PS_LIST_TAIL, "PROF_FLUX", PS_DATA_VECTOR, "flux within annuli", radFlux); 540 psMetadataAdd (row, PS_LIST_TAIL, "PROF_FILL", PS_DATA_VECTOR, "fill factor of annuli", radFill); 541 psFree (radSB); 542 psFree (radFlux); 543 psFree (radFill); 544 } 545 if (nRow < 0) { 546 nRow = row->list->n; 547 } else { 548 psAssert (nRow == row->list->n, "inconsistent row lengths"); 549 } 550 psArrayAdd (table, 100, row); 551 psFree (row); 552 } 553 482 554 if (table->n == 0) { 483 psFitsWriteBlank (fits, outhead, extname); 484 psFree (outhead); 485 psFree (table); 486 return true; 487 } 488 555 if (!psFitsWriteBlank (fits, outhead, extname)) { 556 psError(psErrorCodeLast(), false, "Unable to write empty sources file."); 557 psFree(outhead); 558 psFree(table); 559 return false; 560 } 561 psFree (outhead); 562 psFree (table); 563 return true; 564 } 565 489 566 psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname); 490 567 if (!psFitsWriteTable (fits, outhead, table, extname)) { 491 psError(PS_ERR_IO, false, "writing ext data %s\n", extname);492 psFree (outhead);493 psFree(table);494 return false;568 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname); 569 psFree (outhead); 570 psFree(table); 571 return false; 495 572 } 496 573 psFree (outhead); 497 574 psFree (table); 498 575 499 576 return true; 500 577 } 501 578 502 579 // XXX this layout is still the same as PS1_DEV_1 503 bool pmSourcesWrite_CMF_PS1_V2_XFIT (psFits *fits, p sArray *sources, char *extname)580 bool pmSourcesWrite_CMF_PS1_V2_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname) 504 581 { 505 582 … … 607 684 608 685 if (table->n == 0) { 609 psFitsWriteBlank (fits, outhead, extname); 686 if (!psFitsWriteBlank (fits, outhead, extname)) { 687 psError(psErrorCodeLast(), false, "Unable to write empty sources file."); 688 psFree(outhead); 689 psFree(table); 690 return false; 691 } 610 692 psFree (outhead); 611 693 psFree (table); … … 615 697 psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname); 616 698 if (!psFitsWriteTable (fits, outhead, table, extname)) { 617 psError( PS_ERR_IO, false, "writing ext data %s\n", extname);699 psError(psErrorCodeLast(), false, "writing ext data %s\n", extname); 618 700 psFree (outhead); 619 701 psFree(table); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO_MatchedRefs.c
r24801 r27840 67 67 68 68 if (!table) { 69 table = psArrayAllocEmpty (0x1000);70 pmFPAview *view = pmFPAviewAlloc (0);69 table = psArrayAllocEmpty (0x1000); 70 pmFPAview *view = pmFPAviewAlloc (0); 71 71 72 // this loop selects the matched stars for all chips73 while ((chip = pmFPAviewNextChip (view, fpa, 1)) != NULL) {74 psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);75 if (!chip->process || !chip->file_exists) continue;72 // this loop selects the matched stars for all chips 73 while ((chip = pmFPAviewNextChip (view, fpa, 1)) != NULL) { 74 psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process); 75 if (!chip->process || !chip->file_exists) continue; 76 76 77 char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME");77 char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME"); 78 78 79 while ((cell = pmFPAviewNextCell (view, fpa, 1)) != NULL) {80 psTrace ("psastro", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);81 if (!cell->process || !cell->file_exists) continue;79 while ((cell = pmFPAviewNextCell (view, fpa, 1)) != NULL) { 80 psTrace ("psastro", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process); 81 if (!cell->process || !cell->file_exists) continue; 82 82 83 // process each of the readouts84 // XXX there can only be one readout per chip, right?85 while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) {86 if (! readout->data_exists) continue;83 // process each of the readouts 84 // XXX there can only be one readout per chip, right? 85 while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) { 86 if (! readout->data_exists) continue; 87 87 88 // select the raw objects for this readout89 psArray *rawstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.RAWSTARS");90 if (rawstars == NULL) continue;88 // select the raw objects for this readout 89 psArray *rawstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.RAWSTARS"); 90 if (rawstars == NULL) continue; 91 91 92 // select the raw objects for this readout93 psArray *refstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.REFSTARS");94 if (refstars == NULL) continue;95 psTrace ("psastro", 4, "Trying %ld refstars\n", refstars->n);92 // select the raw objects for this readout 93 psArray *refstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.REFSTARS"); 94 if (refstars == NULL) continue; 95 psTrace ("psastro", 4, "Trying %ld refstars\n", refstars->n); 96 96 97 97 # if (0) 98 // XXX test99 FILE *outfile = fopen ("refstars.dat", "w");100 assert (outfile);101 for (int nn = 0; nn < refstars->n; nn++) {102 pmAstromObj *ref = refstars->data[nn];103 fprintf (outfile, "%lf %lf\n", ref->sky->r*PS_DEG_RAD, ref->sky->d*PS_DEG_RAD);104 }105 fclose (outfile);98 // XXX test 99 FILE *outfile = fopen ("refstars.dat", "w"); 100 assert (outfile); 101 for (int nn = 0; nn < refstars->n; nn++) { 102 pmAstromObj *ref = refstars->data[nn]; 103 fprintf (outfile, "%lf %lf\n", ref->sky->r*PS_DEG_RAD, ref->sky->d*PS_DEG_RAD); 104 } 105 fclose (outfile); 106 106 # endif 107 107 108 psArray *matches = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.MATCH");109 if (matches == NULL) continue;108 psArray *matches = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.MATCH"); 109 if (matches == NULL) continue; 110 110 111 for (int i = 0; i < matches->n; i++) {112 pmAstromMatch *match = matches->data[i];111 for (int i = 0; i < matches->n; i++) { 112 pmAstromMatch *match = matches->data[i]; 113 113 114 pmAstromObj *raw = rawstars->data[match->raw];115 pmAstromObj *ref = refstars->data[match->ref];114 pmAstromObj *raw = rawstars->data[match->raw]; 115 pmAstromObj *ref = refstars->data[match->ref]; 116 116 117 psMetadata *row = psMetadataAlloc (); 118 psMetadataAdd (row, PS_LIST_TAIL, "RA", PS_DATA_F64, "right ascension (deg, J2000)", PM_DEG_RAD*ref->sky->r); 119 psMetadataAdd (row, PS_LIST_TAIL, "DEC", PS_DATA_F64, "declination (deg, J2000)", PM_DEG_RAD*ref->sky->d); 120 psMetadataAdd (row, PS_LIST_TAIL, "X_CHIP", PS_DATA_F32, "x coord on chip", raw->chip->x); 121 psMetadataAdd (row, PS_LIST_TAIL, "Y_CHIP", PS_DATA_F32, "y coord on chip", raw->chip->y); 122 psMetadataAdd (row, PS_LIST_TAIL, "X_FPA", PS_DATA_F32, "x coord on focal plane", raw->FP->x); 123 psMetadataAdd (row, PS_LIST_TAIL, "Y_FPA", PS_DATA_F32, "y coord on focal plane", raw->FP->y); 124 psMetadataAdd (row, PS_LIST_TAIL, "MAG_INST", PS_DATA_F32, "instrumental magnitude", raw->Mag); 125 psMetadataAdd (row, PS_LIST_TAIL, "MAG_REF", PS_DATA_F32, "reference star magnitude", ref->Mag); 126 psMetadataAdd (row, PS_LIST_TAIL, "COLOR_REF",PS_DATA_F32, "reference star color", ref->Color); 127 psMetadataAdd (row, PS_LIST_TAIL, "CHIP_ID", PS_DATA_STRING, "chip identifier", chipName); 128 // XXX need to add the reference color, but this needs getstar / dvo.photcodes for the reference to be refined. 117 psMetadata *row = psMetadataAlloc (); 118 psMetadataAdd (row, PS_LIST_TAIL, "RA", PS_DATA_F64, "right ascension (deg, J2000)", PM_DEG_RAD*ref->sky->r); 119 psMetadataAdd (row, PS_LIST_TAIL, "DEC", PS_DATA_F64, "declination (deg, J2000)", PM_DEG_RAD*ref->sky->d); 120 psMetadataAdd (row, PS_LIST_TAIL, "X_CHIP", PS_DATA_F32, "x coord on chip", raw->chip->x); 121 psMetadataAdd (row, PS_LIST_TAIL, "Y_CHIP", PS_DATA_F32, "y coord on chip", raw->chip->y); 122 psMetadataAdd (row, PS_LIST_TAIL, "X_CHIP_FIT",PS_DATA_F32, "x fitted coord on chip", ref->chip->x); 123 psMetadataAdd (row, PS_LIST_TAIL, "Y_CHIP_FIT",PS_DATA_F32, "y fitted coord on chip", ref->chip->y); 124 psMetadataAdd (row, PS_LIST_TAIL, "X_FPA", PS_DATA_F32, "x coord on focal plane", raw->FP->x); 125 psMetadataAdd (row, PS_LIST_TAIL, "Y_FPA", PS_DATA_F32, "y coord on focal plane", raw->FP->y); 126 psMetadataAdd (row, PS_LIST_TAIL, "MAG_INST", PS_DATA_F32, "instrumental magnitude", raw->Mag); 127 psMetadataAdd (row, PS_LIST_TAIL, "MAG_REF", PS_DATA_F32, "reference star magnitude", ref->Mag); 128 psMetadataAdd (row, PS_LIST_TAIL, "COLOR_REF",PS_DATA_F32, "reference star color", ref->Color); 129 psMetadataAdd (row, PS_LIST_TAIL, "CHIP_ID", PS_DATA_STRING, "chip identifier", chipName); 130 // XXX need to add the reference color, but this needs getstar / dvo.photcodes for the reference to be refined. 129 131 130 psArrayAdd (table, 100, row);131 psFree (row);132 }133 }134 }135 }136 psFree (view);132 psArrayAdd (table, 100, row); 133 psFree (row); 134 } 135 } 136 } 137 } 138 psFree (view); 137 139 138 if (table->n == 0) {139 psFree(table);140 return true;141 }140 if (table->n == 0) { 141 psFree(table); 142 return true; 143 } 142 144 } 143 145 144 146 if (!psFitsWriteTable(fits, NULL, table, "MATCHED_REFS")) { 145 psError( PS_ERR_IO, false, "writing MATCHED_REFS\n");147 psError(psErrorCodeLast(), false, "writing MATCHED_REFS\n"); 146 148 psFree(table); 147 149 return false; … … 161 163 162 164 // try find the MATCHED_REFS extension. if non-existent, note that we tried, and move on. 163 if (!psFitsMoveExtName (fits, "MATCHED_REFS")) { 164 psMetadataAddBool (fpa->analysis, PS_LIST_TAIL, "READ.REFMATCH", PS_META_REPLACE, "attempted to read MATCHED_REFS", true); 165 return true; 165 // It is not an error to lack this entry -- psFitsMoveExtNameClean does not raise an error 166 if (!psFitsMoveExtNameClean (fits, "MATCHED_REFS")) { 167 psMetadataAddBool (fpa->analysis, PS_LIST_TAIL, "READ.REFMATCH", PS_META_REPLACE, "attempted to read MATCHED_REFS", true); 168 return true; 166 169 } 167 170 168 171 // We get the size of the table, and allocate the array of sources first because the table 169 172 // is large and ephemeral --- when the table gets blown away, whatever is allocated after … … 175 178 for (int i = 0; i < numRows; i++) { 176 179 psMetadata *row = psFitsReadTableRow(fits, i); // Table row 177 rows->data[i] = row; 180 if (!row) { 181 psError(psErrorCodeLast(), false, "Unable to read row %d of matched references.", i); 182 psFree(rows); 183 return false; 184 } 185 rows->data[i] = row; 178 186 } 179 187 -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO_PS1_CAL_0.c
r21516 r27840 282 282 pmPSF_AxesToModel (PAR, axes); 283 283 284 float lflux = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG"); 285 float flux = (isfinite(lflux)) ? pow(10.0, -0.4*lflux) : NAN; 286 source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], flux, PM_PEAK_LONE); 287 source->peak->flux = flux; 284 float peakMag = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG"); 285 float peakFlux = (isfinite(peakMag)) ? pow(10.0, -0.4*peakMag) : NAN; 286 287 source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE); 288 source->peak->flux = peakFlux; 289 source->peak->dx = dPAR[PM_PAR_XPOS]; 290 source->peak->dy = dPAR[PM_PAR_YPOS]; 288 291 289 292 source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF"); … … 349 352 350 353 // which extended source analyses should we perform? 351 bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");352 bool doIsophotal = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");353 bool doAnnuli = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");354 bool doKron = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");354 // bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN"); 355 // bool doIsophotal = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL"); 356 // bool doAnnuli = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI"); 357 // bool doKron = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON"); 355 358 356 359 psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER"); … … 410 413 psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG", PS_DATA_F32, "Sigma in EXT y coordinate", yErr); 411 414 415 # if (0) 412 416 // Petrosian measurements 413 417 // XXX insert header data: petrosian ref radius, flux ratio … … 501 505 } 502 506 } 507 # endif 503 508 504 509 psArrayAdd (table, 100, row); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO_PS1_DEV_0.c
r20937 r27840 208 208 pmPSF_AxesToModel (PAR, axes); 209 209 210 float lflux = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG"); 211 float flux = (isfinite(lflux)) ? pow(10.0, -0.4*lflux) : NAN; 212 source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], flux, PM_PEAK_LONE); 213 source->peak->flux = flux; 210 float peakMag = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG"); 211 float peakFlux = (isfinite(peakMag)) ? pow(10.0, -0.4*peakMag) : NAN; 212 213 source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE); 214 source->peak->flux = peakFlux; 215 source->peak->dx = dPAR[PM_PAR_XPOS]; 216 source->peak->dy = dPAR[PM_PAR_YPOS]; 214 217 215 218 source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF"); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO_PS1_DEV_1.c
r21516 r27840 252 252 pmPSF_AxesToModel (PAR, axes); 253 253 254 float lflux = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG"); 255 float flux = (isfinite(lflux)) ? pow(10.0, -0.4*lflux) : NAN; 256 source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], flux, PM_PEAK_LONE); 257 source->peak->flux = flux; 254 float peakMag = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG"); 255 float peakFlux = (isfinite(peakMag)) ? pow(10.0, -0.4*peakMag) : NAN; 256 257 source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE); 258 source->peak->flux = peakFlux; 259 source->peak->dx = dPAR[PM_PAR_XPOS]; 260 source->peak->dy = dPAR[PM_PAR_YPOS]; 258 261 259 262 source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF"); … … 300 303 301 304 // which extended source analyses should we perform? 302 bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");303 bool doIsophotal = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");304 bool doAnnuli = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");305 bool doKron = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");305 // bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN"); 306 // bool doIsophotal = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL"); 307 // bool doAnnuli = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI"); 308 // bool doKron = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON"); 306 309 307 310 psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER"); … … 343 346 psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG", PS_DATA_F32, "Sigma in EXT y coordinate", yErr); 344 347 348 // XXX disable these outputs until we clean up the names 349 # if (0) 345 350 // Petrosian measurements 346 351 // XXX insert header data: petrosian ref radius, flux ratio … … 422 427 } 423 428 } 429 # endif 424 430 425 431 psArrayAdd (table, 100, row); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO_RAW.c
r24581 r27840 119 119 logChi, logChiNorm, 120 120 source[0].peak->SN, 121 model[0].radiusFit,121 source[0].apRadius, 122 122 source[0].pixWeight, 123 123 model[0].nDOF, … … 181 181 log10(model[0].chisqNorm/model[0].nDOF), 182 182 source[0].peak->SN, 183 model[0].radiusFit,183 source[0].apRadius, 184 184 source[0].pixWeight, 185 185 model[0].nDOF, -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceIO_SMPDATA.c
r20937 r27840 184 184 pmPSF_AxesToModel (PAR, axes); 185 185 186 187 186 source->psfMag = psMetadataLookupF32 (&status, row, "MAG_RAW") - ZERO_POINT; 188 187 source->extMag = psMetadataLookupF32 (&status, row, "MAG_GAL") - ZERO_POINT; … … 198 197 199 198 source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE); 199 source->peak->flux = peakFlux; 200 200 201 sources->data[i] = source; 201 202 } -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceMatch.c
r24262 r27840 8 8 9 9 #include "pmSource.h" 10 #include "pmErrorCodes.h" 10 11 11 12 #include "pmSourceMatch.h" … … 112 113 psFree(match->mag); 113 114 psFree(match->magErr); 115 psFree(match->x); 116 psFree(match->y); 114 117 psFree(match->image); 115 118 psFree(match->index); 119 psFree(match->mask); 116 120 } 117 121 … … 124 128 match->mag = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 125 129 match->magErr = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 130 match->x = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 131 match->y = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 126 132 match->image = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_U32); 127 133 match->index = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_U32); … … 133 139 void pmSourceMatchAdd(pmSourceMatch *match, // Match data 134 140 float mag, float magErr, // Magnitude and error 141 float x, float y, // Position 135 142 int image, // Image index 136 143 int index // Source index … … 141 148 match->mag = psVectorExtend(match->mag, match->mag->nalloc, 1); 142 149 match->magErr = psVectorExtend(match->magErr, match->magErr->nalloc, 1); 150 match->x = psVectorExtend(match->x, match->x->nalloc, 1); 151 match->y = psVectorExtend(match->y, match->y->nalloc, 1); 143 152 match->image = psVectorExtend(match->image, match->image->nalloc, 1); 144 153 match->index = psVectorExtend(match->index, match->index->nalloc, 1); … … 147 156 match->mag->data.F32[num] = mag; 148 157 match->magErr->data.F32[num] = magErr; 158 match->x->data.F32[num] = x; 159 match->y->data.F32[num] = y; 149 160 match->image->data.S32[num] = image; 150 161 match->index->data.S32[num] = index; … … 172 183 for (int i = 0; i < numImages; i++) { 173 184 psArray *sources = sourceArrays->data[i]; // Sources in image 174 if (!sources ) {185 if (!sources || sources->n == 0) { 175 186 continue; 176 187 } … … 192 203 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 193 204 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 194 i, indices->data.S32[j]);205 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 195 206 matches->data[j] = match; 196 207 } … … 212 223 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 213 224 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 214 i, indices->data.S32[j]);225 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 215 226 matches->data[k] = match; 216 227 } … … 221 232 } else { 222 233 // Match with the master list 223 psTree *tree = psTreePlant(2, SOURCES_MAX_LEAF, xMaster, yMaster); // kd Tree with sources234 psTree *tree = psTreePlant(2, SOURCES_MAX_LEAF, PS_TREE_EUCLIDEAN, xMaster, yMaster); // kd Tree 224 235 long numMatch = 0; // Number of matches 225 236 … … 238 249 pmSourceMatch *match = matches->data[index]; // Match data 239 250 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 240 i, indices->data.S32[j]);251 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 241 252 numMatch++; 242 253 } else { … … 244 255 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 245 256 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 246 i, indices->data.S32[j]);257 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 247 258 xMaster->data.F32[numMaster] = xImage->data.F32[j]; 248 259 yMaster->data.F32[numMaster] = yImage->data.F32[j]; … … 262 273 psFree(magImage); 263 274 psFree(magErrImage); 264 } 275 psFree(indices); 276 } 277 278 psFree(xMaster); 279 psFree(yMaster); 280 psFree(boundsMaster); 265 281 266 282 if (cullSingles) { … … 304 320 pmSourceMatch *match = matches->data[i]; // Match of interest 305 321 for (int j = 0; j < match->num && !source; j++) { 306 if (!isfinite(match->mag->data.F32[j]) || !isfinite(match->magErr->data.F32[j])) { 322 if (!isfinite(match->mag->data.F32[j]) || !isfinite(match->magErr->data.F32[j]) || 323 !isfinite(match->x->data.F32[j]) || !isfinite(match->y->data.F32[j])) { 307 324 continue; 308 325 } … … 365 382 double star = 0.0, starErr = 0.0; // Accumulators for star 366 383 for (int j = 0; j < match->num; j++) { 367 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {384 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 368 385 continue; 369 386 } … … 396 413 pmSourceMatch *match = matches->data[i]; // Matched stars 397 414 for (int j = 0; j < match->num; j++) { 398 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {415 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 399 416 continue; 400 417 } … … 424 441 pmSourceMatch *match = matches->data[i]; // Matched stars 425 442 for (int j = 0; j < match->num; j++) { 426 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {443 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 427 444 continue; 428 445 } … … 543 560 pmSourceMatch *match = matches->data[i]; // Matched stars 544 561 for (int j = 0; j < match->num; j++) { 545 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {562 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 546 563 continue; 547 564 } … … 564 581 if (PS_SQR(dev) > starClip * (PS_SQR(magErr) + sysErr2)) { 565 582 numRejected++; 566 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xFF;583 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] |= PM_SOURCE_MATCH_MASK_PHOT; 567 584 } 568 585 } … … 599 616 int numImages = zp->n; // Number of images 600 617 int numStars = matches->n; // Number of stars 618 psVector *badImage = psVectorAlloc(numImages, PS_TYPE_U8); // Bad image? 619 psVectorInit(badImage, 0); 620 621 // Check for data integrity 622 { 623 psVector *num = psVectorAlloc(numImages, PS_TYPE_S32); // Number of stars per image 624 psVectorInit(num, 0); 625 for (int i = 0; i < numStars; i++) { 626 pmSourceMatch *match = matches->data[i]; // Matched stars 627 for (int j = 0; j < match->num; j++) { 628 int index = match->image->data.U32[j]; // Image index 629 psAssert(index >= 0 && index < numImages, "Bad index: %d", index); 630 num->data.S32[index]++; 631 } 632 } 633 int numGood = 0; // Number of good images 634 for (int i = 0; i < numImages; i++) { 635 if (num->data.S32[i] == 0 || !isfinite(zp->data.F32[i])) { 636 badImage->data.U8[i] = 0xFF; 637 continue; 638 } 639 numGood++; 640 } 641 psFree(num); 642 if (numGood == 0) { 643 psError(PM_ERR_DATA, true, "No images with good stars."); 644 psFree(badImage); 645 return false; 646 } 647 } 648 601 649 psVector *trans = psVectorAlloc(numImages, PS_TYPE_F32); // Transparencies for each image, magnitudes 602 650 psVectorInit(trans, 0.0); 603 651 psVector *photo = psVectorAlloc(numImages, PS_TYPE_U8); // Photometric determination for each image 604 652 psVectorInit(photo, 0); 605 psVector *badImage = psVectorAlloc(numImages, PS_TYPE_U8); // Bad image?606 psVectorInit(badImage, 0);607 653 psVector *stars = psVectorAlloc(numStars, PS_TYPE_F32); // Magnitudes for each star 608 654 … … 627 673 return NULL; 628 674 } 629 psTrace("psModules.objects", 3, "Pass 1: Determined %d/%d are photometric ", numPhoto, numImages);675 psTrace("psModules.objects", 3, "Pass 1: Determined %d/%d are photometric\n", numPhoto, numImages); 630 676 631 677 fracRej = sourceMatchRelphotReject(trans, stars, matches, zp, photo, badImage, rej1, sys1); 632 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected ", fracRej * 100);678 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected\n", fracRej * 100); 633 679 634 680 chi2 = sourceMatchRelphotIterate(trans, stars, badImage, matches, zp, photo, sys1); … … 649 695 return NULL; 650 696 } 651 psTrace("psModules.objects", 3, "Pass 2: Determined %d/%d are photometric ", numPhoto, numImages);697 psTrace("psModules.objects", 3, "Pass 2: Determined %d/%d are photometric\n", numPhoto, numImages); 652 698 653 699 fracRej = sourceMatchRelphotReject(trans, stars, matches, zp, photo, badImage, rej2, sys2); 654 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected ", fracRej * 100);700 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected\n", fracRej * 100); 655 701 656 702 chi2 = sourceMatchRelphotIterate(trans, stars, badImage, matches, zp, photo, sys2); … … 668 714 return trans; 669 715 } 716 717 718 // Iterate on the star positions and image shifts 719 // Returns the solution chi^2 720 static float sourceMatchRelastroIterate(psVector *xShift, psVector *yShift, // Shift for image 721 psVector *xStar, psVector *yStar, // Position for star 722 const psArray *matches // Array of matches 723 ) 724 { 725 psAssert(matches, "Need list of matches"); 726 727 int numImages = xShift->n; // Number of images 728 int numStars = matches->n; // Number of stars 729 730 psAssert(xShift && xShift->type.type == PS_TYPE_F32 && yShift && yShift->type.type == PS_TYPE_F32, 731 "Need shifts"); 732 psAssert(yShift->n == numImages, "Not enough shifts: %ld\n", yShift->n); 733 psAssert(xStar && xStar->type.type == PS_TYPE_F32 && yStar && yStar->type.type == PS_TYPE_F32, 734 "Need star positions"); 735 psAssert(xStar->n == numStars && yStar->n == numStars, "Not enough stars\n"); 736 737 // Solve the star positions 738 psVectorInit(xStar, NAN); 739 psVectorInit(yStar, NAN); 740 psVector *starMask = psVectorAlloc(numStars, PS_TYPE_U8); // Mask for stars 741 psVectorInit(starMask, 0xFF); 742 int numGoodStars = 0; // Number of stars with good measurements 743 for (int i = 0; i < numStars; i++) { 744 pmSourceMatch *match = matches->data[i]; // Matched stars 745 int numMeasurements = 0; // Number of unmasked measurements for star 746 double xSum = 0.0, ySum = 0.0; // Accumulators for star 747 for (int j = 0; j < match->num; j++) { 748 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 749 continue; 750 } 751 numMeasurements++; 752 int index = match->image->data.U32[j]; // Image index 753 754 xSum += match->x->data.F32[j] - xShift->data.F32[index]; 755 ySum += match->y->data.F32[j] - yShift->data.F32[index]; 756 } 757 if (numMeasurements > 1) { 758 // It's only a good star (contributing to the chi^2) if there's more than 1 measurement 759 numGoodStars++; 760 xStar->data.F32[i] = xSum / numMeasurements; 761 yStar->data.F32[i] = ySum / numMeasurements; 762 starMask->data.U8[i] = 0; 763 } 764 } 765 766 // Solve for the shifts 767 psVectorInit(xShift, 0.0); 768 psVectorInit(yShift, 0.0); 769 psVector *num = psVectorAlloc(numImages, PS_TYPE_S32); // Number of stars 770 psVectorInit(num, 0); 771 for (int i = 0; i < numStars; i++) { 772 if (starMask->data.U8[i]) { 773 continue; 774 } 775 pmSourceMatch *match = matches->data[i]; // Matched stars 776 for (int j = 0; j < match->num; j++) { 777 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 778 continue; 779 } 780 int index = match->image->data.U32[j]; // Image index 781 782 xShift->data.F32[index] += match->x->data.F32[j] - xStar->data.F32[i]; 783 yShift->data.F32[index] += match->y->data.F32[j] - yStar->data.F32[i]; 784 num->data.S32[index]++; 785 } 786 } 787 for (int i = 0; i < numImages; i++) { 788 xShift->data.F32[i] /= num->data.S32[i]; 789 yShift->data.F32[i] /= num->data.S32[i]; 790 psTrace("psModules.objects", 3, "Shift for image %d: %f,%f\n", 791 i, xShift->data.F32[i], yShift->data.F32[i]); 792 } 793 psFree(num); 794 795 // Once more through to evaluate chi^2 796 float chi2 = 0.0; // chi^2 for iteration 797 int dof = 0; // Degrees of freedom 798 for (int i = 0; i < numStars; i++) { 799 pmSourceMatch *match = matches->data[i]; // Matched stars 800 if (starMask->data.U8[i]) { 801 continue; 802 } 803 for (int j = 0; j < match->num; j++) { 804 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j]) { 805 continue; 806 } 807 808 int index = match->image->data.U32[j]; // Image index 809 float dx = match->x->data.F32[j] - xShift->data.F32[index] - xStar->data.F32[i]; 810 float dy = match->y->data.F32[j] - yShift->data.F32[index] - yStar->data.F32[i]; 811 812 chi2 += PS_SQR(dx) + PS_SQR(dy); 813 dof++; 814 } 815 } 816 dof -= numGoodStars + numImages; 817 chi2 /= dof; 818 819 return chi2; 820 } 821 822 // Reject star measurements 823 // Returns the fraction of measurements that were rejected 824 static float sourceMatchRelastroReject(const psVector *xShift, const psVector *yShift, // Shifts for each image 825 const psVector *xStar, const psVector *yStar, // Positions for each star 826 const psArray *matches, // Array of matches 827 float chi2, // chi^2 from fit 828 float rej // Rejection threshold 829 ) 830 { 831 psAssert(matches, "Need list of matches"); 832 833 int numImages = xShift->n; // Number of images 834 int numStars = matches->n; // Number of stars 835 836 psAssert(xShift && xShift->type.type == PS_TYPE_F32 && yShift && yShift->type.type == PS_TYPE_F32, 837 "Need shifts"); 838 psAssert(yShift->n == numImages, "Not enough shifts: %ld\n", yShift->n); 839 psAssert(xStar && xStar->type.type == PS_TYPE_F32 && yStar && yStar->type.type == PS_TYPE_F32, 840 "Need star positions"); 841 psAssert(xStar->n == numStars && yStar->n == numStars, "Not enough stars\n"); 842 843 int numRejected = 0; // Number rejected 844 int numMeasurements = 0; // Number of measurements 845 846 float thresh = PS_SQR(rej) * chi2; // Threshold for rejection 847 848 for (int i = 0; i < numStars; i++) { 849 pmSourceMatch *match = matches->data[i]; // Matched stars 850 for (int j = 0; j < match->num; j++) { 851 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 852 continue; 853 } 854 numMeasurements++; 855 int index = match->image->data.U32[j]; // Image index 856 857 float dx = match->x->data.F32[j] - xShift->data.F32[index] - xStar->data.F32[i]; 858 float dy = match->y->data.F32[j] - yShift->data.F32[index] - yStar->data.F32[i]; 859 860 if (PS_SQR(dx) + PS_SQR(dy) > thresh) { 861 numRejected++; 862 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] |= PM_SOURCE_MATCH_MASK_ASTRO; 863 } 864 } 865 } 866 867 return (float)numRejected / (float)numMeasurements; 868 } 869 870 psArray *pmSourceMatchRelastro(const psArray *matches, // Array of matches 871 int numImages, // Number of images 872 float tol, // Relative tolerance for convergence 873 int iter1, // Number of iterations for pass 1 874 float rej1, // Limit on rejection between iterations for pass 1 875 int iter2, // Number of iterations for pass 2 876 float rej2, // Limit on rejection between iterations for pass 2 877 float rejLimit // Limit on rejection between iterations 878 ) 879 { 880 PS_ASSERT_ARRAY_NON_NULL(matches, NULL); 881 882 int numStars = matches->n; // Number of stars 883 psVector *xShift = psVectorAlloc(numImages, PS_TYPE_F32); // x shift for each image 884 psVector *yShift = psVectorAlloc(numImages, PS_TYPE_F32); // y shift for each image 885 psVectorInit(xShift, 0.0); 886 psVectorInit(yShift, 0.0); 887 psVector *xStar = psVectorAlloc(numStars, PS_TYPE_F32); // x position for each star 888 psVector *yStar = psVectorAlloc(numStars, PS_TYPE_F32); // y position for each star 889 890 float chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); // chi^2 for solution 891 psTrace("psModules.objects", 1, "Initial: chi^2 = %f\n", chi2); 892 float lastChi2 = INFINITY; // chi^2 on last iteration 893 float fracRej = INFINITY; // Fraction of measurements rejected 894 895 // In the first passes, the shifts are not well deteremined: use high systematic error and 896 // rejection thresholds 897 for (int i = 0; i < iter1; i++) { 898 fracRej = sourceMatchRelastroReject(xShift, yShift, xStar, yStar, matches, chi2, rej1); 899 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected\n", fracRej * 100); 900 901 chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); 902 psTrace("psModules.objects", 1, "Pass 1: iter = %d: chi^2 = %f rejected = %f\n", i, chi2, fracRej); 903 } 904 905 for (int i = 0; i < iter2 && (fabsf(lastChi2 - chi2) > tol * chi2 || fracRej > rejLimit); i++) { 906 lastChi2 = chi2; 907 908 fracRej = sourceMatchRelastroReject(xShift, yShift, xStar, yStar, matches, chi2, rej2); 909 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected\n", fracRej * 100); 910 911 chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); 912 psTrace("psModules.objects", 1, "Pass 2: iter = %d: chi^2 = %f rejected = %f\n", i, chi2, fracRej); 913 } 914 915 psFree(xStar); 916 psFree(yStar); 917 918 if (fabsf(lastChi2 - chi2) > tol * chi2 || fracRej > rejLimit) { 919 psWarning("Unable to converge to relphot solution (%f,%f)", (lastChi2 - chi2) / chi2, fracRej); 920 } 921 922 psArray *results = psArrayAlloc(numImages); // Array of results 923 for (int i = 0; i < numImages; i++) { 924 psVector *offset = results->data[i] = psVectorAlloc(2, PS_TYPE_F32); // Offset for image 925 offset->data.F32[0] = xShift->data.F32[i]; 926 offset->data.F32[1] = yShift->data.F32[i]; 927 } 928 psFree(xShift); 929 psFree(yShift); 930 931 return results; 932 } 933 -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceMatch.h
r23241 r27840 1 1 #ifndef PM_SOURCE_MATCH_H 2 2 #define PM_SOURCE_MATCH_H 3 4 #include <pslib.h> 5 6 /// Mask values for matched sources 7 typedef enum { 8 PM_SOURCE_MATCH_MASK_PHOT = 0x01, // Source was rejected from photometry fit 9 PM_SOURCE_MATCH_MASK_ASTRO = 0x02, // Source was rejected from astrometry fit 10 } pmSourceMatchMask; 3 11 4 12 /// Matched sources … … 12 20 psVector *mag; // Magnitudes 13 21 psVector *magErr; // Magnitude errors 22 psVector *x, *y; // Positions 14 23 psVector *mask; // Mask for measurements 15 24 } pmSourceMatch; … … 26 35 PS_ASSERT_VECTOR_NON_NULL((MATCH)->mag, RVAL); \ 27 36 PS_ASSERT_VECTOR_NON_NULL((MATCH)->magErr, RVAL); \ 37 PS_ASSERT_VECTOR_NON_NULL((MATCH)->x, RVAL); \ 38 PS_ASSERT_VECTOR_NON_NULL((MATCH)->y, RVAL); \ 28 39 PS_ASSERT_VECTOR_SIZE((MATCH)->image, (MATCH)->num, RVAL); \ 29 40 PS_ASSERT_VECTOR_SIZE((MATCH)->index, (MATCH)->num, RVAL); \ 30 41 PS_ASSERT_VECTOR_SIZE((MATCH)->mag, (MATCH)->num, RVAL); \ 31 42 PS_ASSERT_VECTOR_SIZE((MATCH)->magErr, (MATCH)->num, RVAL); \ 43 PS_ASSERT_VECTOR_SIZE((MATCH)->x, (MATCH)->num, RVAL); \ 44 PS_ASSERT_VECTOR_SIZE((MATCH)->y, (MATCH)->num, RVAL); \ 32 45 } 33 46 … … 38 51 void pmSourceMatchAdd(pmSourceMatch *match, // Match data 39 52 float mag, float magErr, // Magnitude and error 53 float x, float y, // Position 40 54 int image, // Image index 41 55 int index // Source index … … 75 89 ); 76 90 91 /// Perform relative astrometry to calibrate images 92 psArray *pmSourceMatchRelastro(const psArray *matches, // Array of matches 93 int numImages, // Number of images 94 float tol, // Relative tolerance for convergence 95 int iter1, // Number of iterations for pass 1 96 float rej1, // Limit on rejection between iterations for pass 1 97 int iter2, // Number of iterations for pass 2 98 float rej2, // Limit on rejection between iterations for pass 2 99 float rejLimit // Limit on rejection between iterations 100 ); 101 77 102 #endif -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceMoments.c
r24577 r27840 36 36 #include "pmSource.h" 37 37 38 bool pmSourceMoments_Old(pmSource *source, psF32 radius);39 40 38 /****************************************************************************** 41 39 pmSourceMoments(source, radius): this function takes a subImage defined in the … … 50 48 pmSource->mask (optional) 51 49 52 XXX: The peak calculations are done in image coords, not subImage coords. 53 54 this version clips input pixels on S/N 55 XXX EAM : this version returns false for several reasons 50 The peak calculations are done in image coords, not subImage coords. 51 52 this version optionally clips input pixels on S/N 56 53 *****************************************************************************/ 57 54 # define VALID_RADIUS(X,Y,RAD2) (((RAD2) >= (PS_SQR(X) + PS_SQR(Y))) ? 1 : 0) 58 55 59 bool pmSourceMoments(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN )56 bool pmSourceMoments(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN, psImageMaskType maskVal) 60 57 { 61 58 PS_ASSERT_PTR_NON_NULL(source, false); … … 64 61 PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false); 65 62 66 // XXX supply sky in a different way?63 // use sky from moments if defined, 0.0 otherwise 67 64 psF32 sky = 0.0; 68 65 if (source->moments == NULL) { … … 91 88 // col0,row0: a pixel (x,y) in the primary image has coordinates of (x-col0, y-row0) in 92 89 // this subimage. we subtract off the peak coordinates, adjusted to this subimage, to have 93 // minimal round-off error in the sums 94 95 psF32 xOff = source->peak->x; 96 psF32 yOff = source->peak->y; 97 psF32 xPeak = source->peak->x - source->pixels->col0; // coord of peak in subimage 98 psF32 yPeak = source->peak->y - source->pixels->row0; // coord of peak in subimage 90 // minimal round-off error in the sums. since these values are subtracted just to minimize 91 // the dynamic range and are added back below, the exact value does not matter. these are 92 // (int) so they can be used in the image index below. 93 94 int xOff = source->peak->x; 95 int yOff = source->peak->y; 96 int xPeak = source->peak->x - source->pixels->col0; // coord of peak in subimage 97 int yPeak = source->peak->y - source->pixels->row0; // coord of peak in subimage 98 99 // we are guaranteed to have a valid pixel and variance at this location (right? right?) 100 // psF32 weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]); 101 // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel"); 102 // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel"); 103 // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel"); 99 104 100 105 for (psS32 row = 0; row < source->pixels->numRows ; row++) { … … 109 114 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) { 110 115 if (vMsk) { 111 if (*vMsk ) {116 if (*vMsk & maskVal) { 112 117 vMsk++; 113 118 continue; … … 126 131 psF32 wDiff = *vWgt; 127 132 128 // skip pixels below specified significance level 133 // skip pixels below specified significance level. this is allowed, but should be 134 // avoided -- the over-weights the wings of bright stars compared to those of faint 135 // stars. 129 136 if (PS_SQR(pDiff) < minSN2*wDiff) continue; 130 if (pDiff < 0) continue; 131 137 // if (pDiff < 0) continue; // XXX : MWV says I should include < 0.0 valued points... 138 139 // Apply a Gaussian window function. Be careful with the window function. S/N 140 // weighting over weights the sky for faint sources 132 141 if (sigma > 0.0) { 133 // apply a pseudo-gaussian weight 134 135 // XXX a lot of extra flops; can we do pre-calculate? 136 psF32 z = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2; 137 assert (z >= 0.0); 138 psF32 t = 1.0 + z*(1.0 + z/2.0*(1.0 + z/3.0)); 139 psF32 weight = 1.0 / t; 140 141 // fprintf (stderr, "%6.1f %6.1f %8.1f %8.1f %5.3f ", xDiff, yDiff, pDiff, wDiff, weight); 142 143 wDiff *= weight; 144 pDiff *= weight; 142 // XXX a lot of extra flops; can we pre-calculate? 143 psF32 z = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2; 144 assert (z >= 0.0); 145 psF32 weight = exp(-z); 146 147 wDiff *= weight; 148 pDiff *= weight; 145 149 } 146 150 … … 154 158 Y1 += yWght; 155 159 156 // fprintf (stderr, " : %6.1f %6.1f %8.1f %8.1f\n", X1, Y1, Sum, Var);157 158 peakPixel = PS_MAX (*vPix, peakPixel); 159 numPixels++;160 } 161 }162 163 // if we have less than (1/2) of the possible pixels, force a retry 160 peakPixel = PS_MAX (*vPix, peakPixel); 161 numPixels++; 162 } 163 } 164 165 // if we have less than (1/4) of the possible pixels (in circle or box), force a retry 166 int minPixels = PS_MIN(0.75*R2, source->pixels->numCols*source->pixels->numRows/4.0); 167 164 168 // XXX EAM - the limit is a bit arbitrary. make it user defined? 165 if ((numPixels < 0.75*R2) || (Sum <= 0)) {166 psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, (int)(0.75*R2), Sum);167 return (false);169 if ((numPixels < minPixels) || (Sum <= 0)) { 170 psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, minPixels, Sum); 171 return (false); 168 172 } 169 173 … … 172 176 float My = Y1/Sum; 173 177 if ((fabs(Mx) > radius) || (fabs(My) > radius)) { 174 psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y);175 return (false);178 psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y); 179 return (false); 176 180 } 177 181 … … 179 183 180 184 // add back offset of peak in primary image 181 source->moments->Mx = Mx + xOff; 182 source->moments->My = My + yOff; 185 // also offset from pixel index to pixel coordinate 186 // (the calculation above uses pixel index instead of coordinate) 187 // 0.5 PIX: moments are calculated using the pixel index and converted here to pixel coords 188 source->moments->Mx = Mx + xOff + 0.5; 189 source->moments->My = My + yOff + 0.5; 183 190 184 191 source->moments->Sum = Sum; … … 205 212 Sum = 0.0; // the second pass may include slightly different pixels, re-determine Sum 206 213 207 // center of mass in subimage 214 // center of mass in subimage. Note: the calculation below uses pixel index, so we do not 215 // correct xCM, yCM to pixel coordinate here. 208 216 psF32 xCM = Mx + xPeak; // coord of peak in subimage 209 217 psF32 yCM = My + yPeak; // coord of peak in subimage … … 211 219 for (psS32 row = 0; row < source->pixels->numRows ; row++) { 212 220 213 psF32 yDiff = row - yCM;221 psF32 yDiff = row - yCM; 214 222 if (fabs(yDiff) > radius) continue; 215 223 216 psF32 *vPix = source->pixels->data.F32[row];217 psF32 *vWgt = source->variance->data.F32[row];218 psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];219 220 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {221 if (vMsk) {222 if (*vMsk) {223 vMsk++;224 continue;225 }226 vMsk++;227 }228 if (isnan(*vPix)) continue;229 230 psF32 xDiff = col - xCM;224 psF32 *vPix = source->pixels->data.F32[row]; 225 psF32 *vWgt = source->variance->data.F32[row]; 226 psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row]; 227 228 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) { 229 if (vMsk) { 230 if (*vMsk & maskVal) { 231 vMsk++; 232 continue; 233 } 234 vMsk++; 235 } 236 if (isnan(*vPix)) continue; 237 238 psF32 xDiff = col - xCM; 231 239 if (fabs(xDiff) > radius) continue; 232 240 233 // radius is just a function of (xDiff, yDiff) 234 psF32 r2 = PS_SQR(xDiff) + PS_SQR(yDiff); 235 psF32 r = sqrt(r2); 236 if (r > radius) continue; 237 238 psF32 pDiff = *vPix - sky; 239 psF32 wDiff = *vWgt; 240 241 // XXX EAM : should this limit be user-defined? 242 243 if (PS_SQR(pDiff) < minSN2*wDiff) continue; 244 if (pDiff < 0) continue; 245 241 // radius is just a function of (xDiff, yDiff) 242 psF32 r2 = PS_SQR(xDiff) + PS_SQR(yDiff); 243 psF32 r = sqrt(r2); 244 if (r > radius) continue; 245 246 psF32 pDiff = *vPix - sky; 247 psF32 wDiff = *vWgt; 248 249 // skip pixels below specified significance level. this is allowed, but should be 250 // avoided -- the over-weights the wings of bright stars compared to those of faint 251 // stars. 252 if (PS_SQR(pDiff) < minSN2*wDiff) continue; 253 // if (pDiff < 0) continue; 254 255 // Apply a Gaussian window function. Be careful with the window function. S/N 256 // weighting over weights the sky for faint sources 246 257 if (sigma > 0.0) { 247 // apply a pseudo-gaussian weight 248 249 // XXX a lot of extra flops; can we do pre-calculate? 250 psF32 z = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2; 251 assert (z >= 0.0); 252 psF32 t = 1.0 + z*(1.0 + z/2.0*(1.0 + z/3.0)); 253 psF32 weight = 1.0 / t; 254 255 // fprintf (stderr, "%6.1f %6.1f %8.1f %8.1f %5.3f ", xDiff, yDiff, pDiff, wDiff, weight); 256 257 wDiff *= weight; 258 pDiff *= weight; 258 // XXX a lot of extra flops; can we do pre-calculate? 259 psF32 z = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2; 260 assert (z >= 0.0); 261 psF32 weight = exp(-z); 262 263 wDiff *= weight; 264 pDiff *= weight; 259 265 } 260 266 261 Sum += pDiff;262 263 psF32 x = xDiff * pDiff;264 psF32 y = yDiff * pDiff;265 266 psF32 xx = xDiff * x;267 psF32 xy = xDiff * y;268 psF32 yy = yDiff * y;269 270 psF32 xxx = xDiff * xx / r;271 psF32 xxy = xDiff * xy / r;272 psF32 xyy = xDiff * yy / r;273 psF32 yyy = yDiff * yy / r;274 275 psF32 xxxx = xDiff * xxx / r2;276 psF32 xxxy = xDiff * xxy / r2;277 psF32 xxyy = xDiff * xyy / r2;278 psF32 xyyy = xDiff * yyy / r2;279 psF32 yyyy = yDiff * yyy / r2;280 281 XX += xx;282 XY += xy;283 YY += yy;284 285 XXX += xxx;286 XXY += xxy;287 XYY += xyy;288 YYY += yyy;289 290 XXXX += xxxx;291 XXXY += xxxy;292 XXYY += xxyy;293 XYYY += xyyy;294 YYYY += yyyy;295 }267 Sum += pDiff; 268 269 psF32 x = xDiff * pDiff; 270 psF32 y = yDiff * pDiff; 271 272 psF32 xx = xDiff * x; 273 psF32 xy = xDiff * y; 274 psF32 yy = yDiff * y; 275 276 psF32 xxx = xDiff * xx / r; 277 psF32 xxy = xDiff * xy / r; 278 psF32 xyy = xDiff * yy / r; 279 psF32 yyy = yDiff * yy / r; 280 281 psF32 xxxx = xDiff * xxx / r2; 282 psF32 xxxy = xDiff * xxy / r2; 283 psF32 xxyy = xDiff * xyy / r2; 284 psF32 xyyy = xDiff * yyy / r2; 285 psF32 yyyy = yDiff * yyy / r2; 286 287 XX += xx; 288 XY += xy; 289 YY += yy; 290 291 XXX += xxx; 292 XXY += xxy; 293 XYY += xyy; 294 YYY += yyy; 295 296 XXXX += xxxx; 297 XXXY += xxxy; 298 XXYY += xxyy; 299 XYYY += xyyy; 300 YYYY += yyyy; 301 } 296 302 } 297 303 … … 311 317 source->moments->Myyyy = YYYY/Sum; 312 318 313 if (source->moments->Mxx < 0) {314 fprintf (stderr, "error: neg second moment??\n");315 }316 if (source->moments->Myy < 0) {317 fprintf (stderr, "error: neg second moment??\n");318 }319 // if (source->moments->Mxx < 0) { 320 // fprintf (stderr, "error: neg second moment??\n"); 321 // } 322 // if (source->moments->Myy < 0) { 323 // fprintf (stderr, "error: neg second moment??\n"); 324 // } 319 325 320 326 psTrace ("psModules.objects", 4, "Mxx: %f Mxy: %f Myy: %f Mxxx: %f Mxxy: %f Mxyy: %f Myyy: %f Mxxxx: %f Mxxxy: %f Mxxyy: %f Mxyyy: %f Mxyyy: %f\n", 321 source->moments->Mxx, source->moments->Mxy, source->moments->Myy,322 source->moments->Mxxx, source->moments->Mxxy, source->moments->Mxyy, source->moments->Myyy,323 source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy);327 source->moments->Mxx, source->moments->Mxy, source->moments->Myy, 328 source->moments->Mxxx, source->moments->Mxxy, source->moments->Mxyy, source->moments->Myyy, 329 source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy); 324 330 325 331 psTrace ("psModules.objects", 3, "peak %f %f (%f = %f) Mx: %f My: %f Sum: %f Mxx: %f Mxy: %f Myy: %f sky: %f Npix: %d\n", 326 source->peak->xf, source->peak->yf, source->peak->flux, source->peak->SN, source->moments->Mx, source->moments->My, Sum, source->moments->Mxx, source->moments->Mxy, source->moments->Myy, sky, numPixels); 327 328 if (source->moments->Mxx < 0) { 329 fprintf (stderr, "error: neg second moment??\n"); 330 } 331 if (source->moments->Myy < 0) { 332 fprintf (stderr, "error: neg second moment??\n"); 333 } 334 335 // XXX TEST: 336 // pmSourceMoments_Old (source, radius); 332 source->peak->xf, source->peak->yf, source->peak->flux, source->peak->SN, source->moments->Mx, source->moments->My, Sum, source->moments->Mxx, source->moments->Mxy, source->moments->Myy, sky, numPixels); 333 337 334 return(true); 338 335 } 339 340 341 bool pmSourceMoments_Old(pmSource *source, psF32 radius)342 {343 PS_ASSERT_PTR_NON_NULL(source, false);344 PS_ASSERT_PTR_NON_NULL(source->peak, false);345 PS_ASSERT_PTR_NON_NULL(source->pixels, false);346 PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false);347 348 psF32 sky = 0.0;349 if (source->moments == NULL) {350 source->moments = pmMomentsAlloc();351 } else {352 sky = source->moments->Sky;353 }354 355 // Sum = SUM (z - sky)356 // X1 = SUM (x - xc)*(z - sky)357 // X2 = SUM (x - xc)^2 * (z - sky)358 // XY = SUM (x - xc)*(y - yc)*(z - sky)359 psF32 peakPixel = -PS_MAX_F32;360 psS32 numPixels = 0;361 psF32 Sum = 0.0;362 psF32 Var = 0.0;363 psF32 X1 = 0.0;364 psF32 Y1 = 0.0;365 psF32 X2 = 0.0;366 psF32 Y2 = 0.0;367 psF32 XY = 0.0;368 psF32 x = 0;369 psF32 y = 0;370 psF32 R2 = PS_SQR(radius);371 372 // a note about coordinates: coordinates of objects throughout psphot refer to the primary373 // image coordinates. the source->pixels image has an offset relative to its parent of374 // col0,row0: a pixel (x,y) in the primary image has coordinates of (x-col0, y-row0) in375 // this subimage. we subtract off the peak coordinates, adjusted to this subimage, to have376 // minimal round-off error in the sums377 378 psF32 xPeak = source->peak->x - source->pixels->col0; // coord of peak in subimage379 psF32 yPeak = source->peak->y - source->pixels->row0; // coord of peak in subimage380 381 for (psS32 row = 0; row < source->pixels->numRows ; row++) {382 383 psF32 *vPix = source->pixels->data.F32[row];384 psF32 *vWgt = source->variance->data.F32[row];385 psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];386 387 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {388 if (vMsk) {389 if (*vMsk) {390 vMsk++;391 continue;392 }393 vMsk++;394 }395 if (isnan(*vPix)) continue;396 397 psF32 xDiff = col - xPeak;398 psF32 yDiff = row - yPeak;399 400 // radius is just a function of (xDiff, yDiff)401 if (!VALID_RADIUS(xDiff, yDiff, R2)) continue;402 403 psF32 pDiff = *vPix - sky;404 psF32 wDiff = *vWgt;405 406 // XXX EAM : should this limit be user-defined?407 if (PS_SQR(pDiff) < wDiff) continue;408 409 Var += wDiff;410 Sum += pDiff;411 412 psF32 xWght = xDiff * pDiff;413 psF32 yWght = yDiff * pDiff;414 415 X1 += xWght;416 Y1 += yWght;417 418 X2 += xDiff * xWght;419 XY += xDiff * yWght;420 Y2 += yDiff * yWght;421 422 peakPixel = PS_MAX (*vPix, peakPixel);423 numPixels++;424 }425 }426 427 // if we have less than (1/4) of the possible pixels, force a retry428 // XXX EAM - the limit is a bit arbitrary. make it user defined?429 if ((numPixels < 0.75*R2) || (Sum <= 0)) {430 psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, (int)(0.75*R2), Sum);431 return (false);432 }433 434 psTrace ("psModules.objects", 4, "sky: %f Sum: %f X1: %f Y1: %f X2: %f Y2: %f XY: %f Npix: %d\n",435 sky, Sum, X1, Y1, X2, Y2, XY, numPixels);436 437 //438 // first moment X = X1/Sum + xc439 // second moment X = sqrt (X2/Sum - (X1/Sum)^2)440 // Sxy = XY / Sum441 //442 x = X1/Sum;443 y = Y1/Sum;444 if ((fabs(x) > radius) || (fabs(y) > radius)) {445 psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n",446 source->peak->x, source->peak->y);447 return (false);448 }449 450 # if (PS_TRACE_ON)451 float Sxx = PS_MAX(X2/Sum - PS_SQR(x), 0);452 float Sxy = XY / Sum;453 float Syy = PS_MAX(Y2/Sum - PS_SQR(y), 0);454 455 psTrace ("psModules.objects", 3,456 "sky: %f Sum: %f x: %f y: %f Sx: %f Sy: %f Sxy: %f\n",457 sky, Sum, x, y, Sxx, Sxy, Syy);458 # endif459 460 return(true);461 }462 -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourcePhotometry.c
r21511 r27840 84 84 85 85 // we must have a valid model 86 // XXX allow aperture magnitudes for sources without a model 86 87 model = pmSourceGetModel (&isPSF, source); 87 88 if (model == NULL) { … … 90 91 } 91 92 93 // XXX handle negative flux, low-significance 92 94 if (model->dparams->data.F32[PM_PAR_I0] > 0) { 93 95 SN = model->params->data.F32[PM_PAR_I0] / model->dparams->data.F32[PM_PAR_I0]; … … 101 103 102 104 // measure PSF model photometry 103 if (psf->FluxScale) { 105 // XXX TEST: do not use flux scale 106 if (0 && psf->FluxScale) { 104 107 // the source peak pixel is guaranteed to be on the image, and only minimally different from the source center 105 108 double fluxScale = pmTrend2DEval (psf->FluxScale, (float)source->peak->x, (float)source->peak->y); 106 if (!isfinite(fluxScale)) { 107 // XXX objects on the edge can be slightly outside -- if we get an 108 // error, use the full fit. 109 psErrorClear(); 110 status = pmSourcePhotometryModel (&source->psfMag, source->modelPSF); 111 } else { 112 if (isfinite(fluxScale) && (fluxScale > 0.0)) { 113 source->psfMag = -2.5*log10(fluxScale * source->modelPSF->params->data.F32[PM_PAR_I0]); 114 } else { 115 source->psfMag = NAN; 116 } 117 } 109 psAssert (isfinite(fluxScale), "how can the flux scale be invalid? source at %d, %d\n", source->peak->x, source->peak->y); 110 psAssert (fluxScale > 0.0, "how can the flux scale be negative? source at %d, %d\n", source->peak->x, source->peak->y); 111 source->psfFlux = fluxScale * source->modelPSF->params->data.F32[PM_PAR_I0]; 112 source->psfFluxErr = fluxScale * source->modelPSF->dparams->data.F32[PM_PAR_I0]; 113 source->psfMag = -2.5*log10(source->psfFlux); 118 114 } else { 119 status = pmSourcePhotometryModel (&source->psfMag, source->modelPSF);120 } 121 122 // if we have a collection of model fits, one of them is a pointer to modelEXT? 123 // XXX not guaranteed115 status = pmSourcePhotometryModel (&source->psfMag, &source->psfFlux, source->modelPSF); 116 source->psfFluxErr = source->psfFlux * (source->modelPSF->dparams->data.F32[PM_PAR_I0] / source->modelPSF->params->data.F32[PM_PAR_I0]); 117 } 118 119 // if we have a collection of model fits, check if one of them is a pointer to modelEXT 124 120 if (source->modelFits) { 125 for (int i = 0; i < source->modelFits->n; i++) { 126 pmModel *model = source->modelFits->data[i]; 127 status = pmSourcePhotometryModel (&model->mag, model); 128 } 129 if (source->modelEXT) { 130 source->extMag = source->modelEXT->mag; 131 } 121 bool foundEXT = false; 122 for (int i = 0; i < source->modelFits->n; i++) { 123 pmModel *model = source->modelFits->data[i]; 124 status = pmSourcePhotometryModel (&model->mag, NULL, model); 125 if (model == source->modelEXT) foundEXT = true; 126 } 127 if (foundEXT) { 128 source->extMag = source->modelEXT->mag; 129 } else { 130 status = pmSourcePhotometryModel (&source->extMag, NULL, source->modelEXT); 131 } 132 132 } else { 133 if (source->modelEXT) {134 status = pmSourcePhotometryModel (&source->extMag, source->modelEXT);135 }133 if (source->modelEXT) { 134 status = pmSourcePhotometryModel (&source->extMag, NULL, source->modelEXT); 135 } 136 136 } 137 137 … … 148 148 } 149 149 150 // measure the contribution of included pixels 151 if (mode & PM_SOURCE_PHOT_DIFFSTATS) { 152 pmSourceMeasureDiffStats (source, maskVal); 153 } 154 150 155 // measure the aperture magnitude, if (SN > AP_MIN_SN) 151 156 if (!isfinite(SN)) { … … 160 165 } 161 166 162 // replace source flux 163 // XXX need to be certain which model and size of mask for prior subtraction 164 // XXX full model or just analytical? 165 // XXX use pmSourceAdd instead? 166 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) { 167 pmModelAdd (source->pixels, source->maskObj, model, PM_MODEL_OP_FULL, maskVal); 168 } 167 // if we measure aperture magnitudes, the source must not currently be subtracted! 168 psAssert (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED), "cannot measure ap mags if source is subtracted!"); 169 169 170 170 // if we are measuring aperture photometry and applying the growth correction, … … 201 201 if (isfinite (source->apMag) && isPSF && psf) { 202 202 if (psf->growth && (mode & PM_SOURCE_PHOT_GROWTH)) { 203 source->apMag += pmGrowthCurveCorrect (psf->growth, model->radiusFit);203 source->apMag += pmGrowthCurveCorrect (psf->growth, source->apRadius); 204 204 } 205 205 if (mode & PM_SOURCE_PHOT_APCORR) { 206 // XXX this should be removed -- we no longer fit for the 'sky bias' 206 207 rflux = pow (10.0, 0.4*source->psfMag); 207 source->apMag -= PS_SQR( model->radiusFit)*rflux * psf->skyBias + psf->skySat / rflux;208 source->apMag -= PS_SQR(source->apRadius)*rflux * psf->skyBias + psf->skySat / rflux; 208 209 } 209 210 } … … 211 212 psFree(flux); 212 213 psFree(mask); 213 }214 215 // if source was originally subtracted, re-subtract object, leave local sky216 // XXX replace with pmSourceSub...217 if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {218 pmModelSub (source->pixels, source->maskObj, model, PM_MODEL_OP_FULL, maskVal);219 214 } 220 215 … … 230 225 231 226 // return source model magnitude 232 bool pmSourcePhotometryModel (float *fitMag, pmModel *model) 233 { 234 PS_ASSERT_PTR_NON_NULL(fitMag, false); 235 if (model == NULL) { 236 return false; 237 } 238 239 float fitSum = 0; 240 *fitMag = NAN; 227 bool pmSourcePhotometryModel (float *fitMag, float *fitFlux, pmModel *model) 228 { 229 psAssert (fitMag || fitFlux, "at least one of magnitude or flux must be requested (not NULL)"); 230 if (model == NULL) return false; 231 232 float mag = NAN; 233 float flux = NAN; 241 234 242 235 // measure fitMag 243 fitSum = model->modelFlux (model->params); 244 if (fitSum <= 0) 245 return false; 246 if (!isfinite(fitSum)) 247 return false; 248 *fitMag = -2.5*log10(fitSum); 236 flux = model->modelFlux (model->params); 237 if (flux > 0) { 238 mag = -2.5*log10(flux); 239 } 240 if (fitMag) { 241 *fitMag = mag; 242 } 243 if (fitFlux) { 244 *fitFlux = flux; 245 } 246 247 if (flux <= 0) return false; 248 if (!isfinite(flux)) return false; 249 249 250 250 return (true); … … 369 369 370 370 *pixWeight = validSum / modelSum; 371 return (true); 372 } 373 374 # define FLUX_LIMIT 3.0 375 376 // return source aperture magnitude 377 bool pmSourceMeasureDiffStats (pmSource *source, psImageMaskType maskVal) 378 { 379 PS_ASSERT_PTR_NON_NULL(source, false); 380 381 if (source->diffStats == NULL) { 382 source->diffStats = pmSourceDiffStatsAlloc(); 383 } 384 385 float fGood = 0.0; 386 float fBad = 0.0; 387 int nGood = 0; 388 int nMask = 0; 389 int nBad = 0; 390 391 psImage *flux = source->pixels; 392 psImage *variance = source->variance; 393 psImage *mask = source->maskObj; 394 395 for (int iy = 0; iy < flux->numRows; iy++) { 396 for (int ix = 0; ix < flux->numCols; ix++) { 397 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal) { 398 nMask ++; 399 continue; 400 } 401 402 float SN = flux->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]); 403 404 if (SN > +FLUX_LIMIT) { 405 nGood ++; 406 fGood += fabs(flux->data.F32[iy][ix]); 407 } 408 409 if (SN < -FLUX_LIMIT) { 410 nBad ++; 411 fBad += fabs(flux->data.F32[iy][ix]); 412 } 413 } 414 } 415 416 source->diffStats->nGood = nGood; 417 source->diffStats->fRatio = (fGood + fBad == 0.0) ? NAN : fGood / (fGood + fBad); 418 source->diffStats->nRatioBad = (nGood + nBad == 0) ? NAN : nGood / (float) (nGood + nBad); 419 source->diffStats->nRatioMask = (nGood + nMask == 0) ? NAN : nGood / (float) (nGood + nMask); 420 source->diffStats->nRatioAll = (nGood + nMask + nBad == 0) ? NAN : nGood / (float) (nGood + nMask + nBad); 421 371 422 return (true); 372 423 } … … 558 609 559 610 // determine chisq, etc for linear normalization-only fit 560 bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *variance, 561 psImageMaskType maskVal) 611 bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *variance, psImageMaskType maskVal, const float covarFactor) 562 612 { 563 613 PS_ASSERT_PTR_NON_NULL(model, false); … … 574 624 if (variance->data.F32[j][i] <= 0) 575 625 continue; 576 dC += PS_SQR (image->data.F32[j][i]) / variance->data.F32[j][i];626 dC += PS_SQR (image->data.F32[j][i]) / (covarFactor * variance->data.F32[j][i]); 577 627 Npix ++; 578 628 } … … 586 636 587 637 588 double pmSourceModelWeight(const pmSource *Mi, 589 int term, 590 const bool unweighted_sum) // should the cross product be weighted? 638 double pmSourceModelWeight(const pmSource *Mi, int term, const bool unweighted_sum, const float covarFactor) 591 639 { 592 640 PS_ASSERT_PTR_NON_NULL(Mi, NAN); … … 607 655 continue; 608 656 if (!unweighted_sum) { 609 wt = Wi->data.F32[yi][xi];657 wt = covarFactor * Wi->data.F32[yi][xi]; 610 658 if (wt == 0) 611 659 continue; … … 636 684 } 637 685 638 double pmSourceModelDotModel (const pmSource *Mi, 639 const pmSource *Mj, 640 const bool unweighted_sum) // should the cross product be weighted? 686 double pmSourceModelDotModel (const pmSource *Mi, const pmSource *Mj, const bool unweighted_sum, const float covarFactor) 641 687 { 642 688 PS_ASSERT_PTR_NON_NULL(Mi, NAN); … … 690 736 flux += (Pi->data.F32[yi][xi] * Pj->data.F32[yj][xj]); 691 737 } else { 692 wt = Wi->data.F32[yi][xi];738 wt = covarFactor * Wi->data.F32[yi][xi]; 693 739 if (wt > 0) { 694 740 flux += (Pi->data.F32[yi][xi] * Pj->data.F32[yj][xj]) / wt; … … 700 746 } 701 747 702 double pmSourceDataDotModel (const pmSource *Mi, 703 const pmSource *Mj, 704 const bool unweighted_sum) // should the cross product be weighted? 748 double pmSourceDataDotModel (const pmSource *Mi, const pmSource *Mj, const bool unweighted_sum, const float covarFactor) 705 749 { 706 750 PS_ASSERT_PTR_NON_NULL(Mi, NAN); … … 754 798 flux += (Pi->data.F32[yi][xi] * Pj->data.F32[yj][xj]); 755 799 } else { 756 wt = Wi->data.F32[yi][xi];800 wt = covarFactor * Wi->data.F32[yi][xi]; 757 801 if (wt > 0) { 758 802 flux += (Pi->data.F32[yi][xi] * Pj->data.F32[yj][xj]) / wt; … … 763 807 return flux; 764 808 } 765 766 // XXX this is test code to verify the shift is doing the right thing (seems to be)767 # if (0)768 // measure centroid of unshifted gaussian (should be 16.0,16.0)769 {770 psImage *image = source->pixels;771 float xo = 0.0;772 float yo = 0.0;773 float xo2 = 0.0;774 float yo2 = 0.0;775 float no = 0.0;776 for (int j = 0; j < image->numRows; j++)777 {778 for (int i = 0; i < image->numCols; i++) {779 xo += i*image->data.F32[j][i];780 yo += j*image->data.F32[j][i];781 xo2 += i*i*image->data.F32[j][i];782 yo2 += j*j*image->data.F32[j][i];783 no += image->data.F32[j][i];784 }785 }786 xo /= no;787 yo /= no;788 xo2 = sqrt (xo2/no - xo*xo);789 yo2 = sqrt (yo2/no - yo*yo);790 fprintf (stderr, "pre-shift centroid: %f,%f, sigma: %f,%f: flux: %f\n", xo, yo, xo2, yo2, no);791 }792 793 // measure centroid of unshifted gaussian (should be 16.0,16.0)794 {795 psImage *image = flux;796 float xo = 0.0;797 float yo = 0.0;798 float xo2 = 0.0;799 float yo2 = 0.0;800 float no = 0.0;801 for (int j = 0; j < image->numRows; j++)802 {803 for (int i = 0; i < image->numCols; i++) {804 xo += i*image->data.F32[j][i];805 yo += j*image->data.F32[j][i];806 xo2 += i*i*image->data.F32[j][i];807 yo2 += j*j*image->data.F32[j][i];808 no += image->data.F32[j][i];809 }810 }811 xo /= no;812 yo /= no;813 xo2 = sqrt (xo2/no - xo*xo);814 yo2 = sqrt (yo2/no - yo*yo);815 fprintf (stderr, "pre-shift centroid: %f,%f, sigma: %f,%f: flux: %f\n", xo, yo, xo2, yo2, no);816 }817 # endif -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourcePhotometry.h
r21511 r27840 29 29 30 30 typedef enum { 31 PM_SOURCE_PHOT_NONE = 0x0000, 32 PM_SOURCE_PHOT_GROWTH = 0x0001, 33 PM_SOURCE_PHOT_APCORR = 0x0002, 34 PM_SOURCE_PHOT_WEIGHT = 0x0004, 35 PM_SOURCE_PHOT_INTERP = 0x0008, 31 PM_SOURCE_PHOT_NONE = 0x0000, 32 PM_SOURCE_PHOT_GROWTH = 0x0001, 33 PM_SOURCE_PHOT_APCORR = 0x0002, 34 PM_SOURCE_PHOT_WEIGHT = 0x0004, 35 PM_SOURCE_PHOT_INTERP = 0x0008, 36 PM_SOURCE_PHOT_DIFFSTATS = 0x0010, 36 37 } pmSourcePhotometryMode; 37 38 38 39 bool pmSourcePhotometryModel( 39 40 float *fitMag, ///< integrated fit magnitude 41 float *fitFlux, ///< integrated fit magnitude 40 42 pmModel *model ///< model used for photometry 41 43 ); … … 52 54 bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal); 53 55 bool pmSourcePixelWeight (float *pixWeight, pmModel *model, psImage *mask, psImageMaskType maskVal); 54 bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *weight, psImageMaskType maskVal );56 bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *weight, psImageMaskType maskVal, const float covarFactor); 55 57 58 bool pmSourceMeasureDiffStats (pmSource *source, psImageMaskType maskVal); 56 59 57 double pmSourceDataDotModel (const pmSource *Mi, const pmSource *Mj, const bool unweighted_sum );58 double pmSourceModelDotModel (const pmSource *Mi, const pmSource *Mj, const bool unweighted_sum );59 double pmSourceModelWeight(const pmSource *Mi, int term, const bool unweighted_sum );60 double pmSourceDataDotModel (const pmSource *Mi, const pmSource *Mj, const bool unweighted_sum, const float covarFactor); 61 double pmSourceModelDotModel (const pmSource *Mi, const pmSource *Mj, const bool unweighted_sum, const float covarFactor); 62 double pmSourceModelWeight(const pmSource *Mi, int term, const bool unweighted_sum, const float covarFactor); 60 63 61 64 // retire these: -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourcePlotApResid.c
r20937 r27840 34 34 #include "pmPSF.h" 35 35 #include "pmModel.h" 36 #include "pmDetections.h" 36 37 #include "pmSource.h" 37 38 #include "pmSourcePlots.h" … … 53 54 PS_ASSERT_PTR_NON_NULL(layout, false); 54 55 56 bool status; 55 57 Graphdata graphdata; 56 58 KapaSection section; … … 61 63 pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT"); 62 64 63 psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES"); 64 if (sources == NULL) 65 return false; 65 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 66 if (detections == NULL) return false; 67 68 psArray *sources = detections->allSources; 69 if (sources == NULL) return false; 66 70 67 71 int kapa = pmKapaOpen (false); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourcePlotMoments.c
r20937 r27840 37 37 #include "pmPSF.h" 38 38 #include "pmModel.h" 39 #include "pmDetections.h" 39 40 #include "pmSource.h" 40 41 #include "pmSourcePlots.h" … … 54 55 PS_ASSERT_PTR_NON_NULL(layout, false); 55 56 57 bool status; 56 58 Graphdata graphdata; 57 59 KapaSection section; … … 62 64 pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT"); 63 65 64 psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES"); 65 if (sources == NULL) 66 return false; 66 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 67 if (detections == NULL) return false; 68 69 psArray *sources = detections->allSources; 70 if (sources == NULL) return false; 67 71 68 72 int kapa = pmKapaOpen (false); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourcePlotPSFModel.c
r20937 r27840 37 37 #include "pmPSF.h" 38 38 #include "pmModel.h" 39 #include "pmDetections.h" 39 40 #include "pmSource.h" 40 41 #include "pmSourcePlots.h" … … 56 57 PS_ASSERT_PTR_NON_NULL(layout, false); 57 58 59 bool status; 58 60 Graphdata graphdata; 59 61 KapaSection section; … … 64 66 pmReadout *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT"); 65 67 66 psArray *sources = psMetadataLookupPtr (NULL, readout->analysis, "PSPHOT.SOURCES"); 67 if (sources == NULL) 68 return false; 68 pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS"); 69 if (detections == NULL) return false; 70 71 psArray *sources = detections->allSources; 72 if (sources == NULL) return false; 69 73 70 74 int kapa = pmKapaOpen (false); -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceVisual.c
r23242 r27840 5 5 #include <pslib.h> 6 6 #include "pmTrend2D.h" 7 #include "pmPSF.h" 8 #include "pmPSFtry.h" 9 #include "pmSource.h" 7 10 #include "pmSourceVisual.h" 8 11 … … 15 18 16 19 static int kapa1 = -1; 20 static int kapa2 = -1; 17 21 static bool plotPSF = true; 18 // static int kapa2 = -1;19 22 // static int kapa3 = -1; 20 23 … … 27 30 bool pmSourcePlotPoints3D (int myKapa, Graphdata *graphdata, psVector *xn, psVector *yn, psVector *zn, float theta, float phi); 28 31 29 30 bool pmSourceVisualPSFModelResid (pmTrend2D *trend, psVector *x, psVector *y, psVector *param, psVector *mask) { 31 32 KapaSection section; // put the positive profile in one and the residuals in another? 32 bool pmSourceVisualPlotPSFMetric (pmPSFtry *psfTry) { 33 33 34 34 Graphdata graphdata; 35 35 36 if (!pmVisualIsVisual() || !plotPSF) return true;36 if (!pmVisualIsVisual()) return true; 37 37 38 38 if (kapa1 == -1) { … … 45 45 } 46 46 47 KapaClear Plots (kapa1);47 KapaClearSections (kapa1); 48 48 KapaInitGraph (&graphdata); 49 49 50 float min = +1e32; 51 float max = -1e32; 52 float Min = +1e32; 53 float Max = -1e32; 54 55 psVector *resid = psVectorAlloc (x->n, PS_TYPE_F32); 56 psVector *model = psVectorAlloc (x->n, PS_TYPE_F32); 57 58 for (int i = 0; i < x->n; i++) { 59 model->data.F32[i] = pmTrend2DEval (trend, x->data.F32[i], y->data.F32[i]); 60 resid->data.F32[i] = param->data.F32[i] - model->data.F32[i]; 61 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue; 62 min = PS_MIN (min, resid->data.F32[i]); 63 max = PS_MAX (max, resid->data.F32[i]); 64 Min = PS_MIN (min, param->data.F32[i]); 65 Max = PS_MAX (max, param->data.F32[i]); 66 } 67 68 psVector *xn = psVectorAlloc (x->n, PS_TYPE_F32); 69 psVector *yn = psVectorAlloc (x->n, PS_TYPE_F32); 70 psVector *zn = psVectorAlloc (x->n, PS_TYPE_F32); 71 psVector *Zn = psVectorAlloc (x->n, PS_TYPE_F32); 72 psVector *Fn = psVectorAlloc (x->n, PS_TYPE_F32); 73 for (int i = 0; i < x->n; i++) { 74 xn->data.F32[i] = x->data.F32[i] / 5000.0; 75 yn->data.F32[i] = y->data.F32[i] / 5000.0; 76 zn->data.F32[i] = (resid->data.F32[i] - min) / (max - min); 77 Zn->data.F32[i] = (param->data.F32[i] - Min) / (Max - Min); 78 Fn->data.F32[i] = (model->data.F32[i] - Min) / (Max - Min); 79 } 80 81 // view 1 on resid 82 section.dx = 0.5; 83 section.dy = 0.33; 50 psVector *x = psVectorAllocEmpty (psfTry->sources->n, PS_TYPE_F32); 51 psVector *y = psVectorAllocEmpty (psfTry->sources->n, PS_TYPE_F32); 52 psVector *dy = psVectorAllocEmpty(psfTry->sources->n, PS_TYPE_F32); 53 54 graphdata.xmin = +32.0; 55 graphdata.xmax = -32.0; 56 graphdata.ymin = +32.0; 57 graphdata.ymax = -32.0; 58 59 // construct the plot vectors 60 int n = 0; 61 for (int i = 0; i < psfTry->sources->n; i++) { 62 if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL) continue; 63 x->data.F32[n] = psfTry->fitMag->data.F32[i]; 64 y->data.F32[n] = psfTry->metric->data.F32[i]; 65 dy->data.F32[n] = psfTry->metricErr->data.F32[i]; 66 graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]); 67 graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]); 68 graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]); 69 graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]); 70 n++; 71 } 72 x->n = y->n = dy->n = n; 73 74 float range; 75 range = graphdata.xmax - graphdata.xmin; 76 graphdata.xmax += 0.05*range; 77 graphdata.xmin -= 0.05*range; 78 range = graphdata.ymax - graphdata.ymin; 79 graphdata.ymax += 0.05*range; 80 graphdata.ymin -= 0.05*range; 81 82 // better choice for range? 83 // graphdata.xmin = -17.0; 84 // graphdata.xmax = -9.0; 85 graphdata.ymin = -0.51; 86 graphdata.ymax = +0.51; 87 88 KapaSetLimits (kapa1, &graphdata); 89 90 KapaSetFont (kapa1, "helvetica", 14); 91 KapaBox (kapa1, &graphdata); 92 KapaSendLabel (kapa1, "PSF Mag", KAPA_LABEL_XM); 93 KapaSendLabel (kapa1, "Ap Mag - PSF Mag", KAPA_LABEL_YM); 94 95 graphdata.color = KapaColorByName ("black"); 96 graphdata.ptype = 2; 97 graphdata.size = 0.5; 98 graphdata.style = 2; 99 graphdata.etype |= 0x01; 100 101 KapaPrepPlot (kapa1, n, &graphdata); 102 KapaPlotVector (kapa1, n, x->data.F32, "x"); 103 KapaPlotVector (kapa1, n, y->data.F32, "y"); 104 KapaPlotVector (kapa1, n, dy->data.F32, "dym"); 105 KapaPlotVector (kapa1, n, dy->data.F32, "dyp"); 106 107 psFree (x); 108 psFree (y); 109 psFree (dy); 110 111 pmVisualAskUser(NULL); 112 return true; 113 } 114 115 bool pmSourceVisualPlotPSFMetricSubpix (pmPSFtry *psfTry) { 116 117 KapaSection section; // put the positive profile in one and the residuals in another? 118 Graphdata graphdata; 119 120 if (!pmVisualIsVisual()) return true; 121 122 if (kapa1 == -1) { 123 kapa1 = KapaOpenNamedSocket ("kapa", "pmSource:plots"); 124 if (kapa1 == -1) { 125 fprintf (stderr, "failure to open kapa; visual mode disabled\n"); 126 pmVisualSetVisual(false); 127 return false; 128 } 129 } 130 131 KapaClearSections (kapa1); 132 KapaInitGraph (&graphdata); 133 134 int n; 135 float range; 136 psVector *x = psVectorAllocEmpty (psfTry->sources->n, PS_TYPE_F32); 137 psVector *y = psVectorAllocEmpty (psfTry->sources->n, PS_TYPE_F32); 138 psVector *dy = psVectorAllocEmpty(psfTry->sources->n, PS_TYPE_F32); 139 140 // section a: fractional-x pixel 141 section.dx = 1.0; 142 section.dy = 0.5; 84 143 section.x = 0.0; 85 144 section.y = 0.0; … … 88 147 KapaSetSection (kapa1, §ion); 89 148 psFree (section.name); 90 pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, zn, 30.0*PS_RAD_DEG, -15.0*PS_RAD_DEG); 91 92 // view 2 on resid 93 section.dx = 0.5; 94 section.dy = 0.33; 95 section.x = 0.5; 96 section.y = 0.0; 149 150 graphdata.xmin = +32.0; 151 graphdata.xmax = -32.0; 152 graphdata.ymin = +32.0; 153 graphdata.ymax = -32.0; 154 155 // construct the plot vectors 156 n = 0; 157 for (int i = 0; i < psfTry->sources->n; i++) { 158 if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL) continue; 159 160 pmSource *source = psfTry->sources->data[i]; 161 x->data.F32[n] = source->modelEXT->params->data.F32[PM_PAR_XPOS] - (int)source->modelEXT->params->data.F32[PM_PAR_XPOS]; 162 163 y->data.F32[n] = psfTry->metric->data.F32[i]; 164 dy->data.F32[n] = psfTry->metricErr->data.F32[i]; 165 graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]); 166 graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]); 167 graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]); 168 graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]); 169 n++; 170 } 171 x->n = y->n = dy->n = n; 172 173 range = graphdata.xmax - graphdata.xmin; 174 graphdata.xmax += 0.05*range; 175 graphdata.xmin -= 0.05*range; 176 range = graphdata.ymax - graphdata.ymin; 177 graphdata.ymax += 0.05*range; 178 graphdata.ymin -= 0.05*range; 179 180 // better choice for range? 181 // graphdata.xmin = -17.0; 182 // graphdata.xmax = -9.0; 183 graphdata.ymin = -0.51; 184 graphdata.ymax = +0.51; 185 186 KapaSetLimits (kapa1, &graphdata); 187 188 KapaSetFont (kapa1, "helvetica", 14); 189 KapaBox (kapa1, &graphdata); 190 KapaSendLabel (kapa1, "PSF Mag", KAPA_LABEL_XM); 191 KapaSendLabel (kapa1, "Ap Mag - PSF Mag", KAPA_LABEL_YM); 192 193 graphdata.color = KapaColorByName ("black"); 194 graphdata.ptype = 2; 195 graphdata.size = 0.5; 196 graphdata.style = 2; 197 graphdata.etype |= 0x01; 198 199 KapaPrepPlot (kapa1, n, &graphdata); 200 KapaPlotVector (kapa1, n, x->data.F32, "x"); 201 KapaPlotVector (kapa1, n, y->data.F32, "y"); 202 KapaPlotVector (kapa1, n, dy->data.F32, "dym"); 203 KapaPlotVector (kapa1, n, dy->data.F32, "dyp"); 204 205 // *** section b: fractional-x pixel 206 section.dx = 1.0; 207 section.dy = 0.5; 208 section.x = 0.0; 209 section.y = 0.5; 97 210 section.name = NULL; 98 211 psStringAppend (§ion.name, "a2"); 99 212 KapaSetSection (kapa1, §ion); 100 213 psFree (section.name); 101 pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, zn, -60.0*PS_RAD_DEG, -15.0*PS_RAD_DEG); 102 103 // view 3 on resid 104 section.dx = 0.5; 105 section.dy = 0.33; 214 215 graphdata.xmin = +32.0; 216 graphdata.xmax = -32.0; 217 graphdata.ymin = +32.0; 218 graphdata.ymax = -32.0; 219 220 // construct the plot vectors 221 n = 0; 222 for (int i = 0; i < psfTry->sources->n; i++) { 223 if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL) continue; 224 225 pmSource *source = psfTry->sources->data[i]; 226 x->data.F32[n] = source->modelEXT->params->data.F32[PM_PAR_YPOS] - (int)source->modelEXT->params->data.F32[PM_PAR_YPOS]; 227 228 y->data.F32[n] = psfTry->metric->data.F32[i]; 229 dy->data.F32[n] = psfTry->metricErr->data.F32[i]; 230 graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]); 231 graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]); 232 graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]); 233 graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]); 234 n++; 235 } 236 x->n = y->n = dy->n = n; 237 238 range = graphdata.xmax - graphdata.xmin; 239 graphdata.xmax += 0.05*range; 240 graphdata.xmin -= 0.05*range; 241 range = graphdata.ymax - graphdata.ymin; 242 graphdata.ymax += 0.05*range; 243 graphdata.ymin -= 0.05*range; 244 245 // better choice for range? 246 // graphdata.xmin = -17.0; 247 // graphdata.xmax = -9.0; 248 graphdata.ymin = -0.51; 249 graphdata.ymax = +0.51; 250 251 KapaSetLimits (kapa1, &graphdata); 252 253 KapaSetFont (kapa1, "helvetica", 14); 254 KapaBox (kapa1, &graphdata); 255 KapaSendLabel (kapa1, "PSF Mag", KAPA_LABEL_XM); 256 KapaSendLabel (kapa1, "Ap Mag - PSF Mag", KAPA_LABEL_YM); 257 258 graphdata.color = KapaColorByName ("black"); 259 graphdata.ptype = 2; 260 graphdata.size = 0.5; 261 graphdata.style = 2; 262 graphdata.etype |= 0x01; 263 264 KapaPrepPlot (kapa1, n, &graphdata); 265 KapaPlotVector (kapa1, n, x->data.F32, "x"); 266 KapaPlotVector (kapa1, n, y->data.F32, "y"); 267 KapaPlotVector (kapa1, n, dy->data.F32, "dym"); 268 KapaPlotVector (kapa1, n, dy->data.F32, "dyp"); 269 270 psFree (x); 271 psFree (y); 272 psFree (dy); 273 274 pmVisualAskUser(NULL); 275 return true; 276 } 277 278 // to see the structure of the psf model, place the sources in a fake image 1/10th the size 279 // at their appropriate relative location. later sources stomp on earlier sources 280 bool pmSourceVisualShowModelFits (pmPSF *psf, psArray *sources, psImageMaskType maskVal) { 281 282 if (!pmVisualIsVisual()) return true; 283 284 if (kapa2 == -1) { 285 kapa2 = KapaOpenNamedSocket ("kapa", "pmSource:images"); 286 if (kapa2 == -1) { 287 fprintf (stderr, "failure to open kapa; visual mode disabled\n"); 288 pmVisualSetVisual(false); 289 return false; 290 } 291 } 292 293 // create images 1/10 scale: 294 psImage *image = psImageAlloc (0.1*psf->fieldNx, 0.1*psf->fieldNy, PS_TYPE_F32); 295 psImage *model = psImageAlloc (0.1*psf->fieldNx, 0.1*psf->fieldNy, PS_TYPE_F32); 296 psImage *resid = psImageAlloc (0.1*psf->fieldNx, 0.1*psf->fieldNy, PS_TYPE_F32); 297 psImageInit (image, 0.0); 298 psImageInit (model, 0.0); 299 psImageInit (resid, 0.0); 300 301 for (int i = sources->n - 1; i >= 0; i--) { 302 pmSource *source = sources->data[i]; 303 if (!source) continue; 304 if (!source->pixels) continue; 305 306 pmSourceCacheModel (source, maskVal); 307 if (!source->modelFlux) continue; 308 309 pmModel *srcModel = pmSourceGetModel (NULL, source); 310 if (!model) continue; 311 312 float norm = srcModel->params->data.F32[PM_PAR_I0]; 313 314 int Xo = 0.1*srcModel->params->data.F32[PM_PAR_XPOS]; 315 int Yo = 0.1*srcModel->params->data.F32[PM_PAR_YPOS]; 316 317 // insert source pixels in the image at 1/10th offset 318 for (int iy = 0; iy < source->pixels->numRows; iy++) { 319 int jy = iy + Yo; 320 if (jy >= image->numRows) continue; 321 for (int ix = 0; ix < source->pixels->numCols; ix++) { 322 int jx = ix + Xo; 323 if (jx >= image->numCols) continue; 324 if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) continue; 325 if (source->modelFlux->data.F32[iy][ix] < 0.001) continue; 326 image->data.F32[jy][jx] = source->pixels->data.F32[iy][ix]; 327 model->data.F32[jy][jx] = source->modelFlux->data.F32[iy][ix]; 328 resid->data.F32[jy][jx] = source->pixels->data.F32[iy][ix] - norm*source->modelFlux->data.F32[iy][ix]; 329 } 330 } 331 } 332 333 // KapaClearSections (kapa2); 334 pmVisualScaleImage (kapa2, image, "image", 0, true); 335 pmVisualScaleImage (kapa2, model, "model", 1, true); 336 pmVisualScaleImage (kapa2, resid, "resid", 2, true); 337 338 # ifdef DEBUG 339 { 340 psFits *fits = psFitsOpen ("image.fits", "w"); 341 psFitsWriteImage (fits, NULL, image, 0, NULL); 342 psFitsClose (fits); 343 fits = psFitsOpen ("model.fits", "w"); 344 psFitsWriteImage (fits, NULL, model, 0, NULL); 345 psFitsClose (fits); 346 fits = psFitsOpen ("resid.fits", "w"); 347 psFitsWriteImage (fits, NULL, resid, 0, NULL); 348 psFitsClose (fits); 349 } 350 # endif 351 352 psFree (image); 353 psFree (model); 354 psFree (resid); 355 356 pmVisualAskUser(NULL); 357 return true; 358 } 359 360 bool pmSourceVisualShowModelFit (pmSource *source) { 361 362 if (!pmVisualIsVisual()) return true; 363 if (!source->pixels) return false; 364 if (!source->modelFlux) return false; 365 366 if (kapa2 == -1) { 367 kapa2 = KapaOpenNamedSocket ("kapa", "pmSource:images"); 368 if (kapa2 == -1) { 369 fprintf (stderr, "failure to open kapa; visual mode disabled\n"); 370 pmVisualSetVisual(false); 371 return false; 372 } 373 } 374 375 // KapaClearSections (kapa2); 376 pmVisualScaleImage (kapa2, source->pixels, "source", 0, false); 377 pmVisualScaleImage (kapa2, source->modelFlux, "model", 1, false); 378 379 pmModel *model = pmSourceGetModel (NULL, source); 380 float norm = model->params->data.F32[PM_PAR_I0]; 381 382 psImage *resid = psImageAlloc (source->pixels->numCols, source->pixels->numRows, PS_TYPE_F32); 383 for (int iy = 0; iy < source->pixels->numRows; iy++) { 384 for (int ix = 0; ix < source->pixels->numCols; ix++) { 385 if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) { 386 resid->data.F32[iy][ix] = NAN; 387 continue; 388 } 389 resid->data.F32[iy][ix] = source->pixels->data.F32[iy][ix] - norm*source->modelFlux->data.F32[iy][ix]; 390 } 391 } 392 pmVisualScaleImage (kapa2, resid, "resid", 2, false); 393 394 psFree (resid); 395 396 pmVisualAskUser(NULL); 397 return true; 398 } 399 400 bool pmSourceVisualPSFModelResid (pmTrend2D *trend, psVector *x, psVector *y, psVector *param, psVector *mask) { 401 402 KapaSection section; // put the positive profile in one and the residuals in another? 403 404 Graphdata graphdata; 405 406 if (!pmVisualIsVisual() || !plotPSF) return true; 407 408 if (kapa1 == -1) { 409 kapa1 = KapaOpenNamedSocket ("kapa", "pmSource:plots"); 410 if (kapa1 == -1) { 411 fprintf (stderr, "failure to open kapa; visual mode disabled\n"); 412 pmVisualSetVisual(false); 413 return false; 414 } 415 } 416 417 KapaClearPlots (kapa1); 418 KapaInitGraph (&graphdata); 419 420 float Xmin = +1e32; 421 float Xmax = -1e32; 422 float Ymin = +1e32; 423 float Ymax = -1e32; 424 float Fmin = +1e32; 425 float Fmax = -1e32; 426 427 psVector *resid = psVectorAlloc (x->n, PS_TYPE_F32); 428 psVector *model = psVectorAlloc (x->n, PS_TYPE_F32); 429 430 psVector *xm = psVectorAlloc (x->n, PS_TYPE_F32); 431 psVector *ym = psVectorAlloc (x->n, PS_TYPE_F32); 432 psVector *Fm = psVectorAlloc (x->n, PS_TYPE_F32); 433 434 int n = 0; 435 for (int i = 0; i < x->n; i++) { 436 model->data.F32[i] = pmTrend2DEval (trend, x->data.F32[i], y->data.F32[i]); 437 resid->data.F32[i] = param->data.F32[i] - model->data.F32[i]; 438 if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue; 439 Xmin = PS_MIN (Xmin, x->data.F32[i]); 440 Xmax = PS_MAX (Xmax, x->data.F32[i]); 441 Ymin = PS_MIN (Ymin, y->data.F32[i]); 442 Ymax = PS_MAX (Ymax, y->data.F32[i]); 443 Fmin = PS_MIN (Fmin, param->data.F32[i]); 444 Fmax = PS_MAX (Fmax, param->data.F32[i]); 445 xm->data.F32[n] = x->data.F32[i]; 446 ym->data.F32[n] = y->data.F32[i]; 447 Fm->data.F32[n] = param->data.F32[i]; 448 n++; 449 } 450 xm->n = ym->n = Fm->n = n; 451 452 // view 1 on resid 453 section.dx = 1.0; 454 section.dy = 0.5; 106 455 section.x = 0.0; 107 section.y = 0. 33;456 section.y = 0.0; 108 457 section.name = NULL; 109 psStringAppend (§ion.name, "a 3");458 psStringAppend (§ion.name, "a1"); 110 459 KapaSetSection (kapa1, §ion); 111 460 psFree (section.name); 112 pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, Zn, 30.0*PS_RAD_DEG, -15.0*PS_RAD_DEG); 113 114 // view 4 on resid 115 section.dx = 0.5; 116 section.dy = 0.33; 117 section.x = 0.5; 118 section.y = 0.33; 461 462 graphdata.color = KapaColorByName ("black"); 463 graphdata.xmin = Xmin; 464 graphdata.xmax = Xmax; 465 graphdata.ymin = Fmin; 466 graphdata.ymax = Fmax; 467 468 { 469 float range; 470 range = graphdata.xmax - graphdata.xmin; 471 graphdata.xmax += 0.05*range; 472 graphdata.xmin -= 0.05*range; 473 range = graphdata.ymax - graphdata.ymin; 474 graphdata.ymax += 0.05*range; 475 graphdata.ymin -= 0.05*range; 476 } 477 478 KapaSetLimits (kapa1, &graphdata); 479 KapaSetFont (kapa1, "helvetica", 14); 480 KapaBox (kapa1, &graphdata); 481 KapaSendLabel (kapa1, "X (pixels)", KAPA_LABEL_XM); 482 KapaSendLabel (kapa1, "Model Param", KAPA_LABEL_YM); 483 484 graphdata.ptype = 2; 485 graphdata.size = 1.0; 486 graphdata.style = 2; 487 KapaPrepPlot (kapa1, x->n, &graphdata); 488 KapaPlotVector (kapa1, x->n, x->data.F32, "x"); 489 KapaPlotVector (kapa1, x->n, param->data.F32, "y"); 490 491 graphdata.color = KapaColorByName ("red"); 492 graphdata.ptype = 1; 493 KapaPrepPlot (kapa1, xm->n, &graphdata); 494 KapaPlotVector (kapa1, xm->n, xm->data.F32, "x"); 495 KapaPlotVector (kapa1, xm->n, Fm->data.F32, "y"); 496 497 graphdata.color = KapaColorByName ("blue"); 498 graphdata.ptype = 1; 499 KapaPrepPlot (kapa1, x->n, &graphdata); 500 KapaPlotVector (kapa1, x->n, x->data.F32, "x"); 501 KapaPlotVector (kapa1, x->n, model->data.F32, "y"); 502 503 // view 2 on resid 504 section.dx = 1.0; 505 section.dy = 0.5; 506 section.x = 0.0; 507 section.y = 0.5; 119 508 section.name = NULL; 120 psStringAppend (§ion.name, "a 4");509 psStringAppend (§ion.name, "a2"); 121 510 KapaSetSection (kapa1, §ion); 122 511 psFree (section.name); 123 pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, Zn, -60.0*PS_RAD_DEG, -15.0*PS_RAD_DEG); 124 125 // view 5 on resid 126 section.dx = 0.5; 127 section.dy = 0.33; 128 section.x = 0.0; 129 section.y = 0.66; 130 section.name = NULL; 131 psStringAppend (§ion.name, "a5"); 132 KapaSetSection (kapa1, §ion); 133 psFree (section.name); 134 pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, Fn, 30.0*PS_RAD_DEG, -15.0*PS_RAD_DEG); 135 136 // view 6 on resid 137 section.dx = 0.5; 138 section.dy = 0.33; 139 section.x = 0.5; 140 section.y = 0.66; 141 section.name = NULL; 142 psStringAppend (§ion.name, "a6"); 143 KapaSetSection (kapa1, §ion); 144 psFree (section.name); 145 pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, Fn, -60.0*PS_RAD_DEG, -15.0*PS_RAD_DEG); 512 513 graphdata.color = KapaColorByName ("black"); 514 graphdata.xmin = Ymin; 515 graphdata.xmax = Ymax; 516 graphdata.ymin = Fmin; 517 graphdata.ymax = Fmax; 518 { 519 float range; 520 range = graphdata.xmax - graphdata.xmin; 521 graphdata.xmax += 0.05*range; 522 graphdata.xmin -= 0.05*range; 523 range = graphdata.ymax - graphdata.ymin; 524 graphdata.ymax += 0.05*range; 525 graphdata.ymin -= 0.05*range; 526 } 527 528 KapaSetLimits (kapa1, &graphdata); 529 KapaSetFont (kapa1, "helvetica", 14); 530 KapaBox (kapa1, &graphdata); 531 KapaSendLabel (kapa1, "Y (pixels)", KAPA_LABEL_XM); 532 KapaSendLabel (kapa1, "Model Param", KAPA_LABEL_YM); 533 534 graphdata.ptype = 2; 535 graphdata.size = 1.0; 536 graphdata.style = 2; 537 KapaPrepPlot (kapa1, y->n, &graphdata); 538 KapaPlotVector (kapa1, y->n, y->data.F32, "x"); 539 KapaPlotVector (kapa1, y->n, param->data.F32, "y"); 540 541 graphdata.color = KapaColorByName ("red"); 542 graphdata.ptype = 1; 543 KapaPrepPlot (kapa1, xm->n, &graphdata); 544 KapaPlotVector (kapa1, xm->n, ym->data.F32, "x"); 545 KapaPlotVector (kapa1, xm->n, Fm->data.F32, "y"); 546 547 graphdata.color = KapaColorByName ("blue"); 548 graphdata.ptype = 1; 549 KapaPrepPlot (kapa1, y->n, &graphdata); 550 KapaPlotVector (kapa1, y->n, y->data.F32, "x"); 551 KapaPlotVector (kapa1, y->n, model->data.F32, "y"); 552 553 psFree (xm); 554 psFree (ym); 555 psFree (Fm); 146 556 147 557 psFree (resid); 148 149 psFree (xn); 150 psFree (yn); 151 psFree (zn); 152 psFree (Zn); 558 psFree (model); 153 559 154 560 // pause and wait for user input: … … 159 565 } 160 566 161 // send in normalized points567 // Somewhat broken 3D plotting function (was used by pmSourceVisualPSFModelResid, but not anymore) 162 568 bool pmSourcePlotPoints3D (int myKapa, Graphdata *graphdata, psVector *xn, psVector *yn, psVector *zn, float theta, float phi) { 569 570 return true; 163 571 164 572 psVector *xv = psVectorAlloc (PS_MAX(6, 2*xn->n), PS_TYPE_F32); … … 192 600 KapaSetLimits (myKapa, graphdata); 193 601 194 // KapaSetFont (myKapa, "helvetica", 14);195 // KapaBox (myKapa, graphdata);196 // KapaSendLabel (myKapa, "&ss&h_x| (pixels)", KAPA_LABEL_XM);197 // KapaSendLabel (myKapa, "&ss&h_y| (pixels)", KAPA_LABEL_YM);198 199 602 graphdata->color = KapaColorByName ("black"); 200 603 graphdata->ptype = 100; -
branches/simtest_nebulous_branches/psModules/src/objects/pmSourceVisual.h
r23242 r27840 18 18 19 19 bool pmSourceVisualPSFModelResid (pmTrend2D *trend, psVector *x, psVector *y, psVector *param, psVector *mask); 20 bool pmSourceVisualPlotPSFMetric (pmPSFtry *try); 21 bool pmSourceVisualPlotPSFMetricSubpix (pmPSFtry *try); 22 23 bool pmSourceVisualShowModelFit (pmSource *source); 24 bool pmSourceVisualShowModelFits (pmPSF *psf, psArray *sources, psImageMaskType maskVal); 20 25 21 26 /// @} -
branches/simtest_nebulous_branches/psModules/src/objects/pmTrend2D.c
r21183 r27840 298 298 return PM_TREND_NONE; 299 299 } 300 301 bool pmTrend2DPrintMap (pmTrend2D *trend) { 302 303 if (!trend->map) return false; 304 if (!trend->map->map) return false; 305 306 for (int j = 0; j < trend->map->map->numRows; j++) { 307 for (int i = 0; i < trend->map->map->numCols; i++) { 308 fprintf (stderr, "%5.2f ", trend->map->map->data.F32[j][i]); 309 } 310 fprintf (stderr, "\t\t\t"); 311 for (int i = 0; i < trend->map->map->numCols; i++) { 312 fprintf (stderr, "%5.2f ", trend->map->error->data.F32[j][i]); 313 } 314 fprintf (stderr, "\n"); 315 } 316 return true; 317 } 318 -
branches/simtest_nebulous_branches/psModules/src/objects/pmTrend2D.h
r21183 r27840 97 97 pmTrend2DMode pmTrend2DModeFromString(psString name); 98 98 99 bool pmTrend2DPrintMap (pmTrend2D *trend); 100 99 101 /// @} 100 102 # endif -
branches/simtest_nebulous_branches/psModules/src/psmodules.h
r24891 r27840 10 10 #include <pmKapaPlots.h> 11 11 #include <pmVisual.h> 12 #include <ippStages.h> 13 #include <ippDiffMode.h> 12 14 13 15 // XXX the following headers define constructs needed by the elements below … … 29 31 #include <pmConfigDump.h> 30 32 #include <pmConfigRun.h> 33 #include <pmConfigRecipeValue.h> 31 34 #include <pmVersion.h> 32 35 … … 78 81 #include <pmRemnance.h> 79 82 #include <pmPattern.h> 83 #include <pmPatternIO.h> 80 84 81 85 // the following headers are from psModule:astrom … … 96 100 #include <pmSubtractionStamps.h> 97 101 #include <pmSubtractionKernels.h> 102 #include <pmSubtractionDeconvolve.h> 98 103 #include <pmSubtractionAnalysis.h> 99 104 #include <pmSubtractionMatch.h> … … 108 113 // the following headers are from psModule:objects 109 114 #include <pmSpan.h> 115 #include <pmFootprintSpans.h> 110 116 #include <pmFootprint.h> 111 117 #include <pmPeaks.h> 112 118 #include <pmDetections.h> 113 119 #include <pmMoments.h> 120 #include <pmSourceExtendedPars.h> 121 #include <pmSourceDiffStats.h> 114 122 #include <pmResiduals.h> 115 123 #include <pmGrowthCurve.h> … … 119 127 #include <pmSourceMasks.h> 120 128 #include <pmSource.h> 129 #include <pmPhotObj.h> 121 130 #include <pmSourceUtils.h> 122 131 #include <pmSourceIO.h> … … 133 142 #include <pmSourceVisual.h> 134 143 #include <pmSourceMatch.h> 144 #include <pmDetEff.h> 135 145 136 146 // The following headers are from random locations, here because they cross bounds -
branches/simtest_nebulous_branches/psModules/test/objects/tap_pmGrowthCurve.c
r24851 r27840 131 131 source->mode = PM_SOURCE_MODE_PSFSTAR; 132 132 133 source-> modelPSF->radiusFit= 15.0;133 source->apRadius = 15.0; 134 134 135 135 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 136 136 double refMag = source->apMag; 137 137 138 source-> modelPSF->radiusFit= 10.0;139 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 140 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 141 142 source-> modelPSF->radiusFit= 8.0;143 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 144 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 145 146 source-> modelPSF->radiusFit= 6.0;138 source->apRadius = 10.0; 139 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 140 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 141 142 source->apRadius = 8.0; 143 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 144 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 145 146 source->apRadius = 6.0; 147 147 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 148 148 ok_float_tol(refMag - source->apMag, +0.0003, 0.0001, "growth offset is is %f", refMag - source->apMag); 149 149 150 source-> modelPSF->radiusFit= 4.0;150 source->apRadius = 4.0; 151 151 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 152 152 ok_float_tol(refMag - source->apMag, +0.0020, 0.0001, "growth offset is is %f", refMag - source->apMag); 153 153 154 source-> modelPSF->radiusFit= 3.0;154 source->apRadius = 3.0; 155 155 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 156 156 ok_float_tol(refMag - source->apMag, -0.0001, 0.0001, "growth offset is is %f", refMag - source->apMag); 157 157 158 source-> modelPSF->radiusFit= 2.0;158 source->apRadius = 2.0; 159 159 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 160 160 ok_float_tol(refMag - source->apMag, -0.0075, 0.0001, "growth offset is is %f", refMag - source->apMag); … … 234 234 source->mode = PM_SOURCE_MODE_PSFSTAR; 235 235 236 source-> modelPSF->radiusFit= 15.0;236 source->apRadius = 15.0; 237 237 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 238 238 double refMag = source->apMag; 239 239 240 source-> modelPSF->radiusFit= 10.0;241 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 242 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 243 244 source-> modelPSF->radiusFit= 8.0;245 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 246 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 247 248 source-> modelPSF->radiusFit= 6.0;240 source->apRadius = 10.0; 241 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 242 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 243 244 source->apRadius = 8.0; 245 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 246 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 247 248 source->apRadius = 6.0; 249 249 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 250 250 ok_float_tol(refMag - source->apMag, +0.0004, 0.0001, "growth offset is is %f", refMag - source->apMag); 251 251 252 source-> modelPSF->radiusFit= 4.0;252 source->apRadius = 4.0; 253 253 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 254 254 ok_float_tol(refMag - source->apMag, +0.0026, 0.0001, "growth offset is is %f", refMag - source->apMag); 255 255 256 source-> modelPSF->radiusFit= 3.0;256 source->apRadius = 3.0; 257 257 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 258 258 ok_float_tol(refMag - source->apMag, -0.0001, 0.0001, "growth offset is is %f", refMag - source->apMag); 259 259 260 source-> modelPSF->radiusFit= 2.0;260 source->apRadius = 2.0; 261 261 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 262 262 ok_float_tol(refMag - source->apMag, -0.0103, 0.0001, "growth offset is is %f", refMag - source->apMag); … … 336 336 source->mode = PM_SOURCE_MODE_PSFSTAR; 337 337 338 source-> modelPSF->radiusFit= 15.0;338 source->apRadius = 15.0; 339 339 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 340 340 double refMag = source->apMag; 341 341 342 source-> modelPSF->radiusFit= 10.0;343 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 344 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 345 346 source-> modelPSF->radiusFit= 8.0;347 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 348 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 349 350 source-> modelPSF->radiusFit= 6.0;342 source->apRadius = 10.0; 343 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 344 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 345 346 source->apRadius = 8.0; 347 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 348 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 349 350 source->apRadius = 6.0; 351 351 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 352 352 ok_float_tol(refMag - source->apMag, +0.0006, 0.0001, "growth offset is is %f", refMag - source->apMag); 353 353 354 source-> modelPSF->radiusFit= 4.0;354 source->apRadius = 4.0; 355 355 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 356 356 ok_float_tol(refMag - source->apMag, +0.0038, 0.0001, "growth offset is is %f", refMag - source->apMag); 357 357 358 source-> modelPSF->radiusFit= 3.0;359 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 360 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 361 362 source-> modelPSF->radiusFit= 2.0;358 source->apRadius = 3.0; 359 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 360 ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag); 361 362 source->apRadius = 2.0; 363 363 pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0); 364 364 ok_float_tol(refMag - source->apMag, -0.0164, 0.0001, "growth offset is is %f", refMag - source->apMag); -
branches/simtest_nebulous_branches/psModules/test/objects/tap_pmModel.c
r21471 r27840 77 77 ok(model->nDOF == 0, "pmModelAlloc() set pmModel->nDOF correctly"); 78 78 ok(model->nIter == 0, "pmModelAlloc() set pmModel->nIter correctly"); 79 ok(model-> radiusFit == 0, "pmModelAlloc() set pmModel->radiusFitcorrectly");79 ok(model->fitRadius == 0, "pmModelAlloc() set pmModel->fitRadius correctly"); 80 80 ok(model->flags == PM_MODEL_STATUS_NONE, "pmModelAlloc() set pmModel->flags correctly"); 81 81 ok(model->residuals == NULL, "pmModelAlloc() set pmModel->residuals correctly"); … … 132 132 modelSrc->nIter = 3; 133 133 modelSrc->flags = PM_MODEL_STATUS_NONE; 134 modelSrc-> radiusFit= 4;134 modelSrc->fitRadius = 4; 135 135 pmModel *modelDst = pmModelCopy(modelSrc); 136 136 ok(modelDst != NULL && psMemCheckModel(modelDst), "pmModelCopy() returned a non-NULL pmModel"); … … 139 139 ok(modelDst->nIter == 3, "pmModelCopy() set the pmModel->nIter member correctly"); 140 140 ok(modelDst->flags == PM_MODEL_STATUS_NONE, "pmModelCopy() set the pmModel->flags member correctly"); 141 ok(modelDst-> radiusFit == 4, "pmModelCopy() set the pmModel->radiusFitmember correctly");141 ok(modelDst->fitRadius == 4, "pmModelCopy() set the pmModel->fitRadius member correctly"); 142 142 143 143 psFree(modelSrc); -
branches/simtest_nebulous_branches/psModules/test/objects/tap_pmModelUtils.c
r15985 r27840 81 81 ok(tmpModel->nIter == testModelPSF->nIter, "pmModelFromPSF() set the model->nIter correctly"); 82 82 ok(tmpModel->flags == testModelPSF->flags, "pmModelFromPSF() set the model->flags correctly"); 83 ok(tmpModel-> radiusFit == testModelPSF->radiusFit, "pmModelFromPSF() set the model->radiusFitcorrectly");83 ok(tmpModel->fitRadius == testModelPSF->fitRadius, "pmModelFromPSF() set the model->fitRadius correctly"); 84 84 ok(tmpModel->modelFunc == testModelPSF->modelFunc, "pmModelFromPSF() set the model->modelFunc correctly"); 85 85 ok(tmpModel->modelFlux == testModelPSF->modelFlux, "pmModelFromPSF() set the model->modelFlux correctly"); … … 140 140 ok(tmpModel->nIter == testModelPSF->nIter, "pmModelFromPSF() set the model->nIter correctly"); 141 141 ok(tmpModel->flags == testModelPSF->flags, "pmModelFromPSF() set the model->flags correctly"); 142 ok(tmpModel-> radiusFit == testModelPSF->radiusFit, "pmModelFromPSF() set the model->radiusFitcorrectly");142 ok(tmpModel->fitRadius == testModelPSF->fitRadius, "pmModelFromPSF() set the model->fitRadius correctly"); 143 143 ok(tmpModel->modelFunc == testModelPSF->modelFunc, "pmModelFromPSF() set the model->modelFunc correctly"); 144 144 ok(tmpModel->modelFlux == testModelPSF->modelFlux, "pmModelFromPSF() set the model->modelFlux correctly"); -
branches/simtest_nebulous_branches/psModules/test/objects/tap_pmSourcePhotometry.c
r9922 r27840 96 96 source->modelPSF = pmModelFromPSF (modelRef, psf); 97 97 source->modelPSF->dparams->data.F32[PM_PAR_I0] = 1; 98 source-> modelPSF->radiusFit= radius;98 source->apRadius = radius; 99 99 100 100 // measure photometry for centered source (fractional pix : 0.5,0.5)
Note:
See TracChangeset
for help on using the changeset viewer.
