35 #include "muse_wavecal_z.h"
85 static const char *muse_wavecal_help =
86 "This recipe detects arc emission lines and fits a wavelength solution to each slice of the instrument. The wavelength calibration table contains polynomials defining the wavelength solution of the slices on the CCD. Processing trims the raw data and records the overscan statistics, subtracts the bias (taking account of the overscan, if --overscan is not &none&) and converts them from adu to count. Optionally, the dark can be subtracted and the data can be divided by the flat-field, but this is not recommended. The data is then combined using input parameters, first into separate images for each lamp. If --lampwise is not given or if --lsf or --resample are given, these lamp-separate exposures are summed to create a single combined master arc. To compute the wavelength solution, arc lines are detected at the center of each slice (using threshold detection on a S/N image) and subsequently assigned wavelengths, using pattern matching to identify lines from the input line catalog. Each line is then traced to the edges of the slice, using Gaussian centering in each CCD column. The Gaussians not only yield center, but also centering error, and line properties (e.g. FWHM). Deviant fits are detected using polynomial fits to each arc line (using the xorder parameter) and rejected. If --lampwise is switched on, these analysis and measuring steps are carried out separately on images exposed by the different arc lamps, reducing the amount of blending, that can otherwise influence line identification and Gaussian centering. The final two-dimensional fit uses all positions (of all lamps), their wavelengths, and the given polynomial orders to compute the final wavelength solution for each slice, iteratively rejecting outliers. This final fit can be either unweighted (fitweighting=&uniform&, for fastest processing) or weighted (other values of fitweighting, for higher accuracy). If --lsf is switched on, the line spread function is determined for each slice and saved in the LSF table for later use with sky subtraction.";
88 static const char *muse_wavecal_help_esorex =
89 "\n\nInput frames for raw frame tag \"ARC\":\n"
90 "\n Frame tag Type Req #Fr Description"
91 "\n -------------------- ---- --- --- ------------"
92 "\n ARC raw Y Raw arc lamp exposures"
93 "\n MASTER_BIAS calib Y 1 Master bias"
94 "\n MASTER_DARK calib . 1 Master dark"
95 "\n MASTER_FLAT calib . 1 Master flat"
96 "\n TRACE_TABLE calib Y 1 Trace table"
97 "\n LINE_CATALOG calib Y 1 Arc line catalog"
98 "\n BADPIX_TABLE calib . 1 Bad pixel table"
99 "\n LSF_TABLE calib . First guess for LSF parameters"
100 "\n\nProduct frames for raw frame tag \"ARC\":\n"
101 "\n Frame tag Level Description"
102 "\n -------------------- -------- ------------"
103 "\n WAVECAL_TABLE final Wavelength calibration table"
104 "\n WAVECAL_RESIDUALS final Fit residuals of all arc lines (if --residuals=true)"
105 "\n ARC_RED_LAMP final Reduced ARC image, per lamp"
106 "\n ARC_RED final Reduced master ARC image"
107 "\n ARC_RESAMPLED final Resampled arc images (if --resampled=true)"
108 "\n WAVE_MAP final Wavelength map of the input images"
109 "\n LSF_TABLE final Slice specific LSF parameters (if --lsf=true)"
110 "\n LSF_RESIDUALS final Subtracted pixel table after LSF fit (if --lsf=true and --lsf_residuals=true)";
121 static cpl_recipeconfig *
122 muse_wavecal_new_recipeconfig(
void)
124 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
128 cpl_recipeconfig_set_tag(recipeconfig, tag, 1, -1);
129 cpl_recipeconfig_set_input(recipeconfig, tag,
"MASTER_BIAS", 1, 1);
130 cpl_recipeconfig_set_input(recipeconfig, tag,
"MASTER_DARK", -1, 1);
131 cpl_recipeconfig_set_input(recipeconfig, tag,
"MASTER_FLAT", -1, 1);
132 cpl_recipeconfig_set_input(recipeconfig, tag,
"TRACE_TABLE", 1, 1);
133 cpl_recipeconfig_set_input(recipeconfig, tag,
"LINE_CATALOG", 1, 1);
134 cpl_recipeconfig_set_input(recipeconfig, tag,
"BADPIX_TABLE", -1, 1);
135 cpl_recipeconfig_set_input(recipeconfig, tag,
"LSF_TABLE", 0, -1);
136 cpl_recipeconfig_set_output(recipeconfig, tag,
"WAVECAL_TABLE");
137 cpl_recipeconfig_set_output(recipeconfig, tag,
"WAVECAL_RESIDUALS");
138 cpl_recipeconfig_set_output(recipeconfig, tag,
"ARC_RED_LAMP");
139 cpl_recipeconfig_set_output(recipeconfig, tag,
"ARC_RED");
140 cpl_recipeconfig_set_output(recipeconfig, tag,
"ARC_RESAMPLED");
141 cpl_recipeconfig_set_output(recipeconfig, tag,
"WAVE_MAP");
142 cpl_recipeconfig_set_output(recipeconfig, tag,
"LSF_TABLE");
143 cpl_recipeconfig_set_output(recipeconfig, tag,
"LSF_RESIDUALS");
159 static cpl_error_code
160 muse_wavecal_prepare_header(
const char *aFrametag, cpl_propertylist *aHeader)
162 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
163 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
164 if (!strcmp(aFrametag,
"WAVECAL_TABLE")) {
167 "Number of detected arc lines in slice j");
170 "Number of identified arc lines in slice j");
173 "[count] Mean peak count level above background of detected arc lines in slice j");
176 "[count] Standard deviation of peak count level above background of detected arc lines in slice j");
179 "[count] Peak count level above background of the faintest line in slice j");
182 "[count] Peak count level above background of the brightest line in slice j");
185 "[count] Mean peak count level of lines of lamp l above background of detected arc lines in slice j. Not produced with --lampwise=FALSE!");
188 "[count] Standard deviation of peak count level of lines of lamp l above background of detected arc lines in slice j. Not produced with --lampwise=FALSE!");
191 "[count] Peak count level above background of the brightest line of lamp l in slice j. Not produced with --lampwise=FALSE!");
194 "Mean FWHM of detected arc lines in slice j");
197 "Standard deviation of FWHM of detected arc lines in slice j");
200 "Minimum FWHM of detected arc lines in slice j");
203 "Maximum FWHM of detected arc lines in slice j");
206 "Mean spectral resolution R determined in slice j");
209 "Number of arc lines used in calibration solution fit in slice j");
212 "[Angstrom] RMS of the wavelength calibration fit in slice j");
215 "[Angstrom] Difference in wavelength computed for the bottom left and bottom right corners of the slice on the CCD");
218 "[Angstrom] Difference in wavelength computed for the top left and top right corners of the slice on the CCD");
221 "[pix] Position of wavelength given in WLEN in slice j");
224 "[Angstrom] Wavelength associated to WLPOS in slice j");
225 }
else if (!strcmp(aFrametag,
"WAVECAL_RESIDUALS")) {
226 }
else if (!strcmp(aFrametag,
"ARC_RED_LAMP")) {
229 "Number of saturated pixels in raw arc i in input list");
232 "Number of saturated pixels in output data");
233 }
else if (!strcmp(aFrametag,
"ARC_RED")) {
236 "Number of saturated pixels in raw arc i of lamp l in input list");
239 "Number of saturated pixels in output data");
240 }
else if (!strcmp(aFrametag,
"ARC_RESAMPLED")) {
241 }
else if (!strcmp(aFrametag,
"WAVE_MAP")) {
242 }
else if (!strcmp(aFrametag,
"LSF_TABLE")) {
245 "[Angstrom] Wavelength of line l");
248 "[Angstrom] LSF width in IFU i, slice j at the wavelength of line l");
251 "[Angstrom] Wavelength calibration offset in IFU i, slice j at the wavelength of line l");
254 "[Angstrom] FWHM of the LSF in IFU i, slice j at the wavelength of line l");
257 "Relative error of wavelength calibration of IFU i, slice j");
258 }
else if (!strcmp(aFrametag,
"LSF_RESIDUALS")) {
260 cpl_msg_warning(__func__,
"Frame tag %s is not defined", aFrametag);
261 return CPL_ERROR_ILLEGAL_INPUT;
263 return CPL_ERROR_NONE;
276 static cpl_frame_level
277 muse_wavecal_get_frame_level(
const char *aFrametag)
280 return CPL_FRAME_LEVEL_NONE;
282 if (!strcmp(aFrametag,
"WAVECAL_TABLE")) {
283 return CPL_FRAME_LEVEL_FINAL;
285 if (!strcmp(aFrametag,
"WAVECAL_RESIDUALS")) {
286 return CPL_FRAME_LEVEL_FINAL;
288 if (!strcmp(aFrametag,
"ARC_RED_LAMP")) {
289 return CPL_FRAME_LEVEL_FINAL;
291 if (!strcmp(aFrametag,
"ARC_RED")) {
292 return CPL_FRAME_LEVEL_FINAL;
294 if (!strcmp(aFrametag,
"ARC_RESAMPLED")) {
295 return CPL_FRAME_LEVEL_FINAL;
297 if (!strcmp(aFrametag,
"WAVE_MAP")) {
298 return CPL_FRAME_LEVEL_FINAL;
300 if (!strcmp(aFrametag,
"LSF_TABLE")) {
301 return CPL_FRAME_LEVEL_FINAL;
303 if (!strcmp(aFrametag,
"LSF_RESIDUALS")) {
304 return CPL_FRAME_LEVEL_FINAL;
306 return CPL_FRAME_LEVEL_NONE;
320 muse_wavecal_get_frame_mode(
const char *aFrametag)
325 if (!strcmp(aFrametag,
"WAVECAL_TABLE")) {
328 if (!strcmp(aFrametag,
"WAVECAL_RESIDUALS")) {
331 if (!strcmp(aFrametag,
"ARC_RED_LAMP")) {
334 if (!strcmp(aFrametag,
"ARC_RED")) {
337 if (!strcmp(aFrametag,
"ARC_RESAMPLED")) {
340 if (!strcmp(aFrametag,
"WAVE_MAP")) {
343 if (!strcmp(aFrametag,
"LSF_TABLE")) {
346 if (!strcmp(aFrametag,
"LSF_RESIDUALS")) {
364 muse_wavecal_create(cpl_plugin *aPlugin)
368 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
369 recipe = (cpl_recipe *)aPlugin;
377 muse_wavecal_new_recipeconfig(),
378 muse_wavecal_prepare_header,
379 muse_wavecal_get_frame_level,
380 muse_wavecal_get_frame_mode);
385 cpl_msg_set_time_on();
389 recipe->parameters = cpl_parameterlist_new();
394 p = cpl_parameter_new_range(
"muse.muse_wavecal.nifu",
396 "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
401 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"nifu");
402 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nifu");
404 cpl_parameterlist_append(recipe->parameters, p);
407 p = cpl_parameter_new_value(
"muse.muse_wavecal.overscan",
409 "If this is \"none\", stop when detecting discrepant overscan levels (see ovscsigma), for \"offset\" it assumes that the mean overscan level represents the real offset in the bias levels of the exposures involved, and adjusts the data accordingly; for \"vpoly\", a polynomial is fit to the vertical overscan and subtracted from the whole quadrant.",
411 (
const char *)
"vpoly");
412 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"overscan");
413 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"overscan");
415 cpl_parameterlist_append(recipe->parameters, p);
418 p = cpl_parameter_new_value(
"muse.muse_wavecal.ovscreject",
420 "This influences how values are rejected when computing overscan statistics. Either no rejection at all (\"none\"), rejection using the DCR algorithm (\"dcr\"), or rejection using an iterative constant fit (\"fit\").",
422 (
const char *)
"dcr");
423 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscreject");
424 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscreject");
426 cpl_parameterlist_append(recipe->parameters, p);
429 p = cpl_parameter_new_value(
"muse.muse_wavecal.ovscsigma",
431 "If the deviation of mean overscan levels between a raw input image and the reference image is higher than |ovscsigma x stdev|, stop the processing. If overscan=\"vpoly\", this is used as sigma rejection level for the iterative polynomial fit. Has no effect for overscan=\"offset\".",
434 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscsigma");
435 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscsigma");
437 cpl_parameterlist_append(recipe->parameters, p);
440 p = cpl_parameter_new_value(
"muse.muse_wavecal.ovscignore",
442 "The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when computing statistics or fits.",
445 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscignore");
446 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscignore");
448 cpl_parameterlist_append(recipe->parameters, p);
451 p = cpl_parameter_new_enum(
"muse.muse_wavecal.combine",
453 "Type of lampwise image combination to use.",
455 (
const char *)
"sigclip",
457 (
const char *)
"average",
458 (
const char *)
"median",
459 (
const char *)
"minmax",
460 (
const char *)
"sigclip");
461 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"combine");
462 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"combine");
464 cpl_parameterlist_append(recipe->parameters, p);
467 p = cpl_parameter_new_value(
"muse.muse_wavecal.lampwise",
469 "Identify and measure the arc emission lines on images separately for each lamp setup.",
472 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lampwise");
473 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lampwise");
475 cpl_parameterlist_append(recipe->parameters, p);
478 p = cpl_parameter_new_value(
"muse.muse_wavecal.sigma",
480 "Sigma level used to detect arc emission lines above the median background level in the S/N image of the central column of each slice",
483 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"sigma");
484 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sigma");
486 cpl_parameterlist_append(recipe->parameters, p);
489 p = cpl_parameter_new_value(
"muse.muse_wavecal.dres",
491 "The allowed range of resolutions for pattern matching (of detected arc lines to line list) in fractions relative to the expected value",
494 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"dres");
495 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"dres");
497 cpl_parameterlist_append(recipe->parameters, p);
500 p = cpl_parameter_new_value(
"muse.muse_wavecal.tolerance",
502 "Tolerance for pattern matching (of detected arc lines to line list)",
505 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"tolerance");
506 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"tolerance");
508 cpl_parameterlist_append(recipe->parameters, p);
511 p = cpl_parameter_new_value(
"muse.muse_wavecal.xorder",
513 "Order of the polynomial for the horizontal curvature within each slice",
516 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"xorder");
517 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"xorder");
519 cpl_parameterlist_append(recipe->parameters, p);
522 p = cpl_parameter_new_value(
"muse.muse_wavecal.yorder",
524 "Order of the polynomial used to fit the dispersion relation",
527 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"yorder");
528 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"yorder");
530 cpl_parameterlist_append(recipe->parameters, p);
533 p = cpl_parameter_new_value(
"muse.muse_wavecal.linesigma",
535 "Sigma level for iterative rejection of deviant fits for each arc line within each slice, a negative value means to use the default (2.5).",
538 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"linesigma");
539 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"linesigma");
541 cpl_parameterlist_append(recipe->parameters, p);
544 p = cpl_parameter_new_value(
"muse.muse_wavecal.residuals",
546 "Create a table containing residuals of the fits to the data of all arc lines. This is useful to assess the quality of the wavelength solution in detail.",
549 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"residuals");
550 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"residuals");
552 cpl_parameterlist_append(recipe->parameters, p);
555 p = cpl_parameter_new_value(
"muse.muse_wavecal.fitsigma",
557 "Sigma level for iterative rejection of deviant datapoints during the final polynomial wavelength solution within each slice, a negative value means to use the default (3.0).",
560 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"fitsigma");
561 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"fitsigma");
563 cpl_parameterlist_append(recipe->parameters, p);
566 p = cpl_parameter_new_enum(
"muse.muse_wavecal.fitweighting",
568 "Type of weighting to use in the final polynomial wavelength solution fit, using centroiding error estimate and/or scatter of each single line as estimates of its accuracy.",
570 (
const char *)
"cerrscatter",
572 (
const char *)
"uniform",
573 (
const char *)
"cerr",
574 (
const char *)
"scatter",
575 (
const char *)
"cerrscatter");
576 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"fitweighting");
577 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"fitweighting");
579 cpl_parameterlist_append(recipe->parameters, p);
582 p = cpl_parameter_new_value(
"muse.muse_wavecal.resample",
584 "Resample the input arc images onto 2D images for a visual check using tracing and wavelength calibration solutions. Note that the image produced will show small wiggles even when the calibration was successful!",
587 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"resample");
588 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"resample");
590 cpl_parameterlist_append(recipe->parameters, p);
593 p = cpl_parameter_new_value(
"muse.muse_wavecal.wavemap",
595 "Create a wavelength map of the input images",
598 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"wavemap");
599 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"wavemap");
601 cpl_parameterlist_append(recipe->parameters, p);
604 p = cpl_parameter_new_value(
"muse.muse_wavecal.lsf",
606 "Fit the line spread function for each slice and save the result in the output LSF_TABLE.",
609 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lsf");
610 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lsf");
612 cpl_parameterlist_append(recipe->parameters, p);
615 p = cpl_parameter_new_value(
"muse.muse_wavecal.lsf-residuals",
617 "Store the residual pixel table after the LSF fit.",
620 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lsf-residuals");
621 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lsf-residuals");
623 cpl_parameterlist_append(recipe->parameters, p);
643 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
644 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
647 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.nifu");
648 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
649 aParams->
nifu = cpl_parameter_get_int(p);
651 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.overscan");
652 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
653 aParams->
overscan = cpl_parameter_get_string(p);
655 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.ovscreject");
656 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
657 aParams->
ovscreject = cpl_parameter_get_string(p);
659 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.ovscsigma");
660 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
661 aParams->
ovscsigma = cpl_parameter_get_double(p);
663 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.ovscignore");
664 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
665 aParams->
ovscignore = cpl_parameter_get_int(p);
667 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.combine");
668 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
669 aParams->
combine_s = cpl_parameter_get_string(p);
671 (!strcasecmp(aParams->
combine_s,
"average")) ? MUSE_WAVECAL_PARAM_COMBINE_AVERAGE :
672 (!strcasecmp(aParams->
combine_s,
"median")) ? MUSE_WAVECAL_PARAM_COMBINE_MEDIAN :
673 (!strcasecmp(aParams->
combine_s,
"minmax")) ? MUSE_WAVECAL_PARAM_COMBINE_MINMAX :
674 (!strcasecmp(aParams->
combine_s,
"sigclip")) ? MUSE_WAVECAL_PARAM_COMBINE_SIGCLIP :
675 MUSE_WAVECAL_PARAM_COMBINE_INVALID_VALUE;
676 cpl_ensure_code(aParams->
combine != MUSE_WAVECAL_PARAM_COMBINE_INVALID_VALUE,
677 CPL_ERROR_ILLEGAL_INPUT);
679 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.lampwise");
680 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
681 aParams->
lampwise = cpl_parameter_get_bool(p);
683 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.sigma");
684 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
685 aParams->
sigma = cpl_parameter_get_double(p);
687 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.dres");
688 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
689 aParams->
dres = cpl_parameter_get_double(p);
691 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.tolerance");
692 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
693 aParams->
tolerance = cpl_parameter_get_double(p);
695 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.xorder");
696 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
697 aParams->
xorder = cpl_parameter_get_int(p);
699 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.yorder");
700 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
701 aParams->
yorder = cpl_parameter_get_int(p);
703 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.linesigma");
704 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
705 aParams->
linesigma = cpl_parameter_get_double(p);
707 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.residuals");
708 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
709 aParams->
residuals = cpl_parameter_get_bool(p);
711 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.fitsigma");
712 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
713 aParams->
fitsigma = cpl_parameter_get_double(p);
715 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.fitweighting");
716 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
719 (!strcasecmp(aParams->
fitweighting_s,
"uniform")) ? MUSE_WAVECAL_PARAM_FITWEIGHTING_UNIFORM :
720 (!strcasecmp(aParams->
fitweighting_s,
"cerr")) ? MUSE_WAVECAL_PARAM_FITWEIGHTING_CERR :
721 (!strcasecmp(aParams->
fitweighting_s,
"scatter")) ? MUSE_WAVECAL_PARAM_FITWEIGHTING_SCATTER :
722 (!strcasecmp(aParams->
fitweighting_s,
"cerrscatter")) ? MUSE_WAVECAL_PARAM_FITWEIGHTING_CERRSCATTER :
723 MUSE_WAVECAL_PARAM_FITWEIGHTING_INVALID_VALUE;
724 cpl_ensure_code(aParams->
fitweighting != MUSE_WAVECAL_PARAM_FITWEIGHTING_INVALID_VALUE,
725 CPL_ERROR_ILLEGAL_INPUT);
727 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.resample");
728 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
729 aParams->
resample = cpl_parameter_get_bool(p);
731 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.wavemap");
732 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
733 aParams->
wavemap = cpl_parameter_get_bool(p);
735 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.lsf");
736 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
737 aParams->
lsf = cpl_parameter_get_bool(p);
739 p = cpl_parameterlist_find(aParameters,
"muse.muse_wavecal.lsf-residuals");
740 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
755 muse_wavecal_exec(cpl_plugin *aPlugin)
757 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
760 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
761 cpl_msg_set_threadid_on();
763 cpl_frameset *usedframes = cpl_frameset_new(),
764 *outframes = cpl_frameset_new();
766 muse_wavecal_params_fill(¶ms, recipe->parameters);
768 cpl_errorstate prestate = cpl_errorstate_get();
770 if (params.
nifu < -1 || params.
nifu > kMuseNumIFUs) {
771 cpl_msg_error(__func__,
"Please specify a valid IFU number (between 1 and "
772 "%d), 0 (to process all IFUs consecutively), or -1 (to "
773 "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
778 if (params.
nifu > 0) {
781 rc = muse_wavecal_compute(proc, ¶ms);
782 cpl_frameset_join(usedframes, proc->
usedFrames);
785 }
else if (params.
nifu < 0) {
786 int *rcs = cpl_calloc(kMuseNumIFUs,
sizeof(
int));
788 #pragma omp parallel for default(none) \
789 shared(outframes, params, rcs, recipe, usedframes)
790 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
796 int *rci = rcs + (nifu - 1);
797 *rci = muse_wavecal_compute(proc, pars);
798 if (rci && cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
802 #pragma omp critical(muse_processing_used_frames)
803 cpl_frameset_join(usedframes, proc->
usedFrames);
804 #pragma omp critical(muse_processing_output_frames)
810 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
811 if (rcs[nifu-1] != 0) {
817 for (params.
nifu = 1; params.
nifu <= kMuseNumIFUs && !rc; params.
nifu++) {
820 rc = muse_wavecal_compute(proc, ¶ms);
821 if (rc && cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
824 cpl_frameset_join(usedframes, proc->
usedFrames);
830 if (!cpl_errorstate_is_equal(prestate)) {
834 cpl_msg_set_level(CPL_MSG_INFO);
844 cpl_frameset_join(recipe->frames, usedframes);
845 cpl_frameset_join(recipe->frames, outframes);
846 cpl_frameset_delete(usedframes);
847 cpl_frameset_delete(outframes);
860 muse_wavecal_destroy(cpl_plugin *aPlugin)
864 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
865 recipe = (cpl_recipe *)aPlugin;
871 cpl_parameterlist_delete(recipe->parameters);
888 cpl_plugin_get_info(cpl_pluginlist *aList)
890 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
891 cpl_plugin *plugin = &recipe->interface;
895 helptext = cpl_sprintf(
"%s%s", muse_wavecal_help,
896 muse_wavecal_help_esorex);
898 helptext = cpl_sprintf(
"%s", muse_wavecal_help);
902 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
903 CPL_PLUGIN_TYPE_RECIPE,
905 "Detect arc emission lines and determine the wavelength solution, and optionally the LSF, for each slice.",
912 muse_wavecal_destroy);
913 cpl_pluginlist_append(aList, plugin);
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
double fitsigma
Sigma level for iterative rejection of deviant datapoints during the final polynomial wavelength solu...
double linesigma
Sigma level for iterative rejection of deviant fits for each arc line within each slice...
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
double ovscsigma
If the deviation of mean overscan levels between a raw input image and the reference image is higher ...
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
int ovscignore
The number of pixels of the overscan adjacent to the data region of the CCD that are ignored when com...
double dres
The allowed range of resolutions for pattern matching (of detected arc lines to line list) in fractio...
int lsf
Fit the line spread function for each slice and save the result in the output LSF_TABLE.
const char * muse_get_license(void)
Get the pipeline copyright and license.
muse_processing * muse_processing_new(const char *aRecipeName, cpl_recipe *aRecipe)
Create a new processing structure.
int nifu
IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in ...
const char * overscan
If this is "none", stop when detecting discrepant overscan levels (see ovscsigma), for "offset" it assumes that the mean overscan level represents the real offset in the bias levels of the exposures involved, and adjusts the data accordingly; for "vpoly", a polynomial is fit to the vertical overscan and subtracted from the whole quadrant.
cpl_frameset * outputFrames
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
int wavemap
Create a wavelength map of the input images.
int lampwise
Identify and measure the arc emission lines on images separately for each lamp setup.
int residuals
Create a table containing residuals of the fits to the data of all arc lines. This is useful to asses...
void muse_processinginfo_delete(cpl_recipe *)
Clear all information from the processing info and from the recipe config.
int resample
Resample the input arc images onto 2D images for a visual check using tracing and wavelength calibrat...
int yorder
Order of the polynomial used to fit the dispersion relation.
int lsf_residuals
Store the residual pixel table after the LSF fit.
cpl_error_code muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
Erase all duplicate frames from a frameset.
cpl_error_code muse_cplframeset_erase_all(cpl_frameset *aFrames)
Erase all frames in a frameset.
int fitweighting
Type of weighting to use in the final polynomial wavelength solution fit, using centroiding error est...
const char * combine_s
Type of lampwise image combination to use. (as string)
void muse_processinginfo_register(cpl_recipe *, cpl_recipeconfig *, muse_processing_prepare_header_func *, muse_processing_get_frame_level_func *, muse_processing_get_frame_mode_func *)
Register extended functionalities for MUSE recipes.
int combine
Type of lampwise image combination to use.
Structure to hold the parameters of the muse_wavecal recipe.
double tolerance
Tolerance for pattern matching (of detected arc lines to line list)
cpl_frameset * usedFrames
const char * fitweighting_s
Type of weighting to use in the final polynomial wavelength solution fit, using centroiding error est...
double sigma
Sigma level used to detect arc emission lines above the median background level in the S/N image of t...
int xorder
Order of the polynomial for the horizontal curvature within each slice.
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.