33 #include "muse_instrument.h" 35 #include "muse_astro.h" 36 #include "muse_combine.h" 38 #include "muse_pfits.h" 39 #include "muse_quality.h" 40 #include "muse_resampling.h" 41 #include "muse_utils.h" 47 #define FAKE_POS_ROT 0 96 cpl_table_delete(aWCSObj->detected);
97 aWCSObj->detected = NULL;
98 cpl_propertylist_delete(aWCSObj->wcs);
117 {
"XPOS", CPL_TYPE_DOUBLE,
"pix",
"%f",
"horizontal position", CPL_TRUE },
118 {
"YPOS", CPL_TYPE_DOUBLE,
"pix",
"%f",
"vertical position", CPL_TRUE },
119 {
"XERR", CPL_TYPE_DOUBLE,
"pix",
"%f",
120 "error estimate of the horizontal position", CPL_TRUE },
121 {
"YERR", CPL_TYPE_DOUBLE,
"pix",
"%f",
122 "error estimate of the vertical position", CPL_TRUE },
123 {
"FLUX", CPL_TYPE_DOUBLE,
"count",
"%e",
"(relative) flux of the source", CPL_TRUE },
124 {
"XFWHM", CPL_TYPE_DOUBLE,
"pix",
"%f",
"horizontal FWHM", CPL_TRUE },
125 {
"YFWHM", CPL_TYPE_DOUBLE,
"pix",
"%f",
"vertical FWHM", CPL_TRUE },
126 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
142 {
"SourceID", CPL_TYPE_STRING,
"",
"%s",
"the source identification", CPL_TRUE },
143 {
"RA", CPL_TYPE_DOUBLE,
"deg",
"%f",
"right ascension (decimal degrees)", CPL_TRUE },
144 {
"DEC", CPL_TYPE_DOUBLE,
"deg",
"%f",
"declination (decimal degrees)", CPL_TRUE },
145 {
"filter", CPL_TYPE_STRING,
"",
"%s",
"the filter used for the magnitude", CPL_TRUE },
146 {
"mag", CPL_TYPE_DOUBLE,
"mag",
"%f",
"the object (Vega) magnitude", CPL_TRUE },
147 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
181 cpl_ensure(aImage && aImage->
data && aImage->
stat, CPL_ERROR_NULL_INPUT,
183 cpl_ensure(aSigma > 0., CPL_ERROR_ILLEGAL_INPUT, NULL);
186 cpl_msg_info(__func__,
"Gaussian profile fits for object centroiding");
189 cpl_msg_info(__func__,
"Moffat profile fits for object centroiding");
192 cpl_msg_info(__func__,
"Simple square box object centroiding");
195 cpl_msg_error(__func__,
"Unknown centroiding method!");
196 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
204 image->
data = cpl_image_duplicate(aImage->
data);
205 image->
stat = cpl_image_power_create(aImage->
stat, 0.5);
207 image->
header = cpl_propertylist_duplicate(aImage->
header);
212 image->
dq = cpl_image_duplicate(aImage->
dq);
215 cpl_image_reject_value(image->
data, CPL_VALUE_NAN);
216 cpl_image_reject_value(image->
stat, CPL_VALUE_NAN);
220 cpl_image_fill_rejected(image->
data, cpl_image_get_min(image->
data));
221 cpl_image_fill_rejected(image->
stat, cpl_image_get_max(image->
stat));
224 cpl_apertures *apertures = cpl_apertures_extract_sigma(image->
data, aSigma);
225 int ndet = apertures ? cpl_apertures_get_size(apertures) : 0;
228 cpl_msg_error(__func__,
"No sources for astrometric calibration found down " 229 "to %.3f sigma limit", aSigma);
230 cpl_error_set(__func__, CPL_ERROR_DATA_NOT_FOUND);
233 double med_dist, median = cpl_image_get_median_dev(image->
data, &med_dist),
234 threshold = median + aSigma * med_dist;
235 cpl_msg_debug(__func__,
"The %.3f sigma threshold (%.3f, %.3f +/- %.3f) was " 236 "used to find %d sources", aSigma, threshold, median, med_dist,
239 int nx = cpl_image_get_size_x(image->
data),
240 ny = cpl_image_get_size_y(image->
data);
242 const double bgguess = cpl_image_get_median(image->
data),
244 moffat_alpha_to_fwhm = 1 / (2 * sqrt(pow(2, 1/beta) - 1));
248 if (fwhmguess < FLT_EPSILON) {
252 fwhmguess /= (kMuseSpaxelSizeX_WFM + kMuseSpaxelSizeX_WFM) / 2;
254 fwhmguess /= (kMuseSpaxelSizeX_NFM + kMuseSpaxelSizeX_NFM) / 2;
262 cpl_table_unselect_all(detections);
264 for (idet = 0; idet < ndet; idet++) {
265 double xc = cpl_apertures_get_centroid_x(apertures, idet+1),
266 yc = cpl_apertures_get_centroid_y(apertures, idet+1),
267 fluxaper = cpl_apertures_get_flux(apertures, idet+1);
268 double xwaper, ywaper;
269 cpl_image_get_fwhm(image->
data, lround(xc), lround(yc), &xwaper, &ywaper);
273 if (xwaper < 0 || ywaper < 0) {
274 cpl_msg_debug(__func__,
"FWHM computation unsuccessful at %f,%f, result " 275 "was %.3f,%.3f", xc, yc, xwaper, ywaper);
276 cpl_table_select_row(detections, idet);
282 int x1 = floor(xc) - 5,
289 if (x2 > nx) x2 = nx;
290 if (y2 > ny) y2 = ny;
292 double xcen, ycen, xerr = 0., yerr = 0., xw, yw, flux;
293 cpl_errorstate state = cpl_errorstate_get();
296 cpl_array *pgauss = cpl_array_new(7, CPL_TYPE_DOUBLE),
297 *pgerr = cpl_array_new(7, CPL_TYPE_DOUBLE),
298 *pgfit = cpl_array_new(7, CPL_TYPE_INT);
300 cpl_array_set(pgfit, 3, 1);
301 cpl_array_set(pgfit, 4, 1);
302 cpl_array_set(pgfit, 0, 0);
303 cpl_array_set(pgfit, 1, 0);
304 cpl_array_set(pgfit, 2, 0);
305 cpl_array_set(pgfit, 5, 0);
306 cpl_array_set(pgfit, 6, 0);
307 cpl_array_set(pgauss, 3, xc);
308 cpl_array_set(pgauss, 4, yc);
309 cpl_array_set(pgauss, 0, bgguess);
310 cpl_array_set(pgauss, 1, fluxaper);
311 cpl_array_set(pgauss, 2, 0.);
312 cpl_array_set(pgauss, 5, xwaper * CPL_MATH_SIG_FWHM);
313 cpl_array_set(pgauss, 6, ywaper * CPL_MATH_SIG_FWHM);
314 cpl_fit_image_gaussian(image->
data, image->
stat, lround(xc), lround(yc),
315 x2-x1+1, y2-y1+1, pgauss, pgerr, pgfit, NULL, NULL,
316 NULL, NULL, NULL, NULL, NULL);
317 xcen = cpl_array_get(pgauss, 3, NULL);
318 ycen = cpl_array_get(pgauss, 4, NULL);
319 xerr = cpl_array_get(pgerr, 3, NULL);
320 yerr = cpl_array_get(pgerr, 4, NULL);
322 cpl_array_set(pgfit, 3, 0);
323 cpl_array_set(pgfit, 4, 0);
324 cpl_array_set(pgfit, 1, 1);
325 cpl_array_set(pgfit, 5, 1);
326 cpl_array_set(pgfit, 6, 1);
327 cpl_fit_image_gaussian(image->
data, image->
stat, lround(xc), lround(yc),
328 x2-x1+1, y2-y1+1, pgauss, pgerr, pgfit, NULL, NULL,
329 NULL, NULL, NULL, NULL, NULL);
330 xw = cpl_array_get(pgauss, 5, NULL) * CPL_MATH_FWHM_SIG;
331 yw = cpl_array_get(pgauss, 6, NULL) * CPL_MATH_FWHM_SIG;
332 flux = cpl_array_get(pgauss, 1, NULL);
333 cpl_array_delete(pgauss);
334 cpl_array_delete(pgerr);
335 cpl_array_delete(pgfit);
339 cpl_size nmax = (x2-x1+1) * (y2-y1+1);
340 cpl_matrix *pos = cpl_matrix_new(nmax, 2);
341 cpl_vector *val = cpl_vector_new(nmax),
342 *err = cpl_vector_new(nmax);
344 for (i = x1; i <= x2; i++) {
346 for (j = y1; j <= y2; j++) {
348 double value = cpl_image_get(image->
data, i, j, &error);
352 cpl_matrix_set(pos, npix, 0, i);
353 cpl_matrix_set(pos, npix, 1, j);
354 cpl_vector_set(val, npix, value);
356 cpl_vector_set(err, npix, cpl_image_get(image->
stat, i, j, &error));
360 cpl_matrix_set_size(pos, npix, 2);
361 cpl_vector_set_size(val, npix);
362 cpl_vector_set_size(err, npix);
363 cpl_array *pmoffat = cpl_array_new(8, CPL_TYPE_DOUBLE),
364 *pmerror = cpl_array_new(8, CPL_TYPE_DOUBLE),
365 *pmfit = cpl_array_new(8, CPL_TYPE_INT);
367 cpl_array_set(pmfit, 2, 1);
368 cpl_array_set(pmfit, 3, 1);
369 cpl_array_set(pmfit, 0, 0);
370 cpl_array_set(pmfit, 1, 0);
371 cpl_array_set(pmfit, 4, 0);
372 cpl_array_set(pmfit, 5, 0);
373 cpl_array_set(pmfit, 6, 0);
374 cpl_array_set(pmfit, 7, 0);
375 cpl_array_set(pmoffat, 2, xc);
376 cpl_array_set(pmoffat, 3, yc);
377 cpl_array_set(pmoffat, 0, bgguess);
378 cpl_array_set(pmoffat, 1, fluxaper);
379 cpl_array_set(pmoffat, 4, xwaper * moffat_alpha_to_fwhm);
380 cpl_array_set(pmoffat, 5, ywaper * moffat_alpha_to_fwhm);
381 cpl_array_set(pmoffat, 6, beta);
382 cpl_array_set(pmoffat, 7, 0.);
384 xcen = cpl_array_get(pmoffat, 2, NULL);
385 ycen = cpl_array_get(pmoffat, 3, NULL);
386 xerr = cpl_array_get(pmerror, 2, NULL);
387 yerr = cpl_array_get(pmerror, 3, NULL);
389 cpl_array_set(pmfit, 2, 0);
390 cpl_array_set(pmfit, 3, 0);
391 cpl_array_set(pmfit, 1, 1);
392 cpl_array_set(pmfit, 4, 1);
393 cpl_array_set(pmfit, 5, 1);
395 xw = cpl_array_get(pmoffat, 4, NULL) / moffat_alpha_to_fwhm;
396 yw = cpl_array_get(pmoffat, 5, NULL) / moffat_alpha_to_fwhm;
397 flux = cpl_array_get(pmoffat, 1, NULL);
398 cpl_array_delete(pmoffat);
399 cpl_array_delete(pmerror);
400 cpl_array_delete(pmfit);
401 cpl_matrix_delete(pos);
402 cpl_vector_delete(val);
403 cpl_vector_delete(err);
411 printf(
"%d apertures %f %f boxes %f %f deltas %f %f\n", idet+1, xc, yc,
412 xcen, ycen, xcen - xc, ycen - yc);
420 cpl_image_get_fwhm(image->
data, lround(xcen), lround(ycen), &xw, &yw);
425 cpl_table_set(detections,
"XPOS", idet, xcen);
426 cpl_table_set(detections,
"YPOS", idet, ycen);
428 cpl_table_set(detections,
"XERR", idet, xerr);
429 cpl_table_set(detections,
"YERR", idet, yerr);
431 cpl_table_set(detections,
"XFWHM", idet, xw);
432 cpl_table_set(detections,
"YFWHM", idet, yw);
434 cpl_table_set(detections,
"FLUX", idet, flux);
436 if (cpl_errorstate_is_equal(state) && xw > 0 && yw > 0 &&
437 xcen >= 1 && xcen <= nx && ycen >= 1 && ycen <= ny) {
441 cpl_table_select_row(detections, idet);
443 cpl_table_erase_selected(detections);
444 cpl_apertures_delete(apertures);
446 cpl_msg_debug(__func__,
"%d of %d sources were recorded in the detections " 447 "table", (
int)cpl_table_get_nrow(detections), ndet);
500 cpl_ensure_code(aPixtable && aPixtable->
header && aWCSObj,
501 CPL_ERROR_NULL_INPUT);
502 cpl_ensure_code(aSigma > 0., CPL_ERROR_ILLEGAL_INPUT);
509 return cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
511 if (getenv(
"MUSE_DEBUG_WCS") && atoi(getenv(
"MUSE_DEBUG_WCS")) > 2) {
512 const char *fn =
"wcs__pixtable.fits";
513 cpl_msg_info(__func__,
"Saving pixel table as \"%s\"", fn);
518 cpl_boolean darcorrected = CPL_FALSE;
521 darcorrected = CPL_TRUE;
523 darcorrected = CPL_TRUE;
526 const char *message =
"Correction for differential atmospheric refraction " 527 "was not applied! Deriving astrometric correction " 528 "from such data is unlikely to give good results!";
529 cpl_msg_warning(__func__,
"%s", message);
530 cpl_error_set_message(__func__, CPL_ERROR_UNSUPPORTED_MODE,
"%s", message);
538 params->dlambda = 50.;
547 return cpl_error_set_message(__func__, cpl_error_get_code(),
548 "Failure while creating cube!");
550 aWCSObj->cube = cube;
551 if (getenv(
"MUSE_DEBUG_WCS") && atoi(getenv(
"MUSE_DEBUG_WCS")) >= 2) {
552 const char *fn =
"wcs__cube.fits";
553 cpl_msg_info(__func__,
"Saving cube as \"%s\"", fn);
558 int iplane, irefplane = cpl_imagelist_get_size(cube->
data) / 2;
563 unsigned int ilist = 0;
564 for (iplane = irefplane - 1; iplane <= irefplane + 1; iplane++) {
566 image->
data = cpl_image_duplicate(cpl_imagelist_get(cube->
data, iplane));
567 image->
dq = cpl_image_duplicate(cpl_imagelist_get(cube->
dq, iplane));
568 image->
stat = cpl_image_duplicate(cpl_imagelist_get(cube->
stat, iplane));
574 cpl_propertylist_copy_property_regexp(median->
header, cube->
header,
575 "^C...*3$|^CD3_.$", 1);
578 return cpl_error_set_message(__func__, cpl_error_get_code(),
579 "Failure while creating detection image!");
581 if (getenv(
"MUSE_DEBUG_WCS") && atoi(getenv(
"MUSE_DEBUG_WCS")) >= 2) {
582 const char *fn =
"wcs__image_median.fits";
583 cpl_msg_info(__func__,
"Saving median detection image as \"%s\"", fn);
587 cube->
recnames = cpl_array_new(2, CPL_TYPE_STRING);
594 cpl_array_set_string(cube->
recnames, 0,
"white");
602 if (!detections || (detections && cpl_table_get_nrow(detections) < 1)) {
603 return cpl_error_get_code();
606 aWCSObj->xcenter = cpl_image_get_size_x(median->
data) / 2.,
607 aWCSObj->ycenter = cpl_image_get_size_y(median->
data) / 2.;
611 cpl_msg_debug(__func__,
"image size: %d x %d --> center %f, %f",
612 (
int)cpl_image_get_size_x(median->
data),
613 (
int)cpl_image_get_size_y(median->
data),
614 aWCSObj->xcenter, aWCSObj->ycenter);
617 if (getenv(
"MUSE_DEBUG_WCS") && atoi(getenv(
"MUSE_DEBUG_WCS")) >= 2) {
618 const char *fn =
"wcs__detections.fits";
619 cpl_msg_info(__func__,
"Saving table of detections as \"%s\"", fn);
620 cpl_table_save(detections, NULL, NULL, fn, CPL_IO_CREATE);
623 aWCSObj->detected = detections;
624 return CPL_ERROR_NONE;
672 float aRadius,
float aFAccuracy,
int aIter,
float aThresh)
674 cpl_ensure_code(aWCSObj, CPL_ERROR_NULL_INPUT);
675 cpl_table *detected = aWCSObj->detected;
676 int ndet = cpl_table_get_nrow(detected),
677 nref = cpl_table_get_nrow(aReference);
678 cpl_ensure_code(ndet > 0 && nref > 0, CPL_ERROR_ILLEGAL_INPUT);
683 CPL_ERROR_BAD_FILE_FORMAT);
684 cpl_ensure_code(aRadius > 0.&& aFAccuracy > 0., CPL_ERROR_ILLEGAL_INPUT);
687 cpl_propertylist *order = cpl_propertylist_new();
688 cpl_propertylist_append_bool(order,
"FLUX", TRUE);
689 cpl_table_sort(detected, order);
690 cpl_propertylist_erase(order,
"FLUX");
691 cpl_propertylist_append_bool(order,
"mag", FALSE);
692 cpl_table_sort(aReference, order);
693 cpl_propertylist_delete(order);
694 if (getenv(
"MUSE_DEBUG_WCS") && atoi(getenv(
"MUSE_DEBUG_WCS")) >= 2) {
695 FILE *fp = fopen(
"wcs__detections.ascii",
"w");
696 fprintf(fp,
"%s: table of detected sources (sorted by flux):\n", __func__);
697 cpl_table_dump(detected, 0, 1000, fp);
699 fp = fopen(
"wcs__references.ascii",
"w");
700 fprintf(fp,
"%s: table of reference objects (sorted by flux):\n", __func__);
701 cpl_table_dump(aReference, 0, 1000, fp);
707 cpl_propertylist_append_double(wcsin,
"CRVAL1", aWCSObj->ra);
708 cpl_propertylist_append_double(wcsin,
"CRVAL2", aWCSObj->dec);
709 cpl_propertylist_update_double(wcsin,
"CRPIX1", aWCSObj->crpix1);
710 cpl_propertylist_update_double(wcsin,
"CRPIX2", aWCSObj->crpix2);
712 cpl_propertylist_append_int(wcsin,
"NAXIS", 2);
713 cpl_propertylist_append_int(wcsin,
"NAXIS1", aWCSObj->xcenter * 2.);
714 cpl_propertylist_append_int(wcsin,
"NAXIS2", aWCSObj->ycenter * 2.);
717 cpl_matrix *data = cpl_matrix_new(2, ndet),
718 *patt = cpl_matrix_new(2, nref);
720 for (i = 0; i < ndet; i++) {
721 cpl_matrix_set(data, 0, i, cpl_table_get(detected,
"XPOS", i, NULL));
722 cpl_matrix_set(data, 1, i, cpl_table_get(detected,
"YPOS", i, NULL));
728 for (i = 0; i < nref; i++) {
729 double ra = cpl_table_get(aReference,
"RA", i, NULL),
730 dec = cpl_table_get(aReference,
"DEC", i, NULL),
733 cpl_matrix_set(patt, 0, i, x);
734 cpl_matrix_set(patt, 1, i, y);
736 printf(
"conversion: %2d\t%.7f %.7f\t%6.2f %6.2f\n", i + 1, ra, dec, x, y);
741 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
742 printf(
"%s: data matrix:\n", __func__);
743 cpl_matrix_dump(data, stdout);
744 printf(
"%s: patt matrix:\n", __func__);
745 cpl_matrix_dump(patt, stdout);
752 double accuracy0 = sqrt(pow(cpl_table_get_column_mean(detected,
"XERR"), 2) +
753 pow(cpl_table_get_column_mean(detected,
"YERR"), 2));
756 double accuracy = accuracy0 * aFAccuracy,
759 cpl_array *aid = NULL;
760 cpl_boolean dupes = CPL_FALSE;
761 double xscale, yscale;
769 int ndata = ndet < USE_DATA ? ndet : USE_DATA,
770 npatt = nref < USE_PATT ? nref : USE_PATT;
771 cpl_array_delete(aid);
773 cpl_msg_debug(__func__,
"trying pattern matching with accuracy %g and " 774 "radius %g", accuracy, radius);
775 aid = cpl_ppm_match_points(data, ndata, accuracy,
777 0.1 , radius, NULL, NULL,
780 accuracy /= aid ? 1. : 1.5;
781 if (accuracy < FLT_EPSILON) {
785 cpl_errorstate state = cpl_errorstate_get();
786 nid = cpl_array_get_size(aid);
788 nid -= cpl_array_count_invalid(aid);
791 printf(
"aid (valid=%d):\n", nid);
792 cpl_array_dump(aid, 0, cpl_array_get_size(aid), stdout);
796 cpl_array_delete(aid);
797 cpl_matrix_delete(data);
798 cpl_matrix_delete(patt);
799 cpl_errorstate_set(state);
800 cpl_propertylist_delete(wcsin);
801 return cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
"None of " 802 "the %d detections could be identified with " 803 "the %d reference positions with radius %.3f " 804 "pix (starting value %.3f) and data accuracy " 805 "%.3e pix (intrinsic mean error %.3e)", ndet,
806 nref, radius, aRadius, accuracy, accuracy0);
812 cpl_msg_debug(__func__,
"%d %sidentified points [scale = %g, angle = %g; " 813 "used radius = %.3f pix (starting value %.3f), data accuracy " 814 "= %.3e pix (intrinsic mean error %.3e)]", nid,
815 dupes ?
"(non-unique!) " :
"unique ",
816 scale*1800.*(xscale+yscale), angle, radius, aRadius, accuracy,
820 cpl_matrix_delete(data);
821 cpl_matrix_delete(patt);
826 cpl_matrix *mpx = cpl_matrix_new(nid, 2),
827 *msky = cpl_matrix_new(nid, 2);
829 for (i = 0; i < cpl_array_get_size(aid); i++) {
830 if (!cpl_array_is_valid(aid, i)) {
833 int idata = cpl_array_get_int(aid, i, NULL);
834 cpl_matrix_set(mpx, iid, 0, cpl_table_get(detected,
"XPOS", idata, NULL));
835 cpl_matrix_set(mpx, iid, 1, cpl_table_get(detected,
"YPOS", idata, NULL));
836 cpl_matrix_set(msky, iid, 0, cpl_table_get(aReference,
"RA", i, NULL));
837 cpl_matrix_set(msky, iid, 1, cpl_table_get(aReference,
"DEC", i, NULL));
839 printf(
"matrices: %2d\t%.7f %.7f\t%6.2f %6.2f\n", iid + 1,
840 cpl_table_get(aReference,
"RA", i, NULL),
841 cpl_table_get(aReference,
"DEC", i, NULL),
842 cpl_table_get(detected,
"XPOS", idata, NULL),
843 cpl_table_get(detected,
"YPOS", idata, NULL));
849 cpl_matrix_dump(mpx, stdout);
851 cpl_matrix_dump(msky, stdout);
854 cpl_array_delete(aid);
857 cpl_propertylist *wcsout = NULL;
858 cpl_error_code rc = cpl_wcs_platesol(wcsin, msky, mpx, aIter, aThresh,
859 CPL_WCS_PLATESOL_6, CPL_WCS_MV_CRVAL,
862 cpl_propertylist_copy_property_regexp(wcsout, aWCSObj->cube->
header,
865 cpl_matrix_delete(mpx);
866 cpl_matrix_delete(msky);
867 cpl_propertylist_delete(wcsin);
868 if (rc != CPL_ERROR_NONE) {
869 cpl_msg_warning(__func__,
"Computing the WCS solution returned an error " 870 "(%d): %s", rc, cpl_error_get_message());
878 det = cd11 * cd22 - cd12 * cd21;
889 cpl_msg_info(__func__,
"astrometric calibration results: scales %f/%f " 890 "arcsec/spaxel, rotation %g/%g deg", xscale, yscale, xang, yang);
893 printf(
"%s: output propertylist (rc = %d):\n", __func__, rc);
895 cpl_propertylist_save(wcsout,
"astrometry_wcsout.fits", CPL_IO_CREATE);
896 system(
"fold -w 80 astrometry_wcsout.fits | grep -v \"^ \"");
897 remove(
"astrometry_wcsout.fits");
901 cpl_propertylist_update_int(wcsout, QC_ASTROMETRY_NSTARS, nid);
903 cpl_propertylist_update_float(wcsout, QC_ASTROMETRY_SCX, xscale);
904 cpl_propertylist_update_float(wcsout, QC_ASTROMETRY_SCY, yscale);
906 cpl_propertylist_update_float(wcsout, QC_ASTROMETRY_ANGX, xang);
907 cpl_propertylist_update_float(wcsout, QC_ASTROMETRY_ANGY, yang);
909 double medresx = cpl_propertylist_get_double(wcsout,
"CSYER1") * 3600.,
910 medresy = cpl_propertylist_get_double(wcsout,
"CSYER2") * 3600.;
911 cpl_propertylist_update_float(wcsout, QC_ASTROMETRY_RESX, medresx);
912 cpl_propertylist_update_float(wcsout, QC_ASTROMETRY_RESY, medresy);
915 cpl_propertylist_update_float(wcsout, MUSE_HDR_WCS_RADIUS, radius);
916 cpl_propertylist_set_comment(wcsout, MUSE_HDR_WCS_RADIUS,
917 MUSE_HDR_WCS_RADIUS_C);
918 cpl_propertylist_update_float(wcsout, MUSE_HDR_WCS_ACCURACY, accuracy);
919 cpl_propertylist_set_comment(wcsout, MUSE_HDR_WCS_ACCURACY,
920 MUSE_HDR_WCS_ACCURACY_C);
921 cpl_propertylist_update_float(wcsout, MUSE_HDR_WCS_FACCURACY,
922 accuracy / accuracy0);
923 cpl_propertylist_set_comment(wcsout, MUSE_HDR_WCS_FACCURACY,
924 MUSE_HDR_WCS_FACCURACY_C);
926 aWCSObj->wcs = wcsout;
990 cpl_table *aReference,
float aRadius,
991 float aFAccuracy,
int aIter,
float aRejSigma)
993 cpl_ensure_code(aWCSObj && aWCSObj->cube, CPL_ERROR_NULL_INPUT);
995 cpl_ensure_code(!strncmp(cpl_array_get_string(aWCSObj->cube->
recnames, 1),
997 CPL_ERROR_DATA_NOT_FOUND);
998 cpl_ensure_code(aDetSigma < 0., CPL_ERROR_ILLEGAL_INPUT);
1005 return cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
1007 int nref = cpl_table_get_nrow(aReference);
1008 cpl_ensure_code(nref > 0, CPL_ERROR_ILLEGAL_INPUT);
1010 == CPL_ERROR_NONE, CPL_ERROR_BAD_FILE_FORMAT);
1011 cpl_ensure_code(aRadius > 0.&& aFAccuracy > 0., CPL_ERROR_ILLEGAL_INPUT);
1013 float detsigma = fabsf(aDetSigma),
1018 cpl_table_delete(aWCSObj->detected);
1019 aWCSObj->detected = NULL;
1020 cpl_propertylist_delete(aWCSObj->wcs);
1021 aWCSObj->wcs = NULL;
1023 cpl_table *tres = cpl_table_new(lround((detsigma - lolimit) / 0.1) + 1);
1024 cpl_table_new_column(tres,
"detsigma", CPL_TYPE_FLOAT);
1025 cpl_table_set_column_format(tres,
"detsigma",
"%.3f");
1026 cpl_table_new_column(tres,
"ndet", CPL_TYPE_INT);
1027 cpl_table_new_column(tres,
"nid", CPL_TYPE_INT);
1028 cpl_table_new_column(tres,
"scalex", CPL_TYPE_FLOAT);
1029 cpl_table_set_column_format(tres,
"scalex",
"%.4f");
1030 cpl_table_new_column(tres,
"scaley", CPL_TYPE_FLOAT);
1031 cpl_table_set_column_format(tres,
"scaley",
"%.4f");
1032 cpl_table_new_column(tres,
"anglex", CPL_TYPE_FLOAT);
1033 cpl_table_set_column_format(tres,
"anglex",
"%.3f");
1034 cpl_table_new_column(tres,
"angley", CPL_TYPE_FLOAT);
1035 cpl_table_set_column_format(tres,
"angley",
"%.3f");
1036 cpl_table_new_column(tres,
"medresx", CPL_TYPE_FLOAT);
1037 cpl_table_set_column_format(tres,
"medresx",
"%.3f");
1038 cpl_table_new_column(tres,
"medresy", CPL_TYPE_FLOAT);
1039 cpl_table_set_column_format(tres,
"medresy",
"%.3f");
1042 cpl_error_code rc = CPL_ERROR_NONE;
1045 for (ds = detsigma, irow = 0; ds > lolimit; ds -= 0.1, irow++) {
1046 cpl_msg_debug(__func__,
"searching for solution with detection sigma %.3f", ds);
1047 cpl_msg_indent_more();
1050 cpl_msg_severity level = cpl_msg_get_level();
1051 cpl_msg_set_level(CPL_MSG_WARNING);
1055 cpl_table_set_float(tres,
"detsigma", irow, ds);
1056 cpl_table_set_int(tres,
"ndet", irow, cpl_table_get_nrow(aWCSObj->detected));
1059 cpl_errorstate state = cpl_errorstate_get();
1060 rc =
muse_wcs_solve(aWCSObj, aReference, aRadius, aFAccuracy, aIter,
1062 if (rc == CPL_ERROR_NONE && aWCSObj->wcs) {
1063 cpl_table_set_int(tres,
"nid", irow,
1064 cpl_propertylist_get_int(aWCSObj->wcs, QC_ASTROMETRY_NSTARS));
1065 cpl_table_set_float(tres,
"scalex", irow,
1066 cpl_propertylist_get_float(aWCSObj->wcs, QC_ASTROMETRY_SCX));
1067 cpl_table_set_float(tres,
"scaley", irow,
1068 cpl_propertylist_get_float(aWCSObj->wcs, QC_ASTROMETRY_SCY));
1069 cpl_table_set_float(tres,
"anglex", irow,
1070 cpl_propertylist_get_float(aWCSObj->wcs, QC_ASTROMETRY_ANGX));
1071 cpl_table_set_float(tres,
"angley", irow,
1072 cpl_propertylist_get_float(aWCSObj->wcs, QC_ASTROMETRY_ANGY));
1073 cpl_table_set_float(tres,
"medresx", irow,
1074 cpl_propertylist_get_float(aWCSObj->wcs, QC_ASTROMETRY_RESX));
1075 cpl_table_set_float(tres,
"medresy", irow,
1076 cpl_propertylist_get_float(aWCSObj->wcs, QC_ASTROMETRY_RESY));
1077 cpl_propertylist_delete(aWCSObj->wcs);
1078 aWCSObj->wcs = NULL;
1080 cpl_errorstate_set(state);
1082 cpl_table_delete(aWCSObj->detected);
1083 aWCSObj->detected = NULL;
1084 cpl_msg_set_level(level);
1085 cpl_msg_indent_less();
1088 cpl_boolean debug = getenv(
"MUSE_DEBUG_WCS") && atoi(getenv(
"MUSE_DEBUG_WCS")) >= 1;
1090 printf(
"%s: full table of results:\n", __func__);
1091 cpl_table_dump(tres, 0, 1000, stdout);
1097 ? kMuseSpaxelSizeX_NFM : kMuseSpaxelSizeY_WFM;
1098 cpl_msg_debug(__func__,
"pruning results +/-10%% away from expected spaxel " 1099 "scale of %.3f arcsec/pixel", scale);
1100 cpl_table_unselect_all(tres);
1101 cpl_table_or_selected_float(tres,
"scalex", CPL_GREATER_THAN, scale * 1.1);
1102 cpl_table_or_selected_float(tres,
"scalex", CPL_LESS_THAN, scale * 0.9);
1103 cpl_table_or_selected_float(tres,
"scaley", CPL_GREATER_THAN, scale * 1.1);
1104 cpl_table_or_selected_float(tres,
"scaley", CPL_LESS_THAN, scale * 0.9);
1105 cpl_table_or_selected_invalid(tres,
"nid");
1106 cpl_table_erase_selected(tres);
1108 printf(
"%s: pruned table of results:\n", __func__);
1109 cpl_table_dump(tres, 0, 1000, stdout);
1113 if (cpl_table_get_nrow(tres) < 1) {
1114 cpl_table_delete(tres);
1115 cpl_msg_error(__func__,
"No valid solution found in the range %.3f .. %.3f " 1116 "sigma", detsigma, lolimit);
1117 return cpl_error_set(__func__, CPL_ERROR_ILLEGAL_OUTPUT);
1124 cpl_table_cast_column(tres,
"nid",
"weight", CPL_TYPE_DOUBLE);
1125 cpl_table_set_column_format(tres,
"weight",
"%.5g");
1126 cpl_table_divide_scalar(tres,
"weight", 50.);
1127 cpl_table_divide_columns(tres,
"weight",
"medresx");
1128 cpl_table_multiply_scalar(tres,
"weight",
1129 cpl_table_get_column_min(tres,
"medresx"));
1130 cpl_table_divide_columns(tres,
"weight",
"medresy");
1131 cpl_table_multiply_scalar(tres,
"weight",
1132 cpl_table_get_column_min(tres,
"medresy"));
1133 cpl_propertylist *sort = cpl_propertylist_new();
1134 cpl_propertylist_append_bool(sort,
"weight", CPL_TRUE);
1135 cpl_propertylist_append_bool(sort,
"nid", CPL_TRUE);
1136 cpl_table_sort(tres, sort);
1137 cpl_propertylist_delete(sort);
1139 detsigma = cpl_table_get_float(tres,
"detsigma", 0, NULL);
1141 printf(
"%s: pruned and sorted table of results:\n", __func__);
1142 cpl_table_dump(tres, 0, 1000, stdout);
1143 printf(
"%s: ===> use the %.3f-sigma level\n", __func__, detsigma);
1146 cpl_table_delete(tres);
1150 rc =
muse_wcs_solve(aWCSObj, aReference, aRadius, aFAccuracy, aIter, aRejSigma);
1154 cpl_propertylist_update_float(aWCSObj->wcs, MUSE_HDR_WCS_DETSIGMA, detsigma);
1155 cpl_propertylist_set_comment(aWCSObj->wcs, MUSE_HDR_WCS_DETSIGMA,
1156 MUSE_HDR_WCS_DETSIGMA_C);
1176 cpl_propertylist *wcs = cpl_propertylist_new();
1180 cpl_propertylist_append_int(wcs,
"WCSAXES", 2);
1185 double smallvalue = FLT_MIN;
1186 const char *cpldesc = cpl_get_description(CPL_DESCRIPTION_DEFAULT);
1188 char *pcpldesc = strstr(cpldesc,
"WCSLIB = ");
1191 double wcslibversion = atof(pcpldesc);
1192 if (wcslibversion >= 4.23) {
1199 cpl_propertylist_append_double(wcs,
"CRPIX1", smallvalue);
1201 cpl_propertylist_append_double(wcs,
"CD1_1", -kMuseSpaxelSizeX_WFM / 3600);
1202 cpl_propertylist_append_string(wcs,
"CTYPE1",
"RA---TAN");
1203 cpl_propertylist_append_string(wcs,
"CUNIT1",
"deg");
1206 cpl_propertylist_append_double(wcs,
"CRPIX2", smallvalue);
1207 cpl_propertylist_append_double(wcs,
"CD2_2", kMuseSpaxelSizeY_WFM / 3600);
1208 cpl_propertylist_append_string(wcs,
"CTYPE2",
"DEC--TAN");
1209 cpl_propertylist_append_string(wcs,
"CUNIT2",
"deg");
1212 cpl_propertylist_append_double(wcs,
"CD1_2", 0.);
1213 cpl_propertylist_append_double(wcs,
"CD2_1", 0.);
1238 const cpl_propertylist *aCalHeader)
1240 cpl_ensure(aCalHeader && aExpHeader, CPL_ERROR_NULL_INPUT, NULL);
1243 cpl_propertylist *header = cpl_propertylist_duplicate(aCalHeader);
1248 xang, yang, xsc, ysc;
1251 cpl_msg_debug(__func__,
"WCS solution: scales %f / %f arcsec, angles %f / %f " 1252 "deg", xsc * 3600., ysc * 3600., xang, yang);
1254 cpl_matrix *pc = cpl_matrix_new(2, 2);
1259 cpl_matrix *pcinv = cpl_matrix_invert_create(pc);
1260 cpl_matrix_delete(pc);
1262 double cd11cor, cd12cor, cd21cor, cd22cor;
1264 cd11cor = xsc * cpl_matrix_get(pcinv, 0, 0);
1265 cd12cor = xsc * cpl_matrix_get(pcinv, 0, 1);
1266 cd21cor = ysc * cpl_matrix_get(pcinv, 1, 0);
1267 cd22cor = ysc * cpl_matrix_get(pcinv, 1, 1);
1268 cpl_matrix_delete(pcinv);
1270 cpl_msg_warning(__func__,
"CD matrix of astrometric solution could not " 1271 "be inverted! Assuming negligible zeropoint rotation.");
1278 double cd11 = cos(pa) * cd11cor - sin(pa) * cd21cor,
1279 cd12 = cos(pa) * cd12cor - sin(pa) * cd22cor,
1280 cd21 = sin(pa) * cd11cor + cos(pa) * cd21cor,
1281 cd22 = sin(pa) * cd12cor + cos(pa) * cd22cor;
1282 cpl_propertylist_update_double(header,
"CD1_1", cd11),
1283 cpl_propertylist_update_double(header,
"CD1_2", cd12),
1284 cpl_propertylist_update_double(header,
"CD2_1", cd21);
1285 cpl_propertylist_update_double(header,
"CD2_2", cd22),
1288 cpl_msg_debug(__func__,
"Updated CD matrix (%f deg field rotation): " 1289 "%e %e %e %e (scales %f / %f arcsec, angles %f / %f deg)",
1290 pa * CPL_MATH_DEG_RAD, cd11, cd12, cd21, cd22,
1291 xsc * 3600., ysc * 3600., xang, yang);
1330 cpl_ensure_code(nrow > 0 && aPixtable->
header && aWCS, CPL_ERROR_NULL_INPUT);
1332 CPL_ERROR_INCOMPATIBLE_INPUT);
1336 cpl_ensure_code(type1 && type2 && !strncmp(type1,
"RA---TAN", 9) &&
1337 !strncmp(type2,
"DEC--TAN", 9),
1338 CPL_ERROR_UNSUPPORTED_MODE);
1349 cpl_propertylist_erase_regexp(header,
"^CRVAL[0-9]+$|^L[OA][NT]POLE$", 0);
1358 cpl_errorstate prestate = cpl_errorstate_get();
1363 if (!cpl_errorstate_is_equal(prestate)) {
1364 cpl_errorstate_set(prestate);
1373 crpix1 = (xhi + xlo) / 2. + wcspix1,
1374 crpix2 = (yhi + ylo) / 2. + wcspix2;
1375 cpl_propertylist_update_double(header,
"CRPIX1", crpix1),
1376 cpl_propertylist_update_double(header,
"CRPIX2", crpix2),
1377 cpl_msg_debug(__func__,
"Using reference pixel %f/%f (limits in pixel table " 1378 "%f..%f/%f..%f, WCS correction %f,%f)", crpix1, crpix2,
1379 xlo, xhi, ylo, yhi, wcspix1, wcspix2);
1390 #pragma omp parallel for default(none) \ 1391 shared(cd11, cd12, cd21, cd22, crpix1, crpix2, nrow, xpos, ypos) 1392 for (n = 0; n < nrow; n++) {
1395 double x = cd11 * (xpos[n] - crpix1) + cd12 * (ypos[n] - crpix2),
1396 y = cd22 * (ypos[n] - crpix2) + cd21 * (xpos[n] - crpix1);
1404 double phi = atan2(x, -y),
1405 theta = atan(CPL_MATH_DEG_RAD / sqrt(x*x + y*y));
1407 phi += CPL_MATH_2PI;
1413 ypos[n] = theta - CPL_MATH_PI_2;
1423 cpl_propertylist_copy_property_regexp(aPixtable->
header, header,
1425 cpl_propertylist_delete(header);
1431 MUSE_HDR_PT_WCS_COMMENT_PROJ);
1432 return CPL_ERROR_NONE;
1470 cpl_ensure_code(nrow > 0 && aPixtable->
header, CPL_ERROR_NULL_INPUT);
1472 CPL_ERROR_INCOMPATIBLE_INPUT);
1476 cpl_ensure_code(type1 && type2 && !strncmp(type1,
"RA---TAN", 9) &&
1477 !strncmp(type2,
"DEC--TAN", 9),
1478 CPL_ERROR_UNSUPPORTED_MODE);
1480 cpl_msg_info(__func__,
"Adapting WCS to RA/DEC=%f/%f deg", aRA, aDEC);
1490 double dp = aDEC / CPL_MATH_DEG_RAD;
1492 #pragma omp parallel for default(none) \ 1493 shared(aDEC, dp, nrow, xpos, ypos) 1494 for (n = 0; n < nrow; n++) {
1500 double phi = xpos[n],
1501 theta = ypos[n] + CPL_MATH_PI_2,
1502 ra = atan2(cos(theta) * sin(phi),
1503 sin(theta) * cos(dp) + cos(theta) * sin(dp) * cos(phi))
1505 dec = asin(sin(theta) * sin(dp) - cos(theta) * cos(dp) * cos(phi))
1513 ypos[n] = dec - aDEC;
1521 cpl_propertylist_update_double(aPixtable->
header,
"CRVAL1", aRA);
1522 cpl_propertylist_update_double(aPixtable->
header,
"CRVAL2", aDEC);
1530 MUSE_HDR_PT_WCS_COMMENT_POSI);
1531 return CPL_ERROR_NONE;
1560 double *aRA,
double *aDEC)
1562 cpl_ensure_code(aHeader && aRA && aDEC, CPL_ERROR_NULL_INPUT);
1565 cpl_ensure_code(type1 && type2 && !strncmp(type1,
"RA---TAN", 9) &&
1566 !strncmp(type2,
"DEC--TAN", 9),
1567 CPL_ERROR_UNSUPPORTED_MODE);
1573 return CPL_ERROR_NONE;
1604 double *aX,
double *aY)
1606 cpl_ensure_code(aHeader && aX && aY, CPL_ERROR_NULL_INPUT);
1610 cpl_ensure_code(type1 && type2 && !strncmp(type1,
"RA---TAN", 9) &&
1611 !strncmp(type2,
"DEC--TAN", 9),
1612 CPL_ERROR_UNSUPPORTED_MODE);
1615 if (wcs->
cddet == 0.) {
1617 cpl_error_set(__func__, CPL_ERROR_SINGULAR_MATRIX);
1619 return CPL_ERROR_SINGULAR_MATRIX;
1621 wcs->crval1 /= CPL_MATH_DEG_RAD;
1622 wcs->
crval2 /= CPL_MATH_DEG_RAD;
1624 aDEC / CPL_MATH_DEG_RAD, aX, aY);
1627 return CPL_ERROR_NONE;
1659 double aDEC,
double *aX,
double *aY)
1661 cpl_ensure_code(aHeader && aX && aY, CPL_ERROR_NULL_INPUT);
1665 cpl_ensure_code(type1 && type2 && !strncmp(type1,
"RA---TAN", 9) &&
1666 !strncmp(type2,
"DEC--TAN", 9),
1667 CPL_ERROR_UNSUPPORTED_MODE);
1670 double a = aRA / CPL_MATH_DEG_RAD,
1671 d = aDEC / CPL_MATH_DEG_RAD,
1675 phi = atan2(-cos(d) * sin(a - ap),
1676 sin(d) * cos(dp) - cos(d) * sin(dp) * cos(a-ap))
1677 + 180 / CPL_MATH_DEG_RAD,
1678 theta = asin(sin(d) * sin(dp) + cos(d) * cos(dp) * cos(a-ap)),
1679 R_theta = CPL_MATH_DEG_RAD / tan(theta);
1681 *aX = R_theta * sin(phi),
1682 *aY = -R_theta * cos(phi);
1684 return CPL_ERROR_NONE;
1707 double *aXOut,
double *aYOut)
1709 cpl_ensure_code(aHeader && aXOut && aYOut, CPL_ERROR_NULL_INPUT);
1715 return CPL_ERROR_NONE;
1740 double *aXOut,
double *aYOut)
1742 cpl_ensure_code(aHeader && aXOut && aYOut, CPL_ERROR_NULL_INPUT);
1745 if (wcs->
cddet == 0.) {
1746 *aXOut = *aYOut = NAN;
1747 cpl_error_set(__func__, CPL_ERROR_SINGULAR_MATRIX);
1749 return CPL_ERROR_SINGULAR_MATRIX;
1754 return CPL_ERROR_NONE;
1780 cpl_ensure_code(aHeader && aXAngle && aYAngle, CPL_ERROR_NULL_INPUT);
1782 cpl_errorstate prestate = cpl_errorstate_get();
1787 det = cd11 * cd22 - cd12 * cd21;
1788 cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
1793 if (cd12 == 0. && cd21 == 0.) {
1796 return CPL_ERROR_NONE;
1799 *aXAngle = atan2(cd12, cd11) * CPL_MATH_DEG_RAD;
1800 *aYAngle = atan2(-cd21, cd22) * CPL_MATH_DEG_RAD;
1801 return CPL_ERROR_NONE;
1827 cpl_ensure_code(aHeader && aXScale && aYScale, CPL_ERROR_NULL_INPUT);
1829 cpl_errorstate prestate = cpl_errorstate_get();
1834 det = cd11 * cd22 - cd12 * cd21;
1835 cpl_ensure_code(cpl_errorstate_is_equal(prestate), cpl_error_get_code());
1841 if (cd12 == 0. && cd21 == 0.) {
1844 return CPL_ERROR_NONE;
1846 *aXScale = sqrt(cd11*cd11 + cd12*cd12);
1847 *aYScale = sqrt(cd22*cd22 + cd21*cd21);
1848 return CPL_ERROR_NONE;
1874 wcs->cd11 = wcs->
cd22 = wcs->
cddet = 1.;
1878 cpl_errorstate prestate = cpl_errorstate_get();
1883 if (!cpl_errorstate_is_equal(prestate)) {
1886 cpl_errorstate_set(prestate);
1889 prestate = cpl_errorstate_get();
1894 if (!cpl_errorstate_is_equal(prestate) &&
1895 wcs->cd11 == 0. && wcs->cd12 == 0. && wcs->cd21 == 0. && wcs->
cd22 == 0.) {
1898 wcs->cd11 = wcs->
cd22 = wcs->
cddet = 1.;
1899 cpl_errorstate_set(prestate);
1901 wcs->
cddet = wcs->cd11 * wcs->
cd22 - wcs->cd12 * wcs->cd21;
1902 if (wcs->
cddet == 0.) {
1903 cpl_error_set(__func__, CPL_ERROR_SINGULAR_MATRIX);
1907 if (getenv(
"MUSE_DEBUG_WCS") && atoi(getenv(
"MUSE_DEBUG_WCS")) > 0) {
1908 cpl_msg_debug(__func__,
"wcs: axis1 = { %f %f %e }, axis2 = { %f %f %e }, " 1909 "crossterms = { %e %e }, det = %e",
1910 wcs->crpix1, wcs->crval1, wcs->cd11,
1912 wcs->cd12, wcs->cd21, wcs->
cddet);
#define MUSE_PIXTABLE_XPOS
Structure definition of a MUSE datacube.
#define MUSE_HDR_PT_PREDAR_YLO
Structure definition for a collection of muse_images.
cpl_error_code muse_wcs_get_scales(cpl_propertylist *aHeader, double *aXScale, double *aYScale)
Compute the spatial scales (in degrees) from the FITS header WCS.
cpl_error_code muse_wcs_pixel_from_projplane(cpl_propertylist *aHeader, double aX, double aY, double *aXOut, double *aYOut)
Convert from projection plane coordinates to pixel coordinates.
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
double muse_pfits_get_cd(const cpl_propertylist *aHeaders, unsigned int aAxisI, unsigned int aAxisJ)
find out the WCS coordinate at the reference point
#define MUSE_HDR_PT_XLO
FITS header keyword contains the lower limit of the data in x-direction.
double muse_pfits_get_crval(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS coordinate at the reference point
A structure containing a spatial two-axis WCS.
double muse_pfits_get_ra(const cpl_propertylist *aHeaders)
find out the right ascension
const muse_cpltable_def muse_wcs_detections_def[]
Definition of the table structure for the astrometric field detections.
cpl_image * data
the data extension
cpl_size muse_pixtable_get_nrow(const muse_pixtable *aPixtable)
get the number of rows within the pixel table
#define MUSE_WCS_DETIMAGE_EXTNAME
name for special astrometry detection image
muse_image * muse_combine_median_create(muse_imagelist *aImages)
Median combine a list of input images.
static void muse_wcs_pixel_from_projplane_fast(muse_wcs *aWCS, double aX, double aY, double *aXOut, double *aYOut)
Convert from projection plane coordinates to pixel coordinates.
muse_datacube * muse_resampling_cube(muse_pixtable *aPixtable, muse_resampling_params *aParams, muse_pixgrid **aGrid)
Resample a pixel table onto a regular grid structure representing a FITS NAXIS=3 datacube.
cpl_image * stat
the statistics extension
cpl_error_code muse_wcs_projplane_from_celestial(cpl_propertylist *aHeader, double aRA, double aDEC, double *aX, double *aY)
Convert from celestial spherical coordinates to projection plane coordinates.
#define MUSE_HDR_PT_WCS_PROJ
void muse_datacube_delete(muse_datacube *aCube)
Deallocate memory associated to a muse_datacube object.
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
WCS object to store data needed while computing the astrometric solution.
Structure definition of MUSE three extension FITS file.
cpl_array * recnames
the reconstructed image filter names
cpl_table * table
The pixel table.
cpl_propertylist * header
the FITS header
cpl_boolean muse_cplarray_has_duplicate(const cpl_array *aArray)
Check, if an array contains duplicate values.
cpl_error_code muse_pixtable_reset_dq(muse_pixtable *aPixtable, unsigned int aDQ)
Reset a given bad pixel status (DQ flag) for all pixels in the table.
cpl_error_code muse_cpltable_check(const cpl_table *aTable, const muse_cpltable_def *aDef)
Check whether the table contains the fields of the definition.
cpl_error_code muse_datacube_save(muse_datacube *aCube, const char *aFilename)
Save the three cube extensions and the FITS headers of a MUSE datacube to a file. ...
cpl_error_code muse_wcs_project_tan(muse_pixtable *aPixtable, const cpl_propertylist *aWCS)
Carry out a gnomonic projection of a pixel table into native spherical coordinates.
cpl_table * muse_wcs_centroid_stars(muse_image *aImage, float aSigma, muse_wcs_centroid_type aCentroid)
Detect and centroid stars on an image of an astrometric exposure.
muse_resampling_crstats_type crtype
cpl_image * dq
the data quality extension
cpl_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
double muse_pfits_get_crpix(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS reference point
const muse_cpltable_def muse_wcs_reference_def[]
Definition of the table structure for the astrometric reference sources.
muse_wcs * muse_wcs_new(cpl_propertylist *aHeader)
Create a new WCS structure from a given FITS header.
double muse_pfits_get_fwhm_end(const cpl_propertylist *aHeaders)
find out the ambient seeing at end of exposure (in arcsec)
muse_wcs_centroid_type
Type of centroiding algorithm to use.
#define MUSE_HDR_PT_PREDAR_YHI
Structure definition of MUSE pixel table.
#define MUSE_WCS_KEYS
regular expression for WCS properties
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
muse_pixtable_wcs muse_pixtable_wcs_check(muse_pixtable *aPixtable)
Check the state of the world coordinate system of a pixel table.
cpl_error_code muse_wcs_celestial_from_pixel(cpl_propertylist *aHeader, double aX, double aY, double *aRA, double *aDEC)
Convert from pixel coordinates to celestial spherical coordinates.
#define MUSE_HDR_PT_YLO
FITS header keyword contains the lower limit of the data in y-direction.
cpl_error_code muse_utils_fit_moffat_2d(const cpl_matrix *aPositions, const cpl_vector *aValues, const cpl_vector *aErrors, cpl_array *aParams, cpl_array *aPErrors, const cpl_array *aPFlags, double *aRMS, double *aRedChisq)
Fit a 2D Moffat function to a given set of data.
static void muse_wcs_pixel_from_celestial_fast(muse_wcs *aWCS, double aRA, double aDEC, double *aX, double *aY)
Convert from celestial spherical coordinates to pixel coordinates.
static void muse_wcs_celestial_from_pixel_fast(muse_wcs *aWCS, double aX, double aY, double *aRA, double *aDEC)
Convert from pixel coordinates to celestial spherical coordinates.
muse_resampling_params * muse_resampling_params_new(muse_resampling_type aMethod)
Create the resampling parameters structure.
cpl_error_code muse_wcs_solve(muse_wcs_object *aWCSObj, cpl_table *aReference, float aRadius, float aFAccuracy, int aIter, float aThresh)
Find the world coordinate solution for a given field using coordinates of detected sources and coordi...
muse_wcs_object * muse_wcs_object_new(void)
Allocate memory for a new muse_wcs_object object.
#define MUSE_HDR_PT_PREDAR_XLO
cpl_error_code muse_wcs_projplane_from_pixel(cpl_propertylist *aHeader, double aX, double aY, double *aXOut, double *aYOut)
Convert from pixel coordinates to projection plane coordinates.
double muse_pfits_get_fwhm_start(const cpl_propertylist *aHeaders)
find out the ambient seeing at start of exposure (in arcsec)
muse_table * muse_table_load_filter(muse_processing *aProcessing, const char *aFilterName)
Load a table for a given filter name.
cpl_imagelist * data
the cube containing the actual data values
cpl_error_code muse_wcs_pixel_from_celestial(cpl_propertylist *aHeader, double aRA, double aDEC, double *aX, double *aY)
Convert from celestial spherical coordinates to pixel coordinates.
double muse_pfits_get_dec(const cpl_propertylist *aHeaders)
find out the declination
#define MUSE_HDR_PT_PREDAR_XHI
Structure to store a table together with a property list.
void muse_table_delete(muse_table *aTable)
Deallocate memory associated to a muse_table object.
cpl_imagelist * dq
the optional cube containing the bad pixel status
const char * muse_pfits_get_ctype(const cpl_propertylist *aHeaders, unsigned int aAxis)
find out the WCS axis type string
cpl_error_code muse_pixtable_save(muse_pixtable *aPixtable, const char *aFilename)
Save a MUSE pixel table to a file on disk.
cpl_propertylist * header
the FITS header
double muse_astro_posangle(const cpl_propertylist *aHeader)
Derive the position angle of an observation from information in a FITS header.
cpl_error_code muse_wcs_optimize_solution(muse_wcs_object *aWCSObj, float aDetSigma, muse_wcs_centroid_type aCentroid, cpl_table *aReference, float aRadius, float aFAccuracy, int aIter, float aRejSigma)
Find an optimal astrometry solution given a detection image.
#define MUSE_HDR_PT_WCS_POSI
cpl_error_code muse_image_save(muse_image *aImage, const char *aFilename)
Save the three image extensions and the FITS headers of a MUSE image to a file.
muse_imagelist * muse_imagelist_new(void)
Create a new (empty) MUSE image list.
static void muse_wcs_projplane_from_pixel_fast(muse_wcs *aWCS, double aX, double aY, double *aXOut, double *aYOut)
Convert from pixel coordinates to projection plane coordinates.
#define MUSE_HDR_PT_DAR_NAME
cpl_propertylist * muse_wcs_apply_cd(const cpl_propertylist *aExpHeader, const cpl_propertylist *aCalHeader)
Apply the CDi_j matrix of an astrometric solution to an observation.
cpl_error_code muse_utils_image_get_centroid_window(cpl_image *aImage, int aX1, int aY1, int aX2, int aY2, double *aX, double *aY, muse_utils_centroid_type aBgType)
Compute centroid over an image window, optionally marginalizing over the background.
Definition of a cpl table structure.
void muse_resampling_params_delete(muse_resampling_params *aParams)
Delete a resampling parameters structure.
cpl_error_code muse_wcs_get_angles(cpl_propertylist *aHeader, double *aXAngle, double *aYAngle)
Compute the rotation angles (in degrees) from the FITS header WCS.
muse_image * muse_datacube_collapse(muse_datacube *aCube, const muse_table *aFilter)
Integrate a FITS NAXIS=3 datacube along the wavelength direction.
void muse_wcs_object_delete(muse_wcs_object *aWCSObj)
Deallocate memory associated to a muse_wcs_object.
#define MUSE_HDR_PT_DAR_CORR
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
cpl_error_code muse_wcs_position_celestial(muse_pixtable *aPixtable, double aRA, double aDEC)
Convert native to celestial spherical coordinates in a pixel table.
#define MUSE_PIXTABLE_YPOS
#define MUSE_HDR_PT_YHI
FITS header keyword contains the upper limit of the data in y-direction.
cpl_error_code muse_imagelist_set(muse_imagelist *aList, muse_image *aImage, unsigned int aIdx)
Set the muse_image of given list index.
cpl_error_code muse_pixtable_compute_limits(muse_pixtable *aPixtable)
(Re-)Compute the limits of the coordinate columns of a pixel table.
int muse_quality_image_reject_using_dq(cpl_image *aData, cpl_image *aDQ, cpl_image *aStat)
Reject pixels of one or two images on a DQ image.
muse_ins_mode muse_pfits_get_mode(const cpl_propertylist *aHeaders)
find out the observation mode
muse_imagelist * recimages
the reconstructed image data
cpl_error_code muse_wcs_locate_sources(muse_pixtable *aPixtable, float aSigma, muse_wcs_centroid_type aCentroid, muse_wcs_object *aWCSObj)
Determine the centers of stars on an astrometric exposure.
cpl_imagelist * stat
the cube containing the data variance
cpl_propertylist * header
The FITS header.
#define MUSE_HDR_PT_XHI
FITS header keyword contains the upper limit of the data in x-ion.
cpl_propertylist * muse_wcs_create_default(void)
Create FITS headers containing a default (relative) WCS.