34#include "kmo_priv_sky_mask.h"
35#include "kmo_priv_functions.h"
37#include "kmo_constants.h"
44static int kmo_sky_mask_create(cpl_plugin *);
45static int kmo_sky_mask_exec(cpl_plugin *);
46static int kmo_sky_mask_destroy(cpl_plugin *);
47static int kmo_sky_mask(cpl_parameterlist *, cpl_frameset *);
53static char kmo_sky_mask_description[] =
54"This recipes calculates masks of the skies surrounding the objects in the diff-\n"
55"erent IFUs of a reconstructed F3I frame. In the resulting mask pixels belonging\n"
56"to objects have value 1 and sky pixels have value 0.\n"
57"The noise and the background level of the input data cube are estimated using\n"
58"the mode calculated in kmo_stats. If the results aren't satisfactory, try chan-\n"
59"ging --cpos_rej and --cneg_rej. Then pixels are flagged in the data cube which\n"
60"have a value less than the mode plus twice the noise (val < mode + 2*sigma).\n"
61"For each spatial pixel the fraction of flagged pixels in its spectral channel\n"
63"Spatial pixels are selected where the fraction of flagged spectral pixels is\n"
64"greater than 0.95 (corresponding to the 2*sigma above).\n"
65"The input cube can contain noise extensions, but they will be ignored. The out-\n"
66"put doesn’t contain noise extensions.\n"
71"The fraction of pixels that have to be greater than the threshold can be defi-\n"
72"ned with this parameter (value must be between 0 and 1).\n"
75"If required, a limited wavelength range can be defined (e.g. \"1.8,2.1\").\n"
77"ADVANCED PARAMETERS\n"
78"-------------------\n"
82"An iterative sigma clipping is applied in order to calculate the mode (using\n"
83"kmo_stats). For each position all pixels in the spectrum are examined. If they\n"
84"deviate significantly, they will be rejected according to the conditions:\n"
85" val > mean + stdev * cpos_rej\n"
87" val < mean - stdev * cneg_rej\n"
88"In the first iteration median and percentile level are used.\n"
90"-------------------------------------------------------------------------------\n"
94" category Type Explanation Required #Frames\n"
95" -------- ----- ----------- -------- -------\n"
96" <none or any> F3I The datacube frame Y 1 \n"
101" category Type Explanation\n"
102" -------- ----- -----------\n"
103" SKY_MASK F2I The mask frame\n"
104"-------------------------------------------------------------------------------\n"
129 cpl_recipe *recipe = cpl_calloc(1,
sizeof *recipe);
130 cpl_plugin *plugin = &recipe->interface;
132 cpl_plugin_init(plugin,
135 CPL_PLUGIN_TYPE_RECIPE,
137 "Create a mask of spatial pixels that indicates which "
138 "pixels can be considered as sky.",
139 kmo_sky_mask_description,
141 "https://support.eso.org/",
145 kmo_sky_mask_destroy);
147 cpl_pluginlist_append(list, plugin);
159static int kmo_sky_mask_create(cpl_plugin *plugin)
165 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
166 recipe = (cpl_recipe *)plugin;
171 recipe->parameters = cpl_parameterlist_new();
175 p = cpl_parameter_new_value(
"kmos.kmo_sky_mask.range",
177 "Min & max wavelengths to use in sky pixel "
178 "determination, e.g. [x1_start,x1_end]"
182 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"range");
183 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
184 cpl_parameterlist_append(recipe->parameters, p);
187 p = cpl_parameter_new_value(
"kmos.kmo_sky_mask.fraction",
189 "Minimum fraction of spatial pixels to select "
190 "as sky (value between 0 and 1).",
193 cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI,
"fraction");
194 cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
195 cpl_parameterlist_append(recipe->parameters, p);
197 return kmos_combine_pars_create(recipe->parameters,
208static int kmo_sky_mask_exec(cpl_plugin *plugin)
213 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
214 recipe = (cpl_recipe *)plugin;
217 return kmo_sky_mask(recipe->parameters, recipe->frames);
225static int kmo_sky_mask_destroy(cpl_plugin *plugin)
230 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
231 recipe = (cpl_recipe *)plugin;
234 cpl_parameterlist_delete(recipe->parameters);
252static int kmo_sky_mask(cpl_parameterlist *parlist, cpl_frameset *frameset)
254 cpl_imagelist *data_in = NULL;
256 cpl_image *data_out = NULL;
258 cpl_vector *ranges = NULL;
268 double cpos_rej = 0.0,
275 const char *ranges_txt = NULL,
278 cpl_propertylist *sub_header_data = NULL;
282 cpl_frame *frame = NULL;
286 kmo_init_fits_desc(&desc);
289 KMO_TRY_ASSURE((parlist != NULL) &&
291 CPL_ERROR_NULL_INPUT,
292 "Not all input data is provided!");
294 KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1,
295 CPL_ERROR_NULL_INPUT,
296 "Exactly one data cube must be provided!");
298 KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset) == 1,
299 CPL_ERROR_ILLEGAL_INPUT,
300 "Cannot identify RAW and CALIB frames!");
302 KMO_TRY_EXIT_IF_NULL(
303 frame = kmo_dfs_get_frame(frameset,
"0"));
305 cpl_msg_info(
"",
"--- Parameter setup for kmo_sky_mask ------");
307 ranges_txt = kmo_dfs_get_parameter_string(parlist,
308 "kmos.kmo_sky_mask.range");
309 KMO_TRY_CHECK_ERROR_STATE();
310 KMO_TRY_EXIT_IF_ERROR(
311 kmo_dfs_print_parameter_help(parlist,
"kmos.kmo_shift.range"));
313 ranges = kmo_identify_ranges(ranges_txt);
314 KMO_TRY_CHECK_ERROR_STATE();
316 fraction = kmo_dfs_get_parameter_double(parlist,
317 "kmos.kmo_sky_mask.fraction");
318 KMO_TRY_CHECK_ERROR_STATE();
319 KMO_TRY_EXIT_IF_ERROR(
320 kmo_dfs_print_parameter_help(parlist,
"kmos.kmo_shift.fraction"));
322 KMO_TRY_ASSURE((fraction >= 0.0) &&
324 CPL_ERROR_ILLEGAL_INPUT,
325 "fraction must be between 0.0 and 1.0!!");
327 KMO_TRY_EXIT_IF_ERROR(
328 kmos_combine_pars_load(parlist,
338 cpl_msg_info(
"",
"-------------------------------------------");
341 desc = kmo_identify_fits_header(
342 cpl_frame_get_filename(frame));
343 KMO_TRY_CHECK_ERROR_STATE_MSG(
"Provided fits file doesn't seem to be "
346 KMO_TRY_ASSURE(desc.fits_type == f3i_fits,
347 CPL_ERROR_ILLEGAL_INPUT,
348 "The input file hasn't correct data type "
349 "(KMOSTYPE must be F3I)!");
352 KMO_TRY_EXIT_IF_ERROR(
353 kmo_dfs_save_main_header(frameset, SKY_MASK,
"", frame,
354 NULL, parlist, cpl_func));
357 if (desc.ex_noise == TRUE) {
358 nr_devices = desc.nr_ext / 2;
360 nr_devices = desc.nr_ext;
363 for (i = 1; i <= nr_devices; i++) {
364 if (desc.ex_noise == FALSE) {
365 devnr = desc.sub_desc[i - 1].device_nr;
367 devnr = desc.sub_desc[2 * i - 1].device_nr;
370 if (desc.ex_badpix == FALSE) {
371 index_data = kmo_identify_index_desc(desc, devnr, FALSE);
373 index_data = kmo_identify_index_desc(desc, devnr, 2);
375 KMO_TRY_CHECK_ERROR_STATE();
377 KMO_TRY_EXIT_IF_NULL(
378 sub_header_data = kmo_dfs_load_sub_header(frameset,
"0", devnr,
383 if (desc.sub_desc[index_data-1].valid_data == TRUE) {
389 KMO_TRY_EXIT_IF_NULL(
390 data_in = kmo_dfs_load_cube(frameset,
"0", devnr, FALSE));
392 if (ranges != NULL) {
393 ifu_crpix = cpl_propertylist_get_double(sub_header_data, CRPIX3);
394 KMO_TRY_CHECK_ERROR_STATE_MSG(
395 "CRPIX3 keyword in FITS-header is missing!");
397 ifu_crval = cpl_propertylist_get_double(sub_header_data, CRVAL3);
398 KMO_TRY_CHECK_ERROR_STATE_MSG(
399 "CRVAL3 keyword in FITS-header is missing!");
401 ifu_cdelt = cpl_propertylist_get_double(sub_header_data, CDELT3);
402 KMO_TRY_CHECK_ERROR_STATE_MSG(
403 "CDELT3 keyword in FITS-header is missing!");
406 cpl_propertylist_erase(sub_header_data, CRPIX3);
407 cpl_propertylist_erase(sub_header_data, CRVAL3);
408 cpl_propertylist_erase(sub_header_data, CDELT3);
409 cpl_propertylist_erase(sub_header_data, CTYPE3);
412 KMO_TRY_EXIT_IF_NULL(
413 data_out = kmo_calc_sky_mask(data_in,
424 KMO_TRY_EXIT_IF_ERROR(
425 kmo_dfs_save_image(data_out, SKY_MASK,
"", sub_header_data, 0.));
428 cpl_imagelist_delete(data_in); data_in = NULL;
429 cpl_image_delete(data_out); data_out = NULL;
432 KMO_TRY_EXIT_IF_ERROR(
433 kmo_dfs_save_sub_header(SKY_MASK,
"", sub_header_data));
437 cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
447 kmo_free_fits_desc(&desc);
448 cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
449 cpl_imagelist_delete(data_in); data_in = NULL;
450 cpl_image_delete(data_out); data_out = NULL;
451 cpl_vector_delete(ranges); ranges = NULL;
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.