VIRCAM Pipeline 2.3.12
casu_platesol.c
1/* $Id: casu_platesol.c,v 1.3 2015/08/07 13:06:54 jim Exp $
2 *
3 * This file is part of the CASU Pipeline utilities
4 * Copyright (C) 2015 European Southern Observatory
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * $Author: jim $
23 * $Date: 2015/08/07 13:06:54 $
24 * $Revision: 1.3 $
25 * $Name: $
26 */
27
28/* Includes */
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33
34#include <cpl.h>
35#include <math.h>
36
37#include "casu_mods.h"
38#include "catalogue/casu_utils.h"
39#include "catalogue/casu_wcsutils.h"
40#include "casu_stats.h"
41
42static int casu_plate6(double *xpos, double *ypos, double *xi, double *eta,
43 unsigned char *flag, int nstds, double *a, double *b,
44 double *c, double *d, double *e, double *f);
45static int casu_plate4(double *xpos, double *ypos, double *xi, double *eta,
46 unsigned char *flag, int nstds, double *a, double *b,
47 double *c, double *d, double *e, double *f);
48static void tidy(double *work, unsigned char *iwork);
49
52/*---------------------------------------------------------------------------*/
124/*---------------------------------------------------------------------------*/
125
126extern int casu_platesol(cpl_propertylist *plist, cpl_propertylist *tlist,
127 cpl_table *matchedstds, int nconst, int shiftan,
128 int *status) {
129 int nstds,nc2,i,niter,nrej,ngood,nreq=6,xcol,ycol,nulval;
130 long n1,n2;
131 const char *fctid = "casu_platesol";
132 float *tptr;
133 double *xptr,*yptr,*xptr2,*yptr2,*ra,*dec,*xiptr,*etaptr,*wptr,averr;
134 double r1,r2,d1,d2,newcrval1,newcrval2,a,b,c,d,e,f,xifit,etafit,dxi,deta;
135 double crpix1,crpix2,xi,eta,rac_before,rac_after,decc_before,decc_after;
136 double xcen,ycen,oldtheta,scale,oldcrpix1,oldcrpix2,*dptr;
137 double *work=NULL;
138 const double *crdata;
139 unsigned char *isbad,*wptr2,*iwork=NULL;
140 const char *reqcols[] = {"X_coordinate","Y_coordinate","xpredict",
141 "ypredict","RA","Dec"};
142 char key[9];
143 cpl_wcs *wcs;
144 const cpl_array *cr;
145 const cpl_matrix *crm;
146
147 /* Inherited status */
148
149 if (*status != CASU_OK)
150 return(*status);
151
152 /* Check the value of nconst */
153
154 if (nconst != 4 && nconst != 6) {
155 cpl_msg_error(fctid,
156 "Value of nconst = %" CPL_SIZE_FORMAT " is unsupported",
157 (cpl_size)nconst);
158 FATAL_ERROR
159 }
160
161 /* How many standards are in the input matched standards table? */
162
163 nstds = (int)cpl_table_get_nrow(matchedstds);
164 nc2 = nconst/2;
165 if (nstds < nc2) {
166 cpl_msg_error(fctid,
167 "Too few standards (%" CPL_SIZE_FORMAT ") in table for %" CPL_SIZE_FORMAT " coefficient fit",
168 (cpl_size)nstds,(cpl_size)nconst);
169 FATAL_ERROR
170 }
171
172 /* Check that the matched standards table has all the required columns */
173
174 for (i = 0; i < nreq; i++) {
175 if (cpl_table_has_column(matchedstds,reqcols[i]) != 1) {
176 cpl_msg_error(fctid,"Matched standards table missing column %s",
177 reqcols[i]);
178 FATAL_ERROR
179 }
180 }
181
182 /* Get some workspace now */
183
184 work = cpl_malloc(10*nstds*sizeof(*work));
185 iwork = cpl_calloc(3*nstds,sizeof(*isbad));
186 xptr = work;
187 yptr = work + nstds;
188 xptr2 = work + 2*nstds;
189 yptr2 = work + 3*nstds;
190 ra = work + 4*nstds;
191 dec = work + 5*nstds;
192 xiptr = work + 6*nstds;
193 etaptr = work + 7*nstds;
194 wptr = work + 8*nstds;
195 isbad = iwork;
196 wptr2 = iwork + nstds;
197
198 /* Get the data from the table and put it all into double precision
199 arrays */
200
201 tptr = cpl_table_get_data_float(matchedstds,"X_coordinate");
202 for (i = 0; i < nstds; i++)
203 xptr[i] = (double)tptr[i];
204 tptr = cpl_table_get_data_float(matchedstds,"Y_coordinate");
205 for (i = 0; i < nstds; i++)
206 yptr[i] = (double)tptr[i];
207 tptr = cpl_table_get_data_float(matchedstds,"xpredict");
208 for (i = 0; i < nstds; i++)
209 xptr2[i] = (double)tptr[i];
210 tptr = cpl_table_get_data_float(matchedstds,"ypredict");
211 for (i = 0; i < nstds; i++)
212 yptr2[i] = (double)tptr[i];
213 if (cpl_table_get_column_type(matchedstds,"RA") == CPL_TYPE_FLOAT) {
214 tptr = cpl_table_get_data_float(matchedstds,"RA");
215 for (i = 0; i < nstds; i++)
216 ra[i] = (double)tptr[i];
217 tptr = cpl_table_get_data_float(matchedstds,"Dec");
218 for (i = 0; i < nstds; i++)
219 dec[i] = (double)tptr[i];
220 } else {
221 dptr = cpl_table_get_data_double(matchedstds,"RA");
222 for (i = 0; i < nstds; i++)
223 ra[i] = dptr[i];
224 dptr = cpl_table_get_data_double(matchedstds,"Dec");
225 for (i = 0; i < nstds; i++)
226 dec[i] = dptr[i];
227 }
228
229 /* If you want to shift the RA and Dec of the tangent point, then
230 do that now */
231
232 newcrval1 = 0.0;
233 newcrval2 = 0.0;
234 if (shiftan) {
235 wcs = cpl_wcs_new_from_propertylist(plist);
236 cr = cpl_wcs_get_crval(wcs);
237 crdata = cpl_array_get_data_double_const(cr);
238 for (i = 0; i < nstds; i++) {
239 casu_xytoradec(wcs,xptr[i],yptr[i],&r1,&d1);
240 casu_xytoradec(wcs,xptr2[i],yptr2[i],&r2,&d2);
241 xiptr[i] = r2 - r1;
242 etaptr[i] = d2 - d1;
243 }
244 r1 = casu_dmed(xiptr,NULL,nstds);
245 d1 = casu_dmed(etaptr,NULL,nstds);
246 newcrval1 = crdata[0] + r1;
247 newcrval2 = crdata[1] + d1;
248 cpl_propertylist_update_double(plist,"CRVAL1",newcrval1);
249 cpl_propertylist_update_double(plist,"CRVAL2",newcrval2);
250 cpl_wcs_delete(wcs);
251 }
252
253 /* Calculate the central RA and Dec */
254
255 wcs = cpl_wcs_new_from_propertylist(plist);
256 n1 = cpl_array_get_int(cpl_wcs_get_image_dims(wcs),0,&nulval);
257 n2 = cpl_array_get_int(cpl_wcs_get_image_dims(wcs),1,&nulval);
258 cr = cpl_wcs_get_crpix(wcs);
259 crdata = cpl_array_get_data_double_const(cr);
260 oldcrpix1 = crdata[0];
261 oldcrpix2 = crdata[1];
262 xcen = 0.5*(double)n1;
263 ycen = 0.5*(double)n2;
264 casu_xytoradec(wcs,xcen,ycen,&rac_before,&decc_before);
265
266 /* Right, calculate xi and eta for each of the standards */
267
268 for (i = 0; i < nstds; i++) {
269 casu_radectoxieta(wcs,ra[i],dec[i],&xi,&eta);
270 xiptr[i] = xi;
271 etaptr[i] = eta;
272 }
273
274 /* Right, now loop for maximum number of iterations or until
275 convergence */
276
277 niter = 0;
278 while (niter >= 0) {
279
280 /* Do a plate solution */
281
282 switch (nconst) {
283 case 6:
284 *status = casu_plate6(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
285 &c,&e,&d,&f);
286 break;
287 case 4:
288 *status = casu_plate4(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
289 &c,&e,&d,&f);
290 break;
291 default:
292 *status = casu_plate6(xptr,yptr,xiptr,etaptr,isbad,nstds,&a,&b,
293 &c,&e,&d,&f);
294 break;
295 }
296 if (*status != CASU_OK) {
297 cpl_msg_error(fctid,"Plate constant solution failed");
298 tidy(work,iwork);
299 FATAL_ERROR
300 }
301
302 /* Now look at the residuals and see if any should be rejected */
303
304 for (i = 0; i < nstds; i++) {
305 xifit = xptr[i]*a + yptr[i]*b + c;
306 etafit = xptr[i]*d + yptr[i]*e + f;
307 dxi = fabs(xifit - xiptr[i]);
308 deta = fabs(etafit - etaptr[i]);
309 wptr[i*2] = dxi;
310 wptr[i*2+1] = deta;
311 wptr2[i*2] = isbad[i];
312 wptr2[i*2+1] = isbad[i];
313 }
314 averr = casu_dmed(wptr,wptr2,2*nstds);
315 averr *= 1.48;
316 if (niter == 3)
317 break;
318 nrej = 0;
319 ngood = 0;
320 for (i = 0; i < nstds; i++) {
321 if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) nrej++;
322 if (!isbad[i])
323 ngood++;
324 }
325 ngood -= nrej;
326 if (nrej == 0 || ngood < nconst)
327 break;
328 for (i = 0; i < nstds; i++) {
329 if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) isbad[i] = 1;
330 }
331 niter++;
332 }
333
334 /* Convert values to degrees now */
335
336 crpix1 = (e*c - b*f)/(d*b - e*a);
337 crpix2 = (a*f - d*c)/(d*b - e*a);
338 a *= DEGRAD;
339 b *= DEGRAD;
340 d *= DEGRAD;
341 e *= DEGRAD;
342
343 /* Number of good points fit and average error in arcsec*/
344
345 ngood = 0;
346 for (i = 0; i < nstds; i++)
347 if (! isbad[i])
348 ngood++;
349 averr *= DEGRAD*3600.0;
350
351 /* Right, now update the header */
352
353 casu_propertylist_update_double(plist,"CRPIX1",crpix1);
354 casu_propertylist_update_double(plist,"CRPIX2",crpix2);
355 cpl_propertylist_update_double(plist,"CD1_1",a);
356 cpl_propertylist_update_double(plist,"CD1_2",b);
357 cpl_propertylist_update_double(plist,"CD2_1",d);
358 cpl_propertylist_update_double(plist,"CD2_2",e);
359 cpl_propertylist_update_int(plist,"ESO DRS NUMBRMS",ngood);
360 cpl_propertylist_set_comment(plist,"ESO DRS NUMBRMS",
361 "Number of stars in WCS fit");
362 cpl_propertylist_update_double(plist,"ESO DRS STDCRMS",averr);
363 cpl_propertylist_set_comment(plist,"ESO DRS STDCRMS",
364 "[arcsec] Average error in WCS fit");
365
366 /* Add some extra stuff for PhaseIII compliance */
367
368 cpl_propertylist_update_string(plist,"CUNIT1","deg");
369 cpl_propertylist_set_comment(plist,"CUNIT1",
370 "Unit of coordinate transformation");
371 cpl_propertylist_update_string(plist,"CUNIT2","deg");
372 cpl_propertylist_set_comment(plist,"CUNIT2",
373 "Unit of coordinate transformation");
374 cpl_propertylist_update_double(plist,"CSYER1",0.0);
375 cpl_propertylist_set_comment(plist,"CSYER1","Systematic error axis 1");
376 cpl_propertylist_update_double(plist,"CSYER2",0.0);
377 cpl_propertylist_set_comment(plist,"CSYER2","Systematic error axis 2");
378 cpl_propertylist_update_double(plist,"CRDER1",averr);
379 cpl_propertylist_set_comment(plist,"CRDER1","Random error axis 1");
380 cpl_propertylist_update_double(plist,"CRDER2",averr);
381 cpl_propertylist_set_comment(plist,"CRDER2","Random error axis 2");
382 cpl_propertylist_update_string(plist,"RADECSYS","ICRS");
383 cpl_propertylist_set_comment(plist,"RADECSYS","Coordinate reference frame");
384 cpl_propertylist_update_double(plist,"EQUINOX",2000.0);
385 cpl_propertylist_set_comment(plist,"EQUINOX","Coordinate equinox");
386
387 /* Calculate the central RA and Dec again */
388
389 crm = cpl_wcs_get_cd(wcs);
390 crdata = cpl_matrix_get_data_const(crm);
391 oldtheta = 0.5*(fabs(atan2(crdata[1],crdata[0])) +
392 fabs(atan2(crdata[2],crdata[3])));
393 cpl_wcs_delete(wcs);
394 wcs = cpl_wcs_new_from_propertylist(plist);
395 casu_xytoradec(wcs,xcen,ycen,&rac_after,&decc_after);
396 xcen = 3600.0*(rac_after - rac_before);
397 ycen = 3600.0*(decc_after - decc_before);
398 cpl_propertylist_update_double(plist,"ESO DRS WCSRAOFF",xcen);
399 cpl_propertylist_set_comment(plist,"ESO DRS WCSRAOFF",
400 "[arcsec] cenpix RA_after - RA_before)");
401 cpl_propertylist_update_double(plist,"ESO DRS WCSDECOFF",ycen);
402 cpl_propertylist_set_comment(plist,"ESO DRS WCSDECOFF",
403 "[arcsec] cenpix Dec_after - Dec_before)");
404
405 /* Update the table header */
406
407 if (tlist != NULL) {
408 xcol = casu_findcol(tlist,"X");
409 ycol = casu_findcol(tlist,"Y");
410 if (xcol != -1 && ycol != -1) {
411 snprintf(key,9,"TCRPX%d",xcol);
412 casu_propertylist_update_double(tlist,key,crpix1);
413 snprintf(key,9,"TCRPX%d",ycol);
414 casu_propertylist_update_double(tlist,key,crpix2);
415 if (shiftan) {
416 snprintf(key,9,"TCRVL%d",xcol);
417 cpl_propertylist_update_double(tlist,key,newcrval1);
418 snprintf(key,9,"TCRVL%d",ycol);
419 cpl_propertylist_update_double(tlist,key,newcrval2);
420 }
421 snprintf(key,9,"TC%d_%d",xcol,xcol);
422 cpl_propertylist_update_double(tlist,key,a);
423 snprintf(key,9,"TC%d_%d",xcol,ycol);
424 cpl_propertylist_update_double(tlist,key,b);
425 snprintf(key,9,"TC%d_%d",ycol,xcol);
426 cpl_propertylist_update_double(tlist,key,d);
427 snprintf(key,9,"TC%d_%d",ycol,ycol);
428 cpl_propertylist_update_double(tlist,key,e);
429 cpl_propertylist_update_int(tlist,"ESO DRS NUMBRMS",ngood);
430 cpl_propertylist_set_comment(tlist,"ESO DRS NUMBRMS",
431 "Number of stars in WCS fit");
432 cpl_propertylist_update_double(tlist,"ESO DRS STDCRMS",averr);
433 cpl_propertylist_set_comment(tlist,"ESO DRS STDCRMS",
434 "[arcsec] Average error in WCS fit");
435 cpl_propertylist_update_double(tlist,"ESO DRS WCSRAOFF",xcen);
436 cpl_propertylist_set_comment(tlist,"ESO DRS WCSRAOFF",
437 "[arcsec] cenpix RA_after - RA_before)");
438 cpl_propertylist_update_double(tlist,"ESO DRS WCSDECOFF",ycen);
439 cpl_propertylist_set_comment(tlist,"ESO DRS WCSDECOFF",
440 "[arcsec] cenpix Dec_after - Dec_before)");
441
442 /* PhaseIII stuff for table headers */
443
444 snprintf(key,9,"TCUNI%d",xcol);
445 cpl_propertylist_update_string(tlist,key,"deg");
446 cpl_propertylist_set_comment(tlist,key,
447 "Unit of coordinate transformation");
448 snprintf(key,9,"TCUNI%d",ycol);
449 cpl_propertylist_update_string(tlist,key,"deg");
450 cpl_propertylist_set_comment(tlist,key,
451 "Unit of coordinate transformation");
452 snprintf(key,9,"TCSY%d",xcol);
453 cpl_propertylist_update_double(tlist,key,0.0);
454 cpl_propertylist_set_comment(tlist,key,"Systematic error x-axis ");
455 snprintf(key,9,"TCSY%d",ycol);
456 cpl_propertylist_update_double(tlist,key,0.0);
457 cpl_propertylist_set_comment(tlist,key,"Systematic error y-axis");
458 snprintf(key,9,"TCRD%d",xcol);
459 cpl_propertylist_update_double(tlist,key,averr);
460 cpl_propertylist_set_comment(tlist,key,"Random error axis 1");
461 snprintf(key,9,"TCRD%d",ycol);
462 cpl_propertylist_update_double(tlist,key,averr);
463 cpl_propertylist_set_comment(tlist,key,"Random error axis 2");
464 cpl_propertylist_update_string(tlist,"RADECSYS","ICRS");
465 cpl_propertylist_set_comment(tlist,"RADECSYS",
466 "Coordinate reference frame");
467 cpl_propertylist_update_double(tlist,"EQUINOX",2000.0);
468 cpl_propertylist_set_comment(tlist,"EQUINOX","Coordinate equinox");
469 }
470 }
471
472 /* Back-calculate a crval for the old value of crpix. Compare to the
473 WCS crval and write to QC header */
474
475 cr = cpl_wcs_get_crval(wcs);
476 crdata = cpl_array_get_data_double_const(cr);
477 casu_xytoradec(wcs,oldcrpix1,oldcrpix2,&rac_after,&decc_after);
478 rac_after -= crdata[0];
479 decc_after -= crdata[1];
480 cpl_propertylist_update_double(plist,"ESO QC WCS_DCRVAL1",rac_after);
481 cpl_propertylist_set_comment(plist,"ESO QC WCS_DCRVAL1",
482 "[deg] change in crval1");
483 cpl_propertylist_update_double(plist,"ESO QC WCS_DCRVAL2",decc_after);
484 cpl_propertylist_set_comment(plist,"ESO QC WCS_DCRVAL2",
485 "[deg] change in crval2");
486
487 /* Work out the change in the rotation */
488
489 crm = cpl_wcs_get_cd(wcs);
490 crdata = cpl_matrix_get_data_const(crm);
491 oldtheta = 0.5*(fabs(atan2(crdata[1],crdata[0])) +
492 fabs(atan2(crdata[2],crdata[3]))) - oldtheta;
493 oldtheta *= DEGRAD;
494 cpl_propertylist_update_double(plist,"ESO QC WCS_DTHETA",oldtheta);
495 cpl_propertylist_set_comment(plist,"ESO QC WCS_DTHETA",
496 "[deg] change in rotation");
497
498 /* Work out the mean plate scale */
499
500 scale = 1800.0*(sqrt(pow(crdata[0],2.0) + pow(crdata[1],2.0)) +
501 sqrt(pow(crdata[2],2.0) + pow(crdata[3],2.0)));
502 cpl_propertylist_update_double(plist,"ESO QC WCS_SCALE",scale);
503 cpl_propertylist_set_comment(plist,"ESO QC WCS_SCALE",
504 "[arcsec] mean plate scale");
505
506 /* Work out the shear of this new WCS */
507
508 oldtheta = fabs(atan2(crdata[1],crdata[0])) -
509 fabs(atan2(crdata[2],crdata[3]));
510 cpl_propertylist_update_double(plist,"ESO QC WCS_SHEAR",oldtheta);
511 cpl_propertylist_set_comment(plist,"ESO QC WCS_SHEAR",
512 "[deg] abs(xrot) - abs(yrot)");
513
514 /* Now just add in the RMS */
515
516 cpl_propertylist_update_double(plist,"ESO QC WCS_RMS",averr);
517 cpl_propertylist_set_comment(plist,"ESO QC WCS_RMS",
518 "[arcsec] Average error in WCS fit");
519
520 /* Right, get out of here now... */
521
522 cpl_wcs_delete(wcs);
523 tidy(work,iwork);
524 GOOD_STATUS
525}
526
527/*---------------------------------------------------------------------------*/
567/*---------------------------------------------------------------------------*/
568
569extern int casu_platexy(cpl_table *matchedxy, int nconst, cpl_array **coefs,
570 int *status) {
571 const char *fctid = "casu_platexy";
572 int nxy,nc2,i,niter,nrej,ngood;
573 unsigned char *isbad,*wptr2,*iwork=NULL;
574 double *xptr1,*xptr2,*yptr1,*yptr2,*wptr,a,b,c,d,e,f,*cc,xfit,yfit;
575 double dx,dy,averr,*work=NULL;
576 float *tptr;
577 int nreq = 4;
578 const char *reqcols[] = {"X_coordinate_1","Y_coordinate_1","X_coordinate_2",
579 "Y_coordinate_2"};
580
581 /* Inherited status */
582
583 *coefs = NULL;
584 if (*status != CASU_OK)
585 return(*status);
586
587 /* Check the value of nconst */
588
589 if (nconst != 4 && nconst != 6) {
590 cpl_msg_error(fctid,
591 "Value of nconst = %" CPL_SIZE_FORMAT " is unsupported",
592 (cpl_size)nconst);
593 FATAL_ERROR
594 }
595
596 /* How many objects are in the input table? */
597
598 nxy = (int)cpl_table_get_nrow(matchedxy);
599 nc2 = nconst/2;
600 if (nxy < nc2) {
601 cpl_msg_error(fctid,
602 "Too few objects (%" CPL_SIZE_FORMAT ") in table for %" CPL_SIZE_FORMAT " coefficient fit",
603 (cpl_size)nxy,(cpl_size)nconst);
604 FATAL_ERROR
605 }
606
607 /* Check that the matched standards table has all the required columns */
608
609 for (i = 0; i < nreq; i++) {
610 if (cpl_table_has_column(matchedxy,reqcols[i]) != 1) {
611 cpl_msg_error(fctid,"Input table missing column %s\n",reqcols[i]);
612 FATAL_ERROR
613 }
614 }
615
616 /* Get some workspace now */
617
618 work = cpl_malloc(6*nxy*sizeof(*work));
619 iwork = cpl_calloc(3*nxy,sizeof(*isbad));
620 xptr1 = work;
621 yptr1 = work + nxy;
622 xptr2 = work + 2*nxy;
623 yptr2 = work + 3*nxy;
624 wptr = work + 4*nxy;
625 isbad = iwork;
626 wptr2 = iwork + nxy;
627
628 /* Get the data from the table and put it all into double precision
629 arrays */
630
631 tptr = cpl_table_get_data_float(matchedxy,"X_coordinate_1");
632 for (i = 0; i < nxy; i++)
633 xptr1[i] = (double)tptr[i];
634 tptr = cpl_table_get_data_float(matchedxy,"Y_coordinate_1");
635 for (i = 0; i < nxy; i++)
636 yptr1[i] = (double)tptr[i];
637 tptr = cpl_table_get_data_float(matchedxy,"X_coordinate_2");
638 for (i = 0; i < nxy; i++)
639 xptr2[i] = (double)tptr[i];
640 tptr = cpl_table_get_data_float(matchedxy,"Y_coordinate_2");
641 for (i = 0; i < nxy; i++)
642 yptr2[i] = (double)tptr[i];
643
644 /* Right, now loop for maximum number of iterations or until
645 convergence */
646
647 niter = 0;
648 while (niter >= 0) {
649
650 /* Do a plate solution */
651
652 switch (nconst) {
653 case 6:
654 *status = casu_plate6(xptr2,yptr2,xptr1,yptr1,isbad,nxy,&a,&b,
655 &c,&e,&d,&f);
656 break;
657 case 4:
658 *status = casu_plate4(xptr2,yptr2,xptr1,yptr1,isbad,nxy,&a,&b,
659 &c,&e,&d,&f);
660 break;
661 default:
662 *status = casu_plate6(xptr2,yptr2,xptr1,yptr1,isbad,nxy,&a,&b,
663 &c,&e,&d,&f);
664 break;
665 }
666 if (*status != CASU_OK) {
667 cpl_msg_error(fctid,"Plate constant solution failed");
668 tidy(work,iwork);
669 FATAL_ERROR
670 }
671
672 /* Now look at the residuals and see if any should be rejected */
673
674 for (i = 0; i < nxy; i++) {
675 xfit = xptr2[i]*a + yptr2[i]*b + c;
676 yfit = xptr2[i]*d + yptr2[i]*e + f;
677 dx = fabs(xfit - xptr1[i]);
678 dy = fabs(yfit - yptr1[i]);
679 wptr[i*2] = dx;
680 wptr[i*2+1] = dy;
681 wptr2[i*2] = isbad[i];
682 wptr2[i*2+1] = isbad[i];
683 }
684 averr = casu_dmed(wptr,wptr2,2*nxy);
685 averr *= 1.48;
686 if (niter == 3)
687 break;
688 nrej = 0;
689 ngood = 0;
690 for (i = 0; i < nxy; i++) {
691 if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) nrej++;
692 if (!isbad[i])
693 ngood++;
694 }
695 ngood -= nrej;
696 if (nrej == 0 || ngood < nconst)
697 break;
698 for (i = 0; i < nxy; i++) {
699 if (!isbad[i] && (wptr[i*2] > 3.0*averr || wptr[i*2+1] > 3.0*averr)) isbad[i] = 1;
700 }
701 niter++;
702 }
703
704 /* Set the output array */
705
706 *coefs = cpl_array_new(6,CPL_TYPE_DOUBLE);
707 cc = cpl_array_get_data_double(*coefs);
708 cc[0] = a;
709 cc[1] = b;
710 cc[2] = c;
711 cc[3] = d;
712 cc[4] = e;
713 cc[5] = f;
714
715 /* Right, get out of here now... */
716
717 tidy(work,iwork);
718 GOOD_STATUS
719}
720
721/*---------------------------------------------------------------------------*/
755/*---------------------------------------------------------------------------*/
756
757static int casu_plate6(double *xpos, double *ypos, double *xi, double *eta,
758 unsigned char *flag, int nstds, double *a, double *b,
759 double *c, double *d, double *e, double *f) {
760 double sx1sq,sy1sq,sx1y1,sx1x2,sy1x2;
761 double sy1y2,sx1y2,xposmean,yposmean,ximean,etamean,xx1,yy1,xx2,yy2;
762 int i,ngood,nbad;
763
764 /* Is it worthwhile even being here? */
765
766 (void)casu_sumbpm(flag,(long)nstds,&nbad);
767 ngood = nstds - nbad;
768 if (ngood < 2)
769 return(CASU_FATAL);
770
771 /* Initialise all the counters and summations */
772
773 sx1sq = 0.0;
774 sy1sq = 0.0;
775 sx1y1 = 0.0;
776 sx1x2 = 0.0;
777 sy1x2 = 0.0;
778 sy1y2 = 0.0;
779 sx1y2 = 0.0;
780
781 /* Find means in each coordinate system */
782
783 xposmean = casu_dmean(xpos,flag,nstds);
784 yposmean = casu_dmean(ypos,flag,nstds);
785 ximean = casu_dmean(xi,flag,nstds);
786 etamean = casu_dmean(eta,flag,nstds);
787
788 /* Now accumulate the sums */
789
790 for (i = 0; i < nstds; i++) {
791 if (!flag[i]) {
792 xx1 = xpos[i] - xposmean;
793 yy1 = ypos[i] - yposmean;
794 xx2 = xi[i] - ximean;
795 yy2 = eta[i] - etamean;
796 sx1sq += xx1*xx1;
797 sy1sq += yy1*yy1;
798 sx1y1 += xx1*yy1;
799 sx1x2 += xx1*xx2;
800 sy1x2 += yy1*xx2;
801 sy1y2 += yy1*yy2;
802 sx1y2 += xx1*yy2;
803 }
804 }
805
806 /* Do solution for X */
807
808 *a = (sx1y1*sy1x2 - sx1x2*sy1sq)/(sx1y1*sx1y1 - sx1sq*sy1sq);
809 *b = (sx1x2*sx1y1 - sx1sq*sy1x2)/(sx1y1*sx1y1 - sx1sq*sy1sq);
810 *c = -xposmean*(*a) - yposmean*(*b) + ximean;
811
812 /* Now the solution for Y */
813
814 *d = (sx1y1*sx1y2 - sy1y2*sx1sq)/(sx1y1*sx1y1 - sy1sq*sx1sq);
815 *e = (sy1y2*sx1y1 - sy1sq*sx1y2)/(sx1y1*sx1y1 - sy1sq*sx1sq);
816 *f = -xposmean*(*e) - yposmean*(*d) + etamean;
817
818 /* Get outta here */
819
820 return(CASU_OK);
821}
822
823/*---------------------------------------------------------------------------*/
857/*---------------------------------------------------------------------------*/
858
859static int casu_plate4(double *xpos, double *ypos, double *xi, double *eta,
860 unsigned char *flag, int nstds, double *a, double *b,
861 double *c, double *d, double *e, double *f) {
862 double sx1sq,sy1sq,sx1x2,sy1x2,sy1y2,sx1y2,xposmean,yposmean;
863 double ximean,etamean,xx1,yy1,xx2,yy2,det,num,denom,theta,mag;
864 double stheta,ctheta;
865 int i,ngood,nbad;
866
867 /* Is it worthwhile even being here? */
868
869 (void)casu_sumbpm(flag,(long)nstds,&nbad);
870 ngood = nstds - nbad;
871 if (ngood < 2)
872 return(CASU_FATAL);
873
874 /* Initialise all the counters and summations */
875
876 sx1sq = 0.0;
877 sy1sq = 0.0;
878 sx1x2 = 0.0;
879 sy1x2 = 0.0;
880 sy1y2 = 0.0;
881 sx1y2 = 0.0;
882
883 /* Find means in each coordinate system */
884
885 xposmean = casu_dmean(xpos,flag,nstds);
886 yposmean = casu_dmean(ypos,flag,nstds);
887 ximean = casu_dmean(xi,flag,nstds);
888 etamean = casu_dmean(eta,flag,nstds);
889
890 /* Now accumulate the sums */
891
892 for (i = 0; i < nstds; i++) {
893 if (!flag[i]) {
894 xx1 = xpos[i] - xposmean;
895 yy1 = ypos[i] - yposmean;
896 xx2 = xi[i] - ximean;
897 yy2 = eta[i] - etamean;
898 sx1sq += xx1*xx1;
899 sy1sq += yy1*yy1;
900 sx1x2 += xx1*xx2;
901 sy1x2 += yy1*xx2;
902 sy1y2 += yy1*yy2;
903 sx1y2 += xx1*yy2;
904 }
905 }
906
907 /* Compute the rotation angle */
908
909 det = sx1x2*sy1y2 - sy1x2*sx1y2;
910 if (det < 0.0) {
911 num = sy1x2 + sx1y2;
912 denom = -sx1x2 + sy1y2;
913 } else {
914 num = sy1x2 - sx1y2;
915 denom = sx1x2 + sy1y2;
916 }
917 if (num == 0.0 && denom == 0.0) {
918 theta = 0.0;
919 } else {
920 theta = atan2(num,denom);
921 if (theta < 0.0)
922 theta += CPL_MATH_2PI;
923 }
924
925 /* Compute magnification factor */
926
927 ctheta = cos(theta);
928 stheta = sin(theta);
929 num = denom*ctheta + num*stheta;
930 denom = sx1sq + sy1sq;
931 if (denom <= 0.0) {
932 mag = 1.0;
933 } else {
934 mag = num/denom;
935 }
936
937 /* Compute coeffs */
938
939 if (det < 0.0) {
940 *a = -mag*ctheta;
941 *e = mag*stheta;
942 } else {
943 *a = mag*ctheta;
944 *e = -mag*stheta;
945 }
946 *b = mag*stheta;
947 *d = mag*ctheta;
948 *c = -xposmean*(*a) - yposmean*(*b) + ximean;
949 *f = -xposmean*(*e) - yposmean*(*d) + etamean;
950
951 /* Get outta here */
952
953 return(CASU_OK);
954}
955
956static void tidy(double *work, unsigned char *iwork) {
957 if(work != NULL) {cpl_free(work);}
958 //freespace(work);
959 if(iwork != NULL) {cpl_free(iwork);}
960 //freespace(iwork);
961}
962
966/*
967
968$Log: casu_platesol.c,v $
969Revision 1.3 2015/08/07 13:06:54 jim
970Fixed copyright to ESO
971
972Revision 1.2 2015/08/06 05:34:02 jim
973Fixes to get rid of compiler moans
974
975Revision 1.1.1.1 2015/06/12 10:44:32 jim
976Initial import
977
978Revision 1.8 2015/05/13 11:46:30 jim
979Now used casu_propertylist_update_double to get around datatype mismatches
980in propertylists
981
982Revision 1.7 2015/01/29 11:56:27 jim
983modified comments
984
985Revision 1.6 2015/01/09 12:13:15 jim
986*** empty log message ***
987
988Revision 1.5 2014/12/11 12:23:33 jim
989new version
990
991Revision 1.4 2014/04/26 18:39:45 jim
992uses new version of casu_sumbpm
993
994Revision 1.3 2014/03/26 15:56:46 jim
995Removed globals
996
997Revision 1.2 2013/11/21 09:38:14 jim
998detabbed
999
1000Revision 1.1.1.1 2013-08-27 12:07:48 jim
1001Imported
1002
1003
1004*/
int casu_platexy(cpl_table *matchedxy, int nconst, cpl_array **coefs, int *status)
Work out an xy transformation for two coodinate lists.
int casu_platesol(cpl_propertylist *plist, cpl_propertylist *tlist, cpl_table *matchedstds, int nconst, int shiftan, int *status)
Work out a WCS for an image.
double casu_dmean(double *data, unsigned char *bpm, long npts)
Definition: casu_stats.c:534
double casu_dmed(double *data, unsigned char *bpm, long npts)
Definition: casu_stats.c:170
int casu_sumbpm(unsigned char *bpm, long npts, int *sumb)
Definition: casu_stats.c:738
int casu_findcol(cpl_propertylist *p, const char *col)
Find from catalogue header which are x,y columns.
Definition: casu_utils.c:1050
void casu_propertylist_update_double(cpl_propertylist *plist, const char *name, double val)
Definition: casu_utils.c:1212
void casu_radectoxieta(cpl_wcs *wcs, double ra, double dec, double *xi, double *eta)
void casu_xytoradec(cpl_wcs *wcs, double x, double y, double *ra, double *dec)
Definition: casu_wcsutils.c:93