KMOS Pipeline Reference Manual  1.3.11
kmo_sky_mask.c
00001 /*
00002  * This file is part of the KMOS Pipeline
00003  * Copyright (C) 2002,2003 European Southern Observatory
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 /*-----------------------------------------------------------------------------
00025  *                              Includes
00026  *----------------------------------------------------------------------------*/
00027 
00028 #include <string.h>
00029 
00030 #include <cpl.h>
00031 
00032 #include "kmo_utils.h"
00033 #include "kmo_dfs.h"
00034 #include "kmo_priv_sky_mask.h"
00035 #include "kmo_priv_functions.h"
00036 #include "kmo_error.h"
00037 #include "kmo_constants.h"
00038 #include "kmo_debug.h"
00039 
00040 /*-----------------------------------------------------------------------------
00041  *                          Functions prototypes
00042  *----------------------------------------------------------------------------*/
00043 
00044 static int kmo_sky_mask_create(cpl_plugin *);
00045 static int kmo_sky_mask_exec(cpl_plugin *);
00046 static int kmo_sky_mask_destroy(cpl_plugin *);
00047 static int kmo_sky_mask(cpl_parameterlist *, cpl_frameset *);
00048 
00049 /*-----------------------------------------------------------------------------
00050  *                          Static variables
00051  *----------------------------------------------------------------------------*/
00052 
00053 static char kmo_sky_mask_description[] =
00054 "This recipes calculates masks of the skies surrounding the objects in the diff-\n"
00055 "erent IFUs of a reconstructed F3I frame. In the resulting mask pixels belonging\n"
00056 "to objects have value 1 and sky pixels have value 0.\n"
00057 "The noise and the background level of the input data cube are estimated using\n"
00058 "the mode calculated in kmo_stats. If the results aren't satisfactory, try chan-\n"
00059 "ging --cpos_rej and --cneg_rej. Then pixels are flagged in the data cube which\n"
00060 "have a value less than the mode plus twice the noise (val < mode + 2*sigma).\n"
00061 "For each spatial pixel the fraction of flagged pixels in its spectral channel\n"
00062 "is determined.\n"
00063 "Spatial pixels are selected where the fraction of flagged spectral pixels is\n"
00064 "greater than 0.95 (corresponding to the 2*sigma above).\n"
00065 "The input cube can contain noise extensions, but they will be ignored. The out-\n"
00066 "put doesn’t contain noise extensions.\n"
00067 "\n"
00068 "BASIC PARAMETERS:\n"
00069 "-----------------\n"
00070 "--fraction\n"
00071 "The fraction of pixels that have to be greater than the threshold can be defi-\n"
00072 "ned with this parameter (value must be between 0 and 1).\n"
00073 "\n"
00074 "--range\n"
00075 "If required, a limited wavelength range can be defined (e.g. \"1.8,2.1\").\n"
00076 "\n"
00077 "ADVANCED PARAMETERS\n"
00078 "-------------------\n"
00079 "--cpos_rej\n"
00080 "--cneg_rej\n"
00081 "--citer\n"
00082 "An iterative sigma clipping is applied in order to calculate the mode (using\n"
00083 "kmo_stats). For each position all pixels in the spectrum are examined. If they\n"
00084 "deviate significantly, they will be rejected according to the conditions:\n"
00085 "       val > mean + stdev * cpos_rej\n"
00086 "   and\n"
00087 "       val < mean - stdev * cneg_rej\n"
00088 "In the first iteration median and percentile level are used.\n"
00089 "\n"
00090 "-------------------------------------------------------------------------------\n"
00091 "  Input files:\n"
00092 "\n"
00093 "   DO                    KMOS                                                  \n"
00094 "   category              Type   Explanation                    Required #Frames\n"
00095 "   --------              -----  -----------                    -------- -------\n"
00096 "   <none or any>         F3I    The datacube frame                 Y       1   \n"
00097 "\n"
00098 "  Output files:\n"
00099 "\n"
00100 "   DO                    KMOS\n"
00101 "   category              Type   Explanation\n"
00102 "   --------              -----  -----------\n"
00103 "   SKY_MASK              F2I    The mask frame\n"
00104 "-------------------------------------------------------------------------------\n"
00105 "\n";
00106 
00107 /*-----------------------------------------------------------------------------
00108  *                              Functions code
00109  *----------------------------------------------------------------------------*/
00110 
00127 int cpl_plugin_get_info(cpl_pluginlist *list)
00128 {
00129     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00130     cpl_plugin *plugin = &recipe->interface;
00131 
00132     cpl_plugin_init(plugin,
00133                         CPL_PLUGIN_API,
00134                         KMOS_BINARY_VERSION,
00135                         CPL_PLUGIN_TYPE_RECIPE,
00136                         "kmo_sky_mask",
00137                         "Create a mask of spatial pixels that indicates which "
00138                         "pixels can be considered as sky.",
00139                         kmo_sky_mask_description,
00140                         "Alex Agudo Berbel",
00141                         "usd-help@eso.org",
00142                         kmos_get_license(),
00143                         kmo_sky_mask_create,
00144                         kmo_sky_mask_exec,
00145                         kmo_sky_mask_destroy);
00146 
00147     cpl_pluginlist_append(list, plugin);
00148 
00149     return 0;
00150 }
00151 
00159 static int kmo_sky_mask_create(cpl_plugin *plugin)
00160 {
00161     cpl_recipe *recipe;
00162     cpl_parameter *p;
00163 
00164     /* Check that the plugin is part of a valid recipe */
00165     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00166         recipe = (cpl_recipe *)plugin;
00167     else
00168         return -1;
00169 
00170     /* Create the parameters list in the cpl_recipe object */
00171     recipe->parameters = cpl_parameterlist_new();
00172 
00173     /* Fill the parameters list */
00174     /* --range */
00175     p = cpl_parameter_new_value("kmos.kmo_sky_mask.range",
00176                                 CPL_TYPE_STRING,
00177                                 "Min & max wavelengths to use in sky pixel "
00178                                     "determination, e.g. [x1_start,x1_end]"
00179                                     " (microns).",
00180                                 "kmos.kmo_sky_mask",
00181                                 "");
00182     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "range");
00183     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00184     cpl_parameterlist_append(recipe->parameters, p);
00185 
00186     /* --fraction */
00187     p = cpl_parameter_new_value("kmos.kmo_sky_mask.fraction",
00188                                 CPL_TYPE_DOUBLE,
00189                                 "Minimum fraction of spatial pixels to select "
00190                                 "as sky (value between 0 and 1).",
00191                                 "kmos.kmo_sky_mask",
00192                                 0.95);
00193     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fraction");
00194     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00195     cpl_parameterlist_append(recipe->parameters, p);
00196 
00197     return kmos_combine_pars_create(recipe->parameters,
00198                                    "kmos.kmo_sky_mask",
00199                                    DEF_REJ_METHOD,
00200                                    TRUE);
00201 }
00202 
00208 static int kmo_sky_mask_exec(cpl_plugin *plugin)
00209 {
00210     cpl_recipe  *recipe;
00211 
00212     /* Get the recipe out of the plugin */
00213     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00214         recipe = (cpl_recipe *)plugin;
00215     else return -1;
00216 
00217     return kmo_sky_mask(recipe->parameters, recipe->frames);
00218 }
00219 
00225 static int kmo_sky_mask_destroy(cpl_plugin *plugin)
00226 {
00227     cpl_recipe *recipe;
00228 
00229     /* Get the recipe out of the plugin */
00230     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00231         recipe = (cpl_recipe *)plugin;
00232     else return -1 ;
00233 
00234     cpl_parameterlist_delete(recipe->parameters);
00235     return 0 ;
00236 }
00237 
00252 static int kmo_sky_mask(cpl_parameterlist *parlist, cpl_frameset *frameset)
00253 {
00254     cpl_imagelist    *data_in            = NULL;
00255 
00256     cpl_image        *data_out           = NULL;
00257 
00258     cpl_vector       *ranges             = NULL;
00259 
00260     int              ret_val             = 0,
00261                      nr_devices          = 0,
00262                      i                   = 0,
00263                      valid_ifu           = FALSE,
00264                      citer               = 0,
00265                      devnr               = 0,
00266                      index_data          = 0;
00267 
00268     double           cpos_rej            = 0.0,
00269                      cneg_rej            = 0.0,
00270                      fraction            = 0.0,
00271                      ifu_crpix           = 0.0,
00272                      ifu_crval           = 0.0,
00273                      ifu_cdelt           = 0.0;
00274 
00275     const char       *ranges_txt         = NULL,
00276                      *cmethod            = NULL;
00277 
00278     cpl_propertylist *sub_header_data    = NULL;
00279 
00280     main_fits_desc   desc;
00281 
00282     cpl_frame        *frame              = NULL;
00283 
00284     KMO_TRY
00285     {
00286         kmo_init_fits_desc(&desc);
00287 
00288         // --- check input ---
00289         KMO_TRY_ASSURE((parlist != NULL) &&
00290                        (frameset != NULL),
00291                        CPL_ERROR_NULL_INPUT,
00292                        "Not all input data is provided!");
00293 
00294         KMO_TRY_ASSURE(cpl_frameset_get_size(frameset) == 1,
00295                        CPL_ERROR_NULL_INPUT,
00296                        "Exactly one data cube must be provided!");
00297 
00298         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_sky_mask") == 1,
00299                        CPL_ERROR_ILLEGAL_INPUT,
00300                        "Cannot identify RAW and CALIB frames!");
00301 
00302         KMO_TRY_EXIT_IF_NULL(
00303             frame = kmo_dfs_get_frame(frameset, "0"));
00304 
00305         cpl_msg_info("", "--- Parameter setup for kmo_sky_mask ------");
00306 
00307         ranges_txt = kmo_dfs_get_parameter_string(parlist,
00308                                                   "kmos.kmo_sky_mask.range");
00309         KMO_TRY_CHECK_ERROR_STATE();
00310         KMO_TRY_EXIT_IF_ERROR(
00311             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.range"));
00312 
00313         ranges = kmo_identify_ranges(ranges_txt);
00314         KMO_TRY_CHECK_ERROR_STATE();
00315 
00316         fraction = kmo_dfs_get_parameter_double(parlist,
00317                                            "kmos.kmo_sky_mask.fraction");
00318         KMO_TRY_CHECK_ERROR_STATE();
00319         KMO_TRY_EXIT_IF_ERROR(
00320             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_shift.fraction"));
00321 
00322         KMO_TRY_ASSURE((fraction >= 0.0) &&
00323                        (fraction <= 1.0),
00324                        CPL_ERROR_ILLEGAL_INPUT,
00325                        "fraction must be between 0.0 and 1.0!!");
00326 
00327         KMO_TRY_EXIT_IF_ERROR(
00328             kmos_combine_pars_load(parlist,
00329                                   "kmos.kmo_sky_mask",
00330                                   &cmethod,
00331                                   &cpos_rej,
00332                                   &cneg_rej,
00333                                   &citer,
00334                                   NULL,
00335                                   NULL,
00336                                   FALSE));
00337 
00338         cpl_msg_info("", "-------------------------------------------");
00339 
00340         // load descriptor, header and data of first operand
00341         desc = kmo_identify_fits_header(
00342                     cpl_frame_get_filename(frame));
00343         KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to be "
00344                                       "in KMOS-format!");
00345 
00346         KMO_TRY_ASSURE(desc.fits_type == f3i_fits,
00347                        CPL_ERROR_ILLEGAL_INPUT,
00348                        "The input file hasn't correct data type "
00349                        "(KMOSTYPE must be F3I)!");
00350 
00351         // --- load, update & save primary header ---
00352         KMO_TRY_EXIT_IF_ERROR(
00353             kmo_dfs_save_main_header(frameset, SKY_MASK, "", frame,
00354                                      NULL, parlist, cpl_func));
00355 
00356         // --- load data ---
00357         if (desc.ex_noise == TRUE) {
00358             nr_devices = desc.nr_ext / 2;
00359         } else {
00360             nr_devices = desc.nr_ext;
00361         }
00362 
00363         for (i = 1; i <= nr_devices; i++) {
00364             if (desc.ex_noise == FALSE) {
00365                 devnr = desc.sub_desc[i - 1].device_nr;
00366             } else {
00367                 devnr = desc.sub_desc[2 * i - 1].device_nr;
00368             }
00369 
00370             if (desc.ex_badpix == FALSE) {
00371                 index_data = kmo_identify_index_desc(desc, devnr, FALSE);
00372             } else {
00373                 index_data = kmo_identify_index_desc(desc, devnr, 2);
00374             }
00375             KMO_TRY_CHECK_ERROR_STATE();
00376 
00377             KMO_TRY_EXIT_IF_NULL(
00378                 sub_header_data = kmo_dfs_load_sub_header(frameset, "0", devnr,
00379                                                           FALSE));
00380 
00381             // check if IFU is valid
00382             valid_ifu = FALSE;
00383             if (desc.sub_desc[index_data-1].valid_data == TRUE) {
00384                 valid_ifu = TRUE;
00385             }
00386 
00387             if (valid_ifu) {
00388                 // load data
00389                 KMO_TRY_EXIT_IF_NULL(
00390                     data_in = kmo_dfs_load_cube(frameset, "0", devnr, FALSE));
00391 
00392                 if (ranges != NULL) {
00393                     ifu_crpix = cpl_propertylist_get_double(sub_header_data, CRPIX3);
00394                     KMO_TRY_CHECK_ERROR_STATE_MSG(
00395                                    "CRPIX3 keyword in FITS-header is missing!");
00396 
00397                     ifu_crval = cpl_propertylist_get_double(sub_header_data, CRVAL3);
00398                     KMO_TRY_CHECK_ERROR_STATE_MSG(
00399                                    "CRVAL3 keyword in FITS-header is missing!");
00400 
00401                     ifu_cdelt = cpl_propertylist_get_double(sub_header_data, CDELT3);
00402                     KMO_TRY_CHECK_ERROR_STATE_MSG(
00403                                    "CDELT3 keyword in FITS-header is missing!");
00404                 }
00405 
00406                 cpl_propertylist_erase(sub_header_data, CRPIX3);
00407                 cpl_propertylist_erase(sub_header_data, CRVAL3);
00408                 cpl_propertylist_erase(sub_header_data, CDELT3);
00409                 cpl_propertylist_erase(sub_header_data, CTYPE3);
00410 
00411                 // calc mode and noise
00412                 KMO_TRY_EXIT_IF_NULL(
00413                     data_out = kmo_calc_sky_mask(data_in,
00414                                                  ranges,
00415                                                  fraction,
00416                                                  ifu_crpix,
00417                                                  ifu_crval,
00418                                                  ifu_cdelt,
00419                                                  cpos_rej,
00420                                                  cneg_rej,
00421                                                  citer));
00422 
00423                 // save data
00424                 KMO_TRY_EXIT_IF_ERROR(
00425                     kmo_dfs_save_image(data_out, SKY_MASK, "", sub_header_data, 0.));
00426 
00427                 // free memory
00428                 cpl_imagelist_delete(data_in); data_in = NULL;
00429                 cpl_image_delete(data_out); data_out = NULL;
00430             } else {
00431                 // invalid IFU, just save sub_headers
00432                 KMO_TRY_EXIT_IF_ERROR(
00433                     kmo_dfs_save_sub_header(SKY_MASK, "", sub_header_data));
00434             }
00435 
00436             // free memory
00437             cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00438         }
00439     }
00440     KMO_CATCH
00441     {
00442         KMO_CATCH_MSG();
00443 
00444         ret_val = -1;
00445     }
00446 
00447     kmo_free_fits_desc(&desc);
00448     cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00449     cpl_imagelist_delete(data_in); data_in = NULL;
00450     cpl_image_delete(data_out); data_out = NULL;
00451     cpl_vector_delete(ranges); ranges = NULL;
00452     return ret_val;
00453 }
00454