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 
42 static 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);
45 static 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);
48 static void tidy(double *work, unsigned char *iwork);
49 
52 /*---------------------------------------------------------------------------*/
124 /*---------------------------------------------------------------------------*/
125 
126 extern 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 
569 extern 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 
757 static 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 
859 static 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 
956 static 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 $
969 Revision 1.3 2015/08/07 13:06:54 jim
970 Fixed copyright to ESO
971 
972 Revision 1.2 2015/08/06 05:34:02 jim
973 Fixes to get rid of compiler moans
974 
975 Revision 1.1.1.1 2015/06/12 10:44:32 jim
976 Initial import
977 
978 Revision 1.8 2015/05/13 11:46:30 jim
979 Now used casu_propertylist_update_double to get around datatype mismatches
980 in propertylists
981 
982 Revision 1.7 2015/01/29 11:56:27 jim
983 modified comments
984 
985 Revision 1.6 2015/01/09 12:13:15 jim
986 *** empty log message ***
987 
988 Revision 1.5 2014/12/11 12:23:33 jim
989 new version
990 
991 Revision 1.4 2014/04/26 18:39:45 jim
992 uses new version of casu_sumbpm
993 
994 Revision 1.3 2014/03/26 15:56:46 jim
995 Removed globals
996 
997 Revision 1.2 2013/11/21 09:38:14 jim
998 detabbed
999 
1000 Revision 1.1.1.1 2013-08-27 12:07:48 jim
1001 Imported
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