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