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