VIRCAM Pipeline 2.3.15
casu_match.c
1/* $Id: casu_match.c,v 1.2 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.2 $
25 * $Name: $
26 */
27
28/* Includes */
29
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33
34#include <math.h>
35
36#include <cpl.h>
37#include <string.h>
38#include <strings.h>
39
40#include "casu_mods.h"
41#include "casu_stats.h"
42#include "catalogue/casu_utils.h"
43
44#define NX 2048
45#define NY 2048
46#define NGRIDMAX_XY 61
47#define NGRIDMAX_STD 31
48
49static cpl_table *casu_mkmstd_table(cpl_table *objtab, cpl_table *stdstab);
50
53/*---------------------------------------------------------------------------*/
103/*---------------------------------------------------------------------------*/
104
105extern int casu_matchxy(cpl_table *progtab, cpl_table *template, float srad,
106 float *xoffset, float *yoffset, int *nm,
107 cpl_table **outtab, int *status) {
108 cpl_propertylist *p;
109 float *xprog,*yprog,*xtemp,*ytemp,aveden,errlim,xoffbest,yoffbest,xoff;
110 float yoff,x,y,*xoffs,*yoffs;
111 const char *fctid = "casu_matchxy";
112 int nprog,ntemp,ngrid,ngrid2,ibest,ig,jg,nmatch,k,jm;
113
114 /* Inherited status */
115
116 *xoffset = 0.0;
117 *yoffset = 0.0;
118 *nm = 0;
119 *outtab = NULL;
120 if (*status != CASU_OK)
121 return(*status);
122
123 /* Check the size of each of the tables */
124
125 nprog = (int)cpl_table_get_nrow(progtab);
126 ntemp = (int)cpl_table_get_nrow(template);
127 if (nprog == 0) {
128 cpl_msg_warning(fctid,"Program table has no rows");
129 WARN_RETURN
130 } else if (ntemp == 0) {
131 cpl_msg_warning(fctid,"Template table has no rows");
132 WARN_RETURN
133 }
134
135 /* First, sort the two tables by the Y coordinate */
136
137 p = cpl_propertylist_new();
138 cpl_propertylist_append_bool(p,"Y_coordinate",0);
139 if (cpl_table_sort(progtab,p) != CPL_ERROR_NONE) {
140 cpl_propertylist_delete(p);
141 FATAL_ERROR
142 }
143 if (cpl_table_sort(template,p) != CPL_ERROR_NONE) {
144 cpl_propertylist_delete(p);
145 FATAL_ERROR
146 }
147 cpl_propertylist_delete(p);
148
149 /* Get the x,y coordinates for each table */
150
151 xprog = cpl_table_get_data_float(progtab,"X_coordinate");
152 yprog = cpl_table_get_data_float(progtab,"Y_coordinate");
153 xtemp = cpl_table_get_data_float(template,"X_coordinate");
154 ytemp = cpl_table_get_data_float(template,"Y_coordinate");
155 if (xprog == NULL || yprog == NULL || xtemp == NULL || ytemp == NULL)
156 FATAL_ERROR
157
158 /* Calculate the error limit and the number of grid points */
159
160 aveden = (float)ntemp/(float)(NX*NY);
161 errlim = 1.0/sqrt(4.0*CPL_MATH_PI*aveden);
162 errlim = min(errlim,15.0);
163 ngrid = (int)(srad/errlim);
164 ngrid = (ngrid/2)*2 + 1;
165 ngrid = max(5,min(NGRIDMAX_XY,ngrid));
166 ngrid2 = ngrid/2 + 1;
167
168 /* Now search for the best solution */
169
170 ibest = 0;
171 xoffbest = 0.0;
172 yoffbest = 0.0;
173 for (ig = -ngrid2; ig <= ngrid2; ig++) {
174 xoff = (float)ig*errlim*CPL_MATH_SQRT2;
175 for (jg = -ngrid2; jg <= ngrid2; jg++) {
176 yoff = (float)jg*errlim*CPL_MATH_SQRT2;
177 nmatch = 0;
178 for (k = 0; k < nprog; k++) {
179 x = xprog[k] + xoff;
180 y = yprog[k] + yoff;
181 if (casu_fndmatch(x,y,xtemp,ytemp,ntemp,errlim) > -1)
182 nmatch++;
183 }
184 if (nmatch > ibest) {
185 ibest = nmatch;
186 xoffbest = xoff;
187 yoffbest = yoff;
188 }
189 }
190 }
191
192 /* Now allocate some workspace so that you can calculate a good median
193 coordinate difference */
194
195 xoffs = cpl_malloc(nprog*sizeof(*xoffs));
196 yoffs = cpl_malloc(nprog*sizeof(*yoffs));
197
198 /* Now get the coordinate differences and find the medians */
199
200 nmatch = 0;
201 for (k = 0; k < nprog; k++) {
202 x = xprog[k] + xoffbest;
203 y = yprog[k] + yoffbest;
204 jm = casu_fndmatch(x,y,xtemp,ytemp,ntemp,errlim);
205 if (jm > -1) {
206 xoffs[nmatch] = xtemp[jm] - xprog[k];
207 yoffs[nmatch] = ytemp[jm] - yprog[k];
208 nmatch++;
209 }
210 }
211 if (nmatch > 0) {
212 *xoffset = casu_med(xoffs,NULL,nmatch);
213 *yoffset = casu_med(yoffs,NULL,nmatch);
214 } else {
215 *xoffset = 0.0;
216 *yoffset = 0.0;
217 }
218 *nm = nmatch;
219
220 /* Create the output table */
221
222 *outtab = cpl_table_new((cpl_size)nprog);
223 cpl_table_new_column(*outtab,"X_coordinate_1",CPL_TYPE_FLOAT);
224 cpl_table_new_column(*outtab,"Y_coordinate_1",CPL_TYPE_FLOAT);
225 cpl_table_new_column(*outtab,"X_coordinate_2",CPL_TYPE_FLOAT);
226 cpl_table_new_column(*outtab,"Y_coordinate_2",CPL_TYPE_FLOAT);
227 nmatch = 0;
228 for (k = 0; k < nprog; k++) {
229 x = xprog[k] + *xoffset;
230 y = yprog[k] + *yoffset;
231 jm = casu_fndmatch(x,y,xtemp,ytemp,ntemp,1.0);
232 if (jm > -1) {
233 cpl_table_set_float(*outtab,"X_coordinate_1",(cpl_size)nmatch,
234 xtemp[jm]);
235 cpl_table_set_float(*outtab,"Y_coordinate_1",(cpl_size)nmatch,
236 ytemp[jm]);
237 cpl_table_set_float(*outtab,"X_coordinate_2",(cpl_size)nmatch,
238 xprog[k]);
239 cpl_table_set_float(*outtab,"Y_coordinate_2",(cpl_size)nmatch,
240 yprog[k]);
241 nmatch++;
242 }
243 }
244 cpl_table_set_size(*outtab,(cpl_size)nmatch);
245
246 /* Tidy and exit */
247
248 freespace(xoffs);
249 freespace(yoffs);
250 GOOD_STATUS
251}
252
253/*---------------------------------------------------------------------------*/
298/*---------------------------------------------------------------------------*/
299
300extern int casu_matchstds(cpl_table *objtab, cpl_table *stdstab, float srad,
301 cpl_table **outtab, int *status) {
302 const char *fctid = "casu_matchstds";
303 char *colname;
304 int nobj,nstd,ngrid,ngrid2,ibest,ig,jg,nmatch,k,*matches,jm,l,dont,null,k2;
305 float *xstd,*ystd,*xobj,*yobj,aveden,errlim,xoffbest,yoffbest,*xoffs;
306 float *yoffs,x,y,xx2,yy2,r2,xx1,yy1,r1,xoffmed,sigx,yoffmed,sigy,xoff,yoff;
307 cpl_propertylist *p;
308 cpl_table *mstds;
309 cpl_array *colnames;
310
311 /* Inherited status */
312
313 *outtab = NULL;
314 if (*status != CASU_OK)
315 return(*status);
316
317 /* Check the size of each of the tables */
318
319 nobj = (int)cpl_table_get_nrow(objtab);
320 nstd = (int)cpl_table_get_nrow(stdstab);
321 if (nobj == 0) {
322 cpl_msg_warning(fctid,"Object table has no rows");
323 mstds = casu_mkmstd_table(objtab,stdstab);
324 *outtab = cpl_table_extract_selected(mstds);
325 cpl_table_delete(mstds);
326 WARN_RETURN
327 } else if (nstd == 0) {
328 cpl_msg_warning(fctid,"Standards RA/DEC table has no rows");
329 mstds = casu_mkmstd_table(objtab,stdstab);
330 *outtab = cpl_table_extract_selected(mstds);
331 cpl_table_delete(mstds);
332 WARN_RETURN
333 }
334
335 /* First, sort the two tables by the Y coordinate */
336
337 p = cpl_propertylist_new();
338 cpl_propertylist_append_bool(p,"Y_coordinate",0);
339 if (cpl_table_sort(objtab,p) != CPL_ERROR_NONE) {
340 cpl_propertylist_delete(p);
341 FATAL_ERROR
342 }
343 cpl_propertylist_erase(p,"Y_coordinate");
344 cpl_propertylist_append_bool(p,"ypredict",0);
345 if (cpl_table_sort(stdstab,p) != CPL_ERROR_NONE) {
346 cpl_propertylist_delete(p);
347 FATAL_ERROR
348 }
349 cpl_propertylist_delete(p);
350
351 /* Get the x,y coordinates for each table */
352
353 xobj = cpl_table_get_data_float(objtab,"X_coordinate");
354 yobj = cpl_table_get_data_float(objtab,"Y_coordinate");
355 xstd = cpl_table_get_data_float(stdstab,"xpredict");
356 ystd = cpl_table_get_data_float(stdstab,"ypredict");
357 if (xstd == NULL || ystd == NULL || xobj == NULL || yobj == NULL)
358 FATAL_ERROR
359
360 /* Calculate the error limit and the number of grid points */
361
362 // This is the average density of stars in the image
363 // FIXME it is incorrect to assume NX and NY are fixed
364 aveden = (float)max(nstd,nobj)/(float)(NX*NY);
365 // An initial estimate of a sensible error limit
366 errlim = 1.0/sqrt(4.0*CPL_MATH_PI*aveden);
367 errlim = min(errlim,15.0);
368 // The grid size to achieve this
369 ngrid = (int)(srad/errlim);
370 ngrid = (ngrid/2)*2 + 1;
371 // Constrain the number of grid points
372 ngrid = max(5,min(NGRIDMAX_STD,ngrid));
373 ngrid2 = ngrid/2 + 1;
374
375 cpl_msg_info(fctid, "Search radius is %f pixels. Using a %d x %d grid, with error limit of %f", srad, ngrid, ngrid, errlim);
376
377 /* Now search for the best solution */
378
379 ibest = 0;
380 xoffbest = 0.0;
381 yoffbest = 0.0;
382 for (ig = -ngrid2; ig <= ngrid2; ig++) {
383 xoff = (float)ig*errlim*CPL_MATH_SQRT2;
384 for (jg = -ngrid2; jg <= ngrid2; jg++) {
385 yoff = (float)jg*errlim*CPL_MATH_SQRT2;
386 nmatch = 0;
387 for (k = 0; k < nobj; k++) {
388 x = xobj[k] + xoff;
389 y = yobj[k] + yoff;
390 if (casu_fndmatch(x,y,xstd,ystd,nstd,errlim) > -1)
391 nmatch++;
392 }
393 if (nmatch > ibest) {
394 ibest = nmatch;
395 xoffbest = xoff;
396 yoffbest = yoff;
397 }
398 }
399 }
400
401 /* Now allocate some workspace so that you can calculate a good median
402 coordinate difference */
403
404 xoffs = cpl_malloc(nstd*sizeof(*xoffs));
405 yoffs = cpl_malloc(nstd*sizeof(*yoffs));
406 matches = cpl_malloc(nstd*sizeof(*matches));
407 for (k = 0; k < nstd; k++)
408 matches[k] = -1;
409
410 /* Now get the best matches */
411
412 nmatch = 0;
413 for (k = 0; k < nstd; k++) {
414 x = xstd[k] - xoffbest;
415 y = ystd[k] - yoffbest;
416 jm = casu_fndmatch(x,y,xobj,yobj,nobj,errlim);
417 if (jm > -1) {
418 dont = 0;
419 xx2 = xobj[jm] - x;
420 yy2 = yobj[jm] - y;
421 r2 = sqrt(xx2*xx2 + yy2*yy2);
422 for (l = 0; l < nstd; l++) {
423 if (matches[l] == jm) {
424 xx1 = xobj[jm] - (xstd[l] - xoffbest);
425 yy1 = yobj[jm] - (ystd[l] - yoffbest);
426 r1 = sqrt(xx1*xx1 + yy1*yy1);
427 if (r2 < r1)
428 matches[l] = -1;
429 else
430 dont = 1;
431 break;
432 }
433 }
434 if (dont == 0)
435 matches[k] = jm;
436 }
437 }
438
439 /* Now get the coordinate difference for the best matches */
440
441 for (k = 0; k < nstd; k++) {
442 jm = matches[k];
443 if (jm != -1) {
444 xoffs[nmatch] = xobj[jm] - xstd[k];
445 yoffs[nmatch] = yobj[jm] - ystd[k];
446 nmatch++;
447 }
448 }
449 if (nmatch == 0) {
450 xoffmed = 0.0;
451 sigx = 1.0;
452 yoffmed = 0.0;
453 sigy = 1.0;
454 } else {
455 casu_medmad(xoffs,NULL,nmatch,&xoffmed,&sigx);
456 sigx *= 1.48;
457 casu_medmad(yoffs,NULL,nmatch,&yoffmed,&sigy);
458 sigy *= 1.48;
459 }
460
461 cpl_msg_info(fctid, "Median offset x=%f y=%f, sigx=%f sigy=%f", xoffmed, yoffmed, sigx, sigy);
462
463 /* Now go through one final time with a reduced error box and get
464 the final matches */
465
466 errlim = 3.0*max(sigx,sigy);
467 for (k = 0; k < nstd; k++)
468 matches[k] = -1;
469 for (k = 0; k < nstd; k++) {
470 x = xstd[k] + xoffmed;
471 y = ystd[k] + yoffmed;
472 jm = casu_fndmatch(x,y,xobj,yobj,nobj,errlim);
473 if (jm > -1) {
474 dont = 0;
475 xx2 = xobj[jm] - x;
476 yy2 = yobj[jm] - y;
477 r2 = sqrt(xx2*xx2 + yy2*yy2);
478 for (l = 0; l < nstd; l++) {
479 if (matches[l] == jm) {
480 xx1 = xobj[jm] - (xstd[l] + xoffmed);
481 yy1 = yobj[jm] - (ystd[l] + yoffmed);
482 r1 = sqrt(xx1*xx1 + yy1*yy1);
483 if (r2 < r1)
484 matches[l] = -1;
485 else
486 dont = 1;
487/* break; */
488 }
489 }
490 if (dont == 0)
491 matches[k] = jm;
492 }
493 }
494 jm = matches[1];
495
496 /* Make a copy of the standards table and add all the columns from the
497 object catalogue to it. Ignore the RA and DEC columns in the catalogue
498 as the standards table will already have these.*/
499
500 mstds = cpl_table_duplicate(stdstab);
501 colnames = cpl_table_get_column_names(objtab);
502 ig = (int)cpl_array_get_size(colnames);
503 for (k = 0; k < ig; k++) {
504 colname = (char *)cpl_array_get_string(colnames,(cpl_size)k);
505 if (strcasecmp(colname,"RA") && strcasecmp(colname,"DEC"))
506 cpl_table_new_column(mstds,colname,
507 cpl_table_get_column_type(objtab,colname));
508 }
509 cpl_table_unselect_all(mstds);
510 cpl_array_delete(colnames);
511
512 /* Now go through and find the matches. NB: the columns in objtab
513 are created by casu_imcore which only produces integer, float and
514 double columns, so we don't need to worry about any other type
515 when copying the columns to the matched standards catalogue. */
516
517 colnames = cpl_table_get_column_names(objtab);
518 ig = (int)cpl_array_get_size(colnames);
519 for (k = 0; k < nstd; k++) {
520 jm = matches[k];
521 if (jm != -1) {
522 for (k2 = 0; k2 < ig; k2++) {
523 colname = (char *)cpl_array_get_string(colnames,
524 (cpl_size)k2);
525 if (!strcasecmp(colname,"RA") || !strcasecmp(colname,"DEC"))
526 continue;
527 null = 0;
528 switch (cpl_table_get_column_type(objtab,colname)) {
529 case CPL_TYPE_INT:
530 cpl_table_set_int(mstds,colname,(cpl_size)k,
531 cpl_table_get_int(objtab,colname,
532 (cpl_size)jm,&null));
533 break;
534 case CPL_TYPE_FLOAT:
535 cpl_table_set_float(mstds,colname,(cpl_size)k,
536 cpl_table_get_float(objtab,colname,
537 (cpl_size)jm,&null));
538 break;
539 case CPL_TYPE_DOUBLE:
540 cpl_table_set_double(mstds,colname,(cpl_size)k,
541 cpl_table_get_double(objtab,colname,
542 (cpl_size)jm,&null));
543 break;
544 case CPL_TYPE_STRING:
545 cpl_table_set_string(mstds,colname,(cpl_size)k,
546 cpl_table_get_string(objtab,colname,
547 (cpl_size)jm));
548 break;
549 default:
550 cpl_msg_info(fctid, "Ignoring column %s of type %d", colname, cpl_table_get_column_type(objtab,colname));
551 break;
552 }
553 }
554 cpl_table_select_row(mstds,(cpl_size)k);
555 }
556 }
557 cpl_array_delete(colnames);
558
559 /* Now extract the selected rows into the output table */
560
561 *outtab = cpl_table_extract_selected(mstds);
562 cpl_table_delete(mstds);
563
564 /* Tidy up */
565
566 freespace(matches);
567 freespace(xoffs);
568 freespace(yoffs);
569 GOOD_STATUS
570}
571
572/*---------------------------------------------------------------------------*/
592/*---------------------------------------------------------------------------*/
593
594static cpl_table *casu_mkmstd_table(cpl_table *objtab, cpl_table *stdstab) {
595 cpl_table *mstds;
596 char *colname;
597 cpl_array *colnames;
598 cpl_size ncol,i;
599
600 /* Copy the input standards table */
601
602 mstds = cpl_table_duplicate(stdstab);
603
604 /* Loop throught the object table columns and copy all of them over,
605 except for the RA and DEC tables */
606
607 colnames = cpl_table_get_column_names((const cpl_table *)objtab);
608 ncol = cpl_array_get_size(colnames);
609 for (i = 0; i < ncol; i++) {
610 colname = (char *)cpl_array_get_string(colnames,i);
611 if (strcmp(colname,"RA") && strcmp(colname,"DEC"))
612 cpl_table_new_column(mstds,colname,
613 cpl_table_get_column_type(objtab,colname));
614 }
615 cpl_array_delete(colnames);
616 cpl_table_unselect_all(mstds);
617
618 /* Get out of here */
619
620 return(mstds);
621}
622
626/*
627
628$Log: casu_match.c,v $
629Revision 1.2 2015/08/07 13:06:54 jim
630Fixed copyright to ESO
631
632Revision 1.1.1.1 2015/06/12 10:44:32 jim
633Initial import
634
635Revision 1.5 2015/05/20 11:59:48 jim
636Modified to remove calls to deprecated cpl_table_get_column_name
637
638Revision 1.4 2015/02/14 12:32:06 jim
639fixed typo
640
641Revision 1.3 2015/01/29 11:51:56 jim
642modified comments
643
644Revision 1.2 2013/11/21 09:38:14 jim
645detabbed
646
647Revision 1.1.1.1 2013-08-27 12:07:48 jim
648Imported
649
650
651*/
int casu_matchstds(cpl_table *objtab, cpl_table *stdstab, float srad, cpl_table **outtab, int *status)
Match object and standard star tables by their xy coordinates.
Definition: casu_match.c:300
int casu_matchxy(cpl_table *progtab, cpl_table *template, float srad, float *xoffset, float *yoffset, int *nm, cpl_table **outtab, int *status)
Match two lists of x,y coordinates from two tables to find the cartesian offset between them.
Definition: casu_match.c:105
void casu_medmad(float *data, unsigned char *bpm, long np, float *med, float *mad)
Definition: casu_stats.c:347
float casu_med(float *data, unsigned char *bpm, long npts)
Definition: casu_stats.c:89
int casu_fndmatch(float x, float y, float *xlist, float *ylist, int nlist, float err)
Match the x,y coordinates of an object to one from a list.
Definition: casu_utils.c:982