35 #include "muse_lsf_z.h" 51 static const char *muse_lsf_help =
52 "Compute the slice and wavelength dependent LSF from a lines spectrum (ARC lamp).";
54 static const char *muse_lsf_help_esorex =
55 "\n\nInput frames for raw frame tag \"ARC\":\n" 56 "\n Frame tag Type Req #Fr Description" 57 "\n -------------------- ---- --- --- ------------" 58 "\n ARC raw . Raw arc lamp exposures (from a standard arc sequence)" 59 "\n ARC_LSF raw . Raw arc lamp exposures (from a long LSF arc sequence)" 60 "\n MASTER_BIAS calib Y 1 Master bias" 61 "\n MASTER_DARK calib . 1 Master dark" 62 "\n MASTER_FLAT calib . 1 Master flat" 63 "\n TRACE_TABLE calib Y 1 Trace table" 64 "\n WAVECAL_TABLE calib Y 1 Wavelength calibration table" 65 "\n BADPIX_TABLE calib . Known bad pixels" 66 "\n LINE_CATALOG calib Y 1 Arc line catalog" 67 "\n\nProduct frames for raw frame tag \"ARC\":\n" 68 "\n Frame tag Level Description" 69 "\n -------------------- -------- ------------" 70 "\n LSF_PROFILE final Slice specific LSF images, stacked into one data cube per IFU." 71 "\n PIXTABLE_SUBTRACTED final Subtracted combined pixel table, if --save_subtracted=true. This file contains only the subtracted arc lines that contributed to the LSF calculation. There are additional columns line_lambda and line_flux with the reference wavelength and the estimated line flux of the corresponding arc line.";
82 static cpl_recipeconfig *
83 muse_lsf_new_recipeconfig(
void)
85 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
87 cpl_recipeconfig_set_tag(recipeconfig,
"ARC", -1, -1);
88 cpl_recipeconfig_set_input(recipeconfig,
"ARC",
"MASTER_BIAS", 1, 1);
89 cpl_recipeconfig_set_input(recipeconfig,
"ARC",
"MASTER_DARK", -1, 1);
90 cpl_recipeconfig_set_input(recipeconfig,
"ARC",
"MASTER_FLAT", -1, 1);
91 cpl_recipeconfig_set_input(recipeconfig,
"ARC",
"TRACE_TABLE", 1, 1);
92 cpl_recipeconfig_set_input(recipeconfig,
"ARC",
"WAVECAL_TABLE", 1, 1);
93 cpl_recipeconfig_set_input(recipeconfig,
"ARC",
"BADPIX_TABLE", -1, -1);
94 cpl_recipeconfig_set_input(recipeconfig,
"ARC",
"LINE_CATALOG", 1, 1);
95 cpl_recipeconfig_set_output(recipeconfig,
"ARC",
"LSF_PROFILE");
96 cpl_recipeconfig_set_output(recipeconfig,
"ARC",
"PIXTABLE_SUBTRACTED");
97 cpl_recipeconfig_set_tag(recipeconfig,
"ARC_LSF", -1, -1);
98 cpl_recipeconfig_set_input(recipeconfig,
"ARC_LSF",
"MASTER_BIAS", 1, 1);
99 cpl_recipeconfig_set_input(recipeconfig,
"ARC_LSF",
"MASTER_DARK", -1, 1);
100 cpl_recipeconfig_set_input(recipeconfig,
"ARC_LSF",
"MASTER_FLAT", -1, 1);
101 cpl_recipeconfig_set_input(recipeconfig,
"ARC_LSF",
"TRACE_TABLE", 1, 1);
102 cpl_recipeconfig_set_input(recipeconfig,
"ARC_LSF",
"WAVECAL_TABLE", 1, 1);
103 cpl_recipeconfig_set_input(recipeconfig,
"ARC_LSF",
"BADPIX_TABLE", -1, -1);
104 cpl_recipeconfig_set_input(recipeconfig,
"ARC_LSF",
"LINE_CATALOG", 1, 1);
105 cpl_recipeconfig_set_output(recipeconfig,
"ARC_LSF",
"LSF_PROFILE");
106 cpl_recipeconfig_set_output(recipeconfig,
"ARC_LSF",
"PIXTABLE_SUBTRACTED");
122 static cpl_error_code
123 muse_lsf_prepare_header(
const char *aFrametag, cpl_propertylist *aHeader)
125 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
126 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
127 if (!strcmp(aFrametag,
"LSF_PROFILE")) {
130 "Mean FWHM of the LSF slice j");
133 "Standard deviation of the LSF in slice j");
136 "Minimum FWHM of the LSF in slice j");
139 "Maximum FWHM of the LSF in slice j");
140 }
else if (!strcmp(aFrametag,
"PIXTABLE_SUBTRACTED")) {
142 cpl_msg_warning(__func__,
"Frame tag %s is not defined", aFrametag);
143 return CPL_ERROR_ILLEGAL_INPUT;
145 return CPL_ERROR_NONE;
158 static cpl_frame_level
159 muse_lsf_get_frame_level(
const char *aFrametag)
162 return CPL_FRAME_LEVEL_NONE;
164 if (!strcmp(aFrametag,
"LSF_PROFILE")) {
165 return CPL_FRAME_LEVEL_FINAL;
167 if (!strcmp(aFrametag,
"PIXTABLE_SUBTRACTED")) {
168 return CPL_FRAME_LEVEL_FINAL;
170 return CPL_FRAME_LEVEL_NONE;
184 muse_lsf_get_frame_mode(
const char *aFrametag)
189 if (!strcmp(aFrametag,
"LSF_PROFILE")) {
192 if (!strcmp(aFrametag,
"PIXTABLE_SUBTRACTED")) {
210 muse_lsf_create(cpl_plugin *aPlugin)
214 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
215 recipe = (cpl_recipe *)aPlugin;
223 muse_lsf_new_recipeconfig(),
224 muse_lsf_prepare_header,
225 muse_lsf_get_frame_level,
226 muse_lsf_get_frame_mode);
231 cpl_msg_set_time_on();
235 recipe->parameters = cpl_parameterlist_new();
240 p = cpl_parameter_new_range(
"muse.muse_lsf.nifu",
242 "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
247 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"nifu");
248 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nifu");
250 cpl_parameterlist_append(recipe->parameters, p);
253 p = cpl_parameter_new_value(
"muse.muse_lsf.overscan",
255 "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.",
257 (
const char *)
"vpoly");
258 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"overscan");
259 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"overscan");
261 cpl_parameterlist_append(recipe->parameters, p);
264 p = cpl_parameter_new_value(
"muse.muse_lsf.ovscreject",
266 "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\").",
268 (
const char *)
"dcr");
269 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscreject");
270 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscreject");
272 cpl_parameterlist_append(recipe->parameters, p);
275 p = cpl_parameter_new_value(
"muse.muse_lsf.ovscsigma",
277 "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 (the level comparison is then done afterwards with |100 x stdev| to guard against incompatible settings). Has no effect for overscan=\"offset\".",
280 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscsigma");
281 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscsigma");
283 cpl_parameterlist_append(recipe->parameters, p);
286 p = cpl_parameter_new_value(
"muse.muse_lsf.ovscignore",
288 "The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits.",
291 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscignore");
292 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscignore");
294 cpl_parameterlist_append(recipe->parameters, p);
297 p = cpl_parameter_new_value(
"muse.muse_lsf.save_subtracted",
299 "Save the pixel table after the LSF subtraction.",
302 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"save_subtracted");
303 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"save_subtracted");
305 cpl_parameterlist_append(recipe->parameters, p);
308 p = cpl_parameter_new_value(
"muse.muse_lsf.line_quality",
310 "Minimal quality flag in line catalog for selection",
313 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"line_quality");
314 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"line_quality");
316 cpl_parameterlist_append(recipe->parameters, p);
319 p = cpl_parameter_new_value(
"muse.muse_lsf.lsf_range",
321 "Wavelength window (half size) around each line to estimate LSF",
324 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lsf_range");
325 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lsf_range");
327 cpl_parameterlist_append(recipe->parameters, p);
330 p = cpl_parameter_new_value(
"muse.muse_lsf.lsf_size",
332 "Image size in LSF direction",
335 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lsf_size");
336 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lsf_size");
338 cpl_parameterlist_append(recipe->parameters, p);
341 p = cpl_parameter_new_value(
"muse.muse_lsf.lambda_size",
343 "Image size in line wavelength direction",
346 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lambda_size");
347 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lambda_size");
349 cpl_parameterlist_append(recipe->parameters, p);
352 p = cpl_parameter_new_value(
"muse.muse_lsf.lsf_regression_window",
354 "Size of the regression window in LSF direction",
357 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lsf_regression_window");
358 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lsf_regression_window");
360 cpl_parameterlist_append(recipe->parameters, p);
363 p = cpl_parameter_new_value(
"muse.muse_lsf.merge",
365 "Merge output products from different IFUs into a common file.",
368 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"merge");
369 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"merge");
371 cpl_parameterlist_append(recipe->parameters, p);
374 p = cpl_parameter_new_enum(
"muse.muse_lsf.combine",
376 "Type of lampwise image combination to use.",
378 (
const char *)
"sigclip",
380 (
const char *)
"average",
381 (
const char *)
"median",
382 (
const char *)
"minmax",
383 (
const char *)
"sigclip");
384 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"combine");
385 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"combine");
387 cpl_parameterlist_append(recipe->parameters, p);
390 p = cpl_parameter_new_enum(
"muse.muse_lsf.method",
392 "LSF generation method. Depending on this value, either an interpolated LSF cube is created, or a table with the parameters of a hermitean gaussian.",
394 (
const char *)
"interpolate",
396 (
const char *)
"interpolate",
397 (
const char *)
"hermit");
398 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"method");
399 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"method");
401 cpl_parameterlist_append(recipe->parameters, p);
421 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
422 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
425 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.nifu");
426 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
427 aParams->
nifu = cpl_parameter_get_int(p);
429 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.overscan");
430 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
431 aParams->
overscan = cpl_parameter_get_string(p);
433 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.ovscreject");
434 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
435 aParams->
ovscreject = cpl_parameter_get_string(p);
437 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.ovscsigma");
438 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
439 aParams->
ovscsigma = cpl_parameter_get_double(p);
441 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.ovscignore");
442 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
443 aParams->
ovscignore = cpl_parameter_get_int(p);
445 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.save_subtracted");
446 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
449 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.line_quality");
450 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
453 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.lsf_range");
454 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
455 aParams->
lsf_range = cpl_parameter_get_double(p);
457 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.lsf_size");
458 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
459 aParams->
lsf_size = cpl_parameter_get_int(p);
461 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.lambda_size");
462 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
465 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.lsf_regression_window");
466 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
469 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.merge");
470 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
471 aParams->
merge = cpl_parameter_get_bool(p);
473 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.combine");
474 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
475 aParams->
combine_s = cpl_parameter_get_string(p);
477 (!strcasecmp(aParams->
combine_s,
"average")) ? MUSE_LSF_PARAM_COMBINE_AVERAGE :
478 (!strcasecmp(aParams->
combine_s,
"median")) ? MUSE_LSF_PARAM_COMBINE_MEDIAN :
479 (!strcasecmp(aParams->
combine_s,
"minmax")) ? MUSE_LSF_PARAM_COMBINE_MINMAX :
480 (!strcasecmp(aParams->
combine_s,
"sigclip")) ? MUSE_LSF_PARAM_COMBINE_SIGCLIP :
481 MUSE_LSF_PARAM_COMBINE_INVALID_VALUE;
482 cpl_ensure_code(aParams->
combine != MUSE_LSF_PARAM_COMBINE_INVALID_VALUE,
483 CPL_ERROR_ILLEGAL_INPUT);
485 p = cpl_parameterlist_find(aParameters,
"muse.muse_lsf.method");
486 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
487 aParams->
method_s = cpl_parameter_get_string(p);
489 (!strcasecmp(aParams->
method_s,
"interpolate")) ? MUSE_LSF_PARAM_METHOD_INTERPOLATE :
490 (!strcasecmp(aParams->
method_s,
"hermit")) ? MUSE_LSF_PARAM_METHOD_HERMIT :
491 MUSE_LSF_PARAM_METHOD_INVALID_VALUE;
492 cpl_ensure_code(aParams->
method != MUSE_LSF_PARAM_METHOD_INVALID_VALUE,
493 CPL_ERROR_ILLEGAL_INPUT);
507 muse_lsf_exec(cpl_plugin *aPlugin)
509 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
513 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
514 cpl_msg_set_threadid_on();
516 cpl_frameset *usedframes = cpl_frameset_new(),
517 *outframes = cpl_frameset_new();
519 muse_lsf_params_fill(¶ms, recipe->parameters);
521 cpl_errorstate prestate = cpl_errorstate_get();
523 if (params.
nifu < -1 || params.
nifu > kMuseNumIFUs) {
524 cpl_msg_error(__func__,
"Please specify a valid IFU number (between 1 and " 525 "%d), 0 (to process all IFUs consecutively), or -1 (to " 526 "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
530 cpl_boolean donotmerge = CPL_FALSE;
532 if (params.
nifu > 0) {
535 rc = muse_lsf_compute(proc, ¶ms);
536 cpl_frameset_join(usedframes, proc->
usedframes);
537 cpl_frameset_join(outframes, proc->
outframes);
539 donotmerge = CPL_TRUE;
540 }
else if (params.
nifu < 0) {
541 int *rcs = cpl_calloc(kMuseNumIFUs,
sizeof(
int));
543 #pragma omp parallel for default(none) \ 544 shared(outframes, params, rcs, recipe, usedframes) 545 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
551 int *rci = rcs + (nifu - 1);
552 *rci = muse_lsf_compute(proc, pars);
553 if (rci && (
int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
557 #pragma omp critical(muse_processing_used_frames) 558 cpl_frameset_join(usedframes, proc->
usedframes);
559 #pragma omp critical(muse_processing_output_frames) 560 cpl_frameset_join(outframes, proc->
outframes);
565 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
566 if (rcs[nifu-1] != 0) {
572 for (params.
nifu = 1; params.
nifu <= kMuseNumIFUs && !rc; params.
nifu++) {
575 rc = muse_lsf_compute(proc, ¶ms);
576 if (rc && (
int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
579 cpl_frameset_join(usedframes, proc->
usedframes);
580 cpl_frameset_join(outframes, proc->
outframes);
584 UNUSED_ARGUMENT(donotmerge);
586 if (!cpl_errorstate_is_equal(prestate)) {
590 cpl_msg_set_level(CPL_MSG_INFO);
597 if (params.
merge && !donotmerge) {
606 cpl_frameset_join(recipe->frames, usedframes);
607 cpl_frameset_join(recipe->frames, outframes);
608 cpl_frameset_delete(usedframes);
609 cpl_frameset_delete(outframes);
622 muse_lsf_destroy(cpl_plugin *aPlugin)
626 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
627 recipe = (cpl_recipe *)aPlugin;
633 cpl_parameterlist_delete(recipe->parameters);
650 cpl_plugin_get_info(cpl_pluginlist *aList)
652 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
653 cpl_plugin *plugin = &recipe->interface;
657 helptext = cpl_sprintf(
"%s%s", muse_lsf_help,
658 muse_lsf_help_esorex);
660 helptext = cpl_sprintf(
"%s", muse_lsf_help);
664 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
665 CPL_PLUGIN_TYPE_RECIPE,
675 cpl_pluginlist_append(aList, plugin);
int method
LSF generation method. Depending on this value, either an interpolated LSF cube is created...
int lambda_size
Image size in line wavelength direction.
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
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.
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
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.
int save_subtracted
Save the pixel table after the LSF subtraction.
int merge
Merge output products from different IFUs into a common file.
int ovscignore
The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when co...
cpl_frameset * usedframes
muse_processing * muse_processing_new(const char *aName, cpl_recipe *aRecipe)
Create a new processing structure.
const char * muse_get_license(void)
Get the pipeline copyright and license.
int lsf_size
Image size in LSF direction.
const char * combine_s
Type of lampwise image combination to use. (as string)
Structure to hold the parameters of the muse_lsf recipe.
int line_quality
Minimal quality flag in line catalog for selection.
void muse_cplerrorstate_dump_some(unsigned aCurrent, unsigned aFirst, unsigned aLast)
Dump some CPL errors.
void muse_processinginfo_delete(cpl_recipe *)
Clear all information from the processing info and from the recipe config.
int combine
Type of lampwise image combination to use.
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.
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.
const char * method_s
LSF generation method. Depending on this value, either an interpolated LSF cube is created...
void muse_processing_recipeinfo(cpl_plugin *)
Output main pipeline configuration, inputs, and parameters.
double lsf_range
Wavelength window (half size) around each line to estimate LSF.
cpl_error_code muse_utils_frameset_merge_frames(cpl_frameset *aFrames, cpl_boolean aDelete)
Merge IFU-specific files from a frameset to create multi-IFU outputs.
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.
double lsf_regression_window
Size of the regression window in LSF direction.