KMOS Pipeline Reference Manual  1.1.5
kmo_multi_reconstruct.c
00001 /* $Id: kmo_multi_reconstruct.c,v 1.29 2013/05/24 14:32:23 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/05/24 14:32:23 $
00024  * $Revision: 1.29 $
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 "--suppress_extension\n"
00133 "If set to TRUE, the arbitrary filename extensions are supressed. If multiple\n"
00134 "products with the same category are produced, they will be numered consecutively\n"
00135 "starting from 0.\n"
00136 "\n"
00137 "-------------------------------------------------------------------------------\n"
00138 "  Input files:\n"
00139 "\n"
00140 "   DO            DO      KMOS                                                  \n"
00141 "   category      group   Type   Explanation                    Required #Frames\n"
00142 "   --------      -----   -----  -----------                    -------- -------\n"
00143 "   OBJECT or             RAW    The science frames                Y      >=2   \n"
00144 "   STD                   RAW                                                   \n"
00145 "   XCAL                  F2D    x calibration frame               Y       1    \n"
00146 "   YCAL                  F2D    y calibration frame               Y       1    \n"
00147 "   LCAL                  F2D    Wavelength calib. frame           Y       1    \n"
00148 "   WAVE_BAND             F2L    Table with start-/end-wavelengths Y       1    \n"
00149 "\n"
00150 "  Output files:\n"
00151 "\n"
00152 "   DO                    KMOS\n"
00153 "   category              Type   Explanation\n"
00154 "   --------              -----  -----------\n"
00155 "   SCI_COMBINED          F3I    Combined cubes with noise\n"
00156 "   SCI_RECONSTRUCTED     F3I    Reconstructed cube with noise\n"
00157 
00158 
00159 
00160 "   <none or any>   -     F3I    data frame                         Y      2-n  \n"
00161 "   WAVE_BAND             F2L    Table with start-/end-wavelengths  Y       1   \n"
00162 "\n"
00163 "  Output files:\n"
00164 "\n"
00165 "   DO                    KMOS\n"
00166 "   category              Type   Explanation\n"
00167 "   --------              -----  -----------\n"
00168 "   CUBE_MULTI_<name/ifu> F3I    Combined data cube\n"
00169 "-------------------------------------------------------------------------------\n"
00170 "\n";
00171 
00188 int cpl_plugin_get_info(cpl_pluginlist *list)
00189 {
00190     cpl_recipe *recipe = cpl_calloc(1, sizeof *recipe);
00191     cpl_plugin *plugin = &recipe->interface;
00192 
00193     cpl_plugin_init(plugin,
00194                         CPL_PLUGIN_API,
00195                         KMOS_BINARY_VERSION,
00196                         CPL_PLUGIN_TYPE_RECIPE,
00197                         "kmo_multi_reconstruct",
00198                         "Combine reconstructed cubes",
00199                         kmo_multi_reconstruct_description,
00200                         "Alex Agudo Berbel",
00201                         "kmos-spark@mpe.mpg.de",
00202                         kmos_get_license(),
00203                         kmo_multi_reconstruct_create,
00204                         kmo_multi_reconstruct_exec,
00205                         kmo_multi_reconstruct_destroy);
00206 
00207     cpl_pluginlist_append(list, plugin);
00208 
00209     return 0;
00210 }
00211 
00219 static int kmo_multi_reconstruct_create(cpl_plugin *plugin)
00220 {
00221     cpl_recipe *recipe;
00222     cpl_parameter *p;
00223 
00224     /* Check that the plugin is part of a valid recipe */
00225     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00226         recipe = (cpl_recipe *)plugin;
00227     else
00228         return -1;
00229 
00230     /* Create the parameters list in the cpl_recipe object */
00231     recipe->parameters = cpl_parameterlist_new();
00232 
00233     /* Fill the parameters list */
00234     /* --name */
00235     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.name",
00236                                 CPL_TYPE_STRING,
00237                                 "Name of the object to combine.",
00238                                 "kmos.kmo_multi_reconstruct",
00239                                 "");
00240     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
00241     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00242     cpl_parameterlist_append(recipe->parameters, p);
00243 
00244     /* --ifus */
00245     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.ifus",
00246                                 CPL_TYPE_STRING,
00247                                 "The indices of the IFUs to combine. "
00248                                 "\"ifu1;ifu2;...\"",
00249                                 "kmos.kmo_multi_reconstruct",
00250                                 "");
00251     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
00252     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00253     cpl_parameterlist_append(recipe->parameters, p);
00254 
00255     /* --size */
00256     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.size",
00257                                 CPL_TYPE_STRING,
00258                                 "Spatial size of the output cube.",
00259                                 "kmos.kmo_multi_reconstruct",
00260                                 "max");
00261     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "size");
00262     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00263     cpl_parameterlist_append(recipe->parameters, p);
00264 
00265 
00266     /* --smethod  shift method*/
00267     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.smethod",
00268                                 CPL_TYPE_STRING,
00269                                 "The shifting method:   "
00270                                 "'none': no shifting, combined directly "
00271                                                                   "(default), "
00272                                 "'header': shift according to WCS, "
00273                                 "'center': centering algorithm, "
00274                                 "'user': read shifts from file",
00275                                 "kmos.kmo_multi_reconstruct",
00276                                 "none");
00277     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "smethod");
00278     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00279     cpl_parameterlist_append(recipe->parameters, p);
00280 
00281     /* --fmethod */
00282     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.fmethod",
00283                                 CPL_TYPE_STRING,
00284                                 "The fitting method (applies only when "
00285                                 "method='center'):   "
00286                                 "'gauss': fit a gauss function to collapsed "
00287                                 "image (default), "
00288                                 "'moffat': fit a moffat function to collapsed"
00289                                 " image",
00290                                 "kmos.kmo_combine",
00291                                 "gauss");
00292     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
00293     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00294     cpl_parameterlist_append(recipe->parameters, p);
00295 
00296     /* --imethod interpolation method */
00297     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.imethod",
00298                                 CPL_TYPE_STRING,
00299                                 "Method to use for interpolation. "
00300                                 "[\"NN\" (nearest neighbour), "
00301                                 "\"lwNN\" (linear weighted nearest neighbor), "
00302                                 "\"swNN\" (square weighted nearest neighbor), "
00303                                 "\"MS\" (Modified Shepard's method)"
00304                                 "\"CS\" (Cubic spline)]",
00305                                 "kmos.kmo_multi_reconstruct",
00306                                 "NN");
00307     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00308     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00309     cpl_parameterlist_append(recipe->parameters, p);
00310 
00311     /* --neighborhoodRange */
00312     p = cpl_parameter_new_value("kmos.kmo_reconstruct.neighborhoodRange",
00313                                 CPL_TYPE_DOUBLE,
00314                                 "Defines the range to search for neighbors. "
00315                                 "in pixels",
00316                                 "kmos.kmo_reconstruct",
00317                                 1.001);
00318     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "neighborhoodRange");
00319     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00320     cpl_parameterlist_append(recipe->parameters, p);
00321 
00322     /* --filename */
00323     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.filename",
00324                                 CPL_TYPE_STRING,
00325                                 "The path to the file with the shift vectors."
00326                                 "(Applies only to smethod='user')",
00327                                 "kmos.kmo_multi_reconstruct",
00328                                 "");
00329     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "filename");
00330     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00331     cpl_parameterlist_append(recipe->parameters, p);
00332 
00333     /* --suppress_extension */
00334     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.suppress_extension",
00335                                 CPL_TYPE_BOOL,
00336                                 "Suppress arbitrary filename extension."
00337                                 "(TRUE (apply) or FALSE (don't apply)",
00338                                 "kmos.kmo_multi_reconstruct",
00339                                 FALSE);
00340     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
00341     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00342     cpl_parameterlist_append(recipe->parameters, p);
00343 
00344     // add parameters for band-definition
00345     kmo_band_pars_create(recipe->parameters,
00346                          "kmos.kmo_multi_reconstruct");
00347 
00348     return kmo_combine_pars_create(recipe->parameters,
00349                                    "kmos.kmo_multi_reconstruct",
00350                                    DEF_REJ_METHOD,
00351                                    FALSE);
00352 }
00353 
00359 static int kmo_multi_reconstruct_exec(cpl_plugin *plugin)
00360 {
00361     cpl_recipe  *recipe;
00362 
00363     /* Get the recipe out of the plugin */
00364     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00365         recipe = (cpl_recipe *)plugin;
00366     else return -1 ;
00367 
00368     return kmo_multi_reconstruct(recipe->parameters, recipe->frames);
00369 }
00370 
00376 static int kmo_multi_reconstruct_destroy(cpl_plugin *plugin)
00377 {
00378     cpl_recipe *recipe;
00379 
00380     /* Get the recipe out of the plugin */
00381     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00382         recipe = (cpl_recipe *)plugin;
00383     else return -1 ;
00384 
00385     cpl_parameterlist_delete(recipe->parameters);
00386     return 0 ;
00387 }
00388 
00389 //int kmo_tolerance_round(double x, double tol)
00390 //{
00391 //    int ret = 0;
00392 
00393 //    KMO_TRY
00394 //    {
00395 //        if (fabs(x - floor(x)) < tol) {
00396 //            // value is slightly greater than the real int value
00397 //            ret = floor(x);
00398 //        } else {
00399 //            if (fabs(x - floor(x+tol)) < tol) {
00400 //                // value is slightly greater than the real int value
00401 //                ret = floor(x+tol);
00402 //            } else {
00403 //                // error: sub pixel shift
00404 //                KMO_TRY_ASSURE(1 == 0,
00405 //                               CPL_ERROR_ILLEGAL_INPUT,
00406 //                               "Please apply only whole pixel shifts here "
00407 //                               "and no subpixel shifts!");
00408 //            }
00409 //        }
00410 //    }
00411 //    KMO_CATCH
00412 //    {
00413 //        KMO_CATCH_MSG();
00414 
00415 //        ret = 0;
00416 //    }
00417 
00418 //    return ret;
00419 //}
00420 
00435 static int kmo_multi_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
00436 {
00437     const char       *smethod               = NULL,
00438                      *cmethod               = NULL,
00439                      *fmethod               = NULL,
00440                      *imethod               = NULL,
00441                      *filename              = NULL,
00442                      *ifus_txt              = NULL,
00443                      *name                  = NULL,
00444                      *size                  = NULL,
00445                      *filter_id             = NULL;
00446 
00447     char             *tmp_str               = NULL,
00448                      *filename_output_cube  = NULL,
00449                      *extname               = NULL,
00450                      *keyword               = NULL,
00451                      *tmp_ocs               = NULL;
00452 
00453     cpl_imagelist    **data_cube_list       = NULL,
00454                      **noise_cube_list      = NULL,
00455                      *cube_combined_data    = NULL,
00456                      *cube_combined_noise   = NULL;
00457 
00458     cpl_vector       *ifus                  = NULL;
00459 
00460     int              ret_val                = 0,
00461                      nr_exposures           = 0,
00462                      device_nr              = 0,
00463                      citer                  = 0,
00464                      cmin                   = 0,
00465                      cmax                   = 0,
00466                      nr_alloc               = 0,
00467                      suppress_extension     = FALSE;
00468 
00469     double           neighborhoodRange      = 1.001,
00470                      cpos_rej               = 0.0,
00471                      cneg_rej               = 0.0;
00472 
00473     char             **exposure_filename    = NULL,
00474                      **exposure_objectname  = NULL;
00475     int              *exposure_ifus         = NULL,
00476                      nr_object_frames       = 0,
00477                      nr_std_frames          = 0;
00478 
00479     double           *xshifts               = NULL,
00480                      *yshifts               = NULL,
00481                      cd1_1                  = 0.0,
00482                      cd1_2                  = 0.0,
00483                      ang1                   = 0.0,
00484                      ang2                   = 0.0,
00485                      exposure_rotangle      = 0.0;
00486 
00487     cpl_propertylist *pl                    = NULL,
00488                      *main_header           = NULL,
00489                      *ref_main_header       = NULL,
00490                      *ref_sub_header        = NULL,
00491                      *tmp_header            = NULL,
00492                      **header_data          = NULL,
00493                      **data_header_list     = NULL,
00494                      **noise_header_list    = NULL;
00495 
00496     cpl_frame        *frame                 = NULL,
00497                      *lcal_frame            = NULL;
00498 
00499     cpl_table        *band_table            = NULL;
00500 
00501     cpl_image        *lcalImg               = NULL;
00502 
00503     main_fits_desc   desc;
00504 
00505     cpl_frameset     *exposures             = NULL;
00506 
00507     cpl_frame        **empty_frames         = NULL,
00508                      *tmp_frame             = NULL,
00509                      *ref_frame             = NULL;
00510 
00511     gridDefinition   gd;
00512 
00513     KMO_TRY
00514     {
00515         /* --- check input --- */
00516         KMO_TRY_ASSURE((parlist != NULL) &&
00517                        (frameset != NULL),
00518                        CPL_ERROR_NULL_INPUT,
00519                        "Not all input data is provided!");
00520 
00521         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_multi_reconstruct") == 1,
00522                        CPL_ERROR_ILLEGAL_INPUT,
00523                        "Cannot identify RAW and CALIB frames!");
00524 
00525         KMO_TRY_ASSURE(! ((cpl_frameset_count_tags(frameset, XCAL) == 0) &&
00526                           (cpl_frameset_count_tags(frameset, YCAL) == 0) &&
00527                           (cpl_frameset_count_tags(frameset, LCAL) == 0) &&
00528                           (cpl_frameset_count_tags(frameset, WAVE_BAND) == 0)),
00529                           CPL_ERROR_FILE_NOT_FOUND,
00530                           "XCAL, YCAL, LCAL or WAVE_BAND frames missing in "
00531                           "frameset!!");
00532 
00533         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00534                        CPL_ERROR_FILE_NOT_FOUND,
00535                        "Exactly one XCAL frame is expected in frameset!");
00536 
00537         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00538                        CPL_ERROR_FILE_NOT_FOUND,
00539                        "Exactly one YCAL frame is expected in frameset!");
00540 
00541         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00542                        CPL_ERROR_FILE_NOT_FOUND,
00543                        "Exactly one LCAL frame is expected in frameset!");
00544 
00545         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00546                        CPL_ERROR_FILE_NOT_FOUND,
00547                        "Exactly one WAVE_BAND frame is expected in frameset!");
00548 
00549         // assert that at least two OBJECT or STD frames are available and create
00550         // intermediate frameset just with these science frames
00551         nr_object_frames = cpl_frameset_count_tags(frameset, OBJECT);
00552         nr_std_frames = cpl_frameset_count_tags(frameset, STD);
00553         KMO_TRY_CHECK_ERROR_STATE();
00554         nr_exposures = nr_object_frames + nr_std_frames;
00555 
00556         KMO_TRY_ASSURE(((nr_object_frames > 1) && (nr_std_frames == 0)) ||
00557                        ((nr_object_frames == 0) && (nr_std_frames > 1)),
00558                        CPL_ERROR_ILLEGAL_INPUT,
00559                        "OBJECT and STD frames mustn't be intermixed and at "
00560                        "least two frames (OBJECT or STD) must be provided "
00561                        "to combine!");
00562         KMO_TRY_EXIT_IF_NULL(
00563             exposures = cpl_frameset_new());
00564         if (nr_object_frames > 1) {
00565             KMO_TRY_EXIT_IF_NULL(
00566                 tmp_frame = kmo_dfs_get_frame(frameset, OBJECT));
00567         } else {
00568             KMO_TRY_EXIT_IF_NULL(
00569                 tmp_frame = kmo_dfs_get_frame(frameset, STD));
00570         }
00571 
00572         for (int i = 0; i < nr_exposures; i++) {
00573             KMO_TRY_EXIT_IF_ERROR(
00574                 cpl_frameset_insert(exposures, cpl_frame_duplicate(tmp_frame)));
00575             KMO_TRY_CHECK_ERROR_STATE();
00576 
00577             tmp_frame = kmo_dfs_get_frame(frameset, NULL);
00578         }
00579 
00580         cpl_msg_info("", "--- Parameter setup for kmo_multi_reconstruct -------");
00581 
00582         KMO_TRY_EXIT_IF_NULL(
00583             imethod = kmo_dfs_get_parameter_string(parlist,
00584                                          "kmos.kmo_multi_reconstruct.imethod"));
00585 
00586         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00587                        (strcmp(imethod, "lwNN") == 0) ||
00588                        (strcmp(imethod, "swNN") == 0) ||
00589                        (strcmp(imethod, "MS") == 0) ||
00590                        (strcmp(imethod, "CS") == 0),
00591                        CPL_ERROR_ILLEGAL_INPUT,
00592                        "imethod must be either \"NN\", \"lwNN\", "
00593                        "\"swNN\", \"MS\" or \"CS\"!");
00594 
00595         KMO_TRY_EXIT_IF_ERROR(
00596             kmo_dfs_print_parameter_help(parlist,
00597                                         "kmos.kmo_multi_reconstruct.imethod"));
00598 
00599         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00600                 "kmos.kmo_reconstruct.neighborhoodRange");
00601         KMO_TRY_CHECK_ERROR_STATE();
00602 
00603         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00604                        CPL_ERROR_ILLEGAL_INPUT,
00605                        "neighborhoodRange must be greater than 0.0");
00606 
00607         KMO_TRY_EXIT_IF_ERROR(
00608             kmo_dfs_print_parameter_help(parlist,
00609                                      "kmos.kmo_reconstruct.neighborhoodRange"));
00610 
00611         KMO_TRY_EXIT_IF_NULL(
00612             size = kmo_dfs_get_parameter_string(parlist,
00613                                             "kmos.kmo_multi_reconstruct.size"));
00614 
00615         KMO_TRY_EXIT_IF_NULL(
00616             smethod = kmo_dfs_get_parameter_string(parlist,
00617                                          "kmos.kmo_multi_reconstruct.smethod"));
00618 
00619         KMO_TRY_EXIT_IF_NULL(
00620             fmethod = kmo_dfs_get_parameter_string(parlist,
00621                                          "kmos.kmo_multi_reconstruct.fmethod"));
00622 
00623         KMO_TRY_ASSURE((strcmp(size, "max") == 0) ||
00624                        (strcmp(size, "std") == 0),
00625                        CPL_ERROR_ILLEGAL_INPUT,
00626                        "Following output cube size specifications are available: "
00627                        "'std' or 'max'");
00628 
00629 
00630         KMO_TRY_ASSURE((strcmp(smethod, "none") == 0) ||
00631                        (strcmp(smethod, "header") == 0) ||
00632                        (strcmp(smethod, "center") == 0) ||
00633                        (strcmp(smethod, "user") == 0),
00634                        CPL_ERROR_ILLEGAL_INPUT,
00635                        "Following shift methods are available : 'none', "
00636                        "'header', 'center' or 'user'");
00637 
00638         if (strcmp(smethod, "user") == 0) {
00639             filename = kmo_dfs_get_parameter_string(parlist,
00640                                          "kmos.kmo_multi_reconstruct.filename");
00641             KMO_TRY_CHECK_ERROR_STATE();
00642 
00643             KMO_TRY_ASSURE(strcmp(filename, "") != 0,
00644                            CPL_ERROR_ILLEGAL_INPUT,
00645                            "path of file with shift information must be "
00646                            "provided!");
00647 
00648             KMO_TRY_EXIT_IF_ERROR(
00649                 kmo_dfs_print_parameter_help(parlist,
00650                                         "kmos.kmo_multi_reconstruct.filename"));
00651         }
00652 
00653         KMO_TRY_EXIT_IF_ERROR(
00654             kmo_dfs_print_parameter_help(parlist,
00655                                          "kmos.kmo_multi_reconstruct.smethod"));
00656 
00657         ifus_txt = kmo_dfs_get_parameter_string(parlist,
00658                                              "kmos.kmo_multi_reconstruct.ifus");
00659         KMO_TRY_CHECK_ERROR_STATE();
00660 
00661         name = kmo_dfs_get_parameter_string(parlist,
00662                                             "kmos.kmo_multi_reconstruct.name");
00663         KMO_TRY_CHECK_ERROR_STATE();
00664 
00665         if (strcmp(ifus_txt, "") != 0) {
00666             KMO_TRY_ASSURE(strcmp(name, "") == 0,
00667                            CPL_ERROR_ILLEGAL_INPUT,
00668                            "name parameter must be NULL if IFU indices are "
00669                            "provided!");
00670 
00671             KMO_TRY_EXIT_IF_NULL(
00672                 ifus = kmo_identify_values(ifus_txt));
00673 
00674             KMO_TRY_ASSURE(cpl_vector_get_size(ifus) == nr_exposures,
00675                            CPL_ERROR_ILLEGAL_INPUT,
00676                            "ifus parameter must have the same number of values "
00677                            "than frames provided ) (%lld!=%d)",
00678                            cpl_vector_get_size(ifus), nr_exposures);
00679 
00680             for (int i = 0; i < nr_exposures; i++) {
00681                 KMO_TRY_ASSURE((cpl_vector_get(ifus, i) > 0.5 &&
00682                                cpl_vector_get(ifus, i) < 24.5 ),
00683                                CPL_ERROR_ILLEGAL_INPUT,
00684                                "IFU numbers must be in the range 1..24");
00685             }
00686         }
00687 
00688         if (strcmp(name, "") != 0) {
00689             KMO_TRY_ASSURE(strcmp(ifus_txt, "") == 0,
00690                            CPL_ERROR_ILLEGAL_INPUT,
00691                            "ifus parameter must be NULL if name is provided!");
00692         }
00693 
00694         KMO_TRY_ASSURE((strcmp(name, "") != 0) || (strcmp(ifus_txt, "") != 0),
00695                        CPL_ERROR_ILLEGAL_INPUT,
00696                        "Either the name of the object or the numbers of the "
00697                        "IFUs to combine must be provided (--name or --ifus "
00698                        "parameters)");
00699 
00700         KMO_TRY_EXIT_IF_ERROR(
00701             kmo_dfs_print_parameter_help(parlist,
00702                                          "kmos.kmo_multi_reconstruct.ifus"));
00703 
00704         KMO_TRY_EXIT_IF_ERROR(
00705             kmo_dfs_print_parameter_help(parlist,
00706                                          "kmos.kmo_multi_reconstruct.name"));
00707 
00708 
00709         suppress_extension = kmo_dfs_get_parameter_bool(parlist,
00710                                           "kmos.kmo_multi_reconstruct.suppress_extension");
00711         KMO_TRY_CHECK_ERROR_STATE();
00712         KMO_TRY_EXIT_IF_ERROR(
00713             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_multi_reconstruct.suppress_extension"));
00714 
00715         KMO_TRY_ASSURE((suppress_extension == TRUE) || (suppress_extension == FALSE),
00716                        CPL_ERROR_ILLEGAL_INPUT,
00717                        "suppress_extension must be TRUE or FALSE!");
00718 
00719         KMO_TRY_EXIT_IF_ERROR(
00720             kmo_combine_pars_load(parlist,
00721                                   "kmos.kmo_multi_reconstruct",
00722                                   &cmethod,
00723                                   &cpos_rej,
00724                                   &cneg_rej,
00725                                   &citer,
00726                                   &cmin,
00727                                   &cmax,
00728                                   FALSE));
00729 
00730         kmo_band_pars_load(parlist, "kmos.kmo_multi_reconstruct");
00731 
00732         cpl_msg_info("", "-------------------------------------------");
00733 
00734         // assure that filters and grating  match for
00735         // XCAL, YCAL, LCAL and for data frames to reconstruct
00736         KMO_TRY_EXIT_IF_ERROR(
00737             kmo_check_frameset_setup(frameset, XCAL,
00738                                        TRUE, FALSE, FALSE));
00739         KMO_TRY_EXIT_IF_ERROR(
00740             kmo_check_frameset_setup(frameset, YCAL,
00741                                        TRUE, FALSE, FALSE));
00742         KMO_TRY_EXIT_IF_ERROR(
00743             kmo_check_frameset_setup(frameset, LCAL,
00744                                        TRUE, FALSE, FALSE));
00745         KMO_TRY_EXIT_IF_ERROR(
00746             kmo_check_frame_setup(frameset, XCAL, YCAL,
00747                                        TRUE, FALSE, TRUE));
00748         KMO_TRY_EXIT_IF_ERROR(
00749             kmo_check_frame_setup(frameset, XCAL, LCAL,
00750                                        TRUE, FALSE, TRUE));
00751         if (nr_object_frames > 1) {
00752             KMO_TRY_EXIT_IF_ERROR(
00753                 kmo_check_frameset_setup(frameset, OBJECT,
00754                                            TRUE, FALSE, FALSE));
00755             KMO_TRY_EXIT_IF_ERROR(
00756                 kmo_check_frame_setup(frameset, XCAL, OBJECT,
00757                                            TRUE, FALSE, TRUE));
00758         } else {
00759             KMO_TRY_EXIT_IF_ERROR(
00760                 kmo_check_frameset_setup(frameset, STD,
00761                                            TRUE, FALSE, FALSE));
00762             KMO_TRY_EXIT_IF_ERROR(
00763                 kmo_check_frame_setup(frameset, XCAL, STD,
00764                                            TRUE, FALSE, TRUE));
00765         }
00766 
00767         KMO_TRY_EXIT_IF_ERROR(
00768             kmo_check_frame_setup_md5_xycal(frameset));
00769         KMO_TRY_EXIT_IF_ERROR(
00770             kmo_check_frame_setup_md5(frameset));
00771 
00772 //        KMO_TRY_EXIT_IF_ERROR(
00773 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00774 //        KMO_TRY_EXIT_IF_ERROR(
00775 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00776 
00777 
00778         nr_alloc = nr_exposures;
00779         KMO_TRY_EXIT_IF_NULL(
00780             exposure_filename = cpl_malloc(nr_alloc * sizeof(char *)));
00781         KMO_TRY_EXIT_IF_NULL(
00782             exposure_objectname = cpl_malloc(nr_alloc * sizeof(char *)));
00783         KMO_TRY_EXIT_IF_NULL(
00784             exposure_ifus  = cpl_malloc(nr_alloc * sizeof(int)));
00785 
00786         // check exposure frames
00787         for (int i = 0; i < nr_exposures; i++) {
00788             KMO_TRY_EXIT_IF_NULL(
00789                 tmp_str = cpl_sprintf("%d", i));
00790 
00791             KMO_TRY_EXIT_IF_NULL(
00792                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00793             cpl_free(tmp_str);
00794 
00795             KMO_TRY_EXIT_IF_NULL(
00796                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00797 
00798             kmo_init_fits_desc(&desc);
00799 
00800             desc = kmo_identify_fits_header(exposure_filename[i]);
00801             KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to "
00802                                           "be in KMOS-format!");
00803 
00804             KMO_TRY_ASSURE(((desc.nr_ext == KMOS_NR_DETECTORS) ||
00805                             ((desc.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00806                            (desc.ex_badpix == FALSE) &&
00807                            ((desc.fits_type == raw_fits) ||
00808                             (desc.fits_type == f2d_fits)) &&
00809                            (desc.frame_type == detector_frame),
00810                            CPL_ERROR_ILLEGAL_INPUT,
00811                            "The frame to reconstruct isn't in the correct "
00812                            "format!!!");
00813             kmo_free_fits_desc(&desc);
00814         }
00815 
00816         // select IFU for each exposure
00817         KMO_TRY_EXIT_IF_NULL(
00818             empty_frames = cpl_malloc(nr_alloc * sizeof(cpl_frame *)));
00819         int found=0;
00820         for (int i = 0; i < nr_exposures; i++) {
00821             empty_frames[i] = NULL;
00822             if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
00823                 found = 1;
00824                 const char *tmpString;
00825                 exposure_ifus[i] = (int) (cpl_vector_get(ifus, i) + 0.1);
00826                 KMO_TRY_EXIT_IF_NULL(
00827                     pl = kmclipm_propertylist_load(exposure_filename[i], 0));
00828                 KMO_TRY_EXIT_IF_NULL(
00829                     tmp_ocs = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX,
00830                                           exposure_ifus[i], IFU_NAME_POSTFIX));
00831                 if (cpl_propertylist_has(pl, tmp_ocs)) {
00832                     tmpString = cpl_propertylist_get_string(pl, tmp_ocs);
00833                 } else {
00834                     tmpString = "";
00835                 }
00836                 cpl_free(tmp_ocs);
00837                 int len = strlen(tmpString);
00838                 const int maxLen = 40;
00839                 if (len > maxLen) {
00840                     len = maxLen;
00841                 }
00842                 exposure_objectname[i] = (char *) cpl_malloc(len * sizeof(char));
00843                 strncpy(exposure_objectname[i], tmpString, len-1);
00844                 if (len > 0) {
00845                     (exposure_objectname[i])[len-1] = '\0';
00846                 }
00847                 cpl_propertylist_delete(pl); pl = NULL;
00848             }  else {                   //IFU selected by user given object name
00849                 exposure_objectname[i] = (char*)name;
00850                 KMO_TRY_EXIT_IF_NULL(
00851                     tmp_str = cpl_sprintf("%d", i));
00852 
00853                 KMO_TRY_EXIT_IF_NULL(
00854                     frame = kmo_dfs_get_frame(exposures, tmp_str));
00855                 cpl_free(tmp_str);
00856 
00857                 KMO_TRY_CHECK_ERROR_STATE();
00858                 int this_ifu = kmo_get_index_from_ocs_name(frame, name);
00859                 KMO_TRY_CHECK_ERROR_STATE();
00860                 if (this_ifu > 0) {
00861                     found = 1;
00862                     exposure_ifus[i] = this_ifu;
00863                 } else {
00864                     empty_frames[i] = frame;
00865                     exposure_ifus[i] = -1;
00866                     cpl_msg_warning("",
00867                                     "Could not find any IFU with an object "
00868                                     "named '%s' in file %s",
00869                                     name, exposure_filename[i]);
00870                 }
00871             }
00872             KMO_TRY_CHECK_ERROR_STATE();
00873         }
00874         if (! found) {
00875             cpl_msg_error("",
00876                           "Could not find any IFU with an object named '%s' in "
00877                           "any input file", name);
00878             KMO_TRY_EXIT_WITH_ERROR(CPL_ERROR_ILLEGAL_INPUT);
00879         }
00880         int j = 0;
00881         for (int i = 0; i < nr_alloc; i++) {
00882             if (empty_frames[i] != NULL) {
00883                 KMO_TRY_EXIT_IF_ERROR(
00884                     cpl_frameset_erase_frame(exposures, empty_frames[i]));
00885                 nr_exposures--;
00886                 exposure_ifus[j] = exposure_ifus[i];
00887             } else {
00888                 exposure_ifus[j] = exposure_ifus[i];
00889                 j++;
00890             }
00891         }
00892         for (int i = 0; i < nr_exposures; i++) {
00893             KMO_TRY_EXIT_IF_NULL(
00894                 tmp_str = cpl_sprintf("%d", i));
00895 
00896             KMO_TRY_EXIT_IF_NULL(
00897                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00898             cpl_free(tmp_str);
00899 
00900             KMO_TRY_EXIT_IF_NULL(
00901                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00902         }
00903 
00904         cpl_free(empty_frames); empty_frames = NULL;
00905 
00906         // get reference header, subheader and set grid definition
00907         device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00908 
00909         KMO_TRY_EXIT_IF_NULL(
00910             ref_main_header = kmclipm_propertylist_load(exposure_filename[0],0));
00911         KMO_TRY_EXIT_IF_NULL(
00912             ref_frame = cpl_frameset_get_first(exposures));
00913         KMO_TRY_EXIT_IF_NULL(
00914             ref_sub_header = kmclipm_propertylist_load(exposure_filename[0],
00915                                                        device_nr));
00916         KMO_TRY_EXIT_IF_ERROR(
00917             kmclipm_setup_grid(&gd, imethod, neighborhoodRange, KMOS_PIX_RESOLUTION));
00918 
00919         exposure_rotangle = kmo_mr_get_rot_angle(kmo_dfs_get_frame(exposures, "0"));
00920         KMO_TRY_EXIT_IF_NULL(
00921             lcal_frame = kmo_mr_get_closest_cal_frame(frameset, LCAL,
00922                                                       exposure_rotangle));
00923         KMO_TRY_EXIT_IF_NULL(
00924             lcalImg = kmo_dfs_load_image_frame(lcal_frame, device_nr, 0,
00925                                                FALSE, NULL));
00926 
00927         KMO_TRY_EXIT_IF_NULL(
00928             tmp_header = kmclipm_propertylist_load(
00929                                         cpl_frame_get_filename(lcal_frame), 0));
00930         KMO_TRY_EXIT_IF_NULL(
00931             keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, device_nr,
00932                                   IFU_FILTID_POSTFIX));
00933         KMO_TRY_EXIT_IF_NULL(
00934             filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00935 
00936         int band_method = 0;
00937         KMO_TRY_EXIT_IF_NULL(
00938             band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0));
00939 
00940         KMO_TRY_EXIT_IF_ERROR(
00941             kmclipm_setup_grid_band_lcal(&gd, lcalImg, filter_id,
00942                                          band_method, band_table));
00943         cpl_image_delete(lcalImg); lcalImg = NULL;
00944         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00945         cpl_free(keyword); keyword = NULL;
00946         cpl_table_delete(band_table); band_table = NULL;
00947 
00948         //extract sub-headers for each exposures, calculate WCS
00949         KMO_TRY_EXIT_IF_NULL(
00950             header_data = cpl_malloc(nr_exposures*sizeof(cpl_propertylist*)));
00951         for (int i = 0; i < nr_exposures; i++) {
00952            device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00953            KMO_TRY_EXIT_IF_NULL(
00954                header_data[i] = kmclipm_propertylist_load(exposure_filename[i],
00955                                                           device_nr));
00956            KMO_TRY_EXIT_IF_ERROR(
00957                 kmclipm_update_property_int(header_data[i],"NAXIS", 3,""));
00958            KMO_TRY_EXIT_IF_ERROR(
00959                 kmclipm_update_property_int(header_data[i],"NAXIS1",gd.x.dim,""));
00960            KMO_TRY_EXIT_IF_ERROR(
00961                 kmclipm_update_property_int(header_data[i],"NAXIS2",gd.y.dim,""));
00962            KMO_TRY_EXIT_IF_ERROR(
00963                 kmclipm_update_property_int(header_data[i],"NAXIS3",gd.l.dim,""));
00964            cpl_propertylist *tmpHeader;
00965            KMO_TRY_EXIT_IF_NULL(
00966                 tmpHeader = kmclipm_propertylist_load(exposure_filename[i],0));
00967            KMO_TRY_EXIT_IF_ERROR(
00968                 kmo_calc_wcs_gd(tmpHeader, header_data[i], exposure_ifus[i], gd));
00969            cpl_propertylist_delete(tmpHeader);
00970         }
00971 
00972         // check rotation angle
00973         cd1_1 = kmo_dfs_get_property_double(header_data[0], CD1_1);
00974         cd1_2 = kmo_dfs_get_property_double(header_data[0], CD1_2);
00975         KMO_TRY_CHECK_ERROR_STATE();
00976         ang1 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
00977         for (int i = 1; i < nr_exposures; i++) {
00978             cd1_1 = kmo_dfs_get_property_double(header_data[i], CD1_1);
00979             cd1_2 = kmo_dfs_get_property_double(header_data[i], CD1_2);
00980             KMO_TRY_CHECK_ERROR_STATE();
00981             ang2 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
00982 
00983             if (strcmp(smethod, "none") != 0) {
00984                 // center, header, user
00985                 KMO_TRY_ASSURE(fabs(ang1-ang2) <= 0.5,
00986                                CPL_ERROR_ILLEGAL_INPUT,
00987                                "Orientation of cube 1 (%gdeg) and cube %d "
00988                                "(%gdeg) differ! "
00989                                "Align the orientation of this cube with "
00990                                "kmo_rotate before applying this recipe.",
00991                                ang1, i+1, ang2);
00992             } else {
00993                 // none
00994                 if (fabs(ang1-ang2) > 0.5) {
00995                     cpl_msg_warning("",
00996                                     "Orientation of cube 1 (%gdeg) and cube %d "
00997                                     "(%gdeg) differ! Processing anyway.",
00998                                     ang1, i+1, ang2);
00999                 }
01000             }
01001         }
01002 
01003         // set x/y shifts
01004         KMO_TRY_EXIT_IF_NULL(
01005             xshifts = cpl_malloc(nr_exposures * sizeof(double)));
01006         KMO_TRY_EXIT_IF_NULL(
01007             yshifts = cpl_malloc(nr_exposures * sizeof(double)));
01008         KMO_TRY_EXIT_IF_ERROR(
01009             kmo_mr_get_offsets(nr_exposures, smethod, imethod, neighborhoodRange,
01010                                filename, frameset, exposures, exposure_ifus,
01011                                (const cpl_propertylist**)header_data,
01012                                fmethod,
01013                                cmethod,
01014                                cpos_rej,
01015                                cneg_rej,
01016                                citer,
01017                                cmin,
01018                                cmax,
01019                                xshifts, yshifts));
01020 
01021         for (int i = 0; i < nr_exposures; i++) {
01022             printf("exposure %d: filename %s, selected IFU %d, object name "
01023                    "\"%s\", xshift %f, yshift %f\n", i, exposure_filename[i],
01024                    exposure_ifus[i], exposure_objectname[i], xshifts[i], yshifts[i]);
01025         }
01026 
01027         //
01028         // set spatial part of the grid
01029         //
01030 //        size = "max";
01031         if (strcmp(size, "max") == 0) {
01032             double xmin=0, xmax=0, ymin=0, ymax=0;
01033             double gxshift, gyshift, gxdim, gydim;
01034             double pixel_resolution = KMOS_PIXEL_RESOLUTION;
01035             int xdim, ydim;
01036 
01037             for (int i = 0; i < nr_exposures; i++) {
01038                 if (xmin > xshifts[i]) { xmin = xshifts[i]; }
01039                 if (xmax < xshifts[i]) { xmax = xshifts[i]; }
01040                 if (ymin > yshifts[i]) { ymin = yshifts[i]; }
01041                 if (ymax < yshifts[i]) { ymax = yshifts[i]; }
01042             }
01043             if (xmax > 0.0001) {
01044                 gxshift = - ceil(xmax);
01045             } else {
01046                 gxshift = 0.;
01047             }
01048             if (ymin < -0.0001) {
01049                 gyshift = floor(ymin);
01050             } else {
01051                 gyshift = 0.;
01052             }
01053             if (xmin < -0.0001) {
01054                 gxdim = - floor(xmin);
01055             } else {
01056                 gxdim = 0.;
01057             }
01058             if (ymax > 0.0001) {
01059                 gydim = ceil(ymax);
01060             } else {
01061                 gydim = 0.;
01062             }
01063 
01064             xdim = (int) (gxdim - gxshift + .5);
01065             ydim = (int) (gydim - gyshift + .5);
01066             gd.x.start += gxshift * pixel_resolution;
01067             gd.y.start += gyshift * pixel_resolution;
01068             gd.x.dim += xdim;
01069             gd.y.dim += ydim;
01070 //            printf("X: %f < %f      Y: %f < %f \n",xmin,xmax,ymin,ymax);
01071 //            printf("gxshift: %f  gxdim: %f   xdim: %d        gyshift: %f  gydim: %f  ydim: %d \n",
01072 //                    gxshift, gxdim, xdim, gyshift, gydim, ydim);
01073 //            printf("GD: %f  %d     %f %d\n", gd.x.start, gd.x.dim, gd.y.start, gd.y.dim);
01074         }
01075 
01076         //
01077         // reconstruct multiple detector images
01078         //
01079 
01080 //        printf("GD: %f %f %d     %f %f %d     %f %f %d\n",
01081 //                gd.x.start, gd.x.delta, gd.x.dim,
01082 //                gd.y.start, gd.y.delta, gd.y.dim,
01083 //                gd.l.start, gd.l.delta, gd.l.dim);
01084 
01085         KMO_TRY_EXIT_IF_ERROR(
01086             kmo_priv_multi_reconstruct(frameset,
01087                                        exposures,
01088                                        exposure_ifus,
01089                                        xshifts,
01090                                        yshifts,
01091                                        gd,
01092                                        &cube_combined_data,
01093                                        &cube_combined_noise));
01094 
01095         if (!suppress_extension) {
01096             // setup output category COMBINE + ESO PRO CATG
01097             if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
01098                 KMO_TRY_EXIT_IF_NULL(
01099                     tmp_str = cpl_sprintf("IFU"));
01100             } else {
01101                 KMO_TRY_EXIT_IF_NULL(
01102                     tmp_str = cpl_sprintf("%s", name));
01103             }
01104 
01105             KMO_TRY_EXIT_IF_NULL(
01106                 filename_output_cube = cpl_sprintf("%s_%s", CUBE_MULTI, tmp_str));
01107             cpl_free(tmp_str); tmp_str = NULL;
01108         } else {
01109             KMO_TRY_EXIT_IF_NULL(
01110                 filename_output_cube = cpl_sprintf("%s", CUBE_MULTI));
01111         }
01112 
01113         KMO_TRY_EXIT_IF_ERROR(
01114             kmo_dfs_save_main_header(frameset, filename_output_cube, "",
01115                                      ref_frame, NULL, parlist, cpl_func));
01116         // save output
01117         KMO_TRY_EXIT_IF_NULL(
01118             extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01119                                           EXT_DATA));
01120 
01121         // calculate WCS
01122         KMO_TRY_EXIT_IF_ERROR(
01123             kmo_calc_wcs_gd(ref_main_header, ref_sub_header, exposure_ifus[0], gd));
01124 
01125         KMO_TRY_EXIT_IF_ERROR(
01126             kmclipm_update_property_string(ref_sub_header,
01127                                            EXTNAME,
01128                                            extname,
01129                                            "FITS extension name"));
01130         cpl_free(extname); extname = NULL;
01131 
01132         KMO_TRY_EXIT_IF_ERROR(
01133             kmo_dfs_save_cube(cube_combined_data, filename_output_cube,
01134                               "", ref_sub_header, 0./0.));
01135 
01136         if (cube_combined_noise != NULL) {
01137             KMO_TRY_EXIT_IF_NULL(
01138                 extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01139                                               EXT_NOISE));
01140 
01141             KMO_TRY_EXIT_IF_ERROR(
01142                 kmclipm_update_property_string(ref_sub_header,
01143                                         EXTNAME,
01144                                         extname,
01145                                         "FITS extension name"));
01146             cpl_free(extname); extname = NULL;
01147 
01148             KMO_TRY_EXIT_IF_ERROR(
01149                 kmo_dfs_save_cube(cube_combined_noise, filename_output_cube,
01150                                   "", ref_sub_header, 0./0.));
01151         }
01152     }
01153     KMO_CATCH
01154     {
01155         KMO_CATCH_MSG();
01156         ret_val = -1;
01157     }
01158 
01159     cpl_free(filename_output_cube); filename_output_cube = NULL;
01160     cpl_propertylist_delete(main_header); main_header = NULL;
01161     cpl_vector_delete(ifus); ifus = NULL;
01162     cpl_imagelist_delete(cube_combined_data); cube_combined_data = NULL;
01163     cpl_imagelist_delete(cube_combined_noise); cube_combined_noise = NULL;
01164     if (exposures != NULL) {cpl_frameset_delete(exposures);}
01165     if (exposure_filename != NULL) {cpl_free(exposure_filename);}
01166     if ((ifus_txt != NULL) && (strcmp(ifus_txt, "") != 0)) { //IFU selected by user given list
01167         for (int i = 0; i < nr_alloc; i++) {
01168             cpl_free(exposure_objectname[i]);
01169         }
01170     }
01171     if (exposure_objectname != NULL) {cpl_free(exposure_objectname);}
01172     if (exposure_ifus != NULL) {cpl_free(exposure_ifus);}
01173     if (ref_main_header != NULL) {cpl_propertylist_delete(ref_main_header);}
01174     if (ref_sub_header != NULL) {cpl_propertylist_delete(ref_sub_header);}
01175     if (xshifts != NULL) {cpl_free(xshifts);}
01176     if (yshifts != NULL) {cpl_free(yshifts);}
01177 
01178     if (data_cube_list != NULL) {
01179         for (int i = 0; i < nr_exposures; i++) {
01180             cpl_imagelist_delete(data_cube_list[i]); data_cube_list[i] = NULL;
01181         }
01182         cpl_free(data_cube_list); data_cube_list = NULL;
01183     }
01184 
01185     if (noise_cube_list != NULL) {
01186         for (int i = 0; i < nr_exposures; i++) {
01187             cpl_imagelist_delete(noise_cube_list[i]); noise_cube_list[i] = NULL;
01188         }
01189         cpl_free(noise_cube_list); noise_cube_list = NULL;
01190     }
01191 
01192     if (data_header_list != NULL) {
01193         for (int i = 0; i < nr_exposures; i++) {
01194             cpl_propertylist_delete(data_header_list[i]);
01195             data_header_list[i] = NULL;
01196         }
01197         cpl_free(data_header_list); data_header_list = NULL;
01198     }
01199 
01200     if (noise_header_list != NULL) {
01201         for (int i = 0; i < nr_exposures; i++) {
01202             cpl_propertylist_delete(noise_header_list[i]);
01203             noise_header_list[i] = NULL;
01204         }
01205         cpl_free(noise_header_list); noise_header_list = NULL;
01206     }
01207 
01208     if (header_data != NULL) {
01209         for (int i = 0; i < nr_exposures; i++) {
01210             cpl_propertylist_delete(header_data[i]);
01211             header_data[i] = NULL;
01212         }
01213         cpl_free(header_data); header_data = NULL;
01214     }
01215 
01216     return ret_val;
01217 }
01218