File Coverage

palsrc/palFitxy.c
Criterion Covered Total %
statement 99 110 90.0
branch 26 36 72.2
condition n/a
subroutine n/a
pod n/a
total 125 146 85.6


line stmt bran cond sub pod time code
1             /*
2             *+
3             * Name:
4             * palFitxy
5              
6             * Purpose:
7             * Fit a linear model to relate two sets of [x,y] coordinates.
8              
9             * Language:
10             * Starlink ANSI C
11              
12             * Type of Module:
13             * Library routine
14              
15             * Invocation:
16             * palFitxy ( int itype, int np, double xye[][2], double xym[][2],
17             * double coeffs[6], int *j )
18              
19             * Arguments:
20             * itype = int (Given)
21             * type of model: 4 or 6 (note 1)
22             * np = int (Given)
23             * number of samples (note 2)
24             * xye = double[np][2] (Given)
25             * expected [x,y] for each sample
26             * xym = double[np][2] (Given)
27             * measured [x,y] for each sample
28             * coeffs = double[6] (Returned)
29             * coefficients of model (note 3)
30             * j = int * (Returned)
31             * status:
32             * - 0 = OK
33             * - -1 = illegal itype
34             * - -2 = insufficient data
35             * - -3 = no solution
36              
37             * Description:
38             * Fits a linear model to relate two sets of [X,Y] coordinates.
39              
40             * Notes:
41             * 1) itype, which must be either 4 or 6, selects the type of model
42             * fitted. Both allowed itype values produce a model coeffs which
43             * consists of six coefficients, namely the zero points and, for
44             * each of xe and ye, the coefficient of xm and ym. For itype=6,
45             * all six coefficients are independent, modelling squash and shear
46             * as well as origin, scale, and orientation. However, itype=4
47             * selects the "solid body rotation" option; the model coeffs
48             * still consists of the same six coefficients, but now two of
49             * them are used twice (appropriately signed). Origin, scale
50             * and orientation are still modelled, but not squash or shear -
51             * the units of x and y have to be the same.
52             *
53             * 2) For itype=4, np must be at least 2. For itype=6, np must be at
54             * least 3.
55             *
56             * 3) The model is returned in the array coeffs. Naming the
57             * elements of coeffs as follows:
58             * ---
59             * coeffs[0] = A
60             * coeffs[1] = B
61             * coeffs[2] = C
62             * coeffs[3] = D
63             * coeffs[4] = E
64             * coeffs[5] = F
65             * ---
66             * the model is:
67             * ---
68             * xe = A + B * xm + C * ym
69             * ye = D + E * xm + F * ym
70             * ---
71             * For the "solid body rotation" option (itype=4), the
72             * magnitudes of B and F, and of C and E, are equal. The
73             * signs of these coefficients depend on whether there is a
74             * sign reversal between xe,ye and xm,ym; fits are performed
75             * with and without a sign reversal and the best one chosen.
76             *
77             * 4) Error status values j=-1 and -2 leave coeffs unchanged;
78             * if j=-3 coeffs may have been changed.
79              
80             * See also:
81             * palPxy, palInvf, palXy2xy and palDcmpf
82              
83             * Authors:
84             * PTW: Pat Wallace (STFC)
85             * GSB: Graham Bell (EAO)
86              
87             * History:
88             * 2001-11-30 (PTW):
89             * SLALIB implementation.
90             * 2005-09-08 (PTW):
91             * Fix compiler uninitialised warnings.
92             * 2018-10-23 (GSB):
93             * Initial version in C.
94              
95             * Copyright:
96             * Copyright (C) 2005 P.T.Wallace. All rights reserved.
97             * Copyright (C) 2018 East Asian Observatory.
98             *
99             * Licence:
100             * This program is free software; you can redistribute it and/or modify
101             * it under the terms of the GNU General Public License as published by
102             * the Free Software Foundation; either version 2 of the License, or
103             * (at your option) any later version.
104             *
105             * This program is distributed in the hope that it will be useful,
106             * but WITHOUT ANY WARRANTY; without even the implied warranty of
107             * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
108             * GNU General Public License for more details.
109             *
110             * You should have received a copy of the GNU General Public License
111             * along with this program (see SLA_CONDITIONS); if not, write to the
112             * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
113             * Boston, MA 02110-1301 USA
114             *-
115             */
116              
117             #include "pal.h"
118              
119 2           void palFitxy ( int itype, int np, double xye[][2], double xym[][2],
120             double coeffs[6], int *j) {
121              
122             int i, jstat, iw[4], nsol;
123             double a, b, c, d, aold, bold, cold, dold, sold,
124             p, sxe, sxexm, sxeym, sye, syeym, syexm, sxm,
125             sym, sxmxm, sxmym, symym, xe, ye,
126             xm, ym, v[4], dm3[3][3], dm4[4][4], det,
127             sgn, sxxyy, sxyyx, sx2y2, sdr2, xr, yr;
128              
129             /* Preset the status */
130 2           *j = 0;
131              
132             /* Variable initializations to avoid compiler warnings */
133             a = 0.0;
134             b = 0.0;
135             c = 0.0;
136             d = 0.0;
137             aold = 0.0;
138             bold = 0.0;
139             cold = 0.0;
140             dold = 0.0;
141             sold = 0.0;
142              
143             /* Float the number of samples */
144 2           p = (double) np;
145              
146             /* Check ITYPE */
147 2 100         if (itype == 6) {
148             /* Six-coefficient linear model */
149              
150             /* Check enough samples */
151 1 50         if (np >= 3) {
152              
153             /* Form summations */
154             sxe = 0.0;
155             sxexm = 0.0;
156             sxeym = 0.0;
157             sye = 0.0;
158             syeym = 0.0;
159             syexm = 0.0;
160             sxm = 0.0;
161             sym = 0.0;
162             sxmxm = 0.0;
163             sxmym = 0.0;
164             symym = 0.0;
165              
166 9 100         for (i = 0; i < np; i++) {
167 8           xe = xye[i][0];
168 8           ye = xye[i][1];
169 8           xm = xym[i][0];
170 8           ym = xym[i][1];
171 8           sxe = sxe + xe;
172 8           sxexm = sxexm + xe * xm;
173 8           sxeym = sxeym + xe * ym;
174 8           sye = sye + ye;
175 8           syeym = syeym + ye * ym;
176 8           syexm = syexm + ye * xm;
177 8           sxm = sxm + xm;
178 8           sym = sym + ym;
179 8           sxmxm = sxmxm + xm * xm;
180 8           sxmym = sxmym + xm * ym;
181 8           symym = symym + ym * ym;
182             }
183              
184             /* Solve for A, B, C in xe = A + B * xm + C * ym */
185 1           v[0] = sxe;
186 1           v[1] = sxexm;
187 1           v[2] = sxeym;
188 1           dm3[0][0] = p;
189 1           dm3[0][1] = sxm;
190 1           dm3[0][2] = sym;
191 1           dm3[1][0] = sxm;
192 1           dm3[1][1] = sxmxm;
193 1           dm3[1][2] = sxmym;
194 1           dm3[2][0] = sym;
195 1           dm3[2][1] = sxmym;
196 1           dm3[2][2] = symym;
197              
198 1           palDmat(3, *dm3, v, &det, &jstat, iw);
199              
200 1 50         if (jstat == 0) {
201 4 100         for (i = 0; i < 3; i ++) {
202 3           coeffs[i] = v[i];
203             }
204              
205             /* Solve for D, E, F in ye = D + E * xm + F * ym */
206 1           v[0] = sye;
207 1           v[1] = syexm;
208 1           v[2] = syeym;
209              
210 1           palDmxv(dm3, v, coeffs + 3);
211             } else {
212             /* No 6-coefficient solution possible */
213 0           *j = -3;
214             }
215             } else {
216             /* Insufficient data for 6-coefficient fit */
217 0           *j = -2;
218             }
219 1 50         } else if (itype == 4) {
220             /* Four-coefficient solid body rotation model */
221              
222             /* Check enough samples */
223 1 50         if (np >= 2) {
224              
225             /* Try two solutions, first without then with flip in X */
226 3 100         for (nsol = 0; nsol < 2; nsol ++) {
227 2 100         if (nsol == 0) {
228             sgn = 1.0;
229             } else {
230             sgn = -1.0;
231             }
232              
233             /* Form summations */
234             sxe = 0.0;
235             sxxyy = 0.0;
236             sxyyx = 0.0;
237             sye = 0.0;
238             sxm = 0.0;
239             sym = 0.0;
240             sx2y2 = 0.0;
241              
242 18 100         for (i = 0; i < np; i ++) {
243 16           xe = xye[i][0] * sgn;
244 16           ye = xye[i][1];
245 16           xm = xym[i][0];
246 16           ym = xym[i][1];
247 16           sxe = sxe + xe;
248 16           sxxyy = sxxyy + xe * xm + ye * ym;
249 16           sxyyx = sxyyx + xe * ym - ye * xm;
250 16           sye = sye + ye;
251 16           sxm = sxm + xm;
252 16           sym = sym + ym;
253 16           sx2y2 = sx2y2 + xm * xm + ym * ym;
254             }
255              
256             /* Solve for A, B, C, D in: +/- xe = A + B * xm - C * ym
257             + ye = D + C * xm + B * ym */
258 2           v[0] = sxe;
259 2           v[1] = sxxyy;
260 2           v[2] = sxyyx;
261 2           v[3] = sye;
262 2           dm4[0][0] = p;
263 2           dm4[0][1] = sxm;
264 2           dm4[0][2] = -sym;
265 2           dm4[0][3] = 0.0;
266 2           dm4[1][0] = sxm;
267 2           dm4[1][1] = sx2y2;
268 2           dm4[1][2] = 0.0;
269 2           dm4[1][3] = sym;
270 2           dm4[2][0] = sym;
271 2           dm4[2][1] = 0.0;
272 2           dm4[2][2] = -sx2y2;
273 2           dm4[2][3] = -sxm;
274 2           dm4[3][0] = 0.0;
275 2           dm4[3][1] = sym;
276 2           dm4[3][2] = sxm;
277 2           dm4[3][3] = p;
278              
279 2           palDmat(4, *dm4, v, &det, &jstat, iw);
280              
281 2 50         if (jstat == 0) {
282 2           a = v[0];
283 2           b = v[1];
284 2           c = v[2];
285 2           d = v[3];
286              
287             /* Determine sum of radial errors squared */
288             sdr2 = 0.0;
289 18 100         for (i = 0; i < np; i ++) {
290 16           xm = xym[i][0];
291 16           ym = xym[i][1];
292 16           xr = a + b * xm - c * ym - xye[i][0] * sgn;
293 16           yr = d + c * xm + b * ym - xye[i][1];
294 16           sdr2 = sdr2 + xr * xr + yr * yr;
295             }
296              
297             } else {
298             /* Singular: set flag */
299             sdr2 = -1.0;
300             }
301              
302             /* If first pass and non-singular, save variables */
303 2 100         if (nsol == 0 && jstat == 0) {
    50          
304             aold = a;
305             bold = b;
306             cold = c;
307             dold = d;
308             sold = sdr2;
309             }
310             }
311              
312             /* Pick the best of the two solutions */
313 1 50         if (sold >= 0.0 && (sold <= sdr2 || np == 2)) {
    50          
    50          
314 0           coeffs[0] = aold;
315 0           coeffs[1] = bold;
316 0           coeffs[2] = -cold;
317 0           coeffs[3] = dold;
318 0           coeffs[4] = cold;
319 0           coeffs[5] = bold;
320 1 50         } else if (jstat == 0) {
321 1           coeffs[0] = -a;
322 1           coeffs[1] = -b;
323 1           coeffs[2] = c;
324 1           coeffs[3] = d;
325 1           coeffs[4] = c;
326 1           coeffs[5] = b;
327             } else {
328             /* No 4-coefficient fit possible */
329 0           *j = -3;
330             }
331             } else {
332             /* Insufficient data for 4-coefficient fit */
333 0           *j = -2;
334             }
335             } else {
336             /* Illegal itype - not 4 or 6 */
337 0           *j = -1;
338             }
339 2           }