1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
|
include <mach.h>
include "../lib/daophotdef.h"
include "../lib/peakdef.h"
# DP_PKFIT -- Do the actual fit.
int procedure dp_pkfit (dao, subim, nx, ny, radius, x, y, dx, dy, rel_bright,
sky, errmag, chi, sharp, iter)
pointer dao # pointer to the DAOPHOT Structure
real subim[nx,ny] # pointer to the image subraster
int nx, ny # size of the image subraster
real radius # the fitting radius
real x, y # initial estimate of the stellar position
real dx, dy # distance of star from the psf position
real rel_bright # initial estimate of stellar brightness
real sky # the sky value associated with this star
real errmag # error estimate for this star
real chi # estimated goodness of fit parameter
real sharp # broadness of the profile compared to the PSF
int iter # number of iterations needed for a fit.
bool clip, redo
int i, flag, npix
pointer psffit, peak
real ronoise, numer, denom, chiold, sum_weight, noise, wcrit
int dp_fitbuild()
begin
# Get the pointer to the PSF structure.
psffit = DP_PSFFIT (dao)
peak = DP_PEAK(dao)
# Initialize the parameters which control the fit.
chiold = 1.0
sharp = INDEFR
clip = false
ronoise = (DP_READNOISE(dao) / DP_PHOTADU(dao)) ** 2
call amovkr (1.0, Memr[DP_PKCLAMP(peak)], DP_PKNTERM(peak))
call amovkr (0.0, Memr[DP_PKOLDRESULT(peak)], DP_PKNTERM(peak))
# Iterate until a solution is found.
for (iter = 1; iter <= DP_MAXITER(dao); iter = iter + 1) {
# Initialize the matrices and vectors required by the fit.
chi = 0.0
numer = 0.0
denom = 0.0
sum_weight = 0.0
call aclrr (Memr[DP_PKRESID(peak)], DP_PKNTERM(peak))
call aclrr (Memr[DP_PKNORMAL(peak)], DP_PKNTERM(peak) *
DP_PKNTERM(peak))
# Set up the critical error limit.
if (iter >= WCRIT_NMAX)
wcrit = WCRIT_MAX
else if (iter >= WCRIT_NMED)
wcrit = WCRIT_MED
else if (iter >= WCRIT_NMIN)
wcrit = WCRIT_MIN
else
wcrit = MAX_REAL
# Build up the vector of residuals and the normal matrix.
npix = dp_fitbuild (dao, subim, nx, ny, radius, x, y, dx, dy,
rel_bright, sky, chiold, chi, clip, iter,
Memr[DP_PKCLAMP(peak)], Memr[DP_PKNORMAL(peak)],
Memr[DP_PKRESID(peak)], Memr[DP_PKDERIV(peak)],
DP_PKNTERM[(peak)], numer, denom, sum_weight)
# Return if the iteration was unsuccessful.
if (npix < MIN_NPIX)
return (PKERR_NOPIX)
# Invert the matrix. Return if inversion was unsuccessful or
# if any of the diagonal elements are less or equal to 0.0.
call invers (Memr[DP_PKNORMAL(peak)], DP_PKNTERM(peak),
DP_PKNTERM(peak), flag)
if (flag != 0)
return (PKERR_SINGULAR)
do i = 1, DP_PKNTERM(peak) {
if (Memr[DP_PKNORMAL(peak)+(i-1)*DP_PKNTERM(peak)+i-1] <= 0.0)
return (PKERR_SINGULAR)
}
# Solve the matrix.
call mvmul (Memr[DP_PKNORMAL(peak)], DP_PKNTERM(peak),
DP_PKNTERM(peak), Memr[DP_PKRESID(peak)],
Memr[DP_PKRESULT(peak)])
# In the beginning the brightness of the star will not be
# permitted to change by more than two magnitudes per
# iteration (that is to say if the estimate is getting
# brighter, it may not get brighter by more than 525%
# per iteration, and if it is getting fainter, it may not
# get fainter by more than 84% per iteration). The x and y
# coordinates of the centroid will be allowed to change by
# no more than one-half pixel per iteration. Any time
# that a parameter correction changes sign, the maximum
# permissible change in that parameter will be reduced
# by a factor of 2.
# Perform the sign check.
do i = 1, DP_PKNTERM(peak) {
if ((Memr[DP_PKOLDRESULT(peak)+i-1] *
Memr[DP_PKRESULT(peak)+i-1]) < 0.0)
Memr[DP_PKCLAMP(peak)+i-1] = 0.5 *
Memr[DP_PKCLAMP(peak)+i-1]
else
Memr[DP_PKCLAMP(peak)+i-1] = min (1.0, 1.1 *
Memr[DP_PKCLAMP(peak)+i-1])
Memr[DP_PKOLDRESULT(peak)+i-1] = Memr[DP_PKRESULT(peak)+i-1]
}
# Compute the new x, y, sky, and magnitude.
rel_bright = rel_bright + Memr[DP_PKRESULT(peak)] /
(1.0 + max (Memr[DP_PKRESULT(peak)] /
(MAX_DELTA_BRIGHTER * rel_bright), -Memr[DP_PKRESULT(peak)] /
(MAX_DELTA_FAINTER * rel_bright)) / Memr[DP_PKCLAMP(peak)])
# Return if the star becomes too faint)
if (rel_bright < MIN_REL_BRIGHT)
return (PKERR_FAINT)
if (DP_RECENTER(dao) == YES) {
x = x + Memr[DP_PKRESULT(peak)+1] / (1.0 +
abs (Memr[DP_PKRESULT(peak)+1]) / (MAX_DELTA_PIX *
Memr[DP_PKCLAMP(peak)+1]))
y = y + Memr[DP_PKRESULT(peak)+2] / (1.0 +
abs (Memr[DP_PKRESULT(peak)+2]) / (MAX_DELTA_PIX *
Memr[DP_PKCLAMP(peak)+2]))
}
if (DP_FITSKY(dao) == YES) {
noise = sqrt ((abs (sky / DP_PHOTADU(dao)) + ronoise))
sky = sky + max (-3.0 * noise, min (Memr[DP_PKRESULT(peak)+
DP_PKNTERM(peak)-1], 3.0 * noise))
}
# Force at least one iteration before checking for convergence.
if (iter <= 1)
next
# Start on the assumption the fit has converged.
redo = false
# Check for convergence. If the most recent computed correction
# to the brightness is larger than 0.1% of the brightness or
# 0.05 * sigma of the brightness whichever is larger, convergence
# has not been achieved.
errmag = chiold * sqrt (Memr[DP_PKNORMAL(peak)])
if (clip) {
if (abs (Memr[DP_PKRESULT(peak)]) > max ((MAX_NEW_ERRMAG *
errmag), (MAX_NEW_RELBRIGHT1 * rel_bright))) {
redo = true
} else {
if (DP_RECENTER(dao) == YES) {
if (max (abs (Memr[DP_PKRESULT(peak)+1]),
abs (Memr[DP_PKRESULT(peak)+2])) > MAX_PIXERR1)
redo = true
}
if (DP_FITSKY(dao) == YES) {
if (abs (Memr[DP_PKRESULT(peak)+DP_PKNTERM(peak)-1]) >
1.0e-4 * sky)
redo = true
}
}
} else {
if (abs (Memr[DP_PKRESULT(peak)]) > max (errmag,
(MAX_NEW_RELBRIGHT2 * rel_bright))) {
redo = true
} else {
if (DP_RECENTER(dao) == YES) {
if (max (abs (Memr[DP_PKRESULT(peak)+1]),
abs (Memr[DP_PKRESULT(peak)+2])) > MAX_PIXERR2)
redo = true
}
if (DP_FITSKY(dao) == YES) {
if (abs (Memr[DP_PKRESULT(peak)+DP_PKNTERM(peak)-1]) >
1.0e-4 * sky)
redo = true
}
}
}
if (redo)
next
if ((iter < DP_MAXITER(dao)) && (! clip)) {
if (DP_CLIPEXP(dao) > 0)
clip = true
call aclrr (Memr[DP_PKOLDRESULT(peak)], DP_PKNTERM(peak))
call amaxkr (Memr[DP_PKCLAMP(peak)], MAX_CLAMPFACTOR,
Memr[DP_PKCLAMP(peak)], DP_PKNTERM(peak))
} else {
sharp = 1.4427 * Memr[DP_PSFPARS(psffit)] *
Memr[DP_PSFPARS(psffit)+1] * numer / (DP_PSFHEIGHT(psffit) *
rel_bright * denom)
if (sharp <= MIN_SHARP || sharp >= MAX_SHARP)
sharp = INDEFR
break
}
}
if (iter > DP_MAXITER(dao))
iter = iter - 1
if ((errmag / rel_bright) >= wcrit)
return (PKERR_FAINT)
else
return (PKERR_OK)
end
# DP_FITBUILD -- Build the normal and vector of residuals for the fit.
int procedure dp_fitbuild (dao, subim, nx, ny, radius, x, y, xfrom_psf,
yfrom_psf, rel_bright, sky, chiold, chi, clip, iter, clamp, normal,
resid, deriv, nterm, numer, denom, sum_weight)
pointer dao # pointer to the DAOPHOT Structure
real subim[nx,ny] # subimage containing star
int nx, ny # size of the image subraster
real radius # the fitting radius
real x, y # initial estimate of the position
real xfrom_psf, yfrom_psf # distance from the psf star
real rel_bright # initial estimate of stellar brightness
real sky # the sky value associated with this star
real chiold # previous estimate of gof
real chi # estimated goodness of fit parameter
bool clip # clip the weights ?
int iter # current iteration number
real clamp[ARB] # clamp array
real normal[nterm,ARB] # normal matrix
real resid[ARB] # residual matrix
real deriv[ARB] # derivative matrix
int nterm # the number of terms to be fit
real numer, denom # used in sharpness calculation
real sum_weight # sum of the weights
int i, j, ix, iy, lowx, lowy, highx, highy, npix
pointer psffit
real fitradsq, pererr, peakerr, datamin, datamax, read_noise
real dx, dy, dxsq, dysq, radsq, dvdx, dvdy, d_pixval
real pred_pixval, sigma, sigmasq, relerr, weight
real rhosq, pixval, dfdsig
real dp_usepsf()
begin
# Get the pointer to the PSF structure.
psffit = DP_PSFFIT (dao)
# Set up some constants.
fitradsq = radius * radius
read_noise = (DP_READNOISE(dao) / DP_PHOTADU(dao)) ** 2
pererr = 0.01 * DP_FLATERR(dao)
peakerr = 0.01 * DP_PROFERR(dao) /
(Memr[DP_PSFPARS(psffit)] * Memr[DP_PSFPARS(psffit)+1])
if (IS_INDEFR (DP_MINGDATA(dao)))
datamin = -MAX_REAL
else
datamin = DP_MINGDATA(dao)
if (IS_INDEFR (DP_MAXGDATA(dao)))
datamax = MAX_REAL
else
datamax = DP_MAXGDATA(dao)
# Define the size of the subraster to be used in the fit.
lowx = max (1, int (x - radius))
lowy = max (1, int (y - radius))
highx = min (nx, int (x + radius) + 1)
highy = min (ny, int (y + radius) + 1)
npix = 0
do iy = lowy, highy {
dy = real (iy) - y
dysq = dy * dy
do ix = lowx, highx {
# Is this pixel in the good data range.
pixval = subim[ix,iy]
if (pixval < datamin || pixval > datamax)
next
# Is this pixel inside the fitting radius?
dx = real(ix) - x
dxsq = dx * dx
radsq = (dxsq + dysq) / fitradsq
if ((1.0 - radsq) <= PEAK_EPSILONR)
next
# We have a good pixel within the fitting radius.
deriv[1] = dp_usepsf (DP_PSFUNCTION(psffit), dx, dy,
DP_PSFHEIGHT(psffit), Memr[DP_PSFPARS(psffit)],
Memr[DP_PSFLUT(psffit)], DP_PSFSIZE(psffit),
DP_NVLTABLE(psffit), DP_NFEXTABLE(psffit), xfrom_psf,
yfrom_psf, dvdx, dvdy)
if (((rel_bright * deriv[1] + sky) > datamax) && (iter >= 3))
next
if (DP_RECENTER(dao) == YES) {
deriv[2] = rel_bright * dvdx
deriv[3] = rel_bright * dvdy
}
if (DP_FITSKY(dao) == YES)
deriv[nterm] = 1.0
# Get the residual from the PSF fit and the pixel
# intensity as predicted by the fit
d_pixval = (pixval - sky) - rel_bright * deriv[1]
pred_pixval = max (0.0, pixval - d_pixval)
# Calculate the anticipated error in the intensity of
# in this pixel including READOUT noise, photon statistics
# and the error of interpolating within the PSF.
sigmasq = pred_pixval / DP_PHOTADU (dao) + read_noise +
(pererr * pred_pixval) ** 2 + (peakerr *
(pred_pixval - sky)) ** 2
if (sigmasq <= 0.0)
next
sigma = sqrt (sigmasq)
relerr = abs (d_pixval / sigma)
# Compute the radial wweighting function.
weight = 5.0 / (5.0 + radsq / (1.0 - radsq))
# Now add this pixel into the quantities which go to make
# up the sharpness index.
rhosq = dxsq / Memr[DP_PSFPARS(psffit)] ** 2 + dysq /
Memr[DP_PSFPARS(psffit)+1] ** 2
# Include in the sharpness calculation only those pixels
# which are within NCORE_SIGMASQ core-sigmasq of the
# centroid. This saves time and floating underflows
# bu excluding pixels which contribute less than one
# part in a million to the fit.
if (rhosq <= NCORE_SIGMASQ) {
rhosq = 0.6931472 * rhosq
dfdsig = exp (-rhosq) * (rhosq - 1.0)
#pred_pixval = max (0.0, pixval - sky) + sky
numer = numer + dfdsig * d_pixval / sigmasq
denom = denom + (dfdsig ** 2) / sigmasq
}
# Derive the weight of this pixel. First of all the weight
# depends on the distance of the pixel from the centroid of
# the star --- it is determined from a function which is very
# nearly unity for radii much smaller than the fitting radius,
# and which goes to zero for radii very near the fitting
# radius. Then reject any pixels with 10 sigma residuals
# after the first iteration.
chi = chi + weight * relerr
sum_weight = sum_weight + weight
# Now the weight is scaled to the inverse square of the
# expected mean error.
weight = weight / sigmasq
# Reduce the weight of a bad pixel. A pixel having a residual
# of 2.5 sigma gets reduced to half weight; a pixel having
# a residual of of 5.0 sigma gets weight 1/257.
if (clip)
weight = weight / (1.0 + (relerr / (DP_CLIPRANGE(dao) *
chiold)) ** DP_CLIPEXP(dao))
# Now add this pixel into the vector of residuals
# and the normal matrix.
do i = 1, nterm {
resid[i] = resid[i] + d_pixval * deriv[i] * weight
do j = 1, nterm {
normal[i,j] = normal[i,j] + deriv[i] * deriv[j] *
weight
}
}
npix = npix + 1
}
}
# Compute the goodness of fit index CHI. CHI is pulled toward its
# expected value of unity before being stored in CHIOLD to keep the
# statistics of a small number of pixels from dominating the error
# analysis.
if (sum_weight > nterm) {
chi = CHI_NORM * chi / sqrt (sum_weight * (sum_weight - nterm))
chiold = ((sum_weight - MIN_SUMWT) * chi + MIN_SUMWT) / sum_weight
} else {
chi = 1.0
chiold = 1.0
}
return (npix)
end
|