00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 #include <config.h>
00024 #endif
00025
00026
00027
00028
00029 #include <cpl.h>
00030 #include <math.h>
00031 #include <string.h>
00032
00033 #include "muse_pixtable.h"
00034 #include "muse_instrument.h"
00035
00036 #include "muse_cplwrappers.h"
00037 #include "muse_geo.h"
00038 #include "muse_mask.h"
00039 #include "muse_pfits.h"
00040 #include "muse_quadrants.h"
00041 #include "muse_quality.h"
00042 #include "muse_tracing.h"
00043 #include "muse_wavecalib.h"
00044 #include "muse_wcs.h"
00045 #include "muse_utils.h"
00046
00047
00048
00049
00050
00051 #define CREATE_MINIMAL_PIXTABLE 0
00052 #define PIXTABLE_CREATE_CCDSIZED 1
00053 #define DEBUG_PIXTABLE_CREATION 0
00054 #define DEBUG_PIXTABLE_FEW_SLICES 0
00055
00056
00057
00095
00096
00099
00100 #define MUSE_ORIGIN_SHIFT_XSLICE 24
00101 #define MUSE_ORIGIN_SHIFT_YPIX 11
00102 #define MUSE_ORIGIN_SHIFT_IFU 6
00103
00104
00105
00106 #define MUSE_ORIGIN_SLICE_SAFETY_OFFSET -20
00107
00108
00110 static inline uint32_t
00111 muse_pixtable_origin_encode_fast(unsigned int aX, unsigned int aY,
00112 unsigned short aIFU,
00113 unsigned short aSlice, unsigned int aOffset)
00114 {
00115 return ((aX - aOffset) << MUSE_ORIGIN_SHIFT_XSLICE)
00116 | (aY << MUSE_ORIGIN_SHIFT_YPIX)
00117 | (aIFU << MUSE_ORIGIN_SHIFT_IFU)
00118 | aSlice;
00119 }
00120
00122 static inline unsigned int
00123 muse_pixtable_origin_get_x_fast(uint32_t aOrigin, uint32_t aOffset)
00124 {
00125 return ((aOrigin >> MUSE_ORIGIN_SHIFT_XSLICE) & 0x7f) + aOffset;
00126 }
00127
00129 static inline unsigned int
00130 muse_pixtable_origin_get_y_fast(uint32_t aOrigin)
00131 {
00132 return (aOrigin >> MUSE_ORIGIN_SHIFT_YPIX) & 0x1fff;
00133 }
00134
00136 static inline unsigned short
00137 muse_pixtable_origin_get_ifu_fast(uint32_t aOrigin)
00138 {
00139 return (aOrigin >> MUSE_ORIGIN_SHIFT_IFU) & 0x1f;
00140 }
00141
00143 static inline unsigned short
00144 muse_pixtable_origin_get_slice_fast(uint32_t aOrigin)
00145 {
00146 return aOrigin & 0x3f;
00147 }
00148
00149
00165
00166 uint32_t
00167 muse_pixtable_origin_encode(unsigned int aX, unsigned int aY,
00168 unsigned short aIFU,
00169 unsigned short aSlice, unsigned int aOffset)
00170
00171
00172 {
00173
00174 cpl_ensure(aX < 8192 && aX > 0 && aY < 8192 && aY > 0 &&
00175 aIFU <= kMuseNumIFUs && aIFU >= 1 &&
00176 aSlice <= kMuseSlicesPerCCD && aSlice >= 1 && aOffset < 8192,
00177 CPL_ERROR_ILLEGAL_INPUT, 0);
00178
00179 #if 0
00180 cpl_msg_debug(__func__, "origin (%d, %d, %d, %d, %d) = 0x%x",
00181 aX, aY, aIFU, aSlice, aOffset,
00182 ((aX - aOffset) << MUSE_ORIGIN_SHIFT_XSLICE)
00183 | (aY << MUSE_ORIGIN_SHIFT_YPIX)
00184 | (aIFU << MUSE_ORIGIN_SHIFT_IFU)
00185 | aSlice);
00186 #endif
00187
00188
00189 return muse_pixtable_origin_encode_fast(aX, aY, aIFU, aSlice, aOffset);
00190 }
00191
00192
00210
00211 unsigned int
00212 muse_pixtable_origin_get_x(uint32_t aOrigin, muse_pixtable *aPixtable,
00213 cpl_size aRow)
00214 {
00215 unsigned short slice = muse_pixtable_origin_get_slice_fast(aOrigin),
00216 ifu = muse_pixtable_origin_get_ifu_fast(aOrigin);
00217 cpl_errorstate prestate = cpl_errorstate_get();
00218 unsigned int expnum = muse_pixtable_get_expnum(aPixtable, aRow);
00219 if (!cpl_errorstate_is_equal(prestate)) {
00220 cpl_errorstate_set(prestate);
00221 }
00222 unsigned int offset = muse_pixtable_origin_get_offset(aPixtable, expnum, ifu,
00223 slice),
00224 x = muse_pixtable_origin_get_x_fast(aOrigin, offset);
00225 #if 0
00226 if (x > 8191 || x < 1 || !cpl_errorstate_is_equal(prestate)) {
00227 cpl_msg_error(__func__, "aOrigin=%#x x=%d (%d %d %d), %s",
00228 aOrigin, x, slice, ifu, offset, cpl_error_get_message());
00229 }
00230 #endif
00231 cpl_ensure(x <= 8191 && x >= 1 && cpl_errorstate_is_equal(prestate),
00232 CPL_ERROR_ILLEGAL_OUTPUT, 0);
00233 return x;
00234 }
00235
00236
00244
00245 unsigned int
00246 muse_pixtable_origin_get_y(uint32_t aOrigin)
00247 {
00248 unsigned int y = muse_pixtable_origin_get_y_fast(aOrigin);
00249 #if 0
00250 if (y > 8191 || y < 1) {
00251 cpl_msg_error(__func__, "aOrigin=%#x y=%d", aOrigin, y);
00252 }
00253 #endif
00254 cpl_ensure(y <= 8191 && y >= 1, CPL_ERROR_ILLEGAL_OUTPUT, 0);
00255 return y;
00256 }
00257
00258
00266
00267 unsigned short
00268 muse_pixtable_origin_get_ifu(uint32_t aOrigin)
00269 {
00270 unsigned short ifu = muse_pixtable_origin_get_ifu_fast(aOrigin);
00271 #if 0
00272 if (ifu > kMuseNumIFUs || ifu < 1) {
00273 cpl_msg_error(__func__, "aOrigin=%#x ifu=%d", aOrigin, ifu);
00274 }
00275 #endif
00276 cpl_ensure(ifu <= kMuseNumIFUs && ifu >= 1, CPL_ERROR_ILLEGAL_OUTPUT, 0);
00277 return ifu;
00278 }
00279
00280
00288
00289 unsigned short
00290 muse_pixtable_origin_get_slice(uint32_t aOrigin)
00291 {
00292 unsigned short slice = muse_pixtable_origin_get_slice_fast(aOrigin);
00293 #if 0
00294 if (slice > kMuseSlicesPerCCD || slice < 1) {
00295 cpl_msg_error(__func__, "aOrigin=%#x slice=%d", aOrigin, slice);
00296 }
00297 #endif
00298 cpl_ensure(slice <= kMuseSlicesPerCCD && slice >= 1,
00299 CPL_ERROR_ILLEGAL_OUTPUT, 0);
00300 return slice;
00301 }
00302
00303
00318
00319 unsigned int
00320 muse_pixtable_origin_set_offset(muse_pixtable *aPixtable,
00321 cpl_polynomial *aLTrace,
00322 unsigned short aIFU, unsigned short aSlice)
00323 {
00324 cpl_ensure(aPixtable && aPixtable->header, CPL_ERROR_NULL_INPUT, 0);
00325 cpl_errorstate prestate = cpl_errorstate_get();
00326 unsigned int offset = floor(cpl_polynomial_eval_1d(aLTrace, 1, NULL))
00327 + MUSE_ORIGIN_SLICE_SAFETY_OFFSET;
00328 cpl_ensure(cpl_errorstate_is_equal(prestate), cpl_error_get_code(), 0);
00329
00330
00331 char *keyword = cpl_sprintf(MUSE_HDR_PT_IFU_SLICE_OFFSET, 0, aIFU, aSlice);
00332 cpl_propertylist_update_int(aPixtable->header, keyword, offset);
00333 cpl_propertylist_set_comment(aPixtable->header, keyword,
00334 MUSE_HDR_PT_IFU_SLICE_OFFSET_COMMENT);
00335 cpl_free(keyword);
00336 return offset;
00337 }
00338
00339
00353
00354 unsigned int
00355 muse_pixtable_origin_get_offset(muse_pixtable *aPixtable, unsigned int aExpNum,
00356 unsigned short aIFU, unsigned short aSlice)
00357 {
00358 cpl_ensure(aPixtable && aPixtable->header, CPL_ERROR_NULL_INPUT, 0);
00359 char *keyword = cpl_sprintf(MUSE_HDR_PT_IFU_SLICE_OFFSET, aExpNum, aIFU,
00360 aSlice);
00361 cpl_errorstate prestate = cpl_errorstate_get();
00362 unsigned int offset = cpl_propertylist_get_int(aPixtable->header, keyword);
00363 cpl_free(keyword);
00364 #if 0
00365 if (offset > 8191 || offset < 1) {
00366 cpl_msg_error(__func__, "aIFU=%d aSlice=%d offset=%d",
00367 aIFU, aSlice, offset);
00368 }
00369 #endif
00370 cpl_ensure(offset <= 8191 && offset >= 1 && cpl_errorstate_is_equal(prestate),
00371 CPL_ERROR_ILLEGAL_OUTPUT, 0);
00372 return offset;
00373 }
00374
00375
00395
00396 cpl_error_code
00397 muse_pixtable_origin_copy_offsets(muse_pixtable *aOut, muse_pixtable *aFrom,
00398 unsigned int aNum)
00399 {
00400 cpl_ensure_code(aOut && aOut->header, CPL_ERROR_NULL_INPUT);
00401 cpl_propertylist *dest = aOut->header,
00402 *from = aOut->header;
00403 if (aFrom && aFrom->header) {
00404 from = aFrom->header;
00405 }
00406 char keyword[KEYWORD_LENGTH];
00407 unsigned short nifu, nslice;
00408 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
00409 for (nslice = 1; nslice <= kMuseSlicesPerCCD; nslice++) {
00410
00411 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_PT_IFU_SLICE_OFFSET,
00412 0, nifu, nslice);
00413 cpl_errorstate prestate = cpl_errorstate_get();
00414 unsigned int offset = cpl_propertylist_get_int(from, keyword);
00415 if (!cpl_errorstate_is_equal(prestate)) {
00416
00417 cpl_errorstate_set(prestate);
00418 continue;
00419 }
00420
00421 cpl_propertylist_erase(from, keyword);
00422
00423 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_PT_IFU_SLICE_OFFSET,
00424 aNum, nifu, nslice);
00425 cpl_propertylist_update_int(dest, keyword, offset);
00426 cpl_propertylist_set_comment(dest, keyword,
00427 MUSE_HDR_PT_IFU_SLICE_OFFSET_COMMENT);
00428 }
00429 }
00430
00431 return CPL_ERROR_NONE;
00432 }
00433
00434
00449
00450 unsigned int
00451 muse_pixtable_get_expnum(muse_pixtable *aPixtable, cpl_size aRow)
00452 {
00453 cpl_ensure(aPixtable && aPixtable->header, CPL_ERROR_NULL_INPUT, 0);
00454 cpl_ensure(aRow >= 0 && muse_pixtable_get_nrow(aPixtable) > aRow,
00455 CPL_ERROR_ILLEGAL_INPUT, 0);
00456
00457 char keyword[KEYWORD_LENGTH];
00458 unsigned int exposure = 0;
00459 cpl_size lo = 0, hi = 0;
00460 do {
00461 cpl_errorstate prestate = cpl_errorstate_get();
00462 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_PT_EXP_FST, ++exposure);
00463 lo = cpl_propertylist_get_long_long(aPixtable->header, keyword);
00464 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_PT_EXP_LST, exposure);
00465 hi = cpl_propertylist_get_long_long(aPixtable->header, keyword);
00466 if (!cpl_errorstate_is_equal(prestate)) {
00467 if (exposure == 1) {
00468
00469
00470 lo = hi = aRow;
00471 exposure = 0;
00472 }
00473 cpl_errorstate_set(prestate);
00474 break;
00475 }
00476 } while (hi < aRow);
00477 cpl_ensure(lo <= aRow && hi >= aRow, CPL_ERROR_ILLEGAL_OUTPUT, 0);
00478 return exposure;
00479 }
00480
00481
00501
00502 const muse_cpltable_def muse_pixtable_def[] = {
00503 { MUSE_PIXTABLE_XPOS, CPL_TYPE_FLOAT, "pix", "%7.2f",
00504 "relative x-pixel position in the output datacube", CPL_TRUE},
00505 { MUSE_PIXTABLE_YPOS, CPL_TYPE_FLOAT, "pix", "%7.2f",
00506 "relative y-pixel position in the output datacube", CPL_TRUE},
00507 { MUSE_PIXTABLE_LAMBDA, CPL_TYPE_FLOAT, "Angstrom", "%8.2f",
00508 "wavelength of this pixel", CPL_TRUE},
00509 { MUSE_PIXTABLE_DATA, CPL_TYPE_FLOAT, "count", "%e",
00510 "data value in this pixel", CPL_TRUE},
00511 { MUSE_PIXTABLE_DQ, CPL_TYPE_INT, NULL, "%#x",
00512 "Euro3D bad pixel status of this pixel", CPL_TRUE},
00513 { MUSE_PIXTABLE_STAT, CPL_TYPE_FLOAT, "count**2", "%e",
00514 "data variance of this pixel", CPL_TRUE},
00515 { MUSE_PIXTABLE_ORIGIN, CPL_TYPE_INT, NULL, "0x%08x",
00516 "encoded value of IFU and slice number, as well as x and y "
00517 "position in the raw (trimmed) data", CPL_TRUE},
00518 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
00519 };
00520
00521
00567
00568 muse_pixtable *
00569 muse_pixtable_create(muse_image *aImage, cpl_table *aTrace, cpl_table *aWave,
00570 cpl_table *aGeoTable)
00571 {
00572 cpl_ensure(aImage && aWave && aTrace, CPL_ERROR_NULL_INPUT, NULL);
00573
00574 unsigned char ifu = muse_utils_get_ifu(aImage->header);
00575 cpl_ensure(ifu >= 1 && ifu <= kMuseNumIFUs, CPL_ERROR_DATA_NOT_FOUND, NULL);
00576
00577
00578 if (!cpl_propertylist_has(aImage->header, "BUNIT")) {
00579 char *msg = cpl_sprintf("Input data of IFU %hhu does not contain a data "
00580 "unit (\"BUNIT\"), cannot proceed!", ifu);
00581 cpl_msg_error(__func__, "%s", msg);
00582 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT, "%s", msg);
00583 cpl_free(msg);
00584 return NULL;;
00585 }
00586 const char *unit = muse_pfits_get_bunit(aImage->header);
00587 if (strncmp(unit, "count", 6)) {
00588 char *msg = cpl_sprintf("Input data of IFU %hhu is not in \"count\" units "
00589 "but in \"%s\", not suitable for a new pixel table!",
00590 ifu, unit);
00591 cpl_msg_error(__func__, "%s", msg);
00592 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT, "%s", msg);
00593 cpl_free(msg);
00594 return NULL;
00595 }
00596
00597
00598 muse_pixtable *pt = cpl_calloc(1, sizeof(muse_pixtable));
00599
00600 int xsize = cpl_image_get_size_x(aImage->data),
00601 ysize = cpl_image_get_size_y(aImage->data),
00602 #if PIXTABLE_CREATE_CCDSIZED
00603
00604
00605 isize = xsize * ysize;
00606 #else
00607
00608
00609 isize = ysize * kMuseSlicesPerCCD * kMuseSliceHiLikelyWidth;
00610 #endif
00611 pt->table = muse_cpltable_new(muse_pixtable_def, isize);
00612
00613
00614
00615 pt->header = cpl_propertylist_duplicate(aImage->header);
00616 cpl_propertylist_erase_regexp(pt->header,
00617 "^SIMPLE$|^BITPIX$|^NAXIS|^EXTEND$|^XTENSION$|"
00618 "^DATASUM$|^DATAMIN$|^DATAMAX$|^DATAMD5$|"
00619 "^PCOUNT$|^GCOUNT$|^HDUVERS$|^BLANK$|"
00620 "^BZERO$|^BSCALE$|^BUNIT$|^CHECKSUM$|^INHERIT$|"
00621 MUSE_HDR_OVSC_REGEXP"|"MUSE_WCS_KEYS, 0);
00622 cpl_propertylist_append_string(pt->header, MUSE_HDR_PT_TYPE,
00623 aGeoTable ? MUSE_PIXTABLE_STRING_FULL
00624 : MUSE_PIXTABLE_STRING_SIMPLE);
00625 cpl_propertylist_set_comment(pt->header, MUSE_HDR_PT_TYPE,
00626 aGeoTable ? MUSE_PIXTABLE_COMMENT_FULL
00627 : MUSE_PIXTABLE_COMMENT_SIMPLE);
00628
00629
00630
00631
00632 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_XPOS, 0, isize, 0);
00633 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_YPOS, 0, isize, 0);
00634 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_LAMBDA, 0, isize, 0);
00635 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_DATA, 0, isize, 0);
00636 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_STAT, 0, isize, 0);
00637 cpl_table_fill_column_window_int(pt->table, MUSE_PIXTABLE_DQ, 0, isize, 0);
00638 cpl_table_fill_column_window_int(pt->table, MUSE_PIXTABLE_ORIGIN, 0, isize, 0);
00639
00640
00641 float *cdata_xpos = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_XPOS),
00642 *cdata_ypos = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_YPOS),
00643 *cdata_lambda = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_LAMBDA),
00644 *cdata_data = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_DATA),
00645 *cdata_stat = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_STAT);
00646 int *cdata_dq = cpl_table_get_data_int(pt->table, MUSE_PIXTABLE_DQ);
00647 uint32_t *cdata_origin = (uint32_t *)cpl_table_get_data_int(pt->table,
00648 MUSE_PIXTABLE_ORIGIN);
00649
00650
00651 const float *pixdata = cpl_image_get_data_float_const(aImage->data),
00652 *pixstat = cpl_image_get_data_float_const(aImage->stat);
00653 const int *pixdq = cpl_image_get_data_int_const(aImage->dq);
00654
00655
00656 unsigned short wavexorder, waveyorder;
00657 muse_wave_table_get_orders(aWave, &wavexorder, &waveyorder);
00658 cpl_msg_info(__func__, "Creating pixel table for IFU %hhu, using order %d for "
00659 "trace solution and orders %hu/%hu for wavelength solution", ifu,
00660 muse_trace_table_get_order(aTrace), wavexorder, waveyorder);
00661
00662
00663 cpl_table *geopos = NULL;
00664 double *slice_x = NULL, *slice_y = NULL, *slice_angle = NULL,
00665 *slice_width = NULL;
00666 if (aGeoTable) {
00667 geopos = muse_geo_table_extract_ifu(aGeoTable, ifu);
00668 slice_x = cpl_table_get_data_double(geopos, MUSE_GEOTABLE_X);
00669 slice_y = cpl_table_get_data_double(geopos, MUSE_GEOTABLE_Y);
00670
00671 if (!geopos || !slice_x || !slice_y) {
00672 char *msg = !geopos
00673 ? cpl_sprintf("Geometry table is missing data for IFU %hhu!", ifu)
00674 : cpl_sprintf("Geometry table is missing column%s%s%s!",
00675 !slice_x && !slice_y ? "s" : "",
00676 slice_x ? "" : " \""MUSE_GEOTABLE_X"\"",
00677 slice_y ? "" : " \""MUSE_GEOTABLE_Y"\"");
00678 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT, "%s", msg);
00679 cpl_msg_error(__func__, "%s", msg);
00680 cpl_free(msg);
00681 cpl_table_delete(geopos);
00682 muse_pixtable_delete(pt);
00683 return NULL;
00684 }
00685
00686
00687 cpl_errorstate prestate = cpl_errorstate_get();
00688 slice_angle = cpl_table_get_data_double(geopos, MUSE_GEOTABLE_ANGLE);
00689 slice_width = cpl_table_get_data_double(geopos, MUSE_GEOTABLE_WIDTH);
00690 if (!cpl_errorstate_is_equal(prestate)) {
00691 char *msg = cpl_sprintf("Geometry table is missing column%s%s%s!",
00692 !slice_angle && !slice_width ? "s" : "",
00693 slice_angle ? "" : " \""MUSE_GEOTABLE_ANGLE"\"",
00694 slice_width ? "" : " \""MUSE_GEOTABLE_WIDTH"\"");
00695 cpl_error_set_message(__func__, CPL_ERROR_BAD_FILE_FORMAT, "%s", msg);
00696 cpl_msg_error(__func__, "%s", msg);
00697 cpl_free(msg);
00698 if (!getenv("MUSE_EXPERT_USER")) {
00699 cpl_table_delete(geopos);
00700 muse_pixtable_delete(pt);
00701 return NULL;
00702 }
00703 }
00704 }
00705
00706
00707 cpl_size itablerow = 0;
00708
00709 double cputime = cpl_test_get_cputime(),
00710 walltime = cpl_test_get_walltime();
00711
00712 int islice;
00713 #if DEBUG_PIXTABLE_FEW_SLICES > 0
00714 # define SLICE_LIMIT DEBUG_PIXTABLE_FEW_SLICES
00715 #else
00716 # define SLICE_LIMIT kMuseSlicesPerCCD
00717 #endif
00718 for (islice = 0; islice < SLICE_LIMIT; islice++) {
00719 #if DEBUG_PIXTABLE_CREATION
00720 cpl_msg_debug(__func__, "Starting to process slice %2d of IFU %2hhu",
00721 islice + 1, ifu);
00722 #endif
00723
00724
00725 cpl_polynomial *pwave = muse_wave_table_get_poly_for_slice(aWave, islice + 1);
00726
00727
00728 cpl_vector *pos = cpl_vector_new(2);
00729
00730
00731 cpl_vector_set(pos, 0, kMuseOutputYTop / 2);
00732 cpl_vector_set(pos, 1, kMuseOutputYTop / 2);
00733 double ltest = cpl_polynomial_eval(pwave, pos);
00734 if (!pwave || !isnormal(ltest) || fabs(ltest) < DBL_EPSILON) {
00735 char *msg = cpl_sprintf("Wavelength calibration polynomial for slice %d "
00736 "of IFU %hhu is not well defined!", islice + 1,
00737 ifu);
00738 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT, "%s", msg);
00739 cpl_msg_error(__func__, "%s", msg);
00740 cpl_free(msg);
00741 cpl_polynomial_delete(pwave);
00742 cpl_vector_delete(pos);
00743 if (getenv("MUSE_EXPERT_USER")) {
00744 continue;
00745 } else {
00746 cpl_table_delete(geopos);
00747 muse_pixtable_delete(pt);
00748 return NULL;
00749 }
00750 }
00751
00752
00753 cpl_polynomial **ptrace = muse_trace_table_get_polys_for_slice(aTrace,
00754 islice + 1);
00755 if (!ptrace) {
00756 char *msg = cpl_sprintf("Tracing polynomials for slice %d of IFU %hhu are"
00757 " not well defined!", islice + 1, ifu);
00758 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT, "%s", msg);
00759 cpl_msg_error(__func__, "%s", msg);
00760 cpl_free(msg);
00761 cpl_polynomial_delete(pwave);
00762 cpl_vector_delete(pos);
00763 if (getenv("MUSE_EXPERT_USER")) {
00764 continue;
00765 } else {
00766 cpl_table_delete(geopos);
00767 muse_pixtable_delete(pt);
00768 return NULL;
00769 }
00770 }
00771 unsigned offset = muse_pixtable_origin_set_offset(pt,
00772 ptrace[MUSE_TRACE_LEFT],
00773 ifu, islice + 1);
00774
00775
00776 int j;
00777 for (j = 1; j <= ysize; j++) {
00778
00779
00780 double x1 = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_LEFT], j, NULL),
00781 x2 = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_RIGHT], j, NULL),
00782 xcenter = (x1 + x2) / 2.,
00783 width = x2 - x1;
00784 if (!isnormal(x1) || !isnormal(x2) || x1 < 1 || x2 > xsize || x1 > x2) {
00785 cpl_msg_warning(__func__, "slice %2d of IFU %hhu: faulty polynomial "
00786 "detected at y=%d (borders: %f ... %f)", islice + 1,
00787 ifu, j, x1, x2);
00788 break;
00789 }
00790
00791 int ileft = ceil(x1),
00792 iright = floor(x2);
00793 cpl_vector_set(pos, 1, j);
00794
00795
00796 int i;
00797 for (i = ileft; i <= iright; i++) {
00798 cpl_vector_set(pos, 0, i);
00799
00800
00801
00802 double lambda = cpl_polynomial_eval(pwave, pos);
00803 if (lambda < 3000. || lambda > 11000. || !isfinite(lambda)) {
00804 continue;
00805 }
00806
00807
00808
00809
00810
00811
00812
00813
00814 float dx = (xcenter - i) / width
00815 * (slice_width ? slice_width[islice] : kMuseSliceNominalWidth);
00816 #if DEBUG_PIXTABLE_CREATION
00817 if (fabs(dx) > 37.5) {
00818 cpl_msg_debug(__func__, "%d - %f -> %f", i, xcenter, dx);
00819 }
00820 #endif
00821
00822 #if CREATE_MINIMAL_PIXTABLE
00823
00824 if (lambda < 6495. || lambda > 6505. || fabs(dx) > 10.) {
00825 continue;
00826 }
00827 #endif
00828
00829
00830 cpl_size irow = itablerow++;
00831 #if !PIXTABLE_CREATE_CCDSIZED
00832 if (irow + 1 > (cpl_size)muse_pixtable_get_nrow(pt)) {
00833 #if DEBUG_PIXTABLE_CREATION
00834 printf("pixel table before enlargement:\n");
00835 cpl_table_dump(pt->table, irow-5, 10, stdout);
00836 fflush(stdout);
00837 #endif
00838
00839
00840
00841 const cpl_size nr = 1000000;
00842 cpl_msg_debug(__func__, "expand table to %"CPL_SIZE_FORMAT" rows "
00843 "(add %"CPL_SIZE_FORMAT" lines)!", irow + nr, nr);
00844 cpl_table_set_size(pt->table, irow + nr);
00845
00846
00847 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_XPOS, irow, nr, 0);
00848 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_YPOS, irow, nr, 0);
00849 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_LAMBDA, irow, nr, 0);
00850 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_DATA, irow, nr, 0);
00851 cpl_table_fill_column_window_float(pt->table, MUSE_PIXTABLE_STAT, irow, nr, 0);
00852 cpl_table_fill_column_window_int(pt->table, MUSE_PIXTABLE_DQ, irow, nr, 0);
00853 cpl_table_fill_column_window_int(pt->table, MUSE_PIXTABLE_ORIGIN, irow, nr, 0);
00854
00855
00856 cdata_xpos = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_XPOS);
00857 cdata_ypos = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_YPOS);
00858 cdata_lambda = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_LAMBDA);
00859 cdata_data = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_DATA);
00860 cdata_stat = cpl_table_get_data_float(pt->table, MUSE_PIXTABLE_STAT);
00861 cdata_dq = cpl_table_get_data_int(pt->table, MUSE_PIXTABLE_DQ);
00862 cdata_origin = (uint32_t *)cpl_table_get_data_int(pt->table,
00863 MUSE_PIXTABLE_ORIGIN);
00864 #if DEBUG_PIXTABLE_CREATION
00865 printf("pixel table after filling new rows:\n");
00866 cpl_table_dump(pt->table, irow-5, 10, stdout);
00867 fflush(stdout);
00868 #endif
00869 }
00870 #endif
00871
00872
00873 double angle = slice_angle ? slice_angle[islice] * CPL_MATH_RAD_DEG
00874 : 0.;
00875 cdata_xpos[irow] = aGeoTable
00876 ? dx * cos(angle) + slice_x[islice]
00877 : dx + islice * kMuseSliceHiLikelyWidth
00878 + kMuseSliceHiLikelyWidth / 2.;
00879 cdata_ypos[irow] = aGeoTable
00880 ? dx * sin(angle) + slice_y[islice]
00881 : 0.;
00882 #if DEBUG_PIXTABLE_CREATION
00883 if (!isfinite(cdata_xpos[irow]) ||
00884 cdata_xpos[irow] < -200 || cdata_xpos[irow] > 4000) {
00885 cpl_msg_debug(__func__, "weird data in x: %e %e",
00886 cdata_xpos[irow], cdata_ypos[irow]);
00887 }
00888 if (!isfinite(cdata_ypos[irow]) ||
00889 cdata_ypos[irow] < -200 || cdata_ypos[irow] > 200) {
00890 cpl_msg_debug(__func__, "weird data in y: %e %e",
00891 cdata_xpos[irow], cdata_ypos[irow]);
00892 }
00893 #endif
00894 cdata_lambda[irow] = lambda;
00895
00896
00897 cdata_data[irow] = pixdata[(i-1) + (j-1)*xsize];
00898 cdata_dq[irow] = pixdq[(i-1) + (j-1)*xsize];
00899 cdata_stat[irow] = pixstat[(i-1) + (j-1)*xsize];
00900
00901 cdata_origin[irow] = muse_pixtable_origin_encode_fast(i, j, ifu,
00902 islice + 1,
00903 offset);
00904 }
00905 }
00906
00907
00908 muse_trace_polys_delete(ptrace);
00909 cpl_polynomial_delete(pwave);
00910 cpl_vector_delete(pos);
00911 }
00912 cpl_table_delete(geopos);
00913 cpl_msg_debug(__func__, "IFU %hhu took %gs (CPU time), %gs (wall-clock)",
00914 ifu, cpl_test_get_cputime() - cputime,
00915 cpl_test_get_walltime() - walltime);
00916
00917
00918 if (muse_pixtable_get_nrow(pt) > itablerow) {
00919 cpl_msg_debug(__func__, "Trimming pixel table of IFU %hhu to %"CPL_SIZE_FORMAT
00920 " of %"CPL_SIZE_FORMAT" rows", ifu, itablerow,
00921 muse_pixtable_get_nrow(pt));
00922 #if DEBUG_PIXTABLE_CREATION
00923 printf("end of used part of pixel table before trimming:\n");
00924 cpl_table_dump(pt->table, itablerow-5, 10, stdout);
00925 fflush(stdout);
00926 #endif
00927 cpl_table_set_size(pt->table, itablerow);
00928 }
00929
00930
00931 muse_pixtable_compute_limits(pt);
00932 #if DEBUG_PIXTABLE_CREATION
00933 printf("beginning of pixel table before returning:\n");
00934 cpl_table_dump(pt->table, 0, 5, stdout);
00935 fflush(stdout);
00936 printf("end of pixel table before returning:\n");
00937 cpl_table_dump(pt->table, muse_pixtable_get_nrow(pt)-5, 10, stdout);
00938 fflush(stdout);
00939 #endif
00940
00941 return pt;
00942 }
00943
00944
00957
00958 muse_pixtable *
00959 muse_pixtable_duplicate(muse_pixtable *aPixtable)
00960 {
00961 if (aPixtable == NULL) {
00962 return NULL;
00963 }
00964 muse_pixtable *pt = cpl_calloc(1, sizeof(muse_pixtable));
00965 pt->table = cpl_table_duplicate(aPixtable->table);
00966 pt->header = cpl_propertylist_duplicate(aPixtable->header);
00967 return pt;
00968 }
00969
00970
00979
00980 void
00981 muse_pixtable_delete(muse_pixtable *aPixtable)
00982 {
00983
00984 if (!aPixtable) {
00985 return;
00986 }
00987
00988
00989 cpl_table_delete(aPixtable->table);
00990 aPixtable->table = NULL;
00991
00992
00993 cpl_propertylist_delete(aPixtable->header);
00994 aPixtable->header = NULL;
00995
00996 cpl_free(aPixtable);
00997 }
00998
00999
01020
01021 static cpl_error_code
01022 muse_pixtable_save_image(muse_pixtable *aPixtable, const char *aFilename)
01023 {
01024 const char *id = "muse_pixtable_save";
01025 cpl_ensure_code(aPixtable, CPL_ERROR_NULL_INPUT);
01026 cpl_size nrow = muse_pixtable_get_nrow(aPixtable);
01027 cpl_ensure_code(nrow > 0, CPL_ERROR_ILLEGAL_INPUT);
01028
01029 cpl_errorstate state = cpl_errorstate_get();
01030 cpl_array *columns = cpl_table_get_column_names(aPixtable->table);
01031 int icol, ncol = cpl_array_get_size(columns);
01032 for (icol = 0; icol < ncol; icol++) {
01033 const char *colname = cpl_array_get_string(columns, icol);
01034
01035 cpl_type type = cpl_table_get_column_type(aPixtable->table, colname);
01036 cpl_image *image = NULL;
01037 switch (type) {
01038 case CPL_TYPE_FLOAT: {
01039 float *data = cpl_table_get_data_float(aPixtable->table, colname);
01040 image = cpl_image_wrap_float(1, nrow, data);
01041 break;
01042 }
01043 case CPL_TYPE_INT: {
01044 int *data = cpl_table_get_data_int(aPixtable->table, colname);
01045 image = cpl_image_wrap_int(1, nrow, data);
01046 break;
01047 }
01048 default:
01049 cpl_error_set_message(id, CPL_ERROR_UNSUPPORTED_MODE, "type \"%s\" (of "
01050 "column %s) is not supported for MUSE pixel tables",
01051 cpl_type_get_name(type), colname);
01052 continue;
01053 }
01054
01055
01056 cpl_propertylist *hext = cpl_propertylist_new();
01057 cpl_propertylist_append_string(hext, "EXTNAME", colname);
01058 const char *unit = cpl_table_get_column_unit(aPixtable->table, colname);
01059 if (unit) {
01060 cpl_propertylist_append_string(hext, "BUNIT", unit);
01061 }
01062 cpl_image_save(image, aFilename, CPL_TYPE_UNSPECIFIED, hext, CPL_IO_EXTEND);
01063 cpl_image_unwrap(image);
01064 cpl_propertylist_delete(hext);
01065 }
01066 cpl_array_delete(columns);
01067 return cpl_errorstate_is_equal(state) ? CPL_ERROR_NONE : cpl_error_get_code();
01068 }
01069
01070
01091
01092 cpl_error_code
01093 muse_pixtable_save(muse_pixtable *aPixtable, const char *aFilename)
01094 {
01095 cpl_ensure_code(aPixtable, CPL_ERROR_NULL_INPUT);
01096
01097
01098
01099
01100
01101 cpl_error_code rc = cpl_propertylist_save(aPixtable->header, aFilename,
01102 CPL_IO_CREATE);
01103 if (rc != CPL_ERROR_NONE) {
01104 cpl_error_set_message(__func__, rc, "could not save FITS header of pixel "
01105 "table \"%s\"", aFilename);
01106 return rc;
01107 }
01108
01109 cpl_boolean astable = getenv("MUSE_PIXTABLE_SAVE_AS_TABLE")
01110 && atoi(getenv("MUSE_PIXTABLE_SAVE_AS_TABLE")) > 0;
01111 if (astable) {
01112 cpl_msg_debug(__func__, "Saving pixel table \"%s\" as binary table",
01113 aFilename);
01114 rc = cpl_table_save(aPixtable->table, NULL, NULL, aFilename, CPL_IO_EXTEND);
01115 } else {
01116 rc = muse_pixtable_save_image(aPixtable, aFilename);
01117 }
01118 return rc;
01119 }
01120
01121
01143
01144 static cpl_table *
01145 muse_pixtable_load_window_image(const char *aFilename,
01146 cpl_size aStart, cpl_size aNRows)
01147 {
01148 const char *id = "muse_pixtable_load";
01149
01150
01151 cpl_size y1 = aStart + 1,
01152 y2 = aStart + aNRows;
01153
01154 int ext = cpl_fits_find_extension(aFilename, MUSE_PIXTABLE_DATA);
01155 cpl_propertylist *hdata = cpl_propertylist_load(aFilename, ext);
01156
01157 cpl_size naxis2 = muse_pfits_get_naxis(hdata, 2);
01158 if (y2 > naxis2) {
01159 y2 = naxis2;
01160 }
01161 cpl_propertylist_delete(hdata);
01162
01163
01164 cpl_size nrow = 0;
01165 cpl_table *table = cpl_table_new(nrow);
01166 int iext, next = cpl_fits_count_extensions(aFilename);
01167 for (iext = 1; iext <= next; iext++) {
01168 cpl_errorstate ps = cpl_errorstate_get();
01169 cpl_image *column = cpl_image_load_window(aFilename, CPL_TYPE_UNSPECIFIED,
01170 0, iext, 1, y1, 1, y2);
01171 if (!column || !cpl_errorstate_is_equal(ps)) {
01172 cpl_image_delete(column);
01173 cpl_error_set_message(id, cpl_error_get_code(), "could not load extension"
01174 " %d of pixel table \"%s\"", iext, aFilename);
01175 continue;
01176 }
01177 cpl_propertylist *hext = cpl_propertylist_load(aFilename, iext);
01178 const char *colname = muse_pfits_get_extname(hext);
01179 cpl_size nrows = cpl_image_get_size_x(column)
01180 * cpl_image_get_size_y(column);
01181 if (nrow < 1) {
01182 cpl_table_set_size(table, nrows);
01183 nrow = nrows;
01184 } else if (nrows != nrow) {
01185 cpl_error_set_message(id, CPL_ERROR_INCOMPATIBLE_INPUT, "size of column "
01186 "%s does not match", colname);
01187 cpl_propertylist_delete(hext);
01188 cpl_image_delete(column);
01189 continue;
01190 }
01191 cpl_type type = cpl_image_get_type(column);
01192 switch (type) {
01193 case CPL_TYPE_FLOAT:
01194 cpl_table_wrap_float(table, cpl_image_unwrap(column), colname);
01195 break;
01196 case CPL_TYPE_INT:
01197 cpl_table_wrap_int(table, cpl_image_unwrap(column), colname);
01198 break;
01199 default:
01200 cpl_error_set_message(id, CPL_ERROR_UNSUPPORTED_MODE, "type \"%s\" (of "
01201 "column %s) is not supported for MUSE pixel tables",
01202 cpl_type_get_name(type), colname);
01203 }
01204 cpl_errorstate state = cpl_errorstate_get();
01205 const char *unit = muse_pfits_get_bunit(hext);
01206 if (!cpl_errorstate_is_equal(state)) {
01207 cpl_errorstate_set(state);
01208 }
01209 if (unit) {
01210 cpl_table_set_column_unit(table, colname, unit);
01211 }
01212 cpl_propertylist_delete(hext);
01213 }
01214 return table;
01215 }
01216
01217
01236
01237 muse_pixtable *
01238 muse_pixtable_load_window(const char *aFilename,
01239 cpl_size aStart, cpl_size aNRows)
01240 {
01241
01242 muse_pixtable *pt = cpl_calloc(1, sizeof(muse_pixtable));
01243
01244
01245 cpl_errorstate prestate = cpl_errorstate_get();
01246 pt->header = cpl_propertylist_load(aFilename, 0);
01247 cpl_ensure(cpl_errorstate_is_equal(prestate) && pt->header,
01248 cpl_error_get_code(), NULL);
01249 if (muse_pixtable_get_type(pt) == MUSE_PIXTABLE_TYPE_UNKNOWN) {
01250 cpl_msg_error(__func__, "unknown pixel table type found in \"%s\"", aFilename);
01251 muse_pixtable_delete(pt);
01252 return NULL;
01253 }
01254
01255
01256
01257 cpl_propertylist *hext = cpl_propertylist_load(aFilename, 1);
01258 cpl_boolean asimage = !strcmp(cpl_propertylist_get_string(hext, "XTENSION"),
01259 "IMAGE");
01260 cpl_propertylist_delete(hext);
01261
01262
01263 if (asimage) {
01264 cpl_msg_info(__func__, "Loading pixel table \"%s\" (image format)",
01265 aFilename);
01266 pt->table = muse_pixtable_load_window_image(aFilename, aStart, aNRows);
01267 } else {
01268 cpl_msg_info(__func__, "Loading pixel table \"%s\" (bintable format)",
01269 aFilename);
01270 pt->table = cpl_table_load_window(aFilename, 1, 0, NULL, aStart, aNRows);
01271 }
01272 if (!cpl_errorstate_is_equal(prestate) || !pt->table) {
01273 cpl_msg_error(__func__, "Failed to load table part of pixel table \"%s\"",
01274 aFilename);
01275 muse_pixtable_delete(pt);
01276 return NULL;
01277 }
01278 cpl_error_code rc = muse_cpltable_check(pt->table, muse_pixtable_def);
01279 if (rc != CPL_ERROR_NONE) {
01280 cpl_error_set_message(__func__, rc, "pixel table \"%s\" does not contain "
01281 "all expected columns", aFilename);
01282 }
01283 return pt;
01284 }
01285
01286
01306
01307 muse_pixtable *
01308 muse_pixtable_load(const char *aFilename)
01309 {
01310
01311 cpl_errorstate prestate = cpl_errorstate_get();
01312 cpl_propertylist *theader = cpl_propertylist_load(aFilename, 1);
01313 cpl_ensure(cpl_errorstate_is_equal(prestate) && theader,
01314 cpl_error_get_code(), NULL);
01315 cpl_size nrow = cpl_propertylist_get_long_long(theader, "NAXIS2");
01316 cpl_propertylist_delete(theader);
01317
01318
01319 muse_pixtable *pt = muse_pixtable_load_window(aFilename, 0, nrow);
01320 return pt;
01321 }
01322
01323
01340
01341 muse_pixtable *
01342 muse_pixtable_load_restricted_wavelength(const char *aFilename,
01343 double aLambdaMin, double aLambdaMax)
01344 {
01345 muse_pixtable *pt = muse_pixtable_load(aFilename);
01346 if (!pt) {
01347 return NULL;
01348 }
01349 cpl_error_code rc = muse_pixtable_restrict_wavelength(pt, aLambdaMin,
01350 aLambdaMax);
01351 if (rc != CPL_ERROR_NONE) {
01352 muse_pixtable_delete(pt);
01353 return NULL;
01354 }
01355 if (muse_pixtable_get_nrow(pt) < 1) {
01356 cpl_msg_error(__func__, "Pixel table contains no entries after cutting to "
01357 "%.3f..%.3f Angstrom", aLambdaMin, aLambdaMax);
01358 cpl_error_set(__func__, CPL_ERROR_DATA_NOT_FOUND);
01359 muse_pixtable_delete(pt);
01360 return NULL;
01361 }
01362 return pt;
01363 }
01364
01365
01399
01400 muse_pixtable *
01401 muse_pixtable_load_merge_channels(cpl_table *aExposureList,
01402 double aLambdaMin, double aLambdaMax)
01403 {
01404 cpl_ensure(aExposureList, CPL_ERROR_NULL_INPUT, NULL);
01405
01406 muse_pixtable *pt = NULL;
01407 if (cpl_table_has_column(aExposureList, "00")) {
01408 const char *filename = cpl_table_get_string(aExposureList, "00", 0);
01409 if (filename) {
01410 pt = muse_pixtable_load_restricted_wavelength(filename, aLambdaMin,
01411 aLambdaMax);
01412 }
01413 if (pt) {
01414 return pt;
01415 }
01416 }
01417 cpl_boolean isfirst = CPL_TRUE;
01418 double fluxlref = 0,
01419 fluxsref = 0;
01420 int i, nifu = 0;
01421 for (i = 1; i <= kMuseNumIFUs; i++) {
01422 char *colname = cpl_sprintf("%02d", i);
01423 const char *filename = cpl_table_get_string(aExposureList, colname, 0);
01424 cpl_free(colname);
01425 if (!filename) {
01426 cpl_msg_warning(__func__, "Channel for IFU %02d is missing", i);
01427 continue;
01428 }
01429 muse_pixtable *onept = muse_pixtable_load_restricted_wavelength(filename,
01430 aLambdaMin,
01431 aLambdaMax);
01432 if (!onept) {
01433 cpl_msg_error(__func__, "failed to load pixel table from \"%s\"",
01434 filename);
01435 return pt;
01436 }
01437 nifu++;
01438
01439
01440 if (isfirst) {
01441 pt = onept;
01442 cpl_msg_debug(__func__, "loaded pixel table with %"CPL_SIZE_FORMAT" rows",
01443 muse_pixtable_get_nrow(pt));
01444 isfirst = CPL_FALSE;
01445 cpl_errorstate prestate = cpl_errorstate_get();
01446 fluxsref = cpl_propertylist_get_double(pt->header, MUSE_HDR_FLAT_FLUX_SKY);
01447 fluxlref = cpl_propertylist_get_double(pt->header, MUSE_HDR_FLAT_FLUX_LAMP);
01448 if (fluxsref == 0. && fluxlref == 0. && !cpl_errorstate_is_equal(prestate)) {
01449
01450
01451
01452 cpl_msg_debug(__func__, "\"%s\" was previously merged (got \"%s\" when"
01453 " asking for flat-field fluxes)", filename,
01454 cpl_error_get_message());
01455 cpl_errorstate_set(prestate);
01456 break;
01457 }
01458 if (fluxsref == 0. && fluxlref > 0. && !cpl_errorstate_is_equal(prestate)) {
01459
01460 cpl_msg_warning(__func__, "only found reference lamp-flat flux (%e) in "
01461 "\"%s\", flux levels may vary between IFUs!", fluxlref,
01462 filename);
01463 cpl_errorstate_set(prestate);
01464 } else {
01465 cpl_msg_debug(__func__, "reference flat fluxes sky: %e lamp: %e",
01466 fluxsref, fluxlref);
01467 }
01468 cpl_propertylist_erase(pt->header, MUSE_HDR_FLAT_FLUX_SKY);
01469 cpl_propertylist_erase(pt->header, MUSE_HDR_FLAT_FLUX_LAMP);
01470 continue;
01471 }
01472
01473
01474 muse_pixtable_origin_copy_offsets(pt, onept, 0);
01475
01476
01477 cpl_errorstate state = cpl_errorstate_get();
01478 double fluxs = cpl_propertylist_get_double(onept->header,
01479 MUSE_HDR_FLAT_FLUX_SKY),
01480 fluxl = cpl_propertylist_get_double(onept->header,
01481 MUSE_HDR_FLAT_FLUX_LAMP),
01482 scale = 1.;
01483 if (fluxsref > 0. && fluxs > 0.) {
01484 scale = fluxs / fluxsref;
01485 } else if (fluxlref > 0. && fluxl > 0.) {
01486 scale = fluxl / fluxlref;
01487 if (!cpl_errorstate_is_equal(state)) {
01488 cpl_msg_warning(__func__, "only found relative lamp-flat flux (%e) in "
01489 "\"%s\", flux levels may vary between IFUs!", fluxl,
01490 filename);
01491 cpl_errorstate_set(state);
01492 }
01493 }
01494 muse_pixtable_flux_multiply(onept, 1. / scale);
01495
01496
01497 cpl_table_insert(pt->table, onept->table, muse_pixtable_get_nrow(pt));
01498 cpl_msg_debug(__func__, "big pixel table now has %"CPL_SIZE_FORMAT" entries,"
01499 " scale was %e (flat fluxes sky: %e lamp: %e)",
01500 muse_pixtable_get_nrow(pt), scale, fluxs, fluxl);
01501
01502
01503 muse_pixtable_delete(onept);
01504 }
01505 muse_pixtable_compute_limits(pt);
01506 if (!pt) {
01507 cpl_error_set_message(__func__, CPL_ERROR_FILE_NOT_FOUND,
01508 "None of the pixel tables could be loaded");
01509 return NULL;
01510 }
01511
01512
01513 cpl_propertylist_erase_regexp(pt->header, "^EXTNAME|"MUSE_HDR_PT_ILLUM_REGEXP,
01514 0);
01515
01516 cpl_propertylist_erase_regexp(pt->header, "ESO DET (CHIP|OUT) ", 0);
01517 cpl_propertylist_erase_regexp(pt->header, "ESO DET2 ", 0);
01518
01519 cpl_propertylist_update_int(pt->header, MUSE_HDR_PT_MERGED, nifu);
01520 cpl_propertylist_set_comment(pt->header, MUSE_HDR_PT_MERGED,
01521 MUSE_HDR_PT_MERGED_COMMENT);
01522 return pt;
01523 }
01524
01525
01537
01538 int
01539 muse_pixtable_get_type(muse_pixtable *aPixtable)
01540 {
01541 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, MUSE_PIXTABLE_TYPE_UNKNOWN);
01542 const char *type = cpl_propertylist_get_string(aPixtable->header,
01543 MUSE_HDR_PT_TYPE);
01544 #if 0
01545 cpl_msg_debug(__func__, "pixel table type \"%s\"", type);
01546 #endif
01547 if (!type) {
01548 return MUSE_PIXTABLE_TYPE_UNKNOWN;
01549 }
01550 if (!strncmp(type, MUSE_PIXTABLE_STRING_FULL,
01551 strlen(MUSE_PIXTABLE_STRING_FULL) + 1)) {
01552 return MUSE_PIXTABLE_TYPE_FULL;
01553 } else if (!strncmp(type, MUSE_PIXTABLE_STRING_SIMPLE,
01554 strlen(MUSE_PIXTABLE_STRING_SIMPLE) + 1)) {
01555 return MUSE_PIXTABLE_TYPE_SIMPLE;
01556 }
01557
01558 return MUSE_PIXTABLE_TYPE_UNKNOWN;
01559 }
01560
01561
01570
01571 cpl_size
01572 muse_pixtable_get_nrow(const muse_pixtable *aPixtable)
01573 {
01574
01575 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, 0);
01576 cpl_ensure(aPixtable->table, CPL_ERROR_NULL_INPUT, 0);
01577
01578
01579 return cpl_table_get_nrow(aPixtable->table);
01580 }
01581
01582
01598
01599 cpl_error_code
01600 muse_pixtable_compute_limits(muse_pixtable *aPixtable)
01601 {
01602
01603 cpl_ensure_code(aPixtable && aPixtable->table && aPixtable->header,
01604 CPL_ERROR_NULL_INPUT);
01605 cpl_ensure_code(muse_cpltable_check(aPixtable->table, muse_pixtable_def)
01606 == CPL_ERROR_NONE, CPL_ERROR_DATA_NOT_FOUND);
01607
01608 if (muse_pixtable_get_nrow(aPixtable) == 0) {
01609 return CPL_ERROR_NONE;
01610 }
01611
01612 float *cdata_xpos = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_XPOS),
01613 *cdata_ypos = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_YPOS),
01614 *cdata_lambda = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_LAMBDA);
01615 uint32_t *origin = (uint32_t *)cpl_table_get_data_int(aPixtable->table,
01616 MUSE_PIXTABLE_ORIGIN);
01617
01618 float xlo = FLT_MAX, xhi = -FLT_MAX,
01619 ylo = FLT_MAX, yhi = -FLT_MAX,
01620 llo = FLT_MAX, lhi = -FLT_MAX;
01621 int ifulo = INT_MAX, ifuhi = 0,
01622 slicelo = INT_MAX, slicehi = 0;
01623 cpl_size i, nrow = muse_pixtable_get_nrow(aPixtable);
01624 for (i = 0; i < nrow; i++) {
01625 if (cdata_xpos[i] > xhi) xhi = cdata_xpos[i];
01626 if (cdata_xpos[i] < xlo) xlo = cdata_xpos[i];
01627 if (cdata_ypos[i] > yhi) yhi = cdata_ypos[i];
01628 if (cdata_ypos[i] < ylo) ylo = cdata_ypos[i];
01629 if (cdata_lambda[i] > lhi) lhi = cdata_lambda[i];
01630 if (cdata_lambda[i] < llo) llo = cdata_lambda[i];
01631 int ifu = muse_pixtable_origin_get_ifu_fast(origin[i]),
01632 slice = muse_pixtable_origin_get_slice_fast(origin[i]);
01633 if (ifu > ifuhi) ifuhi = ifu;
01634 if (ifu < ifulo) ifulo = ifu;
01635 if (slice > slicehi) slicehi = slice;
01636 if (slice < slicelo) slicelo = slice;
01637 }
01638 char *dodebug = getenv("MUSE_DEBUG_PIXTABLE_LIMITS");
01639 if (dodebug && atoi(dodebug)) {
01640 cpl_msg_debug(__func__, "x: %f...%f, y: %f...%f, lambda: %f...%f, "
01641 "ifu: %d...%d, slice: %d...%d",
01642 xlo, xhi, ylo, yhi, llo, lhi, ifulo, ifuhi, slicelo, slicehi);
01643 }
01644 cpl_propertylist_erase_regexp(aPixtable->header, MUSE_HDR_PT_LIMITS_REGEXP, 0);
01645 double ptxoff = 0.,
01646 ptyoff = 0.;
01647 if (muse_pixtable_wcs_check(aPixtable) == MUSE_PIXTABLE_WCS_CELSPH) {
01648 ptxoff = muse_pfits_get_crval(aPixtable->header, 1);
01649 ptyoff = muse_pfits_get_crval(aPixtable->header, 2);
01650 }
01651 cpl_propertylist_append_float(aPixtable->header, MUSE_HDR_PT_XLO, xlo + ptxoff);
01652 cpl_propertylist_append_float(aPixtable->header, MUSE_HDR_PT_XHI, xhi + ptxoff);
01653 cpl_propertylist_append_float(aPixtable->header, MUSE_HDR_PT_YLO, ylo + ptyoff);
01654 cpl_propertylist_append_float(aPixtable->header, MUSE_HDR_PT_YHI, yhi + ptyoff);
01655 cpl_propertylist_append_float(aPixtable->header, MUSE_HDR_PT_LLO, llo);
01656 cpl_propertylist_append_float(aPixtable->header, MUSE_HDR_PT_LHI, lhi);
01657 cpl_propertylist_append_int(aPixtable->header, MUSE_HDR_PT_ILO, ifulo);
01658 cpl_propertylist_append_int(aPixtable->header, MUSE_HDR_PT_IHI, ifuhi);
01659 cpl_propertylist_append_int(aPixtable->header, MUSE_HDR_PT_SLO, slicelo);
01660 cpl_propertylist_append_int(aPixtable->header, MUSE_HDR_PT_SHI, slicehi);
01661
01662 return CPL_ERROR_NONE;
01663 }
01664
01665
01680
01681 cpl_error_code
01682 muse_pixtable_flux_multiply(muse_pixtable *aPixtable, double aScale)
01683 {
01684 cpl_ensure_code(aPixtable && aPixtable->table, CPL_ERROR_NULL_INPUT);
01685 cpl_errorstate prestate = cpl_errorstate_get();
01686 cpl_table_multiply_scalar(aPixtable->table, MUSE_PIXTABLE_DATA, aScale);
01687 cpl_table_multiply_scalar(aPixtable->table, MUSE_PIXTABLE_STAT, aScale*aScale);
01688 cpl_error_code rc = CPL_ERROR_NONE;
01689 if (!cpl_errorstate_is_equal(prestate)) {
01690 rc = cpl_error_get_code();
01691 }
01692 return rc;
01693 }
01694
01695
01705
01706 static cpl_error_code
01707 muse_pixtable_fix_exp_headers(muse_pixtable *aPixtable)
01708 {
01709 cpl_ensure_code(aPixtable && aPixtable->header && aPixtable->table,
01710 CPL_ERROR_NULL_INPUT);
01711 if (cpl_table_count_selected(aPixtable->table) < 1) {
01712 return CPL_ERROR_NONE;
01713 }
01714 cpl_array *sel = cpl_table_where_selected(aPixtable->table);
01715 cpl_size narray = cpl_array_get_size(sel),
01716 nselprev = 0,
01717 ifst = 0, ilst = 0;
01718 const cpl_size *asel = cpl_array_get_data_cplsize_const(sel);
01719 unsigned int nexp = 0;
01720 do {
01721
01722 char *kwfst = cpl_sprintf(MUSE_HDR_PT_EXP_FST, ++nexp),
01723 *kwlst = cpl_sprintf(MUSE_HDR_PT_EXP_LST, nexp);
01724 if (!cpl_propertylist_has(aPixtable->header, kwfst) ||
01725 !cpl_propertylist_has(aPixtable->header, kwlst)) {
01726 cpl_free(kwfst);
01727 cpl_free(kwlst);
01728 break;
01729 }
01730 ifst = cpl_propertylist_get_long_long(aPixtable->header, kwfst);
01731 ilst = cpl_propertylist_get_long_long(aPixtable->header, kwlst);
01732
01733 cpl_size i, nsel = 0;
01734 for (i = 0; i < narray; i++) {
01735 if (asel[i] >= ifst && asel[i] <= ilst) {
01736 nsel++;
01737 }
01738 }
01739 cpl_size ifst2 = ifst - nselprev,
01740 ilst2 = ilst - nsel - nselprev;
01741 cpl_msg_debug(__func__, "exp %d old %"CPL_SIZE_FORMAT"..%"CPL_SIZE_FORMAT
01742 ", %"CPL_SIZE_FORMAT" selected (previous: %"CPL_SIZE_FORMAT
01743 "), new %"CPL_SIZE_FORMAT"..%"CPL_SIZE_FORMAT, nexp,
01744 ifst, ilst, nsel, nselprev, ifst2, ilst2);
01745
01746 muse_cplpropertylist_update_long_long(aPixtable->header, kwfst, ifst2);
01747 muse_cplpropertylist_update_long_long(aPixtable->header, kwlst, ilst2);
01748 cpl_free(kwfst);
01749 cpl_free(kwlst);
01750 nselprev += nsel;
01751 } while (ilst >= ifst);
01752 cpl_array_delete(sel);
01753 return CPL_ERROR_NONE;
01754 }
01755
01756
01765
01766 cpl_error_code
01767 muse_pixtable_restrict_wavelength(muse_pixtable *aPixtable, double aLow,
01768 double aHigh)
01769 {
01770 cpl_ensure_code(aPixtable && aPixtable->table && aPixtable->header,
01771 CPL_ERROR_NULL_INPUT);
01772 if (cpl_propertylist_get_float(aPixtable->header, MUSE_HDR_PT_LLO) > aLow &&
01773 cpl_propertylist_get_float(aPixtable->header, MUSE_HDR_PT_LHI) < aHigh) {
01774
01775 return CPL_ERROR_NONE;
01776 }
01777 #pragma omp critical(cpl_table_select)
01778 {
01779 cpl_table_unselect_all(aPixtable->table);
01780 cpl_table_or_selected_float(aPixtable->table, MUSE_PIXTABLE_LAMBDA,
01781 CPL_LESS_THAN, aLow);
01782 cpl_table_or_selected_float(aPixtable->table, MUSE_PIXTABLE_LAMBDA,
01783 CPL_GREATER_THAN, aHigh);
01784 muse_pixtable_fix_exp_headers(aPixtable);
01785 cpl_table_erase_selected(aPixtable->table);
01786 }
01787 return muse_pixtable_compute_limits(aPixtable);
01788 }
01789
01790
01801
01802 cpl_error_code
01803 muse_pixtable_restrict_xpos(muse_pixtable *aPixtable, double aLo, double aHi)
01804 {
01805 cpl_ensure_code(aPixtable && aPixtable->table && aPixtable->header,
01806 CPL_ERROR_NULL_INPUT);
01807 if (cpl_propertylist_get_float(aPixtable->header, MUSE_HDR_PT_XLO) > aLo &&
01808 cpl_propertylist_get_float(aPixtable->header, MUSE_HDR_PT_XHI) < aHi) {
01809
01810 return CPL_ERROR_NONE;
01811 }
01812 double ptxoff = 0.;
01813 if (muse_pixtable_wcs_check(aPixtable) == MUSE_PIXTABLE_WCS_CELSPH) {
01814
01815 ptxoff = muse_pfits_get_crval(aPixtable->header, 1);
01816 }
01817 #pragma omp critical(cpl_table_select)
01818 {
01819 cpl_table_unselect_all(aPixtable->table);
01820 cpl_table_or_selected_float(aPixtable->table, MUSE_PIXTABLE_XPOS,
01821 CPL_LESS_THAN, aLo - ptxoff);
01822 cpl_table_or_selected_float(aPixtable->table, MUSE_PIXTABLE_XPOS,
01823 CPL_GREATER_THAN, aHi - ptxoff);
01824 muse_pixtable_fix_exp_headers(aPixtable);
01825 cpl_table_erase_selected(aPixtable->table);
01826 }
01827 return muse_pixtable_compute_limits(aPixtable);
01828 }
01829
01830
01841
01842 cpl_error_code
01843 muse_pixtable_restrict_ypos(muse_pixtable *aPixtable, double aLo, double aHi)
01844 {
01845 cpl_ensure_code(aPixtable && aPixtable->table && aPixtable->header,
01846 CPL_ERROR_NULL_INPUT);
01847 if (cpl_propertylist_get_float(aPixtable->header, MUSE_HDR_PT_YLO) > aLo &&
01848 cpl_propertylist_get_float(aPixtable->header, MUSE_HDR_PT_YHI) < aHi) {
01849
01850 return CPL_ERROR_NONE;
01851 }
01852 double ptyoff = 0.;
01853 if (muse_pixtable_wcs_check(aPixtable) == MUSE_PIXTABLE_WCS_CELSPH) {
01854
01855 ptyoff = muse_pfits_get_crval(aPixtable->header, 2);
01856 }
01857 #pragma omp critical(cpl_table_select)
01858 {
01859 cpl_table_unselect_all(aPixtable->table);
01860 cpl_table_or_selected_float(aPixtable->table, MUSE_PIXTABLE_YPOS,
01861 CPL_LESS_THAN, aLo - ptyoff);
01862 cpl_table_or_selected_float(aPixtable->table, MUSE_PIXTABLE_YPOS,
01863 CPL_GREATER_THAN, aHi - ptyoff);
01864 muse_pixtable_fix_exp_headers(aPixtable);
01865 cpl_table_erase_selected(aPixtable->table);
01866 }
01867 return muse_pixtable_compute_limits(aPixtable);
01868 }
01869
01870
01884
01885 cpl_error_code
01886 muse_pixtable_erase_ifu_slice(muse_pixtable *aPixtable, unsigned char aIFU,
01887 unsigned short aSlice)
01888 {
01889 cpl_ensure_code(aPixtable, CPL_ERROR_NULL_INPUT);
01890 cpl_size nrow = muse_pixtable_get_nrow(aPixtable);
01891 cpl_ensure_code(nrow > 0, CPL_ERROR_DATA_NOT_FOUND);
01892
01893 cpl_table_unselect_all(aPixtable->table);
01894 uint32_t *origin = (uint32_t *)cpl_table_get_data_int(aPixtable->table,
01895 MUSE_PIXTABLE_ORIGIN);
01896 cpl_size irow;
01897 for (irow = 0; irow < nrow; irow++) {
01898 unsigned char ifu = muse_pixtable_origin_get_ifu(origin[irow]);
01899 unsigned short slice = muse_pixtable_origin_get_slice(origin[irow]);
01900 if (ifu == aIFU && slice == aSlice) {
01901 cpl_table_select_row(aPixtable->table, irow);
01902 }
01903 }
01904 cpl_size nsel = cpl_table_count_selected(aPixtable->table);
01905 cpl_error_code rc = cpl_table_erase_selected(aPixtable->table);
01906 cpl_msg_debug(__func__, "Erased %"CPL_SIZE_FORMAT" rows from pixel table",
01907 nsel);
01908
01909 muse_pixtable_fix_exp_headers(aPixtable);
01910 muse_pixtable_compute_limits(aPixtable);
01911 return rc;
01912 }
01913
01914
01931
01932 cpl_error_code
01933 muse_pixtable_and_selected_mask(muse_pixtable *aPixtable, muse_mask *aMask)
01934 {
01935 cpl_ensure_code(aPixtable && aPixtable->table, CPL_ERROR_NULL_INPUT);
01936 cpl_ensure_code(aMask && aMask->mask, CPL_ERROR_NULL_INPUT);
01937 float *cdata_xpos = cpl_table_get_data_float(aPixtable->table,
01938 MUSE_PIXTABLE_XPOS);
01939 float *cdata_ypos = cpl_table_get_data_float(aPixtable->table,
01940 MUSE_PIXTABLE_YPOS);
01941 cpl_size n_rows = cpl_table_get_nrow(aPixtable->table);
01942 cpl_size i_row;
01943 double crval_x = 0;
01944 double crpix_x = 1;
01945 double cdelt_x = 1;
01946 double crval_y = 0;
01947 double crpix_y = 1;
01948 double cdelt_y = 1;
01949 if (aMask->header) {
01950 crval_x = muse_pfits_get_crval(aMask->header, 1);
01951 crpix_x = muse_pfits_get_crpix(aMask->header, 1);
01952 cdelt_x = muse_pfits_get_cd(aMask->header, 1, 1);
01953 crval_y = muse_pfits_get_crval(aMask->header, 2);
01954 crpix_y = muse_pfits_get_crpix(aMask->header, 2);
01955 cdelt_y = muse_pfits_get_cd(aMask->header, 2, 2);
01956 }
01957 cpl_size nx = cpl_mask_get_size_x(aMask->mask);
01958 cpl_size ny = cpl_mask_get_size_y(aMask->mask);
01959 cpl_size n_enabled = cpl_mask_count(aMask->mask);
01960 cpl_msg_debug(__func__, "Mask contains %"CPL_SIZE_FORMAT" (%.2f %%) enabled "
01961 "pixels of %"CPL_SIZE_FORMAT" total", n_enabled,
01962 100.*n_enabled/nx/ny, nx*ny);
01963 cpl_size n_sel = n_rows;
01964 cpl_size n_in_table = 0;
01965 for (i_row = 0; i_row < n_rows; i_row++) {
01966 cpl_size ix = lround((cdata_xpos[i_row] - crval_x) / cdelt_x + crpix_x);
01967 cpl_size iy = lround((cdata_ypos[i_row] - crval_y) / cdelt_y + crpix_y);
01968 if ((ix < 1) || (ix > nx) || (iy < 1) || (iy > ny)) {
01969 continue;
01970 }
01971 n_in_table++;
01972 if (cpl_mask_get(aMask->mask, ix, iy) != CPL_BINARY_1) {
01973 cpl_table_unselect_row(aPixtable->table, i_row);
01974 n_sel--;
01975 }
01976 }
01977 cpl_msg_debug(__func__, "Mask selected %"CPL_SIZE_FORMAT" (%.2f %%/%.2f %%) "
01978 "pixels of %"CPL_SIZE_FORMAT" total/%"CPL_SIZE_FORMAT" in mask "
01979 "area", n_sel, 100.*n_sel/n_rows, 100.*n_sel/n_in_table,
01980 n_rows, n_in_table);
01981 return CPL_ERROR_NONE;
01982 }
01983
01984
02011
02012 cpl_error_code
02013 muse_pixtable_dump(muse_pixtable *aPixtable, cpl_size aStart, cpl_size aCount,
02014 unsigned char aDisplayHeader)
02015 {
02016 cpl_ensure_code(aPixtable && aPixtable->table && aPixtable->header,
02017 CPL_ERROR_NULL_INPUT);
02018 cpl_size nrows = muse_pixtable_get_nrow(aPixtable);
02019 cpl_ensure_code(aStart >= 0 && aStart < nrows && aCount >= 0,
02020 CPL_ERROR_ILLEGAL_INPUT);
02021 cpl_size last = aStart + aCount;
02022 if (last > nrows - 1) {
02023 last = nrows;
02024 }
02025 int haswcs = muse_pixtable_wcs_check(aPixtable);
02026 double ptxoff = 0., ptyoff = 0.;
02027 if (haswcs == MUSE_PIXTABLE_WCS_CELSPH) {
02028
02029 ptxoff = muse_pfits_get_crval(aPixtable->header, 1);
02030 ptyoff = muse_pfits_get_crval(aPixtable->header, 2);
02031 }
02032
02033 haswcs = (haswcs == MUSE_PIXTABLE_WCS_NATSPH ||
02034 haswcs == MUSE_PIXTABLE_WCS_CELSPH);
02035 float *cdata_xpos = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_XPOS),
02036 *cdata_ypos = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_YPOS),
02037 *cdata_lambda = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_LAMBDA),
02038 *cdata_data = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_DATA),
02039 *cdata_stat = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_STAT);
02040 cpl_errorstate es = cpl_errorstate_get();
02041 float *cdata_weight = cpl_table_get_data_float(aPixtable->table, MUSE_PIXTABLE_WEIGHT);
02042 cpl_errorstate_set(es);
02043 int *cdata_dq = cpl_table_get_data_int(aPixtable->table, MUSE_PIXTABLE_DQ);
02044 uint32_t *cdata_origin = (uint32_t *)cpl_table_get_data_int(aPixtable->table,
02045 MUSE_PIXTABLE_ORIGIN);
02046 cpl_ensure_code(cdata_xpos && cdata_ypos && cdata_lambda &&
02047 cdata_data && cdata_dq && cdata_stat,
02048 CPL_ERROR_BAD_FILE_FORMAT);
02049
02050
02051 if (aDisplayHeader) {
02052 printf("# xpos ypos lambda data dq stat"
02053 " weight exposure IFU xCCD yCCD xRaw yRaw slice\n");
02054 }
02055 if (aDisplayHeader == 1) {
02056 printf("#%13s %13s %9s %11s flag %11s ---------- No No pix "
02057 " pix pix pix No\n# flux in [%s]\n# flux**2 in [%s]\n",
02058 cpl_table_get_column_unit(aPixtable->table, MUSE_PIXTABLE_XPOS),
02059 cpl_table_get_column_unit(aPixtable->table, MUSE_PIXTABLE_YPOS),
02060 cpl_table_get_column_unit(aPixtable->table, MUSE_PIXTABLE_LAMBDA),
02061 "(flux)", "(flux**2)",
02062 cpl_table_get_column_unit(aPixtable->table, MUSE_PIXTABLE_DATA),
02063 cpl_table_get_column_unit(aPixtable->table, MUSE_PIXTABLE_STAT));
02064 }
02065
02066 cpl_size i;
02067 for (i = aStart; i < last; i++) {
02068 int x = muse_pixtable_origin_get_x(cdata_origin[i], aPixtable, i),
02069 y = muse_pixtable_origin_get_y_fast(cdata_origin[i]),
02070 xraw = x, yraw = y;
02071 muse_quadrants_coords_to_raw(NULL, &xraw, &yraw);
02072 if (haswcs) {
02073 printf("%14.7e %14.7e %9.3f ", cdata_xpos[i] + ptxoff, cdata_ypos[i] + ptyoff,
02074 cdata_lambda[i]);
02075 } else {
02076 printf("%14.8f %14.8f %9.3f ", cdata_xpos[i], cdata_ypos[i], cdata_lambda[i]);
02077 }
02078 printf("%12.5e 0x%08x %11.5e %10.4e %2d %2d %4d %4d %4d %4d %2d\n",
02079 cdata_data[i], cdata_dq[i], cdata_stat[i],
02080 cdata_weight ? cdata_weight[i] : 0.,
02081 muse_pixtable_get_expnum(aPixtable, i),
02082 cdata_origin ? muse_pixtable_origin_get_ifu_fast(cdata_origin[i])
02083 : 0,
02084 x, y, xraw, yraw,
02085 cdata_origin ? muse_pixtable_origin_get_slice_fast(cdata_origin[i])
02086 : 0);
02087 }
02088
02089 return CPL_ERROR_NONE;
02090 }
02091
02092
02114
02115 muse_pixtable_wcs
02116 muse_pixtable_wcs_check(muse_pixtable *aPixtable)
02117 {
02118 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, MUSE_PIXTABLE_WCS_UNKNOWN);
02119 const char *unitx = cpl_table_get_column_unit(aPixtable->table,
02120 MUSE_PIXTABLE_XPOS),
02121 *unity = cpl_table_get_column_unit(aPixtable->table,
02122 MUSE_PIXTABLE_YPOS);
02123 cpl_ensure(unitx, CPL_ERROR_DATA_NOT_FOUND, MUSE_PIXTABLE_WCS_UNKNOWN);
02124
02125 cpl_ensure(!strncmp(unitx, unity, 4), CPL_ERROR_INCOMPATIBLE_INPUT,
02126 MUSE_PIXTABLE_WCS_UNKNOWN);
02127 if (!strncmp(unitx, "deg", 4)) {
02128 return MUSE_PIXTABLE_WCS_CELSPH;
02129 }
02130 if (!strncmp(unitx, "pix", 4)) {
02131 return MUSE_PIXTABLE_WCS_PIXEL;
02132 }
02133 if (!strncmp(unitx, "rad", 4)) {
02134 return MUSE_PIXTABLE_WCS_NATSPH;
02135 }
02136 cpl_error_set(__func__, CPL_ERROR_ILLEGAL_INPUT);
02137 return MUSE_PIXTABLE_WCS_UNKNOWN;
02138 }
02139
02140
02148
02149 cpl_boolean
02150 muse_pixtable_is_fluxcal(muse_pixtable *aPixtable)
02151 {
02152 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, CPL_FALSE);
02153 cpl_errorstate prestate = cpl_errorstate_get();
02154 cpl_boolean flag = cpl_propertylist_get_bool(aPixtable->header,
02155 MUSE_HDR_PT_FLUXCAL);
02156 cpl_errorstate_set(prestate);
02157 return flag;
02158 }
02159
02160
02168
02169 cpl_boolean
02170 muse_pixtable_is_skysub(muse_pixtable *aPixtable)
02171 {
02172 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, CPL_FALSE);
02173 cpl_errorstate prestate = cpl_errorstate_get();
02174 cpl_boolean flag = cpl_propertylist_get_bool(aPixtable->header,
02175 MUSE_HDR_PT_SKYSUB);
02176 cpl_errorstate_set(prestate);
02177 return flag;
02178 }
02179
02180
02188
02189 cpl_boolean
02190 muse_pixtable_is_rvcorr(muse_pixtable *aPixtable)
02191 {
02192 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, CPL_FALSE);
02193 return cpl_propertylist_has(aPixtable->header, MUSE_HDR_PT_RVCORR);
02194 }
02195
02196
02205
02206 cpl_error_code
02207 muse_pixtable_reset_dq(muse_pixtable *aPixtable, unsigned int aDQ)
02208 {
02209 cpl_ensure_code(aPixtable, CPL_ERROR_NULL_INPUT);
02210
02211 unsigned int *dq = (unsigned int *)cpl_table_get_data_int(aPixtable->table,
02212 MUSE_PIXTABLE_DQ),
02213 inverse = ~aDQ;
02214 cpl_size i, nrow = muse_pixtable_get_nrow(aPixtable);
02215 #pragma omp parallel for default(none) \
02216 shared(dq, inverse, nrow)
02217 for (i = 0; i < nrow; i++) {
02218 dq[i] &= inverse;
02219 }
02220 return CPL_ERROR_NONE;
02221 }
02222
02223
02240
02241 muse_imagelist *
02242 muse_pixtable_to_imagelist(muse_pixtable *aPixtable)
02243 {
02244 cpl_ensure(aPixtable && aPixtable->header, CPL_ERROR_NULL_INPUT, NULL);
02245 unsigned int expnum = muse_pixtable_get_expnum(aPixtable, 0),
02246 explast = muse_pixtable_get_expnum(aPixtable,
02247 muse_pixtable_get_nrow(aPixtable) - 1);
02248 cpl_ensure(expnum == explast, CPL_ERROR_ILLEGAL_INPUT, NULL);
02249
02250
02251 muse_imagelist *list = muse_imagelist_new();
02252
02253
02254
02255 muse_pixtable **pts = muse_pixtable_extracted_get_slices(aPixtable);
02256
02257 muse_image *image = NULL;
02258 unsigned short ifu = 0,
02259 ilist = 0;
02260 int ipt, npt = muse_pixtable_extracted_get_size(pts);
02261 for (ipt = 0; ipt < npt; ipt++) {
02262 float *cdata = cpl_table_get_data_float(pts[ipt]->table, MUSE_PIXTABLE_DATA),
02263 *cstat = cpl_table_get_data_float(pts[ipt]->table, MUSE_PIXTABLE_STAT);
02264 int *cdq = cpl_table_get_data_int(pts[ipt]->table, MUSE_PIXTABLE_DQ);
02265 uint32_t *corigin = (uint32_t *)cpl_table_get_data_int(pts[ipt]->table,
02266 MUSE_PIXTABLE_ORIGIN);
02267
02268
02269
02270 if (ifu != muse_pixtable_origin_get_ifu_fast(corigin[0])) {
02271 image = muse_image_new();
02272 image->header = cpl_propertylist_duplicate(pts[ipt]->header);
02273 cpl_propertylist_erase_regexp(image->header, "^ESO DRS MUSE PIXTABLE", 0);
02274 image->data = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop, CPL_TYPE_FLOAT);
02275 image->dq = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop, CPL_TYPE_INT);
02276
02277 cpl_image_fill_noise_uniform(image->dq, EURO3D_MISSDATA, EURO3D_MISSDATA + 0.1);
02278 image->stat = cpl_image_new(kMuseOutputXRight, kMuseOutputYTop, CPL_TYPE_FLOAT);
02279 cpl_msg_debug(__func__, "new image (index %hu in list)", ilist);
02280 muse_imagelist_set(list, image, ilist++);
02281 }
02282 if (!image) {
02283 cpl_msg_error(__func__, "ipt = %d: no image!", ipt);
02284 continue;
02285 }
02286 float *idata = cpl_image_get_data_float(image->data),
02287 *istat = cpl_image_get_data_float(image->stat);
02288 int *idq = cpl_image_get_data_int(image->dq);
02289
02290 ifu = muse_pixtable_origin_get_ifu_fast(corigin[0]);
02291 unsigned short slice = muse_pixtable_origin_get_slice_fast(corigin[0]);
02292 unsigned int xoff = muse_pixtable_origin_get_offset(pts[ipt], expnum, ifu,
02293 slice),
02294 x1 = INT_MAX, x2 = 0,
02295 irow, nrow = muse_pixtable_get_nrow(pts[ipt]);
02296 for (irow = 0; irow < nrow; irow++) {
02297
02298 unsigned int x = muse_pixtable_origin_get_x_fast(corigin[irow], xoff) - 1,
02299 y = muse_pixtable_origin_get_y_fast(corigin[irow]) - 1;
02300 idata[x + y*kMuseOutputXRight] = cdata[irow];
02301 idq[x + y*kMuseOutputXRight] = cdq[irow];
02302 istat[x + y*kMuseOutputXRight] = cstat[irow];
02303 if (x < x1) {
02304 x1 = x;
02305 }
02306 if (x > x2) {
02307 x2 = x;
02308 }
02309 }
02310
02311 char *keyword = cpl_sprintf("ESO DRS MUSE SLICE%hu CENTER", slice);
02312 cpl_propertylist_update_float(image->header, keyword, (x2 + x1) / 2. + 1.);
02313 #if 0
02314 cpl_msg_debug(__func__, "IFU %hu %s = %.1f", ifu, keyword,
02315 (x2 + x1) / 2. + 1.);
02316 #endif
02317 cpl_free(keyword);
02318 }
02319 muse_pixtable_extracted_delete(pts);
02320
02321 return list;
02322 }
02323
02324
02350
02351 cpl_error_code
02352 muse_pixtable_from_imagelist(muse_pixtable *aPixtable, muse_imagelist *aList)
02353 {
02354 cpl_ensure_code(aPixtable && aPixtable->header && aList, CPL_ERROR_NULL_INPUT);
02355 unsigned int expnum = muse_pixtable_get_expnum(aPixtable, 0),
02356 explast = muse_pixtable_get_expnum(aPixtable,
02357 muse_pixtable_get_nrow(aPixtable) - 1);
02358 cpl_ensure_code(expnum == explast, CPL_ERROR_ILLEGAL_INPUT);
02359
02360
02361
02362
02363 muse_pixtable **pts = muse_pixtable_extracted_get_slices(aPixtable);
02364 if (muse_pixtable_extracted_get_size(pts) / kMuseSlicesPerCCD
02365 != muse_imagelist_get_size(aList)) {
02366 muse_pixtable_extracted_delete(pts);
02367 return cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
02368 }
02369
02370 muse_image *image = NULL;
02371 unsigned short ifu = 0,
02372 ilist = 0;
02373 int ipt, npt = muse_pixtable_extracted_get_size(pts);
02374 for (ipt = 0; ipt < npt; ipt++) {
02375 float *cdata = cpl_table_get_data_float(pts[ipt]->table, MUSE_PIXTABLE_DATA),
02376 *cstat = cpl_table_get_data_float(pts[ipt]->table, MUSE_PIXTABLE_STAT);
02377 uint32_t *corigin = (uint32_t *)cpl_table_get_data_int(pts[ipt]->table,
02378 MUSE_PIXTABLE_ORIGIN);
02379
02380 if (ifu != muse_pixtable_origin_get_ifu_fast(corigin[0])) {
02381 image = muse_imagelist_get(aList, ilist++);
02382 }
02383 if (!image) {
02384 cpl_msg_error(__func__, "ipt = %d: no image!", ipt);
02385 continue;
02386 }
02387 float *idata = cpl_image_get_data_float(image->data),
02388 *istat = cpl_image_get_data_float(image->stat);
02389 ifu = muse_pixtable_origin_get_ifu_fast(corigin[0]);
02390 unsigned short slice = muse_pixtable_origin_get_slice_fast(corigin[0]);
02391 unsigned int xoff = muse_pixtable_origin_get_offset(pts[ipt], expnum, ifu,
02392 slice),
02393 irow, nrow = muse_pixtable_get_nrow(pts[ipt]);
02394 for (irow = 0; irow < nrow; irow++) {
02395
02396 unsigned int x = muse_pixtable_origin_get_x_fast(corigin[irow], xoff) - 1,
02397 y = muse_pixtable_origin_get_y_fast(corigin[irow]) - 1;
02398 cdata[irow] = idata[x + y*kMuseOutputXRight];
02399 cstat[irow] = istat[x + y*kMuseOutputXRight];
02400 }
02401 }
02402 muse_pixtable_extracted_delete(pts);
02403
02404 return CPL_ERROR_NONE;
02405 }
02406
02407
02420
02421 muse_pixtable **
02422 muse_pixtable_extracted_get_slices(muse_pixtable *aPixtable)
02423 {
02424 cpl_ensure(aPixtable, CPL_ERROR_NULL_INPUT, NULL);
02425 cpl_size n_rows = cpl_table_get_nrow(aPixtable->table);
02426 unsigned int ifu_slice_mask = (0x1f << MUSE_ORIGIN_SHIFT_IFU) | 0x3f;
02427 cpl_table_duplicate_column(aPixtable->table, "ifuslice",
02428 aPixtable->table, MUSE_PIXTABLE_ORIGIN);
02429 unsigned int *slicedata = (unsigned int *)
02430 cpl_table_get_data_int(aPixtable->table, "ifuslice");
02431 cpl_size i_row;
02432 unsigned int last_ifu_slice = 0;
02433 int is_sorted = CPL_TRUE;
02434 for (i_row = 0; i_row < n_rows; i_row++) {
02435 slicedata[i_row] &= ifu_slice_mask;
02436 if (is_sorted && slicedata[i_row] < last_ifu_slice) {
02437 is_sorted = CPL_FALSE;
02438 } else {
02439 last_ifu_slice = slicedata[i_row];
02440 }
02441 }
02442 if (!is_sorted) {
02443 cpl_propertylist *order = cpl_propertylist_new();
02444 cpl_propertylist_append_bool(order, "ifuslice", CPL_FALSE);
02445 cpl_propertylist_append_bool(order, MUSE_PIXTABLE_LAMBDA, CPL_FALSE);
02446 cpl_msg_debug(__func__, "sorting pixel table: quick sort, %"CPL_SIZE_FORMAT
02447 " entries", n_rows);
02448 cpl_table_sort(aPixtable->table, order);
02449 cpl_propertylist_delete(order);
02450
02451 cpl_propertylist_erase_regexp(aPixtable->header, MUSE_HDR_PT_EXP_REGEXP, 0);
02452 cpl_msg_debug(__func__, "pixel table sorted.");
02453 }
02454
02455 i_row = 0;
02456 cpl_size n_col = cpl_table_get_ncol(aPixtable->table);
02457 cpl_array *colnames = cpl_table_get_column_names(aPixtable->table);
02458 muse_pixtable **slice_tables = cpl_calloc(1, sizeof(muse_pixtable *));
02459 cpl_size n_slices = 0;
02460 while (i_row < n_rows) {
02461 unsigned int ifu_slice = slicedata[i_row];
02462 cpl_size j_row;
02463 for (j_row = i_row+1; j_row < n_rows && slicedata[j_row] == ifu_slice;
02464 j_row++)
02465 ;
02466 cpl_size nrows_slice = j_row - i_row;
02467 muse_pixtable *slice_pixtable = cpl_calloc(1, sizeof(muse_pixtable));
02468 slice_pixtable->table = cpl_table_new(nrows_slice);
02469 cpl_size i_col;
02470 for (i_col = 0; i_col < n_col; i_col++) {
02471 const char *cname = cpl_array_get_string(colnames, i_col);
02472 if (strcmp(cname, "ifuslice") == 0)
02473 continue;
02474 cpl_type ctype = cpl_table_get_column_type(aPixtable->table, cname);
02475 if (ctype == CPL_TYPE_INT) {
02476 int *cdata = cpl_table_get_data_int(aPixtable->table, cname);
02477 cpl_table_wrap_int(slice_pixtable->table, cdata + i_row, cname);
02478 } else if (ctype == CPL_TYPE_FLOAT) {
02479 float *cdata = cpl_table_get_data_float(aPixtable->table, cname);
02480 cpl_table_wrap_float(slice_pixtable->table, cdata + i_row, cname);
02481 } else if (ctype == CPL_TYPE_DOUBLE) {
02482 double *cdata = cpl_table_get_data_double(aPixtable->table, cname);
02483 cpl_table_wrap_double(slice_pixtable->table, cdata + i_row, cname);
02484 } else if (ctype == CPL_TYPE_STRING) {
02485 char **cdata = cpl_table_get_data_string(aPixtable->table, cname);
02486 cpl_table_wrap_string(slice_pixtable->table, cdata + i_row, cname);
02487 }
02488 const char *unit = cpl_table_get_column_unit(aPixtable->table, cname);
02489 cpl_table_set_column_unit(slice_pixtable->table, cname, unit);
02490 }
02491
02492 slice_pixtable->header = cpl_propertylist_duplicate(aPixtable->header);
02493 muse_pixtable_compute_limits(slice_pixtable);
02494 slice_tables = cpl_realloc(slice_tables,
02495 (n_slices + 2) * sizeof(muse_pixtable *));
02496 slice_tables[n_slices] = slice_pixtable;
02497 n_slices++;
02498 slice_tables[n_slices] = NULL;
02499 i_row = j_row;
02500 }
02501 cpl_array_delete(colnames);
02502 cpl_table_erase_column(aPixtable->table, "ifuslice");
02503
02504 return slice_tables;
02505 }
02506
02507
02518
02519 cpl_size
02520 muse_pixtable_extracted_get_size(muse_pixtable **aPixtables)
02521 {
02522 cpl_ensure(aPixtables, CPL_ERROR_NULL_INPUT, -1);
02523 cpl_size n = 0;
02524 while (aPixtables[n] != NULL) {
02525 n++;
02526 }
02527 return n;
02528 }
02529
02530
02540
02541 void
02542 muse_pixtable_extracted_delete(muse_pixtable **aPixtables)
02543 {
02544 if (!aPixtables) {
02545 return;
02546 }
02547 muse_pixtable **t;
02548 for (t = aPixtables; *t != NULL; t++) {
02549 cpl_array *colnames = cpl_table_get_column_names((*t)->table);
02550 cpl_size n_col = cpl_table_get_ncol((*t)->table);
02551 cpl_size i_col;
02552 for (i_col = 0; i_col < n_col; i_col++) {
02553 const char *cname = cpl_array_get_string(colnames, i_col);
02554 cpl_table_unwrap((*t)->table, cname);
02555 }
02556 cpl_array_delete(colnames);
02557 cpl_table_delete((*t)->table);
02558 cpl_propertylist_delete((*t)->header);
02559 cpl_free(*t);
02560 }
02561 cpl_free(aPixtables);
02562 }
02563