KMOS Pipeline Reference Manual 4.5.10
kmo_sky_mask.c
1/*
2 * This file is part of the KMOS Pipeline
3 * Copyright (C) 2002,2003 European Southern Observatory
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24/*-----------------------------------------------------------------------------
25 * Includes
26 *----------------------------------------------------------------------------*/
27
28#include <string.h>
29
30#include <cpl.h>
31
32#include "kmo_utils.h"
33#include "kmo_dfs.h"
34#include "kmo_priv_sky_mask.h"
35#include "kmo_priv_functions.h"
36#include "kmo_error.h"
37#include "kmo_constants.h"
38#include "kmo_debug.h"
39
40/*-----------------------------------------------------------------------------
41 * Functions prototypes
42 *----------------------------------------------------------------------------*/
43
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 *);
48
49/*-----------------------------------------------------------------------------
50 * Static variables
51 *----------------------------------------------------------------------------*/
52
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"
62"is determined.\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"
67"\n"
68"BASIC PARAMETERS:\n"
69"-----------------\n"
70"--fraction\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"
73"\n"
74"--range\n"
75"If required, a limited wavelength range can be defined (e.g. \"1.8,2.1\").\n"
76"\n"
77"ADVANCED PARAMETERS\n"
78"-------------------\n"
79"--cpos_rej\n"
80"--cneg_rej\n"
81"--citer\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"
86" and\n"
87" val < mean - stdev * cneg_rej\n"
88"In the first iteration median and percentile level are used.\n"
89"\n"
90"-------------------------------------------------------------------------------\n"
91" Input files:\n"
92"\n"
93" DO KMOS \n"
94" category Type Explanation Required #Frames\n"
95" -------- ----- ----------- -------- -------\n"
96" <none or any> F3I The datacube frame Y 1 \n"
97"\n"
98" Output files:\n"
99"\n"
100" DO KMOS\n"
101" category Type Explanation\n"
102" -------- ----- -----------\n"
103" SKY_MASK F2I The mask frame\n"
104"-------------------------------------------------------------------------------\n"
105"\n";
106
107/*-----------------------------------------------------------------------------
108 * Functions code
109 *----------------------------------------------------------------------------*/
110
127int cpl_plugin_get_info(cpl_pluginlist *list)
128{
129 cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
130 cpl_plugin *plugin = &recipe->interface;
131
132 cpl_plugin_init(plugin,
133 CPL_PLUGIN_API,
134 KMOS_BINARY_VERSION,
135 CPL_PLUGIN_TYPE_RECIPE,
136 "kmo_sky_mask",
137 "Create a mask of spatial pixels that indicates which "
138 "pixels can be considered as sky.",
139 kmo_sky_mask_description,
140 "Alex Agudo Berbel",
141 "https://support.eso.org/",
142 kmos_get_license(),
143 kmo_sky_mask_create,
144 kmo_sky_mask_exec,
145 kmo_sky_mask_destroy);
146
147 cpl_pluginlist_append(list, plugin);
148
149 return 0;
150}
151
159static int kmo_sky_mask_create(cpl_plugin *plugin)
160{
161 cpl_recipe *recipe;
162 cpl_parameter *p;
163
164 /* Check that the plugin is part of a valid recipe */
165 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
166 recipe = (cpl_recipe *)plugin;
167 else
168 return -1;
169
170 /* Create the parameters list in the cpl_recipe object */
171 recipe->parameters = cpl_parameterlist_new();
172
173 /* Fill the parameters list */
174 /* --range */
175 p = cpl_parameter_new_value("kmos.kmo_sky_mask.range",
176 CPL_TYPE_STRING,
177 "Min & max wavelengths to use in sky pixel "
178 "determination, e.g. [x1_start,x1_end]"
179 " (microns).",
180 "kmos.kmo_sky_mask",
181 "");
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);
185
186 /* --fraction */
187 p = cpl_parameter_new_value("kmos.kmo_sky_mask.fraction",
188 CPL_TYPE_DOUBLE,
189 "Minimum fraction of spatial pixels to select "
190 "as sky (value between 0 and 1).",
191 "kmos.kmo_sky_mask",
192 0.95);
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);
196
197 return kmos_combine_pars_create(recipe->parameters,
198 "kmos.kmo_sky_mask",
199 DEF_REJ_METHOD,
200 TRUE);
201}
202
208static int kmo_sky_mask_exec(cpl_plugin *plugin)
209{
210 cpl_recipe *recipe;
211
212 /* Get the recipe out of the plugin */
213 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
214 recipe = (cpl_recipe *)plugin;
215 else return -1;
216
217 return kmo_sky_mask(recipe->parameters, recipe->frames);
218}
219
225static int kmo_sky_mask_destroy(cpl_plugin *plugin)
226{
227 cpl_recipe *recipe;
228
229 /* Get the recipe out of the plugin */
230 if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE)
231 recipe = (cpl_recipe *)plugin;
232 else return -1 ;
233
234 cpl_parameterlist_delete(recipe->parameters);
235 return 0 ;
236}
237
252static int kmo_sky_mask(cpl_parameterlist *parlist, cpl_frameset *frameset)
253{
254 cpl_imagelist *data_in = NULL;
255
256 cpl_image *data_out = NULL;
257
258 cpl_vector *ranges = NULL;
259
260 int ret_val = 0,
261 nr_devices = 0,
262 i = 0,
263 valid_ifu = FALSE,
264 citer = 0,
265 devnr = 0,
266 index_data = 0;
267
268 double cpos_rej = 0.0,
269 cneg_rej = 0.0,
270 fraction = 0.0,
271 ifu_crpix = 0.0,
272 ifu_crval = 0.0,
273 ifu_cdelt = 0.0;
274
275 const char *ranges_txt = NULL,
276 *cmethod = NULL;
277
278 cpl_propertylist *sub_header_data = NULL;
279
280 main_fits_desc desc;
281
282 cpl_frame *frame = NULL;
283
284 KMO_TRY
285 {
286 kmo_init_fits_desc(&desc);
287
288 // --- check input ---
289 KMO_TRY_ASSURE((parlist != NULL) &&
290 (frameset != NULL),
291 CPL_ERROR_NULL_INPUT,
292 "Not all input data is provided!");
293
294 KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1,
295 CPL_ERROR_NULL_INPUT,
296 "Exactly one data cube must be provided!");
297
298 KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset) == 1,
299 CPL_ERROR_ILLEGAL_INPUT,
300 "Cannot identify RAW and CALIB frames!");
301
302 KMO_TRY_EXIT_IF_NULL(
303 frame = kmo_dfs_get_frame(frameset, "0"));
304
305 cpl_msg_info("", "--- Parameter setup for kmo_sky_mask ------");
306
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"));
312
313 ranges = kmo_identify_ranges(ranges_txt);
314 KMO_TRY_CHECK_ERROR_STATE();
315
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"));
321
322 KMO_TRY_ASSURE((fraction >= 0.0) &&
323 (fraction <= 1.0),
324 CPL_ERROR_ILLEGAL_INPUT,
325 "fraction must be between 0.0 and 1.0!!");
326
327 KMO_TRY_EXIT_IF_ERROR(
328 kmos_combine_pars_load(parlist,
329 "kmos.kmo_sky_mask",
330 &cmethod,
331 &cpos_rej,
332 &cneg_rej,
333 &citer,
334 NULL,
335 NULL,
336 TRUE));
337
338 cpl_msg_info("", "-------------------------------------------");
339
340 // load descriptor, header and data of first operand
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 "
344 "in KMOS-format!");
345
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)!");
350
351 // --- load, update & save primary header ---
352 KMO_TRY_EXIT_IF_ERROR(
353 kmo_dfs_save_main_header(frameset, SKY_MASK, "", frame,
354 NULL, parlist, cpl_func));
355
356 // --- load data ---
357 if (desc.ex_noise == TRUE) {
358 nr_devices = desc.nr_ext / 2;
359 } else {
360 nr_devices = desc.nr_ext;
361 }
362
363 for (i = 1; i <= nr_devices; i++) {
364 if (desc.ex_noise == FALSE) {
365 devnr = desc.sub_desc[i - 1].device_nr;
366 } else {
367 devnr = desc.sub_desc[2 * i - 1].device_nr;
368 }
369
370 if (desc.ex_badpix == FALSE) {
371 index_data = kmo_identify_index_desc(desc, devnr, FALSE);
372 } else {
373 index_data = kmo_identify_index_desc(desc, devnr, 2);
374 }
375 KMO_TRY_CHECK_ERROR_STATE();
376
377 KMO_TRY_EXIT_IF_NULL(
378 sub_header_data = kmo_dfs_load_sub_header(frameset, "0", devnr,
379 FALSE));
380
381 // check if IFU is valid
382 valid_ifu = FALSE;
383 if (desc.sub_desc[index_data-1].valid_data == TRUE) {
384 valid_ifu = TRUE;
385 }
386
387 if (valid_ifu) {
388 // load data
389 KMO_TRY_EXIT_IF_NULL(
390 data_in = kmo_dfs_load_cube(frameset, "0", devnr, FALSE));
391
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!");
396
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!");
400
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!");
404 }
405
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);
410
411 // calc mode and noise
412 KMO_TRY_EXIT_IF_NULL(
413 data_out = kmo_calc_sky_mask(data_in,
414 ranges,
415 fraction,
416 ifu_crpix,
417 ifu_crval,
418 ifu_cdelt,
419 cpos_rej,
420 cneg_rej,
421 citer));
422
423 // save data
424 KMO_TRY_EXIT_IF_ERROR(
425 kmo_dfs_save_image(data_out, SKY_MASK, "", sub_header_data, 0.));
426
427 // free memory
428 cpl_imagelist_delete(data_in); data_in = NULL;
429 cpl_image_delete(data_out); data_out = NULL;
430 } else {
431 // invalid IFU, just save sub_headers
432 KMO_TRY_EXIT_IF_ERROR(
433 kmo_dfs_save_sub_header(SKY_MASK, "", sub_header_data));
434 }
435
436 // free memory
437 cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
438 }
439 }
440 KMO_CATCH
441 {
442 KMO_CATCH_MSG();
443
444 ret_val = -1;
445 }
446
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;
452 return ret_val;
453}
454
int cpl_plugin_get_info(cpl_pluginlist *list)
Build the list of available plugins, for this module.
Definition: kmo_sky_mask.c:127