35 #include "muse_dark_z.h" 64 static const char *muse_dark_help =
65 "This recipe combines several separate dark images into one master dark file. The master dark contains the combined pixel values of the raw dark exposures, with respect to the image combination method used and normalization time specified. Processing trims the raw data and records the overscan statistics, subtracts the bias (taking account of the overscan, if --overscan is not \"none\") from each raw input image, converts them from adu to count, scales them according to their exposure time, and combines them using input parameters. Hot pixels are then identified using image statistics and marked in the data quality extension. The combined image is normalized to 1 hour exposure time. QC statistics are computed on the output master dark.";
67 static const char *muse_dark_help_esorex =
68 "\n\nInput frames for raw frame tag \"DARK\":\n" 69 "\n Frame tag Type Req #Fr Description" 70 "\n -------------------- ---- --- --- ------------" 71 "\n DARK raw Y >=3 Raw dark" 72 "\n MASTER_BIAS calib Y 1 Master bias" 73 "\n BADPIX_TABLE calib . Known bad pixels" 74 "\n\nProduct frames for raw frame tag \"DARK\":\n" 75 "\n Frame tag Level Description" 76 "\n -------------------- -------- ------------" 77 "\n MASTER_DARK final Master dark";
88 static cpl_recipeconfig *
89 muse_dark_new_recipeconfig(
void)
91 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
93 cpl_recipeconfig_set_tag(recipeconfig,
"DARK", 3, -1);
94 cpl_recipeconfig_set_input(recipeconfig,
"DARK",
"MASTER_BIAS", 1, 1);
95 cpl_recipeconfig_set_input(recipeconfig,
"DARK",
"BADPIX_TABLE", -1, -1);
96 cpl_recipeconfig_set_output(recipeconfig,
"DARK",
"MASTER_DARK");
112 static cpl_error_code
113 muse_dark_prepare_header(
const char *aFrametag, cpl_propertylist *aHeader)
115 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
116 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
117 if (!strcmp(aFrametag,
"MASTER_DARK")) {
120 "Number of saturated pixels in raw dark i in input list");
123 "Number of bad pixels determined from master dark");
126 "Median value of the master dark");
129 "Mean value of the master dark");
132 "Standard deviation of the master dark");
135 "Minimum value of the master dark");
138 "Maximum value of the master dark");
141 "[count/pix/h] Dark current measured on master dark in randomly placed windows");
144 "[count/pix/h] Dark current error measured on master dark in randomly placed windows");
147 "Number of saturated pixels in output data");
149 cpl_msg_warning(__func__,
"Frame tag %s is not defined", aFrametag);
150 return CPL_ERROR_ILLEGAL_INPUT;
152 return CPL_ERROR_NONE;
165 static cpl_frame_level
166 muse_dark_get_frame_level(
const char *aFrametag)
169 return CPL_FRAME_LEVEL_NONE;
171 if (!strcmp(aFrametag,
"MASTER_DARK")) {
172 return CPL_FRAME_LEVEL_FINAL;
174 return CPL_FRAME_LEVEL_NONE;
188 muse_dark_get_frame_mode(
const char *aFrametag)
193 if (!strcmp(aFrametag,
"MASTER_DARK")) {
211 muse_dark_create(cpl_plugin *aPlugin)
215 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
216 recipe = (cpl_recipe *)aPlugin;
224 muse_dark_new_recipeconfig(),
225 muse_dark_prepare_header,
226 muse_dark_get_frame_level,
227 muse_dark_get_frame_mode);
232 cpl_msg_set_time_on();
236 recipe->parameters = cpl_parameterlist_new();
241 p = cpl_parameter_new_range(
"muse.muse_dark.nifu",
243 "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
248 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"nifu");
249 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nifu");
251 cpl_parameterlist_append(recipe->parameters, p);
254 p = cpl_parameter_new_value(
"muse.muse_dark.overscan",
256 "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.",
258 (
const char *)
"vpoly");
259 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"overscan");
260 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"overscan");
262 cpl_parameterlist_append(recipe->parameters, p);
265 p = cpl_parameter_new_value(
"muse.muse_dark.ovscreject",
267 "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\").",
269 (
const char *)
"dcr");
270 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscreject");
271 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscreject");
273 cpl_parameterlist_append(recipe->parameters, p);
276 p = cpl_parameter_new_value(
"muse.muse_dark.ovscsigma",
278 "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\".",
281 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscsigma");
282 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscsigma");
284 cpl_parameterlist_append(recipe->parameters, p);
287 p = cpl_parameter_new_value(
"muse.muse_dark.ovscignore",
289 "The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when computing statistics or fits.",
292 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ovscignore");
293 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ovscignore");
295 cpl_parameterlist_append(recipe->parameters, p);
298 p = cpl_parameter_new_enum(
"muse.muse_dark.combine",
300 "Type of image combination to use.",
302 (
const char *)
"sigclip",
304 (
const char *)
"average",
305 (
const char *)
"median",
306 (
const char *)
"minmax",
307 (
const char *)
"sigclip");
308 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"combine");
309 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"combine");
311 cpl_parameterlist_append(recipe->parameters, p);
314 p = cpl_parameter_new_value(
"muse.muse_dark.nlow",
316 "Number of minimum pixels to reject with minmax.",
319 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"nlow");
320 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nlow");
322 cpl_parameterlist_append(recipe->parameters, p);
325 p = cpl_parameter_new_value(
"muse.muse_dark.nhigh",
327 "Number of maximum pixels to reject with minmax.",
330 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"nhigh");
331 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nhigh");
333 cpl_parameterlist_append(recipe->parameters, p);
336 p = cpl_parameter_new_value(
"muse.muse_dark.nkeep",
338 "Number of pixels to keep with minmax.",
341 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"nkeep");
342 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nkeep");
344 cpl_parameterlist_append(recipe->parameters, p);
347 p = cpl_parameter_new_value(
"muse.muse_dark.lsigma",
349 "Low sigma for pixel rejection with sigclip.",
352 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"lsigma");
353 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"lsigma");
355 cpl_parameterlist_append(recipe->parameters, p);
358 p = cpl_parameter_new_value(
"muse.muse_dark.hsigma",
360 "High sigma for pixel rejection with sigclip.",
363 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"hsigma");
364 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"hsigma");
366 cpl_parameterlist_append(recipe->parameters, p);
369 p = cpl_parameter_new_value(
"muse.muse_dark.scale",
371 "Scale the individual images to a common exposure time before combining them.",
374 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"scale");
375 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"scale");
376 if (!getenv(
"MUSE_EXPERT_USER")) {
377 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
380 cpl_parameterlist_append(recipe->parameters, p);
383 p = cpl_parameter_new_value(
"muse.muse_dark.normalize",
385 "Normalize the master dark to this exposure time (in seconds). To disable normalization, set this to a negative value.",
388 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"normalize");
389 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"normalize");
390 if (!getenv(
"MUSE_EXPERT_USER")) {
391 cpl_parameter_disable(p, CPL_PARAMETER_MODE_CLI);
394 cpl_parameterlist_append(recipe->parameters, p);
397 p = cpl_parameter_new_value(
"muse.muse_dark.hotsigma",
399 "Sigma level, in terms of median deviation above the median dark level, above which a pixel is detected and marked as 'hot'.",
402 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"hotsigma");
403 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"hotsigma");
405 cpl_parameterlist_append(recipe->parameters, p);
408 p = cpl_parameter_new_value(
"muse.muse_dark.merge",
410 "Merge output products from different IFUs into a common file.",
413 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"merge");
414 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"merge");
416 cpl_parameterlist_append(recipe->parameters, p);
436 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
437 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
440 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.nifu");
441 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
442 aParams->
nifu = cpl_parameter_get_int(p);
444 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.overscan");
445 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
446 aParams->
overscan = cpl_parameter_get_string(p);
448 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.ovscreject");
449 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
450 aParams->
ovscreject = cpl_parameter_get_string(p);
452 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.ovscsigma");
453 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
454 aParams->
ovscsigma = cpl_parameter_get_double(p);
456 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.ovscignore");
457 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
458 aParams->
ovscignore = cpl_parameter_get_int(p);
460 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.combine");
461 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
462 aParams->
combine_s = cpl_parameter_get_string(p);
464 (!strcasecmp(aParams->
combine_s,
"average")) ? MUSE_DARK_PARAM_COMBINE_AVERAGE :
465 (!strcasecmp(aParams->
combine_s,
"median")) ? MUSE_DARK_PARAM_COMBINE_MEDIAN :
466 (!strcasecmp(aParams->
combine_s,
"minmax")) ? MUSE_DARK_PARAM_COMBINE_MINMAX :
467 (!strcasecmp(aParams->
combine_s,
"sigclip")) ? MUSE_DARK_PARAM_COMBINE_SIGCLIP :
468 MUSE_DARK_PARAM_COMBINE_INVALID_VALUE;
469 cpl_ensure_code(aParams->
combine != MUSE_DARK_PARAM_COMBINE_INVALID_VALUE,
470 CPL_ERROR_ILLEGAL_INPUT);
472 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.nlow");
473 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
474 aParams->
nlow = cpl_parameter_get_int(p);
476 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.nhigh");
477 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
478 aParams->
nhigh = cpl_parameter_get_int(p);
480 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.nkeep");
481 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
482 aParams->
nkeep = cpl_parameter_get_int(p);
484 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.lsigma");
485 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
486 aParams->
lsigma = cpl_parameter_get_double(p);
488 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.hsigma");
489 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
490 aParams->
hsigma = cpl_parameter_get_double(p);
492 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.scale");
493 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
494 aParams->
scale = cpl_parameter_get_bool(p);
496 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.normalize");
497 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
498 aParams->
normalize = cpl_parameter_get_double(p);
500 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.hotsigma");
501 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
502 aParams->
hotsigma = cpl_parameter_get_double(p);
504 p = cpl_parameterlist_find(aParameters,
"muse.muse_dark.merge");
505 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
506 aParams->
merge = cpl_parameter_get_bool(p);
520 muse_dark_exec(cpl_plugin *aPlugin)
522 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
526 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
527 cpl_msg_set_threadid_on();
529 cpl_frameset *usedframes = cpl_frameset_new(),
530 *outframes = cpl_frameset_new();
532 muse_dark_params_fill(¶ms, recipe->parameters);
534 cpl_errorstate prestate = cpl_errorstate_get();
536 if (params.
nifu < -1 || params.
nifu > kMuseNumIFUs) {
537 cpl_msg_error(__func__,
"Please specify a valid IFU number (between 1 and " 538 "%d), 0 (to process all IFUs consecutively), or -1 (to " 539 "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
543 cpl_boolean donotmerge = CPL_FALSE;
545 if (params.
nifu > 0) {
548 rc = muse_dark_compute(proc, ¶ms);
549 cpl_frameset_join(usedframes, proc->
usedframes);
550 cpl_frameset_join(outframes, proc->
outframes);
552 donotmerge = CPL_TRUE;
553 }
else if (params.
nifu < 0) {
554 int *rcs = cpl_calloc(kMuseNumIFUs,
sizeof(
int));
556 #pragma omp parallel for default(none) \ 557 shared(outframes, params, rcs, recipe, usedframes) 558 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
564 int *rci = rcs + (nifu - 1);
565 *rci = muse_dark_compute(proc, pars);
566 if (rci && (
int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
570 #pragma omp critical(muse_processing_used_frames) 571 cpl_frameset_join(usedframes, proc->
usedframes);
572 #pragma omp critical(muse_processing_output_frames) 573 cpl_frameset_join(outframes, proc->
outframes);
578 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
579 if (rcs[nifu-1] != 0) {
585 for (params.
nifu = 1; params.
nifu <= kMuseNumIFUs && !rc; params.
nifu++) {
588 rc = muse_dark_compute(proc, ¶ms);
589 if (rc && (
int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
592 cpl_frameset_join(usedframes, proc->
usedframes);
593 cpl_frameset_join(outframes, proc->
outframes);
597 UNUSED_ARGUMENT(donotmerge);
599 if (!cpl_errorstate_is_equal(prestate)) {
603 cpl_msg_set_level(CPL_MSG_INFO);
610 if (params.
merge && !donotmerge) {
619 cpl_frameset_join(recipe->frames, usedframes);
620 cpl_frameset_join(recipe->frames, outframes);
621 cpl_frameset_delete(usedframes);
622 cpl_frameset_delete(outframes);
635 muse_dark_destroy(cpl_plugin *aPlugin)
639 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
640 recipe = (cpl_recipe *)aPlugin;
646 cpl_parameterlist_delete(recipe->parameters);
663 cpl_plugin_get_info(cpl_pluginlist *aList)
665 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
666 cpl_plugin *plugin = &recipe->interface;
670 helptext = cpl_sprintf(
"%s%s", muse_dark_help,
671 muse_dark_help_esorex);
673 helptext = cpl_sprintf(
"%s", muse_dark_help);
677 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
678 CPL_PLUGIN_TYPE_RECIPE,
680 "Combine several separate dark images into one master dark file and locate hot pixels.",
688 cpl_pluginlist_append(aList, plugin);
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
int ovscignore
The number of pixels of the overscan adjacent to the data section of the CCD that are ignored when co...
const char * combine_s
Type of image combination to use. (as string)
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
int scale
Scale the individual images to a common exposure time before combining them.
const char * ovscreject
This influences how values are rejected when computing overscan statistics. Either no rejection at al...
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.
double hotsigma
Sigma level, in terms of median deviation above the median dark level, above which a pixel is detecte...
int nkeep
Number of pixels to keep with minmax.
Structure to hold the parameters of the muse_dark recipe.
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.
double ovscsigma
If the deviation of mean overscan levels between a raw input image and the reference image is higher ...
int merge
Merge output products from different IFUs into a common file.
double lsigma
Low sigma for pixel rejection with sigclip.
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 combine
Type of image combination to use.
int nifu
IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in ...
double normalize
Normalize the master dark to this exposure time (in seconds). To disable normalization, set this to a negative value.
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 * 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 nlow
Number of minimum pixels to reject with minmax.
void muse_processing_recipeinfo(cpl_plugin *)
Output main pipeline configuration, inputs, and parameters.
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.
int nhigh
Number of maximum pixels to reject with minmax.
double hsigma
High sigma for pixel rejection with sigclip.
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.