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
|
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
include <math/iminterp.h>
include <pkg/center1d.h>
define MIN_WIDTH 3. # Minimum centering width
define EPSILON 0.001 # Accuracy of centering
define EPSILON1 0.005 # Tolerance for convergence check
define ITERATIONS 100 # Maximum number of iterations
define MAX_DXCHECK 3 # Look back for failed convergence
define INTERPTYPE II_SPLINE3 # Image interpolation type
# CENTER1D -- Locate the center of a one dimensional feature.
# A value of INDEF is returned in the centering fails for any reason.
# This procedure just sets up the data and adjusts for emission or
# absorption features. The actual centering is done by C1D_CENTER.
# If twidth <= 1 return the nearest minima or maxima.
real procedure center1d (x, data, npts, width, type, radius, threshold)
real x # Initial guess
int npts # Number of data points
real data[npts] # Data points
real width # Feature width
int type # Feature type
real radius # Centering radius
real threshold # Minimum range in feature
real xc # Center
int x1, x2, nx
real a, b, rad, wid
pointer sp, data1
real c1d_center()
begin
# Check starting value.
if (IS_INDEF(x) || (x < 1) || (x > npts))
return (INDEF)
# Set parameters. The minimum in the error radius
# is for defining the data window. The user error radius is used to
# check for an error in the derived center at the end of the centering.
call c1d_params (INDEFI, INDEFR)
wid = max (width, MIN_WIDTH)
rad = max (2., radius)
# Determine the pixel value range around the initial center, including
# the width and error radius buffer. Check for a minimum range.
x1 = max (1., x - wid / 2 - rad - wid)
x2 = min (real (npts), x + wid / 2 + rad + wid + 1)
nx = x2 - x1 + 1
call alimr (data[x1], nx, a, b)
if (b - a < threshold)
return (INDEF)
# Allocate memory for the continuum subtracted data vector. The X
# range is just large enough to include the error radius and the
# half width.
x1 = max (1., x - wid / 2 - rad)
x2 = min (real (npts), x + wid / 2 + rad + 1)
nx = x2 - x1 + 1
call smark (sp)
call salloc (data1, nx, TY_REAL)
call amovr (data[x1], Memr[data1], nx)
# Make the centering data positive, subtract the continuum, and
# apply a threshold to eliminate noise spikes.
switch (type) {
case EMISSION:
a = min (0., a)
call asubkr (data[x1], a + threshold, Memr[data1], nx)
call amaxkr (Memr[data1], 0., Memr[data1], nx)
case ABSORPTION:
call anegr (data[x1], Memr[data1], nx)
call asubkr (Memr[data1], threshold - b, Memr[data1], nx)
call amaxkr (Memr[data1], 0., Memr[data1], nx)
default:
call error (0, "Unknown feature type")
}
# Determine the center.
xc = c1d_center (x - x1 + 1, Memr[data1], nx, width)
# Check user centering error radius.
if (!IS_INDEF(xc)) {
xc = xc + x1 - 1
if (abs (x - xc) > radius)
xc = INDEF
}
# Free memory and return the center position.
call sfree (sp)
return (xc)
end
# C1D_PARAMS -- Set parameters.
procedure c1d_params (interp, eps)
int interp # Interpolation type
real eps # Accuracy of centering
int first
data first /YES/
int interptype
real epsilon
common /c1d_common/ interptype, epsilon
begin
if (!IS_INDEFI(interp))
interptype = interp
else if (first == YES)
interptype = INTERPTYPE
if (!IS_INDEFR(eps))
epsilon = eps
else if (first == YES)
epsilon = EPSILON
first = NO
end
# C1D_CENTER -- One dimensional centering algorithm.
# If the width is <= 1. return the nearest local maximum.
real procedure c1d_center (x, data, npts, width)
real x # Starting guess
int npts # Number of points in data vector
real data[npts] # Data vector
real width # Centering width
int i, j, iteration, dxcheck
real xc, wid, hwidth, dx, dxabs, dxlast
real a, b, sum1, sum2, intgrl1, intgrl2
pointer asi1, asi2, sp, data1
real asigrl()
int interptype
real epsilon
common /c1d_common/ interptype, epsilon
define done_ 99
begin
# Find the nearest local maxima as the starting point.
# This is required because the threshold limit may have set
# large regions of the data to zero and without a gradient
# the centering will fail.
for (i=x+.5; (i<npts) && (data[i]<=data[i+1]); i=i+1)
;
for (; (i>1) && (data[i]<=data[i-1]); i=i-1)
;
for (j=x+.5; (j>1) && (data[j]<=data[j-1]); j=j-1)
;
for (; (j<npts) && (data[j]<=data[j+1]); j=j+1)
;
if (abs(i-x) < abs(x-j))
xc = i
else
xc = j
if (width <= 1.)
return (xc)
wid = max (width, MIN_WIDTH)
# Check data range.
hwidth = wid / 2
if ((xc - hwidth < 1) || (xc + hwidth > npts))
return (INDEF)
# Set interpolation functions.
call asiinit (asi1, interptype)
call asiinit (asi2, interptype)
call asifit (asi1, data, npts)
# Allocate, compute, and interpolate the x*y values.
call smark (sp)
call salloc (data1, npts, TY_REAL)
do i = 1, npts
Memr[data1+i-1] = data[i] * i
call asifit (asi2, Memr[data1], npts)
call sfree (sp)
# Iterate to find center. This loop exits when 1) the maximum
# number of iterations is reached, 2) the delta is less than
# the required accuracy (criterion for finding a center), 3)
# there is a problem in the computation, 4) successive steps
# continue to exceed the minimum delta.
dxlast = npts
do iteration = 1, ITERATIONS {
# Ramp centering function.
# a = xc - hwidth
# b = xc + hwidth
# intgrl1 = asigrl (asi1, a, b)
# intgrl2 = asigrl (asi2, a, b)
# sum1 = intgrl2 - xc * intgrl1
# sum2 = intgrl1
# Triangle centering function.
a = xc - hwidth
b = xc - hwidth / 2
intgrl1 = asigrl (asi1, a, b)
intgrl2 = asigrl (asi2, a, b)
sum1 = (xc - hwidth) * intgrl1 - intgrl2
sum2 = -intgrl1
a = b
b = xc + hwidth / 2
intgrl1 = asigrl (asi1, a, b)
intgrl2 = asigrl (asi2, a, b)
sum1 = sum1 - xc * intgrl1 + intgrl2
sum2 = sum2 + intgrl1
a = b
b = xc + hwidth
intgrl1 = asigrl (asi1, a, b)
intgrl2 = asigrl (asi2, a, b)
sum1 = sum1 + (xc + hwidth) * intgrl1 - intgrl2
sum2 = sum2 - intgrl1
# Return no center if sum2 is zero.
if (sum2 == 0.)
break
# Limit dx change in one iteration to 1 pixel.
dx = sum1 / abs (sum2)
dxabs = abs (dx)
xc = xc + max (-1., min (1., dx))
# Check data range. Return no center if at edge of data.
if ((xc - hwidth < 1) || (xc + hwidth > npts))
break
# Convergence tests.
if (dxabs < epsilon)
goto done_
if (dxabs > dxlast + EPSILON1) {
dxcheck = dxcheck + 1
if (dxcheck > MAX_DXCHECK)
break
} else if (dxabs > dxlast - EPSILON1) {
xc = xc - max (-1., min (1., dx)) / 2
dxcheck = 0
} else {
dxcheck = 0
dxlast = dxabs
}
}
# If we get here then no center was found.
xc = INDEF
done_ call asifree (asi1)
call asifree (asi2)
return (xc)
end
|