KMOS Pipeline Reference Manual  1.0.8
kmo_extract_spec.c
00001 /* $Id: kmo_extract_spec.c,v 1.11 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.11 $
00025  * $Name: kmosp_v1_0_8__20130220 $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033  *                              Includes
00034  *----------------------------------------------------------------------------*/
00035 
00036 #include <string.h>
00037 #include <math.h>
00038 
00039 #include <cpl.h>
00040 
00041 #include "kmo_utils.h"
00042 #include "kmo_dfs.h"
00043 #include "kmo_error.h"
00044 #include "kmo_priv_extract_spec.h"
00045 #include "kmo_priv_functions.h"
00046 #include "kmo_cpl_extensions.h"
00047 #include "kmo_constants.h"
00048 #include "kmo_priv_fit_profile.h"
00049 #include "kmo_debug.h"
00050 
00051 
00052 /*-----------------------------------------------------------------------------
00053  *                          Functions prototypes
00054  *----------------------------------------------------------------------------*/
00055 
00056 static int kmo_extract_spec_create(cpl_plugin *);
00057 static int kmo_extract_spec_exec(cpl_plugin *);
00058 static int kmo_extract_spec_destroy(cpl_plugin *);
00059 static int kmo_extract_spec(cpl_parameterlist *, cpl_frameset *);
00060 
00061 /*-----------------------------------------------------------------------------
00062  *                          Static variables
00063  *----------------------------------------------------------------------------*/
00064 
00065 static char kmo_extract_spec_description[] =
00066 "This recipe extracts a spectrum from a datacube. The datacube must be in\n"
00067 "F3I KMOS FITS format (either with or without noise). The output will be a\n"
00068 "similarly formatted F1I KMOS FITS file.\n"
00069 "\n"
00070 "BASIC PARAMETERS:\n"
00071 "-----------------\n"
00072 "--mask_method\n"
00073 "There are several ways to define the region to consider for spectrum calculation:\n"
00074 "  * 'integrated'' (default)\n"
00075 "  A circular mask with defined centre and radius is created (--centre and\n"
00076 "  --radius have to be defined). This mask is applied to all extensions.\n"
00077 "\n"
00078 "  * 'mask'\n"
00079 "  An arbitrary mask can be provided (for example the mask created by kmo_sky_mask\n"
00080 "  can be used). The mask must be in F2I KMOS FITS format, mustn't contain noise\n"
00081 "  and must have as many extensions as the input cube. The mask can be binary as\n"
00082 "  well as it can contain float values, so a weighted mask is also possible.\n"
00083 "  (0: pixels is ignored, 1: pixel is included) The mask must be of the same size\n"
00084 "  that the input datacube.\n"
00085 "\n"
00086 "  * 'optimal'\n"
00087 "  The mask is created automatically by fitting a normalised profile (using\n"
00088 "  kmo_fit_profile) to the image of the datacube (using kmo_make_image the data-\n"
00089 "  cube is summed up in spectral direction according to the specified --cmethod).\n"
00090 "  This profile is then used as mask input. When --save_mask is set to true the\n"
00091 "  mask is saved on disk. The remaining parameters not described here apply to\n"
00092 "  the fitting of the profile.\n"
00093 "\n"
00094 "If the spectra of several objects in a IFU should be extracted, --mask_method=\n"
00095 "'mask' is recommended. With several calls to kmo_extract_spec using different\n"
00096 "masks all spectra can be extracted.\n"
00097 "\n"
00098 "ADVANCED PARAMETERS\n"
00099 "-------------------\n"
00100 "--centre\n"
00101 "--radius\n"
00102 "see --mask_method = 'integrated'\n"
00103 "\n"
00104 "--save_mask\n"
00105 "see --mask_method = 'optimal'\n"
00106 "\n"
00107 "--cmethod\n"
00108 "Applies only if –mask_method = 'integral'\n"
00109 "Following methods of frame combination are available:\n"
00110 "   * 'ksigma' (Default)\n"
00111 "   An iterative sigma clipping. For each position all pixels in the spectrum\n"
00112 "   are examined. If they deviate significantly, they will be rejected according\n"
00113 "   to the conditions:\n"
00114 "       val > mean + stdev * cpos_rej\n"
00115 "   and\n"
00116 "       val < mean - stdev * cneg_rej\n"
00117 "   where --cpos_rej, --cneg_rej and --citer are the corresponding configuration\n"
00118 "   parameters. In the first iteration median and percentile level are used.\n"
00119 "\n"
00120 "   * 'median'\n"
00121 "   At each pixel position the median is calculated.\n"
00122 "\n"
00123 "   * 'average'\n"
00124 "   At each pixel position the average is calculated.\n"
00125 "\n"
00126 "   * 'sum'\n"
00127 "   At each pixel position the sum is calculated.\n"
00128 "\n"
00129 "   * 'min_max'\n"
00130 "   The specified number of minimum and maximum pixel values will be rejected.\n"
00131 "   --cmax and --cmin apply to this method.\n"
00132 "\n"
00133 "--cpos_rej\n"
00134 "--cneg_rej\n"
00135 "--citer\n"
00136 "see --cmethod='ksigma'\n"
00137 "\n"
00138 "--cmax\n"
00139 "--cmin\n"
00140 "see --cmethod='min_max'\n"
00141 
00142 "\n"
00143 "-------------------------------------------------------------------------------\n"
00144 "  Input files:\n"
00145 "\n"
00146 "   DO                    KMOS                                                  \n"
00147 "   category              Type   Explanation                    Required #Frames\n"
00148 "   --------              -----  -----------                    -------- -------\n"
00149 "   EXTRACT_DATA          F3I    The datacubes                     Y        1   \n"
00150 "   EXTRACT_MASK          F2I    The mask                          N       0,1  \n"
00151 "\n"
00152 "  Output files:\n"
00153 "\n"
00154 "   DO                    KMOS\n"
00155 "   category              Type   Explanation\n"
00156 "   --------              -----  -----------\n"
00157 "   EXTRACT_SPEC          F3I    Extracted spectrum                             \n"
00158 "   EXTRACT_SPEC_MASK     F2I    (optional, if --save_mask=true and             \n"
00159 "                                --mask_method='optimal': The calculated mask)  \n"
00160 "-------------------------------------------------------------------------------\n"
00161 "\n";
00162 
00163 /*-----------------------------------------------------------------------------
00164  *                              Functions code
00165  *----------------------------------------------------------------------------*/
00166 
00183 int cpl_plugin_get_info(cpl_pluginlist *list)
00184 {
00185     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00186     cpl_plugin *plugin = &recipe->interface;
00187 
00188     cpl_plugin_init(plugin,
00189                         CPL_PLUGIN_API,
00190                         KMOS_BINARY_VERSION,
00191                         CPL_PLUGIN_TYPE_RECIPE,
00192                         "kmo_extract_spec",
00193                         "Extract a spectrum from a cube.",
00194                         kmo_extract_spec_description,
00195                         "Alex Agudo Berbel",
00196                         "agudo@mpe.mpg.de",
00197                         kmos_get_license(),
00198                         kmo_extract_spec_create,
00199                         kmo_extract_spec_exec,
00200                         kmo_extract_spec_destroy);
00201 
00202     cpl_pluginlist_append(list, plugin);
00203 
00204     return 0;
00205 }
00206 
00214 static int kmo_extract_spec_create(cpl_plugin *plugin)
00215 {
00216     cpl_recipe *recipe;
00217     cpl_parameter *p;
00218 
00219     /* Check that the plugin is part of a valid recipe */
00220     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00221         recipe = (cpl_recipe *)plugin;
00222     else
00223         return -1;
00224 
00225     /* Create the parameters list in the cpl_recipe object */
00226     recipe->parameters = cpl_parameterlist_new();
00227 
00228     /* Fill the parameters list */
00229     /* --mask_method */
00230     p = cpl_parameter_new_value("kmos.kmo_extract_spec.mask_method",
00231                                 CPL_TYPE_STRING,
00232                                 "Either apply 'mask', 'integrated' or "
00233                                     "'optimal' masking method.",
00234                                 "kmos.kmo_extract_spec",
00235                                 "integrated");
00236     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "mask_method");
00237     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00238     cpl_parameterlist_append(recipe->parameters, p);
00239 
00240     /* --centre */
00241     p = cpl_parameter_new_value("kmos.kmo_extract_spec.centre",
00242                                 CPL_TYPE_STRING,
00243                                 "The centre of the circular mask (pixel).",
00244                                 "kmos.kmo_extract_spec",
00245                                 "7.5,7.5");
00246     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "centre");
00247     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00248     cpl_parameterlist_append(recipe->parameters, p);
00249 
00250     /* --radius */
00251     p = cpl_parameter_new_value("kmos.kmo_extract_spec.radius",
00252                                 CPL_TYPE_DOUBLE,
00253                                 "The radius of the circular mask (pixel).",
00254                                 "kmos.kmo_extract_spec",
00255                                 3.0);
00256     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "radius");
00257     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00258     cpl_parameterlist_append(recipe->parameters, p);
00259 
00260     /* --save_mask */
00261     p = cpl_parameter_new_value("kmos.kmo_extract_spec.save_mask",
00262                                 CPL_TYPE_BOOL,
00263                                 "True if the calculated mask should be saved.",
00264                                 "kmos.kmo_extract_spec",
00265                                 FALSE);
00266     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "save_mask");
00267     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00268     cpl_parameterlist_append(recipe->parameters, p);
00269 
00270     return kmo_combine_pars_create(recipe->parameters,
00271                                    "kmos.kmo_extract_spec",
00272                                    DEF_REJ_METHOD,
00273                                    FALSE);
00274 }
00275 
00281 static int kmo_extract_spec_exec(cpl_plugin *plugin)
00282 {
00283     cpl_recipe  *recipe;
00284 
00285     /* Get the recipe out of the plugin */
00286     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00287         recipe = (cpl_recipe *)plugin;
00288     else return -1;
00289 
00290     return kmo_extract_spec(recipe->parameters, recipe->frames);
00291 }
00292 
00298 static int kmo_extract_spec_destroy(cpl_plugin *plugin)
00299 {
00300     cpl_recipe *recipe;
00301 
00302     /* Get the recipe out of the plugin */
00303     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00304         recipe = (cpl_recipe *)plugin;
00305     else return -1 ;
00306 
00307     cpl_parameterlist_delete(recipe->parameters);
00308     return 0 ;
00309 }
00310 
00325 static int kmo_extract_spec(cpl_parameterlist *parlist, cpl_frameset *frameset)
00326 {
00327     cpl_imagelist    *data_in            = NULL,
00328                      *noise_in           = NULL;
00329 
00330     cpl_image        *mask               = NULL,
00331                      *made_data_img      = NULL;
00332 
00333     cpl_vector       *spec_data_out      = NULL,
00334                      *spec_noise_out     = NULL,
00335                      *centre             = NULL,
00336                      *fit_par            = NULL;
00337 
00338     int              ret_val             = 0,
00339                      nr_devices          = 0,
00340                      i                   = 0,
00341                      valid_ifu           = FALSE,
00342                      citer               = 0,
00343                      cmin                = 0,
00344                      cmax                = 0,
00345                      x                   = 0,
00346                      y                   = 0,
00347                      save_mask           = FALSE,
00348                      devnr1              = 0,
00349                      devnr2              = 0,
00350                      index_data          = 0,
00351                      index_noise          = 0;
00352 
00353     cpl_propertylist *sub_header_data    = NULL,
00354                      *sub_header_noise   = NULL,
00355                      *sub_header_mask    = NULL,
00356                      *fit_pl             = NULL;
00357 
00358     const char       *mask_method        = NULL,
00359                      *cmethod            = NULL,
00360                      *centre_txt         = NULL;
00361 
00362     double           cpos_rej            = 0.0,
00363                      cneg_rej            = 0.0,
00364                      radius              = 0.0,
00365                      r                   = 0.0,
00366                      x_lo                = 0.0,
00367                      y_lo                = 0.0,
00368                      x_hi                = 0.0,
00369                      y_hi                = 0.0,
00370                      cen_x               = 0.0,
00371                      cen_y               = 0.0;
00372 
00373     float            *pmask              = NULL;
00374 
00375     main_fits_desc   desc1,
00376                      desc2;
00377 
00378     cpl_frame        *op1_frame          = NULL,
00379                      *op2_frame          = NULL;
00380 
00381     char             do_mode1[256],
00382                      do_mode2[256];
00383 
00384     KMO_TRY
00385     {
00386         kmo_init_fits_desc(&desc1);
00387         kmo_init_fits_desc(&desc2);
00388 
00389         /* --- check input --- */
00390         KMO_TRY_ASSURE((parlist != NULL) &&
00391                        (frameset != NULL),
00392                        CPL_ERROR_NULL_INPUT,
00393                        "Not all input data is provided!");
00394 
00395         KMO_TRY_ASSURE((cpl_frameset_get_size(frameset) == 1) ||
00396                        ((cpl_frameset_get_size(frameset) == 2)),
00397                        CPL_ERROR_NULL_INPUT,
00398                        "Either one data cube or a datacube and a mask"
00399                        "must be provided!");
00400 
00401         if (cpl_frameset_get_size(frameset) == 1) {
00402 
00403             KMO_TRY_ASSURE((cpl_frameset_count_tags(frameset, EXTRACT_DATA) == 1) ||
00404                            (cpl_frameset_count_tags(frameset, COMMANDLINE) == 1),
00405                            CPL_ERROR_ILLEGAL_INPUT,
00406                            "The cube must be tagged as EXTRACT_DATA!");
00407 
00408             if (cpl_frameset_count_tags(frameset, EXTRACT_DATA) == 1) {
00409                 strcpy(do_mode1, EXTRACT_DATA);
00410                 strcpy(do_mode2, "");
00411             } else {
00412                 strcpy(do_mode1, "0");
00413                 strcpy(do_mode2, "");
00414             }
00415         } else {
00416             if ((cpl_frameset_count_tags(frameset, EXTRACT_DATA) == 1) &&
00417                 (cpl_frameset_count_tags(frameset, EXTRACT_MASK) == 1)){
00418                 strcpy(do_mode1, EXTRACT_DATA);
00419                 strcpy(do_mode2, EXTRACT_MASK);
00420             } else {
00421                 strcpy(do_mode1, "0");
00422                 strcpy(do_mode2, "1");
00423             }
00424             KMO_TRY_EXIT_IF_NULL(
00425                 op2_frame = kmo_dfs_get_frame(frameset, do_mode2));
00426         }
00427         KMO_TRY_EXIT_IF_NULL(
00428             op1_frame = kmo_dfs_get_frame(frameset, do_mode1));
00429 
00430         desc1 = kmo_identify_fits_header(
00431                     cpl_frame_get_filename(op1_frame));
00432         KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to be "
00433                                       "in KMOS-format!");
00434 
00435         KMO_TRY_ASSURE(desc1.fits_type == f3i_fits,
00436                CPL_ERROR_ILLEGAL_INPUT,
00437                "The input data hasn't the correct data type "
00438                "(KMOSTYPE must be F3I)!");
00439 
00440         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_extract_spec") == 1,
00441                        CPL_ERROR_ILLEGAL_INPUT,
00442                        "Cannot identify RAW and CALIB frames!");
00443 
00444         cpl_msg_info("", "--- Parameter setup for kmo_extract_spec ---");
00445 
00446         KMO_TRY_EXIT_IF_NULL(
00447             mask_method = kmo_dfs_get_parameter_string(parlist,
00448                                           "kmos.kmo_extract_spec.mask_method"));
00449 
00450         KMO_TRY_EXIT_IF_ERROR(
00451             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_extract_spec.mask_method"));
00452 
00453         if (strcmp(mask_method, "integrated") == 0) {
00454             KMO_TRY_EXIT_IF_NULL(
00455                 centre_txt = kmo_dfs_get_parameter_string(parlist,
00456                                             "kmos.kmo_extract_spec.centre"));
00457             KMO_TRY_EXIT_IF_ERROR(
00458                 kmo_dfs_print_parameter_help(parlist, "kmos.kmo_extract_spec.centre"));
00459 
00460             centre = kmo_identify_ranges(centre_txt);
00461             KMO_TRY_CHECK_ERROR_STATE();
00462 
00463             KMO_TRY_ASSURE(cpl_vector_get_size(centre) == 2,
00464                            CPL_ERROR_ILLEGAL_INPUT,
00465                          "centre must have exactly 2 values like \"2.0:3.1\"!");
00466 
00467             cen_x = cpl_vector_get(centre, 0);
00468             cen_y = cpl_vector_get(centre, 1);
00469 
00470             KMO_TRY_ASSURE((cen_x >= 0.0) &&
00471                            (cen_y >= 0.0),
00472                            CPL_ERROR_ILLEGAL_INPUT,
00473                            "centre must be greater than 0.0!");
00474 
00475             radius = kmo_dfs_get_parameter_double(parlist,
00476                                             "kmos.kmo_extract_spec.radius");
00477             KMO_TRY_CHECK_ERROR_STATE();
00478             KMO_TRY_EXIT_IF_ERROR(
00479                 kmo_dfs_print_parameter_help(parlist, "kmos.kmo_extract_spec.radius"));
00480 
00481             KMO_TRY_ASSURE(radius >= 0.0,
00482                            CPL_ERROR_ILLEGAL_INPUT,
00483                            "radius must be greater than 0.0!");
00484 
00485         } else if (strcmp(mask_method, "mask") == 0) {
00486             /* load descriptor of second operand */
00487             desc2 = kmo_identify_fits_header(
00488                         cpl_frame_get_filename(op2_frame));
00489             KMO_TRY_CHECK_ERROR_STATE_MSG("Mask doesn't seem to be "
00490                                           "in KMOS-format!");
00491 
00492             KMO_TRY_ASSURE(desc2.fits_type == f2i_fits,
00493                            CPL_ERROR_ILLEGAL_INPUT,
00494                            "Mask hasn't correct data type "
00495                            "(KMOSTYPE must be F2I)!");
00496 
00497             KMO_TRY_ASSURE(desc2.ex_noise == FALSE,
00498                            CPL_ERROR_ILLEGAL_INPUT,
00499                            "Mask must not contain noise extensions!");
00500 
00501             KMO_TRY_ASSURE(
00502                 ((desc1.ex_noise == TRUE) &&
00503                  (desc1.nr_ext / 2 == desc2.nr_ext)) ||
00504                 ((desc1.ex_noise == FALSE) &&
00505                  (desc1.nr_ext == desc2.nr_ext)),
00506                         CPL_ERROR_ILLEGAL_INPUT,
00507                         "Cube and mask haven't same number of extensions!");
00508 
00509             KMO_TRY_ASSURE((desc1.naxis1 == desc2.naxis1) &&
00510                            (desc1.naxis2 == desc2.naxis2),
00511                            CPL_ERROR_ILLEGAL_INPUT,
00512                            "Cube and mask haven't same dimensions in x and y!");
00513 
00514         } else if (strcmp(mask_method, "optimal") == 0) {
00515             KMO_TRY_EXIT_IF_ERROR(
00516                 kmo_combine_pars_load(parlist,
00517                                       "kmos.kmo_extract_spec",
00518                                       &cmethod,
00519                                       &cpos_rej,
00520                                       &cneg_rej,
00521                                       &citer,
00522                                       &cmin,
00523                                       &cmax,
00524                                       FALSE));
00525 
00526             save_mask = kmo_dfs_get_parameter_bool(parlist,
00527                                             "kmos.kmo_extract_spec.save_mask");
00528             KMO_TRY_CHECK_ERROR_STATE();
00529             KMO_TRY_EXIT_IF_ERROR(
00530                 kmo_dfs_print_parameter_help(parlist, "kmos.kmo_extract_spec.save_mask"));
00531 
00532         } else {
00533             KMO_TRY_ERROR_SET_MSG(CPL_ERROR_ILLEGAL_INPUT,
00534                                          "Wrong mask method!");
00535         }
00536 
00537         cpl_msg_info(cpl_func, "-------------------------------------------");
00538 
00539         /* --- load, update & save primary header --- */
00540         KMO_TRY_EXIT_IF_ERROR(
00541             kmo_dfs_save_main_header(frameset, EXTRACT_SPEC, "", op1_frame,
00542                                      NULL, parlist, cpl_func));
00543 
00544         if (save_mask) {
00545             KMO_TRY_EXIT_IF_ERROR(
00546                 kmo_dfs_save_main_header(frameset, EXTRACT_SPEC_MASK, "", op1_frame,
00547                                          NULL, parlist, cpl_func));
00548         }
00549 
00550         /* --- load data --- */
00551         if (desc1.ex_noise == TRUE) {
00552             nr_devices = desc1.nr_ext / 2;
00553         } else {
00554             nr_devices = desc1.nr_ext;
00555         }
00556 
00557         // create mask for integrated-method just once here
00558         // and not in the for-loop
00559         if (strcmp(mask_method, "integrated") == 0) {
00560             KMO_TRY_EXIT_IF_NULL(
00561                 mask = cpl_image_new(desc1.naxis1, desc1.naxis2,
00562                                      CPL_TYPE_FLOAT));
00563 
00564             KMO_TRY_EXIT_IF_ERROR(
00565                 kmo_image_fill(mask,0.0));
00566 
00567             KMO_TRY_EXIT_IF_NULL(
00568                 pmask = cpl_image_get_data_float(mask));
00569 
00570             /* draw circle */
00571             x_lo = floor(cen_x - radius);
00572             if (x_lo < 0) {
00573                 x_lo = 0;
00574             }
00575 
00576             y_lo = floor(cen_y - radius);
00577             if (y_lo < 0) {
00578                 y_lo = 0;
00579             }
00580 
00581             x_hi = ceil(cen_x + radius);
00582             if (x_hi > desc1.naxis1) {
00583                 x_hi = desc1.naxis1;
00584             }
00585 
00586             y_hi = ceil(cen_y + radius);
00587             if (y_hi > desc1.naxis2) {
00588                 y_hi = desc1.naxis2;
00589             }
00590 
00591             for (x = x_lo; x < x_hi; x++) {
00592                 for (y = y_lo; y < y_hi; y++) {
00593                     r = sqrt(pow(x - cen_x,2) + pow(y - cen_y,2));
00594                     if (r <= radius) {
00595                         pmask[x + y * desc1.naxis1] = 1.0;
00596                     }
00597                 }
00598             }            
00599         }
00600 
00601         for (i = 1; i <= nr_devices; i++) {
00602             if (desc1.ex_noise == FALSE) {
00603                 devnr1 = desc1.sub_desc[i - 1].device_nr;
00604             } else {
00605                 devnr1 = desc1.sub_desc[2 * i - 1].device_nr;
00606             }
00607             // mask doesn't contain any noise extensions
00608             if (strcmp(mask_method, "mask") == 0) {
00609                 devnr2 = desc2.sub_desc[i - 1].device_nr;
00610             }
00611 
00612             if (desc1.ex_badpix == FALSE) {
00613                 index_data = kmo_identify_index_desc(desc1, devnr1, FALSE);
00614             } else {
00615                 index_data = kmo_identify_index_desc(desc1, devnr1, 2);
00616             }
00617             KMO_TRY_CHECK_ERROR_STATE();
00618 
00619             if (desc1.ex_noise) {
00620                 index_noise = kmo_identify_index_desc(desc1, devnr1, TRUE);
00621             }
00622             KMO_TRY_CHECK_ERROR_STATE();
00623 
00624             KMO_TRY_EXIT_IF_NULL(
00625                 sub_header_data = kmo_dfs_load_sub_header(frameset, do_mode1,
00626                                                           devnr1, FALSE));
00627 
00628             // check if IFU is valid
00629             valid_ifu = FALSE;
00630             if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
00631                 if ((strcmp(mask_method, "mask") != 0) ||
00632                     ((strcmp(mask_method, "mask") == 0) &&
00633                     (desc2.sub_desc[i - 1].valid_data == TRUE))
00634                    )
00635                 {
00636                     valid_ifu = TRUE;
00637                 }
00638             }
00639 
00640             if (desc1.ex_noise) {
00641                 KMO_TRY_EXIT_IF_NULL(
00642                     sub_header_noise = kmo_dfs_load_sub_header(frameset,
00643                                                                do_mode1,
00644                                                                devnr1, TRUE));
00645             }
00646 
00647             if (valid_ifu) {
00648                 // load data
00649                 KMO_TRY_EXIT_IF_NULL(
00650                     data_in = kmo_dfs_load_cube(frameset, do_mode1, devnr1, FALSE));
00651 
00652                 // load noise, if existing
00653                 if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) {
00654                     KMO_TRY_EXIT_IF_NULL(
00655                         noise_in = kmo_dfs_load_cube(frameset, do_mode1, devnr1, TRUE));
00656                 }
00657 
00658                 // create or load mask (for integrated-method already
00659                 // done outside the for-loop)
00660                 if (strcmp(mask_method, "mask") == 0) {
00661                     KMO_TRY_EXIT_IF_NULL(
00662                         mask = kmo_dfs_load_image(frameset, do_mode2,
00663                                                   devnr2, FALSE, FALSE, NULL));
00664                 } else if (strcmp(mask_method, "optimal") == 0) {
00665                     KMO_TRY_EXIT_IF_ERROR(
00666                         kmclipm_make_image(data_in, NULL,
00667                                        &made_data_img, NULL,
00668                                        NULL,
00669                                        cmethod, cpos_rej, cneg_rej, citer,
00670                                        cmax, cmin));
00671 
00672                     KMO_TRY_EXIT_IF_NULL(
00673                         fit_par = kmo_fit_profile_2D(made_data_img,
00674                                                      NULL,
00675                                                      "gauss",
00676                                                      &mask,
00677                                                      &fit_pl));
00678 
00679                     // update subheader with fit parameters
00680                     KMO_TRY_EXIT_IF_ERROR(
00681                         cpl_propertylist_append(sub_header_data, fit_pl));
00682 
00683                     cpl_propertylist_delete(fit_pl); fit_pl = NULL;
00684 
00685                     // normalise mask
00686                     // (subtract first background and then normalise)
00687                     cpl_image_subtract_scalar(mask, cpl_vector_get(fit_par, 0));
00688                     cpl_image_divide_scalar(mask, cpl_vector_get(fit_par, 1));
00689                     cpl_vector_delete(fit_par); fit_par = NULL;
00690                     cpl_image_delete(made_data_img); made_data_img = NULL;
00691                 }
00692 
00693                 // process & save data
00694                 KMO_TRY_EXIT_IF_ERROR(
00695                     kmo_priv_extract_spec(data_in,
00696                                           noise_in,
00697                                           mask,
00698                                           &spec_data_out,
00699                                           &spec_noise_out));
00700 
00701                 KMO_TRY_EXIT_IF_NULL(
00702                     sub_header_mask = cpl_propertylist_duplicate(
00703                                                               sub_header_data));
00704 
00705                 // change WCS here (CRPIX3 goes to CRPIX1 etc...)
00706                 KMO_TRY_EXIT_IF_NULL(
00707                     sub_header_data = kmo_priv_update_header(sub_header_data));
00708 
00709                 kmclipm_vector *ddd = kmclipm_vector_create(spec_data_out);
00710                 KMO_TRY_CHECK_ERROR_STATE();
00711 
00712                 KMO_TRY_EXIT_IF_ERROR(
00713                     kmo_dfs_save_vector(ddd, EXTRACT_SPEC, "",
00714                                         sub_header_data, 0./0.));
00715                 kmclipm_vector_delete(ddd); ddd = NULL; spec_data_out = NULL;
00716 
00717                 if (save_mask) {
00718                     // delete WCS for 3rd dimension since mask is 2D
00719                     KMO_TRY_EXIT_IF_ERROR(
00720                         cpl_propertylist_erase(sub_header_data, CRPIX3));
00721                     KMO_TRY_EXIT_IF_ERROR(
00722                         cpl_propertylist_erase(sub_header_data, CRVAL3));
00723                     KMO_TRY_EXIT_IF_ERROR(
00724                         cpl_propertylist_erase(sub_header_data, CDELT3));
00725                     KMO_TRY_EXIT_IF_ERROR(
00726                         cpl_propertylist_erase(sub_header_data, CTYPE3));
00727                     KMO_TRY_EXIT_IF_ERROR(
00728                         cpl_propertylist_erase(sub_header_data, CD1_3));
00729                     KMO_TRY_EXIT_IF_ERROR(
00730                         cpl_propertylist_erase(sub_header_data, CD2_3));
00731                     KMO_TRY_EXIT_IF_ERROR(
00732                         cpl_propertylist_erase(sub_header_data, CD3_3));
00733                     KMO_TRY_EXIT_IF_ERROR(
00734                         cpl_propertylist_erase(sub_header_data, CD3_1));
00735                     KMO_TRY_EXIT_IF_ERROR(
00736                         cpl_propertylist_erase(sub_header_data, CD3_2));
00737 
00738                     KMO_TRY_EXIT_IF_ERROR(
00739                         kmo_dfs_save_image(mask, EXTRACT_SPEC_MASK, "",
00740                                            sub_header_mask, 0.));
00741                 }
00742                 cpl_propertylist_delete(sub_header_mask);
00743                 sub_header_mask = NULL;
00744 
00745                 // process & save noise, if existing
00746                 if (desc1.ex_noise) {
00747                     kmclipm_vector *nnn = NULL;
00748                     if (spec_noise_out != NULL) {
00749                         nnn = kmclipm_vector_create(spec_noise_out);
00750                     }
00751                     KMO_TRY_EXIT_IF_NULL(
00752                         sub_header_noise = kmo_priv_update_header(
00753                                                              sub_header_noise));
00754 
00755                     KMO_TRY_EXIT_IF_ERROR(
00756                         kmo_dfs_save_vector(nnn, EXTRACT_SPEC, "",
00757                                             sub_header_noise, 0./0.));
00758                     kmclipm_vector_delete(nnn); nnn = NULL; spec_noise_out = NULL;
00759                 }
00760 
00761                 // free memory
00762                 cpl_imagelist_delete(data_in); data_in = NULL;
00763                 cpl_imagelist_delete(noise_in); noise_in = NULL;
00764                 KMO_TRY_CHECK_ERROR_STATE();
00765 
00766                 if (strcmp(mask_method, "integrated") != 0) {
00767                     // for integrated-method the mask will be deleted
00768                     // at the very end!
00769                     cpl_image_delete(mask); mask = NULL;
00770                 }
00771             } else {
00772                 // invalid IFU, just save sub_headers
00773                 KMO_TRY_EXIT_IF_ERROR(
00774                     kmo_dfs_save_sub_header(EXTRACT_SPEC, "", sub_header_data));
00775 
00776                 if (desc1.ex_noise) {
00777                     KMO_TRY_EXIT_IF_ERROR(
00778                         kmo_dfs_save_sub_header(EXTRACT_SPEC, "", sub_header_noise));
00779                 }
00780             }
00781 
00782             // free memory
00783             cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00784             cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
00785         }
00786 
00787         if (strcmp(mask_method, "integrated") == 0) {
00788             cpl_image_delete(mask); mask = NULL;
00789             cpl_vector_delete(centre); centre = NULL;
00790         }
00791     }
00792     KMO_CATCH
00793     {
00794         KMO_CATCH_MSG();
00795 
00796         ret_val = -1;
00797     }
00798 
00799     kmo_free_fits_desc(&desc1);
00800     kmo_free_fits_desc(&desc2);
00801 
00802     cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00803     cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
00804     cpl_propertylist_delete(sub_header_mask); sub_header_mask = NULL;
00805     cpl_imagelist_delete(data_in); data_in = NULL;
00806     cpl_imagelist_delete(noise_in); noise_in = NULL;
00807     cpl_vector_delete(spec_data_out); spec_data_out = NULL;
00808     cpl_vector_delete(spec_noise_out); spec_noise_out = NULL;
00809     cpl_image_delete(mask); mask = NULL;
00810     cpl_vector_delete(centre); centre = NULL;
00811 
00812     return ret_val;
00813 }
00814