IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ticket #624: pmPSFtry.c

File pmPSFtry.c, 12.2 KB (added by eugene, 21 years ago)

pmPSFtry.c with indent errors fixed.

Line 
1# include <pslib.h>
2# include "psLibUtils.h"
3# include "pmObjects.h"
4# include "psModulesUtils.h"
5# include "pmPSF.h"
6# include "pmPSFtry.h"
7# include "pmModelGroup.h"
8
9// ******** pmPSFtry functions **************************************************
10// * pmPSFtry holds a single pmPSF model test, with the input sources, the freely
11// * fitted version of the model, the pmPSF fit to the fitted model parameters,
12// * and the PSF fits to the source. It also includes the statistics from the
13// * fits, both the individual sources, and the collection
14
15// free a pmPSFtry structure
16static void pmPSFtryFree (pmPSFtry *test)
17{
18
19 if (test == NULL)
20 return;
21
22 psFree (test->psf);
23 psFree (test->sources);
24 psFree (test->modelFLT);
25 psFree (test->modelPSF);
26 psFree (test->metric);
27 psFree (test->fitMag);
28 psFree (test->mask);
29 return;
30}
31
32// allocate a pmPSFtry based on the desired sources and the model (identified by name)
33pmPSFtry *pmPSFtryAlloc (psArray *sources, char *modelName)
34{
35
36 pmModelType type;
37
38 pmPSFtry *test = (pmPSFtry *) psAlloc(sizeof(pmPSFtry));
39
40 // XXX probably need to increment ref counter
41 type = pmModelSetType (modelName);
42 test->psf = pmPSFAlloc (type);
43 test->sources = psMemCopy(sources);
44 test->modelFLT = psArrayAlloc (sources->n);
45 test->modelPSF = psArrayAlloc (sources->n);
46 test->metric = psVectorAlloc (sources->n, PS_TYPE_F64);
47 test->fitMag = psVectorAlloc (sources->n, PS_TYPE_F64);
48 test->mask = psVectorAlloc (sources->n, PS_TYPE_U8);
49
50 for (int i = 0; i < test->modelFLT->n; i++) {
51 test->mask->data.U8[i] = 0;
52 test->modelFLT->data[i] = NULL;
53 test->modelPSF->data[i] = NULL;
54 test->metric->data.F64[i] = 0;
55 test->fitMag->data.F64[i] = 0;
56 }
57
58 psMemSetDeallocator(test, (psFreeFunc) pmPSFtryFree);
59 return (test);
60}
61
62// build a pmPSFtry for the given model:
63// - fit each source with the free-floating model
64// - construct the pmPSF from the collection of models
65// - fit each source with the PSF-parameter models
66// - measure the pmPSF quality metric (dApResid)
67
68// sources used in for pmPSFtry may be masked by the analysis
69// mask values indicate the reason the source was rejected:
70
71pmPSFtry *pmPSFtryModel (psArray *sources, char *modelName, float RADIUS)
72{
73 bool status;
74 float obsMag;
75 float fitMag;
76 float x;
77 float y;
78 int Nflt = 0;
79 int Npsf = 0;
80
81 pmPSFtry *try = pmPSFtryAlloc (sources, modelName);
82
83 // stage 1: fit an independent model (freeModel) to all sources
84 psTimerStart ("fit");
85 for (int i = 0; i < try->sources->n; i++) {
86
87 pmSource *source = try->sources->data[i];
88 pmModel *model = pmSourceModelGuess (source, try->psf->type);
89 x = source->peak->x;
90 y = source->peak->y;
91
92 // set temporary object mask and fit object
93 // fit model as FLT, not PSF
94 psImageKeepCircle (source->mask, x, y, RADIUS, "OR", PSPHOT_MASK_MARKED);
95 status = pmSourceFitModel (source, model, false);
96 psImageKeepCircle (source->mask, x, y, RADIUS, "AND", ~PSPHOT_MASK_MARKED);
97
98 // exclude the poor fits
99 if (!status) {
100 try->mask->data.U8[i] = PSFTRY_MASK_FLT_FAIL;
101 psFree (model);
102 continue;
103 }
104 try->modelFLT->data[i] = model;
105 Nflt ++;
106 }
107 psLogMsg ("psphot.psftry", 4, "fit flt: %f sec for %d sources\n", psTimerMark ("fit"), sources->n);
108 psTrace ("psphot.psftry", 3, "keeping %d of %d PSF candidates (FLT)\n", Nflt, sources->n);
109
110 // make this optional?
111 // DumpModelFits (try->modelFLT, "modelsFLT.dat");
112
113 // stage 2: construct a psf (pmPSF) from this collection of model fits
114 pmPSFFromModels (try->psf, try->modelFLT, try->mask);
115
116 // stage 3: refit with fixed shape parameters
117 psTimerStart ("fit");
118 for (int i = 0; i < try->sources->n; i++) {
119 // masked for: bad model fit, outlier in parameters
120 if (try->mask->data.U8[i] & PSFTRY_MASK_ALL) continue;
121
122 pmSource *source = try->sources->data[i];
123 pmModel *modelFLT = try->modelFLT->data[i];
124
125 // set shape for this model based on PSF
126 pmModel *modelPSF = pmModelFromPSF (modelFLT, try->psf);
127 x = source->peak->x;
128 y = source->peak->y;
129
130 psImageKeepCircle (source->mask, x, y, RADIUS, "OR", PSPHOT_MASK_MARKED);
131 status = pmSourceFitModel (source, modelPSF, true);
132
133 // skip poor fits
134 if (!status) {
135 try->mask->data.U8[i] = PSFTRY_MASK_PSF_FAIL;
136 psFree (modelPSF);
137 goto next_source;
138 }
139
140 // otherwise, save the resulting model
141 try->modelPSF->data[i] = modelPSF;
142
143 // XXX : use a different aperture radius from the fit radius?
144 // XXX : use a different estimator for the local sky?
145 // XXX : pass 'source' as input?
146 if (!pmSourcePhotometry (&fitMag, &obsMag, modelPSF, source->pixels, source->mask)) {
147 try->mask->data.U8[i] = PSFTRY_MASK_BAD_PHOT;
148 goto next_source;
149 }
150
151 try->metric->data.F64[i] = obsMag - fitMag;
152 try->fitMag->data.F64[i] = fitMag;
153 Npsf ++;
154
155 next_source:
156 psImageKeepCircle (source->mask, x, y, RADIUS, "AND", ~PSPHOT_MASK_MARKED);
157
158 }
159 psLogMsg ("psphot.psftry", 4, "fit psf: %f sec for %d sources\n", psTimerMark ("fit"), sources->n);
160 psTrace ("psphot.psftry", 3, "keeping %d of %d PSF candidates (PSF)\n", Npsf, sources->n);
161
162 // make this optional
163 // DumpModelFits (try->modelPSF, "modelsPSF.dat");
164
165 // XXX this function wants aperture radius for pmSourcePhotometry
166 pmPSFtryMetric_Alt (try, RADIUS);
167 psLogMsg ("psphot.pspsf", 3, "try model %s, ap-fit: %f +/- %f, sky bias: %f\n",
168 modelName, try->psf->ApResid, try->psf->dApResid, try->psf->skyBias);
169
170 return (try);
171}
172
173
174bool pmPSFtryMetric (pmPSFtry *try
175 , float RADIUS)
176{
177
178 float dBin;
179 int nKeep, nSkip;
180
181 // the measured (aperture - fit) magnitudes (dA == try->metric)
182 // depend on both the true ap-fit (dAo) and the bias in the sky measurement:
183 // dA = dAo + dsky/flux
184 // where flux is the flux of the star
185 // we fit this trend to find the infinite flux aperture correction (dAo),
186 // the nominal sky bias (dsky), and the error on dAo
187 // the values of dA are contaminated by stars with close neighbors in the aperture
188 // we use an outlier rejection to avoid this bias
189
190 // rflux = ten(0.4*fitMag);
191 psVector *rflux = psVectorAlloc (try->sources->n, PS_TYPE_F64);
192 for (int i = 0; i < try->sources->n; i++) {
193 if (try->mask->data.U8[i] & PSFTRY_MASK_ALL) continue;
194 rflux->data.F64[i] = pow(10.0, 0.4*try->fitMag->data.F64[i]);
195 }
196
197 // find min and max of (1/flux):
198 psStats *stats = psStatsAlloc (PS_STAT_MIN | PS_STAT_MAX);
199 psVectorStats (stats, rflux, NULL, try->mask, PSFTRY_MASK_ALL);
200
201 // build binned versions of rflux, metric
202 dBin = (stats->max - stats->min) / 10.0;
203 psVector *rfBin = psVectorCreate(NULL, stats->min, stats->max, dBin, PS_TYPE_F64);
204 psVector *daBin = psVectorAlloc (rfBin->n, PS_TYPE_F64);
205 psVector *maskB = psVectorAlloc (rfBin->n, PS_TYPE_U8);
206 psFree (stats);
207
208 psTrace ("psphot.metricmodel", 3, "rflux max: %g, min: %g, delta: %g\n", stats->max, stats->min, dBin);
209
210 // group data in daBin bins, measure lower 50% mean
211 for (int i = 0; i < daBin->n; i++) {
212
213 psVector *tmp = psVectorAlloc (try->sources->n, PS_TYPE_F64);
214 tmp->n = 0;
215
216 // accumulate data within bin range
217 for (int j = 0; j < try->sources->n; j++) {
218 // masked for: bad model fit, outlier in parameters
219 if (try->mask->data.U8[j] & PSFTRY_MASK_ALL) continue;
220
221 // skip points with extreme dA values
222 if (fabs(try->metric->data.F64[j]) > 0.5) continue;
223
224 // skip points outside of this bin
225 if (rflux->data.F64[j] < rfBin->data.F64[i] - 0.5*dBin)
226 continue;
227 if (rflux->data.F64[j] > rfBin->data.F64[i] + 0.5*dBin)
228 continue;
229
230 tmp->data.F64[tmp->n] = try->metric->data.F64[j];
231 tmp->n ++;
232 }
233
234 // is this a valid point?
235 maskB->data.U8[i] = 0;
236 if (tmp->n < 2) {
237 maskB->data.U8[i] = 1;
238 psFree (tmp);
239 continue;
240 }
241
242 // dA values are contaminated with low outliers
243 // measure statistics only on upper 50% of points
244 // this would be easier if we could sort in reverse:
245 //
246 // psVectorSort (tmp, tmp);
247 // tmp->n = 0.5*tmp->n;
248 // stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
249 // psVectorStats (stats, tmp, NULL, NULL, 0);
250 // psTrace ("psphot.metricmodel", 4, "rfBin %d (%g): %d pts, %g\n", i, rfBin->data.F64[i], tmp->n, stats->sampleMedian);
251
252 psVectorSort (tmp, tmp);
253 nKeep = 0.5*tmp->n;
254 nSkip = tmp->n - nKeep;
255
256 psVector *tmp2 = psVectorAlloc (nKeep, PS_TYPE_F64);
257 for (int j = 0; j < tmp2->n; j++) {
258 tmp2->data.F64[j] = tmp->data.F64[j + nSkip];
259 }
260
261 stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
262 psVectorStats (stats, tmp2, NULL, NULL, 0);
263 psTrace ("psphot.metricmodel", 4, "rfBin %d (%g): %d pts, %g\n", i, rfBin->data.F64[i], tmp->n, stats->sampleMedian);
264
265 daBin->data.F64[i] = stats->sampleMedian;
266
267 psFree (stats);
268 psFree (tmp);
269 psFree (tmp2);
270 }
271
272 // linear fit to rfBin, daBin
273 psPolynomial1D *poly = psPolynomial1DAlloc(1, PS_POLYNOMIAL_ORD);
274 psStats *fitstat = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
275 poly = psVectorClipFitPolynomial1D (poly, fitstat, maskB, 1, daBin, NULL, rfBin);
276
277 // XXX EAM : this is the intended API (cycle 7? cycle 8?)
278 // poly = psVectorFitPolynomial1D(poly, maskB, 1, daBin, NULL, rfBin);
279
280 // XXX EAM : replace this when the above version is implemented
281 // poly = psVectorFitPolynomial1DOrd(poly, maskB, rfBin, daBin, NULL);
282
283 psVector *daBinFit = psPolynomial1DEvalVector (poly, rfBin);
284 psVector *daResid = (psVector *) psBinaryOp (NULL, (void *) daBin, "-", (void *) daBinFit);
285
286 stats = psStatsAlloc (PS_STAT_CLIPPED_STDEV);
287 stats = psVectorStats (stats, daResid, NULL, maskB, 1);
288
289 try->psf->ApResid = poly->coeff[0];
290 try->psf->dApResid = stats->clippedStdev;
291 try->psf->skyBias = poly->coeff[1] / (M_PI * PS_SQR(RADIUS));
292
293 psFree (rflux);
294 psFree (rfBin);
295 psFree (daBin);
296 psFree (maskB);
297 psFree (daBinFit);
298 psFree (daResid);
299 psFree (poly);
300 psFree (stats);
301 psFree (fitstat);
302
303 return true;
304}
305
306bool pmPSFtryMetric_Alt (pmPSFtry *try, float RADIUS) {
307
308 // the measured (aperture - fit) magnitudes (dA == try->metric)
309 // depend on both the true ap-fit (dAo) and the bias in the sky measurement:
310 // dA = dAo + dsky/flux
311 // where flux is the flux of the star
312 // we fit this trend to find the infinite flux aperture correction (dAo),
313 // the nominal sky bias (dsky), and the error on dAo
314 // the values of dA are contaminated by stars with close neighbors in the aperture
315 // we use an outlier rejection to avoid this bias
316
317 // rflux = ten(0.4*fitMag);
318 psVector *rflux = psVectorAlloc (try->sources->n, PS_TYPE_F64);
319 for (int i = 0; i < try->sources->n; i++) {
320 if (try->mask->data.U8[i] & PSFTRY_MASK_ALL) continue;
321 rflux->data.F64[i] = pow(10.0, 0.4*try->fitMag->data.F64[i]);
322 }
323
324 // XXX EAM : try 3hi/1lo sigma clipping on the rflux vs metric fit
325 psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
326
327 // XXX EAM
328 stats->min = 1.0;
329 stats->max = 3.0;
330 stats->clipIter = 3;
331
332 // linear clipped fit to rfBin, daBin
333 psPolynomial1D *poly = psPolynomial1DAlloc (1, PS_POLYNOMIAL_ORD);
334 poly = psVectorClipFitPolynomial1D (poly, stats, try->mask, PSFTRY_MASK_ALL, try->metric, NULL, rflux);
335 fprintf (stderr, "fit stats: %f +/- %f\n", stats->sampleMedian, stats->sampleStdev);
336
337 try->psf->ApResid = poly->coeff[0];
338 try->psf->dApResid = stats->sampleStdev;
339 try->psf->skyBias = poly->coeff[1] / (M_PI * PS_SQR(RADIUS));
340
341 fprintf (stderr, "*******************************************************************************\n");
342
343 FILE *f;
344 f = fopen ("apresid.dat", "w");
345 if (f == NULL) psAbort ("pmPSFtry", "can't open output file");
346
347 for (int i = 0; i < try->sources->n; i++) {
348 fprintf (f, "%3d %8.4f %12.5e %8.4f %3d\n", i, try->fitMag->data.F64[i], rflux->data.F64[i], try->metric->data.F64[i], try->mask->data.U8[i]);
349 }
350 fclose (f);
351
352 psFree (rflux);
353 psFree (poly);
354 psFree (stats);
355
356 // psFree (daFit);
357 // psFree (daResid);
358
359 return true;
360}