29#include "casu_stats.h"
42#include "eris_nix_defs.h"
43#include "eris_nix_match.h"
75 const int strict_classification,
76 cpl_table ** associated_std) {
78 if (cpl_error_get_code() != CPL_ERROR_NONE)
return cpl_error_get_code();
79 if (!objtab)
return CPL_ERROR_NONE;
80 if (!stdtab)
return CPL_ERROR_NONE;
89 cpl_size nstd = cpl_table_get_nrow(stdtab);
90 cpl_size nobj = cpl_table_get_nrow(objtab);
91 enu_check_error_code(
"Error accessing standard or object tables");
93 cpl_msg_warning(cpl_func,
"No associated sources: standards "
94 "catalogue is empty");
95 *associated_std = NULL;
96 return CPL_ERROR_NONE;
97 }
else if (nobj == 0) {
98 cpl_msg_warning(cpl_func,
"No associated sources: image "
99 "catalogue is empty");
100 *associated_std = NULL;
101 return CPL_ERROR_NONE;
106 cpl_table_cast_column(stdtab,
"xpredict", NULL, CPL_TYPE_DOUBLE);
107 double * xstd = cpl_table_get_data_double(stdtab,
"xpredict");
108 cpl_table_cast_column(stdtab,
"ypredict", NULL, CPL_TYPE_DOUBLE);
109 double * ystd = cpl_table_get_data_double(stdtab,
"ypredict");
110 enu_check_error_code(
"Error mapping table columns 1");
111 cpl_table_cast_column(objtab,
"X_coordinate", NULL, CPL_TYPE_DOUBLE);
112 double * xobj = cpl_table_get_data_double(objtab,
"X_coordinate");
113 cpl_table_cast_column(objtab,
"Y_coordinate", NULL, CPL_TYPE_DOUBLE);
114 double * yobj = cpl_table_get_data_double(objtab,
"Y_coordinate");
115 cpl_table_cast_column(objtab,
"Classification", NULL, CPL_TYPE_DOUBLE);
116 double * classification = cpl_table_get_data_double(objtab,
118 cpl_table_cast_column(objtab,
"Ellipticity", NULL, CPL_TYPE_DOUBLE);
119 double * ellipticity = cpl_table_get_data_double(objtab,
125 float assoc2 = assoc * assoc;
126 cpl_table_unselect_all(stdtab);
128 for (cpl_size istd = 0; istd < nstd; istd++) {
132 cpl_size iobj_match = -1;
133 int unique = CPL_TRUE;
135 for (cpl_size iobj= 0; iobj < nobj; iobj++) {
139 if (strict_classification &&
140 (classification[iobj] >= 0.0 || ellipticity[iobj] < 0.5)) {
144 float distance2 = pow(xobj[iobj] - xstd[istd], 2.0) +
145 pow(yobj[iobj] - ystd[istd], 2.0);
146 if (distance2 < assoc2) {
147 if (iobj_match != -1) {
156 if (iobj_match != -1 && unique) {
157 cpl_table_select_row(stdtab, istd);
161 if (cpl_table_count_selected(stdtab) > 0) {
165 *associated_std = cpl_table_extract_selected(stdtab);
172 cpl_array * colnames = cpl_table_get_column_names(objtab);
173 cpl_size ncol = cpl_array_get_size(colnames);
175 for (cpl_size i = 0; i < ncol; i++) {
176 const char * colname = cpl_array_get_string(colnames, i);
177 if (strcmp(colname,
"RA") && strcmp(colname,
"DEC")) {
178 cpl_table_new_column(*associated_std, colname,
179 cpl_table_get_column_type(objtab,
184 nstd = cpl_table_get_nrow(*associated_std);
186 cpl_table_cast_column(*associated_std,
"xpredict", NULL,
188 xstd = cpl_table_get_data_double(*associated_std,
"xpredict");
189 cpl_table_cast_column(*associated_std,
"ypredict", NULL,
191 ystd = cpl_table_get_data_double(*associated_std,
"ypredict");
192 enu_check_error_code(
"Error mapping matched table columns 1");
194 for (cpl_size istd = 0; istd < nstd; istd++) {
198 cpl_size iobj_match = -1;
199 for (cpl_size iobj= 0; iobj < nobj; iobj++) {
200 if (strict_classification &&
201 (classification[iobj] >= 0.0 || ellipticity[iobj] < 0.5)) {
204 float distance2 = pow(xobj[iobj] - xstd[istd], 2.0) +
205 pow(yobj[iobj] - ystd[istd], 2.0);
206 if (distance2 < assoc2) {
212 for (cpl_size i = 0; i < ncol; i++) {
213 const char * colname = cpl_array_get_string(colnames, i);
214 if (strcmp(colname,
"RA") && strcmp(colname,
"DEC")) {
217 switch (cpl_table_get_column_type(objtab, colname)) {
219 cpl_table_set_int(*associated_std, colname, istd,
220 cpl_table_get_int(objtab, colname,
221 iobj_match, &ignore));
224 cpl_table_set_float(*associated_std, colname, istd,
225 cpl_table_get_float(objtab,
226 colname, iobj_match, &ignore));
228 case CPL_TYPE_DOUBLE:
229 cpl_table_set_double(*associated_std, colname, istd,
230 cpl_table_get_double(objtab,
231 colname, iobj_match, &ignore));
234 cpl_table_set_float(*associated_std, colname, istd,
235 cpl_table_get_float(objtab,
236 colname, iobj_match, &ignore));
242 cpl_array_delete(colnames);
245 cpl_msg_warning(cpl_func,
"No sources associated");
246 *associated_std = NULL;
247 return CPL_ERROR_NONE;
252 if (cpl_error_get_code() != CPL_ERROR_NONE) {
253 cpl_table_delete(*associated_std);
254 *associated_std = NULL;
256 return cpl_error_get_code();
279 const char * catalogue,
280 cpl_table * matched_stds,
281 located_image * limage,
282 cpl_matrix ** xy_shift) {
284 if (cpl_error_get_code() != CPL_ERROR_NONE)
return cpl_error_get_code();
285 cpl_ensure_code(wcs_method, CPL_ERROR_NULL_INPUT);
286 cpl_ensure_code(catalogue, CPL_ERROR_NULL_INPUT);
287 cpl_ensure_code(limage, CPL_ERROR_NULL_INPUT);
288 cpl_ensure_code(xy_shift, CPL_ERROR_NULL_INPUT);
296 nmatch = cpl_table_get_nrow(matched_stds);
303 if (cpl_table_get_column_type(matched_stds,
"X_coordinate") ==
305 cpl_table_cast_column(matched_stds,
309 cpl_table_cast_column(matched_stds,
313 cpl_table_cast_column(matched_stds,
317 cpl_table_cast_column(matched_stds,
323 const double * x_coord = cpl_table_get_data_double_const(matched_stds,
325 const double * y_coord = cpl_table_get_data_double_const(matched_stds,
327 const double * xpredict = cpl_table_get_data_double_const(matched_stds,
329 const double * ypredict = cpl_table_get_data_double_const(matched_stds,
332 enu_check_error_code(
"failed to access matched table: %s",
333 cpl_error_get_message());
336 for (cpl_size i = 0; i < nmatch; i++) {
337 diff[i] = x_coord[i] - xpredict[i];
339 double xoffset = casu_dmed(diff, NULL, nmatch);
340 for (cpl_size i = 0; i < nmatch; i++) {
341 diff[i] = y_coord[i] - ypredict[i];
343 double yoffset = casu_dmed(diff, NULL, nmatch);
347 cpl_msg_info(cpl_func,
"correcting %4.2e %4.2e", xoffset, yoffset);
349 double crpix1 = cpl_propertylist_get_double(limage->plist,
"CRPIX1");
350 cpl_propertylist_update_double(limage->plist,
"CRPIX1", crpix1 + xoffset);
351 double crpix2 = cpl_propertylist_get_double(limage->plist,
"CRPIX2");
352 cpl_propertylist_update_double(limage->plist,
"CRPIX2", crpix2 + yoffset);
356 cpl_propertylist_update_string(limage->plist,
"ESO WCS_METHOD",
358 cpl_propertylist_update_string(limage->plist,
"WCS_CAT",
363 *xy_shift = cpl_matrix_new(1, 2);
364 cpl_matrix_set(*xy_shift, 0, 0, xoffset);
365 cpl_matrix_set(*xy_shift, 0, 1, yoffset);
367 cpl_msg_info(cpl_func,
"no entries in matched standards table, no "
368 "correction applied");
374 return cpl_error_get_code();
402 const double match_rad,
403 cpl_table ** matchtab) {
405 cpl_array * colnames = NULL;
406 const char * funcid =
"enm_match_brute_force";
407 cpl_size * matches = NULL;
408 cpl_array * match_is = NULL;
409 cpl_array * match_io = NULL;
410 cpl_table * mstds = NULL;
412 if (cpl_error_get_code() != CPL_ERROR_NONE)
return cpl_error_get_code();
413 if (!objtab)
return CPL_ERROR_NONE;
414 if (!stdtab)
return CPL_ERROR_NONE;
421 cpl_size nstd = cpl_table_get_nrow(stdtab);
422 cpl_size nobj = cpl_table_get_nrow(objtab);
423 enu_check(nstd > 0, CPL_ERROR_ILLEGAL_INPUT,
"Standards catalogue"
424 "contains no entries");
425 enu_check(nobj > 0, CPL_ERROR_ILLEGAL_INPUT,
"Image catalogue"
426 "contains no entries");
434 if (cpl_table_has_column(stdtab,
"Aper_flux_3")) {
435 cpl_msg_info(cpl_func,
" ..sorting standards table");
436 cpl_propertylist * reflist = cpl_propertylist_new();
437 cpl_propertylist_update_bool(reflist,
"Aper_flux_3", CPL_TRUE);
438 cpl_table_sort(stdtab, reflist);
439 cpl_propertylist_delete(reflist);
441 if (cpl_table_has_column(objtab,
"Aper_flux_3")) {
442 cpl_msg_info(cpl_func,
" ..sorting catalogue table");
443 cpl_propertylist * reflist = cpl_propertylist_new();
444 cpl_propertylist_update_bool(reflist,
"Aper_flux_3", CPL_TRUE);
445 cpl_table_sort(objtab, reflist);
446 cpl_propertylist_delete(reflist);
458 cpl_msg_info(cpl_func,
"truncating standards table to 100 entries");
462 cpl_msg_info(cpl_func,
"truncating catalogue table to 100 entries");
470 double * xstd = cpl_table_get_data_double(stdtab,
"xpredict");
471 double * ystd = cpl_table_get_data_double(stdtab,
"ypredict");
472 double * xobj = cpl_table_get_data_double(objtab,
"X_coordinate");
473 double * yobj = cpl_table_get_data_double(objtab,
"Y_coordinate");
475 cpl_size max_match = 0;
476 cpl_size match_std = -1;
477 cpl_size match_obj = -1;
479 for (cpl_size is = 0; is < nstd; is++) {
480 for (cpl_size io = 0; io < nobj; io++) {
482 cpl_matrix * distances = NULL;
489 cpl_array * match_distances = cpl_array_new(0, CPL_TYPE_DOUBLE);
491 while (cpl_matrix_get_min(distances) < match_rad) {
492 cpl_size istd_min = 0;
493 cpl_size iobj_min = 0;
494 double dist = cpl_matrix_get_min(distances);
495 cpl_matrix_get_minpos(distances,
498 cpl_matrix_fill_row(distances, 10000.0, istd_min);
499 cpl_matrix_fill_column(distances, 10000.0, iobj_min);
502 cpl_size next = cpl_array_get_size(match_distances);
503 cpl_array_set_size(match_distances, next+1);
504 cpl_array_set_double(match_distances, next, dist);
507 cpl_size nmatch = cpl_array_get_size(match_distances);
508 if (nmatch > max_match) {
514 cpl_array_delete(match_distances);
515 cpl_matrix_delete(distances);
518 cpl_msg_info(cpl_func,
" ..best match s=%d o=%d nmatch=%d match_rad=%e",
519 (
int)match_std, (
int)match_obj, (
int)max_match, match_rad);
520 if (max_match == 1) {
521 cpl_msg_warning(cpl_func,
"\033[0;31m"
522 "WCS calibration is unreliable because the pattern "
523 "match is based on a single source"
531 nstd = cpl_table_get_nrow(stdtab);
532 nobj = cpl_table_get_nrow(objtab);
534 cpl_matrix * distances = NULL;
537 match_std, match_obj, &distances);
539 match_is = cpl_array_new(0, CPL_TYPE_INT);
540 match_io = cpl_array_new(0, CPL_TYPE_INT);
544 while (cpl_matrix_get_min(distances) < match_rad) {
545 cpl_size istd_min = 0;
546 cpl_size iobj_min = 0;
547 cpl_matrix_get_minpos(distances,
550 cpl_matrix_fill_row(distances, 10000.0, istd_min);
551 cpl_matrix_fill_column(distances, 10000.0, iobj_min);
552 cpl_size nmatch = cpl_array_get_size(match_is);
553 cpl_array_set_size(match_is, nmatch+1);
554 cpl_array_set_int(match_is, nmatch, istd_min);
555 cpl_array_set_size(match_io, nmatch+1);
556 cpl_array_set_int(match_io, nmatch, iobj_min);
558 cpl_matrix_delete(distances);
563 mstds = cpl_table_duplicate(stdtab);
564 colnames = cpl_table_get_column_names(objtab);
565 cpl_size ncol = cpl_array_get_size(colnames);
566 for (cpl_size k = 0; k < ncol; k++) {
567 const char * colname = cpl_array_get_string(colnames, k);
568 if (!cpl_table_has_column(mstds, colname)) {
569 cpl_table_new_column(mstds, colname,
570 cpl_table_get_column_type(objtab, colname));
581 cpl_table_unselect_all(mstds);
583 for (cpl_size im = 0; im < cpl_array_get_size(match_is); im++) {
585 cpl_size is = cpl_array_get_int(match_is, im, &ignore);
590 cpl_table_select_row(mstds, is);
592 cpl_size io = cpl_array_get_int(match_io, im, &ignore);
594 for (cpl_size k = 0; k < ncol; k++) {
595 const char * colname = cpl_array_get_string(colnames, k);
596 if (!strcmp(colname,
"RA") || !strcmp(colname,
"DEC")) {
600 cpl_type column_type = cpl_table_get_column_type(objtab,
602 switch (column_type) {
604 cpl_table_set_int(mstds, colname, is,
605 cpl_table_get_int(objtab,
606 colname, io, &ignore));
610 cpl_table_set_float(mstds, colname, is,
611 cpl_table_get_float(objtab,
612 colname, io, &ignore));
614 case CPL_TYPE_DOUBLE:
615 cpl_table_set_double(mstds, colname, is,
616 cpl_table_get_double(objtab,
617 colname, io, &ignore));
620 cpl_error_set_message(funcid,
621 CPL_ERROR_UNSUPPORTED_MODE,
622 "column type not handled: %s",
623 cpl_type_get_name(column_type));
631 *matchtab = cpl_table_extract_selected(mstds);
637 cpl_array_delete(colnames);
639 cpl_array_delete(match_is);
640 cpl_array_delete(match_io);
641 cpl_table_delete(mstds);
643 if (cpl_error_get_code() != CPL_ERROR_NONE) {
644 cpl_table_delete(*matchtab);
648 return cpl_error_get_code();
685 cpl_matrix ** distances) {
687 if (cpl_error_get_code() != CPL_ERROR_NONE)
return cpl_error_get_code();
688 cpl_ensure_code(xstd, CPL_ERROR_NULL_INPUT);
689 cpl_ensure_code(ystd, CPL_ERROR_NULL_INPUT);
690 cpl_ensure_code(xobj, CPL_ERROR_NULL_INPUT);
691 cpl_ensure_code(yobj, CPL_ERROR_NULL_INPUT);
692 cpl_ensure_code(is>=0 && is<nstd, CPL_ERROR_ACCESS_OUT_OF_RANGE);
693 cpl_ensure_code(io>=0 && io<nobj, CPL_ERROR_ACCESS_OUT_OF_RANGE);
699 double xshift = xstd[is] - xobj[io];
700 double yshift = ystd[is] - yobj[io];
704 *distances = cpl_matrix_new(nstd, nobj);
705 cpl_matrix_fill(*distances, 10000.0);
707 for (cpl_size iis = 0; iis < nstd; iis++) {
708 for (cpl_size iio = 0; iio < nobj; iio++) {
711 double xobj_shifted = xobj[iio] + xshift;
712 double yobj_shifted = yobj[iio] + yshift;
715 double xdist = xstd[iis] - xobj_shifted;
716 double ydist = ystd[iis] - yobj_shifted;
717 double dist = sqrt(xdist*xdist + ydist * ydist);
719 cpl_matrix_set(*distances, iis, iio, dist);
723 return cpl_error_get_code();
cpl_error_code enm_correct_crpix(const char *wcs_method, const char *catalogue, cpl_table *matched_stds, located_image *limage, cpl_matrix **xy_shift)
Apply median offsets from matched standards table to image.
cpl_error_code enm_try_association(const double xstd[], const double ystd[], const cpl_size nstd, const double xobj[], const double yobj[], const cpl_size nobj, const cpl_size is, const cpl_size io, cpl_matrix **distances)
Method to calculate 'distances' matrix given an object association.
cpl_error_code enm_try_all_associations(cpl_table *objtab, cpl_table *stdtab, const double match_rad, cpl_table **matchtab)
Match standards with objects by trying all possibilities and selecting best.
cpl_error_code enm_associate_std(cpl_table *objtab, cpl_table *stdtab, const float assoc, const int strict_classification, cpl_table **associated_std)
Associate image catalogue objects with standards.