KMOS Pipeline Reference Manual  1.0.8
kmo_multi_reconstruct.c
00001 /* $Id: kmo_multi_reconstruct.c,v 1.24 2013/01/24 00:19:57 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/24 00:19:57 $
00024  * $Revision: 1.24 $
00025  * $Name: kmosp_v1_0_8__20130220 $
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_cal_frames_rotangle(frameset, XCAL, YCAL));
00742 //        KMO_TRY_EXIT_IF_ERROR(
00743 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00744 
00745 
00746         nr_alloc = nr_exposures;
00747         KMO_TRY_EXIT_IF_NULL(
00748             exposure_filename = cpl_malloc(nr_alloc * sizeof(char *)));
00749         KMO_TRY_EXIT_IF_NULL(
00750             exposure_objectname = cpl_malloc(nr_alloc * sizeof(char *)));
00751         KMO_TRY_EXIT_IF_NULL(
00752             exposure_ifus  = cpl_malloc(nr_alloc * sizeof(int)));
00753 
00754         // check exposure frames
00755         for (int i = 0; i < nr_exposures; i++) {
00756             KMO_TRY_EXIT_IF_NULL(
00757                 tmp_str = cpl_sprintf("%d", i));
00758 
00759             KMO_TRY_EXIT_IF_NULL(
00760                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00761             cpl_free(tmp_str);
00762 
00763             KMO_TRY_EXIT_IF_NULL(
00764                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00765 
00766             kmo_init_fits_desc(&desc);
00767 
00768             desc = kmo_identify_fits_header(exposure_filename[i]);
00769             KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to "
00770                                           "be in KMOS-format!");
00771 
00772             KMO_TRY_ASSURE(((desc.nr_ext == KMOS_NR_DETECTORS) ||
00773                             ((desc.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00774                            (desc.ex_badpix == FALSE) &&
00775                            ((desc.fits_type == raw_fits) ||
00776                             (desc.fits_type == f2d_fits)) &&
00777                            (desc.frame_type == detector_frame),
00778                            CPL_ERROR_ILLEGAL_INPUT,
00779                            "The frame to reconstruct isn't in the correct "
00780                            "format!!!");
00781             kmo_free_fits_desc(&desc);
00782         }
00783 
00784         // select IFU for each exposure
00785         KMO_TRY_EXIT_IF_NULL(
00786             empty_frames = cpl_malloc(nr_alloc * sizeof(cpl_frame *)));
00787         int found=0;
00788         for (int i = 0; i < nr_exposures; i++) {
00789             empty_frames[i] = NULL;
00790             if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
00791                 found = 1;
00792                 const char *tmpString;
00793                 exposure_ifus[i] = (int) (cpl_vector_get(ifus, i) + 0.1);
00794                 KMO_TRY_EXIT_IF_NULL(
00795                     pl = kmclipm_propertylist_load(exposure_filename[i], 0));
00796                 KMO_TRY_EXIT_IF_NULL(
00797                     tmp_ocs = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX,
00798                                           exposure_ifus[i], IFU_NAME_POSTFIX));
00799                 if (cpl_propertylist_has(pl, tmp_ocs)) {
00800                     tmpString = cpl_propertylist_get_string(pl, tmp_ocs);
00801                 } else {
00802                     tmpString = "";
00803                 }
00804                 cpl_free(tmp_ocs);
00805                 int len = strlen(tmpString);
00806                 const int maxLen = 40;
00807                 if (len > maxLen) {
00808                     len = maxLen;
00809                 }
00810                 exposure_objectname[i] = (char *) cpl_malloc(len * sizeof(char));
00811                 strncpy(exposure_objectname[i], tmpString, len-1);
00812                 if (len > 0) {
00813                     (exposure_objectname[i])[len-1] = '\0';
00814                 }
00815                 cpl_propertylist_delete(pl); pl = NULL;
00816             }  else {                   //IFU selected by user given object name
00817                 exposure_objectname[i] = (char*)name;
00818                 KMO_TRY_EXIT_IF_NULL(
00819                     tmp_str = cpl_sprintf("%d", i));
00820 
00821                 KMO_TRY_EXIT_IF_NULL(
00822                     frame = kmo_dfs_get_frame(exposures, tmp_str));
00823                 cpl_free(tmp_str);
00824 
00825                 KMO_TRY_CHECK_ERROR_STATE();
00826                 int this_ifu = kmo_get_index_from_ocs_name(frame, name);
00827                 KMO_TRY_CHECK_ERROR_STATE();
00828                 if (this_ifu > 0) {
00829                     found = 1;
00830                     exposure_ifus[i] = this_ifu;
00831                 } else {
00832                     empty_frames[i] = frame;
00833                     exposure_ifus[i] = -1;
00834                     cpl_msg_warning("",
00835                                     "Could not find any IFU with an object "
00836                                     "named '%s' in file %s",
00837                                     name, exposure_filename[i]);
00838                 }
00839             }
00840             KMO_TRY_CHECK_ERROR_STATE();
00841         }
00842         if (! found) {
00843             cpl_msg_error("",
00844                           "Could not find any IFU with an object named '%s' in "
00845                           "any input file", name);
00846             KMO_TRY_EXIT_WITH_ERROR(CPL_ERROR_ILLEGAL_INPUT);
00847         }
00848         int j = 0;
00849         for (int i = 0; i < nr_alloc; i++) {
00850             if (empty_frames[i] != NULL) {
00851                 KMO_TRY_EXIT_IF_ERROR(
00852                     cpl_frameset_erase_frame(exposures, empty_frames[i]));
00853                 nr_exposures--;
00854                 exposure_ifus[j] = exposure_ifus[i];
00855             } else {
00856                 exposure_ifus[j] = exposure_ifus[i];
00857                 j++;
00858             }
00859         }
00860         for (int i = 0; i < nr_exposures; i++) {
00861             KMO_TRY_EXIT_IF_NULL(
00862                 tmp_str = cpl_sprintf("%d", i));
00863 
00864             KMO_TRY_EXIT_IF_NULL(
00865                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00866             cpl_free(tmp_str);
00867 
00868             KMO_TRY_EXIT_IF_NULL(
00869                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00870         }
00871 
00872         cpl_free(empty_frames); empty_frames = NULL;
00873 
00874         // get reference header, subheader and set grid definition
00875         device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00876 
00877         KMO_TRY_EXIT_IF_NULL(
00878             ref_main_header = kmclipm_propertylist_load(exposure_filename[0],0));
00879         KMO_TRY_EXIT_IF_NULL(
00880             ref_frame = cpl_frameset_get_first(exposures));
00881         KMO_TRY_EXIT_IF_NULL(
00882             ref_sub_header = kmclipm_propertylist_load(exposure_filename[0],
00883                                                        device_nr));
00884         KMO_TRY_EXIT_IF_ERROR(
00885             kmclipm_setup_grid(&gd, imethod, neighborhoodRange));
00886 
00887         exposure_rotangle = kmo_mr_get_rot_angle(kmo_dfs_get_frame(exposures, "0"));
00888         KMO_TRY_EXIT_IF_NULL(
00889             lcal_frame = kmo_mr_get_closest_cal_frame(frameset, LCAL,
00890                                                       exposure_rotangle));
00891         KMO_TRY_EXIT_IF_NULL(
00892             lcalImg = kmo_dfs_load_image_frame(lcal_frame, device_nr, 0,
00893                                                FALSE, NULL));
00894 
00895         KMO_TRY_EXIT_IF_NULL(
00896             tmp_header = kmclipm_propertylist_load(
00897                                         cpl_frame_get_filename(lcal_frame), 0));
00898         KMO_TRY_EXIT_IF_NULL(
00899             keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, device_nr,
00900                                   IFU_FILTID_POSTFIX));
00901         KMO_TRY_EXIT_IF_NULL(
00902             filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00903 
00904         int band_method = 0;
00905         KMO_TRY_EXIT_IF_NULL(
00906             band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0));
00907 
00908         KMO_TRY_EXIT_IF_ERROR(
00909             kmclipm_setup_grid_band_lcal(&gd, lcalImg, filter_id,
00910                                          band_method, band_table));
00911         cpl_image_delete(lcalImg); lcalImg = NULL;
00912         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00913         cpl_free(keyword); keyword = NULL;
00914         cpl_table_delete(band_table); band_table = NULL;
00915 
00916         //extract sub-headers for each exposures, calculate WCS
00917         KMO_TRY_EXIT_IF_NULL(
00918             header_data = cpl_malloc(nr_exposures*sizeof(cpl_propertylist*)));
00919         for (int i = 0; i < nr_exposures; i++) {
00920            device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00921            KMO_TRY_EXIT_IF_NULL(
00922                header_data[i] = kmclipm_propertylist_load(exposure_filename[i],
00923                                                           device_nr));
00924            KMO_TRY_EXIT_IF_ERROR(
00925                 kmclipm_update_property_int(header_data[i],"NAXIS", 3,""));
00926            KMO_TRY_EXIT_IF_ERROR(
00927                 kmclipm_update_property_int(header_data[i],"NAXIS1",gd.x.dim,""));
00928            KMO_TRY_EXIT_IF_ERROR(
00929                 kmclipm_update_property_int(header_data[i],"NAXIS2",gd.y.dim,""));
00930            KMO_TRY_EXIT_IF_ERROR(
00931                 kmclipm_update_property_int(header_data[i],"NAXIS3",gd.l.dim,""));
00932            cpl_propertylist *tmpHeader;
00933            KMO_TRY_EXIT_IF_NULL(
00934                 tmpHeader = kmclipm_propertylist_load(exposure_filename[i],0));
00935            KMO_TRY_EXIT_IF_ERROR(
00936                 kmo_calc_wcs(tmpHeader, header_data[i],
00937                              exposure_ifus[i], gd.l.start, gd.l.delta));
00938            cpl_propertylist_delete(tmpHeader);
00939         }
00940 
00941         // check rotation angle
00942         cd1_1 = kmo_dfs_get_property_double(header_data[0], CD1_1);
00943         cd1_2 = kmo_dfs_get_property_double(header_data[0], CD1_2);
00944         KMO_TRY_CHECK_ERROR_STATE();
00945         ang1 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
00946         for (int i = 1; i < nr_exposures; i++) {
00947             cd1_1 = kmo_dfs_get_property_double(header_data[i], CD1_1);
00948             cd1_2 = kmo_dfs_get_property_double(header_data[i], CD1_2);
00949             KMO_TRY_CHECK_ERROR_STATE();
00950             ang2 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
00951 
00952             if (strcmp(smethod, "none") != 0) {
00953                 // center, header, user
00954                 KMO_TRY_ASSURE(fabs(ang1-ang2) <= 0.5,
00955                                CPL_ERROR_ILLEGAL_INPUT,
00956                                "Orientation of cube 1 (%gdeg) and cube %d "
00957                                "(%gdeg) differ! "
00958                                "Align the orientation of this cube with "
00959                                "kmo_rotate before applying this recipe.",
00960                                ang1, i+1, ang2);
00961             } else {
00962                 // none
00963                 if (fabs(ang1-ang2) > 0.5) {
00964                     cpl_msg_warning("",
00965                                     "Orientation of cube 1 (%gdeg) and cube %d "
00966                                     "(%gdeg) differ! Processing anyway.",
00967                                     ang1, i+1, ang2);
00968                 }
00969             }
00970         }
00971 
00972         // set x/y shifts
00973         KMO_TRY_EXIT_IF_NULL(
00974             xshifts = cpl_malloc(nr_exposures * sizeof(double)));
00975         KMO_TRY_EXIT_IF_NULL(
00976             yshifts = cpl_malloc(nr_exposures * sizeof(double)));
00977         KMO_TRY_EXIT_IF_ERROR(
00978             kmo_mr_get_offsets(nr_exposures, smethod, imethod, neighborhoodRange,
00979                                filename, frameset, exposures, exposure_ifus,
00980                                (const cpl_propertylist**)header_data,
00981                                fmethod,
00982                                cmethod,
00983                                cpos_rej,
00984                                cneg_rej,
00985                                citer,
00986                                cmin,
00987                                cmax,
00988                                xshifts, yshifts));
00989 
00990         for (int i = 0; i < nr_exposures; i++) {
00991             printf("exposure %d: filename %s, selected IFU %d, object name "
00992                    "\"%s\", xshift %f, yshift %f\n", i, exposure_filename[i],
00993                    exposure_ifus[i], exposure_objectname[i], xshifts[i], yshifts[i]);
00994         }
00995 
00996         //
00997         // set spatial part of the grid
00998         //
00999 //        size = "max";
01000         if (strcmp(size, "max") == 0) {
01001             double xmin=0, xmax=0, ymin=0, ymax=0;
01002             double gxshift, gyshift, gxdim, gydim;
01003             double pixel_resolution = KMOS_PIXEL_RESOLUTION;
01004             int xdim, ydim;
01005 
01006             for (int i = 0; i < nr_exposures; i++) {
01007                 if (xmin > xshifts[i]) { xmin = xshifts[i]; }
01008                 if (xmax < xshifts[i]) { xmax = xshifts[i]; }
01009                 if (ymin > yshifts[i]) { ymin = yshifts[i]; }
01010                 if (ymax < yshifts[i]) { ymax = yshifts[i]; }
01011             }
01012             if (xmax > 0.0001) {
01013                 gxshift = - ceil(xmax);
01014             } else {
01015                 gxshift = 0.;
01016             }
01017             if (ymin < -0.0001) {
01018                 gyshift = floor(ymin);
01019             } else {
01020                 gyshift = 0.;
01021             }
01022             if (xmin < -0.0001) {
01023                 gxdim = - floor(xmin);
01024             } else {
01025                 gxdim = 0.;
01026             }
01027             if (ymax > 0.0001) {
01028                 gydim = ceil(ymax);
01029             } else {
01030                 gydim = 0.;
01031             }
01032 
01033             xdim = (int) (gxdim - gxshift + .5);
01034             ydim = (int) (gydim - gyshift + .5);
01035             gd.x.start += gxshift * pixel_resolution;
01036             gd.y.start += gyshift * pixel_resolution;
01037             gd.x.dim += xdim;
01038             gd.y.dim += ydim;
01039 //            printf("X: %f < %f      Y: %f < %f \n",xmin,xmax,ymin,ymax);
01040 //            printf("gxshift: %f  gxdim: %f   xdim: %d        gyshift: %f  gydim: %f  ydim: %d \n",
01041 //                    gxshift, gxdim, xdim, gyshift, gydim, ydim);
01042 //            printf("GD: %f  %d     %f %d\n", gd.x.start, gd.x.dim, gd.y.start, gd.y.dim);
01043         }
01044 
01045         //
01046         // reconstruct multiple detector images
01047         //
01048 
01049 //        printf("GD: %f %f %d     %f %f %d     %f %f %d\n",
01050 //                gd.x.start, gd.x.delta, gd.x.dim,
01051 //                gd.y.start, gd.y.delta, gd.y.dim,
01052 //                gd.l.start, gd.l.delta, gd.l.dim);
01053 
01054         KMO_TRY_EXIT_IF_ERROR(
01055             kmo_priv_multi_reconstruct(frameset,
01056                                        exposures,
01057                                        exposure_ifus,
01058                                        xshifts,
01059                                        yshifts,
01060                                        gd,
01061                                        &cube_combined_data,
01062                                        &cube_combined_noise));
01063 
01064         // setup output category COMBINE + ESO PRO CATG
01065         if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
01066             KMO_TRY_EXIT_IF_NULL(
01067                 tmp_str = cpl_sprintf("IFU"));
01068         } else {
01069             KMO_TRY_EXIT_IF_NULL(
01070                 tmp_str = cpl_sprintf("%s", name));
01071         }
01072 
01073         KMO_TRY_EXIT_IF_NULL(
01074             filename_output_cube = cpl_sprintf("%s_%s", CUBE_MULTI, tmp_str));
01075         cpl_free(tmp_str); tmp_str = NULL;
01076 
01077         KMO_TRY_EXIT_IF_ERROR(
01078             kmo_dfs_save_main_header(frameset, filename_output_cube, "",
01079                                      ref_frame, NULL, parlist, cpl_func));
01080         // save output
01081         KMO_TRY_EXIT_IF_NULL(
01082             extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01083                                           EXT_DATA));
01084 
01085         // calculate WCS
01086         KMO_TRY_EXIT_IF_ERROR(
01087             kmo_calc_wcs_gd(ref_main_header, ref_sub_header, exposure_ifus[0], gd));
01088 
01089         KMO_TRY_EXIT_IF_ERROR(
01090             kmclipm_update_property_string(ref_sub_header,
01091                                            EXTNAME,
01092                                            extname,
01093                                            "FITS extension name"));
01094         cpl_free(extname); extname = NULL;
01095 
01096         KMO_TRY_EXIT_IF_ERROR(
01097             kmo_dfs_save_cube(cube_combined_data, filename_output_cube,
01098                               "", ref_sub_header, 0./0.));
01099 
01100         if (cube_combined_noise != NULL) {
01101             KMO_TRY_EXIT_IF_NULL(
01102                 extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01103                                               EXT_NOISE));
01104 
01105             KMO_TRY_EXIT_IF_ERROR(
01106                 kmclipm_update_property_string(ref_sub_header,
01107                                         EXTNAME,
01108                                         extname,
01109                                         "FITS extension name"));
01110             cpl_free(extname); extname = NULL;
01111 
01112             KMO_TRY_EXIT_IF_ERROR(
01113                 kmo_dfs_save_cube(cube_combined_noise, filename_output_cube,
01114                                   "", ref_sub_header, 0./0.));
01115         }
01116     }
01117     KMO_CATCH
01118     {
01119         KMO_CATCH_MSG();
01120         ret_val = -1;
01121     }
01122 
01123     cpl_free(filename_output_cube); filename_output_cube = NULL;
01124     cpl_propertylist_delete(main_header); main_header = NULL;
01125     cpl_vector_delete(ifus); ifus = NULL;
01126     cpl_imagelist_delete(cube_combined_data); cube_combined_data = NULL;
01127     cpl_imagelist_delete(cube_combined_noise); cube_combined_noise = NULL;
01128     if (exposures != NULL) {cpl_frameset_delete(exposures);}
01129     if (exposure_filename != NULL) {cpl_free(exposure_filename);}
01130     if ((ifus_txt != NULL) && (strcmp(ifus_txt, "") != 0)) { //IFU selected by user given list
01131         for (int i = 0; i < nr_alloc; i++) {
01132             cpl_free(exposure_objectname[i]);
01133         }
01134     }
01135     if (exposure_objectname != NULL) {cpl_free(exposure_objectname);}
01136     if (exposure_ifus != NULL) {cpl_free(exposure_ifus);}
01137     if (ref_main_header != NULL) {cpl_propertylist_delete(ref_main_header);}
01138     if (ref_sub_header != NULL) {cpl_propertylist_delete(ref_sub_header);}
01139     if (xshifts != NULL) {cpl_free(xshifts);}
01140     if (yshifts != NULL) {cpl_free(yshifts);}
01141 
01142     if (data_cube_list != NULL) {
01143         for (int i = 0; i < nr_exposures; i++) {
01144             cpl_imagelist_delete(data_cube_list[i]); data_cube_list[i] = NULL;
01145         }
01146         cpl_free(data_cube_list); data_cube_list = NULL;
01147     }
01148 
01149     if (noise_cube_list != NULL) {
01150         for (int i = 0; i < nr_exposures; i++) {
01151             cpl_imagelist_delete(noise_cube_list[i]); noise_cube_list[i] = NULL;
01152         }
01153         cpl_free(noise_cube_list); noise_cube_list = NULL;
01154     }
01155 
01156     if (data_header_list != NULL) {
01157         for (int i = 0; i < nr_exposures; i++) {
01158             cpl_propertylist_delete(data_header_list[i]);
01159             data_header_list[i] = NULL;
01160         }
01161         cpl_free(data_header_list); data_header_list = NULL;
01162     }
01163 
01164     if (noise_header_list != NULL) {
01165         for (int i = 0; i < nr_exposures; i++) {
01166             cpl_propertylist_delete(noise_header_list[i]);
01167             noise_header_list[i] = NULL;
01168         }
01169         cpl_free(noise_header_list); noise_header_list = NULL;
01170     }
01171 
01172     if (header_data != NULL) {
01173         for (int i = 0; i < nr_exposures; i++) {
01174             cpl_propertylist_delete(header_data[i]);
01175             header_data[i] = NULL;
01176         }
01177         cpl_free(header_data); header_data = NULL;
01178     }
01179 
01180     return ret_val;
01181 }
01182