32 #include "muse_xcombine.h" 34 #include "muse_pfits.h" 36 #include "muse_utils.h" 37 #include "muse_data_format_z.h" 66 while (aPixtables[npt++]) ;
70 cpl_table *table = cpl_table_new(npt);
71 cpl_table_new_column(table,
"EXPTIME", CPL_TYPE_DOUBLE);
72 cpl_table_new_column(table,
"AGX_AVG", CPL_TYPE_DOUBLE);
73 cpl_table_new_column(table,
"AGX_RMS", CPL_TYPE_DOUBLE);
74 cpl_table_new_column(table,
"AGY_AVG", CPL_TYPE_DOUBLE);
75 cpl_table_new_column(table,
"AGY_RMS", CPL_TYPE_DOUBLE);
76 cpl_table_new_column(table,
"IA_FWHM", CPL_TYPE_DOUBLE);
77 cpl_table_new_column(table,
"DIMM_START", CPL_TYPE_DOUBLE);
78 cpl_table_new_column(table,
"DIMM_END", CPL_TYPE_DOUBLE);
81 cpl_errorstate prestate = cpl_errorstate_get();
83 for (i = 0; i < npt; i++) {
85 cpl_errorstate state = cpl_errorstate_get();
87 if (cpl_errorstate_is_equal(state)) {
88 cpl_table_set_double(table,
"EXPTIME", i, value);
92 state = cpl_errorstate_get();
94 if (cpl_errorstate_is_equal(state)) {
95 cpl_table_set_double(table,
"AGX_AVG", i, value);
97 state = cpl_errorstate_get();
99 if (cpl_errorstate_is_equal(state)) {
100 cpl_table_set_double(table,
"AGX_RMS", i, value);
102 state = cpl_errorstate_get();
104 if (cpl_errorstate_is_equal(state)) {
105 cpl_table_set_double(table,
"AGY_AVG", i, value);
107 state = cpl_errorstate_get();
109 if (cpl_errorstate_is_equal(state)) {
110 cpl_table_set_double(table,
"AGY_RMS", i, value);
114 state = cpl_errorstate_get();
116 if (cpl_errorstate_is_equal(state)) {
117 cpl_table_set_double(table,
"IA_FWHM", i, value);
121 state = cpl_errorstate_get();
123 if (cpl_errorstate_is_equal(state) && value > 0.) {
124 cpl_table_set_double(table,
"DIMM_START", i, value);
126 state = cpl_errorstate_get();
128 if (cpl_errorstate_is_equal(state) && value > 0.) {
129 cpl_table_set_double(table,
"DIMM_END", i, value);
132 cpl_errorstate_set(prestate);
135 cpl_table_duplicate_column(table,
"AG_AVG", table,
"AGX_AVG");
136 cpl_table_add_columns(table,
"AG_AVG",
"AGY_AVG");
137 cpl_table_multiply_scalar(table,
"AG_AVG", 0.5);
139 cpl_table_duplicate_column(table,
"AG_RMS", table,
"AGX_RMS");
140 cpl_table_power_column(table,
"AG_RMS", 2);
141 cpl_table_duplicate_column(table,
"AG2_RMS", table,
"AGY_RMS");
142 cpl_table_power_column(table,
"AG2_RMS", 2);
143 cpl_table_add_columns(table,
"AG_RMS",
"AG2_RMS");
144 cpl_table_erase_column(table,
"AG2_RMS");
145 cpl_table_power_column(table,
"AG_RMS", 0.5);
147 cpl_table_duplicate_column(table,
"DIMM", table,
"DIMM_START");
148 cpl_table_add_columns(table,
"DIMM",
"DIMM_END");
149 cpl_table_multiply_scalar(table,
"DIMM", 0.5);
152 printf(
"%s:\n", __func__);
153 const char *p, *cols[] = {
"EXPTIME",
"AG_AVG",
"IA_FWHM",
"DIMM", NULL };
154 for (i = 0, p = cols[i] ; p; p = cols[i++ + 1]) {
155 prestate = cpl_errorstate_get();
156 printf(
"%s: %.3f +/- %.3f (%"CPL_SIZE_FORMAT
" invalid)\n", p,
157 cpl_table_get_column_mean(table, p), cpl_table_get_column_stdev(table, p),
158 cpl_table_count_invalid(table, p));
160 cpl_errorstate_set(prestate);
162 cpl_table_dump(table, 0, npt, stdout);
207 cpl_ensure_code(aPixtables, CPL_ERROR_NULL_INPUT);
208 unsigned int npt = 0;
209 while (aPixtables[npt++]) ;
210 cpl_ensure_code(--npt > 1, CPL_ERROR_ILLEGAL_INPUT);
212 cpl_msg_info(__func__,
"%d tables, not weighting them", npt);
213 return CPL_ERROR_NONE;
216 cpl_msg_warning(__func__,
"Unknown exposure weighting scheme (%d)",
218 return cpl_error_set(__func__, CPL_ERROR_UNSUPPORTED_MODE);
223 cpl_table *tinfo = muse_xcombine_weights_infotable(aPixtables);
225 double exptime0 = cpl_table_get_double(tinfo,
"EXPTIME", 0, &err);
226 if (err || exptime0 == 0.0) {
227 cpl_table_delete(tinfo);
228 return cpl_error_set(__func__, CPL_ERROR_INCOMPATIBLE_INPUT);
232 const char *fwhmcolumn = NULL,
235 cpl_size ninvalid = cpl_table_count_invalid(tinfo,
"AG_AVG");
237 ninvalid = cpl_table_count_invalid(tinfo,
"IA_FWHM");
239 ninvalid = cpl_table_count_invalid(tinfo,
"DIMM");
242 cpl_msg_info(__func__,
"%d tables to be weighted using EXPTIME & FWHM " 243 "(using DIMM measurements)", npt);
246 fwhmcolumn =
"IA_FWHM";
247 cpl_msg_info(__func__,
"%d tables to be weighted using EXPTIME & FWHM " 248 "(using active optics image analysis)", npt);
251 fwhmcolumn =
"AG_AVG";
252 fwhmerrcol =
"AG_RMS";
253 cpl_msg_info(__func__,
"%d tables to be weighted using EXPTIME & FWHM " 254 "(using auto-guider info)", npt);
257 cpl_msg_warning(__func__,
"%d tables to be weighted using EXPTIME.", npt);
258 cpl_msg_warning(__func__,
"(FWHM-based weighting was requested but cannot" 259 " be carried due to incomplete FITS headers in some " 261 cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
"missing FITS " 262 "headers for FWHM-based exposure weighting");
264 fwhm0 = cpl_table_get_double(tinfo, fwhmcolumn, 0, &err);
268 cpl_msg_info(__func__,
"%d tables to be weighted using EXPTIME.", npt);
273 for (i = 0; i < npt; i++) {
274 double exptime = cpl_table_get_double(tinfo,
"EXPTIME", i, &err),
275 weight = exptime / exptime0;
281 char *fwhmstr = NULL;
283 double fwhm = cpl_table_get_double(tinfo, fwhmcolumn, i, &err),
285 ? cpl_table_get_double(tinfo, fwhmerrcol, i, NULL) : 0.;
286 weight *= fwhm0 / fwhm;
288 fwhmstr = cpl_sprintf(
", FWHM = %.2f +/- %.2f", fwhm, fwhmerr);
290 fwhmstr = cpl_sprintf(
", FWHM = %.2f", fwhm);
293 cpl_msg_debug(__func__,
"Table %d, weight = %f (EXPTIME = %f%s)", i+1, weight,
294 exptime, fwhmstr ? fwhmstr :
"");
296 cpl_table_fill_column_window_float(aPixtables[i]->table,
304 MUSE_HDR_PT_WEIGHTED_COMMENT);
306 cpl_table_delete(tinfo);
308 return CPL_ERROR_NONE;
336 const char *
id =
"muse_xcombine_tables";
337 cpl_ensure(aOffsets && aDateObs, CPL_ERROR_NULL_INPUT, NULL);
340 cpl_ensure(strlen(aDateObs) >= 19 && strlen(aDateObs) <= 68,
341 CPL_ERROR_ILLEGAL_INPUT, NULL);
343 int ioff, noff = cpl_table_get_nrow(aOffsets);
344 for (ioff = 0; ioff < noff; ioff++) {
345 const char *dateobs = cpl_table_get_string(aOffsets, MUSE_OFFSETS_DATEOBS,
349 if (dateobs && !strncmp(dateobs, aDateObs, 23)) {
350 double *offsets = cpl_calloc(3,
sizeof(
double));
352 cpl_msg_debug(__func__,
"found:");
353 cpl_table_dump(aOffsets, ioff, 1, stdout);
357 offsets[0] = cpl_table_get_double(aOffsets, MUSE_OFFSETS_DRA, ioff, &err);
359 cpl_msg_warning(
id,
"%s for %s could not be read from %s!",
360 MUSE_OFFSETS_DRA, aDateObs, MUSE_TAG_OFFSET_LIST);
363 offsets[1] = cpl_table_get_double(aOffsets, MUSE_OFFSETS_DDEC, ioff, &err);
365 cpl_msg_warning(
id,
"%s for %s could not be read from %s!",
366 MUSE_OFFSETS_DDEC, aDateObs, MUSE_TAG_OFFSET_LIST);
369 offsets[2] = cpl_table_has_column(aOffsets, MUSE_OFFSETS_FSCALE)
370 ? cpl_table_get_double(aOffsets, MUSE_OFFSETS_FSCALE, ioff, &err)
437 cpl_ensure(aPixtables, CPL_ERROR_NULL_INPUT, NULL);
438 unsigned int npt = 0;
439 while (aPixtables[npt++]) ;
440 cpl_ensure(--npt > 1, CPL_ERROR_ILLEGAL_INPUT, NULL);
442 CPL_ERROR_INCOMPATIBLE_INPUT, NULL);
443 cpl_msg_info(__func__,
"%u tables to be combined", npt);
445 double timeinit = cpl_test_get_walltime(),
446 cpuinit = cpl_test_get_cputime();
449 aPixtables[0] = NULL;
452 cpl_msg_warning(__func__,
"Data of exposure 1 (DATE-OBS=%s) was not radial-" 458 char keyword[KEYWORD_LENGTH], comment[KEYWORD_LENGTH];
460 cpl_propertylist_append_long_long(pt->
header, keyword, 0);
461 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_PT_EXP_FST_COMMENT, 1);
462 cpl_propertylist_set_comment(pt->
header, keyword, comment);
464 cpl_propertylist_append_long_long(pt->
header, keyword,
466 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_PT_EXP_LST_COMMENT, 1);
467 cpl_propertylist_set_comment(pt->
header, keyword, comment);
476 if (isfinite(offsets[0]) && isfinite(offsets[1])) {
479 cpl_msg_debug(__func__,
"Applying coordinate offsets to exposure 1: %e/%e" 480 " deg", offsets[0], offsets[1]);
482 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DRA, 1);
483 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DRA_C, offsets[0] * 3600.);
484 cpl_propertylist_append_double(pt->
header, keyword, offsets[0]);
485 cpl_propertylist_set_comment(pt->
header, keyword, comment);
486 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DDEC, 1);
487 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DDEC_C, offsets[1] * 3600.);
488 cpl_propertylist_append_double(pt->
header, keyword, offsets[1]);
489 cpl_propertylist_set_comment(pt->
header, keyword, comment);
491 if (isnormal(offsets[2])) {
493 cpl_msg_debug(__func__,
"Scaling flux of exposure 1 by %g.", offsets[2]);
496 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_FLUX_SCALEi, 1);
497 cpl_propertylist_append_double(pt->
header, keyword, offsets[2]);
498 cpl_propertylist_set_comment(pt->
header, keyword, MUSE_HDR_FLUX_SCALEi_C);
501 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DATEOBS, 1);
502 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DATEOBS_C, 1);
503 cpl_propertylist_append_string(pt->
header, keyword,
505 cpl_propertylist_set_comment(pt->
header, keyword, comment);
510 unsigned int i, nskipped = 0;
511 for (i = 1; i < npt; i++) {
513 cpl_msg_warning(__func__,
"Exposure %d was not projected to native " 514 "spherical coordinates, skipping this one!", i + 1);
519 cpl_msg_warning(__func__,
"Data of exposure %u (DATE-OBS=%s) was not " 520 "radial-velocity corrected!", i+1,
531 cpl_boolean offcor = CPL_FALSE;
533 if (isfinite(offsets[0]) && isfinite(offsets[1])) {
536 cpl_msg_debug(__func__,
"Applying coordinate offsets to exposure %d: " 537 "%e/%e deg", i + 1, offsets[0], offsets[1]);
540 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DRA, i + 1);
541 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DRA_C, offsets[0] * 3600.);
542 cpl_propertylist_append_double(pt->
header, keyword, offsets[0]);
543 cpl_propertylist_set_comment(pt->
header, keyword, comment);
544 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DDEC, i + 1);
545 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DDEC_C, offsets[1] * 3600.);
546 cpl_propertylist_append_double(pt->
header, keyword, offsets[1]);
547 cpl_propertylist_set_comment(pt->
header, keyword, comment);
549 if (isnormal(offsets[2])) {
550 cpl_msg_debug(__func__,
"Scaling flux of exposure %u by %g.", i + 1,
554 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_FLUX_SCALEi, i + 1);
555 cpl_propertylist_append_double(pt->
header, keyword, offsets[2]);
556 cpl_propertylist_set_comment(pt->
header, keyword, MUSE_HDR_FLUX_SCALEi_C);
559 snprintf(keyword, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DATEOBS, i + 1);
560 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_OFFSETi_DATEOBS_C, i + 1);
561 cpl_propertylist_append_string(pt->
header, keyword,
563 cpl_propertylist_set_comment(pt->
header, keyword, comment);
569 double raoffset = ra - ra0,
570 decoffset = dec - dec0;
577 #pragma omp parallel for default(none) \ 578 shared(decoffset, nrowi, raoffset, xpos, ypos) 579 for (irow = 0; irow < nrowi; irow++) {
580 xpos[irow] += raoffset;
581 ypos[irow] += decoffset;
590 double avdec = (dec + dec0) / 2.,
591 raoff = (ra - ra0) * cos(avdec * CPL_MATH_RAD_DEG) * 3600.,
592 decoff = (dec - dec0) * 3600.;
593 cpl_msg_info(__func__,
"Distance of exposure %u (relative to exp. 1): " 594 "%.1f,%.1f arcsec%s", i+1, raoff, decoff,
595 offcor ?
" (corrected offset)" :
"");
599 cpl_table_insert(pt->
table, aPixtables[i]->
table, nrow);
603 aPixtables[i] = NULL;
607 cpl_propertylist_append_long_long(pt->
header, keyword, nrow);
608 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_PT_EXP_FST_COMMENT, i + 1);
609 cpl_propertylist_set_comment(pt->
header, keyword, comment);
611 cpl_propertylist_append_long_long(pt->
header, keyword,
613 snprintf(comment, KEYWORD_LENGTH, MUSE_HDR_PT_EXP_LST_COMMENT, i + 1);
614 cpl_propertylist_set_comment(pt->
header, keyword, comment);
620 MUSE_HDR_PT_COMBINED_COMMENT);
622 double timefini = cpl_test_get_walltime(),
623 cpufini = cpl_test_get_cputime();
625 cpl_msg_debug(__func__,
"Combining %u tables took %gs (wall-clock) and %gs " 626 "(CPU)", npt, timefini - timeinit, cpufini - cpuinit);
#define MUSE_PIXTABLE_XPOS
#define MUSE_HDR_PT_EXP_FST
FITS header keyword defining the first row index for a given exposure.
double muse_pfits_get_ra(const cpl_propertylist *aHeaders)
find out the right ascension
cpl_size muse_pixtable_get_nrow(const muse_pixtable *aPixtable)
get the number of rows within the pixel table
double muse_pfits_get_ia_fwhm(const cpl_propertylist *aHeaders)
find out the image analysis FWHM corrected by airmass (in arcsec)
#define MUSE_HDR_PT_EXP_LST
FITS header keyword defining the last row index for a given exposure.
double muse_pfits_get_agy_avg(const cpl_propertylist *aHeaders)
find out the y-FWHM average value from the auto-guider (in arcsec)
void muse_utils_memory_dump(const char *aMarker)
Display the current memory usage of the given program.
const char * muse_pfits_get_dateobs(const cpl_propertylist *aHeaders)
find out the date of observations
#define MUSE_HDR_PT_COMBINED
cpl_table * table
The pixel table.
cpl_error_code muse_xcombine_weights(muse_pixtable **aPixtables, muse_xcombine_types aWeighting)
compute the weights for combination of two or more exposures
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.
#define MUSE_PIXTABLE_WEIGHT
double muse_pfits_get_fwhm_end(const cpl_propertylist *aHeaders)
find out the ambient seeing at end of exposure (in arcsec)
Structure definition of MUSE pixel table.
double * muse_xcombine_find_offsets(const cpl_table *aOffsets, const char *aDateObs)
Get offsets and scale from table row with matching DATE-OBS entry.
#define MUSE_HDR_PT_WEIGHTED
muse_pixtable_wcs muse_pixtable_wcs_check(muse_pixtable *aPixtable)
Check the state of the world coordinate system of a pixel table.
muse_pixtable * muse_xcombine_tables(muse_pixtable **aPixtables, const cpl_table *aOffsets)
combine the pixel tables of several exposures into one
double muse_pfits_get_fwhm_start(const cpl_propertylist *aHeaders)
find out the ambient seeing at start of exposure (in arcsec)
double muse_pfits_get_dec(const cpl_propertylist *aHeaders)
find out the declination
double muse_pfits_get_agy_rms(const cpl_propertylist *aHeaders)
find out the y-FWHM root mean square from the auto-guider (in arcsec)
double muse_pfits_get_agx_rms(const cpl_propertylist *aHeaders)
find out the x-FWHM root mean square from the auto-guider (in arcsec)
double muse_pfits_get_exptime(const cpl_propertylist *aHeaders)
find out the exposure time
cpl_error_code muse_wcs_position_celestial(muse_pixtable *aPixtable, double aRA, double aDEC)
Convert native to celestial spherical coordinates in a pixel table.
double muse_pfits_get_agx_avg(const cpl_propertylist *aHeaders)
find out the x-FWHM average value from the auto-guider (in arcsec)
#define MUSE_PIXTABLE_YPOS
void muse_pixtable_delete(muse_pixtable *aPixtable)
Deallocate memory associated to a pixel table object.
muse_xcombine_types
Xposure combination types.
cpl_error_code muse_pixtable_compute_limits(muse_pixtable *aPixtable)
(Re-)Compute the limits of the coordinate columns of a pixel table.
cpl_propertylist * header
The FITS header.
cpl_error_code muse_pixtable_flux_multiply(muse_pixtable *aPixtable, double aScale)
Scale the flux of a pixel table with correct treatment of variance.
cpl_boolean muse_pixtable_is_rvcorr(muse_pixtable *aPixtable)
Determine whether the pixel table is radial-velocity corrected.