35 #include "muse_lingain_z.h" 76 static const char *muse_lingain_help =
77 "The recipe uses the bias and flat field images of a detector monitoring exposure sequence to determine the detector gain in counts/ADU and to model the residual non-linearity for each of the four detector quadrants of all IFUs. All measurements done by the recipe are done on the illuminated parts of the detector, i.e. on the slices. The location of the slices is taken from the given trace table, which is a mandatory input. Using the traces of the slices on the detector a set of measurement windows is placed along these traces. The data used for the determination of the gain and the residual non-linearity is the taken from these windows. Bad pixels indicated by an, optionally, provided bad pixel table, or flagged during the preprocessing (bias subtraction) of the input data are excluded from the measurements. Local measurements of the read-out-noise, the signal and the gain are calculated for each of the measurement windows. Using these measurements the gain for each detector quadrant is computed as the zero-order coefficient of a 1st order polynomial fitted to the binned gain measurements as a function of the signal level. The residual non-linearity is modelled by a (high) order polynomial which is fitted to the fractional percentage deviation of the count rate from an expected constant count rate (the linear case) as function of the signal level.";
79 static const char *muse_lingain_help_esorex =
80 "\n\nInput frames for raw frame tag \"DETMON_LAMP_OFF\":\n" 81 "\n Frame tag Type Req #Fr Description" 82 "\n -------------------- ---- --- --- ------------" 83 "\n DETMON_LAMP_OFF raw Y >=2 Detector monitoring bias images" 84 "\n DETMON_LAMP_ON raw Y >=2 Detector monitoring flat field images" 85 "\n MASTER_BIAS calib Y 1 Master bias" 86 "\n TRACE_TABLE calib Y 1 Trace table" 87 "\n BADPIX_TABLE calib . Known bad pixels" 88 "\n\nProduct frames for raw frame tag \"DETMON_LAMP_OFF\":\n" 89 "\n Frame tag Level Description" 90 "\n -------------------- -------- ------------" 91 "\n NONLINEARITY_GAIN final List of non-linearity and gain parameters for each detector readout port.";
102 static cpl_recipeconfig *
103 muse_lingain_new_recipeconfig(
void)
105 cpl_recipeconfig *recipeconfig = cpl_recipeconfig_new();
107 cpl_recipeconfig_set_tag(recipeconfig,
"DETMON_LAMP_OFF", 2, -1);
108 cpl_recipeconfig_set_input(recipeconfig,
"DETMON_LAMP_OFF",
"MASTER_BIAS", 1, 1);
109 cpl_recipeconfig_set_input(recipeconfig,
"DETMON_LAMP_OFF",
"TRACE_TABLE", 1, 1);
110 cpl_recipeconfig_set_input(recipeconfig,
"DETMON_LAMP_OFF",
"BADPIX_TABLE", -1, -1);
111 cpl_recipeconfig_set_output(recipeconfig,
"DETMON_LAMP_OFF",
"NONLINEARITY_GAIN");
112 cpl_recipeconfig_set_tag(recipeconfig,
"DETMON_LAMP_ON", 2, -1);
113 cpl_recipeconfig_set_input(recipeconfig,
"DETMON_LAMP_ON",
"MASTER_BIAS", 1, 1);
114 cpl_recipeconfig_set_input(recipeconfig,
"DETMON_LAMP_ON",
"TRACE_TABLE", 1, 1);
115 cpl_recipeconfig_set_input(recipeconfig,
"DETMON_LAMP_ON",
"BADPIX_TABLE", -1, -1);
116 cpl_recipeconfig_set_output(recipeconfig,
"DETMON_LAMP_ON",
"NONLINEARITY_GAIN");
132 static cpl_error_code
133 muse_lingain_prepare_header(
const char *aFrametag, cpl_propertylist *aHeader)
135 cpl_ensure_code(aFrametag, CPL_ERROR_NULL_INPUT);
136 cpl_ensure_code(aHeader, CPL_ERROR_NULL_INPUT);
137 if (!strcmp(aFrametag,
"NONLINEARITY_GAIN")) {
140 "RMS of the first order polynomial fit used to determine the gain.");
143 "RMS of the residual non-linearity fit.");
145 cpl_msg_warning(__func__,
"Frame tag %s is not defined", aFrametag);
146 return CPL_ERROR_ILLEGAL_INPUT;
148 return CPL_ERROR_NONE;
161 static cpl_frame_level
162 muse_lingain_get_frame_level(
const char *aFrametag)
165 return CPL_FRAME_LEVEL_NONE;
167 if (!strcmp(aFrametag,
"NONLINEARITY_GAIN")) {
168 return CPL_FRAME_LEVEL_FINAL;
170 return CPL_FRAME_LEVEL_NONE;
184 muse_lingain_get_frame_mode(
const char *aFrametag)
189 if (!strcmp(aFrametag,
"NONLINEARITY_GAIN")) {
207 muse_lingain_create(cpl_plugin *aPlugin)
211 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
212 recipe = (cpl_recipe *)aPlugin;
220 muse_lingain_new_recipeconfig(),
221 muse_lingain_prepare_header,
222 muse_lingain_get_frame_level,
223 muse_lingain_get_frame_mode);
228 cpl_msg_set_time_on();
232 recipe->parameters = cpl_parameterlist_new();
237 p = cpl_parameter_new_range(
"muse.muse_lingain.nifu",
239 "IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in parallel.",
244 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"nifu");
245 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"nifu");
247 cpl_parameterlist_append(recipe->parameters, p);
252 p = cpl_parameter_new_value(
"muse.muse_lingain.ybox",
254 "Size of windows along the traces of the slices.",
257 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ybox");
258 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ybox");
260 cpl_parameterlist_append(recipe->parameters, p);
265 p = cpl_parameter_new_value(
"muse.muse_lingain.xgap",
267 "Extra offset from tracing edge.",
270 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"xgap");
271 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"xgap");
273 cpl_parameterlist_append(recipe->parameters, p);
278 p = cpl_parameter_new_value(
"muse.muse_lingain.xborder",
280 "Extra offset from the detector edge used for the selection of slices.",
283 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"xborder");
284 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"xborder");
286 cpl_parameterlist_append(recipe->parameters, p);
291 p = cpl_parameter_new_value(
"muse.muse_lingain.order",
293 "Order of the polynomial used to fit the non-linearity residuals.",
296 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"order");
297 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"order");
299 cpl_parameterlist_append(recipe->parameters, p);
304 p = cpl_parameter_new_value(
"muse.muse_lingain.toffset",
306 "Exposure time offset in seconds to apply to linearity flat fields.",
309 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"toffset");
310 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"toffset");
312 cpl_parameterlist_append(recipe->parameters, p);
317 p = cpl_parameter_new_value(
"muse.muse_lingain.fluxtol",
319 "Tolerance value for the overall flux consistency check of a pair of flat fields. The value is the maximum relative offset.",
322 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"fluxtol");
323 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"fluxtol");
325 cpl_parameterlist_append(recipe->parameters, p);
328 p = cpl_parameter_new_value(
"muse.muse_lingain.sigma",
330 "Sigma value used for signal value clipping.",
333 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"sigma");
334 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"sigma");
336 cpl_parameterlist_append(recipe->parameters, p);
339 p = cpl_parameter_new_value(
"muse.muse_lingain.signalmin",
341 "Minimum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model.",
344 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"signalmin");
345 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"signalmin");
347 cpl_parameterlist_append(recipe->parameters, p);
350 p = cpl_parameter_new_value(
"muse.muse_lingain.signalmax",
352 "Maximum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model.",
355 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"signalmax");
356 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"signalmax");
358 cpl_parameterlist_append(recipe->parameters, p);
361 p = cpl_parameter_new_value(
"muse.muse_lingain.signalbin",
363 "Size of a signal bin in log10(ADU) used for the gain analysis and the non-linearity polynomial model.",
366 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"signalbin");
367 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"signalbin");
369 cpl_parameterlist_append(recipe->parameters, p);
372 p = cpl_parameter_new_value(
"muse.muse_lingain.gainlimit",
374 "Minimum signal value [ADU] used for fitting the gain relation.",
377 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"gainlimit");
378 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"gainlimit");
380 cpl_parameterlist_append(recipe->parameters, p);
383 p = cpl_parameter_new_value(
"muse.muse_lingain.gainsigma",
385 "Sigma value for gain value clipping.",
388 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"gainsigma");
389 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"gainsigma");
391 cpl_parameterlist_append(recipe->parameters, p);
394 p = cpl_parameter_new_value(
"muse.muse_lingain.ctsmin",
396 "Minimum signal value in log(counts) to consider for the non-linearity analysis.",
399 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ctsmin");
400 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ctsmin");
402 cpl_parameterlist_append(recipe->parameters, p);
405 p = cpl_parameter_new_value(
"muse.muse_lingain.ctsmax",
407 "Maximum signal value in log(counts) to consider for the non-linearity analysis.",
410 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ctsmax");
411 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ctsmax");
413 cpl_parameterlist_append(recipe->parameters, p);
416 p = cpl_parameter_new_value(
"muse.muse_lingain.ctsbin",
418 "Size of a signal bin in log10(counts) used for the non-linearity analysis.",
421 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"ctsbin");
422 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"ctsbin");
424 cpl_parameterlist_append(recipe->parameters, p);
427 p = cpl_parameter_new_value(
"muse.muse_lingain.linearmin",
429 "Lower limit of desired linear range in log10(counts).",
432 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"linearmin");
433 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"linearmin");
435 cpl_parameterlist_append(recipe->parameters, p);
438 p = cpl_parameter_new_value(
"muse.muse_lingain.linearmax",
440 "Upper limit of desired linear range in log10(counts).",
443 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"linearmax");
444 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"linearmax");
446 cpl_parameterlist_append(recipe->parameters, p);
449 p = cpl_parameter_new_value(
"muse.muse_lingain.merge",
451 "Merge output products from different IFUs into a common file.",
454 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CFG,
"merge");
455 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"merge");
457 cpl_parameterlist_append(recipe->parameters, p);
477 cpl_ensure_code(aParams, CPL_ERROR_NULL_INPUT);
478 cpl_ensure_code(aParameters, CPL_ERROR_NULL_INPUT);
481 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.nifu");
482 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
483 aParams->
nifu = cpl_parameter_get_int(p);
485 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.ybox");
486 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
487 aParams->
ybox = cpl_parameter_get_int(p);
489 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.xgap");
490 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
491 aParams->
xgap = cpl_parameter_get_int(p);
493 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.xborder");
494 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
495 aParams->
xborder = cpl_parameter_get_int(p);
497 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.order");
498 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
499 aParams->
order = cpl_parameter_get_int(p);
501 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.toffset");
502 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
503 aParams->
toffset = cpl_parameter_get_double(p);
505 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.fluxtol");
506 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
507 aParams->
fluxtol = cpl_parameter_get_double(p);
509 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.sigma");
510 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
511 aParams->
sigma = cpl_parameter_get_double(p);
513 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.signalmin");
514 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
515 aParams->
signalmin = cpl_parameter_get_double(p);
517 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.signalmax");
518 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
519 aParams->
signalmax = cpl_parameter_get_double(p);
521 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.signalbin");
522 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
523 aParams->
signalbin = cpl_parameter_get_double(p);
525 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.gainlimit");
526 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
527 aParams->
gainlimit = cpl_parameter_get_double(p);
529 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.gainsigma");
530 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
531 aParams->
gainsigma = cpl_parameter_get_double(p);
533 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.ctsmin");
534 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
535 aParams->
ctsmin = cpl_parameter_get_double(p);
537 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.ctsmax");
538 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
539 aParams->
ctsmax = cpl_parameter_get_double(p);
541 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.ctsbin");
542 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
543 aParams->
ctsbin = cpl_parameter_get_double(p);
545 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.linearmin");
546 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
547 aParams->
linearmin = cpl_parameter_get_double(p);
549 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.linearmax");
550 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
551 aParams->
linearmax = cpl_parameter_get_double(p);
553 p = cpl_parameterlist_find(aParameters,
"muse.muse_lingain.merge");
554 cpl_ensure_code(p, CPL_ERROR_DATA_NOT_FOUND);
555 aParams->
merge = cpl_parameter_get_bool(p);
569 muse_lingain_exec(cpl_plugin *aPlugin)
571 if (cpl_plugin_get_type(aPlugin) != CPL_PLUGIN_TYPE_RECIPE) {
575 cpl_recipe *recipe = (cpl_recipe *)aPlugin;
576 cpl_msg_set_threadid_on();
578 cpl_frameset *usedframes = cpl_frameset_new(),
579 *outframes = cpl_frameset_new();
581 muse_lingain_params_fill(¶ms, recipe->parameters);
583 cpl_errorstate prestate = cpl_errorstate_get();
585 if (params.
nifu < -1 || params.
nifu > kMuseNumIFUs) {
586 cpl_msg_error(__func__,
"Please specify a valid IFU number (between 1 and " 587 "%d), 0 (to process all IFUs consecutively), or -1 (to " 588 "process all IFUs in parallel) using --nifu.", kMuseNumIFUs);
592 cpl_boolean donotmerge = CPL_FALSE;
594 if (params.
nifu > 0) {
597 rc = muse_lingain_compute(proc, ¶ms);
598 cpl_frameset_join(usedframes, proc->
usedframes);
599 cpl_frameset_join(outframes, proc->
outframes);
601 donotmerge = CPL_TRUE;
602 }
else if (params.
nifu < 0) {
603 int *rcs = cpl_calloc(kMuseNumIFUs,
sizeof(
int));
605 #pragma omp parallel for default(none) \ 606 shared(outframes, params, rcs, recipe, usedframes) 607 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
613 int *rci = rcs + (nifu - 1);
614 *rci = muse_lingain_compute(proc, pars);
615 if (rci && (
int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
619 #pragma omp critical(muse_processing_used_frames) 620 cpl_frameset_join(usedframes, proc->
usedframes);
621 #pragma omp critical(muse_processing_output_frames) 622 cpl_frameset_join(outframes, proc->
outframes);
627 for (nifu = 1; nifu <= kMuseNumIFUs; nifu++) {
628 if (rcs[nifu-1] != 0) {
634 for (params.
nifu = 1; params.
nifu <= kMuseNumIFUs && !rc; params.
nifu++) {
637 rc = muse_lingain_compute(proc, ¶ms);
638 if (rc && (
int)cpl_error_get_code() == MUSE_ERROR_CHIP_NOT_LIVE) {
641 cpl_frameset_join(usedframes, proc->
usedframes);
642 cpl_frameset_join(outframes, proc->
outframes);
646 UNUSED_ARGUMENT(donotmerge);
648 if (!cpl_errorstate_is_equal(prestate)) {
652 cpl_msg_set_level(CPL_MSG_INFO);
659 if (params.
merge && !donotmerge) {
668 cpl_frameset_join(recipe->frames, usedframes);
669 cpl_frameset_join(recipe->frames, outframes);
670 cpl_frameset_delete(usedframes);
671 cpl_frameset_delete(outframes);
684 muse_lingain_destroy(cpl_plugin *aPlugin)
688 if (cpl_plugin_get_type(aPlugin) == CPL_PLUGIN_TYPE_RECIPE) {
689 recipe = (cpl_recipe *)aPlugin;
695 cpl_parameterlist_delete(recipe->parameters);
712 cpl_plugin_get_info(cpl_pluginlist *aList)
714 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
715 cpl_plugin *plugin = &recipe->interface;
719 helptext = cpl_sprintf(
"%s%s", muse_lingain_help,
720 muse_lingain_help_esorex);
722 helptext = cpl_sprintf(
"%s", muse_lingain_help);
726 cpl_plugin_init(plugin, CPL_PLUGIN_API, MUSE_BINARY_VERSION,
727 CPL_PLUGIN_TYPE_RECIPE,
729 "Compute the gain and a model of the residual non-linearity for each detector quadrant",
736 muse_lingain_destroy);
737 cpl_pluginlist_append(aList, plugin);
void muse_processing_delete(muse_processing *aProcessing)
Free the muse_processing structure.
int merge
Merge output products from different IFUs into a common file.
muse_cplframework_type muse_cplframework(void)
Return the CPL framework the recipe is run under.
Structure to hold the parameters of the muse_lingain recipe.
double signalmin
Minimum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model...
double linearmin
Lower limit of desired linear range in log10(counts).
double sigma
Sigma value used for signal value clipping.
int nifu
IFU to handle. If set to 0, all IFUs are processed serially. If set to -1, all IFUs are processed in ...
double signalbin
Size of a signal bin in log10(ADU) used for the gain analysis and the non-linearity polynomial model...
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 signalmax
Maximum signal value in log(ADU) used for the gain analysis and the non-linearity polynomial model...
double fluxtol
Tolerance value for the overall flux consistency check of a pair of flat fields. The value is the max...
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 order
Order of the polynomial used to fit the non-linearity residuals.
double toffset
Exposure time offset in seconds to apply to linearity flat fields.
double gainsigma
Sigma value for gain value clipping.
double linearmax
Upper limit of desired linear range in log10(counts).
double ctsmin
Minimum signal value in log(counts) to consider for the non-linearity analysis.
cpl_error_code muse_cplframeset_erase_duplicate(cpl_frameset *aFrames)
Erase all duplicate frames from a frameset.
double ctsbin
Size of a signal bin in log10(counts) used for the non-linearity analysis.
cpl_error_code muse_cplframeset_erase_all(cpl_frameset *aFrames)
Erase all frames in a frameset.
int xborder
Extra offset from the detector edge used for the selection of slices.
double ctsmax
Maximum signal value in log(counts) to consider for the non-linearity analysis.
int xgap
Extra offset from tracing edge.
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.
double gainlimit
Minimum signal value [ADU] used for fitting the gain relation.
int ybox
Size of windows along the traces of the slices.
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.
cpl_error_code muse_processing_prepare_property(cpl_propertylist *, const char *, cpl_type, const char *)
Prepare and check the specified property.