29 #if HAVE_POPEN && HAVE_PCLOSE
36 #include "muse_wavecalib.h"
37 #include "muse_instrument.h"
39 #include "muse_combine.h"
40 #include "muse_cplwrappers.h"
41 #include "muse_data_format_z.h"
43 #include "muse_pfits.h"
44 #include "muse_tracing.h"
45 #include "muse_utils.h"
51 #define SEARCH_DEBUG 0
52 #define SEARCH_DEBUG_FILES 0
54 #define DEBUG_GAUSSFIT 0
55 #define MUSE_WAVE_LINES_SEARCH_SHIFT_WARN 3.0
57 #define MUSE_WAVE_LINE_FIT_MAXSHIFT 2.0
59 #define MUSE_WAVE_LINE_HANDLE_SHIFT_LIMIT 0.25
97 {
"lampno", CPL_TYPE_INT,
"",
"%d",
"Number of the lamp", CPL_TRUE },
98 {
"lampname", CPL_TYPE_STRING,
"",
"%s",
"Name of the lamp", CPL_TRUE },
99 {
"x", CPL_TYPE_DOUBLE,
"pix",
"%.2f",
"x-position on CCD", CPL_TRUE },
100 {
"y", CPL_TYPE_DOUBLE,
"pix",
"%.2f",
"first-guess y-position on CCD", CPL_TRUE },
101 {
"peak", CPL_TYPE_DOUBLE,
"pix",
"%g",
"Peak of line", CPL_TRUE },
102 {
"center", CPL_TYPE_DOUBLE,
"pix",
"%.4f",
"Gaussian line center", CPL_TRUE },
103 {
"cerr", CPL_TYPE_DOUBLE,
"pix",
"%.4f",
"error estimate of line center", CPL_TRUE },
104 {
"sigma", CPL_TYPE_DOUBLE,
"pix",
"%.3f",
"Gaussian sigma", CPL_TRUE },
105 {
"fwhm", CPL_TYPE_DOUBLE,
"pix",
"%.3f",
"Gaussian FWHM", CPL_TRUE },
106 {
"flux", CPL_TYPE_DOUBLE,
"count",
"%g",
"Gaussian area (flux)", CPL_TRUE },
107 {
"bg", CPL_TYPE_DOUBLE,
"count",
"%.2f",
"background level", CPL_TRUE },
108 {
"mse", CPL_TYPE_DOUBLE,
"",
"%e",
"mean squared error", CPL_TRUE },
109 {
"lambda", CPL_TYPE_DOUBLE,
"Angstrom",
"%9.3f",
110 "identified wavelength of the line", CPL_TRUE },
111 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
120 {
"slice", CPL_TYPE_INT,
"",
"%02d",
"slice number", CPL_TRUE},
121 {
"iteration", CPL_TYPE_INT,
"",
"%d",
"iteration", CPL_TRUE},
122 {
"x", CPL_TYPE_INT,
"pix",
"%04d",
"x-position on CCD", CPL_TRUE},
123 {
"y", CPL_TYPE_FLOAT,
"pix",
"%8.3f",
"y-position on CCD", CPL_TRUE},
124 {
"lambda", CPL_TYPE_FLOAT,
"Angstrom",
"%8.3f",
"wavelength", CPL_TRUE},
125 {
"residual", CPL_TYPE_DOUBLE,
"Angstrom",
"%.4e",
"residual at this point", CPL_TRUE},
126 {
"rejlimit", CPL_TYPE_DOUBLE,
"Angstrom",
"%.4e",
127 "rejection limit for this iteration", CPL_TRUE},
128 { NULL, 0, NULL, NULL, NULL, CPL_FALSE }
135 const char *muse_wave_weighting_string[] = {
138 "per-line RMS scatter",
139 "centroid error plus per-line RMS scatter"
167 p->
rflag = CPL_FALSE;
212 muse_wave_calib_qc_peaks(cpl_table *aLines, cpl_propertylist *aHeader,
213 const unsigned short aSlice)
215 char keyword[KEYWORD_LENGTH];
216 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_PEAK_MEAN, aSlice);
217 cpl_propertylist_append_float(aHeader, keyword,
218 cpl_table_get_column_mean(aLines,
"peak"));
219 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_PEAK_STDEV, aSlice);
220 cpl_propertylist_append_float(aHeader, keyword,
221 cpl_table_get_column_stdev(aLines,
"peak"));
222 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_PEAK_MIN, aSlice);
223 cpl_propertylist_append_float(aHeader, keyword,
224 cpl_table_get_column_min(aLines,
"peak"));
225 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_PEAK_MAX, aSlice);
226 cpl_propertylist_append_float(aHeader, keyword,
227 cpl_table_get_column_max(aLines,
"peak"));
234 for (n = 1; n < nlamps; n++) {
236 cpl_table_unselect_all(aLines);
237 cpl_table_or_selected_int(aLines,
"lampno", CPL_EQUAL_TO, n);
238 cpl_table *lamplines = cpl_table_extract_selected(aLines);
239 if (cpl_table_get_nrow(lamplines) < 1) {
240 cpl_table_delete(lamplines);
243 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LAMPl_LINES_PEAK_MEAN,
245 cpl_propertylist_append_float(aHeader, keyword,
246 cpl_table_get_column_mean(lamplines,
"peak"));
247 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LAMPl_LINES_PEAK_STDEV,
249 cpl_propertylist_append_float(aHeader, keyword,
250 cpl_table_get_column_stdev(lamplines,
"peak"));
251 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LAMPl_LINES_PEAK_MAX,
253 cpl_propertylist_append_float(aHeader, keyword,
254 cpl_table_get_column_max(lamplines,
"peak"));
255 cpl_table_delete(lamplines);
270 muse_wave_calib_qc_fwhm_old(cpl_table *aLines, cpl_propertylist *aHeader,
271 cpl_vector *aRefLam,
const unsigned short aSlice)
273 int nlines = cpl_table_get_nrow(aLines);
276 double Rmin = DBL_MAX, Rmax = -DBL_MAX, wlmin = DBL_MAX, wlmax = -DBL_MAX;
280 cpl_vector *fwhms = cpl_vector_new(nlines),
281 *resol = cpl_vector_new(cpl_vector_get_size(aRefLam));
283 for (i = 0; i < nlines; i++) {
285 cpl_errorstate prestate = cpl_errorstate_get();
286 double fwhm = cpl_table_get(aLines,
"fwhm", i, NULL),
287 sampling = kMuseSpectralSamplingA,
288 lambda = cpl_table_get(aLines,
"lambda", i, NULL),
289 s1 = (lambda - cpl_table_get(aLines,
"lambda", i - 1, NULL))
290 / (cpl_table_get(aLines,
"center", i, NULL)
291 - cpl_table_get(aLines,
"center", i - 1, NULL)),
292 s2 = (cpl_table_get(aLines,
"lambda", i + 1, NULL)
293 - cpl_table_get(aLines,
"lambda", i, NULL))
294 / (cpl_table_get(aLines,
"center", i + 1, NULL)
295 - cpl_table_get(aLines,
"center", i, NULL));
296 if (!cpl_errorstate_is_equal(prestate)) {
297 cpl_errorstate_set(prestate);
301 }
else if (i == nlines - 1) {
304 sampling = (s1 + s2) / 2.;
307 cpl_vector_set(fwhms, i, fwhm);
309 double R = lambda / fwhm;
311 if (fabs(cpl_vector_get(aRefLam, cpl_vector_find(aRefLam, lambda)) - lambda)
321 cpl_vector_set(resol, iresol++, R);
324 cpl_vector_set_size(resol, iresol);
326 char keyword[KEYWORD_LENGTH];
327 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_FWHM_MEAN, aSlice);
328 cpl_propertylist_append_float(aHeader, keyword, cpl_vector_get_mean(fwhms));
329 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_FWHM_STDEV, aSlice);
330 cpl_propertylist_append_float(aHeader, keyword, cpl_vector_get_stdev(fwhms));
331 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_FWHM_MIN, aSlice);
332 cpl_propertylist_append_float(aHeader, keyword, cpl_vector_get_min(fwhms));
333 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_FWHM_MAX, aSlice);
334 cpl_propertylist_append_float(aHeader, keyword, cpl_vector_get_max(fwhms));
335 cpl_vector_delete(fwhms);
337 cpl_msg_debug(__func__,
"Average spectral resolution in IFU %hhu is R=%4.0f, "
338 "ranging from %4.0f (at %6.1fA) to %4.0f (at %6.1fA)",
340 Rmin, wlmin, Rmax, wlmax);
341 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_RESOL, aSlice);
342 cpl_propertylist_append_float(aHeader, keyword, cpl_vector_get_mean(resol));
343 cpl_vector_delete(resol);
356 muse_wave_calib_qc_fwhm(cpl_table *aFWHM, cpl_propertylist *aHeader,
357 const unsigned short aSlice)
362 cpl_table_duplicate_column(aFWHM,
"R", aFWHM,
"lambda");
363 cpl_table_divide_columns(aFWHM,
"R",
"fwhm");
364 cpl_table_set_column_unit(aFWHM,
"R",
"");
368 cpl_table_unselect_all(aFWHM);
369 cpl_table_or_selected_double(aFWHM,
"lambda", CPL_LESS_THAN, 6000.);
370 cpl_table *tblue = cpl_table_extract_selected(aFWHM);
372 cpl_table_unselect_all(aFWHM);
373 cpl_table_or_selected_double(aFWHM,
"lambda", CPL_GREATER_THAN, 8000.);
374 cpl_table *tred = cpl_table_extract_selected(aFWHM);
376 cpl_table_unselect_all(aFWHM);
377 cpl_table_or_selected_double(aFWHM,
"lambda", CPL_NOT_LESS_THAN, 6000.);
378 cpl_table_and_selected_double(aFWHM,
"lambda", CPL_NOT_GREATER_THAN, 8000.);
379 cpl_table *tgreen = cpl_table_extract_selected(aFWHM);
382 cpl_table_dump(aFWHM, 0, 100000, stdout);
385 cpl_table_dump(tblue, 0, 100000, stdout);
388 cpl_table_dump(tgreen, 0, 100000, stdout);
391 cpl_table_dump(tred, 0, 100000, stdout);
397 char keyword[KEYWORD_LENGTH];
398 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_RESOL, aSlice);
399 double rmean = cpl_table_get_column_mean(aFWHM,
"R");
400 cpl_propertylist_update_float(aHeader, keyword, rmean);
402 double fmean = cpl_table_get_column_mean(aFWHM,
"fwhm"),
403 fstdev = cpl_table_get_column_stdev(aFWHM,
"fwhm"),
404 flo = cpl_table_get_column_min(aFWHM,
"fwhm"),
405 fhi = cpl_table_get_column_max(aFWHM,
"fwhm");
406 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_FWHM_MEAN, aSlice);
407 cpl_propertylist_update_float(aHeader, keyword, fmean);
408 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_FWHM_STDEV, aSlice);
409 cpl_propertylist_update_float(aHeader, keyword, fstdev);
410 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_FWHM_MIN, aSlice);
411 cpl_propertylist_update_float(aHeader, keyword, flo);
412 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_FWHM_MAX, aSlice);
413 cpl_propertylist_update_float(aHeader, keyword, fhi);
417 cpl_msg_debug(__func__,
"Gaussian FWHM [%s]:\n"
418 "\tFWHM all (%d values)\t%.3f +/- %.3f (%.3f) %.3f...%.3f\n"
419 "\tFWHM blue (%d values)\t%.3f +/- %.3f (%.3f)\n"
420 "\tFWHM green (%d values)\t%.3f +/- %.3f (%.3f)\n"
421 "\tFWHM red (%d values)\t%.3f +/- %.3f (%.3f)",
422 cpl_table_get_column_unit(aFWHM,
"fwhm"),
423 (
int)cpl_table_get_nrow(aFWHM), fmean, fstdev, flo, fhi,
424 cpl_table_get_column_median(aFWHM,
"fwhm"),
425 (
int)cpl_table_get_nrow(tblue),
426 cpl_table_get_column_mean(tblue,
"fwhm"),
427 cpl_table_get_column_stdev(tblue,
"fwhm"),
428 cpl_table_get_column_median(tblue,
"fwhm"),
429 (
int)cpl_table_get_nrow(tgreen),
430 cpl_table_get_column_mean(tgreen,
"fwhm"),
431 cpl_table_get_column_stdev(tgreen,
"fwhm"),
432 cpl_table_get_column_median(tgreen,
"fwhm"),
433 (
int)cpl_table_get_nrow(tred),
434 cpl_table_get_column_mean(tred,
"fwhm"),
435 cpl_table_get_column_stdev(tred,
"fwhm"),
436 cpl_table_get_column_median(tred,
"fwhm"));
437 cpl_msg_debug(__func__,
"Gaussian spectral resolution R:\n"
438 "\tR all (%d values)\t%.1f +/- %.1f (%.1f) %.1f...%.1f\n"
439 "\tR blue (%d values)\t%.1f +/- %.1f (%.1f)\n"
440 "\tR green (%d values)\t%.1f +/- %.1f (%.1f)\n"
441 "\tR red (%d values)\t%.1f +/- %.1f (%.1f)",
442 (
int)cpl_table_get_nrow(aFWHM), rmean,
443 cpl_table_get_column_stdev(aFWHM,
"R"),
444 cpl_table_get_column_median(aFWHM,
"R"),
445 cpl_table_get_column_min(aFWHM,
"R"),
446 cpl_table_get_column_max(aFWHM,
"R"),
447 (
int)cpl_table_get_nrow(tblue),
448 cpl_table_get_column_mean(tblue,
"R"),
449 cpl_table_get_column_stdev(tblue,
"R"),
450 cpl_table_get_column_median(tblue,
"R"),
451 (
int)cpl_table_get_nrow(tgreen),
452 cpl_table_get_column_mean(tgreen,
"R"),
453 cpl_table_get_column_stdev(tgreen,
"R"),
454 cpl_table_get_column_median(tgreen,
"R"),
455 (
int)cpl_table_get_nrow(tred),
456 cpl_table_get_column_mean(tred,
"R"),
457 cpl_table_get_column_stdev(tred,
"R"),
458 cpl_table_get_column_median(tred,
"R"));
459 cpl_table_delete(tblue);
460 cpl_table_delete(tgreen);
461 cpl_table_delete(tred);
463 cpl_table_erase_column(aFWHM,
"R");
480 muse_wave_calib_qc_lambda(
muse_image *aImage,
const unsigned short aSlice,
481 cpl_polynomial **aTrace, cpl_polynomial *aFit)
483 int ny = cpl_image_get_size_y(aImage->
data);
487 double xbotl = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_LEFT], 1, NULL),
488 xbotr = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_RIGHT], 1, NULL),
489 xtopl = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_LEFT], ny, NULL),
490 xtopr = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_RIGHT], ny, NULL);
491 cpl_vector *pos = cpl_vector_new(2);
492 cpl_vector_set(pos, 0, xbotl);
493 cpl_vector_set(pos, 1, 1);
494 double wlbotl = cpl_polynomial_eval(aFit, pos);
495 cpl_vector_set(pos, 0, xbotr);
496 cpl_vector_set(pos, 1, 1);
497 double wlbotr = cpl_polynomial_eval(aFit, pos);
498 cpl_vector_set(pos, 0, xtopl);
499 cpl_vector_set(pos, 1, ny);
500 double wltopl = cpl_polynomial_eval(aFit, pos);
501 cpl_vector_set(pos, 0, xtopr);
502 cpl_vector_set(pos, 1, ny);
503 double wltopr = cpl_polynomial_eval(aFit, pos);
505 cpl_msg_debug(__func__,
"Wavelengths at slice corners in slice %hu of IFU %hhu: "
506 "botl(%.2f,1)=%f, botr(%.2f,1)=%f, topl(%.2f,%d)=%f, topr(%.2f,%d)"
507 "=%f", aSlice, ifu, xbotl, wlbotl, xbotr, wlbotr,
508 xtopl, ny, wltopl, xtopr, ny, wltopr);
510 char *keyword = cpl_sprintf(QC_WAVECAL_SLICEj_DWLEN_BOT, aSlice);
511 cpl_propertylist_append_float(aImage->
header, keyword, wlbotl - wlbotr);
513 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_DWLEN_TOP, aSlice);
514 cpl_propertylist_append_float(aImage->
header, keyword, wltopl - wltopr);
517 #define DWLEN_WARN_LIMIT_N 6.5
518 #define DWLEN_WARN_LIMIT_E 5.9
519 double limit = DWLEN_WARN_LIMIT_E;
520 cpl_errorstate prestate = cpl_errorstate_get();
522 limit = DWLEN_WARN_LIMIT_N;
524 cpl_errorstate_set(prestate);
525 if (fabs(wlbotl - wlbotr) > limit) {
526 cpl_msg_warning(__func__,
"Wavelength differences at bottom of slice %hu "
527 "of IFU %hhu are large (%f Angstrom)!", aSlice, ifu,
530 if (fabs(wltopl - wltopr) > DWLEN_WARN_LIMIT_E) {
531 cpl_msg_warning(__func__,
"Wavelength differences at top of slice %hu of IFU "
532 "%hhu are large (%f Angstrom)!", aSlice, ifu, wltopl - wltopr);
537 const double yc = (1. + ny) / 2.,
538 xc = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_CENTER], yc, NULL);
539 cpl_vector_set(pos, 0, xc);
540 cpl_vector_set(pos, 1, yc);
541 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_WLPOS, aSlice);
542 cpl_propertylist_append_float(aImage->
header, keyword, yc);
544 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_WLEN, aSlice);
545 cpl_propertylist_append_float(aImage->
header, keyword,
546 cpl_polynomial_eval(aFit, pos));
548 cpl_vector_delete(pos);
566 muse_wave_calib_output_summary(
const cpl_propertylist *aHeader,
567 const cpl_table *aWave)
571 cpl_msg_warning(__func__,
"Wavelength solution missing for IFU %hhu, no "
575 cpl_vector *found = cpl_vector_new(kMuseSlicesPerCCD),
576 *ident = cpl_vector_new(kMuseSlicesPerCCD),
577 *used = cpl_vector_new(kMuseSlicesPerCCD),
578 *resolution = cpl_vector_new(kMuseSlicesPerCCD);
579 unsigned short islice;
580 for (islice = 0; islice < kMuseSlicesPerCCD; islice++) {
581 char keyword[KEYWORD_LENGTH];
582 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_NDET, islice + 1);
583 cpl_vector_set(found, islice, cpl_propertylist_get_int(aHeader, keyword));
584 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_LINES_NID, islice + 1);
585 cpl_vector_set(ident, islice, cpl_propertylist_get_int(aHeader, keyword));
586 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_FIT_NLINES, islice + 1);
587 cpl_vector_set(used, islice, cpl_propertylist_get_int(aHeader, keyword));
588 snprintf(keyword, KEYWORD_LENGTH, QC_WAVECAL_SLICEj_RESOL, islice + 1);
589 cpl_vector_set(resolution, islice, cpl_propertylist_get_float(aHeader, keyword));
591 cpl_msg_info(__func__,
"Summary of wavelength solution for IFU %hhu:\n"
592 "\tDetections per slice: %d ... %d\n"
593 "\tIdentified lines per slice: %d ... %d\n"
594 "\tLines per slice used in fit: %d ... %d\n"
595 "\tRMS of fit [Angstrom]: %5.3f +/- %5.3f (%5.3f ... %5.3f)\n"
596 "\tMean spectral resolution R: %6.1f +/- %5.1f", ifu,
597 (
int)cpl_vector_get_min(found), (
int)cpl_vector_get_max(found),
598 (
int)cpl_vector_get_min(ident), (
int)cpl_vector_get_max(ident),
599 (
int)cpl_vector_get_min(used), (
int)cpl_vector_get_max(used),
600 sqrt(cpl_table_get_column_mean(aWave, MUSE_WAVECAL_TABLE_COL_MSE)),
601 sqrt(cpl_table_get_column_stdev(aWave, MUSE_WAVECAL_TABLE_COL_MSE)),
602 sqrt(cpl_table_get_column_min(aWave, MUSE_WAVECAL_TABLE_COL_MSE)),
603 sqrt(cpl_table_get_column_max(aWave, MUSE_WAVECAL_TABLE_COL_MSE)),
604 cpl_vector_get_mean(resolution), cpl_vector_get_stdev(resolution));
605 cpl_vector_delete(found);
606 cpl_vector_delete(ident);
607 cpl_vector_delete(used);
608 cpl_vector_delete(resolution);
663 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"arc image missing!");
668 double minstat = cpl_image_get_min(aImage->
stat);
670 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
"arc image %d does"
671 " not have valid STAT extension in IFU %hhu (minimum "
672 "is %e)!", 0, ifu, minstat);
677 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"trace table missing "
678 "for IFU %hhu, cannot create wavelength calibration!",
681 }
else if (cpl_table_get_nrow(aTrace) != kMuseSlicesPerCCD) {
682 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
"trace table "
683 "not valid for this dataset of IFU %hhu!", ifu);
688 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"no arc line list "
689 "supplied for IFU %hhu!", ifu);
693 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"wavelength "
694 "calibration parameters missing for IFU %hhu!", ifu);
698 cpl_error_set_message(__func__, CPL_ERROR_UNSUPPORTED_MODE,
699 "unknown weighting scheme for IFU %hhu", ifu);
704 int nx = cpl_image_get_size_x(aImage->
data),
705 ny = cpl_image_get_size_y(aImage->
data);
707 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
"this dataset of "
708 "IFU %hhu is too small (%dx%d pix) to be supported",
713 cpl_msg_info(__func__,
"Using polynomial orders %hu (x) and %hu (y), %s "
714 "weighting, assuming initial sampling of %.3f +/- %.3f Angstrom"
717 kMuseSpectralSamplingA, aParams->
ddisp, ifu);
721 cpl_error_set_message(__func__, CPL_ERROR_BAD_FILE_FORMAT,
"could not "
722 "create list of FWHM reference arc wavelengths for "
727 cpl_propertylist_erase_regexp(aImage->
header,
"^ESO QC", 0);
728 cpl_table *wavecaltable = NULL;
730 int debug = getenv(
"MUSE_DEBUG_WAVECAL")
731 ? atoi(getenv(
"MUSE_DEBUG_WAVECAL")) : 0;
733 FILE *fp_debug = NULL;
735 snprintf(fn_debug, 99,
"MUSE_DEBUG_WAVE_LINES-%02hhu.ascii", ifu);
736 cpl_msg_info(__func__,
"Will write all single line fits to \"%s\"", fn_debug);
737 fp_debug = fopen(fn_debug,
"w");
739 fprintf(fp_debug,
"#slice x y lambda lambdaerr\n");
744 unsigned short islice;
745 for (islice = 0; islice < kMuseSlicesPerCCD; islice++) {
747 printf(
"\n\nSlice %hu of IFU %hhu\n", islice + 1, ifu);
754 cpl_msg_warning(__func__,
"slice %2hu of IFU %hhu: tracing polynomials "
755 "missing!", islice + 1, ifu);
760 int imid = lround(cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_CENTER],
762 if (imid < 1 || imid > nx) {
763 cpl_msg_warning(__func__,
"slice %2hu of IFU %hhu: faulty trace polynomial"
764 " detected", islice + 1, ifu);
769 const int kWidth = 3;
770 int k, kcol1 = imid - kWidth/2, kcol2 = kcol1 + kWidth;
772 for (k = kcol1; k <= kcol2; k++) {
774 column->
data = cpl_image_extract(aImage->
data, k, 1, k, ny);
775 column->
dq = cpl_image_extract(aImage->
dq, k, 1, k, ny);
776 column->
stat = cpl_image_extract(aImage->
stat, k, 1, k, ny);
777 column->
header = cpl_propertylist_new();
778 cpl_propertylist_append_string(column->
header,
"BUNIT",
779 cpl_propertylist_get_string(aImage->
header,
790 cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
"problem when "
791 "searching for arc lines in slice %hu of IFU %hhu, "
792 "columns %d..%d", islice + 1, ifu, kcol1, kcol2);
794 cpl_vector_delete(vreflam);
796 cpl_table_delete(wavecaltable);
804 printf(
"Detected arc lines in slice %hu of IFU %hhu:\n", islice + 1, ifu);
805 cpl_table_dump(detlines, 0, cpl_table_get_nrow(detlines), stdout);
811 int nfound = cpl_table_get_nrow(detlines);
813 double minflux = cpl_table_get_column_min(detlines,
"flux") * 1.15;
816 cpl_vector_delete(vlambda);
817 int nlines = cpl_table_get_nrow(detlines);
818 cpl_msg_debug(__func__,
"Identified %d of %d arc lines in slice %hu of IFU "
819 "%hhu (column %d, %d..%d)", nlines, nfound, islice + 1, ifu,
822 printf(
"Identified arc lines with wavelengths in slice %hu of IFU %hhu:\n",
824 cpl_table_dump(detlines, 0, cpl_table_get_nrow(detlines), stdout);
829 char *keyword = cpl_sprintf(QC_WAVECAL_SLICEj_LINES_NDET, islice + 1);
830 cpl_propertylist_append_int(aImage->
header, keyword, nfound);
833 if (nlines < aParams->yorder + 1) {
835 cpl_msg_error(__func__,
"Could not identify enough arc lines in slice %hu"
836 " of IFU %hhu (%d of %d, required %hu)", islice + 1, ifu,
837 nlines, nfound, aParams->
yorder + 1);
839 cpl_table_delete(detlines);
844 muse_wave_calib_qc_peaks(detlines, aImage->
header, islice + 1);
845 muse_wave_calib_qc_fwhm_old(detlines, aImage->
header, vreflam, islice + 1);
848 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_LINES_NID, islice + 1);
849 cpl_propertylist_append_int(aImage->
header, keyword, nlines);
854 cpl_matrix *xypos = cpl_matrix_new(2, 1);
855 cpl_vector *lambdas = cpl_vector_new(1),
858 dlambdas = cpl_vector_new(1);
864 for (j = 0; j < nlines; j++) {
866 double lambda = cpl_table_get(detlines,
"lambda", j, NULL);
867 double ypos = cpl_table_get(detlines,
"center", j, NULL);
870 double sigma = cpl_table_get(detlines,
"sigma", j, NULL);
872 halfwidth = 2.*cpl_table_get(detlines,
"fwhm", j, NULL);
874 double dleft = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_LEFT],
876 dright = cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_RIGHT],
878 dmid = (dleft + dright) / 2.;
879 int ileft = ceil(dleft),
880 iright = floor(dright);
882 cpl_msg_debug(__func__,
"limits at y=%f: %f < %f < %f", ypos, dleft, dmid,
888 (
int)kMuseSliceHiLikelyWidth + 5);
893 for (i = dmid; i >= ileft; i--) {
895 sigma, fittable, ++n);
896 if (rc != CPL_ERROR_NONE) {
901 printf(
"arc line j=%d, columns i=%d...", j + 1, i);
903 for (i = dmid + 1; i <= iright; i++) {
905 sigma, fittable, ++n);
906 if (rc != CPL_ERROR_NONE) {
913 cpl_table_select_all(fittable);
914 cpl_table_and_selected_invalid(fittable,
"center");
915 cpl_table_erase_selected(fittable);
917 printf(
"line %d, %d line fits\n", j + 1, i);
918 cpl_table_dump(fittable, 0, n, stdout);
921 cpl_errorstate state = cpl_errorstate_get();
923 int npos = cpl_table_get_nrow(fittable);
924 if (npos <= aParams->xorder) {
925 cpl_msg_debug(__func__,
"Polynomial fit failed in slice %hu of IFU %hhu"
926 " for line at %.3fA (y-position near %.2f pix): %s",
927 islice + 1, ifu, lambda, ypos, cpl_error_get_message());
928 cpl_errorstate_set(state);
932 printf(
"%s: line %2d, %d line fits, %d with low residuals:\n", __func__,
934 cpl_table_dump(fittable, 0, npos, stdout);
940 cpl_matrix_resize(xypos, 0, 0,
941 0, ientry + npos - cpl_matrix_get_ncol(xypos));
942 cpl_vector_set_size(lambdas, ientry + npos);
944 cpl_vector_set_size(dlambdas, ientry + npos);
949 for (ipos = 0; ipos < npos; ipos++) {
951 cpl_matrix_set(xypos, 0, ientry, cpl_table_get(fittable,
"x", ipos, NULL));
953 cpl_matrix_set(xypos, 1, ientry, cpl_table_get(fittable,
"center", ipos, NULL));
955 cpl_vector_set(lambdas, ientry, lambda);
960 cpl_vector_set(dlambdas, ientry, cpl_table_get(fittable,
"cerr", ipos, NULL)
961 * kMuseSpectralSamplingA);
966 fprintf(fp_debug,
" %02hu %04d %9.4f %10.4f %e\n", islice + 1,
967 (
int)cpl_table_get(fittable,
"x", ipos, NULL),
968 cpl_table_get(fittable,
"center", ipos, NULL), lambda,
969 cpl_table_get(fittable,
"cerr", ipos, NULL) * kMuseSpectralSamplingA);
972 cpl_table_delete(fittable);
975 cpl_table_delete(detlines);
978 cpl_polynomial *poly = NULL;
981 &poly, &mse, aParams, islice + 1);
982 cpl_matrix_delete(xypos);
984 cpl_vector_delete(lambdas);
985 cpl_vector_delete(dlambdas);
988 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_FIT_NLINES, islice + 1);
989 cpl_propertylist_append_int(aImage->
header, keyword, nfinal);
992 muse_wave_calib_qc_lambda(aImage, islice + 1, ptrace, poly);
996 if (rc != CPL_ERROR_NONE) {
997 cpl_msg_warning(__func__,
"Something went wrong while fitting in slice "
998 "%hu of IFU %hhu: %s", islice + 1, ifu,
999 cpl_error_get_message_default(rc));
1000 cpl_polynomial_delete(poly);
1004 if (!wavecaltable) {
1015 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_FIT_RMS, islice + 1);
1016 cpl_propertylist_append_float(aImage->
header, keyword, sqrt(mse));
1019 if (rc != CPL_ERROR_NONE) {
1020 cpl_msg_warning(__func__,
"Could not write polynomial to wavecal table "
1021 "for slice %hu of IFU %hhu: %s", islice + 1, ifu,
1022 cpl_error_get_message_default(rc));
1025 cpl_polynomial_delete(poly);
1027 cpl_vector_delete(vreflam);
1029 cpl_msg_info(__func__,
"Done writing line fits to \"%s\"", fn_debug);
1033 muse_wave_calib_output_summary(aImage->
header, wavecaltable);
1035 if (cpl_msg_get_level() == CPL_MSG_DEBUG) {
1036 cpl_table_dump(wavecaltable, 0, 3, stdout); fflush(stdout);
1040 return wavecaltable;
1113 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"arc imagelist is "
1114 "missing or empty!");
1119 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"trace table missing "
1120 "for IFU %hhu, cannot create wavelength calibration!",
1123 }
else if (cpl_table_get_nrow(aTrace) != kMuseSlicesPerCCD) {
1124 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
"trace table "
1125 "not valid for this dataset of IFU %hhu!", ifu);
1129 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"no arc line list "
1130 "supplied for IFU %hhu!", ifu);
1134 cpl_error_set_message(__func__, CPL_ERROR_NULL_INPUT,
"wavelength "
1135 "calibration parameters missing for IFU %hhu!", ifu);
1139 cpl_error_set_message(__func__, CPL_ERROR_UNSUPPORTED_MODE,
1140 "unknown weighting scheme for IFU %hhu", ifu);
1145 int nx = cpl_image_get_size_x(firstimage->
data),
1146 ny = cpl_image_get_size_y(firstimage->
data);
1149 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_INPUT,
"this dataset of "
1150 "IFU %hhu is too small (%dx%d pix) to be supported",
1155 cpl_msg_info(__func__,
"Using polynomial orders %hu (x) and %hu (y), %s "
1156 "weighting, assuming initial sampling of %.3f +/- %.3f Angstrom"
1159 kMuseSpectralSamplingA, aParams->
ddisp, ifu);
1161 cpl_propertylist_erase_regexp(firstimage->
header,
"^ESO QC", 0);
1163 cpl_msg_debug(__func__,
"Image 1 was taken with lamp %s", lamp);
1169 if (nxk != nx || nyk != ny) {
1170 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
"arc "
1171 "imagelist is not uniform (image %u is %dx%d, "
1172 "first image is %dx%d)", k + 1, nxk, nyk, nx, ny);
1178 cpl_msg_debug(__func__,
"Image %d was taken with lamp %s", k + 1, lamp);
1184 cpl_error_set_message(__func__, CPL_ERROR_BAD_FILE_FORMAT,
"could not "
1185 "create list of FWHM reference arc wavelengths for "
1189 cpl_table *wavecal = NULL;
1190 int debug = getenv(
"MUSE_DEBUG_WAVECAL")
1191 ? atoi(getenv(
"MUSE_DEBUG_WAVECAL")) : 0;
1193 FILE *fp_debug = NULL;
1195 snprintf(fn_debug, 99,
"MUSE_DEBUG_WAVE_LINES-%02hhu.ascii", ifu);
1196 cpl_msg_info(__func__,
"Will write all single line fits to \"%s\"", fn_debug);
1197 fp_debug = fopen(fn_debug,
"w");
1199 fprintf(fp_debug,
"#slice x y lambda lambdaerr\n");
1204 unsigned short islice;
1205 for (islice = 0; islice < kMuseSlicesPerCCD; islice++) {
1207 printf(
"\n\nSlice %hu of IFU %hhu\n", islice + 1, ifu);
1214 cpl_msg_warning(__func__,
"slice %2hu of IFU %hhu: tracing polynomials "
1215 "missing!", islice + 1, ifu);
1219 const int imid = lround(cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_CENTER],
1222 icol1 = imid - iWidth/2,
1223 icol2 = icol1 + iWidth;
1224 if (imid < 1 || imid > nx) {
1225 cpl_msg_warning(__func__,
"slice %2hu of IFU %hhu: faulty trace polynomial"
1226 "detected", islice + 1, ifu);
1230 cpl_table *detlines = NULL;
1237 for (i = icol1; i <= icol2; i++) {
1239 column->
data = cpl_image_extract(arc->
data, i, 1, i, ny);
1240 column->
dq = cpl_image_extract(arc->
dq, i, 1, i, ny);
1241 column->
stat = cpl_image_extract(arc->
stat, i, 1, i, ny);
1242 column->
header = cpl_propertylist_new();
1243 cpl_propertylist_append_string(column->
header,
"BUNIT",
1244 cpl_propertylist_get_string(arc->
header,
1255 int nlampdet = cpl_table_get_nrow(detections);
1258 cpl_table_fill_column_window_string(detections,
"lampname", 0, nlampdet,
1261 cpl_table_fill_column_window_int(detections,
"lampno", 0, nlampdet,
1262 cpl_array_get_int(lampnumbers, 0, NULL));
1263 cpl_array_delete(lampnumbers);
1265 double minflux = cpl_table_get_column_min(detections,
"flux") * 1.15;
1270 cpl_vector_delete(ionlambdas);
1273 detlines = detections;
1275 cpl_table_insert(detlines, detections, cpl_table_get_nrow(detlines));
1276 cpl_table_delete(detections);
1279 cpl_propertylist *order = cpl_propertylist_new();
1280 cpl_propertylist_append_bool(order,
"y", CPL_FALSE);
1281 cpl_table_sort(detlines, order);
1282 cpl_propertylist_delete(order);
1283 int nlines = cpl_table_get_nrow(detlines);
1285 printf(
"Detected and identified %d arc lines in slice %hu of IFU %hhu:\n",
1286 nlines, islice + 1, ifu);
1287 cpl_table_dump(detlines, 0, cpl_table_get_nrow(detlines), stdout);
1291 char *keyword = cpl_sprintf(QC_WAVECAL_SLICEj_LINES_NDET, islice + 1);
1292 cpl_propertylist_append_int(firstimage->
header, keyword, ndet);
1295 if (nlines < aParams->yorder + 1) {
1297 cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
"could not "
1298 "detect and/or identify enough arc lines in slice "
1299 "%hu of IFU %hhu (%d of %d, required %hu)",
1300 islice + 1, ifu, nlines, ndet, aParams->
yorder + 1);
1302 cpl_table_delete(detlines);
1305 cpl_msg_info(__func__,
"Identified %d of %d detected arc lines in slice %hu"
1306 " of IFU %hhu (column %d, %d..%d)", nlines, ndet, islice + 1,
1307 ifu, imid, icol1, icol2);
1310 muse_wave_calib_qc_peaks(detlines, firstimage->
header, islice + 1);
1313 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_LINES_NID, islice + 1);
1314 cpl_propertylist_append_int(firstimage->
header, keyword, nlines);
1319 cpl_vector *cen = cpl_vector_new(nlines);
1320 cpl_matrix *lbda = cpl_matrix_new(1, nlines);
1322 for (idx = 0; idx < nlines; idx++) {
1323 cpl_vector_set(cen, idx, cpl_table_get(detlines,
"center", idx, NULL));
1324 cpl_matrix_set(lbda, 0, idx, cpl_table_get(detlines,
"lambda", idx, NULL));
1327 char *fn = cpl_sprintf(
"slice%02hu_lbda1.dat", islice + 1);
1328 FILE *file = fopen(fn,
"w");
1329 cpl_matrix_dump(lbda, file);
1333 double mse1d, chisq1d;
1339 cpl_vector *res = cpl_vector_new(cpl_vector_get_size(cen));
1340 cpl_vector_fill_polynomial_fit_residual(res, cen, NULL, fit, lbda, NULL);
1341 cpl_bivector *biv = cpl_bivector_wrap_vectors(cen, res);
1342 cpl_plot_bivector(NULL, NULL, NULL, biv);
1343 cpl_bivector_unwrap_vectors(biv);
1344 cpl_vector_delete(res);
1347 printf(
"Initial (inverse) polynomial fit in slice %2hu of IFU %hhu "
1348 "(RMS = %f, chisq = %e, %d of %d input points left)\n", islice + 1,
1349 ifu, sqrt(mse1d), chisq1d, (
int)cpl_vector_get_size(cen), nlines);
1350 cpl_polynomial_dump(fit, stdout);
1353 nlines = cpl_vector_get_size(cen);
1355 fn = cpl_sprintf(
"slice%02hu_lbda2.dat", islice + 1);
1356 file = fopen(fn,
"w");
1357 cpl_matrix_dump(lbda, file);
1361 cpl_vector_delete(cen);
1362 cpl_matrix_delete(lbda);
1366 cpl_matrix *xypos = cpl_matrix_new(2, 1);
1367 cpl_vector *lambdas = cpl_vector_new(1),
1370 dlambdas = cpl_vector_new(1);
1376 cpl_table_set_column_unit(fwhmtable,
"fwhm",
"Angstrom");
1377 int j, narclines = cpl_table_get_nrow(aLinelist);
1378 for (j = 0; j < narclines; j++) {
1379 int quality = cpl_table_get_int(aLinelist, MUSE_LINE_CATALOG_QUALITY, j, NULL);
1390 cpl_boolean match = CPL_FALSE;
1391 if (lampname && thislamp) {
1392 match = strncmp(lampname, thislamp, strlen(lampname)) == 0;
1400 cpl_table *fittable = NULL;
1403 aParams, islice + 1, debug);
1406 aParams, islice + 1, debug);
1411 int nnew = cpl_table_get_nrow(fittable);
1414 cpl_matrix_resize(xypos, 0, 0,
1415 0, ientry + nnew - cpl_matrix_get_ncol(xypos));
1416 cpl_vector_set_size(lambdas, ientry + nnew);
1418 cpl_vector_set_size(dlambdas, ientry + nnew);
1422 cpl_table_set_column_unit(fittable,
"fwhm",
"");
1424 for (ipos = 0; ipos < nnew; ipos++) {
1426 cpl_matrix_set(xypos, 0, ientry, cpl_table_get(fittable,
"x", ipos, NULL));
1428 cpl_matrix_set(xypos, 1, ientry, cpl_table_get(fittable,
"center", ipos, NULL));
1430 double lambda = cpl_table_get(fittable,
"lambda", ipos, NULL);
1431 cpl_vector_set(lambdas, ientry, lambda);
1435 cpl_polynomial_eval_1d(fit, lambda, &dlbda);
1438 cerr = cpl_table_get(fittable,
"cerr", ipos, NULL) / dlbda;
1439 cpl_vector_set(dlambdas, ientry, cerr);
1443 double fwhm = cpl_table_get(fittable,
"fwhm", ipos, &err) / dlbda;
1445 cpl_table_set(fittable,
"fwhm", ipos, fwhm);
1449 fprintf(fp_debug,
" %02hu %04d %9.4f %10.4f %e\n", islice + 1,
1450 (
int)cpl_table_get(fittable,
"x", ipos, NULL),
1451 cpl_table_get(fittable,
"center", ipos, NULL), lambda, cerr);
1454 cpl_table_set_column_unit(fittable,
"fwhm",
"Angstrom");
1456 cpl_table_select_all(fittable);
1457 cpl_table_and_selected_invalid(fittable,
"fwhm");
1458 cpl_table_erase_selected(fittable);
1459 cpl_table_insert(fwhmtable, fittable, cpl_table_get_nrow(fwhmtable));
1460 cpl_table_delete(fittable);
1463 cpl_table_abs_column(aLinelist, MUSE_LINE_CATALOG_QUALITY);
1465 cpl_table_delete(detlines);
1466 cpl_polynomial_delete(fit);
1467 muse_wave_calib_qc_fwhm(fwhmtable, firstimage->
header, islice + 1);
1468 cpl_table_delete(fwhmtable);
1471 cpl_polynomial *poly = NULL;
1474 &poly, &mse2d, aParams, islice + 1);
1475 cpl_msg_info(__func__,
"Polynomial fit of %"CPL_SIZE_FORMAT
" of %d positions"
1476 " in slice %hu of IFU %hhu gave an RMS of %f Angstrom",
1477 cpl_vector_get_size(lambdas), ientry, islice + 1, ifu,
1479 cpl_matrix_delete(xypos);
1481 cpl_vector_delete(lambdas);
1482 cpl_vector_delete(dlambdas);
1485 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_FIT_NLINES, islice + 1);
1486 cpl_propertylist_append_int(firstimage->
header, keyword, nfinal);
1489 muse_wave_calib_qc_lambda(firstimage, islice + 1, ptrace, poly);
1493 if (rc != CPL_ERROR_NONE) {
1494 cpl_error_set_message(__func__, rc,
"a failure while computing the two-di"
1495 "mensional polynomial fit in slice %hu of IFU %hhu",
1497 cpl_polynomial_delete(poly);
1512 keyword = cpl_sprintf(QC_WAVECAL_SLICEj_FIT_RMS, islice + 1);
1513 cpl_propertylist_append_float(firstimage->
header, keyword, sqrt(mse2d));
1516 if (rc != CPL_ERROR_NONE) {
1517 cpl_msg_warning(__func__,
"Could not write polynomial to wavecal table "
1518 "for slice %hu of IFU %hhu: %s", islice + 1, ifu,
1519 cpl_error_get_message_default(rc));
1522 cpl_polynomial_delete(poly);
1524 cpl_vector_delete(vreflam);
1526 cpl_msg_info(__func__,
"Done writing line fits to \"%s\"", fn_debug);
1530 muse_wave_calib_output_summary(firstimage->
header, wavecal);
1534 cpl_propertylist_erase_regexp(header,
"^ESO QC", 0);
1535 cpl_propertylist_copy_property_regexp(header, firstimage->
header,
"^ESO QC", 0);
1563 cpl_ensure(aTable && aHeader, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1565 int nrow = cpl_table_get_nrow(aTable);
1566 cpl_ensure(nrow > 0, CPL_ERROR_NULL_INPUT, CPL_FALSE);
1568 CPL_ERROR_DATA_NOT_FOUND, CPL_FALSE);
1571 if (!cpl_propertylist_has(aHeader, MUSE_HDR_LINE_CATALOG_VERSION)) {
1572 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
"%s does not "
1573 "contain a VERSION header entry!", MUSE_TAG_LINE_CATALOG);
1576 int version = cpl_propertylist_get_int(aHeader, MUSE_HDR_LINE_CATALOG_VERSION);
1577 #define LINE_CATALOG_EXPECTED_VERSION 3
1578 if (version != LINE_CATALOG_EXPECTED_VERSION) {
1579 cpl_error_set_message(__func__, CPL_ERROR_BAD_FILE_FORMAT,
"VERSION = %d "
1580 "is wrong, we need a %s with VERSION = %d", version,
1581 MUSE_TAG_LINE_CATALOG, LINE_CATALOG_EXPECTED_VERSION);
1613 cpl_ensure(aTable, CPL_ERROR_NULL_INPUT, NULL);
1614 int nrow = cpl_table_get_nrow(aTable);
1615 cpl_ensure(nrow > 0, CPL_ERROR_NULL_INPUT, NULL);
1617 cpl_ensure(cpl_table_has_column(aTable, MUSE_LINE_CATALOG_LAMBDA) == 1
1618 && cpl_table_has_column(aTable, MUSE_LINE_CATALOG_QUALITY) == 1,
1619 CPL_ERROR_DATA_NOT_FOUND, NULL);
1622 cpl_vector *lambdas = cpl_vector_new(nrow);
1624 for (i = 0; i < nrow; i++) {
1625 double lambda = cpl_table_get(aTable, MUSE_LINE_CATALOG_LAMBDA, i, NULL),
1626 flux = cpl_table_get(aTable, MUSE_LINE_CATALOG_FLUX, i, NULL);
1629 if (i > 0 && lambda < cpl_table_get(aTable, MUSE_LINE_CATALOG_LAMBDA, i-1,
1631 cpl_error_set_message(__func__, CPL_ERROR_INCOMPATIBLE_INPUT,
"%s is not "
1632 "sorted by increasing lambda (at row %d)!",
1633 MUSE_TAG_LINE_CATALOG, i+1);
1634 cpl_vector_delete(lambdas);
1638 if (cpl_table_get(aTable, MUSE_LINE_CATALOG_QUALITY, i, NULL)
1639 < aGoodnessLimit || flux < aFluxLimit) {
1643 cpl_vector_set(lambdas, pos, lambda);
1647 cpl_vector_delete(lambdas);
1648 cpl_error_set_message(__func__, CPL_ERROR_DATA_NOT_FOUND,
"No lines with "
1649 "%s >= %d found", MUSE_LINE_CATALOG_QUALITY,
1654 cpl_vector_set_size(lambdas, pos);
1657 for (i = 0; i < cpl_vector_get_size(lambdas) - 1; i++) {
1658 double l1 = cpl_vector_get(lambdas, i),
1659 l2 = cpl_vector_get(lambdas, i + 1);
1660 if ((l2 - l1) < 1.5) {
1661 cpl_msg_debug(__func__,
"Excluding lines at %.3f and %.3f (d = %.3f) "
1662 "Angstrom", l1, l2, l2 - l1);
1669 printf(
"%d arc lines in input list are usable:\n", pos);
1670 cpl_vector_dump(lambdas, stdout);
1672 cpl_msg_debug(__func__,
"Using a list of %d %s arc lines (from %6.1f to %6.1f "
1674 aGoodnessLimit == 1 ?
"good"
1675 : (aGoodnessLimit == 5 ?
"FWHM reference"
1677 cpl_vector_get(lambdas, 0),
1678 cpl_vector_get(lambdas, cpl_vector_get_size(lambdas) - 1));
1703 int aGoodnessLimit,
double aFluxLimit)
1705 cpl_ensure(aTable && aLamp, CPL_ERROR_NULL_INPUT, NULL);
1706 int nrow = cpl_table_get_nrow(aTable);
1707 cpl_ensure(nrow > 0, CPL_ERROR_NULL_INPUT, NULL);
1709 cpl_table_unselect_all(aTable);
1711 for (i = 0; i < nrow; i++) {
1713 if (!strcmp(lampname, aLamp)) {
1714 cpl_table_select_row(aTable, i);
1717 cpl_table *lamplines = cpl_table_extract_selected(aTable);
1719 printf(
"lamplines for %s\n", aLamp);
1720 cpl_table_dump(lamplines, 0, 10000, stdout);
1725 cpl_table_delete(lamplines);
1747 cpl_ensure(aTable, CPL_ERROR_NULL_INPUT,
"Unknown_Lamp");
1748 const char *ion = cpl_table_get_string(aTable,
"ion", aIdx);
1749 cpl_ensure(ion, CPL_ERROR_ILLEGAL_INPUT,
"Unknown_Lamp");
1752 if (!strncmp(ion,
"Hg", 2) || !strncmp(ion,
"Cd", 2)) {
1756 if (!strncmp(ion,
"Ne", 2)) {
1760 if (!strncmp(ion,
"Xe", 2)) {
1763 return "Unknown_Lamp";
1782 if (!cpl_table_has_column(aLineList,
"Flux_for_LSF")) {
1783 cpl_table_new_column(aLineList,
"Flux_for_LSF",
1785 cpl_table_fill_column_window(aLineList,
"Flux_for_LSF",
1786 0, cpl_table_get_nrow(aLineList), 0.);
1789 const double sigma = 0.1;
1790 cpl_size i, n = cpl_table_get_nrow(aDetlines);
1791 for (i = 0; i < n; i++) {
1793 double lbda = cpl_table_get(aDetlines,
"lambda", i, &status);
1799 if (cpl_table_get(aLineList, MUSE_LINE_CATALOG_LAMBDA, i_l, &status)
1803 double a = cpl_table_get(aLineList,
"Flux_for_LSF", i_l, &status);
1804 a += cpl_table_get(aDetlines,
"flux", i, &status) / 300.;
1805 cpl_table_set(aLineList,
"Flux_for_LSF", i_l, a);
1839 const unsigned short aSlice,
const unsigned char aIFU)
1841 #if !SEARCH_DEBUG_FILES
1842 UNUSED_ARGUMENT(aSlice);
1844 cpl_ensure(aColumnImage, CPL_ERROR_NULL_INPUT, NULL);
1845 cpl_ensure(cpl_image_get_min(aColumnImage->
stat) > 0.,
1846 CPL_ERROR_DATA_NOT_FOUND, NULL);
1847 cpl_ensure(aSigma > 0., CPL_ERROR_ILLEGAL_INPUT, NULL);
1849 #define SEARCH_SUBTRACT_BG 1
1850 #if SEARCH_SUBTRACT_BG
1854 cpl_image *bgmedian = cpl_image_duplicate(aColumnImage->
data);
1855 cpl_image_fill_noise_uniform(bgmedian, -FLT_MIN, FLT_MIN);
1856 #define BG_KERNEL_WIDTH 51
1857 cpl_mask *filter = cpl_mask_new(1, BG_KERNEL_WIDTH);
1858 cpl_mask_not(filter);
1859 cpl_image_filter_mask(bgmedian, aColumnImage->
data, filter, CPL_FILTER_MEDIAN,
1861 cpl_mask_delete(filter);
1862 #if SEARCH_DEBUG_FILES
1863 char fn[FILENAME_MAX];
1864 sprintf(fn,
"column_slice%02hu.fits", aSlice);
1866 sprintf(fn,
"column_slice%02hu_bgmedian.fits", aSlice);
1867 cpl_image_save(bgmedian, fn, CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
1869 cpl_image *bgsub = cpl_image_subtract_create(aColumnImage->
data, bgmedian);
1870 cpl_image_delete(bgmedian);
1871 #if SEARCH_DEBUG_FILES
1872 sprintf(fn,
"column_slice%02hu_bgsub.fits", aSlice);
1873 cpl_image_save(bgsub, fn, CPL_TYPE_FLOAT, NULL, CPL_IO_DEFAULT);
1878 cpl_image *N = cpl_image_power_create(aColumnImage->
stat, 0.5),
1879 #if SEARCH_SUBTRACT_BG
1880 *SN = cpl_image_divide_create(bgsub, N);
1881 cpl_image_delete(bgsub);
1883 *SN = cpl_image_divide_create(aColumnImage->
data, N);
1885 cpl_image_delete(N);
1886 #if SEARCH_DEBUG_FILES
1887 sprintf(fn,
"column_slice%02hu_SN.fits", aSlice);
1888 cpl_image_save(SN, fn, CPL_TYPE_FLOAT, NULL, CPL_IO_CREATE);
1892 double mdev, median = cpl_image_get_median_dev(SN, &mdev),
1893 limitSN = fmax(0.1, median + aSigma*mdev);
1894 cpl_mask *mask = cpl_mask_threshold_image_create(SN, limitSN, FLT_MAX);
1895 cpl_size nlines = 0;
1896 cpl_image *label = cpl_image_labelise_mask_create(mask, &nlines);
1897 cpl_mask_delete(mask);
1898 #if SEARCH_DEBUG_FILES
1899 sprintf(fn,
"column_slice%02hu_label.fits", aSlice);
1900 cpl_image_save(label, fn, CPL_TYPE_USHORT, NULL, CPL_IO_DEFAULT);
1902 #if SEARCH_DEBUG || SEARCH_DEBUG_FILES
1903 double mean = cpl_image_get_mean(SN),
1904 stdev = cpl_image_get_stdev(SN),
1905 min = cpl_image_get_min(SN),
1906 max = cpl_image_get_max(SN);
1907 cpl_msg_debug(__func__,
"%"CPL_SIZE_FORMAT
" lines found; parameters: sigma=%f, "
1908 "med=%f+/-%f " "mean=%f+/-%f min/max=%f/%f limit(S/N)=%f", nlines,
1909 aSigma, median, mdev, mean, stdev, min, max, limitSN);
1911 cpl_image_delete(SN);
1918 for (i = 0; i < nlines; i++) {
1920 cpl_mask *linemask = cpl_mask_threshold_image_create(label, i+0.5, i+1.5);
1921 int masksize = cpl_mask_get_size_y(linemask);
1925 while (j <= masksize && cpl_mask_get(linemask, 1, j) == CPL_BINARY_0) {
1929 while (j <= masksize && cpl_mask_get(linemask, 1, j) == CPL_BINARY_1) {
1933 double cenpix = (hipix + lopix) / 2.;
1936 cpl_msg_debug(__func__,
"lo/hi/cen=%d,%d,%f: values=%f,%f", lopix, hipix,
1937 cenpix, cpl_image_get(aColumnImage->
data, 1, lopix, &err),
1938 cpl_image_get(aColumnImage->
data, 1, hipix, &err));
1940 cpl_mask_delete(linemask);
1941 if (lopix == hipix) {
1944 cpl_table_set(linesresult,
"flux", i, -1.);
1951 #define MAXENLARGE 5
1953 int err0, err1 = 0, err2 = 0;
1954 double valref = cpl_image_get(aColumnImage->
data, 1, lopix, &err0);
1955 cpl_errorstate prestate = cpl_errorstate_get();
1958 while (err1 == 0 && value < valref && (lopix - j) <= MAXENLARGE) {
1960 value = cpl_image_get(aColumnImage->
data, 1, j, &err1);
1965 valref = cpl_image_get(aColumnImage->
data, 1, hipix, &err2);
1968 while (err2 == 0 && value < valref && (j - hipix) <= MAXENLARGE) {
1970 value = cpl_image_get(aColumnImage->
data, 1, j, &err2);
1974 cpl_msg_debug(__func__,
"region=%d...%d, size=%d", lopix, hipix,
1977 if (err1 < 0 || err2 < 0) {
1978 cpl_errorstate_set(prestate);
1982 cpl_vector *positions = cpl_vector_new(hipix - lopix + 1),
1983 *values = cpl_vector_new(hipix - lopix + 1),
1984 *valuessigma = cpl_vector_new(hipix - lopix + 1);
1986 for (j = lopix, k = 0; j <= hipix; j++, k++) {
1987 cpl_vector_set(positions, k, j);
1988 cpl_vector_set(values, k, cpl_image_get(aColumnImage->
data, 1, j, &err0));
1991 cpl_vector_set(valuessigma, k, sqrt(cpl_image_get(aColumnImage->
stat,
1996 cpl_bivector *biv = cpl_bivector_wrap_vectors(positions, values);
1997 cpl_bivector_dump(biv, stdout);
1998 cpl_bivector_unwrap_vectors(biv);
2003 double center, cerr, sigma, area, bglevel, mse;
2004 cpl_matrix *covariance;
2005 prestate = cpl_errorstate_get();
2006 cpl_error_code rc = cpl_vector_fit_gaussian(positions, NULL, values,
2007 valuessigma, CPL_FIT_ALL,
2008 ¢er, &sigma, &area, &bglevel,
2009 &mse, NULL, &covariance);
2012 if (rc == CPL_ERROR_CONTINUE) {
2015 cerr = sqrt(sigma * sigma / area);
2016 cpl_msg_debug(__func__,
"Gaussian fit in slice %hu of IFU %hhu around "
2017 "position %6.1f: %s", aSlice, aIFU, cenpix,
2018 cpl_error_get_message());
2020 if (cpl_msg_get_log_level() == CPL_MSG_DEBUG) {
2023 cpl_bivector *bv = cpl_bivector_wrap_vectors(positions, values);
2024 printf(
"Gaussian fit: %f+/-%f, %f, %f, %f %f\nand the input data:\n",
2025 center, cerr, bglevel, area, sigma, mse);
2026 cpl_bivector_dump(bv, stdout);
2027 cpl_bivector_unwrap_vectors(bv);
2031 }
else if (rc == CPL_ERROR_SINGULAR_MATRIX || !covariance) {
2032 cerr = sqrt(sigma * sigma / area);
2033 cpl_msg_debug(__func__,
"Gaussian fit in slice %hu of IFU %hhu around "
2034 "position %6.1f: %s", aSlice, aIFU, cenpix,
2035 cpl_error_get_message());
2036 }
else if (rc != CPL_ERROR_NONE) {
2040 cpl_msg_debug(__func__,
"Gaussian fit in slice %hu of IFU %hhu around "
2041 "position %6.1f: %s", aSlice, aIFU, cenpix,
2042 cpl_error_get_message());
2047 cerr = sqrt(cpl_matrix_get(covariance, 0, 0));
2049 cpl_matrix_dump(covariance, stdout);
2051 cpl_matrix_delete(covariance);
2053 cpl_errorstate_set(prestate);
2054 if (fabs(center - cenpix) > MUSE_WAVE_LINES_SEARCH_SHIFT_WARN) {
2055 cpl_msg_debug(__func__,
"Large shift in Gaussian centering in slice %hu "
2056 "of IFU %hhu: initial %7.2f, fit %7.2f", aSlice, aIFU,
2062 cpl_table_set(linesresult,
"y", i, cenpix);
2066 cpl_table_set(linesresult,
"peak", i, cpl_vector_get_max(values));
2067 cpl_table_set(linesresult,
"center", i, center);
2068 cpl_table_set(linesresult,
"cerr", i, cerr);
2069 cpl_table_set(linesresult,
"fwhm", i, CPL_MATH_FWHM_SIG * sigma);
2070 cpl_table_set(linesresult,
"sigma", i, sigma);
2071 cpl_table_set(linesresult,
"flux", i, area);
2072 cpl_table_set(linesresult,
"bg", i, bglevel);
2073 cpl_table_set(linesresult,
"mse", i, mse);
2075 cpl_vector_delete(positions);
2076 cpl_vector_delete(values);
2077 cpl_vector_delete(valuessigma);
2079 printf(
"%s: results of fit stored in table row %d:\n", __func__, i + 1);
2080 cpl_table_dump(linesresult, i, 1, stdout);
2084 cpl_image_delete(label);
2087 cpl_table_unselect_all(linesresult);
2088 for (i = 0; i < cpl_table_get_nrow(linesresult); i++) {
2089 if (cpl_table_get(linesresult,
"cerr", i, NULL) > kMuseArcMaxCenteringError ||
2090 cpl_table_get(linesresult,
"fwhm", i, NULL) < kMuseArcMinFWHM ||
2091 cpl_table_get(linesresult,
"fwhm", i, NULL) > kMuseArcMaxFWHM ||
2092 cpl_table_get(linesresult,
"flux", i, NULL) < kMuseArcMinFlux) {
2093 cpl_table_select_row(linesresult, i);
2096 cpl_table_erase_selected(linesresult);
2126 cpl_ensure_code(aLines && aLambdas, CPL_ERROR_NULL_INPUT);
2129 int i, nlines = cpl_table_get_nrow(aLines);
2130 cpl_vector *vcenter = cpl_vector_new(nlines);
2131 for (i = 0; i < nlines; i++) {
2132 cpl_vector_set(vcenter, i, cpl_table_get(aLines,
"center", i, NULL));
2135 cpl_vector_dump(vcenter, stdout);
2137 double dmin = kMuseSpectralSamplingA - kMuseSpectralSamplingA * aParams->
ddisp,
2138 dmax = kMuseSpectralSamplingA + kMuseSpectralSamplingA * aParams->
ddisp;
2139 cpl_bivector *id_lines = cpl_ppm_match_positions(vcenter, aLambdas, dmin, dmax,
2142 cpl_msg_debug(__func__,
"%"CPL_SIZE_FORMAT
" identified lines (of %"
2143 CPL_SIZE_FORMAT
" detected lines and %"CPL_SIZE_FORMAT
2144 " from linelist)", cpl_bivector_get_size(id_lines),
2145 cpl_vector_get_size(vcenter), cpl_vector_get_size(aLambdas));
2146 cpl_bivector_dump(id_lines, stdout);
2149 cpl_vector_delete(vcenter);
2152 printf(
"detected lines before cleanup:\n");
2153 cpl_table_dump(aLines, 0, nlines, stdout);
2157 const double *id_center = cpl_bivector_get_x_data_const(id_lines),
2158 *id_lambda = cpl_bivector_get_y_data_const(id_lines);
2159 cpl_table_unselect_all(aLines);
2160 int j, nid = cpl_bivector_get_size(id_lines);
2161 for (i = 0, j = 0; i < cpl_table_get_nrow(aLines) && id_center && id_lambda; i++) {
2163 cpl_msg_debug(__func__,
"c=%f, l=%f, c_det=%f", id_center[j], id_lambda[j],
2164 cpl_table_get(aLines,
"center", i, NULL));
2166 if (j < nid && fabs(id_center[j] - cpl_table_get(aLines,
"center", i, NULL))
2169 cpl_table_set(aLines,
"lambda", i, id_lambda[j]);
2173 cpl_table_select_row(aLines, i);
2175 cpl_table_erase_selected(aLines);
2176 cpl_bivector_delete(id_lines);
2177 int debug = getenv(
"MUSE_DEBUG_WAVECAL")
2178 ? atoi(getenv(
"MUSE_DEBUG_WAVECAL")) : 0;
2180 printf(
"identified %d lines, %"CPL_SIZE_FORMAT
" after cleanup:\n", nid,
2181 cpl_table_get_nrow(aLines));
2182 cpl_table_dump(aLines, 0, nid, stdout);
2185 nid = cpl_table_get_nrow(aLines);
2188 return CPL_ERROR_DATA_NOT_FOUND;
2189 }
else if (nid < aParams->yorder + 1) {
2190 return CPL_ERROR_ILLEGAL_OUTPUT;
2192 return CPL_ERROR_NONE;
2230 unsigned int aIdx, cpl_polynomial *aPoly,
2231 cpl_polynomial **aTrace,
2233 const unsigned short aSlice,
int aDebug)
2235 cpl_ensure(aImage && aLinelist && aPoly && aTrace, CPL_ERROR_NULL_INPUT, NULL);
2240 double sigma = kMuseSliceSlitWidthA / kMuseSpectralSamplingA / CPL_MATH_FWHM_SIG;
2242 if (cpl_table_get(aLinelist, MUSE_LINE_CATALOG_QUALITY, aIdx, NULL) != 5) {
2245 int halfwidth = 3.*kMuseSliceSlitWidthA / kMuseSpectralSamplingA;
2248 double lambda = cpl_table_get(aLinelist, MUSE_LINE_CATALOG_LAMBDA, aIdx, NULL),
2249 ypos = cpl_polynomial_eval_1d(aPoly, lambda, NULL);
2250 if ((ypos - halfwidth) < 1 ||
2251 (ypos + halfwidth) > cpl_image_get_size_y(aImage->
data)) {
2253 cpl_msg_debug(__func__,
"%f is supposed to lie near %.3f in slice %2hu of"
2254 " IFU %hhu, i.e. outside!", lambda, ypos, aSlice,
2260 cpl_msg_debug(__func__,
"%f is supposed to lie near %.3f in slice %2hu of "
2261 "IFU %hhu", lambda, ypos, aSlice,
2265 double dleft = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_LEFT],
2267 dright = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_RIGHT],
2269 dmid = (dleft + dright) / 2.;
2270 int ileft = ceil(dleft),
2271 iright = floor(dright);
2273 cpl_msg_debug(__func__,
"limits at y=%f: %f < %f < %f", ypos, dleft, dmid,
2279 (
int)kMuseSliceHiLikelyWidth + 5);
2285 for (i = dmid; i >= ileft; i--) {
2287 sigma, fittable, ++n);
2288 if (rc != CPL_ERROR_NONE) {
2291 double ynew = cpl_table_get(fittable,
"center", n - 1, NULL);
2292 if (fabs(y - ynew) < MUSE_WAVE_LINE_HANDLE_SHIFT_LIMIT) {
2298 printf(
"arc line aIdx=%u, columns i=%d...", aIdx + 1, i);
2301 for (i = dmid + 1; i <= iright; i++) {
2303 sigma, fittable, ++n);
2304 if (rc != CPL_ERROR_NONE) {
2307 double ynew = cpl_table_get(fittable,
"center", n - 1, NULL);
2308 if (fabs(y - ynew) < MUSE_WAVE_LINE_HANDLE_SHIFT_LIMIT) {
2316 cpl_table_select_all(fittable);
2317 cpl_table_and_selected_invalid(fittable,
"center");
2318 cpl_table_erase_selected(fittable);
2319 cpl_table_fill_column_window(fittable,
"lambda", 0,
2320 cpl_table_get_nrow(fittable), lambda);
2322 printf(
"line %u, %d line fits\n", aIdx + 1, n);
2323 cpl_table_dump(fittable, 0, n, stdout);
2328 int npos = cpl_table_get_nrow(fittable);
2330 cpl_msg_warning(__func__,
"Polynomial fit failed in slice %hu of IFU %hhu "
2331 "for line %u (y-position near %.2f pix): %s", aSlice,
2333 cpl_error_get_message());
2337 printf(
"%s: line %2u, %d line fits, %d with low residuals:\n", __func__,
2339 cpl_table_dump(fittable, 0, npos, stdout);
2385 unsigned int aIdx, cpl_polynomial *aPoly,
2386 cpl_polynomial **aTrace,
2388 const unsigned short aSlice,
int aDebug)
2390 cpl_ensure(aImage && aLinelist && aPoly && aTrace, CPL_ERROR_NULL_INPUT, NULL);
2393 #define MULTIPLET_SEARCH_RANGE 40.
2394 unsigned int nlines = 1;
2395 double lbda1 = cpl_table_get(aLinelist, MUSE_LINE_CATALOG_LAMBDA, aIdx, NULL);
2397 cpl_vector *lambdas = cpl_vector_new(nlines),
2398 *fluxes = cpl_vector_new(nlines);
2399 cpl_vector_set(lambdas, 0, lbda1);
2400 cpl_vector_set(fluxes, 0, cpl_table_get(aLinelist, MUSE_LINE_CATALOG_FLUX,
2403 unsigned int j = aIdx;
2404 for (lambda = cpl_table_get(aLinelist, MUSE_LINE_CATALOG_LAMBDA, ++j, NULL);
2405 fabs(lambda - lbda1) < MULTIPLET_SEARCH_RANGE;
2406 lambda = cpl_table_get(aLinelist, MUSE_LINE_CATALOG_LAMBDA, ++j, NULL)) {
2407 int quality = cpl_table_get(aLinelist, MUSE_LINE_CATALOG_QUALITY, j, NULL);
2409 if (quality == 2 && !strcmp(lamp1, lamp)) {
2411 cpl_vector_set_size(lambdas, nlines);
2412 cpl_vector_set_size(fluxes, nlines);
2413 cpl_vector_set(lambdas, nlines - 1, lambda);
2414 double flux = cpl_table_get(aLinelist, MUSE_LINE_CATALOG_FLUX, j, NULL);
2415 cpl_vector_set(fluxes, nlines - 1, flux);
2417 cpl_table_set(aLinelist, MUSE_LINE_CATALOG_QUALITY, j, -quality);
2422 printf(
"found multiplet of lamp %s with %u lines:\n", lamp1, nlines);
2423 cpl_bivector *bv = cpl_bivector_wrap_vectors(lambdas, fluxes);
2424 cpl_bivector_dump(bv, stdout);
2425 cpl_bivector_unwrap_vectors(bv);
2431 double sigma = kMuseSliceSlitWidthA / kMuseSpectralSamplingA / CPL_MATH_FWHM_SIG;
2432 int halfwidth = 3.*kMuseSliceSlitWidthA / kMuseSpectralSamplingA;
2434 cpl_vector *ypos = cpl_vector_new(nlines);
2435 for (j = 0; j < nlines; j++) {
2436 double yp = cpl_polynomial_eval_1d(aPoly, cpl_vector_get(lambdas, j), NULL);
2437 cpl_vector_set(ypos, j, yp);
2439 double ypos1 = cpl_vector_get(ypos, 0),
2440 ypos2 = cpl_vector_get(ypos, nlines - 1);
2441 cpl_bivector *peaks = cpl_bivector_wrap_vectors(ypos, fluxes);
2442 if ((ypos1 - halfwidth) < 1 ||
2443 (ypos2 + halfwidth) > cpl_image_get_size_y(aImage->
data)) {
2445 cpl_msg_debug(__func__,
"%f is supposed to lie at %.3f..%.3f in slice "
2446 "%2hu of IFU %hhu, i.e. outside!", lambda, ypos1, ypos2,
2449 cpl_bivector_delete(peaks);
2450 cpl_vector_delete(lambdas);
2454 cpl_msg_debug(__func__,
"%f is supposed to lie at %.3f..%.3f in slice %2hu "
2455 "of IFU %hhu", lambda, ypos1, ypos2, aSlice,
2459 double dleft = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_LEFT],
2460 (ypos1 + ypos2)/2., NULL),
2461 dright = cpl_polynomial_eval_1d(aTrace[MUSE_TRACE_RIGHT],
2462 (ypos1 + ypos2)/2., NULL),
2463 dmid = (dleft + dright) / 2.;
2464 int ileft = ceil(dleft),
2465 iright = floor(dright);
2469 ((
int)kMuseSliceHiLikelyWidth + 5) * nlines);
2473 cpl_bivector *bp = cpl_bivector_duplicate(peaks),
2474 *bpgood = cpl_bivector_duplicate(peaks);
2476 for (i = dmid; i >= ileft; i--) {
2479 halfwidth, sigma, fittable, n);
2480 if (rc != CPL_ERROR_NONE) {
2481 cpl_bivector_delete(bp);
2482 bp = cpl_bivector_duplicate(bpgood);
2485 cpl_vector *shifts = cpl_vector_duplicate(cpl_bivector_get_x(bp));
2486 cpl_vector_subtract(shifts, cpl_bivector_get_x(bpgood));
2487 double shift = cpl_vector_get_median(shifts);
2488 cpl_vector_delete(shifts);
2489 if (fabs(shift) < MUSE_WAVE_LINE_HANDLE_SHIFT_LIMIT) {
2490 cpl_bivector_delete(bpgood);
2491 bpgood = cpl_bivector_duplicate(bp);
2493 cpl_bivector_delete(bp);
2494 bp = cpl_bivector_duplicate(bpgood);
2498 cpl_bivector_delete(bp);
2499 cpl_bivector_delete(bpgood);
2500 bp = cpl_bivector_duplicate(peaks);
2501 bpgood = cpl_bivector_duplicate(peaks);
2502 for (i = dmid + 1; i <= iright; i++) {
2505 halfwidth, sigma, fittable, n);
2506 if (rc != CPL_ERROR_NONE) {
2507 cpl_bivector_delete(bp);
2508 bp = cpl_bivector_duplicate(bpgood);
2511 cpl_vector *shifts = cpl_vector_duplicate(cpl_bivector_get_x(bp));
2512 cpl_vector_subtract(shifts, cpl_bivector_get_x(bpgood));
2513 double shift = cpl_vector_get_median(shifts);
2514 cpl_vector_delete(shifts);
2515 if (fabs(shift) < MUSE_WAVE_LINE_HANDLE_SHIFT_LIMIT) {
2516 cpl_bivector_delete(bpgood);
2517 bpgood = cpl_bivector_duplicate(bp);
2519 cpl_bivector_delete(bp);
2520 bp = cpl_bivector_duplicate(bpgood);
2524 cpl_bivector_delete(bp);
2525 cpl_bivector_delete(bpgood);
2528 cpl_table_select_all(fittable);
2529 cpl_table_and_selected_invalid(fittable,
"center");
2530 cpl_table_erase_selected(fittable);
2531 cpl_bivector_delete(peaks);
2533 for (j = 0; j < nlines; j++) {
2536 cpl_vector_delete(lambdas);
2575 double aSigma, cpl_table *aFitTable,
int aRowsNeeded)
2577 cpl_ensure_code(aImage && aImage->
data && aImage->
stat && aFitTable,
2578 CPL_ERROR_NULL_INPUT);
2580 cpl_msg_debug(__func__,
"%d %d %d -> %d, %d", aX, (
int)aY, aHalfWidth,
2581 2*aHalfWidth+1, aRowsNeeded);
2584 cpl_vector *positions = cpl_vector_new(2*aHalfWidth+1),
2585 *values = cpl_vector_new(2*aHalfWidth+1),
2586 *valuessigma = cpl_vector_new(2*aHalfWidth+1);
2587 int i, j, ny = cpl_image_get_size_y(aImage->
data);
2588 for (i = (
int)aY - aHalfWidth, j = 0; i <= (int)aY + aHalfWidth && i <= ny;
2591 cpl_vector_set(positions, j, i);
2592 cpl_vector_set(values, j, cpl_image_get(aImage->
data, aX, i, &err));
2593 cpl_vector_set(valuessigma, j,
2594 sqrt(cpl_image_get(aImage->
stat, aX, i, &err)));
2597 printf(
"input vectors: positions, values\n");
2598 cpl_bivector *biv = cpl_bivector_wrap_vectors(positions, values);
2599 cpl_bivector_dump(biv, stdout);
2601 cpl_bivector_unwrap_vectors(biv);
2603 printf(
"input vectors: values, valuessigma\n");
2604 biv = cpl_bivector_wrap_vectors(values, valuessigma);
2605 cpl_bivector_dump(biv, stdout);
2607 cpl_bivector_unwrap_vectors(biv);
2612 cpl_errorstate prestate = cpl_errorstate_get();
2613 double center, cerror, area, bglevel, mse;
2614 cpl_matrix *covariance = NULL;
2615 cpl_fit_mode mode = CPL_FIT_ALL;
2616 double sigma = aSigma;
2618 mode = CPL_FIT_CENTROID | CPL_FIT_AREA | CPL_FIT_OFFSET;
2622 = cpl_vector_fit_gaussian(positions, NULL, values, valuessigma, mode,
2623 ¢er, &sigma, &area, &bglevel, &mse, NULL,
2626 printf(
"--> rc=%d (%d) %s %#x %#x\n", rc, CPL_ERROR_NONE,
2627 cpl_error_get_message(), covariance, &covariance);
2630 cpl_vector_delete(positions);
2631 cpl_vector_delete(values);
2632 cpl_vector_delete(valuessigma);
2637 cerror = sqrt(cpl_matrix_get(covariance, 0, 0));
2638 cpl_matrix_delete(covariance);
2640 cpl_msg_debug(__func__,
"Gauss fit produced no covariance matrix (y=%.3f in "
2641 "column=%d): %s", aY, aX, cpl_error_get_message());
2642 cpl_errorstate_set(prestate);
2643 return rc == CPL_ERROR_NONE ? CPL_ERROR_ILLEGAL_OUTPUT : rc;
2645 if (rc == CPL_ERROR_CONTINUE) {
2648 cerror = sqrt(sigma * sigma / area);
2649 cpl_errorstate_set(prestate);
2650 rc = CPL_ERROR_NONE;
2652 if (rc != CPL_ERROR_NONE) {
2654 cpl_msg_debug(__func__,
"Gauss fit failed with some error (y=%.3f in "
2655 "column=%d): %s", aY, aX, cpl_error_get_message());
2656 cpl_errorstate_set(prestate);
2659 if (fabs(center - aY) > MUSE_WAVE_LINE_FIT_MAXSHIFT) {
2661 cpl_msg_debug(__func__,
"Gauss fit gave unexpectedly large offset "
2662 "(shifted %.3f pix from y=%.3f in column=%d)",
2663 center - aY, aY, aX);
2664 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
2668 if (cpl_table_get_nrow(aFitTable) < aRowsNeeded) {
2669 cpl_table_set_size(aFitTable, aRowsNeeded);
2671 cpl_table_set(aFitTable,
"center", aRowsNeeded - 1, center);
2672 cpl_table_set(aFitTable,
"cerr", aRowsNeeded - 1, cerror);
2673 cpl_table_set(aFitTable,
"sigma", aRowsNeeded - 1, sigma);
2674 if (mode == CPL_FIT_ALL) {
2675 cpl_table_set(aFitTable,
"fwhm", aRowsNeeded - 1, CPL_MATH_FWHM_SIG * sigma);
2677 cpl_table_set(aFitTable,
"flux", aRowsNeeded - 1, area);
2678 cpl_table_set(aFitTable,
"bg", aRowsNeeded - 1, bglevel);
2679 cpl_table_set(aFitTable,
"mse", aRowsNeeded - 1, mse);
2680 cpl_table_set(aFitTable,
"x", aRowsNeeded - 1, aX);
2681 cpl_table_set(aFitTable,
"y", aRowsNeeded - 1, aY);
2684 printf(
"--> Gaussian fit: %f +/- %f, %f\n", center, cerror, area);
2731 cpl_vector *aLambdas,
int aHalfWidth,
double aSigma,
2732 cpl_table *aFitTable,
int aRowsNeeded)
2734 cpl_ensure_code(aImage && aImage->
data && aImage->
stat && aFitTable,
2735 CPL_ERROR_NULL_INPUT);
2736 cpl_vector *ypeaks = cpl_bivector_get_x(aPeaks),
2737 *fluxes = cpl_bivector_get_y(aPeaks);
2738 int np = cpl_vector_get_size(ypeaks);
2739 double yp1 = cpl_vector_get(ypeaks, 0),
2740 yp2 = cpl_vector_get(ypeaks, np - 1);
2741 int i1 = floor(yp1),
2744 cpl_msg_debug(__func__,
"%d %d..%d %d -> %d", aX, i1, i2, aHalfWidth,
2748 int npoints = (i2 + aHalfWidth) - (i1 - aHalfWidth) + 1;
2749 cpl_vector *positions = cpl_vector_new(npoints),
2750 *values = cpl_vector_new(npoints),
2751 *valuessigma = cpl_vector_new(npoints);
2752 double minval = DBL_MAX;
2753 int i, j, ny = cpl_image_get_size_y(aImage->
data);
2754 for (i = i1 - aHalfWidth, j = 0; i <= i2 + aHalfWidth && i <= ny; i++, j++) {
2756 cpl_vector_set(positions, j, i);
2757 double value = cpl_image_get(aImage->
data, aX, i, &err);
2758 cpl_vector_set(values, j, value);
2759 if (value < minval) {
2762 cpl_vector_set(valuessigma, j,
2763 sqrt(cpl_image_get(aImage->
stat, aX, i, &err)));
2765 minval = minval > 0 ? minval : 0.;
2767 printf(
"input vectors: positions, values\n");
2768 cpl_bivector *biv = cpl_bivector_wrap_vectors(positions, values);
2769 cpl_bivector_dump(biv, stdout);
2771 cpl_bivector_unwrap_vectors(biv);
2773 cpl_bivector *bvalues = cpl_bivector_wrap_vectors(values, valuessigma);
2777 cpl_vector *poly = cpl_vector_new(2);
2778 cpl_vector_set(poly, 0, minval);
2779 cpl_vector_set(poly, 1, 0.);
2781 cpl_array *afluxes = cpl_array_wrap_double(cpl_vector_get_data(fluxes), np);
2783 cpl_array_get_maxpos(afluxes, &imaxflux);
2784 double yposmax = cpl_vector_get(ypeaks, imaxflux);
2785 cpl_array_unwrap(afluxes);
2787 cpl_errorstate prestate = cpl_errorstate_get();
2788 double sigma = aSigma,
2790 cpl_matrix *covariance;
2792 &sigma, fluxes, poly,
2793 &mse, &chisq, &covariance);
2794 cpl_vector_delete(positions);
2795 cpl_bivector_delete(bvalues);
2801 cpl_msg_debug(__func__,
"Multi-Gauss fit produced no covariance matrix (y=%."
2802 "3f..%.3f in column=%d): %s", yp1, yp2, aX, cpl_error_get_message());
2803 cpl_errorstate_set(prestate);
2804 cpl_vector_delete(poly);
2805 return rc == CPL_ERROR_NONE ? CPL_ERROR_ILLEGAL_OUTPUT : rc;
2807 if (rc != CPL_ERROR_NONE) {
2809 cpl_msg_debug(__func__,
"Multi-Gauss fit failed with some error (y=%.3f..%."
2810 "3f in column=%d): %s", yp1, yp2, aX, cpl_error_get_message());
2811 cpl_errorstate_set(prestate);
2812 cpl_matrix_delete(covariance);
2813 cpl_vector_delete(poly);
2817 double yfitmax = cpl_vector_get(ypeaks, imaxflux);
2818 if (fabs(yposmax - yfitmax) > MUSE_WAVE_LINE_FIT_MAXSHIFT) {
2819 cpl_msg_debug(__func__,
"Multi-Gauss fit gave unexpectedly large offset "
2820 "(shifted %.3f pix from y=%.3f..%.3f in column=%d)",
2821 yposmax - yfitmax, yp1, yp2, aX);
2822 cpl_matrix_delete(covariance);
2823 cpl_vector_delete(poly);
2824 return CPL_ERROR_ACCESS_OUT_OF_RANGE;
2827 double yfitmin = cpl_vector_get_min(fluxes);
2829 cpl_msg_debug(__func__,
"Multi-Gauss fit gave negative flux (%e in "
2830 "multiplet from y=%.3f..%.3f in column=%d)", yfitmin,
2832 cpl_matrix_delete(covariance);
2833 cpl_vector_delete(poly);
2834 return CPL_ERROR_ILLEGAL_OUTPUT;
2838 if (cpl_table_get_nrow(aFitTable) < aRowsNeeded) {
2839 cpl_table_set_size(aFitTable, aRowsNeeded);
2842 cpl_table_fill_column_window(aFitTable,
"mse", aRowsNeeded - np, np, mse);
2843 cpl_table_fill_column_window(aFitTable,
"x", aRowsNeeded - np, np, aX);
2844 cpl_table_fill_column_window(aFitTable,
"sigma", aRowsNeeded - np, np, sigma);
2846 for (i = 0, j = aRowsNeeded - np; i < np; i++, j++) {
2847 cpl_table_set(aFitTable,
"lambda", j, cpl_vector_get(aLambdas, i));
2848 cpl_table_set(aFitTable,
"y", j, cpl_vector_get(ypeaks, i));
2849 double center = cpl_vector_get(ypeaks, i);
2850 cpl_table_set(aFitTable,
"center", j, center);
2853 double cerror = sqrt(cpl_matrix_get(covariance, 3 + i, 3 + i));
2854 cpl_table_set(aFitTable,
"cerr", j, cerror);
2855 cpl_table_set(aFitTable,
"flux", j, cpl_vector_get(fluxes, i));
2857 double bg = cpl_vector_get(poly, 0) + cpl_vector_get(poly, 1) * center;
2858 cpl_table_set(aFitTable,
"bg", j, bg);
2860 cpl_vector_delete(poly);
2861 cpl_matrix_delete(covariance);
2863 printf(
"stored %d fitted multiplet values:\n", np);
2864 cpl_table_dump(aFitTable, aRowsNeeded - np - 2 < 0 ? 0 : aRowsNeeded - np - 2, np + 5, stdout);
2915 cpl_ensure_code(aFitTable, CPL_ERROR_NULL_INPUT);
2916 int npos = cpl_table_get_nrow(aFitTable);
2917 cpl_ensure_code(npos > 0, CPL_ERROR_ILLEGAL_INPUT);
2921 cpl_table *fittable = NULL;
2923 cpl_table_unselect_all(aFitTable);
2924 cpl_table_or_selected_double(aFitTable,
"lambda", CPL_EQUAL_TO, aLambda);
2925 npos = cpl_table_count_selected(aFitTable);
2926 cpl_ensure_code(npos > 0, CPL_ERROR_ILLEGAL_INPUT);
2927 fittable = cpl_table_extract_selected(aFitTable);
2928 cpl_table_erase_selected(aFitTable);
2930 fittable = aFitTable;
2934 cpl_matrix *pos = cpl_matrix_new(1, npos);
2935 cpl_vector *val = cpl_vector_new(npos);
2937 for (i = 0; i < npos; i++) {
2938 cpl_matrix_set(pos, 0, i, cpl_table_get(fittable,
"x", i, NULL));
2939 cpl_vector_set(val, i, cpl_table_get(fittable,
"center", i, NULL));
2943 cpl_errorstate state = cpl_errorstate_get();
2948 cpl_matrix_delete(pos);
2949 cpl_vector_delete(val);
2950 cpl_polynomial_delete(fit);
2951 if (!cpl_errorstate_is_equal(state)) {
2954 cpl_table_fill_column_window(fittable,
"cerr",
2955 0, cpl_table_get_nrow(fittable), 10.);
2958 cpl_table_fill_column_window(fittable,
"cerr",
2959 0, cpl_table_get_nrow(fittable), sqrt(mse));
2963 cpl_table_power_column(fittable,
"cerr", 2.);
2964 cpl_table_add_scalar(fittable,
"cerr", mse);
2965 cpl_table_power_column(fittable,
"cerr", 0.5);
2968 printf(
"line at %.3f Angstrom: rms = %f (mean error %f)\n", aLambda,
2969 sqrt(mse), cpl_table_get_column_mean(fittable,
"cerr"));
2970 cpl_table_dump(fittable, 0, npos, stdout);
2974 cpl_table_insert(aFitTable, fittable, cpl_table_get_nrow(aFitTable));
2975 cpl_table_delete(fittable);
2977 return CPL_ERROR_NONE;
2993 static inline double
2994 muse_wave_ipow(
double x,
unsigned int y)
3015 result = y & 1 ? x : 1.;
3042 muse_wave_poly_2d(
const double xy[],
const double p[],
double *f)
3044 unsigned short xorder = p[0],
3050 unsigned int i, idx = 2;
3051 for (i = 0; i <= xorder; i++) {
3052 double xi = muse_wave_ipow(x, i);
3054 for (j = 0; j <= yorder; j++) {
3055 *f += p[idx++] * xi * muse_wave_ipow(y, j);
3076 muse_wave_dpoly_2d(
const double xy[],
const double p[],
double f[])
3078 unsigned short xorder = p[0],
3084 unsigned int i, idx = 2;
3085 for (i = 0; i <= xorder; i++) {
3086 double xi = muse_wave_ipow(x, i);
3088 for (j = 0; j <= yorder; j++) {
3089 f[idx++] = xi * muse_wave_ipow(y, j);
3134 const unsigned short aSlice)
3136 cpl_ensure_code(aPoly && aXYPos && aLambdas, CPL_ERROR_NULL_INPUT);
3138 printf(
"aXYPos (%"CPL_SIZE_FORMAT
"x%"CPL_SIZE_FORMAT
"):\n",
3139 cpl_matrix_get_ncol(aXYPos), cpl_matrix_get_nrow(aXYPos));
3140 cpl_matrix_dump(aXYPos, stdout);
3141 printf(
"aLambdas (%"CPL_SIZE_FORMAT
"):\n", cpl_vector_get_size(aLambdas));
3142 cpl_vector_dump(aLambdas, stdout);
3143 printf(
"aDLambdas (%"CPL_SIZE_FORMAT
"):\n", cpl_vector_get_size(aDLambdas));
3144 cpl_vector_dump(aDLambdas, stdout);
3148 int debug = getenv(
"MUSE_DEBUG_WAVECAL")
3149 ? atoi(getenv(
"MUSE_DEBUG_WAVECAL")) : 0;
3151 *aPoly = cpl_polynomial_new(2);
3154 int large_residuals = 1,
3156 while (large_residuals > 0) {
3158 cpl_error_code errfit = CPL_ERROR_SINGULAR_MATRIX;
3163 cpl_matrix *xypos = cpl_matrix_transpose_create(aXYPos);
3165 int npar = 2 + (aParams->
xorder + 1) * (aParams->
yorder + 1);
3166 cpl_vector *pars = cpl_vector_new(npar);
3168 cpl_vector_fill(pars, 0.);
3170 cpl_vector_set(pars, 0, aParams->
xorder);
3171 cpl_vector_set(pars, 1, aParams->
yorder);
3172 cpl_vector_set(pars, 2, 5000.);
3173 cpl_array *aflags = cpl_array_new(npar, CPL_TYPE_INT);
3175 cpl_array_set_int(aflags, 0, 0);
3176 cpl_array_set_int(aflags, 1, 0);
3177 cpl_array_fill_window_int(aflags, 2, npar - 2, 1);
3178 int *pflags = cpl_array_get_data_int(aflags);
3179 errfit = cpl_fit_lvmq(xypos, NULL,
3180 aLambdas, aDLambdas, pars, pflags,
3181 muse_wave_poly_2d, muse_wave_dpoly_2d,
3182 CPL_FIT_LVMQ_TOLERANCE, CPL_FIT_LVMQ_COUNT,
3183 CPL_FIT_LVMQ_MAXITER, NULL, NULL, NULL);
3184 cpl_array_delete(aflags);
3187 for (i = 0; i <= aParams->
xorder; i++) {
3189 for (j = 0; j <= aParams->
yorder; j++) {
3190 cpl_size pows[2] = { i, j };
3191 cpl_polynomial_set_coeff(*aPoly, pows,
3192 cpl_vector_get(pars, k++));
3195 cpl_matrix_delete(xypos);
3196 cpl_vector_delete(pars);
3199 const cpl_boolean sym = CPL_FALSE;
3200 const cpl_size mindeg2d[] = { 0, 0 },
3202 errfit = cpl_polynomial_fit(*aPoly, aXYPos, &sym, aLambdas, NULL,
3203 CPL_TRUE, mindeg2d, maxdeg2d);
3206 printf(
"polynomial (orders=%hu/%hu, degree=%"CPL_SIZE_FORMAT
"):\n",
3207 aParams->
xorder, aParams->
yorder, cpl_polynomial_get_degree(*aPoly));
3208 cpl_polynomial_dump(*aPoly, stdout);
3214 cpl_msg_error(__func__,
"The polynomial fit in slice %hu failed: %s",
3215 aSlice, cpl_error_get_message());
3220 FILE *gp = popen(
"gnuplot -persist",
"w");
3223 fprintf(gp,
"set title \"2D polynomial fit residuals (failed fit: "
3224 "\'%s\')\n", cpl_error_get_message());
3226 fprintf(gp,
"set palette defined ( 0 \"dark-violet\","
3227 "1 \"dark-blue\", 4 \"green\", 6 \"yellow\", 8 \"orange\","
3228 "9 \"red\", 10 \"dark-red\")\n");
3229 fprintf(gp,
"unset key\n");
3230 cpl_matrix *xpos = cpl_matrix_extract_row(aXYPos, 0);
3231 fprintf(gp,
"set xrange [%f:%f]\n", cpl_matrix_get_min(xpos),
3232 cpl_matrix_get_max(xpos));
3233 cpl_matrix_delete(xpos);
3234 fprintf(gp,
"set cbrange [%f:%f]\n", cpl_vector_get_min(aLambdas),
3235 cpl_vector_get_max(aLambdas));
3236 fprintf(gp,
"plot \"-\" w p pal\n");
3238 printf(
"# X Y lambda\n");
3240 for (n = 0; n < cpl_vector_get_size(aLambdas); n++) {
3241 printf(
"%4d %7.2f %8.3f\n", (
int)cpl_matrix_get(aXYPos, 0, n),
3242 cpl_matrix_get(aXYPos, 1, n), cpl_vector_get(aLambdas, n));
3243 fprintf(gp,
"%f %f %f\n", cpl_matrix_get(aXYPos, 0, n),
3244 cpl_matrix_get(aXYPos, 1, n), cpl_vector_get(aLambdas, n));
3247 fprintf(gp,
"EOF\n");
3253 cpl_polynomial_delete(*aPoly);
3255 return CPL_ERROR_ILLEGAL_OUTPUT;
3258 int npoints = cpl_vector_get_size(aLambdas);
3259 cpl_vector *res = cpl_vector_new(npoints);
3262 cpl_vector_fill_polynomial_fit_residual(res, aLambdas, aDLambdas, *aPoly,
3270 for (i = 0; i < npoints; i++) {
3271 double weight = 1. / cpl_vector_get(aDLambdas, i);
3272 mse += pow(cpl_vector_get(res, i), 2) * weight;
3277 mse = cpl_vector_product(res, res) / npoints;
3279 double rlimit = rsigma * sqrt(mse);
3281 printf(
"Resulting 2D polynomial of slice %hu (%d points, RMS = %f dRMS = "
3282 "%f), %.1f-sigma limit now %f (target RMS = %f):\n", aSlice,
3283 npoints, sqrt(mse), rms < 0 ? 0. : rms - sqrt(mse), rsigma, rlimit,
3286 cpl_polynomial_dump(*aPoly, stdout);
3293 cpl_plot_vector(
"set title \"res\"\n",
"",
"", res);
3295 if (aParams->
rflag) {
3296 int nnew = cpl_vector_get_size(res),
3301 cpl_table_set_column_savetype(aParams->
residuals,
"slice", CPL_TYPE_UCHAR);
3303 cpl_table_set_size(aParams->
residuals, nrow + nnew);
3305 cpl_table_fill_column_window_int(aParams->
residuals,
"slice",
3306 nrow, nnew, aSlice);
3307 cpl_table_fill_column_window_int(aParams->
residuals,
"iteration",
3309 cpl_table_fill_column_window_double(aParams->
residuals,
"rejlimit",
3310 nrow, nnew, rlimit);
3312 for (n = 0; n < cpl_vector_get_size(res); n++) {
3313 cpl_table_set_int(aParams->
residuals,
"x", nrow + n,
3314 (
int)cpl_matrix_get(aXYPos, 0, n));
3315 cpl_table_set_float(aParams->
residuals,
"y", nrow + n,
3316 cpl_matrix_get(aXYPos, 1, n));
3317 cpl_table_set_float(aParams->
residuals,
"lambda", nrow + n,
3318 cpl_vector_get(aLambdas, n));
3319 cpl_table_set_double(aParams->
residuals,
"residual", nrow + n,
3320 cpl_vector_get(res, n));
3323 cpl_msg_debug(__func__,
"%"CPL_SIZE_FORMAT
" entries in residuals table "
3324 "after iteration %d of slice %hu",
3325 cpl_table_get_nrow(aParams->
residuals), niter, aSlice);
3332 cpl_boolean isgoodenough = (rms < 0 ? CPL_FALSE : rms - sqrt(mse) < 0.001)
3334 large_residuals = 0;
3336 for (i = 0; !isgoodenough && i < cpl_vector_get_size(res); i++) {
3338 if (fabs(cpl_vector_get(res, i)) < rlimit) {
3344 cpl_msg_debug(__func__,
"residual = %f (position %fx%f, lambda=%f+/-%f)",
3345 cpl_vector_get(res, i),
3346 cpl_matrix_get(aXYPos, 0, i), cpl_matrix_get(aXYPos, 1, i),
3347 cpl_vector_get(aLambdas, i),
3348 aDLambdas ? cpl_vector_get(aDLambdas, i) : 1.);
3350 if (cpl_vector_get_size(res) == 1) {
3351 cpl_msg_debug(__func__,
"trying to remove the last vector/matrix "
3352 "element when checking against fit sigma (slice %hu)",
3358 cpl_matrix_erase_columns(aXYPos, i, 1);
3369 if (!large_residuals) {
3378 cpl_vector_delete(res);
3381 return CPL_ERROR_NONE;
3397 const unsigned short aYOrder)
3399 cpl_table *table = cpl_table_new(aNSlices);
3400 cpl_ensure(table, CPL_ERROR_UNSPECIFIED, NULL);
3403 cpl_table_new_column(table, MUSE_WAVECAL_TABLE_COL_SLICE_NO, CPL_TYPE_INT);
3404 cpl_table_set_column_unit(table, MUSE_WAVECAL_TABLE_COL_SLICE_NO,
"No");
3405 cpl_table_set_column_format(table, MUSE_WAVECAL_TABLE_COL_SLICE_NO,
"%2d");
3409 for (i = 0; i <= aXOrder; i++) {
3411 for (j = 0; j <= aYOrder; j++) {
3413 char *colname = cpl_sprintf(MUSE_WAVECAL_TABLE_COL_COEFF, i, j);
3414 cpl_table_new_column(table, colname, CPL_TYPE_DOUBLE);
3416 cpl_table_set_column_unit(table, colname,
"Angstrom");
3417 cpl_table_set_column_format(table, colname,
"%12.5e");
3422 cpl_table_new_column(table, MUSE_WAVECAL_TABLE_COL_MSE, CPL_TYPE_DOUBLE);
3423 cpl_table_set_column_format(table, MUSE_WAVECAL_TABLE_COL_MSE,
"%f");
3445 double aMSE,
unsigned short aXOrder,
3446 unsigned short aYOrder,
const unsigned short aRow)
3448 cpl_ensure_code(aTable && aPoly, CPL_ERROR_NULL_INPUT);
3449 cpl_ensure_code(cpl_polynomial_get_dimension(aPoly) == 2,
3450 CPL_ERROR_ILLEGAL_INPUT);
3453 cpl_table_set_int(aTable, MUSE_WAVECAL_TABLE_COL_SLICE_NO, aRow, aRow + 1);
3454 cpl_table_set_double(aTable, MUSE_WAVECAL_TABLE_COL_MSE, aRow, aMSE);
3458 for (i = 0; i <= aXOrder; i++) {
3460 for (j = 0; j <= aYOrder; j++) {
3461 cpl_size pows[2] = { i, j };
3463 char *colname = cpl_sprintf(MUSE_WAVECAL_TABLE_COL_COEFF, i, j);
3464 cpl_error_code rc = cpl_table_set_double(aTable, colname, aRow,
3465 cpl_polynomial_get_coeff(aPoly,
3467 if (rc != CPL_ERROR_NONE) {
3468 cpl_msg_warning(__func__,
"Problem writing %f to field %s in "
3469 "wavelength table: %s",
3470 cpl_polynomial_get_coeff(aPoly, pows), colname,
3471 cpl_error_get_message());
3472 cpl_polynomial_dump(aPoly, stdout);
3473 cpl_table_dump(aTable, aRow, 1, stdout);
3480 return CPL_ERROR_NONE;
3501 unsigned short *aYOrder)
3503 cpl_ensure_code(aWave && aXOrder && aYOrder, CPL_ERROR_NULL_INPUT);
3504 cpl_array *cols = cpl_table_get_column_names(aWave);
3507 const char *highcol = cpl_array_get_string(cols, cpl_array_get_size(cols) - 2);
3508 char *colname = cpl_strdup(highcol);
3509 cpl_array_delete(cols);
3512 *aYOrder = atoi(colname+4);
3515 *aXOrder = atoi(colname+3);
3518 return CPL_ERROR_NONE;
3545 const unsigned short aSlice)
3547 cpl_ensure(aTable, CPL_ERROR_NULL_INPUT, NULL);
3548 cpl_ensure(aSlice >= 1 && aSlice <= kMuseSlicesPerCCD,
3549 CPL_ERROR_ILLEGAL_INPUT, NULL);
3552 int irow, nrow = cpl_table_get_nrow(aTable);
3553 for (irow = 0; irow < nrow; irow++) {
3555 unsigned short slice = cpl_table_get_int(aTable,
3556 MUSE_WAVECAL_TABLE_COL_SLICE_NO,
3558 if (slice == aSlice && !err) {
3562 cpl_ensure(irow < nrow, CPL_ERROR_DATA_NOT_FOUND, NULL);
3564 cpl_polynomial *pwave = cpl_polynomial_new(2);
3566 unsigned short wavexorder, waveyorder;
3569 for (l = 0; l <= wavexorder; l++) {
3571 for (k = 0; k <= waveyorder; k++) {
3572 cpl_size pows[2] = { l, k };
3573 sprintf(colname, MUSE_WAVECAL_TABLE_COL_COEFF, l, k);
3575 cpl_polynomial_set_coeff(pwave, pows,
3576 cpl_table_get_double(aTable, colname, irow,
3579 cpl_polynomial_delete(pwave);
3580 cpl_error_set_message(__func__, CPL_ERROR_ILLEGAL_OUTPUT,
"Wavelength "
3581 "calibration table broken in slice %hu (row index"
3582 " %d) column %s", aSlice, irow, colname);
3616 const cpl_table *aTrace)
3618 cpl_ensure(aImage && aWave && aTrace, CPL_ERROR_NULL_INPUT, NULL);
3619 int nx = cpl_image_get_size_x(aImage->
data),
3620 ny = cpl_image_get_size_y(aImage->
data);
3621 cpl_image *wavemap = cpl_image_new(nx, ny, CPL_TYPE_FLOAT);
3622 cpl_ensure(wavemap, cpl_error_get_code(), NULL);
3626 float *wdata = cpl_image_get_data_float(wavemap);
3628 unsigned short wavexorder, waveyorder;
3630 cpl_msg_debug(__func__,
"Order for trace solution is %d, for wavelength "
3632 wavexorder, waveyorder, ifu);
3635 unsigned short islice;
3636 for (islice = 0; islice < kMuseSlicesPerCCD; islice++) {
3638 cpl_msg_debug(__func__,
"Starting to process slice %hu of IFU %hhu",
3646 cpl_vector *pos = cpl_vector_new(2);
3652 cpl_msg_warning(__func__,
"slice %2hu of IFU %hhu: tracing polynomials "
3653 "missing!", islice + 1, ifu);
3657 printf(
"polynomials for slice %hu:\n", islice + 1);
3658 cpl_polynomial_dump(ptrace[MUSE_TRACE_LEFT], stdout);
3659 cpl_polynomial_dump(ptrace[MUSE_TRACE_RIGHT], stdout);
3660 cpl_polynomial_dump(pwave, stdout);
3666 for (j = 1; j <= ny; j++) {
3669 int ileft = ceil(cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_LEFT],
3671 iright = floor(cpl_polynomial_eval_1d(ptrace[MUSE_TRACE_RIGHT],
3674 if (ileft < 1 || iright > nx || ileft > iright) {
3675 cpl_msg_warning(__func__,
"slice %2hu of IFU %hhu: faulty polynomial "
3676 "detected at y=%d", islice + 1, ifu, j);
3679 cpl_vector_set(pos, 1, j);
3683 for (i = ileft; i <= iright; i++) {
3684 cpl_vector_set(pos, 0, i);
3687 wdata[(i-1) + (j-1)*nx] = cpl_polynomial_eval(pwave, pos);
3693 cpl_polynomial_delete(pwave);
3694 cpl_vector_delete(pos);
3727 unsigned int aIter, cpl_boolean aPlotLambda,
3730 #if HAVE_POPEN && HAVE_PCLOSE
3731 cpl_ensure_code(aTable, CPL_ERROR_NULL_INPUT);
3733 cpl_ensure_code(rc == CPL_ERROR_NONE, rc);
3735 FILE *gp = popen(
"gnuplot",
"w");
3737 return CPL_ERROR_ASSIGNING_STREAM;
3741 cpl_table_unselect_all(aTable);
3743 int n, nrow = cpl_table_get_nrow(aTable),
3746 printf(
"Selecting data of all slices.\n");
3748 const int *slice = cpl_table_get_data_int_const(aTable,
"slice"),
3749 *iter = cpl_table_get_data_int_const(aTable,
"iteration");
3751 fprintf(stderr,
"Selecting data of last iteration of all slices\n");
3753 int sliceno = slice[nrow - 1],
3754 iterlast = iter[nrow - 1];
3755 for (n = nrow - 2; n >= 0; n--) {
3756 if (slice[n] == sliceno && iter[n] != iterlast) {
3757 cpl_table_select_row(aTable, n);
3759 if (slice[n] != sliceno) {
3764 cpl_table_erase_selected(aTable);
3766 fprintf(gp,
"set title \"slices %d..%d, iterations %d..%d: 2D polynomial "
3767 "fit residuals (limits %f..%f)\n",
3768 (
int)cpl_table_get_column_min(aTable,
"slice"),
3769 (
int)cpl_table_get_column_max(aTable,
"slice"),
3770 (
int)cpl_table_get_column_min(aTable,
"iteration"),
3771 (
int)cpl_table_get_column_max(aTable,
"iteration"),
3772 cpl_table_get_column_min(aTable,
"rejlimit"),
3773 cpl_table_get_column_max(aTable,
"rejlimit"));
3775 printf(
"Selecting data of iteration %d.\n", aIter);
3776 for (n = 0; n < nrow; n++) {
3777 if (iter[n] != (
int)aIter) {
3778 cpl_table_select_row(aTable, n);
3781 cpl_table_erase_selected(aTable);
3783 fprintf(gp,
"set title \"slices %d..%d, iteration %d: 2D polynomial fit "
3784 "residuals (limits %f..%f)\n",
3785 (
int)cpl_table_get_column_min(aTable,
"slice"),
3786 (
int)cpl_table_get_column_max(aTable,
"slice"), aIter,
3787 cpl_table_get_column_min(aTable,
"rejlimit"),
3788 cpl_table_get_column_max(aTable,
"rejlimit"));
3791 printf(
"Selecting data of slice %hu.\n", aSlice);
3792 const int *slice = cpl_table_get_data_int_const(aTable,
"slice");
3793 for (n = 0; n < nrow; n++) {
3794 if (slice[n] != aSlice) {
3795 cpl_table_select_row(aTable, n);
3798 cpl_table_erase_selected(aTable);
3799 nrow = cpl_table_get_nrow(aTable);
3800 cpl_table_unselect_all(aTable);
3802 const int *iter = cpl_table_get_data_int_const(aTable,
"iteration");
3805 aIter = iter[nrow - 1];
3807 printf(
"Selecting data of iteration %d.\n", aIter);
3808 for (n = 0; n < nrow; n++) {
3809 if (iter[n] != (
int)aIter) {
3810 cpl_table_select_row(aTable, n);
3813 cpl_table_erase_selected(aTable);
3816 fprintf(gp,
"set title \"slice %hu, iteration %d: 2D polynomial fit residuals"
3817 " (limit=%f)\n", aSlice, aIter,
3818 cpl_table_get_double(aTable,
"rejlimit", 0, &error));
3822 nrow = cpl_table_get_nrow(aTable);
3823 cpl_ensure_code(nrow > 0, CPL_ERROR_DATA_NOT_FOUND);
3824 printf(
"Plotting %d points.\n", nrow);
3825 const int *x = cpl_table_get_data_int_const(aTable,
"x");
3826 const float *y = cpl_table_get_data_float_const(aTable,
"y"),
3827 *lambda = cpl_table_get_data_float_const(aTable,
"lambda");
3828 const double *r = cpl_table_get_data_double_const(aTable,
"residual");
3832 int xmin = cpl_table_get_column_min(aTable,
"x") - 2,
3833 xmax = cpl_table_get_column_max(aTable,
"x") + 2;
3834 float ymin = cpl_table_get_column_min(aTable,
"y") - 2,
3835 ymax = cpl_table_get_column_max(aTable,
"y") + 2,
3836 lmin = cpl_table_get_column_min(aTable,
"lambda") - 2,
3837 lmax = cpl_table_get_column_max(aTable,
"lambda") + 2;
3838 double rmin = cpl_table_get_column_min(aTable,
"residual"),
3839 rmax = cpl_table_get_column_max(aTable,
"residual");
3840 if (aCuts && cpl_vector_get_size(aCuts) == 2) {
3841 rmin = cpl_vector_get(aCuts, 0);
3842 rmax = cpl_vector_get(aCuts, 1);
3846 fprintf(gp,
"set palette defined ( 0 \"dark-violet\","
3847 "1 \"dark-blue\", 4 \"green\", 6 \"yellow\", 8 \"orange\","
3848 "9 \"red\", 10 \"dark-red\")\n");
3849 fprintf(gp,
"unset key\n");
3850 printf(
"Setting plotting limits: [%d:%d][%.2f:%.2f][%.4f:%.4f]\n",
3851 xmin, xmax, aPlotLambda ? lmin : ymin, aPlotLambda ? lmax : ymax,
3853 fprintf(gp,
"set xrange [%d:%d]\n", xmin, xmax);
3855 fprintf(gp,
"set yrange [%f:%f]\n", lmin, lmax);
3857 fprintf(gp,
"set yrange [%f:%f]\n", ymin, ymax);
3859 fprintf(gp,
"set cbrange [%f:%f]\n", rmin, rmax);
3860 fprintf(gp,
"set view map\n");
3861 fprintf(gp,
"splot \"-\" w p pal\n");
3862 for (n = 0; n < nrow; n++) {
3864 fprintf(gp,
"%d %f %e\n", x[n], lambda[n], r[n]);
3866 fprintf(gp,
"%d %f %e\n", x[n], y[n], r[n]);
3869 fprintf(gp,
"EOF\n");
3874 printf(
"Press ENTER to end program and close plot\n");
3877 return CPL_ERROR_NONE;
3879 return CPL_ERROR_UNSUPPORTED_MODE;
3912 const unsigned short aSlice,
unsigned int aColumn,
3913 unsigned int aIter, cpl_boolean aPlotRes)
3915 #if HAVE_POPEN && HAVE_PCLOSE
3916 cpl_ensure_code(aCTable && aRTable, CPL_ERROR_NULL_INPUT);
3918 cpl_ensure_code(rc == CPL_ERROR_NONE, rc);
3920 unsigned short xorder, yorder;
3922 cpl_ensure_code(xorder > 0 && yorder > 0, CPL_ERROR_ILLEGAL_INPUT);
3923 cpl_ensure_code(aSlice >= 1 && aSlice <= kMuseSlicesPerCCD,
3924 CPL_ERROR_ACCESS_OUT_OF_RANGE);
3926 FILE *gp = popen(
"gnuplot",
"w");
3928 return CPL_ERROR_ASSIGNING_STREAM;
3932 cpl_table_unselect_all(aRTable);
3934 printf(
"Selecting data of slice %hu.\n", aSlice);
3935 const int *slice = cpl_table_get_data_int_const(aRTable,
"slice");
3936 int n, nrow = cpl_table_get_nrow(aRTable);
3937 for (n = 0; n < nrow; n++) {
3938 if (slice[n] != aSlice) {
3939 cpl_table_select_row(aRTable, n);
3942 cpl_table_erase_selected(aRTable);
3943 nrow = cpl_table_get_nrow(aRTable);
3944 cpl_ensure_code(nrow > 0, CPL_ERROR_DATA_NOT_FOUND);
3945 cpl_table_unselect_all(aRTable);
3947 const int *iter = cpl_table_get_data_int_const(aRTable,
"iteration");
3950 aIter = iter[nrow - 1];
3952 printf(
"Selecting data of iteration %d.\n", aIter);
3953 for (n = 0; n < nrow; n++) {
3954 if (iter[n] != (
int)aIter) {
3955 cpl_table_select_row(aRTable, n);
3958 cpl_table_erase_selected(aRTable);
3959 nrow = cpl_table_get_nrow(aRTable);
3960 cpl_ensure_code(nrow > 0, CPL_ERROR_DATA_NOT_FOUND);
3961 cpl_table_unselect_all(aRTable);
3963 unsigned int col1 = cpl_table_get_column_min(aRTable,
"x"),
3964 col2 = cpl_table_get_column_max(aRTable,
"x");
3966 col1 = col2 = aColumn;
3967 }
else if (aColumn > (
unsigned)kMuseOutputXRight) {
3969 col1 = col2 = (col1 + col2) / 2;
3971 printf(
"Plotting data of columns %u..%u.\n", col1, col2);
3974 float ymin = cpl_table_get_column_min(aRTable,
"y") - 10,
3975 ymax = cpl_table_get_column_max(aRTable,
"y") + 10,
3976 lmin = cpl_table_get_column_min(aRTable,
"lambda") - 10,
3977 lmax = cpl_table_get_column_max(aRTable,
"lambda") + 10;
3978 double rmin = cpl_table_get_column_min(aRTable,
"residual") * 1.03,
3979 rmax = cpl_table_get_column_max(aRTable,
"residual") * 1.03;
3981 fprintf(gp,
"set title \"slice %hu, iteration %d, column %u..%u: polynomial "
3982 "and ", aSlice, aIter, col1, col2);
3983 printf(
"Setting plotting limits: ");
3985 fprintf(gp,
"residuals (limit=%f)\"\n",
3986 cpl_table_get_double(aRTable,
"rejlimit", 0, NULL));
3987 printf(
"[%.2f:%.2f][%.4f:%.4f]\n", lmin, lmax, rmin, rmax);
3988 fprintf(gp,
"set xrange [%f:%f]\n", lmin, lmax);
3989 fprintf(gp,
"set yrange [%f:%f]\n", rmin, rmax);
3990 fprintf(gp,
"set xlabel \"Wavelength [Angstrom]\"\n");
3991 fprintf(gp,
"set ylabel \"Residuals [Angstrom]\"\n");
3993 fprintf(gp,
"arc line positions\"\n");
3994 printf(
"[%.2f:%.2f][%.2f:%.2f]\n", ymin, ymax, lmin, lmax);
3995 fprintf(gp,
"set xrange [%g:%g]\n", ymin, ymax);
3996 fprintf(gp,
"set yrange [%f:%f]\n", lmin, lmax);
3997 fprintf(gp,
"set xlabel \"y-position [pix]\"\n");
3998 fprintf(gp,
"set ylabel \"Wavelength [Angstrom]\"\n");
4000 fprintf(gp,
"set key outside below\n");
4001 fprintf(gp,
"set samples 1000\n");
4004 fprintf(gp,
"p(x,y) = 0 ");
4007 for (i = 0; i <= xorder; i++) {
4009 for (j = 0; j <= yorder; j++) {
4010 char *coeff = cpl_sprintf(MUSE_WAVECAL_TABLE_COL_COEFF, i, j);
4011 double cvalue = cpl_table_get(aCTable, coeff, aSlice - 1, NULL);
4013 fprintf(gp,
" + (%g) * x**(%hu) * y**(%hu)", cvalue, i, j);
4019 const int *x = cpl_table_get_data_int_const(aRTable,
"x");
4020 const float *y = cpl_table_get_data_float_const(aRTable,
"y"),
4021 *lambda = cpl_table_get_data_float_const(aRTable,
"lambda");
4022 const double *r = cpl_table_get_data_double_const(aRTable,
"residual");
4025 double dcol = (col2 - col1) / 255.;
4030 fprintf(gp,
"plot ");
4032 fprintf(gp,
"0 t \"\", ");
4034 unsigned int ncol, npoints = 0;
4035 for (ncol = col1; ncol <= col2; ncol++) {
4037 int red = (ncol - col1) / dcol,
4038 grn = (col2 - ncol) / dcol,
4041 fprintf(gp,
"\"-\" u 2:3 t \"col %u\" w p ps 0.8 lt rgb \"#%02x%02x%02x\"",
4042 ncol, red, grn, blu);
4045 fprintf(gp,
"p(%u, x) t \"\" w l lw 0.7 lt rgb \"#%02x%02x%02x\", "
4046 "\"-\" u 1:(p(%u,$1)+$3) t \"col %u\" w p ps 0.8 lt rgb \"#%02x%02x%02x\"",
4047 ncol, red, grn, blu, ncol, ncol, red, grn, blu);
4055 for (ncol = col1; ncol <= col2; ncol++) {
4056 for (n = 0; n < nrow; n++) {
4057 if (x[n] == (
int)ncol) {
4058 fprintf(gp,
"%f %f %g\n", y[n], lambda[n], r[n]);
4062 fprintf(gp,
"EOF\n");
4064 printf(
"Plotted %u points.\n", npoints);
4069 printf(
"Press ENTER to end program and close plot\n");
4072 return CPL_ERROR_NONE;
4074 return CPL_ERROR_UNSUPPORTED_MODE;
cpl_table * muse_wave_lines_search(muse_image *aColumnImage, double aSigma, const unsigned short aSlice, const unsigned char aIFU)
Search and store emission lines in a column of an arc frame.
cpl_table * muse_wave_calib_lampwise(muse_imagelist *aImages, cpl_table *aTrace, cpl_table *aLinelist, muse_wave_params *aParams)
Find wavelength calibration solution using a list of arc images with different lamps.
cpl_table * muse_wave_calib(muse_image *aImage, cpl_table *aTrace, cpl_table *aLinelist, muse_wave_params *aParams)
Find wavelength calibration solution on an arc frame.
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
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
void muse_image_delete(muse_image *aImage)
Deallocate memory associated to a muse_image object.
muse_wave_weighting_type fitweighting
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.
cpl_vector * muse_wave_lines_get_for_lamp(cpl_table *aTable, const char *aLamp, int aGoodnessLimit, double aFluxLimit)
Load wavelengths for a given lamp from a linelist table into a vector.
cpl_error_code muse_wave_lines_identify(cpl_table *aLines, cpl_vector *aLambdas, const muse_wave_params *aParams)
Identify the wavelength of arc detected lines using pattern matching.
void muse_wave_params_delete(muse_wave_params *aParams)
Deallocate memory associated to a wavelength parameters structure.
unsigned char muse_utils_get_ifu(const cpl_propertylist *aHeaders)
Find out the IFU/channel from which this header originated.
cpl_image * data
the data extension
cpl_error_code muse_wave_poly_fit(cpl_matrix *aXYPos, cpl_vector *aLambdas, cpl_vector *aDLambdas, cpl_polynomial **aPoly, double *aMSE, muse_wave_params *aParams, const unsigned short aSlice)
Compute the wavelength solution from the sample positions and the respective wavelengths.
cpl_table * muse_wave_table_create(const unsigned short aNSlices, const unsigned short aXOrder, const unsigned short aYOrder)
Create the table to save te wave wavelength calibration coefficients.
muse_image * muse_combine_median_create(muse_imagelist *aImages)
Median combine a list of input images.
cpl_image * stat
the statistics extension
void muse_imagelist_delete(muse_imagelist *aList)
Free the memory of the MUSE image list.
cpl_vector * muse_wave_lines_get(cpl_table *aTable, int aGoodnessLimit, double aFluxLimit)
Load usable wavelengths from a linelist table into a vector.
static void muse_wave_lines_add_flux_for_lsf(cpl_table *, cpl_table *)
Add the measured flux of the detected lines to a linelist.
Structure definition of MUSE three extension FITS file.
int muse_pfits_get_lampnum(const cpl_propertylist *aHeaders)
query the number of lamps installed
cpl_table * muse_wave_line_handle_multiplet(muse_image *aImage, cpl_table *aLinelist, unsigned int aIdx, cpl_polynomial *aPoly, cpl_polynomial **aTrace, const muse_wave_params *aParams, const unsigned short aSlice, int aDebug)
Handle fitting of all multiplets across the columns a given slice.
cpl_propertylist * header
the FITS header
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.
void muse_trace_polys_delete(cpl_polynomial *aPolys[])
Delete the multi-polynomial array created in relation to tracing.
cpl_image * dq
the data quality extension
cpl_table * muse_cpltable_new(const muse_cpltable_def *aDef, cpl_size aLength)
Create an empty table according to the specified definition.
const char * muse_wave_lines_get_lampname(cpl_table *aTable, const int aIdx)
Associate the ion listed in a linelist table row to a lamp name.
muse_image * muse_imagelist_get(muse_imagelist *aList, unsigned int aIdx)
Get the muse_image of given list index.
cpl_error_code muse_cplvector_erase_element(cpl_vector *aVector, int aElement)
delete the given element from the input vector
Structure containing wavelength calibration parameters.
cpl_polynomial * muse_utils_iterate_fit_polynomial(cpl_matrix *aPos, cpl_vector *aVal, cpl_vector *aErr, cpl_table *aExtra, const unsigned int aOrder, const double aRSigma, double *aMSE, double *aChiSq)
Iterate a polynomial fit.
cpl_error_code muse_wave_table_add_poly(cpl_table *aTable, cpl_polynomial *aPoly, double aMSE, unsigned short aXOrder, unsigned short aYOrder, const unsigned short aRow)
Save the given polynomials to the wavelength calibration table.
cpl_image * muse_wave_map(muse_image *aImage, const cpl_table *aWave, const cpl_table *aTrace)
Write out a wavelength map for visual checks.
const muse_cpltable_def muse_wavedebug_def[]
MUSE wavelength calibration residuals table definition.
cpl_error_code muse_utils_fit_multigauss_1d(const cpl_vector *aX, const cpl_bivector *aY, cpl_vector *aCenter, double *aSigma, cpl_vector *aFlux, cpl_vector *aPoly, double *aMSE, double *aRedChisq, cpl_matrix **aCovariance)
Carry out a multi-Gaussian fit of data in a vector.
char * muse_utils_header_get_lamp_names(cpl_propertylist *aHeader, char aSep)
Concatenate names of all active calibration lamps.
cpl_size muse_cpltable_find_sorted(const cpl_table *aTable, const char *aColumn, double aValue)
Find a row in a table.
cpl_error_code muse_wave_plot_residuals(cpl_table *aTable, const unsigned short aSlice, unsigned int aIter, cpl_boolean aPlotLambda, cpl_vector *aCuts)
Fancy plotting of wavelength calibration residuals (color coded over x/y-position) using gnuplot...
cpl_array * muse_utils_header_get_lamp_numbers(cpl_propertylist *aHeader)
List numbers of all active calibration lamps.
cpl_error_code muse_image_save(muse_image *aImage, const char *aFilename)
Save the three image extensions and the FITS headers of a MUSE image to a file.
cpl_error_code muse_wave_line_fit_iterate(cpl_table *aFitTable, double aLambda, const muse_wave_params *aParams)
Use a low-order polynomial to find and discard bad values for line centroid fits of single arc line a...
muse_imagelist * muse_imagelist_new(void)
Create a new (empty) MUSE image list.
cpl_error_code muse_wave_line_fit_single(muse_image *aImage, int aX, double aY, int aHalfWidth, double aSigma, cpl_table *aFitTable, int aRowsNeeded)
Fit a Gaussian to a single emission line in an arc frame and do simple error handling.
cpl_size muse_cplvector_count_unique(const cpl_vector *aVector)
Count the number of unique entries in a given vector.
Definition of a cpl table structure.
cpl_boolean muse_wave_lines_check(cpl_table *aTable, cpl_propertylist *aHeader)
Check that a LINE_CATALOG has the expected format.
cpl_error_code muse_wave_plot_column(cpl_table *aCTable, cpl_table *aRTable, const unsigned short aSlice, unsigned int aColumn, unsigned int aIter, cpl_boolean aPlotRes)
Plot wavelength calibration polynomial and data or residuals using gnuplot.
muse_image * muse_image_new(void)
Allocate memory for a new muse_image object.
cpl_error_code muse_wave_line_fit_multiple(muse_image *aImage, int aX, cpl_bivector *aPeaks, cpl_vector *aLambdas, int aHalfWidth, double aSigma, cpl_table *aFitTable, int aRowsNeeded)
Fit a multi-Gaussian to a multiplet of arc emission lines and do simple error handling.
muse_wave_params * muse_wave_params_new(void)
Allocate a wavelength parameters structure and fill it with defaults.
cpl_error_code muse_imagelist_set(muse_imagelist *aList, muse_image *aImage, unsigned int aIdx)
Set the muse_image of given list index.
const muse_cpltable_def muse_wavelines_def[]
MUSE wavelength calibration arc line fit properties table definition.
cpl_table * muse_wave_line_handle_singlet(muse_image *aImage, cpl_table *aLinelist, unsigned int aIdx, cpl_polynomial *aPoly, cpl_polynomial **aTrace, const muse_wave_params *aParams, const unsigned short aSlice, int aDebug)
Handle fitting of all single lines across the columns a given slice.
muse_ins_mode muse_pfits_get_mode(const cpl_propertylist *aHeaders)
find out the observation mode