KMOS Pipeline Reference Manual  1.1.0
kmo_multi_reconstruct.c
00001 /* $Id: kmo_multi_reconstruct.c,v 1.25 2013/03/18 11:52:13 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/03/18 11:52:13 $
00024  * $Revision: 1.25 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 #include <string.h>
00033 #include <math.h>
00034 
00035 #include <cpl.h>
00036 #include <cpl_wcs.h>
00037 
00038 #include "kmo_debug.h"
00039 #include "kmo_utils.h"
00040 #include "kmo_dfs.h"
00041 #include "kmo_error.h"
00042 #include "kmo_priv_functions.h"
00043 #include "kmo_cpl_extensions.h"
00044 #include "kmo_constants.h"
00045 #include "kmo_priv_multi_reconstruct.h"
00046 #include "kmo_priv_reconstruct.h"
00047 
00048 static int kmo_multi_reconstruct_create(cpl_plugin *);
00049 static int kmo_multi_reconstruct_exec(cpl_plugin *);
00050 static int kmo_multi_reconstruct_destroy(cpl_plugin *);
00051 static int kmo_multi_reconstruct(cpl_parameterlist *, cpl_frameset *);
00052 
00053 static char kmo_multi_reconstruct_description[] =
00054 "This recipe shifts several exposures of an object and combines them. The diffe-\n"
00055 "rent methods to match the exposures are described below (--smethod parameter).\n"
00056 "The output cube is larger than the input cubes, according to the shifts to be\n"
00057 "applied. Additionally a border of NaN values is added. The WCS is the same as\n"
00058 "for the first exposure.\n"
00059 "For each spatial/spectral pixel a new value will be calculated (according the\n"
00060 "--cmethod parameter) and written into the output cube.\n"
00061 "Only exposures with equal orientation regarding the WCS can be combined (except\n"
00062 "-–smethod=”none”), north must point to the same direction. It is recommended to\n"
00063 "apply any rotation possibly after combining.\n"
00064 "The default mapping mode is done via the --name parameter, where the name of\n"
00065 "the object has to be provided. The recipe searches in all input data cubes IFUs\n"
00066 "pointing to that object.\n"
00067 "\n"
00068 "BASIC PARAMETERS:\n"
00069 "-----------------\n"
00070 "--name\n"
00071 "--ifus\n"
00072 "Since an object can be present only once per exposure and since it can be\n"
00073 "located in different IFUs for the existing exposures, there are two modes to\n"
00074 "identify the objects:\n"
00075 "   * Combine by object names (default)\n"
00076 "   In this case the object name must be provided via the --name parameter. The\n"
00077 "   object name will be searched for in all primary headers of all provided frames\n"
00078 "   in the keyword ESO OCS ARMx NAME.\n"
00079 "\n"
00080 "   * Combine by index (advanced)\n"
00081 "   In this case the --ifus parameter must be provided. The parameter must have\n"
00082 "   the same number of entries as frames are provided, e.g. \"3;1;24\" for 3 expo-\n"
00083 "   sures. The index doesn't reference the extension in the frame but the real\n"
00084 "   index of the IFU as defined in the EXTNAME keyword (e.g. 'IFU.3.DATA').\n"
00085 "\n"
00086 "--smethod\n"
00087 "There are following sources to get the shift parameters from:\n"
00088 "   * 'none' (default)\n"
00089 "   The cubes are directly recombined, not shifting at all. The ouput frame will\n"
00090 "   have the same dimensions as the input cubes.\n"
00091 "   If the size differs a warning will be emitted and the cubes will be aligned\n"
00092 "   to the lower left corner. If the orientation differs a warning will be emit-\n"
00093 "   ted, but the cubes are combined anyway.\n"
00094 "\n"
00095 "   * 'header'\n"
00096 "   The shifts are calculated according to the WCS information stored in the\n"
00097 "   header of every IFU. The output frame will get larger, except the object is\n"
00098 "   at the exact same position for all exposures. The size of the exposures can\n"
00099 "   differ, but the orientation must be the same for all exposures.\n"
00100 "\n"
00101 "   * 'user'\n"
00102 "   Read the shifts from a user specified file. The path of the file must be pro-\n"
00103 "   vided using the --filename parameter. For every exposure (except the first one)\n"
00104 "   two shift values are expected per line, they have to be separated with simple\n"
00105 "   spaces. The values indicate pixel shifts and are referenced to the first\n"
00106 "   frame. The 1st value is the shift in x-direction to the left, the 2nd the\n"
00107 "   shift in y-direction upwards. The size of the exposures can differ, but the\n"
00108 "   orientation must be the same for all exposures.\n"
00109 "\n"
00110 "   * 'center'\n"
00111 "   The shifts are calculated using a centering algorithm. The detector exposures\""
00112 "   will be reconstructed and the resulting data cubes will be collapsed to an image.\n"
00113 "   A 2D profile of the image will be fitted to it to identify the centre. With \n"
00114 "   the parameter --fmethod the function to fit can be provided. The size of the\n"
00115 "   exposures can differ, but the orientation must be the same for all exposures.\n"
00116 "\n"
00117 "--fmethod\n"
00118 "The type of function that should be fitted spatially to the collapsed image.\n"
00119 "This fit is used to create a mask to extract the spectrum of the object. Valid\n"
00120 "values are “gauss” and “moffat”.\n"
00121 "\n"
00122 "ADVANCED PARAMETERS\n"
00123 "-------------------\n"
00124 "--b_samples\n"
00125 "The number of samples in spectral direction for the reconstructed cube. Ideal-\n"
00126 "ly this number should be greater than 2048, the detector size.\n"
00127 "\n"
00128 "--b_start\n"
00129 "--b_end\n"
00130 "Used to define manually the start and end wavelength for the reconstructed\n"
00131 "cube. By default the internally defined values are used.\n"
00132 "\n"
00133 "-------------------------------------------------------------------------------\n"
00134 "  Input files:\n"
00135 "\n"
00136 "   DO            DO      KMOS                                                  \n"
00137 "   category      group   Type   Explanation                    Required #Frames\n"
00138 "   --------      -----   -----  -----------                    -------- -------\n"
00139 "   OBJECT or             RAW    The science frames                Y      >=2   \n"
00140 "   STD                   RAW                                                   \n"
00141 "   XCAL                  F2D    x calibration frame               Y       1    \n"
00142 "   YCAL                  F2D    y calibration frame               Y       1    \n"
00143 "   LCAL                  F2D    Wavelength calib. frame           Y       1    \n"
00144 "   WAVE_BAND             F2L    Table with start-/end-wavelengths Y       1    \n"
00145 "\n"
00146 "  Output files:\n"
00147 "\n"
00148 "   DO                    KMOS\n"
00149 "   category              Type   Explanation\n"
00150 "   --------              -----  -----------\n"
00151 "   SCI_COMBINED          F3I    Combined cubes with noise\n"
00152 "   SCI_RECONSTRUCTED     F3I    Reconstructed cube with noise\n"
00153 
00154 
00155 
00156 "   <none or any>   -     F3I    data frame                         Y      2-n  \n"
00157 "   WAVE_BAND             F2L    Table with start-/end-wavelengths  Y       1   \n"
00158 "\n"
00159 "  Output files:\n"
00160 "\n"
00161 "   DO                    KMOS\n"
00162 "   category              Type   Explanation\n"
00163 "   --------              -----  -----------\n"
00164 "   CUBE_MULTI_<name/ifu> F3I    Combined data cube\n"
00165 "-------------------------------------------------------------------------------\n"
00166 "\n";
00167 
00184 int cpl_plugin_get_info(cpl_pluginlist *list)
00185 {
00186     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00187     cpl_plugin *plugin = &recipe->interface;
00188 
00189     cpl_plugin_init(plugin,
00190                         CPL_PLUGIN_API,
00191                         KMOS_BINARY_VERSION,
00192                         CPL_PLUGIN_TYPE_RECIPE,
00193                         "kmo_multi_reconstruct",
00194                         "Combine reconstructed cubes",
00195                         kmo_multi_reconstruct_description,
00196                         "Alex Agudo Berbel",
00197                         "agudo@mpe.mpg.de",
00198                         kmos_get_license(),
00199                         kmo_multi_reconstruct_create,
00200                         kmo_multi_reconstruct_exec,
00201                         kmo_multi_reconstruct_destroy);
00202 
00203     cpl_pluginlist_append(list, plugin);
00204 
00205     return 0;
00206 }
00207 
00215 static int kmo_multi_reconstruct_create(cpl_plugin *plugin)
00216 {
00217     cpl_recipe *recipe;
00218     cpl_parameter *p;
00219 
00220     /* Check that the plugin is part of a valid recipe */
00221     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00222         recipe = (cpl_recipe *)plugin;
00223     else
00224         return -1;
00225 
00226     /* Create the parameters list in the cpl_recipe object */
00227     recipe->parameters = cpl_parameterlist_new();
00228 
00229     /* Fill the parameters list */
00230     /* --name */
00231     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.name",
00232                                 CPL_TYPE_STRING,
00233                                 "Name of the object to combine.",
00234                                 "kmos.kmo_multi_reconstruct",
00235                                 "");
00236     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
00237     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00238     cpl_parameterlist_append(recipe->parameters, p);
00239 
00240     /* --ifus */
00241     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.ifus",
00242                                 CPL_TYPE_STRING,
00243                                 "The indices of the IFUs to combine. "
00244                                 "\"ifu1;ifu2;...\"",
00245                                 "kmos.kmo_multi_reconstruct",
00246                                 "");
00247     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
00248     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00249     cpl_parameterlist_append(recipe->parameters, p);
00250 
00251     /* --size */
00252     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.size",
00253                                 CPL_TYPE_STRING,
00254                                 "Spatial size of the output cube.",
00255                                 "kmos.kmo_multi_reconstruct",
00256                                 "max");
00257     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "size");
00258     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00259     cpl_parameterlist_append(recipe->parameters, p);
00260 
00261 
00262     /* --smethod  shift method*/
00263     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.smethod",
00264                                 CPL_TYPE_STRING,
00265                                 "The shifting method:   "
00266                                 "'none': no shifting, combined directly "
00267                                                                   "(default), "
00268                                 "'header': shift according to WCS, "
00269                                 "'center': centering algorithm, "
00270                                 "'user': read shifts from file",
00271                                 "kmos.kmo_multi_reconstruct",
00272                                 "none");
00273     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "smethod");
00274     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00275     cpl_parameterlist_append(recipe->parameters, p);
00276 
00277     /* --fmethod */
00278     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.fmethod",
00279                                 CPL_TYPE_STRING,
00280                                 "The fitting method (applies only when "
00281                                 "method='center'):   "
00282                                 "'gauss': fit a gauss function to collapsed "
00283                                 "image (default), "
00284                                 "'moffat': fit a moffat function to collapsed"
00285                                 " image",
00286                                 "kmos.kmo_combine",
00287                                 "gauss");
00288     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
00289     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00290     cpl_parameterlist_append(recipe->parameters, p);
00291 
00292     /* --imethod interpolation method */
00293     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.imethod",
00294                                 CPL_TYPE_STRING,
00295                                 "Method to use for interpolation. "
00296                                 "[\"NN\" (nearest neighbour), "
00297                                 "\"lwNN\" (linear weighted nearest neighbor), "
00298                                 "\"swNN\" (square weighted nearest neighbor), "
00299                                 "\"MS\" (Modified Shepard's method)"
00300                                 "\"CS\" (Cubic spline)]",
00301                                 "kmos.kmo_multi_reconstruct",
00302                                 "NN");
00303     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00304     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00305     cpl_parameterlist_append(recipe->parameters, p);
00306 
00307     /* --neighborhoodRange */
00308     p = cpl_parameter_new_value("kmos.kmo_reconstruct.neighborhoodRange",
00309                                 CPL_TYPE_DOUBLE,
00310                                 "Defines the range to search for neighbors. "
00311                                 "in pixels",
00312                                 "kmos.kmo_reconstruct",
00313                                 1.001);
00314     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
00315     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00316     cpl_parameterlist_append(recipe->parameters, p);
00317 
00318     /* --filename */
00319     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.filename",
00320                                 CPL_TYPE_STRING,
00321                                 "The path to the file with the shift vectors."
00322                                 "(Applies only to smethod='user')",
00323                                 "kmos.kmo_multi_reconstruct",
00324                                 "");
00325     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
00326     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00327     cpl_parameterlist_append(recipe->parameters, p);
00328 
00329     // add parameters for band-definition
00330     kmo_band_pars_create(recipe->parameters,
00331                          "kmos.kmo_multi_reconstruct");
00332 
00333     return kmo_combine_pars_create(recipe->parameters,
00334                                    "kmos.kmo_multi_reconstruct",
00335                                    DEF_REJ_METHOD,
00336                                    FALSE);
00337 }
00338 
00344 static int kmo_multi_reconstruct_exec(cpl_plugin *plugin)
00345 {
00346     cpl_recipe  *recipe;
00347 
00348     /* Get the recipe out of the plugin */
00349     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00350         recipe = (cpl_recipe *)plugin;
00351     else return -1 ;
00352 
00353     return kmo_multi_reconstruct(recipe->parameters, recipe->frames);
00354 }
00355 
00361 static int kmo_multi_reconstruct_destroy(cpl_plugin *plugin)
00362 {
00363     cpl_recipe *recipe;
00364 
00365     /* Get the recipe out of the plugin */
00366     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00367         recipe = (cpl_recipe *)plugin;
00368     else return -1 ;
00369 
00370     cpl_parameterlist_delete(recipe->parameters);
00371     return 0 ;
00372 }
00373 
00374 //int kmo_tolerance_round(double x, double tol)
00375 //{
00376 //    int ret = 0;
00377 
00378 //    KMO_TRY
00379 //    {
00380 //        if (fabs(x - floor(x)) < tol) {
00381 //            // value is slightly greater than the real int value
00382 //            ret = floor(x);
00383 //        } else {
00384 //            if (fabs(x - floor(x+tol)) < tol) {
00385 //                // value is slightly greater than the real int value
00386 //                ret = floor(x+tol);
00387 //            } else {
00388 //                // error: sub pixel shift
00389 //                KMO_TRY_ASSURE(1 == 0,
00390 //                               CPL_ERROR_ILLEGAL_INPUT,
00391 //                               "Please apply only whole pixel shifts here "
00392 //                               "and no subpixel shifts!");
00393 //            }
00394 //        }
00395 //    }
00396 //    KMO_CATCH
00397 //    {
00398 //        KMO_CATCH_MSG();
00399 
00400 //        ret = 0;
00401 //    }
00402 
00403 //    return ret;
00404 //}
00405 
00420 static int kmo_multi_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
00421 {
00422     const char       *smethod               = NULL,
00423                      *cmethod               = NULL,
00424                      *fmethod               = NULL,
00425                      *imethod               = NULL,
00426                      *filename              = NULL,
00427                      *ifus_txt              = NULL,
00428                      *name                  = NULL,
00429                      *size                  = NULL,
00430                      *filter_id             = NULL;
00431 
00432     char             *tmp_str               = NULL,
00433                      *filename_output_cube  = NULL,
00434                      *extname               = NULL,
00435                      *keyword               = NULL,
00436                      *tmp_ocs               = NULL;
00437 
00438     cpl_imagelist    **data_cube_list       = NULL,
00439                      **noise_cube_list      = NULL,
00440                      *cube_combined_data    = NULL,
00441                      *cube_combined_noise   = NULL;
00442 
00443     cpl_vector       *ifus                  = NULL;
00444 
00445     int              ret_val                = 0,
00446                      nr_exposures           = 0,
00447                      device_nr              = 0,
00448                      citer                  = 0,
00449                      cmin                   = 0,
00450                      cmax                   = 0,
00451                      nr_alloc               = 0;
00452 
00453     double           neighborhoodRange      = 1.001,
00454                      cpos_rej               = 0.0,
00455                      cneg_rej               = 0.0;
00456 
00457     char             **exposure_filename    = NULL,
00458                      **exposure_objectname  = NULL;
00459     int              *exposure_ifus         = NULL,
00460                      nr_object_frames       = 0,
00461                      nr_std_frames          = 0;
00462 
00463     double           *xshifts               = NULL,
00464                      *yshifts               = NULL,
00465                      cd1_1                  = 0.0,
00466                      cd1_2                  = 0.0,
00467                      ang1                   = 0.0,
00468                      ang2                   = 0.0,
00469                      exposure_rotangle      = 0.0;
00470 
00471     cpl_propertylist *pl                    = NULL,
00472                      *main_header           = NULL,
00473                      *ref_main_header       = NULL,
00474                      *ref_sub_header        = NULL,
00475                      *tmp_header            = NULL,
00476                      **header_data          = NULL,
00477                      **data_header_list     = NULL,
00478                      **noise_header_list    = NULL;
00479 
00480     cpl_frame        *frame                 = NULL,
00481                      *lcal_frame            = NULL;
00482 
00483     cpl_table        *band_table            = NULL;
00484 
00485     cpl_image        *lcalImg               = NULL;
00486 
00487     main_fits_desc   desc;
00488 
00489     cpl_frameset     *exposures             = NULL;
00490 
00491     cpl_frame        **empty_frames         = NULL,
00492                      *tmp_frame             = NULL,
00493                      *ref_frame             = NULL;
00494 
00495     gridDefinition   gd;
00496 
00497     KMO_TRY
00498     {
00499         /* --- check input --- */
00500         KMO_TRY_ASSURE((parlist != NULL) &&
00501                        (frameset != NULL),
00502                        CPL_ERROR_NULL_INPUT,
00503                        "Not all input data is provided!");
00504 
00505         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_multi_reconstruct") == 1,
00506                        CPL_ERROR_ILLEGAL_INPUT,
00507                        "Cannot identify RAW and CALIB frames!");
00508 
00509         KMO_TRY_ASSURE(! ((cpl_frameset_count_tags(frameset, XCAL) == 0) &&
00510                           (cpl_frameset_count_tags(frameset, YCAL) == 0) &&
00511                           (cpl_frameset_count_tags(frameset, LCAL) == 0) &&
00512                           (cpl_frameset_count_tags(frameset, WAVE_BAND) == 0)),
00513                           CPL_ERROR_FILE_NOT_FOUND,
00514                           "XCAL, YCAL, LCAL or WAVE_BAND frames missing in "
00515                           "frameset!!");
00516 
00517         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00518                        CPL_ERROR_FILE_NOT_FOUND,
00519                        "Exactly one XCAL frame is expected in frameset!");
00520 
00521         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00522                        CPL_ERROR_FILE_NOT_FOUND,
00523                        "Exactly one YCAL frame is expected in frameset!");
00524 
00525         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00526                        CPL_ERROR_FILE_NOT_FOUND,
00527                        "Exactly one LCAL frame is expected in frameset!");
00528 
00529         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00530                        CPL_ERROR_FILE_NOT_FOUND,
00531                        "Exactly one WAVE_BAND frame is expected in frameset!");
00532 
00533         // assert that at least two OBJECT or STD frames are available and create
00534         // intermediate frameset just with these science frames
00535         nr_object_frames = cpl_frameset_count_tags(frameset, OBJECT);
00536         nr_std_frames = cpl_frameset_count_tags(frameset, STD);
00537         KMO_TRY_CHECK_ERROR_STATE();
00538         nr_exposures = nr_object_frames + nr_std_frames;
00539 
00540         KMO_TRY_ASSURE(((nr_object_frames > 1) && (nr_std_frames == 0)) ||
00541                        ((nr_object_frames == 0) && (nr_std_frames > 1)),
00542                        CPL_ERROR_ILLEGAL_INPUT,
00543                        "OBJECT and STD frames mustn't be intermixed and at "
00544                        "least two frames (OBJECT or STD) must be provided "
00545                        "to combine!");
00546         KMO_TRY_EXIT_IF_NULL(
00547             exposures = cpl_frameset_new());
00548         if (nr_object_frames > 1) {
00549             KMO_TRY_EXIT_IF_NULL(
00550                 tmp_frame = kmo_dfs_get_frame(frameset, OBJECT));
00551         } else {
00552             KMO_TRY_EXIT_IF_NULL(
00553                 tmp_frame = kmo_dfs_get_frame(frameset, STD));
00554         }
00555 
00556         for (int i = 0; i < nr_exposures; i++) {
00557             KMO_TRY_EXIT_IF_ERROR(
00558                 cpl_frameset_insert(exposures, cpl_frame_duplicate(tmp_frame)));
00559             KMO_TRY_CHECK_ERROR_STATE();
00560 
00561             tmp_frame = kmo_dfs_get_frame(frameset, NULL);
00562         }
00563 
00564         cpl_msg_info("", "--- Parameter setup for kmo_multi_reconstruct -------");
00565 
00566         KMO_TRY_EXIT_IF_NULL(
00567             imethod = kmo_dfs_get_parameter_string(parlist,
00568                                          "kmos.kmo_multi_reconstruct.imethod"));
00569 
00570         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00571                        (strcmp(imethod, "lwNN") == 0) ||
00572                        (strcmp(imethod, "swNN") == 0) ||
00573                        (strcmp(imethod, "MS") == 0) ||
00574                        (strcmp(imethod, "CS") == 0),
00575                        CPL_ERROR_ILLEGAL_INPUT,
00576                        "imethod must be either \"NN\", \"lwNN\", "
00577                        "\"swNN\", \"MS\" or \"CS\"!");
00578 
00579         KMO_TRY_EXIT_IF_ERROR(
00580             kmo_dfs_print_parameter_help(parlist,
00581                                         "kmos.kmo_multi_reconstruct.imethod"));
00582 
00583         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00584                 "kmos.kmo_reconstruct.neighborhoodRange");
00585         KMO_TRY_CHECK_ERROR_STATE();
00586 
00587         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00588                        CPL_ERROR_ILLEGAL_INPUT,
00589                        "neighborhoodRange must be greater than 0.0");
00590 
00591         KMO_TRY_EXIT_IF_ERROR(
00592             kmo_dfs_print_parameter_help(parlist,
00593                                      "kmos.kmo_reconstruct.neighborhoodRange"));
00594 
00595         KMO_TRY_EXIT_IF_NULL(
00596             size = kmo_dfs_get_parameter_string(parlist,
00597                                             "kmos.kmo_multi_reconstruct.size"));
00598 
00599         KMO_TRY_EXIT_IF_NULL(
00600             smethod = kmo_dfs_get_parameter_string(parlist,
00601                                          "kmos.kmo_multi_reconstruct.smethod"));
00602 
00603         KMO_TRY_EXIT_IF_NULL(
00604             fmethod = kmo_dfs_get_parameter_string(parlist,
00605                                          "kmos.kmo_multi_reconstruct.fmethod"));
00606 
00607         KMO_TRY_ASSURE((strcmp(size, "max") == 0) ||
00608                        (strcmp(size, "std") == 0),
00609                        CPL_ERROR_ILLEGAL_INPUT,
00610                        "Following output cube size specifications are available: "
00611                        "'std' or 'max'");
00612 
00613 
00614         KMO_TRY_ASSURE((strcmp(smethod, "none") == 0) ||
00615                        (strcmp(smethod, "header") == 0) ||
00616                        (strcmp(smethod, "center") == 0) ||
00617                        (strcmp(smethod, "user") == 0),
00618                        CPL_ERROR_ILLEGAL_INPUT,
00619                        "Following shift methods are available : 'none', "
00620                        "'header', 'center' or 'user'");
00621 
00622         if (strcmp(smethod, "user") == 0) {
00623             filename = kmo_dfs_get_parameter_string(parlist,
00624                                          "kmos.kmo_multi_reconstruct.filename");
00625             KMO_TRY_CHECK_ERROR_STATE();
00626 
00627             KMO_TRY_ASSURE(strcmp(filename, "") != 0,
00628                            CPL_ERROR_ILLEGAL_INPUT,
00629                            "path of file with shift information must be "
00630                            "provided!");
00631 
00632             KMO_TRY_EXIT_IF_ERROR(
00633                 kmo_dfs_print_parameter_help(parlist,
00634                                         "kmos.kmo_multi_reconstruct.filename"));
00635         }
00636 
00637         KMO_TRY_EXIT_IF_ERROR(
00638             kmo_dfs_print_parameter_help(parlist,
00639                                          "kmos.kmo_multi_reconstruct.smethod"));
00640 
00641         ifus_txt = kmo_dfs_get_parameter_string(parlist,
00642                                              "kmos.kmo_multi_reconstruct.ifus");
00643         KMO_TRY_CHECK_ERROR_STATE();
00644 
00645         name = kmo_dfs_get_parameter_string(parlist,
00646                                             "kmos.kmo_multi_reconstruct.name");
00647         KMO_TRY_CHECK_ERROR_STATE();
00648 
00649         if (strcmp(ifus_txt, "") != 0) {
00650             KMO_TRY_ASSURE(strcmp(name, "") == 0,
00651                            CPL_ERROR_ILLEGAL_INPUT,
00652                            "name parameter must be NULL if IFU indices are "
00653                            "provided!");
00654 
00655             KMO_TRY_EXIT_IF_NULL(
00656                 ifus = kmo_identify_values(ifus_txt));
00657 
00658             KMO_TRY_ASSURE(cpl_vector_get_size(ifus) == nr_exposures,
00659                            CPL_ERROR_ILLEGAL_INPUT,
00660                            "ifus parameter must have the same number of values "
00661                            "than frames provided ) (%lld!=%d)",
00662                            cpl_vector_get_size(ifus), nr_exposures);
00663 
00664             for (int i = 0; i < nr_exposures; i++) {
00665                 KMO_TRY_ASSURE((cpl_vector_get(ifus, i) > 0.5 &&
00666                                cpl_vector_get(ifus, i) < 24.5 ),
00667                                CPL_ERROR_ILLEGAL_INPUT,
00668                                "IFU numbers must be in the range 1..24");
00669             }
00670         }
00671 
00672         if (strcmp(name, "") != 0) {
00673             KMO_TRY_ASSURE(strcmp(ifus_txt, "") == 0,
00674                            CPL_ERROR_ILLEGAL_INPUT,
00675                            "ifus parameter must be NULL if name is provided!");
00676         }
00677 
00678         KMO_TRY_ASSURE((strcmp(name, "") != 0) || (strcmp(ifus_txt, "") != 0),
00679                        CPL_ERROR_ILLEGAL_INPUT,
00680                        "Either the name of the object or the numbers of the "
00681                        "IFUs to combine must be provided (--name or --ifus "
00682                        "parameters)");
00683 
00684         KMO_TRY_EXIT_IF_ERROR(
00685             kmo_dfs_print_parameter_help(parlist,
00686                                          "kmos.kmo_multi_reconstruct.ifus"));
00687 
00688         KMO_TRY_EXIT_IF_ERROR(
00689             kmo_dfs_print_parameter_help(parlist,
00690                                          "kmos.kmo_multi_reconstruct.name"));
00691 
00692         KMO_TRY_EXIT_IF_ERROR(
00693             kmo_combine_pars_load(parlist,
00694                                   "kmos.kmo_multi_reconstruct",
00695                                   &cmethod,
00696                                   &cpos_rej,
00697                                   &cneg_rej,
00698                                   &citer,
00699                                   &cmin,
00700                                   &cmax,
00701                                   FALSE));
00702 
00703         kmo_band_pars_load(parlist, "kmos.kmo_multi_reconstruct");
00704 
00705         cpl_msg_info("", "-------------------------------------------");
00706 
00707         // assure that filters and grating  match for
00708         // XCAL, YCAL, LCAL and for data frames to reconstruct
00709         KMO_TRY_EXIT_IF_ERROR(
00710             kmo_check_frameset_setup(frameset, XCAL,
00711                                        TRUE, FALSE, FALSE));
00712         KMO_TRY_EXIT_IF_ERROR(
00713             kmo_check_frameset_setup(frameset, YCAL,
00714                                        TRUE, FALSE, FALSE));
00715         KMO_TRY_EXIT_IF_ERROR(
00716             kmo_check_frameset_setup(frameset, LCAL,
00717                                        TRUE, FALSE, FALSE));
00718         KMO_TRY_EXIT_IF_ERROR(
00719             kmo_check_frame_setup(frameset, XCAL, YCAL,
00720                                        TRUE, FALSE, TRUE));
00721         KMO_TRY_EXIT_IF_ERROR(
00722             kmo_check_frame_setup(frameset, XCAL, LCAL,
00723                                        TRUE, FALSE, TRUE));
00724         if (nr_object_frames > 1) {
00725             KMO_TRY_EXIT_IF_ERROR(
00726                 kmo_check_frameset_setup(frameset, OBJECT,
00727                                            TRUE, FALSE, FALSE));
00728             KMO_TRY_EXIT_IF_ERROR(
00729                 kmo_check_frame_setup(frameset, XCAL, OBJECT,
00730                                            TRUE, FALSE, TRUE));
00731         } else {
00732             KMO_TRY_EXIT_IF_ERROR(
00733                 kmo_check_frameset_setup(frameset, STD,
00734                                            TRUE, FALSE, FALSE));
00735             KMO_TRY_EXIT_IF_ERROR(
00736                 kmo_check_frame_setup(frameset, XCAL, STD,
00737                                            TRUE, FALSE, TRUE));
00738         }
00739 
00740         KMO_TRY_EXIT_IF_ERROR(
00741             kmo_check_frame_setup_md5(frameset));
00742 
00743 //        KMO_TRY_EXIT_IF_ERROR(
00744 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00745 //        KMO_TRY_EXIT_IF_ERROR(
00746 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00747 
00748 
00749         nr_alloc = nr_exposures;
00750         KMO_TRY_EXIT_IF_NULL(
00751             exposure_filename = cpl_malloc(nr_alloc * sizeof(char *)));
00752         KMO_TRY_EXIT_IF_NULL(
00753             exposure_objectname = cpl_malloc(nr_alloc * sizeof(char *)));
00754         KMO_TRY_EXIT_IF_NULL(
00755             exposure_ifus  = cpl_malloc(nr_alloc * sizeof(int)));
00756 
00757         // check exposure frames
00758         for (int i = 0; i < nr_exposures; i++) {
00759             KMO_TRY_EXIT_IF_NULL(
00760                 tmp_str = cpl_sprintf("%d", i));
00761 
00762             KMO_TRY_EXIT_IF_NULL(
00763                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00764             cpl_free(tmp_str);
00765 
00766             KMO_TRY_EXIT_IF_NULL(
00767                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00768 
00769             kmo_init_fits_desc(&desc);
00770 
00771             desc = kmo_identify_fits_header(exposure_filename[i]);
00772             KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to "
00773                                           "be in KMOS-format!");
00774 
00775             KMO_TRY_ASSURE(((desc.nr_ext == KMOS_NR_DETECTORS) ||
00776                             ((desc.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00777                            (desc.ex_badpix == FALSE) &&
00778                            ((desc.fits_type == raw_fits) ||
00779                             (desc.fits_type == f2d_fits)) &&
00780                            (desc.frame_type == detector_frame),
00781                            CPL_ERROR_ILLEGAL_INPUT,
00782                            "The frame to reconstruct isn't in the correct "
00783                            "format!!!");
00784             kmo_free_fits_desc(&desc);
00785         }
00786 
00787         // select IFU for each exposure
00788         KMO_TRY_EXIT_IF_NULL(
00789             empty_frames = cpl_malloc(nr_alloc * sizeof(cpl_frame *)));
00790         int found=0;
00791         for (int i = 0; i < nr_exposures; i++) {
00792             empty_frames[i] = NULL;
00793             if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
00794                 found = 1;
00795                 const char *tmpString;
00796                 exposure_ifus[i] = (int) (cpl_vector_get(ifus, i) + 0.1);
00797                 KMO_TRY_EXIT_IF_NULL(
00798                     pl = kmclipm_propertylist_load(exposure_filename[i], 0));
00799                 KMO_TRY_EXIT_IF_NULL(
00800                     tmp_ocs = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX,
00801                                           exposure_ifus[i], IFU_NAME_POSTFIX));
00802                 if (cpl_propertylist_has(pl, tmp_ocs)) {
00803                     tmpString = cpl_propertylist_get_string(pl, tmp_ocs);
00804                 } else {
00805                     tmpString = "";
00806                 }
00807                 cpl_free(tmp_ocs);
00808                 int len = strlen(tmpString);
00809                 const int maxLen = 40;
00810                 if (len > maxLen) {
00811                     len = maxLen;
00812                 }
00813                 exposure_objectname[i] = (char *) cpl_malloc(len * sizeof(char));
00814                 strncpy(exposure_objectname[i], tmpString, len-1);
00815                 if (len > 0) {
00816                     (exposure_objectname[i])[len-1] = '\0';
00817                 }
00818                 cpl_propertylist_delete(pl); pl = NULL;
00819             }  else {                   //IFU selected by user given object name
00820                 exposure_objectname[i] = (char*)name;
00821                 KMO_TRY_EXIT_IF_NULL(
00822                     tmp_str = cpl_sprintf("%d", i));
00823 
00824                 KMO_TRY_EXIT_IF_NULL(
00825                     frame = kmo_dfs_get_frame(exposures, tmp_str));
00826                 cpl_free(tmp_str);
00827 
00828                 KMO_TRY_CHECK_ERROR_STATE();
00829                 int this_ifu = kmo_get_index_from_ocs_name(frame, name);
00830                 KMO_TRY_CHECK_ERROR_STATE();
00831                 if (this_ifu > 0) {
00832                     found = 1;
00833                     exposure_ifus[i] = this_ifu;
00834                 } else {
00835                     empty_frames[i] = frame;
00836                     exposure_ifus[i] = -1;
00837                     cpl_msg_warning("",
00838                                     "Could not find any IFU with an object "
00839                                     "named '%s' in file %s",
00840                                     name, exposure_filename[i]);
00841                 }
00842             }
00843             KMO_TRY_CHECK_ERROR_STATE();
00844         }
00845         if (! found) {
00846             cpl_msg_error("",
00847                           "Could not find any IFU with an object named '%s' in "
00848                           "any input file", name);
00849             KMO_TRY_EXIT_WITH_ERROR(CPL_ERROR_ILLEGAL_INPUT);
00850         }
00851         int j = 0;
00852         for (int i = 0; i < nr_alloc; i++) {
00853             if (empty_frames[i] != NULL) {
00854                 KMO_TRY_EXIT_IF_ERROR(
00855                     cpl_frameset_erase_frame(exposures, empty_frames[i]));
00856                 nr_exposures--;
00857                 exposure_ifus[j] = exposure_ifus[i];
00858             } else {
00859                 exposure_ifus[j] = exposure_ifus[i];
00860                 j++;
00861             }
00862         }
00863         for (int i = 0; i < nr_exposures; i++) {
00864             KMO_TRY_EXIT_IF_NULL(
00865                 tmp_str = cpl_sprintf("%d", i));
00866 
00867             KMO_TRY_EXIT_IF_NULL(
00868                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00869             cpl_free(tmp_str);
00870 
00871             KMO_TRY_EXIT_IF_NULL(
00872                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00873         }
00874 
00875         cpl_free(empty_frames); empty_frames = NULL;
00876 
00877         // get reference header, subheader and set grid definition
00878         device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00879 
00880         KMO_TRY_EXIT_IF_NULL(
00881             ref_main_header = kmclipm_propertylist_load(exposure_filename[0],0));
00882         KMO_TRY_EXIT_IF_NULL(
00883             ref_frame = cpl_frameset_get_first(exposures));
00884         KMO_TRY_EXIT_IF_NULL(
00885             ref_sub_header = kmclipm_propertylist_load(exposure_filename[0],
00886                                                        device_nr));
00887         KMO_TRY_EXIT_IF_ERROR(
00888             kmclipm_setup_grid(&gd, imethod, neighborhoodRange));
00889 
00890         exposure_rotangle = kmo_mr_get_rot_angle(kmo_dfs_get_frame(exposures, "0"));
00891         KMO_TRY_EXIT_IF_NULL(
00892             lcal_frame = kmo_mr_get_closest_cal_frame(frameset, LCAL,
00893                                                       exposure_rotangle));
00894         KMO_TRY_EXIT_IF_NULL(
00895             lcalImg = kmo_dfs_load_image_frame(lcal_frame, device_nr, 0,
00896                                                FALSE, NULL));
00897 
00898         KMO_TRY_EXIT_IF_NULL(
00899             tmp_header = kmclipm_propertylist_load(
00900                                         cpl_frame_get_filename(lcal_frame), 0));
00901         KMO_TRY_EXIT_IF_NULL(
00902             keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, device_nr,
00903                                   IFU_FILTID_POSTFIX));
00904         KMO_TRY_EXIT_IF_NULL(
00905             filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00906 
00907         int band_method = 0;
00908         KMO_TRY_EXIT_IF_NULL(
00909             band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0));
00910 
00911         KMO_TRY_EXIT_IF_ERROR(
00912             kmclipm_setup_grid_band_lcal(&gd, lcalImg, filter_id,
00913                                          band_method, band_table));
00914         cpl_image_delete(lcalImg); lcalImg = NULL;
00915         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00916         cpl_free(keyword); keyword = NULL;
00917         cpl_table_delete(band_table); band_table = NULL;
00918 
00919         //extract sub-headers for each exposures, calculate WCS
00920         KMO_TRY_EXIT_IF_NULL(
00921             header_data = cpl_malloc(nr_exposures*sizeof(cpl_propertylist*)));
00922         for (int i = 0; i < nr_exposures; i++) {
00923            device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00924            KMO_TRY_EXIT_IF_NULL(
00925                header_data[i] = kmclipm_propertylist_load(exposure_filename[i],
00926                                                           device_nr));
00927            KMO_TRY_EXIT_IF_ERROR(
00928                 kmclipm_update_property_int(header_data[i],"NAXIS", 3,""));
00929            KMO_TRY_EXIT_IF_ERROR(
00930                 kmclipm_update_property_int(header_data[i],"NAXIS1",gd.x.dim,""));
00931            KMO_TRY_EXIT_IF_ERROR(
00932                 kmclipm_update_property_int(header_data[i],"NAXIS2",gd.y.dim,""));
00933            KMO_TRY_EXIT_IF_ERROR(
00934                 kmclipm_update_property_int(header_data[i],"NAXIS3",gd.l.dim,""));
00935            cpl_propertylist *tmpHeader;
00936            KMO_TRY_EXIT_IF_NULL(
00937                 tmpHeader = kmclipm_propertylist_load(exposure_filename[i],0));
00938            KMO_TRY_EXIT_IF_ERROR(
00939                 kmo_calc_wcs(tmpHeader, header_data[i],
00940                              exposure_ifus[i], gd.l.start, gd.l.delta));
00941            cpl_propertylist_delete(tmpHeader);
00942         }
00943 
00944         // check rotation angle
00945         cd1_1 = kmo_dfs_get_property_double(header_data[0], CD1_1);
00946         cd1_2 = kmo_dfs_get_property_double(header_data[0], CD1_2);
00947         KMO_TRY_CHECK_ERROR_STATE();
00948         ang1 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
00949         for (int i = 1; i < nr_exposures; i++) {
00950             cd1_1 = kmo_dfs_get_property_double(header_data[i], CD1_1);
00951             cd1_2 = kmo_dfs_get_property_double(header_data[i], CD1_2);
00952             KMO_TRY_CHECK_ERROR_STATE();
00953             ang2 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
00954 
00955             if (strcmp(smethod, "none") != 0) {
00956                 // center, header, user
00957                 KMO_TRY_ASSURE(fabs(ang1-ang2) <= 0.5,
00958                                CPL_ERROR_ILLEGAL_INPUT,
00959                                "Orientation of cube 1 (%gdeg) and cube %d "
00960                                "(%gdeg) differ! "
00961                                "Align the orientation of this cube with "
00962                                "kmo_rotate before applying this recipe.",
00963                                ang1, i+1, ang2);
00964             } else {
00965                 // none
00966                 if (fabs(ang1-ang2) > 0.5) {
00967                     cpl_msg_warning("",
00968                                     "Orientation of cube 1 (%gdeg) and cube %d "
00969                                     "(%gdeg) differ! Processing anyway.",
00970                                     ang1, i+1, ang2);
00971                 }
00972             }
00973         }
00974 
00975         // set x/y shifts
00976         KMO_TRY_EXIT_IF_NULL(
00977             xshifts = cpl_malloc(nr_exposures * sizeof(double)));
00978         KMO_TRY_EXIT_IF_NULL(
00979             yshifts = cpl_malloc(nr_exposures * sizeof(double)));
00980         KMO_TRY_EXIT_IF_ERROR(
00981             kmo_mr_get_offsets(nr_exposures, smethod, imethod, neighborhoodRange,
00982                                filename, frameset, exposures, exposure_ifus,
00983                                (const cpl_propertylist**)header_data,
00984                                fmethod,
00985                                cmethod,
00986                                cpos_rej,
00987                                cneg_rej,
00988                                citer,
00989                                cmin,
00990                                cmax,
00991                                xshifts, yshifts));
00992 
00993         for (int i = 0; i < nr_exposures; i++) {
00994             printf("exposure %d: filename %s, selected IFU %d, object name "
00995                    "\"%s\", xshift %f, yshift %f\n", i, exposure_filename[i],
00996                    exposure_ifus[i], exposure_objectname[i], xshifts[i], yshifts[i]);
00997         }
00998 
00999         //
01000         // set spatial part of the grid
01001         //
01002 //        size = "max";
01003         if (strcmp(size, "max") == 0) {
01004             double xmin=0, xmax=0, ymin=0, ymax=0;
01005             double gxshift, gyshift, gxdim, gydim;
01006             double pixel_resolution = KMOS_PIXEL_RESOLUTION;
01007             int xdim, ydim;
01008 
01009             for (int i = 0; i < nr_exposures; i++) {
01010                 if (xmin > xshifts[i]) { xmin = xshifts[i]; }
01011                 if (xmax < xshifts[i]) { xmax = xshifts[i]; }
01012                 if (ymin > yshifts[i]) { ymin = yshifts[i]; }
01013                 if (ymax < yshifts[i]) { ymax = yshifts[i]; }
01014             }
01015             if (xmax > 0.0001) {
01016                 gxshift = - ceil(xmax);
01017             } else {
01018                 gxshift = 0.;
01019             }
01020             if (ymin < -0.0001) {
01021                 gyshift = floor(ymin);
01022             } else {
01023                 gyshift = 0.;
01024             }
01025             if (xmin < -0.0001) {
01026                 gxdim = - floor(xmin);
01027             } else {
01028                 gxdim = 0.;
01029             }
01030             if (ymax > 0.0001) {
01031                 gydim = ceil(ymax);
01032             } else {
01033                 gydim = 0.;
01034             }
01035 
01036             xdim = (int) (gxdim - gxshift + .5);
01037             ydim = (int) (gydim - gyshift + .5);
01038             gd.x.start += gxshift * pixel_resolution;
01039             gd.y.start += gyshift * pixel_resolution;
01040             gd.x.dim += xdim;
01041             gd.y.dim += ydim;
01042 //            printf("X: %f < %f      Y: %f < %f \n",xmin,xmax,ymin,ymax);
01043 //            printf("gxshift: %f  gxdim: %f   xdim: %d        gyshift: %f  gydim: %f  ydim: %d \n",
01044 //                    gxshift, gxdim, xdim, gyshift, gydim, ydim);
01045 //            printf("GD: %f  %d     %f %d\n", gd.x.start, gd.x.dim, gd.y.start, gd.y.dim);
01046         }
01047 
01048         //
01049         // reconstruct multiple detector images
01050         //
01051 
01052 //        printf("GD: %f %f %d     %f %f %d     %f %f %d\n",
01053 //                gd.x.start, gd.x.delta, gd.x.dim,
01054 //                gd.y.start, gd.y.delta, gd.y.dim,
01055 //                gd.l.start, gd.l.delta, gd.l.dim);
01056 
01057         KMO_TRY_EXIT_IF_ERROR(
01058             kmo_priv_multi_reconstruct(frameset,
01059                                        exposures,
01060                                        exposure_ifus,
01061                                        xshifts,
01062                                        yshifts,
01063                                        gd,
01064                                        &cube_combined_data,
01065                                        &cube_combined_noise));
01066 
01067         // setup output category COMBINE + ESO PRO CATG
01068         if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
01069             KMO_TRY_EXIT_IF_NULL(
01070                 tmp_str = cpl_sprintf("IFU"));
01071         } else {
01072             KMO_TRY_EXIT_IF_NULL(
01073                 tmp_str = cpl_sprintf("%s", name));
01074         }
01075 
01076         KMO_TRY_EXIT_IF_NULL(
01077             filename_output_cube = cpl_sprintf("%s_%s", CUBE_MULTI, tmp_str));
01078         cpl_free(tmp_str); tmp_str = NULL;
01079 
01080         KMO_TRY_EXIT_IF_ERROR(
01081             kmo_dfs_save_main_header(frameset, filename_output_cube, "",
01082                                      ref_frame, NULL, parlist, cpl_func));
01083         // save output
01084         KMO_TRY_EXIT_IF_NULL(
01085             extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01086                                           EXT_DATA));
01087 
01088         // calculate WCS
01089         KMO_TRY_EXIT_IF_ERROR(
01090             kmo_calc_wcs_gd(ref_main_header, ref_sub_header, exposure_ifus[0], gd));
01091 
01092         KMO_TRY_EXIT_IF_ERROR(
01093             kmclipm_update_property_string(ref_sub_header,
01094                                            EXTNAME,
01095                                            extname,
01096                                            "FITS extension name"));
01097         cpl_free(extname); extname = NULL;
01098 
01099         KMO_TRY_EXIT_IF_ERROR(
01100             kmo_dfs_save_cube(cube_combined_data, filename_output_cube,
01101                               "", ref_sub_header, 0./0.));
01102 
01103         if (cube_combined_noise != NULL) {
01104             KMO_TRY_EXIT_IF_NULL(
01105                 extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01106                                               EXT_NOISE));
01107 
01108             KMO_TRY_EXIT_IF_ERROR(
01109                 kmclipm_update_property_string(ref_sub_header,
01110                                         EXTNAME,
01111                                         extname,
01112                                         "FITS extension name"));
01113             cpl_free(extname); extname = NULL;
01114 
01115             KMO_TRY_EXIT_IF_ERROR(
01116                 kmo_dfs_save_cube(cube_combined_noise, filename_output_cube,
01117                                   "", ref_sub_header, 0./0.));
01118         }
01119     }
01120     KMO_CATCH
01121     {
01122         KMO_CATCH_MSG();
01123         ret_val = -1;
01124     }
01125 
01126     cpl_free(filename_output_cube); filename_output_cube = NULL;
01127     cpl_propertylist_delete(main_header); main_header = NULL;
01128     cpl_vector_delete(ifus); ifus = NULL;
01129     cpl_imagelist_delete(cube_combined_data); cube_combined_data = NULL;
01130     cpl_imagelist_delete(cube_combined_noise); cube_combined_noise = NULL;
01131     if (exposures != NULL) {cpl_frameset_delete(exposures);}
01132     if (exposure_filename != NULL) {cpl_free(exposure_filename);}
01133     if ((ifus_txt != NULL) && (strcmp(ifus_txt, "") != 0)) { //IFU selected by user given list
01134         for (int i = 0; i < nr_alloc; i++) {
01135             cpl_free(exposure_objectname[i]);
01136         }
01137     }
01138     if (exposure_objectname != NULL) {cpl_free(exposure_objectname);}
01139     if (exposure_ifus != NULL) {cpl_free(exposure_ifus);}
01140     if (ref_main_header != NULL) {cpl_propertylist_delete(ref_main_header);}
01141     if (ref_sub_header != NULL) {cpl_propertylist_delete(ref_sub_header);}
01142     if (xshifts != NULL) {cpl_free(xshifts);}
01143     if (yshifts != NULL) {cpl_free(yshifts);}
01144 
01145     if (data_cube_list != NULL) {
01146         for (int i = 0; i < nr_exposures; i++) {
01147             cpl_imagelist_delete(data_cube_list[i]); data_cube_list[i] = NULL;
01148         }
01149         cpl_free(data_cube_list); data_cube_list = NULL;
01150     }
01151 
01152     if (noise_cube_list != NULL) {
01153         for (int i = 0; i < nr_exposures; i++) {
01154             cpl_imagelist_delete(noise_cube_list[i]); noise_cube_list[i] = NULL;
01155         }
01156         cpl_free(noise_cube_list); noise_cube_list = NULL;
01157     }
01158 
01159     if (data_header_list != NULL) {
01160         for (int i = 0; i < nr_exposures; i++) {
01161             cpl_propertylist_delete(data_header_list[i]);
01162             data_header_list[i] = NULL;
01163         }
01164         cpl_free(data_header_list); data_header_list = NULL;
01165     }
01166 
01167     if (noise_header_list != NULL) {
01168         for (int i = 0; i < nr_exposures; i++) {
01169             cpl_propertylist_delete(noise_header_list[i]);
01170             noise_header_list[i] = NULL;
01171         }
01172         cpl_free(noise_header_list); noise_header_list = NULL;
01173     }
01174 
01175     if (header_data != NULL) {
01176         for (int i = 0; i < nr_exposures; i++) {
01177             cpl_propertylist_delete(header_data[i]);
01178             header_data[i] = NULL;
01179         }
01180         cpl_free(header_data); header_data = NULL;
01181     }
01182 
01183     return ret_val;
01184 }
01185