33 #include "muse_pixtable.h"
34 #include "muse_instrument.h"
36 #include "muse_cplwrappers.h"
38 #include "muse_mask.h"
39 #include "muse_pfits.h"
40 #include "muse_quality.h"
41 #include "muse_tracing.h"
42 #include "muse_wavecalib.h"
44 #include "muse_utils.h"
50 #define CREATE_MINIMAL_PIXTABLE 0
51 #define PIXTABLE_CREATE_CCDSIZED 1
52 #define DEBUG_PIXTABLE_CREATION 0
53 #define DEBUG_PIXTABLE_FEW_SLICES 0
99 #define MUSE_ORIGIN_SHIFT_XSLICE 24
100 #define MUSE_ORIGIN_SHIFT_YPIX 11
101 #define MUSE_ORIGIN_SHIFT_IFU 6
105 #define MUSE_ORIGIN_SLICE_SAFETY_OFFSET -20
109 static inline uint32_t
110 muse_pixtable_origin_encode_fast(
unsigned int aX,
unsigned int aY,
112 unsigned short aSlice,
unsigned int aOffset)
114 return ((aX - aOffset) << MUSE_ORIGIN_SHIFT_XSLICE)
115 | (aY << MUSE_ORIGIN_SHIFT_YPIX)
116 | (aIFU << MUSE_ORIGIN_SHIFT_IFU)
121 static inline unsigned int
122 muse_pixtable_origin_get_x_fast(uint32_t aOrigin, uint32_t aOffset)
124 return ((aOrigin >> MUSE_ORIGIN_SHIFT_XSLICE) & 0x7f) + aOffset;
128 static inline unsigned int
129 muse_pixtable_origin_get_y_fast(uint32_t aOrigin)
131 return (aOrigin >> MUSE_ORIGIN_SHIFT_YPIX) & 0x1fff;
135 static inline unsigned short
136 muse_pixtable_origin_get_ifu_fast(uint32_t aOrigin)
138 return (aOrigin >> MUSE_ORIGIN_SHIFT_IFU) & 0x1f;
142 static inline unsigned short
143 muse_pixtable_origin_get_slice_fast(uint32_t aOrigin)
145 return aOrigin & 0x3f;
168 unsigned short aSlice,
unsigned int aOffset)
173 cpl_ensure(aX < 8192 && aX > 0 && aY < 8192 && aY > 0 &&
174 aIFU <= kMuseNumIFUs && aIFU >= 1 &&
175 aSlice <= kMuseSlicesPerCCD && aSlice >= 1 && aOffset < 8192,
176 CPL_ERROR_ILLEGAL_INPUT, 0);
179 cpl_msg_debug(__func__,
"origin (%d, %d, %d, %d, %d) = 0x%x",
180 aX, aY, aIFU, aSlice, aOffset,
181 ((aX - aOffset) << MUSE_ORIGIN_SHIFT_XSLICE)
182 | (aY << MUSE_ORIGIN_SHIFT_YPIX)
183 | (aIFU << MUSE_ORIGIN_SHIFT_IFU)
188 return muse_pixtable_origin_encode_fast(aX, aY, aIFU, aSlice, aOffset);
214 unsigned short slice = muse_pixtable_origin_get_slice_fast(aOrigin),
215 ifu = muse_pixtable_origin_get_ifu_fast(aOrigin);
216 cpl_errorstate prestate = cpl_errorstate_get();
218 if (!cpl_errorstate_is_equal(prestate)) {
219 cpl_errorstate_set(prestate);
223 x = muse_pixtable_origin_get_x_fast(aOrigin, offset);
225 if (x > 8191 || x < 1 || !cpl_errorstate_is_equal(prestate)) {
226 cpl_msg_error(__func__,
"aOrigin=%#x x=%d (%d %d %d), %s",
227 aOrigin, x, slice, ifu, offset, cpl_error_get_message());
230 cpl_ensure(x <= 8191 && x >= 1 && cpl_errorstate_is_equal(prestate),
231 CPL_ERROR_ILLEGAL_OUTPUT, 0);
247 unsigned int y = muse_pixtable_origin_get_y_fast(aOrigin);
249 if (y > 8191 || y < 1) {
250 cpl_msg_error(__func__,
"aOrigin=%#x y=%d", aOrigin, y);
253 cpl_ensure(y <= 8191 && y >= 1, CPL_ERROR_ILLEGAL_OUTPUT, 0);
269 unsigned short ifu = muse_pixtable_origin_get_ifu_fast(aOrigin);
271 if (ifu > kMuseNumIFUs || ifu < 1) {
272 cpl_msg_error(__func__,
"aOrigin=%#x ifu=%d", aOrigin, ifu);
275 cpl_ensure(ifu <= kMuseNumIFUs && ifu >= 1, CPL_ERROR_ILLEGAL_OUTPUT, 0);
291 unsigned short slice = muse_pixtable_origin_get_slice_fast(aOrigin);
293 if (slice > kMuseSlicesPerCCD || slice < 1) {
294 cpl_msg_error(__func__,
"aOrigin=%#x slice=%d", aOrigin, slice);
297 cpl_ensure(slice <= kMuseSlicesPerCCD && slice >= 1,
298 CPL_ERROR_ILLEGAL_OUTPUT, 0);
320 cpl_polynomial *aLTrace,
321 unsigned short aIFU,
unsigned short aSlice)
323 cpl_ensure(aPixtable && aPixtable->
header, CPL_ERROR_NULL_INPUT, 0);
324 cpl_errorstate prestate = cpl_errorstate_get();
325 unsigned int offset = floor(cpl_polynomial_eval_1d(aLTrace, 1, NULL))
326 + MUSE_ORIGIN_SLICE_SAFETY_OFFSET;
327 cpl_ensure(cpl_errorstate_is_equal(prestate), cpl_error_get_code(), 0);
331 cpl_propertylist_update_int(aPixtable->
header, keyword, offset);
332 cpl_propertylist_set_comment(aPixtable->
header, keyword,
333 MUSE_HDR_PT_IFU_SLICE_OFFSET_COMMENT);
355 unsigned short aIFU,
unsigned short aSlice)
357 cpl_ensure(aPixtable && aPixtable->
header, CPL_ERROR_NULL_INPUT, 0);
360 cpl_errorstate prestate = cpl_errorstate_get();
361 unsigned int offset = cpl_propertylist_get_int(aPixtable->
header, keyword);
364 if (offset > 8191 || offset < 1) {
365 cpl_msg_error(__func__,
"aIFU=%d aSlice=%d offset=%d",
366 aIFU, aSlice, offset);
369 cpl_ensure(offset <= 8191 && offset >= 1 && cpl_errorstate_is_equal(prestate),
370 CPL_ERROR_ILLEGAL_OUTPUT, 0);
399 cpl_ensure_code(aOut && aOut->
header, CPL_ERROR_NULL_INPUT);
400 cpl_propertylist *dest = aOut->
header,
402 if (aFrom && aFrom->
header) {
405 char keyword[KEYWORD_LENGTH];
406 unsigned short nifu, nslice;
407 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
408 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
412 cpl_errorstate prestate = cpl_errorstate_get();
413 unsigned int offset = cpl_propertylist_get_int(from, keyword);
414 if (!cpl_errorstate_is_equal(prestate)) {
416 cpl_errorstate_set(prestate);
420 cpl_propertylist_erase(from, keyword);
424 cpl_propertylist_update_int(dest, keyword, offset);
425 cpl_propertylist_set_comment(dest, keyword,
426 MUSE_HDR_PT_IFU_SLICE_OFFSET_COMMENT);
430 return CPL_ERROR_NONE;
452 cpl_ensure(aPixtable && aPixtable->
header, CPL_ERROR_NULL_INPUT, 0);
454 CPL_ERROR_ILLEGAL_INPUT, 0);
456 char keyword[KEYWORD_LENGTH];
457 unsigned int exposure = 0;
458 cpl_size lo = 0, hi = 0;
460 cpl_errorstate prestate = cpl_errorstate_get();
462 lo = cpl_propertylist_get_long_long(aPixtable->
header, keyword);
464 hi = cpl_propertylist_get_long_long(aPixtable->
header, keyword);
465 if (!cpl_errorstate_is_equal(prestate)) {
472 cpl_errorstate_set(prestate);
476 cpl_ensure(lo <= aRow && hi >= aRow, CPL_ERROR_ILLEGAL_OUTPUT, 0);
502 { MUSE_PIXTABLE_XPOS, CPL_TYPE_FLOAT,
"pix",
"%7.2f",
503 "relative x-pixel position in the output datacube", CPL_TRUE},
504 { MUSE_PIXTABLE_YPOS, CPL_TYPE_FLOAT,
"pix",
"%7.2f",
505 "relative y-pixel position in the output datacube", CPL_TRUE},
506 { MUSE_PIXTABLE_LAMBDA, CPL_TYPE_FLOAT,
"Angstrom",
"%8.2f",
507 "wavelength of this pixel", CPL_TRUE},
508 { MUSE_PIXTABLE_DATA, CPL_TYPE_FLOAT,
"count",
"%e",
509 "data value in this pixel", CPL_TRUE},
510 { MUSE_PIXTABLE_DQ, CPL_TYPE_INT, NULL,
"%#x",
511 "Euro3D bad pixel status of this pixel", CPL_TRUE},
512 { MUSE_PIXTABLE_STAT, CPL_TYPE_FLOAT,
"count**2",
"%e",
513 "data variance of this pixel", CPL_TRUE},
514 { MUSE_PIXTABLE_ORIGIN, CPL_TYPE_INT, NULL,
"0x%08x",
515 "encoded value of IFU and slice number, as well as x and y "
516 "position in the raw (trimmed) data", CPL_TRUE},
517 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
569 cpl_table *aGeoTable)
571 cpl_ensure(aImage && aWave && aTrace, CPL_ERROR_NULL_INPUT, NULL);
574 cpl_ensure(ifu >= 1 && ifu <= kMuseNumIFUs, CPL_ERROR_DATA_NOT_FOUND, NULL);
577 if (!cpl_propertylist_has(aImage->
header,
"BUNIT")) {
578 const char *msg =
"Input data does not contain a data unit (\"BUNIT\"), "
580 cpl_msg_error(__func__,
"%s", msg);
581 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
"%s", msg);
584 const char *unit = cpl_propertylist_get_string(aImage->
header,
"BUNIT");
585 if (strncmp(unit,
"count", 6)) {
586 char *msg = cpl_sprintf(
"Input data is not in \"count\" units but in \"%s\""
587 ", not suitable for a pixel table!", unit);
588 cpl_msg_error(__func__,
"%s", msg);
589 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
"%s", msg);
597 int xsize = cpl_image_get_size_x(aImage->
data),
598 ysize = cpl_image_get_size_y(aImage->
data),
599 #if PIXTABLE_CREATE_CCDSIZED
602 isize = xsize * ysize;
606 isize = ysize * kMuseSlicesPerCCD * kMuseSliceHiLikelyWidth;
612 pt->
header = cpl_propertylist_duplicate(aImage->
header);
613 cpl_propertylist_erase_regexp(pt->
header,
614 "^SIMPLE$|^BITPIX$|^NAXIS|^EXTEND$|^XTENSION$|"
615 "^DATASUM$|^DATAMIN$|^DATAMAX$|^DATAMD5$|"
616 "^PCOUNT$|^GCOUNT$|^HDUVERS$|^BLANK$|"
617 "^BZERO$|^BSCALE$|^BUNIT$|^CHECKSUM$|^INHERIT$|"
618 MUSE_HDR_OVSC_REGEXP
"|"MUSE_WCS_KEYS, 0);
620 aGeoTable ? MUSE_PIXTABLE_STRING_FULL
621 : MUSE_PIXTABLE_STRING_SIMPLE);
623 aGeoTable ? MUSE_PIXTABLE_COMMENT_FULL
624 : MUSE_PIXTABLE_COMMENT_SIMPLE);
629 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_XPOS, 0, isize, 0);
630 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_YPOS, 0, isize, 0);
631 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_LAMBDA, 0, isize, 0);
632 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_DATA, 0, isize, 0);
633 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_STAT, 0, isize, 0);
634 cpl_table_fill_column_window_int(pt->
table, MUSE_PIXTABLE_DQ, 0, isize, 0);
635 cpl_table_fill_column_window_int(pt->
table, MUSE_PIXTABLE_ORIGIN, 0, isize, 0);
638 float *cdata_xpos = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_XPOS),
639 *cdata_ypos = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_YPOS),
640 *cdata_lambda = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_LAMBDA),
641 *cdata_data = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_DATA),
642 *cdata_stat = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_STAT);
643 int *cdata_dq = cpl_table_get_data_int(pt->
table, MUSE_PIXTABLE_DQ);
644 uint32_t *cdata_origin = (uint32_t *)cpl_table_get_data_int(pt->
table,
645 MUSE_PIXTABLE_ORIGIN);
648 const float *pixdata = cpl_image_get_data_float_const(aImage->
data),
649 *pixstat = cpl_image_get_data_float_const(aImage->
stat);
650 const int *pixdq = cpl_image_get_data_int_const(aImage->
dq);
653 unsigned short wavexorder, waveyorder;
655 cpl_msg_info(__func__,
"Creating pixel table for IFU %hhu, using order %d for "
656 "trace solution and orders %hu/%hu for wavelength solution", ifu,
660 cpl_table *geopos = NULL;
661 double *slice_x = NULL, *slice_y = NULL, *slice_angle = NULL,
665 slice_x = cpl_table_get_data_double(geopos, MUSE_GEOTABLE_X);
666 slice_y = cpl_table_get_data_double(geopos, MUSE_GEOTABLE_Y);
668 if (!geopos || !slice_x || !slice_y) {
670 ? cpl_sprintf(
"Geometry table is missing data for IFU %hhu!", ifu)
671 : cpl_sprintf(
"Geometry table is missing column%s%s%s!",
672 !slice_x && !slice_y ?
"s" :
"",
673 slice_x ?
"" :
" \""MUSE_GEOTABLE_X
"\"",
674 slice_y ?
"" :
" \""MUSE_GEOTABLE_Y
"\"");
675 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
"%s", msg);
676 cpl_msg_error(__func__,
"%s", msg);
678 cpl_table_delete(geopos);
684 cpl_errorstate prestate = cpl_errorstate_get();
685 slice_angle = cpl_table_get_data_double(geopos, MUSE_GEOTABLE_ANGLE);
686 slice_width = cpl_table_get_data_double(geopos, MUSE_GEOTABLE_WIDTH);
687 if (!cpl_errorstate_is_equal(prestate)) {
688 char *msg = cpl_sprintf(
"Geometry table is missing column%s%s%s!",
689 !slice_angle && !slice_width ?
"s" :
"",
690 slice_angle ?
"" :
" \""MUSE_GEOTABLE_ANGLE
"\"",
691 slice_width ?
"" :
" \""MUSE_GEOTABLE_WIDTH
"\"");
692 cpl_error_set_message(__func__, CPL_ERROR_BAD_FILE_FORMAT,
"%s", msg);
693 cpl_msg_error(__func__,
"%s", msg);
695 if (!getenv(
"MUSE_EXPERT_USER")) {
696 cpl_table_delete(geopos);
704 cpl_size itablerow = 0;
706 double cputime = cpl_test_get_cputime(),
707 walltime = cpl_test_get_walltime();
710 #if DEBUG_PIXTABLE_FEW_SLICES > 0
711 # define SLICE_LIMIT DEBUG_PIXTABLE_FEW_SLICES
713 # define SLICE_LIMIT kMuseSlicesPerCCD
715 for (islice = 0; islice < SLICE_LIMIT; islice++) {
716 #if DEBUG_PIXTABLE_CREATION
717 cpl_msg_debug(__func__,
"Starting to process slice %2d of IFU %2d",
725 cpl_vector *pos = cpl_vector_new(2);
728 cpl_vector_set(pos, 0, kMuseOutputYTop / 2);
729 cpl_vector_set(pos, 1, kMuseOutputYTop / 2);
730 double ltest = cpl_polynomial_eval(pwave, pos);
731 if (!pwave || !isnormal(ltest) || fabs(ltest) < DBL_EPSILON) {
732 char *msg = cpl_sprintf(
"Wavelength calibration polynomial for slice %d "
733 "is not well defined!", islice + 1);
734 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
"%s", msg);
735 cpl_msg_error(__func__,
"%s", msg);
737 cpl_polynomial_delete(pwave);
738 cpl_vector_delete(pos);
739 if (getenv(
"MUSE_EXPERT_USER")) {
742 cpl_table_delete(geopos);
752 char *msg = cpl_sprintf(
"Tracing polynomials for slice %d are not well "
753 "defined!", islice + 1);
754 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
"%s", msg);
755 cpl_msg_error(__func__,
"%s", msg);
757 cpl_polynomial_delete(pwave);
758 cpl_vector_delete(pos);
759 if (getenv(
"MUSE_EXPERT_USER")) {
762 cpl_table_delete(geopos);
768 ptrace[MUSE_TRACE_LEFT],
773 for (j = 1; j <= ysize; j++) {
776 double x1 = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_LEFT], j, NULL),
777 x2 = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_RIGHT], j, NULL),
778 xcenter = (x1 + x2) / 2.,
780 if (!isnormal(x1) || !isnormal(x2) || x1 < 1 || x2 > xsize || x1 > x2) {
781 cpl_msg_warning(__func__,
"slice %2d: faulty polynomial detected at "
782 "y=%d (borders: %f ... %f)", islice + 1, j, x1, x2);
786 int ileft = ceil(x1),
788 cpl_vector_set(pos, 1, j);
792 for (i = ileft; i <= iright; i++) {
793 cpl_vector_set(pos, 0, i);
797 double lambda = cpl_polynomial_eval(pwave, pos);
798 if (lambda < 3000. || lambda > 11000. || !isfinite(lambda)) {
809 float dx = (xcenter - i) / width
810 * (slice_width ? slice_width[islice] : kMuseSliceNominalWidth);
811 #if DEBUG_PIXTABLE_CREATION
812 if (fabs(dx) > 37.5) {
813 cpl_msg_debug(__func__,
"%d - %f -> %f", i, xcenter, dx);
817 #if CREATE_MINIMAL_PIXTABLE
819 if (lambda < 6495. || lambda > 6505. || fabs(dx) > 10.) {
825 cpl_size irow = itablerow++;
826 #if !PIXTABLE_CREATE_CCDSIZED
828 #if DEBUG_PIXTABLE_CREATION
829 printf(
"pixel table before enlargement:\n");
830 cpl_table_dump(pt->
table, irow-5, 10, stdout);
836 const cpl_size nr = 1000000;
837 cpl_msg_debug(__func__,
"expand table to %"CPL_SIZE_FORMAT
" rows "
838 "(add %"CPL_SIZE_FORMAT
" lines)!", irow + nr, nr);
839 cpl_table_set_size(pt->
table, irow + nr);
842 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_XPOS, irow, nr, 0);
843 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_YPOS, irow, nr, 0);
844 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_LAMBDA, irow, nr, 0);
845 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_DATA, irow, nr, 0);
846 cpl_table_fill_column_window_float(pt->
table, MUSE_PIXTABLE_STAT, irow, nr, 0);
847 cpl_table_fill_column_window_int(pt->
table, MUSE_PIXTABLE_DQ, irow, nr, 0);
848 cpl_table_fill_column_window_int(pt->
table, MUSE_PIXTABLE_ORIGIN, irow, nr, 0);
851 cdata_xpos = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_XPOS);
852 cdata_ypos = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_YPOS);
853 cdata_lambda = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_LAMBDA);
854 cdata_data = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_DATA);
855 cdata_stat = cpl_table_get_data_float(pt->
table, MUSE_PIXTABLE_STAT);
856 cdata_dq = cpl_table_get_data_int(pt->
table, MUSE_PIXTABLE_DQ);
857 cdata_origin = (uint32_t *)cpl_table_get_data_int(pt->
table,
858 MUSE_PIXTABLE_ORIGIN);
859 #if DEBUG_PIXTABLE_CREATION
860 printf(
"pixel table after filling new rows:\n");
861 cpl_table_dump(pt->
table, irow-5, 10, stdout);
868 double angle = slice_angle ? slice_angle[islice] * CPL_MATH_RAD_DEG
870 cdata_xpos[irow] = aGeoTable
871 ? dx * cos(angle) + slice_x[islice]
872 : dx + islice * kMuseSliceHiLikelyWidth
873 + kMuseSliceHiLikelyWidth / 2.;
874 cdata_ypos[irow] = aGeoTable
875 ? dx * sin(angle) + slice_y[islice]
877 #if DEBUG_PIXTABLE_CREATION
878 if (!isfinite(cdata_xpos[irow]) ||
879 cdata_xpos[irow] < -200 || cdata_xpos[irow] > 4000) {
880 cpl_msg_debug(__func__,
"weird data in x: %e %e",
881 cdata_xpos[irow], cdata_ypos[irow]);
883 if (!isfinite(cdata_ypos[irow]) ||
884 cdata_ypos[irow] < -200 || cdata_ypos[irow] > 200) {
885 cpl_msg_debug(__func__,
"weird data in y: %e %e",
886 cdata_xpos[irow], cdata_ypos[irow]);
889 cdata_lambda[irow] = lambda;
892 cdata_data[irow] = pixdata[(i-1) + (j-1)*xsize];
893 cdata_dq[irow] = pixdq[(i-1) + (j-1)*xsize];
894 cdata_stat[irow] = pixstat[(i-1) + (j-1)*xsize];
896 cdata_origin[irow] = muse_pixtable_origin_encode_fast(i, j, ifu,
904 cpl_polynomial_delete(pwave);
905 cpl_vector_delete(pos);
907 cpl_table_delete(geopos);
908 cpl_msg_debug(__func__,
"IFU %d took %gs (CPU time), %gs (wall-clock)",
909 ifu, cpl_test_get_cputime() - cputime,
910 cpl_test_get_walltime() - walltime);
914 cpl_msg_debug(__func__,
"Trimming pixel table to %"CPL_SIZE_FORMAT
" of %"
916 #if DEBUG_PIXTABLE_CREATION
917 printf(
"end of used part of pixel table before trimming:\n");
918 cpl_table_dump(pt->
table, itablerow-5, 10, stdout);
921 cpl_table_set_size(pt->
table, itablerow);
926 #if DEBUG_PIXTABLE_CREATION
927 printf(
"beginning of pixel table before returning:\n");
928 cpl_table_dump(pt->
table, 0, 5, stdout);
930 printf(
"end of pixel table before returning:\n");
955 if (aPixtable == NULL) {
959 pt->
table = cpl_table_duplicate(aPixtable->
table);
960 pt->
header = cpl_propertylist_duplicate(aPixtable->
header);
983 cpl_table_delete(aPixtable->
table);
984 aPixtable->
table = NULL;
987 cpl_propertylist_delete(aPixtable->
header);
1015 static cpl_error_code
1016 muse_pixtable_save_image(
muse_pixtable *aPixtable,
const char *aFilename)
1018 const char *
id =
"muse_pixtable_save";
1019 cpl_ensure_code(aPixtable, CPL_ERROR_NULL_INPUT);
1021 cpl_ensure_code(nrow > 0, CPL_ERROR_ILLEGAL_INPUT);
1023 cpl_errorstate state = cpl_errorstate_get();
1024 cpl_array *columns = cpl_table_get_column_names(aPixtable->
table);
1025 int icol, ncol = cpl_array_get_size(columns);
1026 for (icol = 0; icol < ncol; icol++) {
1027 const char *colname = cpl_array_get_string(columns, icol);
1029 cpl_type type = cpl_table_get_column_type(aPixtable->
table, colname);
1030 cpl_image *image = NULL;
1032 case CPL_TYPE_FLOAT: {
1033 float *data = cpl_table_get_data_float(aPixtable->
table, colname);
1034 image = cpl_image_wrap_float(1, nrow, data);
1037 case CPL_TYPE_INT: {
1038 int *data = cpl_table_get_data_int(aPixtable->
table, colname);
1039 image = cpl_image_wrap_int(1, nrow, data);
1043 cpl_error_set_message(
id, CPL_ERROR_UNSUPPORTED_MODE,
"type \"%s\" (of "
1044 "column %s) is not supported for MUSE pixel tables",
1045 cpl_type_get_name(type), colname);
1050 cpl_propertylist *hext = cpl_propertylist_new();
1051 cpl_propertylist_append_string(hext,
"EXTNAME", colname);
1052 const char *unit = cpl_table_get_column_unit(aPixtable->
table, colname);
1054 cpl_propertylist_append_string(hext,
"BUNIT", unit);
1056 cpl_image_save(image, aFilename, CPL_TYPE_UNSPECIFIED, hext, CPL_IO_EXTEND);
1057 cpl_image_unwrap(image);
1058 cpl_propertylist_delete(hext);
1060 cpl_array_delete(columns);
1061 return cpl_errorstate_is_equal(state) ? CPL_ERROR_NONE : cpl_error_get_code();
1086 cpl_ensure_code(aPixtable, CPL_ERROR_NULL_INPUT);
1092 cpl_error_code rc = cpl_propertylist_save(aPixtable->
header, aFilename,
1094 if (rc != CPL_ERROR_NONE) {
1095 cpl_error_set_message(__func__, rc,
"could not save FITS header of pixel "
1096 "table \"%s\"", aFilename);
1100 cpl_boolean asimage = getenv(
"MUSE_PIXTABLE_SAVE_AS_IMAGE")
1101 && atoi(getenv(
"MUSE_PIXTABLE_SAVE_AS_IMAGE"));
1103 cpl_msg_debug(__func__,
"Saving pixel table \"%s\" as image", aFilename);
1104 rc = muse_pixtable_save_image(aPixtable, aFilename);
1106 rc = cpl_table_save(aPixtable->
table, NULL, NULL, aFilename, CPL_IO_EXTEND);
1135 muse_pixtable_load_window_image(
const char *aFilename,
1136 cpl_size aStart, cpl_size aNRows)
1138 const char *
id =
"muse_pixtable_load";
1141 cpl_size y1 = aStart + 1,
1142 y2 = aStart + aNRows;
1145 cpl_table *table = cpl_table_new(nrow);
1146 int iext, next = cpl_fits_count_extensions(aFilename);
1147 for (iext = 1; iext <= next; iext++) {
1148 cpl_errorstate ps = cpl_errorstate_get();
1149 cpl_image *column = cpl_image_load_window(aFilename, CPL_TYPE_UNSPECIFIED,
1150 0, iext, 1, y1, 1, y2);
1151 if (!column || !cpl_errorstate_is_equal(ps)) {
1152 cpl_image_delete(column);
1153 cpl_error_set_message(
id, cpl_error_get_code(),
"could not load extension"
1154 " %d of pixel table \"%s\"", iext, aFilename);
1157 cpl_propertylist *hext = cpl_propertylist_load(aFilename, iext);
1159 cpl_size nrows = cpl_image_get_size_x(column)
1160 * cpl_image_get_size_y(column);
1162 cpl_table_set_size(table, nrows);
1164 }
else if (nrows != nrow) {
1165 cpl_error_set_message(
id, CPL_ERROR_INCOMPATIBLE_INPUT,
"size of column "
1166 "%s does not match", colname);
1167 cpl_propertylist_delete(hext);
1168 cpl_image_delete(column);
1171 cpl_type type = cpl_image_get_type(column);
1173 case CPL_TYPE_FLOAT:
1174 cpl_table_wrap_float(table, cpl_image_unwrap(column), colname);
1177 cpl_table_wrap_int(table, cpl_image_unwrap(column), colname);
1180 cpl_error_set_message(
id, CPL_ERROR_UNSUPPORTED_MODE,
"type \"%s\" (of "
1181 "column %s) is not supported for MUSE pixel tables",
1182 cpl_type_get_name(type), colname);
1184 cpl_errorstate state = cpl_errorstate_get();
1185 const char *unit = cpl_propertylist_get_string(hext,
"BUNIT");
1186 if (!cpl_errorstate_is_equal(state)) {
1187 cpl_errorstate_set(state);
1190 cpl_table_set_column_unit(table, colname, unit);
1192 cpl_propertylist_delete(hext);
1219 cpl_size aStart, cpl_size aNRows)
1225 cpl_errorstate prestate = cpl_errorstate_get();
1226 pt->
header = cpl_propertylist_load(aFilename, 0);
1227 cpl_ensure(cpl_errorstate_is_equal(prestate) && pt->
header,
1228 cpl_error_get_code(), NULL);
1230 cpl_msg_error(__func__,
"unknown pixel table type found in \"%s\"", aFilename);
1237 cpl_propertylist *hext = cpl_propertylist_load(aFilename, 1);
1238 cpl_boolean asimage = !strcmp(cpl_propertylist_get_string(hext,
"XTENSION"),
1240 cpl_propertylist_delete(hext);
1244 cpl_msg_info(__func__,
"Loading pixel table \"%s\" (as image)", aFilename);
1245 pt->
table = muse_pixtable_load_window_image(aFilename, aStart, aNRows);
1247 cpl_msg_info(__func__,
"Loading pixel table \"%s\"", aFilename);
1248 pt->
table = cpl_table_load_window(aFilename, 1, 0, NULL, aStart, aNRows);
1250 cpl_ensure(cpl_errorstate_is_equal(prestate) && pt->
table,
1251 cpl_error_get_code(), NULL);
1253 if (rc != CPL_ERROR_NONE) {
1254 cpl_error_set_message(__func__, rc,
"pixel table \"%s\" does not contain "
1255 "all expected columns", aFilename);
1286 cpl_errorstate prestate = cpl_errorstate_get();
1287 cpl_propertylist *theader = cpl_propertylist_load(aFilename, 1);
1288 cpl_ensure(cpl_errorstate_is_equal(prestate) && theader,
1289 cpl_error_get_code(), NULL);
1290 cpl_size nrow = cpl_propertylist_get_long_long(theader,
"NAXIS2");
1291 cpl_propertylist_delete(theader);
1318 double aLambdaMin,
double aLambdaMax)
1326 if (rc != CPL_ERROR_NONE) {
1331 cpl_msg_error(__func__,
"Pixel table contains no entries after cutting to "
1332 "%.3f..%.3f Angstrom", aLambdaMin, aLambdaMax);
1333 cpl_error_set(__func__, CPL_ERROR_DATA_NOT_FOUND);
1377 double aLambdaMin,
double aLambdaMax)
1379 cpl_ensure(aExposureList, CPL_ERROR_NULL_INPUT, NULL);
1382 if (cpl_table_has_column(aExposureList,
"00")) {
1383 const char *filename = cpl_table_get_string(aExposureList,
"00", 0);
1392 cpl_boolean isfirst = CPL_TRUE;
1393 double fluxlref = 0,
1396 for (i = 1; i <= kMuseNumIFUs; i++) {
1397 char *colname = cpl_sprintf(
"%02d", i);
1398 const char *filename = cpl_table_get_string(aExposureList, colname, 0);
1401 cpl_msg_warning(__func__,
"Channel for IFU %02d is missing", i);
1408 cpl_msg_error(__func__,
"failed to load pixel table from \"%s\"",
1417 cpl_msg_debug(__func__,
"loaded pixel table with %"CPL_SIZE_FORMAT
" rows",
1419 isfirst = CPL_FALSE;
1420 cpl_errorstate prestate = cpl_errorstate_get();
1421 fluxsref = cpl_propertylist_get_double(pt->
header, MUSE_HDR_FLAT_FLUX_SKY);
1422 fluxlref = cpl_propertylist_get_double(pt->
header, MUSE_HDR_FLAT_FLUX_LAMP);
1423 if (fluxsref == 0. && fluxlref == 0. && !cpl_errorstate_is_equal(prestate)) {
1427 cpl_msg_debug(__func__,
"\"%s\" was previously merged (got \"%s\" when"
1428 " asking for flat-field fluxes)", filename,
1429 cpl_error_get_message());
1430 cpl_errorstate_set(prestate);
1433 if (fluxsref == 0. && fluxlref > 0. && !cpl_errorstate_is_equal(prestate)) {
1435 cpl_msg_warning(__func__,
"only found reference lamp-flat flux (%e) in "
1436 "\"%s\", flux levels may vary between IFUs!", fluxlref,
1438 cpl_errorstate_set(prestate);
1440 cpl_msg_debug(__func__,
"reference flat fluxes sky: %e lamp: %e",
1441 fluxsref, fluxlref);
1443 cpl_propertylist_erase(pt->
header, MUSE_HDR_FLAT_FLUX_SKY);
1444 cpl_propertylist_erase(pt->
header, MUSE_HDR_FLAT_FLUX_LAMP);
1452 cpl_errorstate state = cpl_errorstate_get();
1453 double fluxs = cpl_propertylist_get_double(onept->
header,
1454 MUSE_HDR_FLAT_FLUX_SKY),
1455 fluxl = cpl_propertylist_get_double(onept->
header,
1456 MUSE_HDR_FLAT_FLUX_LAMP),
1458 if (fluxsref > 0. && fluxs > 0.) {
1459 scale = fluxs / fluxsref;
1460 }
else if (fluxlref > 0. && fluxl > 0.) {
1461 scale = fluxl / fluxlref;
1462 if (!cpl_errorstate_is_equal(state)) {
1463 cpl_msg_warning(__func__,
"only found relative lamp-flat flux (%e) in "
1464 "\"%s\", flux levels may vary between IFUs!", fluxl,
1466 cpl_errorstate_set(state);
1469 cpl_table_divide_scalar(onept->
table, MUSE_PIXTABLE_DATA, scale);
1470 cpl_table_divide_scalar(onept->
table, MUSE_PIXTABLE_STAT, scale*scale);
1474 cpl_msg_debug(__func__,
"big pixel table now has %"CPL_SIZE_FORMAT
" entries,"
1475 " scale was %e (flat fluxes sky: %e lamp: %e)",
1483 cpl_error_set_message(__func__, CPL_ERROR_FILE_NOT_FOUND,
1484 "None of the pixel tables could be loaded");
1489 cpl_propertylist_erase_regexp(pt->
header,
"^EXTNAME", 0);
1493 MUSE_HDR_PT_MERGED_COMMENT);
1514 const char *type = cpl_propertylist_get_string(aPixtable->
header,
1517 cpl_msg_debug(__func__,
"pixel table type \"%s\"", type);
1522 if (!strncmp(type, MUSE_PIXTABLE_STRING_FULL,
1523 strlen(MUSE_PIXTABLE_STRING_FULL) + 1)) {
1525 }
else if (!strncmp(type, MUSE_PIXTABLE_STRING_SIMPLE,
1526 strlen(MUSE_PIXTABLE_STRING_SIMPLE) + 1)) {
1547 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, 0);
1548 cpl_ensure(aPixtable->
table, CPL_ERROR_NULL_INPUT, 0);
1551 return cpl_table_get_nrow(aPixtable->
table);
1575 cpl_ensure_code(aPixtable && aPixtable->
table && aPixtable->
header,
1576 CPL_ERROR_NULL_INPUT);
1578 == CPL_ERROR_NONE, CPL_ERROR_DATA_NOT_FOUND);
1581 return CPL_ERROR_NONE;
1584 float *cdata_xpos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_XPOS),
1585 *cdata_ypos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_YPOS),
1586 *cdata_lambda = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA);
1587 uint32_t *origin = (uint32_t *)cpl_table_get_data_int(aPixtable->
table,
1588 MUSE_PIXTABLE_ORIGIN);
1590 float xlo = FLT_MAX, xhi = -FLT_MAX,
1591 ylo = FLT_MAX, yhi = -FLT_MAX,
1592 llo = FLT_MAX, lhi = -FLT_MAX;
1593 int ifulo = INT_MAX, ifuhi = 0,
1594 slicelo = INT_MAX, slicehi = 0;
1596 for (i = 0; i < nrow; i++) {
1597 if (cdata_xpos[i] > xhi) xhi = cdata_xpos[i];
1598 if (cdata_xpos[i] < xlo) xlo = cdata_xpos[i];
1599 if (cdata_ypos[i] > yhi) yhi = cdata_ypos[i];
1600 if (cdata_ypos[i] < ylo) ylo = cdata_ypos[i];
1601 if (cdata_lambda[i] > lhi) lhi = cdata_lambda[i];
1602 if (cdata_lambda[i] < llo) llo = cdata_lambda[i];
1603 int ifu = muse_pixtable_origin_get_ifu_fast(origin[i]),
1604 slice = muse_pixtable_origin_get_slice_fast(origin[i]);
1605 if (ifu > ifuhi) ifuhi = ifu;
1606 if (ifu < ifulo) ifulo = ifu;
1607 if (slice > slicehi) slicehi = slice;
1608 if (slice < slicelo) slicelo = slice;
1610 char *dodebug = getenv(
"MUSE_DEBUG_PIXTABLE_LIMITS");
1611 if (dodebug && atoi(dodebug)) {
1612 cpl_msg_debug(__func__,
"x: %f...%f, y: %f...%f, lambda: %f...%f, "
1613 "ifu: %d...%d, slice: %d...%d",
1614 xlo, xhi, ylo, yhi, llo, lhi, ifulo, ifuhi, slicelo, slicehi);
1616 cpl_propertylist_erase_regexp(aPixtable->
header, MUSE_HDR_PT_LIMITS_REGEXP, 0);
1620 ptxoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL1");
1621 ptyoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL2");
1634 return CPL_ERROR_NONE;
1648 static cpl_error_code
1651 cpl_ensure_code(aPixtable && aPixtable->
header && aPixtable->
table,
1652 CPL_ERROR_NULL_INPUT);
1653 if (cpl_table_count_selected(aPixtable->
table) < 1) {
1654 return CPL_ERROR_NONE;
1656 cpl_array *sel = cpl_table_where_selected(aPixtable->
table);
1657 cpl_size narray = cpl_array_get_size(sel),
1660 const cpl_size *asel = cpl_array_get_data_cplsize_const(sel);
1661 unsigned int nexp = 0;
1666 if (!cpl_propertylist_has(aPixtable->
header, kwfst) ||
1667 !cpl_propertylist_has(aPixtable->
header, kwlst)) {
1672 ifst = cpl_propertylist_get_long_long(aPixtable->
header, kwfst);
1673 ilst = cpl_propertylist_get_long_long(aPixtable->
header, kwlst);
1675 cpl_size i, nsel = 0;
1676 for (i = 0; i < narray; i++) {
1677 if (asel[i] >= ifst && asel[i] <= ilst) {
1681 cpl_size ifst2 = ifst - nselprev,
1682 ilst2 = ilst - nsel - nselprev;
1683 cpl_msg_debug(__func__,
"exp %d old %"CPL_SIZE_FORMAT
"..%"CPL_SIZE_FORMAT
1684 ", %"CPL_SIZE_FORMAT
" selected (previous: %"CPL_SIZE_FORMAT
1685 "), new %"CPL_SIZE_FORMAT
"..%"CPL_SIZE_FORMAT, nexp,
1686 ifst, ilst, nsel, nselprev, ifst2, ilst2);
1693 }
while (ilst >= ifst);
1694 cpl_array_delete(sel);
1695 return CPL_ERROR_NONE;
1712 cpl_ensure_code(aPixtable && aPixtable->
table && aPixtable->
header,
1713 CPL_ERROR_NULL_INPUT);
1717 return CPL_ERROR_NONE;
1719 #pragma omp critical(cpl_table_select)
1721 cpl_table_unselect_all(aPixtable->
table);
1722 cpl_table_or_selected_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA,
1723 CPL_LESS_THAN, aLow);
1724 cpl_table_or_selected_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA,
1725 CPL_GREATER_THAN, aHigh);
1727 cpl_table_erase_selected(aPixtable->
table);
1747 cpl_ensure_code(aPixtable && aPixtable->
table && aPixtable->
header,
1748 CPL_ERROR_NULL_INPUT);
1752 return CPL_ERROR_NONE;
1757 ptxoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL1");
1759 #pragma omp critical(cpl_table_select)
1761 cpl_table_unselect_all(aPixtable->
table);
1762 cpl_table_or_selected_float(aPixtable->
table, MUSE_PIXTABLE_XPOS,
1763 CPL_LESS_THAN, aLo - ptxoff);
1764 cpl_table_or_selected_float(aPixtable->
table, MUSE_PIXTABLE_XPOS,
1765 CPL_GREATER_THAN, aHi - ptxoff);
1767 cpl_table_erase_selected(aPixtable->
table);
1787 cpl_ensure_code(aPixtable && aPixtable->
table && aPixtable->
header,
1788 CPL_ERROR_NULL_INPUT);
1792 return CPL_ERROR_NONE;
1797 ptyoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL2");
1799 #pragma omp critical(cpl_table_select)
1801 cpl_table_unselect_all(aPixtable->
table);
1802 cpl_table_or_selected_float(aPixtable->
table, MUSE_PIXTABLE_YPOS,
1803 CPL_LESS_THAN, aLo - ptyoff);
1804 cpl_table_or_selected_float(aPixtable->
table, MUSE_PIXTABLE_YPOS,
1805 CPL_GREATER_THAN, aHi - ptyoff);
1807 cpl_table_erase_selected(aPixtable->
table);
1833 cpl_ensure_code(aPixtable && aPixtable->
table, CPL_ERROR_NULL_INPUT);
1834 cpl_ensure_code(aMask && aMask->
mask, CPL_ERROR_NULL_INPUT);
1835 float *cdata_xpos = cpl_table_get_data_float(aPixtable->
table,
1836 MUSE_PIXTABLE_XPOS);
1837 float *cdata_ypos = cpl_table_get_data_float(aPixtable->
table,
1838 MUSE_PIXTABLE_YPOS);
1839 cpl_size n_rows = cpl_table_get_nrow(aPixtable->
table);
1848 crval_x = cpl_propertylist_get_double(aMask->
header,
"CRVAL1");
1849 crpix_x = cpl_propertylist_get_double(aMask->
header,
"CRPIX1");
1850 cdelt_x = cpl_propertylist_get_double(aMask->
header,
"CD1_1");
1851 crval_y = cpl_propertylist_get_double(aMask->
header,
"CRVAL2");
1852 crpix_y = cpl_propertylist_get_double(aMask->
header,
"CRPIX2");
1853 cdelt_y = cpl_propertylist_get_double(aMask->
header,
"CD2_2");
1855 cpl_size nx = cpl_mask_get_size_x(aMask->
mask);
1856 cpl_size ny = cpl_mask_get_size_y(aMask->
mask);
1857 cpl_size n_enabled = cpl_mask_count(aMask->
mask);
1858 cpl_msg_debug(__func__,
"Mask contains %"CPL_SIZE_FORMAT
" (%.2f %%) enabled "
1859 "pixels of %"CPL_SIZE_FORMAT
" total", n_enabled,
1860 100.*n_enabled/nx/ny, nx*ny);
1861 cpl_size n_sel = n_rows;
1862 cpl_size n_in_table = 0;
1863 for (i_row = 0; i_row < n_rows; i_row++) {
1864 cpl_size ix = lround((cdata_xpos[i_row] - crval_x) / cdelt_x + crpix_x);
1865 cpl_size iy = lround((cdata_ypos[i_row] - crval_y) / cdelt_y + crpix_y);
1866 if ((ix < 1) || (ix > nx) || (iy < 1) || (iy > ny)) {
1870 if (cpl_mask_get(aMask->
mask, ix, iy) != CPL_BINARY_1) {
1871 cpl_table_unselect_row(aPixtable->
table, i_row);
1875 cpl_msg_debug(__func__,
"Mask selected %"CPL_SIZE_FORMAT
" (%.2f %%/%.2f %%) "
1876 "pixels of %"CPL_SIZE_FORMAT
" total/%"CPL_SIZE_FORMAT
" in mask "
1877 "area", n_sel, 100.*n_sel/n_rows, 100.*n_sel/n_in_table,
1878 n_rows, n_in_table);
1879 return CPL_ERROR_NONE;
1912 unsigned char aDisplayHeader)
1914 cpl_ensure_code(aPixtable && aPixtable->
table && aPixtable->
header,
1915 CPL_ERROR_NULL_INPUT);
1917 cpl_ensure_code(aStart >= 0 && aStart < nrows && aCount >= 0,
1918 CPL_ERROR_ILLEGAL_INPUT);
1919 cpl_size last = aStart + aCount;
1920 if (last > nrows - 1) {
1924 double ptxoff = 0., ptyoff = 0.;
1927 ptxoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL1");
1928 ptyoff = cpl_propertylist_get_double(aPixtable->
header,
"CRVAL2");
1933 float *cdata_xpos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_XPOS),
1934 *cdata_ypos = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_YPOS),
1935 *cdata_lambda = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_LAMBDA),
1936 *cdata_data = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_DATA),
1937 *cdata_stat = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_STAT);
1938 cpl_errorstate es = cpl_errorstate_get();
1939 float *cdata_weight = cpl_table_get_data_float(aPixtable->
table, MUSE_PIXTABLE_WEIGHT);
1940 cpl_errorstate_set(es);
1941 int *cdata_dq = cpl_table_get_data_int(aPixtable->
table, MUSE_PIXTABLE_DQ);
1942 uint32_t *cdata_origin = (uint32_t *)cpl_table_get_data_int(aPixtable->
table,
1943 MUSE_PIXTABLE_ORIGIN);
1944 cpl_ensure_code(cdata_xpos && cdata_ypos && cdata_lambda &&
1945 cdata_data && cdata_dq && cdata_stat,
1946 CPL_ERROR_BAD_FILE_FORMAT);
1949 if (aDisplayHeader) {
1950 printf(
"# xpos ypos lambda data dq stat"
1951 " weight exposure IFU xCCD yCCD xRaw yRaw slice\n");
1953 if (aDisplayHeader == 1) {
1954 printf(
"#%13s %13s %9s %11s flag %11s ---------- No No pix "
1955 " pix pix pix No\n# flux in [%s]\n# flux**2 in [%s]\n",
1956 cpl_table_get_column_unit(aPixtable->
table, MUSE_PIXTABLE_XPOS),
1957 cpl_table_get_column_unit(aPixtable->
table, MUSE_PIXTABLE_YPOS),
1958 cpl_table_get_column_unit(aPixtable->
table, MUSE_PIXTABLE_LAMBDA),
1959 "(flux)",
"(flux**2)",
1960 cpl_table_get_column_unit(aPixtable->
table, MUSE_PIXTABLE_DATA),
1961 cpl_table_get_column_unit(aPixtable->
table, MUSE_PIXTABLE_STAT));
1965 for (i = aStart; i < last; i++) {
1967 y = muse_pixtable_origin_get_y_fast(cdata_origin[i]);
1968 int xraw = x + kMusePreOverscanSize,
1969 yraw = y + kMusePreOverscanSize;
1971 if (x > kMuseOutputXRight / 2) {
1972 xraw += kMusePreOverscanSize * 2;
1974 if (y > kMuseOutputYTop / 2) {
1975 yraw += kMusePreOverscanSize * 2;
1978 printf(
"%14.7e %14.7e %9.3f ", cdata_xpos[i] + ptxoff, cdata_ypos[i] + ptyoff,
1981 printf(
"%14.8f %14.8f %9.3f ", cdata_xpos[i], cdata_ypos[i], cdata_lambda[i]);
1983 printf(
"%12.5e 0x%08x %11.5e %10.4e %2d %2d %4d %4d %4d %4d %2d\n",
1984 cdata_data[i], cdata_dq[i], cdata_stat[i],
1985 cdata_weight ? cdata_weight[i] : 0.,
1987 cdata_origin ? muse_pixtable_origin_get_ifu_fast(cdata_origin[i])
1990 cdata_origin ? muse_pixtable_origin_get_slice_fast(cdata_origin[i])
1994 return CPL_ERROR_NONE;
2024 const char *unitx = cpl_table_get_column_unit(aPixtable->
table,
2025 MUSE_PIXTABLE_XPOS),
2026 *unity = cpl_table_get_column_unit(aPixtable->
table,
2027 MUSE_PIXTABLE_YPOS);
2030 cpl_ensure(!strncmp(unitx, unity, 4), CPL_ERROR_INCOMPATIBLE_INPUT,
2032 if (!strncmp(unitx,
"deg", 4)) {
2035 if (!strncmp(unitx,
"pix", 4)) {
2038 if (!strncmp(unitx,
"rad", 4)) {
2041 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
2057 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, CPL_FALSE);
2058 cpl_errorstate prestate = cpl_errorstate_get();
2059 cpl_boolean flag = cpl_propertylist_get_bool(aPixtable->
header,
2061 cpl_errorstate_set(prestate);
2077 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, CPL_FALSE);
2078 cpl_errorstate prestate = cpl_errorstate_get();
2079 cpl_boolean flag = cpl_propertylist_get_bool(aPixtable->
header,
2081 cpl_errorstate_set(prestate);
2098 cpl_ensure_code(aPixtable, CPL_ERROR_NULL_INPUT);
2100 unsigned int *dq = (
unsigned int *)cpl_table_get_data_int(aPixtable->
table,
2104 #pragma omp parallel for default(none) \
2105 shared(dq, inverse, nrow)
2106 for (i = 0; i < nrow; i++) {
2109 return CPL_ERROR_NONE;
2133 cpl_ensure(aPixtable && aPixtable->
header, CPL_ERROR_NULL_INPUT, NULL);
2137 cpl_ensure(expnum == explast, CPL_ERROR_ILLEGAL_INPUT, NULL);
2147 unsigned short ifu = 0,
2150 for (ipt = 0; ipt < npt; ipt++) {
2151 float *cdata = cpl_table_get_data_float(pts[ipt]->table, MUSE_PIXTABLE_DATA),
2152 *cstat = cpl_table_get_data_float(pts[ipt]->table, MUSE_PIXTABLE_STAT);
2153 int *cdq = cpl_table_get_data_int(pts[ipt]->table, MUSE_PIXTABLE_DQ);
2154 uint32_t *corigin = (uint32_t *)cpl_table_get_data_int(pts[ipt]->table,
2155 MUSE_PIXTABLE_ORIGIN);
2159 if (ifu != muse_pixtable_origin_get_ifu_fast(corigin[0])) {
2161 image->
header = cpl_propertylist_duplicate(pts[ipt]->header);
2162 cpl_propertylist_erase_regexp(image->
header,
"^ESO DRS MUSE PIXTABLE", 0);
2163 image->
data = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop, CPL_TYPE_FLOAT);
2164 image->
dq = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop, CPL_TYPE_INT);
2166 cpl_image_fill_noise_uniform(image->
dq, EURO3D_MISSDATA, EURO3D_MISSDATA + 0.1);
2167 image->
stat = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop, CPL_TYPE_FLOAT);
2168 cpl_msg_debug(__func__,
"new image (index %hu in list)", ilist);
2172 cpl_msg_error(__func__,
"ipt = %d: no image!", ipt);
2175 float *idata = cpl_image_get_data_float(image->
data),
2176 *istat = cpl_image_get_data_float(image->
stat);
2177 int *idq = cpl_image_get_data_int(image->
dq);
2179 ifu = muse_pixtable_origin_get_ifu_fast(corigin[0]);
2180 unsigned short slice = muse_pixtable_origin_get_slice_fast(corigin[0]);
2183 x1 = INT_MAX, x2 = 0,
2185 for (irow = 0; irow < nrow; irow++) {
2187 unsigned int x = muse_pixtable_origin_get_x_fast(corigin[irow], xoff) - 1,
2188 y = muse_pixtable_origin_get_y_fast(corigin[irow]) - 1;
2189 idata[x + y*kMuseOutputXRight] = cdata[irow];
2190 idq[x + y*kMuseOutputXRight] = cdq[irow];
2191 istat[x + y*kMuseOutputXRight] = cstat[irow];
2200 char *keyword = cpl_sprintf(
"ESO DRS MUSE SLICE%hu CENTER", slice);
2201 cpl_propertylist_update_float(image->
header, keyword, (x2 + x1) / 2. + 1.);
2203 cpl_msg_debug(__func__,
"IFU %hu %s = %.1f", ifu, keyword,
2204 (x2 + x1) / 2. + 1.);
2243 cpl_ensure_code(aPixtable && aPixtable->
header && aList, CPL_ERROR_NULL_INPUT);
2247 cpl_ensure_code(expnum == explast, CPL_ERROR_ILLEGAL_INPUT);
2256 return cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
2260 unsigned short ifu = 0,
2263 for (ipt = 0; ipt < npt; ipt++) {
2264 float *cdata = cpl_table_get_data_float(pts[ipt]->table, MUSE_PIXTABLE_DATA),
2265 *cstat = cpl_table_get_data_float(pts[ipt]->table, MUSE_PIXTABLE_STAT);
2266 uint32_t *corigin = (uint32_t *)cpl_table_get_data_int(pts[ipt]->table,
2267 MUSE_PIXTABLE_ORIGIN);
2269 if (ifu != muse_pixtable_origin_get_ifu_fast(corigin[0])) {
2273 cpl_msg_error(__func__,
"ipt = %d: no image!", ipt);
2276 float *idata = cpl_image_get_data_float(image->
data),
2277 *istat = cpl_image_get_data_float(image->
stat);
2278 ifu = muse_pixtable_origin_get_ifu_fast(corigin[0]);
2279 unsigned short slice = muse_pixtable_origin_get_slice_fast(corigin[0]);
2283 for (irow = 0; irow < nrow; irow++) {
2285 unsigned int x = muse_pixtable_origin_get_x_fast(corigin[irow], xoff) - 1,
2286 y = muse_pixtable_origin_get_y_fast(corigin[irow]) - 1;
2287 cdata[irow] = idata[x + y*kMuseOutputXRight];
2288 cstat[irow] = istat[x + y*kMuseOutputXRight];
2293 return CPL_ERROR_NONE;
2313 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, NULL);
2314 cpl_size n_rows = cpl_table_get_nrow(aPixtable->
table);
2315 unsigned int ifu_slice_mask = (0x1f << MUSE_ORIGIN_SHIFT_IFU) | 0x3f;
2316 cpl_table_duplicate_column(aPixtable->
table,
"ifuslice",
2317 aPixtable->
table, MUSE_PIXTABLE_ORIGIN);
2318 unsigned int *slicedata = (
unsigned int *)
2319 cpl_table_get_data_int(aPixtable->
table,
"ifuslice");
2321 unsigned int last_ifu_slice = 0;
2322 int is_sorted = CPL_TRUE;
2323 for (i_row = 0; i_row < n_rows; i_row++) {
2324 slicedata[i_row] &= ifu_slice_mask;
2325 if (is_sorted && slicedata[i_row] < last_ifu_slice) {
2326 is_sorted = CPL_FALSE;
2328 last_ifu_slice = slicedata[i_row];
2332 cpl_propertylist *order = cpl_propertylist_new();
2333 cpl_propertylist_append_bool(order,
"ifuslice", CPL_FALSE);
2334 cpl_propertylist_append_bool(order, MUSE_PIXTABLE_LAMBDA, CPL_FALSE);
2335 cpl_msg_debug(__func__,
"sorting pixel table: quick sort, %"CPL_SIZE_FORMAT
2336 " entries", n_rows);
2337 cpl_table_sort(aPixtable->
table, order);
2338 cpl_propertylist_delete(order);
2340 cpl_propertylist_erase_regexp(aPixtable->
header, MUSE_HDR_PT_EXP_REGEXP, 0);
2341 cpl_msg_debug(__func__,
"pixel table sorted.");
2345 cpl_size n_col = cpl_table_get_ncol(aPixtable->
table);
2346 cpl_array *colnames = cpl_table_get_column_names(aPixtable->
table);
2348 cpl_size n_slices = 0;
2349 while (i_row < n_rows) {
2350 unsigned int ifu_slice = slicedata[i_row];
2352 for (j_row = i_row+1; j_row < n_rows && slicedata[j_row] == ifu_slice;
2355 cpl_size nrows_slice = j_row - i_row;
2357 slice_pixtable->
table = cpl_table_new(nrows_slice);
2359 for (i_col = 0; i_col < n_col; i_col++) {
2360 const char *cname = cpl_array_get_string(colnames, i_col);
2361 if (strcmp(cname,
"ifuslice") == 0)
2363 cpl_type ctype = cpl_table_get_column_type(aPixtable->
table, cname);
2364 if (ctype == CPL_TYPE_INT) {
2365 int *cdata = cpl_table_get_data_int(aPixtable->
table, cname);
2366 cpl_table_wrap_int(slice_pixtable->
table, cdata + i_row, cname);
2367 }
else if (ctype == CPL_TYPE_FLOAT) {
2368 float *cdata = cpl_table_get_data_float(aPixtable->
table, cname);
2369 cpl_table_wrap_float(slice_pixtable->
table, cdata + i_row, cname);
2370 }
else if (ctype == CPL_TYPE_DOUBLE) {
2371 double *cdata = cpl_table_get_data_double(aPixtable->
table, cname);
2372 cpl_table_wrap_double(slice_pixtable->
table, cdata + i_row, cname);
2373 }
else if (ctype == CPL_TYPE_STRING) {
2374 char **cdata = cpl_table_get_data_string(aPixtable->
table, cname);
2375 cpl_table_wrap_string(slice_pixtable->
table, cdata + i_row, cname);
2377 const char *unit = cpl_table_get_column_unit(aPixtable->
table, cname);
2378 cpl_table_set_column_unit(slice_pixtable->
table, cname, unit);
2381 slice_pixtable->
header = cpl_propertylist_duplicate(aPixtable->
header);
2383 slice_tables = cpl_realloc(slice_tables,
2385 slice_tables[n_slices] = slice_pixtable;
2387 slice_tables[n_slices] = NULL;
2390 cpl_array_delete(colnames);
2391 cpl_table_erase_column(aPixtable->
table,
"ifuslice");
2393 return slice_tables;
2411 cpl_ensure(aPixtables, CPL_ERROR_NULL_INPUT, -1);
2413 while (aPixtables[n] != NULL) {
2437 for (t = aPixtables; *t != NULL; t++) {
2438 cpl_array *colnames = cpl_table_get_column_names((*t)->table);
2439 cpl_size n_col = cpl_table_get_ncol((*t)->table);
2441 for (i_col = 0; i_col < n_col; i_col++) {
2442 const char *cname = cpl_array_get_string(colnames, i_col);
2443 cpl_table_unwrap((*t)->table, cname);
2445 cpl_array_delete(colnames);
2446 cpl_table_delete((*t)->table);
2447 cpl_propertylist_delete((*t)->header);
2450 cpl_free(aPixtables);
cpl_polynomial ** muse_trace_table_get_polys_for_slice(const cpl_table *aTable, const unsigned short aSlice)
construct polynomial from the trace table entry for the given slice
muse_pixtable_wcs
State of the astrometric calibration of a MUSE pixel table.
unsigned int muse_pixtable_get_expnum(muse_pixtable *aPixtable, cpl_size aRow)
Get the exposure number of a given row in a pixel table.
cpl_error_code muse_wave_table_get_orders(const cpl_table *aWave, unsigned short *aXOrder, unsigned short *aYOrder)
Determine the x- and y-order of the polynomial stored in a wavelength calibration table...
Structure definition for a collection of muse_images.
int muse_trace_table_get_order(const cpl_table *aTable)
determine order of tracing polynomial from table
#define MUSE_HDR_PT_EXP_FST
FITS header keyword defining the first row index for a given exposure.
void muse_pixtable_extracted_delete(muse_pixtable **aPixtables)
Delete a pixel table array.
cpl_polynomial * muse_wave_table_get_poly_for_slice(const cpl_table *aTable, const unsigned short aSlice)
Construct polynomial from the wavelength calibration table entry for the given slice.
const char * muse_pfits_get_extname(const cpl_propertylist *aHeaders)
find out the extension name
muse_pixtable * muse_pixtable_load(const char *aFilename)
Load the table itself and the FITS headers of a MUSE pixel table from a file.
unsigned short muse_pixtable_origin_get_slice(uint32_t aOrigin)
Get the slice number from the encoded 32bit origin number.
muse_pixtable * muse_pixtable_duplicate(muse_pixtable *aPixtable)
Make a copy of the pixtanle.
#define MUSE_HDR_PT_XLO
FITS header keyword contains the lower limit of the data in x-direction.
cpl_size muse_pixtable_extracted_get_size(muse_pixtable **aPixtables)
Get the size of an array of extracted pixel tables.
cpl_size muse_pixtable_get_nrow(muse_pixtable *aPixtable)
get the number of rows within the pixel table
unsigned int muse_pixtable_origin_set_offset(muse_pixtable *aPixtable, cpl_polynomial *aLTrace, unsigned short aIFU, unsigned short aSlice)
Set the slice offset from the pixel table header.
unsigned char muse_utils_get_ifu(const cpl_propertylist *aHeaders)
Find out the IFU/channel from which this header originated.
#define MUSE_HDR_PT_FLUXCAL
muse_pixtable ** muse_pixtable_extracted_get_slices(muse_pixtable *aPixtable)
Extract one pixel table per IFU and slice.
cpl_image * data
the data extension
#define MUSE_HDR_PT_LHI
FITS header keyword contains the upper limit of the data in spectral direction.
#define MUSE_HDR_PT_ILO
FITS header keyword contains the lowest IFU number in the data.
int muse_pixtable_get_type(muse_pixtable *aPixtable)
Determine the type of pixel table.
#define MUSE_HDR_PT_EXP_LST
FITS header keyword defining the last row index for a given exposure.
cpl_error_code muse_pixtable_and_selected_mask(muse_pixtable *aPixtable, muse_mask *aMask)
Select all pixels where the (x,y) positions are enabled in the given mask.
cpl_error_code muse_pixtable_dump(muse_pixtable *aPixtable, cpl_size aStart, cpl_size aCount, unsigned char aDisplayHeader)
Dump a MUSE pixel table to the screen, resolving the origin column.
cpl_image * stat
the statistics extension
#define MUSE_HDR_PT_TYPE
Pixel table "type" stored in the FITS header.
#define MUSE_HDR_PT_MERGED
Structure definition of MUSE three extension FITS file.
cpl_table * table
The pixel table.
cpl_propertylist * header
the FITS header
cpl_error_code muse_pixtable_origin_copy_offsets(muse_pixtable *aOut, muse_pixtable *aFrom, unsigned int aNum)
Copy MUSE_HDR_PT_IFU_SLICE_OFFSET keywords between pixel tables.
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.
unsigned int muse_imagelist_get_size(muse_imagelist *aList)
Return the number of stored images.
muse_imagelist * muse_pixtable_to_imagelist(muse_pixtable *aPixtable)
Project a pixel table with data from one IFU back onto its image.
void muse_trace_polys_delete(cpl_polynomial *aPolys[])
Delete the multi-polynomial array created in relation to tracing.
#define MUSE_HDR_PT_SHI
FITS header keyword contains the highest slice number in the data.
cpl_image * dq
the data quality extension
cpl_error_code muse_pixtable_restrict_wavelength(muse_pixtable *aPixtable, double aLow, double aHigh)
Restrict a pixel table to a certain wavelength range.
cpl_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
cpl_boolean muse_pixtable_is_skysub(muse_pixtable *aPixtable)
Determine whether the pixel table is sky subtracted.
unsigned int muse_pixtable_origin_get_x(uint32_t aOrigin, muse_pixtable *aPixtable, cpl_size aRow)
Get the horizontal coordinate from the encoded 32bit origin number.
Structure definition of MUSE pixel table.
#define MUSE_HDR_PT_IFU_SLICE_OFFSET
FITS header keyword for the horizontal slice offset on the CCD.
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.
#define MUSE_HDR_PT_YLO
FITS header keyword contains the lower limit of the data in y-direction.
#define MUSE_HDR_PT_SKYSUB
cpl_boolean muse_pixtable_is_fluxcal(muse_pixtable *aPixtable)
Determine whether the pixel table is flux calibrated.
#define MUSE_HDR_PT_IHI
FITS header keyword contains the highest IFU number in the data.
unsigned int muse_pixtable_origin_get_offset(muse_pixtable *aPixtable, unsigned int aExpNum, unsigned short aIFU, unsigned short aSlice)
Get the slice offset from the pixel table header.
uint32_t muse_pixtable_origin_encode(unsigned int aX, unsigned int aY, unsigned short aIFU, unsigned short aSlice, unsigned int aOffset)
Encode the three CCD coordinates defining the origin of one MUSE pixel into a 32bit integer...
muse_pixtable * muse_pixtable_load_window(const char *aFilename, cpl_size aStart, cpl_size aNRows)
Load a range of rows from the table and all the FITS headers of a MUSE pixel table from a file...
muse_pixtable * muse_pixtable_create(muse_image *aImage, cpl_table *aTrace, cpl_table *aWave, cpl_table *aGeoTable)
Create the pixel table for one CCD.
muse_pixtable * muse_pixtable_load_restricted_wavelength(const char *aFilename, double aLambdaMin, double aLambdaMax)
Load a pixel table from file and cut down the wavelength range.
cpl_error_code muse_cplpropertylist_update_long_long(cpl_propertylist *aHeader, const char *aKeyword, cpl_size aValue)
Update an integer-like property irrespective of the real type.
#define MUSE_HDR_PT_LLO
FITS header keyword contains the lower limit of the data in spectral direction.
cpl_error_code muse_pixtable_save(muse_pixtable *aPixtable, const char *aFilename)
Save a MUSE pixel table to a file on disk.
unsigned short muse_pixtable_origin_get_ifu(uint32_t aOrigin)
Get the IFU number from the encoded 32bit origin number.
muse_pixtable * muse_pixtable_load_merge_channels(cpl_table *aExposureList, double aLambdaMin, double aLambdaMax)
Load and merge the pixel tables of the 24 MUSE sub-fields.
cpl_error_code muse_pixtable_restrict_xpos(muse_pixtable *aPixtable, double aLo, double aHi)
Restrict a pixel table to a certain x coordinate range.
cpl_error_code muse_pixtable_from_imagelist(muse_pixtable *aPixtable, muse_imagelist *aList)
Get pixel table values back from a per-IFU imagelist.
Handling of "mask" files.
muse_imagelist * muse_imagelist_new(void)
Create a new (empty) MUSE image list.
const muse_cpltable_def muse_pixtable_def[]
MUSE pixel table definition.
cpl_table * muse_geo_table_extract_ifu(const cpl_table *aTable, const unsigned char aIFU)
Extract the part of a geometry table dealing with a given IFU.
#define MUSE_HDR_PT_SLO
FITS header keyword contains the lowest slice number in the data.
cpl_propertylist * header
the FITS header
Definition of a cpl table structure.
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
unsigned int muse_pixtable_origin_get_y(uint32_t aOrigin)
Get the vertical coordinate from the encoded 32bit origin number.
cpl_mask * mask
The mask data.
void muse_pixtable_delete(muse_pixtable *aPixtable)
Deallocate memory associated to a pixel table object.
cpl_error_code muse_pixtable_restrict_ypos(muse_pixtable *aPixtable, double aLo, double aHi)
Restrict a pixel table to a certain y coordinate range.
#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.
static cpl_error_code muse_pixtable_fix_exp_headers(muse_pixtable *aPixtable)
Fix the exposure ranges in the header of a pixel table.
cpl_propertylist * header
The FITS header.
#define MUSE_HDR_PT_XHI
FITS header keyword contains the upper limit of the data in x-ion.