KMOS Pipeline Reference Manual  1.2.4
kmo_multi_reconstruct.c
00001 /* $Id: kmo_multi_reconstruct.c,v 1.46 2013/08/02 09:38:57 aagudo Exp $
00002  *
00003  * This file is part of the KMOS Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: aagudo $
00023  * $Date: 2013/08/02 09:38:57 $
00024  * $Revision: 1.46 $
00025  * $Name: kmosp_v1_2_4__20130807 $
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 (--method 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 "-–method=”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 "--method\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 --method='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 --method='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 
00277     /* --imethod (interpolation method) */
00278     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.imethod",
00279                                 CPL_TYPE_STRING,
00280                                 "Method to use for interpolation. "
00281                                 "[\"NN\" (nearest neighbour), "
00282                                 "\"lwNN\" (linear weighted nearest neighbor), "
00283                                 "\"swNN\" (square weighted nearest neighbor), "
00284                                 "\"MS\" (Modified Shepard's method)",
00285                                 "kmos.kmo_multi_reconstruct",
00286                                 "MS");
00287     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "imethod");
00288     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00289     cpl_parameterlist_append(recipe->parameters, p);
00290 
00291     /* --method  (shift method) */
00292     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.method",
00293                                 CPL_TYPE_STRING,
00294                                 "The shifting method:   "
00295                                 "'none': no shifting, combined directly "
00296                                                                   "(default), "
00297                                 "'header': shift according to WCS, "
00298                                 "'center': centering algorithm, "
00299                                 "'user': read shifts from file",
00300                                 "kmos.kmo_multi_reconstruct",
00301                                 "header");
00302     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "method");
00303     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00304     cpl_parameterlist_append(recipe->parameters, p);
00305 
00306     /* --fmethod */
00307     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.fmethod",
00308                                 CPL_TYPE_STRING,
00309                                 "The fitting method (applies only when "
00310                                 "method='center'):   "
00311                                 "'gauss': fit a gauss function to collapsed "
00312                                 "image (default), "
00313                                 "'moffat': fit a moffat function to collapsed"
00314                                 " image",
00315                                 "kmos.kmo_combine",
00316                                 "gauss");
00317     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "fmethod");
00318     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00319     cpl_parameterlist_append(recipe->parameters, p);
00320 
00321     /* --name */
00322     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.name",
00323                                 CPL_TYPE_STRING,
00324                                 "Name of the object to combine.",
00325                                 "kmos.kmo_multi_reconstruct",
00326                                 "");
00327     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "name");
00328     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00329     cpl_parameterlist_append(recipe->parameters, p);
00330 
00331     /* --ifus */
00332     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.ifus",
00333                                 CPL_TYPE_STRING,
00334                                 "The indices of the IFUs to combine. "
00335                                 "\"ifu1;ifu2;...\"",
00336                                 "kmos.kmo_multi_reconstruct",
00337                                 "");
00338     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "ifus");
00339     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00340     cpl_parameterlist_append(recipe->parameters, p);
00341 
00342     /* --pix_scale */
00343     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.pix_scale",
00344                                 CPL_TYPE_DOUBLE,
00345                                 "Change the pixel scale [arcsec]. "
00346                                 "Default of 0.2\" results into cubes of 14x14pix, "
00347                                 "a scale of 0.1\" results into cubes of 28x28pix, "
00348                                 "etc.",
00349                                 "kmos.kmo_multi_reconstruct",
00350                                 KMOS_PIX_RESOLUTION);
00351     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "pix_scale");
00352     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00353     cpl_parameterlist_append(recipe->parameters, p);
00354 
00355     /* --suppress_extension */
00356     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.suppress_extension",
00357                                 CPL_TYPE_BOOL,
00358                                 "Suppress arbitrary filename extension."
00359                                 "(TRUE (apply) or FALSE (don't apply)",
00360                                 "kmos.kmo_multi_reconstruct",
00361                                 FALSE);
00362     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "suppress_extension");
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 method='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     /* --dev_cal */
00389     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.dev_cal",
00390                                 CPL_TYPE_BOOL,
00391                                 "Development only: If calibration data is to be "
00392                                 "reconstructed the ALPHA/DELTA keywords are "
00393                                 "missing. Setting this parameter to TRUE prevents "
00394                                 "according data check",
00395                                 "kmos.kmo_multi_reconstruct",
00396                                 FALSE);
00397     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "dev_cal");
00398     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00399     cpl_parameterlist_append(recipe->parameters, p);
00400 
00401     /* --size */
00402     p = cpl_parameter_new_value("kmos.kmo_multi_reconstruct.size",
00403                                 CPL_TYPE_STRING,
00404                                 "Spatial size of the output cube.",
00405                                 "kmos.kmo_multi_reconstruct",
00406                                 "max");
00407     cpl_parameter_set_alias(p, CPL_PARAMETER_MODE_CLI, "size");
00408     cpl_parameter_disable(p, CPL_PARAMETER_MODE_ENV);
00409     cpl_parameterlist_append(recipe->parameters, p);
00410 
00411     // add parameters for band-definition
00412     kmo_band_pars_create(recipe->parameters,
00413                          "kmos.kmo_multi_reconstruct");
00414 
00415     return kmo_combine_pars_create(recipe->parameters,
00416                                    "kmos.kmo_multi_reconstruct",
00417                                    DEF_REJ_METHOD,
00418                                    FALSE);
00419 }
00420 
00426 static int kmo_multi_reconstruct_exec(cpl_plugin *plugin)
00427 {
00428     cpl_recipe  *recipe;
00429 
00430     /* Get the recipe out of the plugin */
00431     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00432         recipe = (cpl_recipe *)plugin;
00433     else return -1 ;
00434 
00435     return kmo_multi_reconstruct(recipe->parameters, recipe->frames);
00436 }
00437 
00443 static int kmo_multi_reconstruct_destroy(cpl_plugin *plugin)
00444 {
00445     cpl_recipe *recipe;
00446 
00447     /* Get the recipe out of the plugin */
00448     if (cpl_plugin_get_type(plugin) == CPL_PLUGIN_TYPE_RECIPE) 
00449         recipe = (cpl_recipe *)plugin;
00450     else return -1 ;
00451 
00452     cpl_parameterlist_delete(recipe->parameters);
00453     return 0 ;
00454 }
00455 
00470 static int kmo_multi_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
00471 {
00472     const char       *method               = NULL,
00473                      *cmethod               = NULL,
00474                      *fmethod               = NULL,
00475                      *imethod               = NULL,
00476                      *filename              = NULL,
00477                      *ifus_txt              = NULL,
00478                      *name                  = NULL,
00479                      *size                  = NULL,
00480                      *filter_id             = NULL;
00481     char             *tmp_str               = NULL,
00482                      *filename_output_cube  = NULL,
00483                      *extname               = NULL,
00484                      *keyword               = NULL,
00485                      *suffix                = NULL,
00486                      *tmp_ocs               = NULL,
00487                      **exposure_filename    = NULL,
00488                      **exposure_objectname  = NULL;
00489     int              ret_val                = 0,
00490                      device_nr              = 0,
00491                      citer                  = 0,
00492                      cmin                   = 0,
00493                      cmax                   = 0,
00494                      nr_alloc               = 0,
00495                      suppress_extension     = FALSE,
00496                      i                      = 0,
00497                      *exposure_ifus         = NULL,
00498                      nr_science_frames      = 0,
00499                      dev_cal                = 0;
00500     double           neighborhoodRange      = 1.001,
00501                      cpos_rej               = 0.0,
00502                      cneg_rej               = 0.0,
00503                      pix_scale              = 0.0,
00504                      *xshifts               = NULL,
00505                      *yshifts               = NULL,
00506                      cd1_1                  = 0.0,
00507                      cd1_2                  = 0.0,
00508                      ang1                   = 0.0,
00509                      ang2                   = 0.0,
00510                      exposure_rotangle      = 0.0,
00511                      rotangle_found         = 0.0;
00512     cpl_imagelist    **data_cube_list       = NULL,
00513                      **noise_cube_list      = NULL,
00514                      *cube_combined_data    = NULL,
00515                      *cube_combined_noise   = NULL;
00516     cpl_vector       *ifus                  = NULL;
00517     cpl_propertylist *pl                    = NULL,
00518                      *main_header           = NULL,
00519                      *ref_main_header       = NULL,
00520                      *ref_sub_header        = NULL,
00521                      *tmp_header            = NULL,
00522                      **header_data          = NULL,
00523                      **data_header_list     = NULL,
00524                      **noise_header_list    = NULL;
00525     cpl_frame        *frame                 = NULL,
00526                      *lcal_frame            = NULL,
00527                      **empty_frames         = NULL,
00528                      *tmp_frame             = NULL,
00529                      *ref_frame             = NULL;
00530     cpl_table        *band_table            = NULL;
00531     cpl_image        *lcalImg               = NULL;
00532     cpl_frameset     *exposures             = NULL;
00533     main_fits_desc   desc;
00534     gridDefinition   gd;
00535 
00536     KMO_TRY
00537     {
00538         //
00539         // check frameset
00540         //
00541         KMO_TRY_ASSURE((parlist != NULL) &&
00542                        (frameset != NULL),
00543                        CPL_ERROR_NULL_INPUT,
00544                        "Not all input data is provided!");
00545 
00546         KMO_TRY_ASSURE(! ((cpl_frameset_count_tags(frameset, XCAL) == 0) &&
00547                           (cpl_frameset_count_tags(frameset, YCAL) == 0) &&
00548                           (cpl_frameset_count_tags(frameset, LCAL) == 0) &&
00549                           (cpl_frameset_count_tags(frameset, WAVE_BAND) == 0)),
00550                           CPL_ERROR_FILE_NOT_FOUND,
00551                           "XCAL, YCAL, LCAL or WAVE_BAND frames missing in "
00552                           "frameset!!");
00553 
00554         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00555                        CPL_ERROR_FILE_NOT_FOUND,
00556                        "Exactly one XCAL frame is expected in frameset!");
00557 
00558         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00559                        CPL_ERROR_FILE_NOT_FOUND,
00560                        "Exactly one YCAL frame is expected in frameset!");
00561 
00562         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00563                        CPL_ERROR_FILE_NOT_FOUND,
00564                        "Exactly one LCAL frame is expected in frameset!");
00565 
00566         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00567                        CPL_ERROR_FILE_NOT_FOUND,
00568                        "Exactly one WAVE_BAND frame is expected in frameset!");
00569 
00570         // assert that at least two SCIENCE frames are available and create
00571         // intermediate frameset just with these science frames
00572         nr_science_frames = cpl_frameset_count_tags(frameset, SCIENCE);
00573         KMO_TRY_CHECK_ERROR_STATE();
00574 
00575         KMO_TRY_ASSURE(nr_science_frames > 1,
00576                        CPL_ERROR_ILLEGAL_INPUT,
00577                        "At least two SCIENCE frames must be provided to combine!");
00578 
00579         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_multi_reconstruct") == 1,
00580                        CPL_ERROR_ILLEGAL_INPUT,
00581                        "Cannot identify RAW and CALIB frames!");
00582 
00583         KMO_TRY_EXIT_IF_NULL(
00584             exposures = cpl_frameset_new());
00585         KMO_TRY_EXIT_IF_NULL(
00586             tmp_frame = kmo_dfs_get_frame(frameset, SCIENCE));
00587 
00588         for (i = 0; i < nr_science_frames; i++) {
00589             KMO_TRY_EXIT_IF_ERROR(
00590                 cpl_frameset_insert(exposures, cpl_frame_duplicate(tmp_frame)));
00591             KMO_TRY_CHECK_ERROR_STATE();
00592 
00593             tmp_frame = kmo_dfs_get_frame(frameset, NULL);
00594         }
00595 
00596         cpl_msg_info("", "--- Parameter setup for kmo_multi_reconstruct -------");
00597 
00598         KMO_TRY_EXIT_IF_NULL(
00599             imethod = kmo_dfs_get_parameter_string(parlist,
00600                                          "kmos.kmo_multi_reconstruct.imethod"));
00601 
00602         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00603                        (strcmp(imethod, "lwNN") == 0) ||
00604                        (strcmp(imethod, "swNN") == 0) ||
00605                        (strcmp(imethod, "MS") == 0),
00606                        CPL_ERROR_ILLEGAL_INPUT,
00607                        "imethod must be either \"NN\", \"lwNN\", "
00608                        "\"swNN\" or \"MS\"!");
00609 
00610         KMO_TRY_EXIT_IF_ERROR(
00611             kmo_dfs_print_parameter_help(parlist,
00612                                         "kmos.kmo_multi_reconstruct.imethod"));
00613 
00614         pix_scale = kmo_dfs_get_parameter_double(parlist,
00615                                         "kmos.kmo_multi_reconstruct.pix_scale");
00616         KMO_TRY_CHECK_ERROR_STATE();
00617         KMO_TRY_EXIT_IF_ERROR(
00618            kmo_dfs_print_parameter_help(parlist,
00619                                        "kmos.kmo_multi_reconstruct.pix_scale"));
00620         KMO_TRY_ASSURE((pix_scale >= 0.01) &&
00621                        (pix_scale <= 0.4),
00622                        CPL_ERROR_ILLEGAL_INPUT,
00623                        "pix_scale must be between 0.01 and 0.4 (results in cubes "
00624                        "with 7x7 to 280x280 pixels)!");
00625 
00626         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00627                 "kmos.kmo_multi_reconstruct.neighborhoodRange");
00628         KMO_TRY_CHECK_ERROR_STATE();
00629 
00630         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00631                        CPL_ERROR_ILLEGAL_INPUT,
00632                        "neighborhoodRange must be greater than 0.0");
00633 
00634         KMO_TRY_EXIT_IF_ERROR(
00635             kmo_dfs_print_parameter_help(parlist,
00636                                      "kmos.kmo_multi_reconstruct.neighborhoodRange"));
00637 
00638         KMO_TRY_EXIT_IF_NULL(
00639             size = kmo_dfs_get_parameter_string(parlist,
00640                                             "kmos.kmo_multi_reconstruct.size"));
00641 
00642         KMO_TRY_EXIT_IF_NULL(
00643             method = kmo_dfs_get_parameter_string(parlist,
00644                                          "kmos.kmo_multi_reconstruct.method"));
00645 
00646         KMO_TRY_EXIT_IF_NULL(
00647             fmethod = kmo_dfs_get_parameter_string(parlist,
00648                                          "kmos.kmo_multi_reconstruct.fmethod"));
00649 
00650         KMO_TRY_ASSURE((strcmp(size, "max") == 0) ||
00651                        (strcmp(size, "std") == 0),
00652                        CPL_ERROR_ILLEGAL_INPUT,
00653                        "Following output cube size specifications are available: "
00654                        "'std' or 'max'");
00655 
00656 
00657         KMO_TRY_ASSURE((strcmp(method, "none") == 0) ||
00658                        (strcmp(method, "header") == 0) ||
00659                        (strcmp(method, "center") == 0) ||
00660                        (strcmp(method, "user") == 0),
00661                        CPL_ERROR_ILLEGAL_INPUT,
00662                        "Following shift methods are available : 'none', "
00663                        "'header', 'center' or 'user'");
00664 
00665         if (strcmp(method, "user") == 0) {
00666             filename = kmo_dfs_get_parameter_string(parlist,
00667                                          "kmos.kmo_multi_reconstruct.filename");
00668             KMO_TRY_CHECK_ERROR_STATE();
00669 
00670             KMO_TRY_ASSURE(strcmp(filename, "") != 0,
00671                            CPL_ERROR_ILLEGAL_INPUT,
00672                            "path of file with shift information must be "
00673                            "provided!");
00674 
00675             KMO_TRY_EXIT_IF_ERROR(
00676                 kmo_dfs_print_parameter_help(parlist,
00677                                         "kmos.kmo_multi_reconstruct.filename"));
00678         }
00679 
00680         KMO_TRY_EXIT_IF_ERROR(
00681             kmo_dfs_print_parameter_help(parlist,
00682                                          "kmos.kmo_multi_reconstruct.method"));
00683 
00684         ifus_txt = kmo_dfs_get_parameter_string(parlist,
00685                                              "kmos.kmo_multi_reconstruct.ifus");
00686         KMO_TRY_CHECK_ERROR_STATE();
00687 
00688         name = kmo_dfs_get_parameter_string(parlist,
00689                                             "kmos.kmo_multi_reconstruct.name");
00690         KMO_TRY_CHECK_ERROR_STATE();
00691 
00692         if (strcmp(ifus_txt, "") != 0) {
00693             KMO_TRY_ASSURE(strcmp(name, "") == 0,
00694                            CPL_ERROR_ILLEGAL_INPUT,
00695                            "name parameter must be NULL if IFU indices are "
00696                            "provided!");
00697 
00698             KMO_TRY_EXIT_IF_NULL(
00699                 ifus = kmo_identify_values(ifus_txt));
00700 
00701             KMO_TRY_ASSURE(cpl_vector_get_size(ifus) == nr_science_frames,
00702                            CPL_ERROR_ILLEGAL_INPUT,
00703                            "ifus parameter must have the same number of values "
00704                            "than frames provided ) (%lld!=%d)",
00705                            cpl_vector_get_size(ifus), nr_science_frames);
00706 
00707             for (i = 0; i < nr_science_frames; i++) {
00708                 KMO_TRY_ASSURE((cpl_vector_get(ifus, i) > 0.5 &&
00709                                cpl_vector_get(ifus, i) < 24.5 ),
00710                                CPL_ERROR_ILLEGAL_INPUT,
00711                                "IFU numbers must be in the range 1..24");
00712             }
00713         }
00714 
00715         if (strcmp(name, "") != 0) {
00716             KMO_TRY_ASSURE(strcmp(ifus_txt, "") == 0,
00717                            CPL_ERROR_ILLEGAL_INPUT,
00718                            "ifus parameter must be NULL if name is provided!");
00719         }
00720 
00721         KMO_TRY_ASSURE((strcmp(name, "") != 0) || (strcmp(ifus_txt, "") != 0),
00722                        CPL_ERROR_ILLEGAL_INPUT,
00723                        "Either the name of the object or the numbers of the "
00724                        "IFUs to combine must be provided (--name or --ifus "
00725                        "parameters)");
00726 
00727         KMO_TRY_EXIT_IF_ERROR(
00728             kmo_dfs_print_parameter_help(parlist,
00729                                          "kmos.kmo_multi_reconstruct.ifus"));
00730 
00731         KMO_TRY_EXIT_IF_ERROR(
00732             kmo_dfs_print_parameter_help(parlist,
00733                                          "kmos.kmo_multi_reconstruct.name"));
00734 
00735 
00736         suppress_extension = kmo_dfs_get_parameter_bool(parlist,
00737                                           "kmos.kmo_multi_reconstruct.suppress_extension");
00738         KMO_TRY_CHECK_ERROR_STATE();
00739         KMO_TRY_EXIT_IF_ERROR(
00740             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_multi_reconstruct.suppress_extension"));
00741 
00742         KMO_TRY_ASSURE((suppress_extension == TRUE) || (suppress_extension == FALSE),
00743                        CPL_ERROR_ILLEGAL_INPUT,
00744                        "suppress_extension must be TRUE or FALSE!");
00745 
00746         dev_cal = kmo_dfs_get_parameter_bool(parlist,
00747                                              "kmos.kmo_multi_reconstruct.dev_cal");
00748            KMO_TRY_CHECK_ERROR_STATE();
00749            KMO_TRY_EXIT_IF_ERROR(
00750                kmo_dfs_print_parameter_help(parlist, "kmos.kmo_multi_reconstruct.dev_cal"));
00751 
00752            KMO_TRY_ASSURE((dev_cal == TRUE) || (dev_cal == FALSE),
00753                           CPL_ERROR_ILLEGAL_INPUT,
00754                           "dev_cal must be TRUE or FALSE!");
00755 
00756         KMO_TRY_EXIT_IF_ERROR(
00757             kmo_combine_pars_load(parlist,
00758                                   "kmos.kmo_multi_reconstruct",
00759                                   &cmethod,
00760                                   &cpos_rej,
00761                                   &cneg_rej,
00762                                   &citer,
00763                                   &cmin,
00764                                   &cmax,
00765                                   FALSE));
00766 
00767         kmo_band_pars_load(parlist, "kmos.kmo_multi_reconstruct");
00768 
00769         cpl_msg_info("", "-------------------------------------------");
00770 
00771         KMO_TRY_EXIT_IF_NULL(
00772             tmp_frame = kmo_dfs_get_frame(frameset, SCIENCE));
00773 
00774         KMO_TRY_EXIT_IF_NULL(
00775             suffix = kmo_dfs_get_suffix(tmp_frame, TRUE, FALSE));
00776 
00777         KMO_TRY_EXIT_IF_ERROR(
00778             kmo_check_frame_setup_md5_xycal(frameset));
00779         KMO_TRY_EXIT_IF_ERROR(
00780             kmo_check_frame_setup_md5(frameset));
00781 
00782         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00783         cpl_msg_info("", "(grating 1, 2 & 3)");
00784         cpl_msg_info("", "-------------------------------------------");
00785 
00786         // assure that filters and grating  match for
00787         // XCAL, YCAL, LCAL and for data frames to reconstruct
00788         KMO_TRY_EXIT_IF_ERROR(
00789             kmo_check_frameset_setup(frameset, XCAL, TRUE, FALSE, FALSE));
00790         KMO_TRY_EXIT_IF_ERROR(
00791             kmo_check_frameset_setup(frameset, YCAL, TRUE, FALSE, FALSE));
00792         KMO_TRY_EXIT_IF_ERROR(
00793             kmo_check_frameset_setup(frameset, LCAL, TRUE, FALSE, FALSE));
00794         KMO_TRY_EXIT_IF_ERROR(
00795             kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE));
00796         KMO_TRY_EXIT_IF_ERROR(
00797             kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE));
00798         KMO_TRY_EXIT_IF_ERROR(
00799             kmo_check_frameset_setup(frameset, SCIENCE, TRUE, FALSE, FALSE));
00800         KMO_TRY_EXIT_IF_ERROR(
00801             kmo_check_frame_setup(frameset, XCAL, SCIENCE, TRUE, FALSE, TRUE));
00802         KMO_TRY_EXIT_IF_ERROR(
00803             kmo_check_frame_setup_md5_xycal(frameset));
00804         KMO_TRY_EXIT_IF_ERROR(
00805             kmo_check_frame_setup_md5(frameset));
00806 
00807 //        KMO_TRY_EXIT_IF_ERROR(
00808 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00809 //        KMO_TRY_EXIT_IF_ERROR(
00810 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00811 
00812         nr_alloc = nr_science_frames;
00813         KMO_TRY_EXIT_IF_NULL(
00814             exposure_filename = cpl_malloc(nr_alloc * sizeof(char *)));
00815         KMO_TRY_EXIT_IF_NULL(
00816             exposure_objectname = cpl_malloc(nr_alloc * sizeof(char *)));
00817         KMO_TRY_EXIT_IF_NULL(
00818             exposure_ifus  = cpl_malloc(nr_alloc * sizeof(int)));
00819 
00820         // check exposure frames
00821         for (i = 0; i < nr_science_frames; i++) {
00822             KMO_TRY_EXIT_IF_NULL(
00823                 tmp_str = cpl_sprintf("%d", i));
00824 
00825             KMO_TRY_EXIT_IF_NULL(
00826                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00827             cpl_free(tmp_str);
00828 
00829             KMO_TRY_EXIT_IF_NULL(
00830                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00831 
00832             kmo_init_fits_desc(&desc);
00833 
00834             desc = kmo_identify_fits_header(exposure_filename[i]);
00835             KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to "
00836                                           "be in KMOS-format!");
00837 
00838             KMO_TRY_ASSURE(((desc.nr_ext == KMOS_NR_DETECTORS) ||
00839                             ((desc.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00840                            (desc.ex_badpix == FALSE) &&
00841                            ((desc.fits_type == raw_fits) ||
00842                             (desc.fits_type == f2d_fits)) &&
00843                            (desc.frame_type == detector_frame),
00844                            CPL_ERROR_ILLEGAL_INPUT,
00845                            "The frame to reconstruct isn't in the correct "
00846                            "format!!!");
00847             kmo_free_fits_desc(&desc);
00848         }
00849 
00850         // select IFU for each exposure
00851         KMO_TRY_EXIT_IF_NULL(
00852             empty_frames = cpl_malloc(nr_alloc * sizeof(cpl_frame *)));
00853         int found=0;
00854         for (i = 0; i < nr_science_frames; i++) {
00855             empty_frames[i] = NULL;
00856             if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
00857                 found = 1;
00858 //                const char *tmpString;
00859                 exposure_ifus[i] = (int) (cpl_vector_get(ifus, i) + 0.1);
00860                 KMO_TRY_EXIT_IF_NULL(
00861                     pl = kmclipm_propertylist_load(exposure_filename[i], 0));
00862                 KMO_TRY_EXIT_IF_NULL(
00863                     tmp_ocs = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX,
00864                                           exposure_ifus[i], IFU_NAME_POSTFIX));
00865                 if (cpl_propertylist_has(pl, tmp_ocs)) {
00866                     tmp_str = (char*)cpl_propertylist_get_string(pl, tmp_ocs);
00867                 } else {
00868                     tmp_str = "";
00869                 }
00870                 KMO_TRY_EXIT_IF_NULL(
00871                     exposure_objectname[i] = cpl_sprintf("%s", tmp_str));
00872                 cpl_free(tmp_ocs);
00873                 cpl_propertylist_delete(pl); pl = NULL;
00874             }  else {                   //IFU selected by user given object name
00875                 exposure_objectname[i] = (char*)name;
00876                 KMO_TRY_EXIT_IF_NULL(
00877                     tmp_str = cpl_sprintf("%d", i));
00878 
00879                 KMO_TRY_EXIT_IF_NULL(
00880                     frame = kmo_dfs_get_frame(exposures, tmp_str));
00881                 cpl_free(tmp_str);
00882 
00883                 KMO_TRY_CHECK_ERROR_STATE();
00884                 int this_ifu = kmo_get_index_from_ocs_name(frame, name);
00885                 KMO_TRY_CHECK_ERROR_STATE();
00886                 if (this_ifu > 0) {
00887                     found = 1;
00888                     exposure_ifus[i] = this_ifu;
00889                 } else {
00890                     empty_frames[i] = frame;
00891                     exposure_ifus[i] = -1;
00892                     cpl_msg_warning("",
00893                                     "Could not find any IFU with an object "
00894                                     "named '%s' in file %s",
00895                                     name, exposure_filename[i]);
00896                 }
00897             }
00898             KMO_TRY_CHECK_ERROR_STATE();
00899         }
00900         if (! found) {
00901             cpl_msg_error("",
00902                           "Could not find any IFU with an object named '%s' in "
00903                           "any input file", name);
00904             KMO_TRY_EXIT_WITH_ERROR(CPL_ERROR_ILLEGAL_INPUT);
00905         }
00906         int j = 0;
00907         for (i = 0; i < nr_alloc; i++) {
00908             if (empty_frames[i] != NULL) {
00909                 KMO_TRY_EXIT_IF_ERROR(
00910                     cpl_frameset_erase_frame(exposures, empty_frames[i]));
00911                 nr_science_frames--;
00912                 exposure_ifus[j] = exposure_ifus[i];
00913             } else {
00914                 exposure_ifus[j] = exposure_ifus[i];
00915                 j++;
00916             }
00917         }
00918         for (i = 0; i < nr_science_frames; i++) {
00919             KMO_TRY_EXIT_IF_NULL(
00920                 tmp_str = cpl_sprintf("%d", i));
00921 
00922             KMO_TRY_EXIT_IF_NULL(
00923                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00924             cpl_free(tmp_str);
00925 
00926             KMO_TRY_EXIT_IF_NULL(
00927                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00928         }
00929 
00930         cpl_free(empty_frames); empty_frames = NULL;
00931 
00932         // get reference header, subheader and set grid definition
00933         device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00934 
00935         KMO_TRY_EXIT_IF_NULL(
00936             ref_main_header = kmclipm_propertylist_load(exposure_filename[0],0));
00937         KMO_TRY_EXIT_IF_NULL(
00938             ref_frame = cpl_frameset_get_first(exposures));
00939         KMO_TRY_EXIT_IF_NULL(
00940             ref_sub_header = kmclipm_propertylist_load(exposure_filename[0],
00941                                                        device_nr));
00942         KMO_TRY_EXIT_IF_ERROR(
00943             kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale));
00944 
00945         exposure_rotangle = kmo_mr_get_rot_angle(kmo_dfs_get_frame(exposures, "0"));
00946 
00947         KMO_TRY_EXIT_IF_NULL(
00948             lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
00949 
00950         KMO_TRY_EXIT_IF_NULL(
00951             lcalImg = kmo_dfs_load_cal_image_frame(lcal_frame,
00952                                                    1, 0, exposure_rotangle,
00953                                                    FALSE, NULL,
00954                                                    &rotangle_found, -1, 0, 0));
00955 
00956         KMO_TRY_EXIT_IF_NULL(
00957             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00958 
00959         KMO_TRY_EXIT_IF_NULL(
00960             keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, device_nr,
00961                                   IFU_FILTID_POSTFIX));
00962         KMO_TRY_EXIT_IF_NULL(
00963             filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00964 
00965         int band_method = 0;
00966         KMO_TRY_EXIT_IF_NULL(
00967             band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0));
00968 
00969         KMO_TRY_EXIT_IF_ERROR(
00970             kmclipm_setup_grid_band_lcal(&gd, lcalImg, filter_id,
00971                                          band_method, band_table));
00972         cpl_image_delete(lcalImg); lcalImg = NULL;
00973         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00974         cpl_free(keyword); keyword = NULL;
00975         cpl_table_delete(band_table); band_table = NULL;
00976 
00977         //extract sub-headers for each exposures, calculate WCS
00978         KMO_TRY_EXIT_IF_NULL(
00979             header_data = cpl_malloc(nr_science_frames*sizeof(cpl_propertylist*)));
00980         for (i = 0; i < nr_science_frames; i++) {
00981            device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00982            KMO_TRY_EXIT_IF_NULL(
00983                header_data[i] = kmclipm_propertylist_load(exposure_filename[i],
00984                                                           device_nr));
00985            KMO_TRY_EXIT_IF_ERROR(
00986                 kmclipm_update_property_int(header_data[i],"NAXIS", 3,""));
00987            KMO_TRY_EXIT_IF_ERROR(
00988                 kmclipm_update_property_int(header_data[i],"NAXIS1",gd.x.dim,""));
00989            KMO_TRY_EXIT_IF_ERROR(
00990                 kmclipm_update_property_int(header_data[i],"NAXIS2",gd.y.dim,""));
00991            KMO_TRY_EXIT_IF_ERROR(
00992                 kmclipm_update_property_int(header_data[i],"NAXIS3",gd.l.dim,""));
00993            cpl_propertylist *tmpHeader;
00994            KMO_TRY_EXIT_IF_NULL(
00995                 tmpHeader = kmclipm_propertylist_load(exposure_filename[i],0));
00996            KMO_TRY_EXIT_IF_ERROR(
00997                 kmo_calc_wcs_gd(tmpHeader, header_data[i], exposure_ifus[i], gd));
00998            cpl_propertylist_delete(tmpHeader);
00999         }
01000 
01001         // check rotation angle
01002         if (dev_cal == FALSE) {
01003             cd1_1 = kmo_dfs_get_property_double(header_data[0], CD1_1);
01004             cd1_2 = kmo_dfs_get_property_double(header_data[0], CD1_2);
01005             KMO_TRY_CHECK_ERROR_STATE();
01006             ang1 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
01007             for (i = 1; i < nr_science_frames; i++) {
01008                 cd1_1 = kmo_dfs_get_property_double(header_data[i], CD1_1);
01009                 cd1_2 = kmo_dfs_get_property_double(header_data[i], CD1_2);
01010                 KMO_TRY_CHECK_ERROR_STATE();
01011                 ang2 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
01012 
01013                 if (strcmp(method, "none") != 0) {
01014                     // center, header, user
01015                     KMO_TRY_ASSURE(fabs(ang1-ang2) <= 0.5,
01016                                    CPL_ERROR_ILLEGAL_INPUT,
01017                                    "Orientation of cube 1 (%gdeg) and cube %d "
01018                                    "(%gdeg) differ! "
01019                                    "Align the orientation of this cube with "
01020                                    "kmo_rotate before applying this recipe.",
01021                                    ang1, i+1, ang2);
01022                 } else {
01023                     // none
01024                     if (fabs(ang1-ang2) > 0.5) {
01025                         cpl_msg_warning("",
01026                                         "Orientation of cube 1 (%gdeg) and cube %d "
01027                                         "(%gdeg) differ! Processing anyway.",
01028                                         ang1, i+1, ang2);
01029                     }
01030                 }
01031             }
01032         }
01033 
01034         // set x/y shifts
01035         KMO_TRY_EXIT_IF_NULL(
01036             xshifts = cpl_malloc(nr_science_frames * sizeof(double)));
01037         KMO_TRY_EXIT_IF_NULL(
01038             yshifts = cpl_malloc(nr_science_frames * sizeof(double)));
01039         KMO_TRY_EXIT_IF_ERROR(
01040             kmo_mr_get_offsets(nr_science_frames, method, imethod, neighborhoodRange,
01041                                filename, frameset, exposures, exposure_ifus,
01042                                (const cpl_propertylist**)header_data,
01043                                fmethod,
01044                                cmethod,
01045                                cpos_rej,
01046                                cneg_rej,
01047                                citer,
01048                                cmin,
01049                                cmax,
01050                                pix_scale,
01051                                xshifts, yshifts));
01052 
01053         for (i = 0; i < nr_science_frames; i++) {
01054             printf("exposure %d: filename %s, selected IFU %d, object name "
01055                    "\"%s\", xshift %f, yshift %f\n", i, exposure_filename[i],
01056                    exposure_ifus[i], exposure_objectname[i], xshifts[i], yshifts[i]);
01057         }
01058 
01059         //
01060         // set spatial part of the grid
01061         //
01062 //        size = "max";
01063         if (strcmp(size, "max") == 0) {
01064             double xmin=0, xmax=0, ymin=0, ymax=0;
01065             double gxshift, gyshift, gxdim, gydim;
01066             double pixel_resolution = pix_scale;
01067             int xdim, ydim;
01068 
01069             for (i = 0; i < nr_science_frames; i++) {
01070                 if (xmin > xshifts[i]) { xmin = xshifts[i]; }
01071                 if (xmax < xshifts[i]) { xmax = xshifts[i]; }
01072                 if (ymin > yshifts[i]) { ymin = yshifts[i]; }
01073                 if (ymax < yshifts[i]) { ymax = yshifts[i]; }
01074             }
01075             if (xmax > 0.0001) {
01076                 gxshift = - ceil(xmax);
01077             } else {
01078                 gxshift = 0.;
01079             }
01080             if (ymin < -0.0001) {
01081                 gyshift = floor(ymin);
01082             } else {
01083                 gyshift = 0.;
01084             }
01085             if (xmin < -0.0001) {
01086                 gxdim = - floor(xmin);
01087             } else {
01088                 gxdim = 0.;
01089             }
01090             if (ymax > 0.0001) {
01091                 gydim = ceil(ymax);
01092             } else {
01093                 gydim = 0.;
01094             }
01095 
01096             xdim = (int) (gxdim - gxshift + .5);
01097             ydim = (int) (gydim - gyshift + .5);
01098             gd.x.start += gxshift * pixel_resolution;
01099             gd.y.start += gyshift * pixel_resolution;
01100             gd.x.dim += xdim;
01101             gd.y.dim += ydim;
01102 //            printf("X: %f < %f      Y: %f < %f \n",xmin,xmax,ymin,ymax);
01103 //            printf("gxshift: %f  gxdim: %f   xdim: %d        gyshift: %f  gydim: %f  ydim: %d \n",
01104 //                    gxshift, gxdim, xdim, gyshift, gydim, ydim);
01105 //            printf("GD: %f  %d     %f %d\n", gd.x.start, gd.x.dim, gd.y.start, gd.y.dim);
01106         }
01107 
01108         //
01109         // reconstruct multiple detector images
01110         //
01111 
01112 //        printf("GD: %f %f %d     %f %f %d     %f %f %d\n",
01113 //                gd.x.start, gd.x.delta, gd.x.dim,
01114 //                gd.y.start, gd.y.delta, gd.y.dim,
01115 //                gd.l.start, gd.l.delta, gd.l.dim);
01116 
01117         KMO_TRY_EXIT_IF_ERROR(
01118             kmo_priv_multi_reconstruct(frameset,
01119                                        exposures,
01120                                        exposure_ifus,
01121                                        xshifts,
01122                                        yshifts,
01123                                        gd,
01124                                        &cube_combined_data,
01125                                        &cube_combined_noise,
01126                                        pix_scale));
01127 
01128         if (!suppress_extension) {
01129             // setup output category COMBINE + ESO PRO CATG
01130             if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
01131                 KMO_TRY_EXIT_IF_NULL(
01132                     tmp_str = cpl_sprintf("IFU"));
01133             } else {
01134                 KMO_TRY_EXIT_IF_NULL(
01135                     tmp_str = cpl_sprintf("%s", name));
01136             }
01137 
01138             KMO_TRY_EXIT_IF_NULL(
01139                 filename_output_cube = cpl_sprintf("%s_%s", CUBE_MULTI, tmp_str));
01140             cpl_free(tmp_str); tmp_str = NULL;
01141         } else {
01142             KMO_TRY_EXIT_IF_NULL(
01143                 filename_output_cube = cpl_sprintf("%s", CUBE_MULTI));
01144         }
01145 
01146         KMO_TRY_EXIT_IF_ERROR(
01147             kmo_dfs_save_main_header(frameset, filename_output_cube, "",
01148                                      ref_frame, NULL, parlist, cpl_func));
01149         // save output
01150         KMO_TRY_EXIT_IF_NULL(
01151             extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01152                                           EXT_DATA));
01153 
01154         // calculate WCS
01155         KMO_TRY_EXIT_IF_ERROR(
01156             kmo_calc_wcs_gd(ref_main_header, ref_sub_header, exposure_ifus[0], gd));
01157 
01158         KMO_TRY_EXIT_IF_ERROR(
01159             kmclipm_update_property_string(ref_sub_header,
01160                                            EXTNAME,
01161                                            extname,
01162                                            "FITS extension name"));
01163         cpl_free(extname); extname = NULL;
01164 
01165         KMO_TRY_EXIT_IF_ERROR(
01166             kmo_dfs_save_cube(cube_combined_data, filename_output_cube,
01167                               "", ref_sub_header, 0./0.));
01168 
01169         if (cube_combined_noise != NULL) {
01170             KMO_TRY_EXIT_IF_NULL(
01171                 extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01172                                               EXT_NOISE));
01173 
01174             KMO_TRY_EXIT_IF_ERROR(
01175                 kmclipm_update_property_string(ref_sub_header,
01176                                         EXTNAME,
01177                                         extname,
01178                                         "FITS extension name"));
01179             cpl_free(extname); extname = NULL;
01180 
01181             KMO_TRY_EXIT_IF_ERROR(
01182                 kmo_dfs_save_cube(cube_combined_noise, filename_output_cube,
01183                                   "", ref_sub_header, 0./0.));
01184         }
01185     }
01186     KMO_CATCH
01187     {
01188         KMO_CATCH_MSG();
01189         ret_val = -1;
01190     }
01191 
01192     cpl_free(suffix); suffix = NULL;
01193     cpl_free(filename_output_cube); filename_output_cube = NULL;
01194     cpl_propertylist_delete(main_header); main_header = NULL;
01195     cpl_vector_delete(ifus); ifus = NULL;
01196     cpl_imagelist_delete(cube_combined_data); cube_combined_data = NULL;
01197     cpl_imagelist_delete(cube_combined_noise); cube_combined_noise = NULL;
01198     if (exposures != NULL) {cpl_frameset_delete(exposures);}
01199     if (exposure_filename != NULL) {cpl_free(exposure_filename);}
01200     if ((ifus_txt != NULL) && (strcmp(ifus_txt, "") != 0)) { //IFU selected by user given list
01201         for (i = 0; i < nr_alloc; i++) {
01202             cpl_free(exposure_objectname[i]);
01203         }
01204     }
01205     if (exposure_objectname != NULL) {cpl_free(exposure_objectname);}
01206     if (exposure_ifus != NULL) {cpl_free(exposure_ifus);}
01207     if (ref_main_header != NULL) {cpl_propertylist_delete(ref_main_header);}
01208     if (ref_sub_header != NULL) {cpl_propertylist_delete(ref_sub_header);}
01209     if (xshifts != NULL) {cpl_free(xshifts);}
01210     if (yshifts != NULL) {cpl_free(yshifts);}
01211 
01212     if (data_cube_list != NULL) {
01213         for (i = 0; i < nr_science_frames; i++) {
01214             cpl_imagelist_delete(data_cube_list[i]); data_cube_list[i] = NULL;
01215         }
01216         cpl_free(data_cube_list); data_cube_list = NULL;
01217     }
01218 
01219     if (noise_cube_list != NULL) {
01220         for (i = 0; i < nr_science_frames; i++) {
01221             cpl_imagelist_delete(noise_cube_list[i]); noise_cube_list[i] = NULL;
01222         }
01223         cpl_free(noise_cube_list); noise_cube_list = NULL;
01224     }
01225 
01226     if (data_header_list != NULL) {
01227         for (i = 0; i < nr_science_frames; i++) {
01228             cpl_propertylist_delete(data_header_list[i]);
01229             data_header_list[i] = NULL;
01230         }
01231         cpl_free(data_header_list); data_header_list = NULL;
01232     }
01233 
01234     if (noise_header_list != NULL) {
01235         for (i = 0; i < nr_science_frames; i++) {
01236             cpl_propertylist_delete(noise_header_list[i]);
01237             noise_header_list[i] = NULL;
01238         }
01239         cpl_free(noise_header_list); noise_header_list = NULL;
01240     }
01241 
01242     if (header_data != NULL) {
01243         for (i = 0; i < nr_science_frames; i++) {
01244             cpl_propertylist_delete(header_data[i]);
01245             header_data[i] = NULL;
01246         }
01247         cpl_free(header_data); header_data = NULL;
01248     }
01249 
01250     return ret_val;
01251 }
01252