29 #include "exam_utils.h"
45 static int _exam_flat_create(cpl_plugin *plugin);
46 static int _exam_flat_exec(cpl_plugin *plugin);
47 static int _exam_flat_destroy(cpl_plugin *plugin);
49 static void _exam_flat_define_parameters(cpl_parameterlist *parameters);
50 static int _exam_flat(cpl_frameset *frameset,
51 const cpl_parameterlist *parameters);
58 static const char *
const _exam_flat_name =
"exam_flat";
60 static const char *
const _exam_flat_description_short =
61 "Compute the master flat frame";
63 static const char *
const _exam_flat_description =
64 "This recipe is used to combine input raw FLAT frames into a"
65 " MASTER_FLAT\nframe.\n\n"
67 " DO category: Type: Explanation: Required:\n"
68 " FLAT Raw Flat frame Y\n"
69 " MASTER_BIAS Raw Master bias frame Y\n\n"
71 " DO category: Data type: Explanation:\n"
72 " MASTER_FLAT FITS image Master flat frame\n"
73 " SMOOTH_FLAT FITS image Master flat frame\n"
74 " NORM_FLAT FITS image Normalized master flat frame\n\n";
106 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
107 cpl_plugin *plugin = &recipe->interface;
109 cpl_plugin_init(plugin,
112 CPL_PLUGIN_TYPE_RECIPE,
114 _exam_flat_description_short,
115 _exam_flat_description,
123 cpl_pluginlist_append(list, plugin);
144 _exam_flat_create(cpl_plugin *plugin)
147 if (cpl_error_get_code() != CPL_ERROR_NONE) {
149 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s,"
150 "skipping recipe instantiation", cpl_func, __LINE__,
151 cpl_error_get_where());
153 return (
int)cpl_error_get_code();
157 if (plugin == NULL) {
159 cpl_msg_error(cpl_func,
"Null plugin received");
160 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
170 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) {
172 cpl_recipe *recipe = (cpl_recipe *)plugin;
179 recipe->parameters = cpl_parameterlist_new();
181 if (recipe->parameters == NULL) {
182 cpl_msg_error(cpl_func,
"Parameter list allocation failed");
183 cpl_ensure_code(0, (
int)CPL_ERROR_ILLEGAL_OUTPUT);
186 _exam_flat_define_parameters(recipe->parameters);
188 if (cpl_error_get_code() != CPL_ERROR_NONE) {
189 cpl_msg_error(cpl_func,
"Could not create %s parameters",
190 cpl_plugin_get_name(plugin));
191 cpl_ensure_code(0, (
int)CPL_ERROR_ILLEGAL_OUTPUT);
197 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
198 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
219 _exam_flat_exec(cpl_plugin *plugin)
223 cpl_recipe *recipe = (cpl_recipe *)plugin;
224 cpl_errorstate initial_errorstate = cpl_errorstate_get();
228 if (cpl_error_get_code() != CPL_ERROR_NONE) {
230 cpl_msg_error(cpl_func,
"%s():%d: An error is already set: %s,"
231 "skipping recipe execution", cpl_func, __LINE__,
232 cpl_error_get_where());
234 return (
int)cpl_error_get_code();
238 if (plugin == NULL) {
240 cpl_msg_error(cpl_func,
"Null plugin received");
241 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
251 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
253 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
254 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
263 if (recipe->parameters == NULL) {
264 cpl_msg_error(cpl_func,
"Recipe invoked with NULL parameter list");
265 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
268 if (recipe->frames == NULL) {
269 cpl_msg_error(cpl_func,
"Recipe invoked with NULL frame set");
270 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
273 recipe_status = exam_dfs_set_groups(recipe->frames);
275 if (recipe_status == CPL_ERROR_NONE) {
276 recipe_status = _exam_flat(recipe->frames, recipe->parameters);
280 if (!cpl_errorstate_is_equal(initial_errorstate)) {
283 cpl_errorstate_dump(initial_errorstate, CPL_FALSE, NULL);
286 return recipe_status;
303 _exam_flat_destroy(cpl_plugin *plugin)
306 cpl_recipe *recipe = (cpl_recipe *)plugin;
308 if (plugin == NULL) {
310 cpl_msg_error(cpl_func,
"Null plugin");
311 cpl_ensure_code(0, (
int)CPL_ERROR_NULL_INPUT);
315 if (cpl_plugin_get_type(plugin) != CPL_PLUGIN_TYPE_RECIPE) {
317 cpl_msg_error(cpl_func,
"Plugin is not a recipe");
318 cpl_ensure_code(0, (
int)CPL_ERROR_TYPE_MISMATCH);
322 cpl_parameterlist_delete(recipe->parameters);
337 _exam_flat_define_parameters(cpl_parameterlist *parameters)
341 const char *full_name = NULL;
345 name =
"stack-method";
346 full_name = cpl_sprintf(
"%s.%s.%s", PACKAGE, _exam_flat_name, name);
347 p = cpl_parameter_new_enum(full_name,
349 "Frames combination method",
352 "average",
"median",
"minmax",
"ksigma");
353 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
354 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
355 cpl_parameterlist_append(parameters, p);
356 cpl_free((
void *)full_name);
361 full_name = cpl_sprintf(
"%s.%s.minmax.%s", PACKAGE, _exam_flat_name, name);
362 p = cpl_parameter_new_value(full_name,
364 "Number of lowest values to be rejected",
367 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
368 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
369 cpl_parameterlist_append(parameters, p);
370 cpl_free((
void *)full_name);
373 full_name = cpl_sprintf(
"%s.%s.minmax.%s", PACKAGE, _exam_flat_name, name);
374 p = cpl_parameter_new_value(full_name,
376 "Number of highest values to be rejected",
379 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
380 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
381 cpl_parameterlist_append(parameters, p);
382 cpl_free((
void *)full_name);
386 full_name = cpl_sprintf(
"%s.%s.ksigma.%s", PACKAGE, _exam_flat_name, name);
387 p = cpl_parameter_new_value(full_name,
389 "Low threshold in ksigma method",
392 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
393 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
394 cpl_parameterlist_append(parameters, p);
395 cpl_free((
void *)full_name);
398 full_name = cpl_sprintf(
"%s.%s.ksigma.%s", PACKAGE, _exam_flat_name, name);
399 p = cpl_parameter_new_value(full_name,
401 "High threshold in ksigma method",
404 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
405 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
406 cpl_parameterlist_append(parameters, p);
407 cpl_free((
void *)full_name);
410 full_name = cpl_sprintf(
"%s.%s.ksigma.%s", PACKAGE, _exam_flat_name, name);
411 p = cpl_parameter_new_value(full_name,
413 "Max number of iterations in ksigma method",
416 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
417 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
418 cpl_parameterlist_append(parameters, p);
419 cpl_free((
void *)full_name);
422 full_name = cpl_sprintf(
"%s.%s.%s", PACKAGE, _exam_flat_name, name);
423 p = cpl_parameter_new_value(full_name,
425 "Saturation level (ADU)",
428 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
429 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
430 cpl_parameterlist_append(parameters, p);
431 cpl_free((
void *)full_name);
434 full_name = cpl_sprintf(
"%s.%s.%s", PACKAGE, _exam_flat_name, name);
435 p = cpl_parameter_new_value(full_name,
437 "Produce normalised flat field",
440 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
441 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
442 cpl_parameterlist_append(parameters, p);
443 cpl_free((
void *)full_name);
446 full_name = cpl_sprintf(
"%s.%s.normalise.%s", PACKAGE, _exam_flat_name, name);
447 p = cpl_parameter_new_value(full_name,
449 "X radius of smoothing box (pixel)",
452 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
453 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
454 cpl_parameterlist_append(parameters, p);
455 cpl_free((
void *)full_name);
458 full_name = cpl_sprintf(
"%s.%s.normalise.%s", PACKAGE, _exam_flat_name, name);
459 p = cpl_parameter_new_value(full_name,
461 "Y radius of smoothing box (pixel)",
464 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, name);
465 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
466 cpl_parameterlist_append(parameters, p);
467 cpl_free((
void *)full_name);
474 #define exam_flat_exit(message) \
476 if (message) cpl_msg_error(_exam_flat_name, message); \
477 cpl_image_delete(master_bias); \
478 cpl_image_delete(master_flat); \
479 cpl_image_delete(norm_flat); \
480 cpl_image_delete(smooth_flat); \
481 cpl_image_delete(flat); \
482 cpl_mask_delete(mask); \
483 cpl_propertylist_delete(qclist); \
484 cpl_propertylist_delete(header); \
502 _exam_flat(cpl_frameset *frameset,
const cpl_parameterlist *parameters)
509 const char *stack_method;
527 cpl_image *master_bias = NULL;
528 cpl_image *flat = NULL;
530 cpl_propertylist *header = NULL;
537 cpl_image *master_flat = NULL;
538 cpl_image *norm_flat = NULL;
539 cpl_image *smooth_flat = NULL;
541 cpl_propertylist *qclist = NULL;
548 cpl_mask *mask = NULL;
556 double qc_median_flat;
570 nbias = cpl_frameset_count_tags(frameset, MASTER_BIAS);
573 cpl_msg_error(_exam_flat_name,
"Missing input: %s", MASTER_BIAS);
574 exam_flat_exit(NULL);
578 cpl_msg_error(_exam_flat_name,
"Too many in input: %s", MASTER_BIAS);
579 exam_flat_exit(NULL);
582 nflats = cpl_frameset_count_tags(frameset, FLAT);
585 cpl_msg_error(_exam_flat_name,
"Missing input: %s", FLAT);
586 exam_flat_exit(NULL);
594 stack_method = exam_dfs_get_parameter_string(parameters, _exam_flat_name,
596 if (cpl_error_get_code()) {
597 exam_flat_exit(
"Failure getting the configuration parameters");
600 if (strcmp(stack_method,
"minmax") == 0) {
602 nmin = exam_dfs_get_parameter_int(parameters, _exam_flat_name,
604 nmax = exam_dfs_get_parameter_int(parameters, _exam_flat_name,
607 exam_flat_exit(
"Parameter nmin must be zero or positive");
610 exam_flat_exit(
"Parameter nmax must be zero or positive");
612 if (nflats < nmin + nmax + 1) {
613 cpl_msg_error(_exam_flat_name,
"Not enough input flats for "
614 "minmax rejection method: at least %d required",
616 exam_flat_exit(NULL);
619 else if (strcmp(stack_method,
"ksigma") == 0) {
621 klow = exam_dfs_get_parameter_double(parameters, _exam_flat_name,
623 khigh = exam_dfs_get_parameter_double(parameters, _exam_flat_name,
625 kiter = exam_dfs_get_parameter_int (parameters, _exam_flat_name,
628 exam_flat_exit(
"Parameter klow must be at least 1");
631 exam_flat_exit(
"Parameter khigh must be at least 1");
634 exam_flat_exit(
"Parameter kiter must be at least 1");
637 saturation = exam_dfs_get_parameter_double(parameters, _exam_flat_name,
639 if (saturation < 0.0) {
640 exam_flat_exit(
"Saturation level should be positive");
644 normalise = exam_dfs_get_parameter_bool(parameters, _exam_flat_name,
648 xradius = exam_dfs_get_parameter_int(parameters, _exam_flat_name,
649 "normalise.xradius");
650 yradius = exam_dfs_get_parameter_int(parameters, _exam_flat_name,
651 "normalise.yradius");
653 if (xradius < 1 || yradius < 1 || xradius > 50 || yradius > 50) {
654 exam_flat_exit(
"Invalid smoothing box radius");
657 xbox = 2*xradius + 1;
658 ybox = 2*yradius + 1;
673 if (strcmp(stack_method,
"average") == 0) {
675 cpl_msg_info(_exam_flat_name,
676 "Averaging %d flat field frames...", nflats);
678 master_flat = exam_dfs_load_image(frameset, FLAT, CPL_TYPE_FLOAT, 0);
680 if (master_flat == NULL)
681 exam_flat_exit(
"Cannot load flat field");
683 for (i = 1; i < nflats; i++) {
684 flat = exam_dfs_load_image(frameset, NULL, CPL_TYPE_FLOAT, 0);
686 cpl_image_add(master_flat, flat);
687 cpl_image_delete(flat); flat = NULL;
690 exam_flat_exit(
"Cannot load flat field");
695 cpl_image_divide_scalar(master_flat, nflats);
698 master_bias = exam_dfs_load_image(frameset, MASTER_BIAS,
701 if (master_bias == NULL) {
702 cpl_msg_error(_exam_flat_name,
"Cannot load master bias: %s",
703 cpl_error_get_message());
704 exam_flat_exit(NULL);
707 cpl_image_subtract(master_flat, master_bias);
708 cpl_image_delete(master_bias); master_bias = NULL;
710 if (cpl_error_get_code()) {
711 cpl_msg_error(_exam_flat_name,
"Cannot subtract master bias: %s",
712 cpl_error_get_message());
713 exam_flat_exit(NULL);
718 else if (strcmp(stack_method,
"median") == 0) {
719 exam_flat_exit(
"Method ksigma not yet implemented");
721 else if (strcmp(stack_method,
"minmax") == 0) {
722 exam_flat_exit(
"Method minmax not yet implemented");
724 else if (strcmp(stack_method,
"ksigma") == 0) {
725 exam_flat_exit(
"Method ksigma not yet implemented");
733 qclist = cpl_propertylist_new();
741 qc_median_flat = cpl_image_get_median(master_flat);
743 cpl_propertylist_update_double(qclist,
"ESO QC FLAT MEDIAN",
746 if (cpl_error_get_code()) {
747 exam_flat_exit(
"Cannot write QC FLAT MEDIAN to product header");
755 mask = cpl_mask_threshold_image_create(master_flat, -DBL_MAX, saturation);
758 exam_flat_exit(
"Cannot create threshold image");
762 qc_overexp_flat = cpl_mask_count(mask);
764 cpl_mask_delete(mask);
767 if (cpl_error_get_code()) {
768 exam_flat_exit(
"Cannot handle threshold mask");
771 cpl_propertylist_update_int(qclist,
"ESO QC FLAT OVEREXP NPIXEL",
774 if (cpl_error_get_code()) {
775 exam_flat_exit(
"Cannot write QC FLAT OVEREXP NPIXEL to product header");
778 cpl_propertylist_update_int(qclist,
"ESO QC FLAT OVEREXP LEVEL",
781 if (cpl_error_get_code()) {
782 exam_flat_exit(
"Cannot write QC FLAT OVEREXP LEVEL to product header");
787 mask = cpl_mask_new(xbox, ybox);
790 smooth_flat = cpl_image_new(cpl_image_get_size_x(master_flat),
791 cpl_image_get_size_y(master_flat),
792 cpl_image_get_type(master_flat));
794 cpl_image_filter_mask(smooth_flat, master_flat, mask, CPL_FILTER_MEDIAN,
797 if (cpl_error_get_code()) {
798 exam_flat_exit(
"Wrong smoothing configuration");
801 cpl_mask_delete(mask);
804 norm_flat = cpl_image_divide_create(master_flat, smooth_flat);
812 cpl_propertylist_update_string(qclist, CPL_DFS_PRO_CATG, MASTER_FLAT);
813 exam_dfs_save_image(frameset, parameters, master_flat, _exam_flat_name,
814 MASTER_FLAT, qclist, PACKAGE
"/" PACKAGE_VERSION);
816 if (cpl_error_get_code()) {
817 exam_flat_exit(
"Cannot save master flat field");
820 cpl_image_delete(master_flat);
824 cpl_propertylist_update_string(qclist, CPL_DFS_PRO_CATG, SMOOTH_FLAT);
825 exam_dfs_save_image(frameset, parameters, smooth_flat, _exam_flat_name,
826 SMOOTH_FLAT, qclist, PACKAGE
"/" PACKAGE_VERSION);
828 if (cpl_error_get_code()) {
829 exam_flat_exit(
"Cannot save smoothed flat field");
832 cpl_image_delete(smooth_flat);
835 cpl_propertylist_update_string(qclist, CPL_DFS_PRO_CATG, NORM_FLAT);
836 exam_dfs_save_image(frameset, parameters, norm_flat, _exam_flat_name,
837 NORM_FLAT, qclist, PACKAGE
"/" PACKAGE_VERSION);
839 if (cpl_error_get_code()) {
840 exam_flat_exit(
"Cannot save normalized flat field");
843 cpl_propertylist_delete(qclist);
846 cpl_image_delete(norm_flat);
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.