KMOS Pipeline Reference Manual  1.3.0b1
kmo_make_image.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 #include <string.h>
00025 
00026 #include <cpl.h>
00027 
00028 #include "kmo_debug.h"
00029 #include "kmo_utils.h"
00030 #include "kmo_dfs.h"
00031 #include "kmo_error.h"
00032 #include "kmo_priv_make_image.h"
00033 #include "kmo_priv_functions.h"
00034 #include "kmo_constants.h"
00035 
00036 static int kmo_make_image_create(cpl_plugin *);
00037 static int kmo_make_image_exec(cpl_plugin *);
00038 static int kmo_make_image_destroy(cpl_plugin *);
00039 static int kmo_make_image(cpl_parameterlist *, cpl_frameset *);
00040 
00041 static char kmo_make_image_description[] =
00042 "This recipe collapses a cube along the spectral axis using rejection. By \n"
00043 "default all spectral slices are averaged.\n"
00044 "Errors are propagated for the same spectral ranges as for the input data if\n"
00045 "a noise map is provided.\n"
00046 "\n"
00047 "BASIC PARAMETERS:\n"
00048 "-----------------\n"
00049 "--range\n"
00050 "The spectral range can be delimited to one or several sub-ranges like \"1.8,1.9\"\n"
00051 "or \"1.8,1.9; 2.0,2.11\"\n"
00052 "\n"
00053 "--cmethod\n"
00054 "Following methods of frame combination are available:\n"
00055 "   * 'ksigma' (Default)\n"
00056 "   An iterative sigma clipping. For each position all pixels in the spectrum\n"
00057 "   are examined. If they deviate significantly, they will be rejected according\n"
00058 "   to the conditions:\n"
00059 "       val > mean + stdev * cpos_rej\n"
00060 "   and\n"
00061 "       val < mean - stdev * cneg_rej\n"
00062 "   where --cpos_rej, --cneg_rej and --citer are the corresponding configuration\n"
00063 "   parameters. In the first iteration median and percentile level are used.\n"
00064 "\n"
00065 "   * 'median'\n"
00066 "   At each pixel position the median is calculated.\n"
00067 "\n"
00068 "   * 'average'\n"
00069 "   At each pixel position the average is calculated.\n"
00070 "\n"
00071 "   * 'sum'\n"
00072 "   At each pixel position the sum is calculated.\n"
00073 "\n"
00074 "   * 'min_max'\n"
00075 "   The specified number of minimum and maximum pixel values will be rejected.\n"
00076 "   --cmax and --cmin apply to this method.\n"
00077 "\n"
00078 "ADVANCED PARAMETERS\n"
00079 "-------------------\n"
00080 "--threshold\n"
00081 "Optionally an OH spectrum can be provided. In this case a threshold can be\n"
00082 "defined. The wavelengths of values above the threshold level in the OH spectrum\n"
00083 "are omitted in the input frame. This parameter can be combined with the --range\n"
00084 "parameter. Negative threshold values are ignored.\n"
00085 "Own spectra can be converted into the required F1S KMOS FITS format for the OH\n"
00086 "spectrum using kmo_fits_stack.\n"
00087 "\n"
00088 "--cpos_rej\n"
00089 "--cneg_rej\n"
00090 "--citer\n"
00091 "see --cmethod='ksigma'\n"
00092 "\n"
00093 "--cmax\n"
00094 "--cmin\n"
00095 "see --cmethod='min_max'\n"
00096 "\n"
00097 "-------------------------------------------------------------------------------\n"
00098 "  Input files:\n"
00099 "\n"
00100 "   DO                    KMOS                                                  \n"
00101 "   category              Type   Explanation                    Required #Frames\n"
00102 "   --------              -----  -----------                    -------- -------\n"
00103 "   <none or any>         F3I    data frame                         Y       1   \n"
00104 "   <none or any>         F1S    OH line spectrum                   N      0,1  \n"
00105 "\n"
00106 "  Output files:\n"
00107 "\n"
00108 "   DO                    KMOS\n"
00109 "   category              Type   Explanation\n"
00110 "   --------              -----  -----------\n"
00111 "   MAKE_IMAGE            F2I    Collapsed data cubes\n"
00112 "-------------------------------------------------------------------------------\n"
00113 "\n";
00114 
00132 int cpl_plugin_get_info(cpl_pluginlist *list)
00133 {
00134     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00135     cpl_plugin *plugin = &recipe->interface;
00136 
00137     cpl_plugin_init(plugin,
00138                         CPL_PLUGIN_API,
00139                         KMOS_BINARY_VERSION,
00140                         CPL_PLUGIN_TYPE_RECIPE,
00141                         "kmo_make_image",
00142                         "Collapse a cube to create a spatial image",
00143                         kmo_make_image_description,
00144                         "Alex Agudo Berbel",
00145                         "usd-help@eso.org",
00146                         kmos_get_license(),
00147                         kmo_make_image_create,
00148                         kmo_make_image_exec,
00149                         kmo_make_image_destroy);
00150 
00151     cpl_pluginlist_append(list, plugin);
00152 
00153     return 0;
00154 }
00155 
00163 static int kmo_make_image_create(cpl_plugin *plugin)
00164 {
00165     cpl_recipe *recipe;
00166     cpl_parameter *p;
00167 
00168     /* Check that the plugin is part of a valid recipe */
00169     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00170         recipe = (cpl_recipe *)plugin;
00171     else
00172         return -1;
00173 
00174     /* Create the parameters list in the cpl_recipe object */
00175     recipe->parameters = cpl_parameterlist_new();
00176 
00177     /* Fill the parameters list */
00178     /* --range */
00179     p = cpl_parameter_new_value("kmos.kmo_make_image.range",
00180                                 CPL_TYPE_STRING,
00181                                 "The spectral ranges to combine. e.g."
00182                                 "\"x1_start,x1_end;x2_start,x2_end\" (microns)",
00183                                 "kmos.kmo_make_image",
00184                                 "");
00185     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "range");
00186     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00187     cpl_parameterlist_append(recipe->parameters, p);
00188 
00189     /* --threshold (if < 0, no thresholding at all) */
00190     p = cpl_parameter_new_value("kmos.kmo_make_image.threshold",
00191                                 CPL_TYPE_DOUBLE,
00192                                 "The OH threshold level (%)",
00193                                 "kmos.kmo_make_image",
00194                                 0.1);
00195     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "threshold");
00196     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00197     cpl_parameterlist_append(recipe->parameters, p);
00198 
00199     return kmo_combine_pars_create(recipe->parameters,
00200                                    "kmos.kmo_make_image",
00201                                    DEF_REJ_METHOD,
00202                                    FALSE);
00203 }
00204 
00210 static int kmo_make_image_exec(cpl_plugin *plugin)
00211 {
00212     cpl_recipe  *recipe;
00213 
00214     /* Get the recipe out of the plugin */
00215     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00216         recipe = (cpl_recipe *)plugin;
00217     else return -1 ;
00218 
00219     return kmo_make_image(recipe->parameters, recipe->frames);
00220 }
00221 
00227 static int kmo_make_image_destroy(cpl_plugin *plugin)
00228 {
00229     cpl_recipe *recipe;
00230 
00231     /* Get the recipe out of the plugin */
00232     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00233         recipe = (cpl_recipe *)plugin;
00234     else return -1 ;
00235 
00236     cpl_parameterlist_delete(recipe->parameters);
00237     return 0 ;
00238 }
00239 
00254 static int kmo_make_image(cpl_parameterlist *parlist, cpl_frameset *frameset)
00255 {
00256     const char       *cmethod             = NULL;
00257 
00258     double           threshold           = 0.0,
00259                      spec_crval          = 0.0,
00260                      spec_cdelt          = 0.0,
00261                      ifu_crval           = 0.0,
00262                      ifu_cdelt           = 0.0,
00263                      cpos_rej            = 0.0,
00264                      cneg_rej            = 0.0;
00265 
00266     cpl_imagelist    *data_in            = NULL,
00267                      *noise_in           = NULL;
00268 
00269     cpl_image        *data_out           = NULL,
00270                      *noise_out          = NULL;
00271 
00272     const char       *ranges_txt         = NULL;
00273 
00274     cpl_vector       *ranges             = NULL,
00275                      *identified_slices  = NULL,
00276                      *spec_data_in       = NULL,
00277                      *spec_lambda_in     = NULL;
00278 
00279     int              ret_val             = 0,
00280                      nr_devices          = 0,
00281                      i                   = 0,
00282                      valid_ifu           = FALSE,
00283                      citer               = 0,
00284                      cmax                = 0,
00285                      cmin                = 0,
00286                      ifu_crpix           = 0,
00287                      spec_crpix          = 0,
00288                      devnr               = 0,
00289                      index_data          = 0,
00290                      index_noise         = 0;
00291 
00292     cpl_propertylist *sub_header_data    = NULL,
00293                      *sub_header_noise   = NULL,
00294                      *spec_header         = NULL;
00295 
00296     main_fits_desc   desc1,
00297                      desc2;
00298 
00299     cpl_frame        *op1_frame          = NULL,
00300                      *op2_frame          = NULL;
00301 
00302     char             do_mode1[256],
00303                      do_mode2[256];
00304 
00305     KMO_TRY
00306     {
00307         kmo_init_fits_desc(&desc1);
00308         kmo_init_fits_desc(&desc2);
00309 
00310         // --- check input ---
00311         KMO_TRY_ASSURE((parlist != NULL) &&
00312                        (frameset != NULL),
00313                        CPL_ERROR_NULL_INPUT,
00314                        "Not all input data is provided!");
00315 
00316         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_make_image") == 1,
00317                        CPL_ERROR_ILLEGAL_INPUT,
00318                        "Cannot identify RAW and CALIB frames!");
00319 
00320         cpl_msg_info("", "--- Parameter setup for kmo_make_image ----");
00321 
00322         threshold = kmo_dfs_get_parameter_double(parlist,
00323                                           "kmos.kmo_make_image.threshold");
00324         KMO_TRY_CHECK_ERROR_STATE();
00325         KMO_TRY_EXIT_IF_ERROR(
00326             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_make_image.threshold"));
00327 
00328         ranges_txt = kmo_dfs_get_parameter_string(parlist,
00329                                                   "kmos.kmo_make_image.range");
00330         KMO_TRY_CHECK_ERROR_STATE();
00331         KMO_TRY_EXIT_IF_ERROR(
00332             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_make_image.range"));
00333 
00334         ranges = kmo_identify_ranges(ranges_txt);
00335         KMO_TRY_CHECK_ERROR_STATE();
00336 
00337         KMO_TRY_EXIT_IF_ERROR(
00338             kmo_combine_pars_load(parlist,
00339                                   "kmos.kmo_make_image",
00340                                   &cmethod,
00341                                   &cpos_rej,
00342                                   &cneg_rej,
00343                                   &citer,
00344                                   &cmin,
00345                                   &cmax,
00346                                   FALSE));
00347         cpl_msg_info("", "-------------------------------------------");
00348 
00349         KMO_TRY_ASSURE((cpl_frameset_get_size(frameset) == 1) ||
00350                        ((cpl_frameset_get_size(frameset) == 2) &&
00351                        (threshold != 0.0)),
00352                        CPL_ERROR_NULL_INPUT,
00353                        "A cube or a cube and a OH line spectrum "
00354                        "must be provided!");
00355 
00356         if (cpl_frameset_get_size(frameset) == 1) {
00357             strcpy(do_mode1, "0");
00358             strcpy(do_mode2, "");
00359         } else {
00360             strcpy(do_mode1, "0");
00361             strcpy(do_mode2, "1");
00362             KMO_TRY_EXIT_IF_NULL(
00363                 op2_frame = kmo_dfs_get_frame(frameset, do_mode2));
00364 
00365             desc2 = kmo_identify_fits_header(cpl_frame_get_filename(op2_frame));
00366             KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem "
00367                                           "to be in KMOS-format! "
00368                                           "(KMOSTYPE must be F1S)!");
00369 
00370             KMO_TRY_ASSURE(desc2.fits_type == f1s_fits,
00371                            CPL_ERROR_ILLEGAL_INPUT,
00372                            "Second input file hasn't correct data type "
00373                            "(KMOSTYPE must be F1S)!");
00374         }
00375         KMO_TRY_EXIT_IF_NULL(
00376             op1_frame = kmo_dfs_get_frame(frameset, do_mode1));
00377 
00378         // load descriptor of first operand
00379         desc1 = kmo_identify_fits_header( cpl_frame_get_filename(op1_frame));
00380         KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to be "
00381                                       "in KMOS-format!");
00382 
00383         KMO_TRY_ASSURE(desc1.fits_type == f3i_fits,
00384                        CPL_ERROR_ILLEGAL_INPUT,
00385                        "First input file hasn't correct data type "
00386                        "(KMOSTYPE must be F3I)!");
00387 
00388         if (cpl_frameset_get_size(frameset) == 1) {
00389             // only cube is provided
00390         } else if (cpl_frameset_get_size(frameset) == 2) {
00391             // cube and OH line spectrum are provided
00392             KMO_TRY_EXIT_IF_NULL(
00393                 spec_header = kmo_dfs_load_sub_header(frameset, do_mode2, 1, FALSE));
00394 
00395             KMO_TRY_ASSURE(cpl_propertylist_get_int(spec_header, NAXIS) == 1,
00396                            CPL_ERROR_ILLEGAL_INPUT,
00397                            "Second input file has to be a vector!");
00398 
00399             // load header & data of OH-lines
00400             switch (cpl_propertylist_get_type(spec_header, CRPIX1)) {
00401             case CPL_TYPE_INT:
00402                 spec_crpix = cpl_propertylist_get_int(spec_header, CRPIX1);
00403                 break;
00404             case CPL_TYPE_DOUBLE:
00405                 spec_crpix = cpl_propertylist_get_double(spec_header, CRPIX1);
00406                 break;
00407             case CPL_TYPE_FLOAT:
00408                 spec_crpix = cpl_propertylist_get_float(spec_header, CRPIX1);
00409                 break;
00410             default:
00411                 KMO_TRY_ASSURE(1 == 0,
00412                                CPL_ERROR_ILLEGAL_INPUT,
00413                                "CRPIX1 is of wrong type!");
00414             }
00415             KMO_TRY_CHECK_ERROR_STATE();
00416             spec_crval = cpl_propertylist_get_double(spec_header, CRVAL1);
00417             KMO_TRY_CHECK_ERROR_STATE();
00418             spec_cdelt = cpl_propertylist_get_double(spec_header, CDELT1);
00419             KMO_TRY_CHECK_ERROR_STATE();
00420 
00421             kmclipm_vector *tmp_vec = NULL;
00422             KMO_TRY_EXIT_IF_NULL(
00423                 tmp_vec = kmo_dfs_load_vector(frameset, do_mode2, 1, FALSE));
00424             KMO_TRY_EXIT_IF_NULL(
00425                 spec_data_in = kmclipm_vector_create_non_rejected(tmp_vec));
00426             kmclipm_vector_delete(tmp_vec); tmp_vec = NULL;
00427 
00428             // convert threshold from percentage to absolute value
00429             threshold = threshold * cpl_vector_get_max(spec_data_in);
00430 
00431             // create lambda-vector for OH-lines
00432             KMO_TRY_EXIT_IF_NULL(
00433                 spec_lambda_in = kmo_create_lambda_vec(
00434                                     cpl_vector_get_size(spec_data_in),
00435                                     spec_crpix,
00436                                     spec_crval,
00437                                     spec_cdelt));
00438 
00439         } else {
00440             KMO_TRY_EXIT_WITH_ERROR(CPL_ERROR_ILLEGAL_INPUT);
00441         }
00442 
00443         // --- load, update & save primary header ---
00444         KMO_TRY_EXIT_IF_ERROR(
00445             kmo_dfs_save_main_header(frameset, MAKE_IMAGE, "", op1_frame,
00446                                      NULL, parlist, cpl_func));
00447 
00448         // --- load data ---
00449         if (desc1.ex_noise == TRUE) {
00450             nr_devices = desc1.nr_ext / 2;
00451         } else {
00452             nr_devices = desc1.nr_ext;
00453         }
00454 
00455         for (i = 1; i <= nr_devices; i++) {
00456             if (desc1.ex_noise == FALSE) {
00457                 devnr = desc1.sub_desc[i - 1].device_nr;
00458             } else {
00459                 devnr = desc1.sub_desc[2 * i - 1].device_nr;
00460             }
00461 
00462             if (desc1.ex_badpix == FALSE) {
00463                 index_data = kmo_identify_index_desc(desc1, devnr, FALSE);
00464             } else {
00465                 index_data = kmo_identify_index_desc(desc1, devnr, 2);
00466             }
00467             KMO_TRY_CHECK_ERROR_STATE();
00468 
00469             if (desc1.ex_noise) {
00470                 index_noise = kmo_identify_index_desc(desc1, devnr, TRUE);
00471             }
00472             KMO_TRY_CHECK_ERROR_STATE();
00473 
00474             KMO_TRY_EXIT_IF_NULL(
00475                 sub_header_data = kmo_dfs_load_sub_header(frameset, do_mode1,
00476                                                           devnr, FALSE));
00477 
00478             // check if IFU is valid
00479             valid_ifu = FALSE;
00480             if (desc1.sub_desc[index_data-1].valid_data == TRUE) {
00481                 valid_ifu = TRUE;
00482             }
00483 
00484             if (desc1.ex_noise) {
00485                 // load noise anyway since we have to save it in the output
00486                 KMO_TRY_EXIT_IF_NULL(
00487                     sub_header_noise = kmo_dfs_load_sub_header(frameset, do_mode1,
00488                                                                devnr, TRUE));
00489 
00490                 if (cpl_propertylist_has(sub_header_noise, CRPIX3))
00491                     cpl_propertylist_erase(sub_header_noise, CRPIX3);
00492                 if (cpl_propertylist_has(sub_header_noise, CRVAL3))
00493                     cpl_propertylist_erase(sub_header_noise, CRVAL3);
00494                 if (cpl_propertylist_has(sub_header_noise, CDELT3))
00495                     cpl_propertylist_erase(sub_header_noise, CDELT3);
00496                 if (cpl_propertylist_has(sub_header_noise, CTYPE3))
00497                     cpl_propertylist_erase(sub_header_noise, CTYPE3);
00498                 if (cpl_propertylist_has(sub_header_noise, CUNIT3))
00499                     cpl_propertylist_erase(sub_header_noise, CUNIT3);
00500                 if (cpl_propertylist_has(sub_header_noise, CD1_3))
00501                     cpl_propertylist_erase(sub_header_noise, CD1_3);
00502                 if (cpl_propertylist_has(sub_header_noise, CD2_3))
00503                     cpl_propertylist_erase(sub_header_noise, CD2_3);
00504                 if (cpl_propertylist_has(sub_header_noise, CD3_3))
00505                     cpl_propertylist_erase(sub_header_noise, CD3_3);
00506                 if (cpl_propertylist_has(sub_header_noise, CD3_2))
00507                     cpl_propertylist_erase(sub_header_noise, CD3_2);
00508                 if (cpl_propertylist_has(sub_header_noise, CD3_1))
00509                     cpl_propertylist_erase(sub_header_noise, CD3_1);
00510             }
00511 
00512             if (valid_ifu) {
00513                 // load data
00514                 KMO_TRY_EXIT_IF_NULL(
00515                     data_in = kmo_dfs_load_cube(frameset, do_mode1,
00516                                                 devnr, FALSE));
00517 
00518                 // load noise, if existing
00519                 if (desc1.ex_noise && desc1.sub_desc[index_noise-1].valid_data) {
00520                     KMO_TRY_EXIT_IF_NULL(
00521                         noise_in = kmo_dfs_load_cube(frameset, do_mode1, devnr,
00522                                                      TRUE));
00523                 }
00524 
00525                 // interpolate oh-lines to fit input data
00526                 if (spec_data_in != NULL) {
00527                     ifu_crpix = cpl_propertylist_get_double(sub_header_data, CRPIX3);
00528                     KMO_TRY_CHECK_ERROR_STATE_MSG(
00529                         "CRPIX3 keyword in FITS-header is missing!");
00530 
00531                     ifu_crval = cpl_propertylist_get_double(sub_header_data, CRVAL3);
00532                     KMO_TRY_CHECK_ERROR_STATE_MSG(
00533                         "CRVAL3 keyword in FITS-header is missing!");
00534 
00535 
00536                     ifu_cdelt = cpl_propertylist_get_double(sub_header_data, CDELT3);
00537                     KMO_TRY_CHECK_ERROR_STATE_MSG(
00538                         "CDELT3 keyword in FITS-header is missing!");
00539 
00540                     KMO_TRY_EXIT_IF_NULL(
00541                         identified_slices = kmo_identify_slices_with_oh(spec_data_in,
00542                                                                         spec_lambda_in,
00543                                                                         ranges,
00544                                                                         threshold,
00545                                                                         ifu_crpix,
00546                                                                         ifu_crval,
00547                                                                         ifu_cdelt,
00548                                                                         desc1.naxis3));
00549                 }
00550 
00551                 if (cpl_propertylist_has(sub_header_data, CRPIX3))
00552                     cpl_propertylist_erase(sub_header_data, CRPIX3);
00553                 if (cpl_propertylist_has(sub_header_data, CRVAL3))
00554                     cpl_propertylist_erase(sub_header_data, CRVAL3);
00555                 if (cpl_propertylist_has(sub_header_data, CDELT3))
00556                     cpl_propertylist_erase(sub_header_data, CDELT3);
00557                 if (cpl_propertylist_has(sub_header_data, CTYPE3))
00558                     cpl_propertylist_erase(sub_header_data, CTYPE3);
00559                 if (cpl_propertylist_has(sub_header_data, CUNIT3))
00560                     cpl_propertylist_erase(sub_header_data, CUNIT3);
00561                 if (cpl_propertylist_has(sub_header_data, CD1_3))
00562                     cpl_propertylist_erase(sub_header_data, CD1_3);
00563                 if (cpl_propertylist_has(sub_header_data, CD2_3))
00564                     cpl_propertylist_erase(sub_header_data, CD2_3);
00565                 if (cpl_propertylist_has(sub_header_data, CD3_3))
00566                     cpl_propertylist_erase(sub_header_data, CD3_3);
00567                 if (cpl_propertylist_has(sub_header_data, CD3_2))
00568                     cpl_propertylist_erase(sub_header_data, CD3_2);
00569                 if (cpl_propertylist_has(sub_header_data, CD3_1))
00570                     cpl_propertylist_erase(sub_header_data, CD3_1);
00571 
00572                 // process & save data
00573                 KMO_TRY_EXIT_IF_ERROR(
00574                     kmclipm_make_image(data_in, noise_in,
00575                                        &data_out, &noise_out,
00576                                        identified_slices,
00577                                        cmethod, cpos_rej, cneg_rej, citer,
00578                                        cmax, cmin));
00579 
00580                 KMO_TRY_EXIT_IF_ERROR(
00581                     kmo_dfs_save_image(data_out, MAKE_IMAGE, "",
00582                                        sub_header_data, 0./0.));
00583 
00584                 // process & save noise, if existing
00585                 if (desc1.ex_noise) {
00586                     KMO_TRY_EXIT_IF_ERROR(
00587                         kmo_dfs_save_image(noise_out, MAKE_IMAGE, "",
00588                                            sub_header_noise, 0./0.));
00589                 }
00590 
00591                 // free memory
00592                 cpl_imagelist_delete(data_in); data_in = NULL;
00593                 cpl_imagelist_delete(noise_in); noise_in = NULL;
00594                 cpl_image_delete(data_out); data_out = NULL;
00595                 cpl_image_delete(noise_out); noise_out = NULL;
00596                 cpl_vector_delete(identified_slices); identified_slices = NULL;
00597             } else {
00598                 if (cpl_propertylist_has(sub_header_data, CRPIX3))
00599                     cpl_propertylist_erase(sub_header_data, CRPIX3);
00600                 if (cpl_propertylist_has(sub_header_data, CRVAL3))
00601                     cpl_propertylist_erase(sub_header_data, CRVAL3);
00602                 if (cpl_propertylist_has(sub_header_data, CDELT3))
00603                     cpl_propertylist_erase(sub_header_data, CDELT3);
00604                 if (cpl_propertylist_has(sub_header_data, CTYPE3))
00605                     cpl_propertylist_erase(sub_header_data, CTYPE3);
00606                 if (cpl_propertylist_has(sub_header_data, CUNIT3))
00607                     cpl_propertylist_erase(sub_header_data, CUNIT3);
00608                 if (cpl_propertylist_has(sub_header_data, CD1_3))
00609                     cpl_propertylist_erase(sub_header_data, CD1_3);
00610                 if (cpl_propertylist_has(sub_header_data, CD2_3))
00611                     cpl_propertylist_erase(sub_header_data, CD2_3);
00612                 if (cpl_propertylist_has(sub_header_data, CD3_3))
00613                     cpl_propertylist_erase(sub_header_data, CD3_3);
00614                 if (cpl_propertylist_has(sub_header_data, CD3_2))
00615                     cpl_propertylist_erase(sub_header_data, CD3_2);
00616                 if (cpl_propertylist_has(sub_header_data, CD3_1))
00617                     cpl_propertylist_erase(sub_header_data, CD3_1);
00618 
00619                 // invalid IFU, just save sub_headers
00620                  KMO_TRY_EXIT_IF_ERROR(
00621                      kmo_dfs_save_sub_header(MAKE_IMAGE, "", sub_header_data));
00622 
00623                  if (desc1.ex_noise) {
00624                      KMO_TRY_EXIT_IF_ERROR(
00625                          kmo_dfs_save_sub_header(MAKE_IMAGE, "", sub_header_noise));
00626                  }
00627             }
00628 
00629             // free memory
00630             cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00631             cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
00632         }
00633     }
00634     KMO_CATCH
00635     {
00636         KMO_CATCH_MSG();
00637         ret_val = -1;
00638     }
00639 
00640     kmo_free_fits_desc(&desc1);
00641     kmo_free_fits_desc(&desc2);
00642     cpl_propertylist_delete(sub_header_data); sub_header_data = NULL;
00643     cpl_propertylist_delete(sub_header_noise); sub_header_noise = NULL;
00644     cpl_propertylist_delete(spec_header); spec_header = NULL;
00645     cpl_imagelist_delete(data_in); data_in = NULL;
00646     cpl_imagelist_delete(noise_in); noise_in = NULL;
00647     cpl_image_delete(data_out); data_out = NULL;
00648     cpl_image_delete(noise_out); noise_out = NULL;
00649     cpl_vector_delete(spec_data_in); spec_data_in = NULL;
00650     cpl_vector_delete(spec_lambda_in); spec_lambda_in = NULL;
00651     cpl_vector_delete(ranges); ranges = NULL;
00652 
00653     return ret_val;
00654 }
00655