Changeset 10052 for trunk/psphot/src/psphotEnsemblePSF.c
- Timestamp:
- Nov 17, 2006, 1:04:04 PM (20 years ago)
- File:
-
- 1 edited
-
trunk/psphot/src/psphotEnsemblePSF.c (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psphot/src/psphotEnsemblePSF.c
r10032 r10052 1 1 # include "psphot.h" 2 2 3 // fit all reasonable sources with the linear PSF model 4 bool psphotEnsemblePSF (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, bool final) { 5 6 bool status; 3 // fit flux (and optionally sky model) to all reasonable sources 4 // with the linear fitting process. sources must have an associated 5 // model with selected pixels, and the fit radius must be defined 6 7 // given the set of sources, each of which points to the pixels in the 8 // science image, we construct a set of simulated sources with their own pixels. 9 // these are used to determine the simultaneous linear fit of fluxes. 10 // the analysis is performed wrt the simulated pixel values 11 12 static bool SetBorderT (psSparseBorder *border, pmReadout *readout, psArray *refSources, bool fitSlope); 13 14 bool psphotEnsemblePSF (pmReadout *readout, psArray *refSources, psMetadata *recipe, pmPSF *psf, bool final) { 15 16 bool isPSF; 17 bool status; 7 18 float x; 8 19 float y; … … 10 21 float r; 11 22 12 // psRegion allArray = psRegionSet (0, 0, 0, 0);13 14 23 psTimerStart ("psphot"); 15 24 16 25 // source analysis is done in spatial order 17 sources = psArraySort (sources, psphotSortByY); 18 19 // radius for source moments if star is saturated 20 // XXX we already do this in psphotSourceStats, is it still needed? 21 float INNER_RADIUS = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS"); 22 23 // setup the PSF fit details 24 psphotInitRadiusPSF (recipe, psf->type); 25 26 // pre-calculate all model pixels 27 psArray *models = psArrayAllocEmpty (sources->n); 28 psVector *index = psVectorAllocEmpty (sources->n, PS_TYPE_U32); 26 refSources = psArraySort (refSources, psphotSortByY); 27 28 // storage arrays for fitSources and sequence index 29 psArray *fitSources = psArrayAllocEmpty (refSources->n); 30 psVector *index = psVectorAllocEmpty (refSources->n, PS_TYPE_U32); 29 31 30 32 // option to limit analysis to a specific region … … 32 34 psRegion AnalysisRegion = psRegionFromString (region); 33 35 AnalysisRegion = psRegionForImage (readout->image, AnalysisRegion); 34 // psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));35 36 if (psRegionIsNaN (AnalysisRegion)) psAbort ("psphot", "analysis region mis-defined"); 36 37 … … 41 42 } 42 43 43 for (int i = 0; i < sources->n; i++) { 44 pmSource *inSource = sources->data[i]; 44 // construct source table with stand-alone fitSources 45 for (int i = 0; i < refSources->n; i++) { 46 pmSource *refSource = refSources->data[i]; 45 47 46 48 // skip non-astronomical objects (very likely defects) 47 // XXX EAM : should we try these anyway? 48 if (inSource->type == PM_SOURCE_TYPE_DEFECT) continue; 49 if (inSource->type == PM_SOURCE_TYPE_SATURATED) continue; 49 if (refSource->type == PM_SOURCE_TYPE_DEFECT) continue; 50 if (refSource->type == PM_SOURCE_TYPE_SATURATED) continue; 50 51 if (final) { 51 if ( inSource->mode & PM_SOURCE_MODE_SUBTRACTED) continue;52 if (refSource->mode & PM_SOURCE_MODE_SUBTRACTED) continue; 52 53 } else { 53 if ( inSource->mode & PM_SOURCE_MODE_BLEND) continue;54 if (refSource->mode & PM_SOURCE_MODE_BLEND) continue; 54 55 } 55 56 56 if (inSource->moments->x < AnalysisRegion.x0) continue; 57 if (inSource->moments->y < AnalysisRegion.y0) continue; 58 if (inSource->moments->x > AnalysisRegion.x1) continue; 59 if (inSource->moments->y > AnalysisRegion.y1) continue; 60 61 pmSource *otSource = pmSourceAlloc (); 62 63 // really saturated stars should be re-measured for a better centroid 64 // XXX EAM : move this to a 'clear satstar function' 65 // XXX : place this in pmSourceMoments or wherever it is called? 66 if (inSource->mode & PM_SOURCE_MODE_SATSTAR) { 67 status = pmSourceMoments (inSource, INNER_RADIUS); 68 } 69 70 // XXX EAM : add option to use EXT or PSF form 71 // use the source moments, etc to guess basic model parameters 72 pmModel *modelEXT = pmSourceModelGuess (inSource, psf->type); 73 if (inSource->mode & PM_SOURCE_MODE_SATSTAR) { 74 modelEXT->params->data.F32[PM_PAR_XPOS] = inSource->moments->x; 75 modelEXT->params->data.F32[PM_PAR_YPOS] = inSource->moments->y; 76 } else { 77 // peak-up on peak (for non-sat objects) 78 79 // ix,iy must land on inSource->pixels 80 int ix = PS_MAX (inSource->pixels->col0 + 1, PS_MIN (inSource->pixels->col0 + inSource->pixels->numCols - 2, inSource->peak->x)); 81 int iy = PS_MAX (inSource->pixels->row0 + 1, PS_MIN (inSource->pixels->row0 + inSource->pixels->numRows - 2, inSource->peak->y)); 82 83 psPolynomial2D *bicube = psImageBicubeFit (inSource->pixels, ix, iy); 84 psPlane min = psImageBicubeMin (bicube); 85 86 psTrace ("psphot", 5, "peak coord: %f %f -> %f %f\n", 87 modelEXT->params->data.F32[PM_PAR_XPOS], modelEXT->params->data.F32[PM_PAR_YPOS], min.x + ix, min.y + iy); 88 89 // if min point is too deviant, keep the old value 90 if ((fabs(min.x) < 1.5) && (fabs(min.y) < 1.5)) { 91 modelEXT->params->data.F32[PM_PAR_XPOS] = min.x + ix; 92 modelEXT->params->data.F32[PM_PAR_YPOS] = min.y + iy; 93 } 94 psFree (bicube); 95 } 96 97 // set PSF parameters for this model 98 pmModel *model = pmModelFromPSF (modelEXT, psf); 99 psFree (modelEXT); 57 // which model to use? 58 pmModel *model = pmSourceGetModel (&isPSF, refSource); 59 if (model == NULL) continue; // model must be defined 100 60 101 61 // save the original coords … … 103 63 y = model->params->data.F32[PM_PAR_YPOS]; 104 64 105 // set the fit radius based on the object flux limit and the model 106 psphotCheckRadiusPSF (readout, inSource, model); 65 // is the source in the region of interest? 66 if (x < AnalysisRegion.x0) continue; 67 if (y < AnalysisRegion.y0) continue; 68 if (x > AnalysisRegion.x1) continue; 69 if (y > AnalysisRegion.y1) continue; 70 71 pmSource *fitSource = pmSourceAlloc (); 107 72 108 73 // make temporary copies of the image pixels and mask 109 74 // we need to have a copy which will not be modified by changes to its neighbor 110 otSource->mask = psImageCopy (NULL, inSource->mask, PS_TYPE_U8); 111 otSource->pixels = psImageCopy (NULL, inSource->pixels, PS_TYPE_F32); 112 otSource->weight = psImageCopy (NULL, inSource->weight, PS_TYPE_F32); 113 114 // build the model image 115 psImage *flux = otSource->pixels; 116 psImage *mask = otSource->mask; 75 fitSource->mask = psImageCopy (NULL, refSource->mask, PS_TYPE_U8); 76 fitSource->pixels = psImageCopy (NULL, refSource->pixels, PS_TYPE_F32); 77 fitSource->weight = psImageCopy (NULL, refSource->weight, PS_TYPE_F32); 117 78 118 79 // set model to unit peak, zero sky (we assume sky is subtracted) 80 // XXX do this with the actual model or use keep the original guess? 119 81 model->params->data.F32[PM_PAR_SKY] = 0.0; 120 82 model->params->data.F32[PM_PAR_I0] = 1.0; 121 83 122 84 // fill in the model pixel values 123 psImageInit (flux, 0.0); 124 psImageKeepCircle (mask, x, y, model->radiusFit, "OR", PM_MASK_MARK); 125 pmModelAdd (flux, mask, model, false, false); 126 127 // calculate nDOF (nPix - 1) 128 // int Nmaskpix = psImageCountPixelMask (mask, allArray, PM_MASK_SAT); 129 // model->nDOF = mask->numCols*mask->numRows - Nmaskpix - 1; 85 psImageInit (fitSource->pixels, 0.0); 86 psImageKeepCircle (fitSource->mask, x, y, model->radiusFit, "OR", PM_MASK_MARK); 87 pmModelAdd (fitSource->pixels, fitSource->mask, model, false, false); 130 88 131 89 // save source in list 132 otSource->modelPSF = model; 133 index->data.U32[models->n] = i; 134 psArrayAdd (models, 100, otSource); 135 psFree (otSource); 136 } 137 psLogMsg ("psphot.emsemble", 4, "built models: %f (%ld objects)\n", psTimerMark ("psphot"), sources->n); 138 139 // fill out the sparse matrix 140 psSparse *sparse = psSparseAlloc (models->n, 100); 141 psVector *weight = psVectorAlloc (models->n, PS_TYPE_F32); 142 psVector *errors = psVectorAlloc (models->n, PS_TYPE_F32); 90 if (isPSF) { 91 fitSource->modelPSF = psMemIncrRefCounter (model); 92 } else { 93 fitSource->modelEXT = psMemIncrRefCounter (model); 94 } 95 index->data.U32[fitSources->n] = i; 96 psArrayAdd (fitSources, 100, fitSource); 97 psFree (fitSource); 98 } 99 psLogMsg (__func__, 4, "built fitSources: %f (%ld objects)\n", psTimerMark ("psphot"), refSources->n); 100 101 // vectors to store stats for each object 102 psVector *weight = psVectorAlloc (fitSources->n, PS_TYPE_F32); 103 psVector *errors = psVectorAlloc (fitSources->n, PS_TYPE_F32); 143 104 144 105 // create the border matrix (includes the sparse matrix) 145 106 // for just sky: 1 row; for x,y terms: 3 rows 107 psSparse *sparse = psSparseAlloc (fitSources->n, 100); 146 108 psSparseBorder *border = psSparseBorderAlloc (sparse, 1); 147 109 148 for (int i = 0; i < models->n; i++) { 110 // fill out the sparse matrix elements and border elements (B) 111 // Ri is the current refSource of interest (sci pixels) 112 // Fi is the current fitSource of interest (fit pixels) 113 for (int i = 0; i < fitSources->n; i++) { 149 114 int N = index->data.U32[i]; 150 pmSource * Fi = sources->data[N];151 pmSource * Mi = models->data[i];115 pmSource *Ri = refSources->data[N]; 116 pmSource *Fi = fitSources->data[i]; 152 117 153 118 // scale by diagonal element (auto-cross-product) 154 r = pmSourceCrossProduct ( Mi, Mi, CONSTANT_PHOTOMETRIC_WEIGHTS);119 r = pmSourceCrossProduct (Fi, Fi, CONSTANT_PHOTOMETRIC_WEIGHTS); 155 120 weight->data.F32[i] = r; 156 121 157 122 // the formal error depends on the weighting scheme 158 123 if (CONSTANT_PHOTOMETRIC_WEIGHTS) { 159 float var = pmSourceCrossProduct ( Mi, Mi, false);124 float var = pmSourceCrossProduct (Fi, Fi, false); 160 125 errors->data.F32[i] = 1.0 / sqrt(var); 161 126 } else { … … 166 131 167 132 // find the image x model value 168 f = pmSourceCrossProduct ( Fi, Mi, CONSTANT_PHOTOMETRIC_WEIGHTS);133 f = pmSourceCrossProduct (Ri, Fi, CONSTANT_PHOTOMETRIC_WEIGHTS); 169 134 psSparseVectorElement (sparse, i, f / r); 170 135 171 136 // add the per-source weights (border region) 172 p = pmSourceWeight (Mi, CONST, CONSTANT_PHOTOMETRIC_WEIGHTS);173 // px = pmSourceWeight (Mi, XTERM, CONSTANT_PHOTOMETRIC_WEIGHTS);174 // py = pmSourceWeight (Mi, YTERM, CONSTANT_PHOTOMETRIC_WEIGHTS);137 float p = pmSourceWeight (Fi, 0, CONSTANT_PHOTOMETRIC_WEIGHTS); 138 // float px = pmSourceWeight (Fi, 1, CONSTANT_PHOTOMETRIC_WEIGHTS); 139 // float py = pmSourceWeight (Fi, 2, CONSTANT_PHOTOMETRIC_WEIGHTS); 175 140 psSparseBorderElementB (border, i, 0, p); 176 141 // psSparseBorderElementB (border, i, 1, px); … … 178 143 179 144 // loop over all other stars following this one 180 for (int j = i + 1; j < models->n; j++) {181 pmSource * Mj = models->data[j];145 for (int j = i + 1; j < fitSources->n; j++) { 146 pmSource *Fj = fitSources->data[j]; 182 147 183 148 // skip over disjoint source images, break after last possible overlap 184 if ( Mi->pixels->row0 + Mi->pixels->numRows < Mj->pixels->row0) break;185 if ( Mj->pixels->row0 + Mj->pixels->numRows < Mi->pixels->row0) continue;186 if ( Mi->pixels->col0 + Mi->pixels->numCols < Mj->pixels->col0) continue;187 if ( Mj->pixels->col0 + Mj->pixels->numCols < Mi->pixels->col0) continue;149 if (Fi->pixels->row0 + Fi->pixels->numRows < Fj->pixels->row0) break; 150 if (Fj->pixels->row0 + Fj->pixels->numRows < Fi->pixels->row0) continue; 151 if (Fi->pixels->col0 + Fi->pixels->numCols < Fj->pixels->col0) continue; 152 if (Fj->pixels->col0 + Fj->pixels->numCols < Fi->pixels->col0) continue; 188 153 189 154 // got an overlap; calculate cross-product and add to output array 190 f = pmSourceCrossProduct ( Mi, Mj, CONSTANT_PHOTOMETRIC_WEIGHTS);155 f = pmSourceCrossProduct (Fi, Fj, CONSTANT_PHOTOMETRIC_WEIGHTS); 191 156 psSparseMatrixElement (sparse, j, i, f / r); 192 157 } 193 158 } 194 psLogMsg ("psphot.emsemble", 4, "built matrix: %f (%d elements)\n", psTimerMark ("psphot"), sparse->Nelem); 159 psSparseResort (sparse); 160 psLogMsg (__func__, 4, "built matrix: %f (%d elements)\n", psTimerMark ("psphot"), sparse->Nelem); 161 162 // set the sky, sky_x, sky_y components of border matrix 163 // XXX ignore sky slope terms for now 164 SetBorderT (border, readout, refSources, false); 165 166 psSparseConstraint constraint; 167 constraint.paramMin = 0.0; 168 constraint.paramMax = 1e8; 169 constraint.paramDelta = 1e8; 170 171 // solve for normalization terms (need include local sky?) 172 psVector *norm = NULL; 173 psVector *skyfit = NULL; 174 psSparseBorderSolve (&norm, &skyfit, constraint, border, 3); 175 176 // adjust fitSources, set refSources and subtract 177 for (int i = 0; i < fitSources->n; i++) { 178 int N = index->data.U32[i]; 179 pmSource *Ri = refSources->data[N]; 180 pmModel *model = pmSourceGetModel (NULL, Ri); 181 182 // assign linearly-fitted normalization 183 if (isnan(norm->data.F32[i])) { 184 psAbort ("psphot", "ensemble source is nan"); 185 } 186 model->params->data.F32[PM_PAR_I0] = norm->data.F32[i]; 187 // XXX note: is the value of 'errors' modified by the sky fit? 188 model->dparams->data.F32[PM_PAR_I0] = errors->data.F32[i]; 189 190 // subtract object 191 pmModelSub (Ri->pixels, Ri->mask, model, false, false); 192 Ri->mode |= PM_SOURCE_MODE_SUBTRACTED; 193 if (!final) Ri->mode |= PM_SOURCE_MODE_TEMPSUB; 194 // XXX not sure about the use of TEMPSUB 195 } 196 197 // measure chisq for each source 198 for (int i = 0; final && (i < fitSources->n); i++) { 199 int N = index->data.U32[i]; 200 pmSource *Ri = refSources->data[N]; 201 pmModel *model = pmSourceGetModel (NULL, Ri); 202 203 x = model->params->data.F32[PM_PAR_XPOS]; 204 y = model->params->data.F32[PM_PAR_YPOS]; 205 206 psImageKeepCircle (Ri->mask, x, y, model->radiusFit, "OR", PM_MASK_MARK); 207 pmSourceChisq (model, Ri->pixels, Ri->mask, Ri->weight); 208 psImageKeepCircle (Ri->mask, x, y, model->radiusFit, "AND", PS_NOT_U8(PM_MASK_MARK)); 209 } 210 211 psFree (index); 212 psFree (sparse); 213 psFree (fitSources); 214 psFree (norm); 215 psFree (weight); 216 psFree (errors); 217 218 psLogMsg (__func__, 3, "measure ensemble of PSFs: %f sec\n", psTimerMark ("psphot")); 219 return true; 220 } 221 222 // calculate the weight terms for the sky fit component of the matrix 223 static bool SetBorderT (psSparseBorder *border, pmReadout *readout, psArray *refSources, bool fitSlope) { 195 224 196 225 // generate the image-wide weight terms 197 // first, mask all object pixels 198 for (int i = 0; i < models->n; i++) { 199 int N = index->data.U32[i]; 200 pmSource *Fi = sources->data[N]; 201 pmSource *Mi = models->data[i]; 202 203 // XXX need to select the correct mode (check this against the selections below 204 // - which model is appropriate for the given source? 205 // - which radius is appropriate for the given source? 206 // - where do x,y come from? 207 psImageKeepCircle (Mi->mask, x, y, model->radiusFit, "OR", PM_MASK_MARK); 226 // turn on MARK for all image pixels 227 psRegion fullArray = psRegionSet (0, 0, 0, 0); 228 fullArray = psRegionForImage (readout->mask, fullArray); 229 psImageMaskRegion (readout->mask, fullArray, "OR", PM_MASK_MARK); 230 231 // turn off MARK for all object pixels 232 // we must use the refSources here since their pixels point at the science image 233 for (int i = 0; i < refSources->n; i++) { 234 pmSource *refSource = refSources->data[i]; 235 pmModel *model = pmSourceGetModel (NULL, refSource); 236 float x = model->params->data.F32[PM_PAR_XPOS]; 237 float y = model->params->data.F32[PM_PAR_YPOS]; 238 psImageMaskCircle (refSource->mask, x, y, model->radiusFit, "AND", PS_NOT_U8(PM_MASK_MARK)); 208 239 } 209 240 210 241 // accumulate the image statistics from the masked regions 211 for (int j = 0; j < numRows; j++) { 212 for (int i = 0; i < numCols; i++) { 213 w += image->data.F32[j][i]/weight->data.F32[j][i]; 214 x += i*image->data.F32[j][i]/weight->data.F32[j][i]; 215 y += j*image->data.F32[j][i]/weight->data.F32[j][i]; 216 x2 += i*i*image->data.F32[j][i]/weight->data.F32[j][i]; 217 xy += i*j*image->data.F32[j][i]/weight->data.F32[j][i]; 218 y2 += j*j*image->data.F32[j][i]/weight->data.F32[j][i]; 242 psF32 **image = readout->image->data.F32; 243 psF32 **weight = readout->weight->data.F32; 244 psU8 **mask = readout->mask->data.U8; 245 246 double w, x, y, x2, xy, y2, xc, yc; 247 w = x = y = x2 = xy = y2 = 0; 248 249 int col0 = readout->image->col0; 250 int row0 = readout->image->row0; 251 252 for (int j = 0; j < readout->image->numRows; j++) { 253 for (int i = 0; i < readout->image->numCols; i++) { 254 if (mask[j][i]) continue; 255 w += image[j][i]/weight[j][i]; 256 if (!fitSlope) continue; 257 xc = i + col0; 258 yc = j + row0; 259 x += xc*image[j][i]/weight[j][i]; 260 y += yc*image[j][i]/weight[j][i]; 261 x2 += xc*xc*image[j][i]/weight[j][i]; 262 xy += xc*yc*image[j][i]/weight[j][i]; 263 y2 += yc*yc*image[j][i]/weight[j][i]; 219 264 } 220 265 } 266 267 // turn off MARK for all image pixels 268 psImageMaskRegion (readout->mask, fullArray, "AND", PS_NOT_U8(PM_MASK_MARK)); 269 270 // set the Border T elements 221 271 psSparseBorderElementT (border, 0, 0, w); 222 if ( 0) {272 if (fitSlope) { 223 273 psSparseBorderElementT (border, 1, 0, x); 224 274 psSparseBorderElementT (border, 2, 0, y); … … 230 280 psSparseBorderElementT (border, 2, 2, y2); 231 281 } 232 233 psSparseConstraint constraint;234 constraint.paramMin = 0.0;235 constraint.paramMax = 1e8;236 constraint.paramDelta = 1e8;237 238 // solve for normalization terms (need include local sky?)239 psSparseResort (sparse);240 psSparseBorderSolve (&xFit, &yFit, constraint, border, 3);241 242 // psVector *norm = psSparseSolve (NULL, constraint, sparse, 3);243 244 // adjust models, set sources and subtract245 for (int i = 0; i < models->n; i++) {246 int N = index->data.U32[i];247 pmSource *Fi = sources->data[N];248 pmSource *Mi = models->data[i];249 250 // if we already have a PSF model, free it.251 psFree (Fi->modelPSF);252 253 // need to increment counter so we can free models here and sources above254 Fi->modelPSF = psMemIncrRefCounter (Mi->modelPSF);255 256 // assign linearly-fitted normalization257 if (isnan(norm->data.F32[i])) {258 psAbort ("psphot", "ensemble source is nan");259 }260 Fi->modelPSF->params->data.F32[PM_PAR_I0] = norm->data.F32[i];261 // XXX I was using this before, but it is not strictly accurate262 // XXX EAM : this factor of sqrt(2) makes the errors consistent, but I don't understand it263 // Fi->modelPSF->dparams->data.F32[PM_PAR_I0] = sqrt(sqrt(2) * norm->data.F32[i] / (sparse->Bfj->data.F32[i] * weight->data.F32[i]));264 Fi->modelPSF->dparams->data.F32[PM_PAR_I0] = errors->data.F32[i];265 266 // subtract object267 pmModelSub (Fi->pixels, Fi->mask, Fi->modelPSF, false, false);268 Fi->mode |= PM_SOURCE_MODE_SUBTRACTED;269 if (!final) Fi->mode |= PM_SOURCE_MODE_TEMPSUB;270 }271 272 // measure chisq for each source273 for (int i = 0; final && (i < models->n); i++) {274 int N = index->data.U32[i];275 pmSource *Fi = sources->data[N];276 pmModel *model = Fi->modelPSF;277 278 x = model->params->data.F32[PM_PAR_XPOS];279 y = model->params->data.F32[PM_PAR_YPOS];280 281 psImageKeepCircle (Fi->mask, x, y, model->radiusFit, "OR", PM_MASK_MARK);282 pmSourceChisq (model, Fi->pixels, Fi->mask, Fi->weight);283 psImageKeepCircle (Fi->mask, x, y, model->radiusFit, "AND", PS_NOT_U8(PM_MASK_MARK));284 }285 286 psFree (index);287 psFree (sparse);288 psFree (models);289 psFree (norm);290 psFree (weight);291 psFree (errors);292 293 psLogMsg ("psphot.emsemble", 3, "measure ensemble of PSFs: %f sec\n", psTimerMark ("psphot"));294 282 return true; 295 283 }
Note:
See TracChangeset
for help on using the changeset viewer.
