KMOS Pipeline Reference Manual  1.2.2
kmo_multi_reconstruct.c
00001 /* $Id: kmo_multi_reconstruct.c,v 1.40 2013/06/27 13:09:49 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/27 13:09:49 $
00024  * $Revision: 1.40 $
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                                 "header");
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 
00471 static int kmo_multi_reconstruct(cpl_parameterlist *parlist, cpl_frameset *frameset)
00472 {
00473     const char       *smethod               = NULL,
00474                      *cmethod               = NULL,
00475                      *fmethod               = NULL,
00476                      *imethod               = NULL,
00477                      *filename              = NULL,
00478                      *ifus_txt              = NULL,
00479                      *name                  = NULL,
00480                      *size                  = NULL,
00481                      *filter_id             = NULL;
00482     char             *tmp_str               = NULL,
00483                      *filename_output_cube  = NULL,
00484                      *extname               = NULL,
00485                      *keyword               = NULL,
00486                      *suffix                = NULL,
00487                      *tmp_ocs               = NULL,
00488                      **exposure_filename    = NULL,
00489                      **exposure_objectname  = NULL;
00490     int              ret_val                = 0,
00491                      device_nr              = 0,
00492                      citer                  = 0,
00493                      cmin                   = 0,
00494                      cmax                   = 0,
00495                      nr_alloc               = 0,
00496                      suppress_extension     = FALSE,
00497                      i                      = 0,
00498                      *exposure_ifus         = NULL,
00499                      nr_science_frames      = 0,
00500                      dev_cal                = 0;
00501     double           neighborhoodRange      = 1.001,
00502                      cpos_rej               = 0.0,
00503                      cneg_rej               = 0.0,
00504                      pix_scale              = 0.0,
00505                      *xshifts               = NULL,
00506                      *yshifts               = NULL,
00507                      cd1_1                  = 0.0,
00508                      cd1_2                  = 0.0,
00509                      ang1                   = 0.0,
00510                      ang2                   = 0.0,
00511                      exposure_rotangle      = 0.0,
00512                      rotangle_found         = 0.0;
00513     cpl_imagelist    **data_cube_list       = NULL,
00514                      **noise_cube_list      = NULL,
00515                      *cube_combined_data    = NULL,
00516                      *cube_combined_noise   = NULL;
00517     cpl_vector       *ifus                  = NULL;
00518     cpl_propertylist *pl                    = NULL,
00519                      *main_header           = NULL,
00520                      *ref_main_header       = NULL,
00521                      *ref_sub_header        = NULL,
00522                      *tmp_header            = NULL,
00523                      **header_data          = NULL,
00524                      **data_header_list     = NULL,
00525                      **noise_header_list    = NULL;
00526     cpl_frame        *frame                 = NULL,
00527                      *lcal_frame            = NULL,
00528                      **empty_frames         = NULL,
00529                      *tmp_frame             = NULL,
00530                      *ref_frame             = NULL;
00531     cpl_table        *band_table            = NULL;
00532     cpl_image        *lcalImg               = NULL;
00533     cpl_frameset     *exposures             = NULL;
00534     main_fits_desc   desc;
00535     gridDefinition   gd;
00536 
00537     KMO_TRY
00538     {
00539         //
00540         // check frameset
00541         //
00542         KMO_TRY_ASSURE((parlist != NULL) &&
00543                        (frameset != NULL),
00544                        CPL_ERROR_NULL_INPUT,
00545                        "Not all input data is provided!");
00546 
00547         KMO_TRY_ASSURE(! ((cpl_frameset_count_tags(frameset, XCAL) == 0) &&
00548                           (cpl_frameset_count_tags(frameset, YCAL) == 0) &&
00549                           (cpl_frameset_count_tags(frameset, LCAL) == 0) &&
00550                           (cpl_frameset_count_tags(frameset, WAVE_BAND) == 0)),
00551                           CPL_ERROR_FILE_NOT_FOUND,
00552                           "XCAL, YCAL, LCAL or WAVE_BAND frames missing in "
00553                           "frameset!!");
00554 
00555         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, XCAL) == 1,
00556                        CPL_ERROR_FILE_NOT_FOUND,
00557                        "Exactly one XCAL frame is expected in frameset!");
00558 
00559         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, YCAL) == 1,
00560                        CPL_ERROR_FILE_NOT_FOUND,
00561                        "Exactly one YCAL frame is expected in frameset!");
00562 
00563         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, LCAL) == 1,
00564                        CPL_ERROR_FILE_NOT_FOUND,
00565                        "Exactly one LCAL frame is expected in frameset!");
00566 
00567         KMO_TRY_ASSURE(cpl_frameset_count_tags(frameset, WAVE_BAND) == 1,
00568                        CPL_ERROR_FILE_NOT_FOUND,
00569                        "Exactly one WAVE_BAND frame is expected in frameset!");
00570 
00571         // assert that at least two SCIENCE frames are available and create
00572         // intermediate frameset just with these science frames
00573         nr_science_frames = cpl_frameset_count_tags(frameset, SCIENCE);
00574         KMO_TRY_CHECK_ERROR_STATE();
00575 
00576         KMO_TRY_ASSURE(nr_science_frames > 1,
00577                        CPL_ERROR_ILLEGAL_INPUT,
00578                        "At least two SCIENCE frames must be provided to combine!");
00579 
00580         KMO_TRY_ASSURE(kmo_dfs_set_groups(frameset, "kmo_multi_reconstruct") == 1,
00581                        CPL_ERROR_ILLEGAL_INPUT,
00582                        "Cannot identify RAW and CALIB frames!");
00583 
00584         KMO_TRY_EXIT_IF_NULL(
00585             exposures = cpl_frameset_new());
00586         KMO_TRY_EXIT_IF_NULL(
00587             tmp_frame = kmo_dfs_get_frame(frameset, SCIENCE));
00588 
00589         for (i = 0; i < nr_science_frames; i++) {
00590             KMO_TRY_EXIT_IF_ERROR(
00591                 cpl_frameset_insert(exposures, cpl_frame_duplicate(tmp_frame)));
00592             KMO_TRY_CHECK_ERROR_STATE();
00593 
00594             tmp_frame = kmo_dfs_get_frame(frameset, NULL);
00595         }
00596 
00597         cpl_msg_info("", "--- Parameter setup for kmo_multi_reconstruct -------");
00598 
00599         KMO_TRY_EXIT_IF_NULL(
00600             imethod = kmo_dfs_get_parameter_string(parlist,
00601                                          "kmos.kmo_multi_reconstruct.imethod"));
00602 
00603         KMO_TRY_ASSURE((strcmp(imethod, "NN") == 0) ||
00604                        (strcmp(imethod, "lwNN") == 0) ||
00605                        (strcmp(imethod, "swNN") == 0) ||
00606                        (strcmp(imethod, "MS") == 0) ||
00607                        (strcmp(imethod, "CS") == 0),
00608                        CPL_ERROR_ILLEGAL_INPUT,
00609                        "imethod must be either \"NN\", \"lwNN\", "
00610                        "\"swNN\", \"MS\" or \"CS\"!");
00611 
00612         KMO_TRY_EXIT_IF_ERROR(
00613             kmo_dfs_print_parameter_help(parlist,
00614                                         "kmos.kmo_multi_reconstruct.imethod"));
00615 
00616         pix_scale = kmo_dfs_get_parameter_double(parlist,
00617                                         "kmos.kmo_multi_reconstruct.pix_scale");
00618         KMO_TRY_CHECK_ERROR_STATE();
00619         KMO_TRY_EXIT_IF_ERROR(
00620            kmo_dfs_print_parameter_help(parlist,
00621                                        "kmos.kmo_multi_reconstruct.pix_scale"));
00622         KMO_TRY_ASSURE((pix_scale >= 0.01) &&
00623                        (pix_scale <= 0.4),
00624                        CPL_ERROR_ILLEGAL_INPUT,
00625                        "pix_scale must be between 0.01 and 0.4 (results in cubes "
00626                        "with 7x7 to 280x280 pixels)!");
00627 
00628         neighborhoodRange = kmo_dfs_get_parameter_double(parlist,
00629                 "kmos.kmo_multi_reconstruct.neighborhoodRange");
00630         KMO_TRY_CHECK_ERROR_STATE();
00631 
00632         KMO_TRY_ASSURE(neighborhoodRange > 0.0,
00633                        CPL_ERROR_ILLEGAL_INPUT,
00634                        "neighborhoodRange must be greater than 0.0");
00635 
00636         KMO_TRY_EXIT_IF_ERROR(
00637             kmo_dfs_print_parameter_help(parlist,
00638                                      "kmos.kmo_multi_reconstruct.neighborhoodRange"));
00639 
00640         KMO_TRY_EXIT_IF_NULL(
00641             size = kmo_dfs_get_parameter_string(parlist,
00642                                             "kmos.kmo_multi_reconstruct.size"));
00643 
00644         KMO_TRY_EXIT_IF_NULL(
00645             smethod = kmo_dfs_get_parameter_string(parlist,
00646                                          "kmos.kmo_multi_reconstruct.smethod"));
00647 
00648         KMO_TRY_EXIT_IF_NULL(
00649             fmethod = kmo_dfs_get_parameter_string(parlist,
00650                                          "kmos.kmo_multi_reconstruct.fmethod"));
00651 
00652         KMO_TRY_ASSURE((strcmp(size, "max") == 0) ||
00653                        (strcmp(size, "std") == 0),
00654                        CPL_ERROR_ILLEGAL_INPUT,
00655                        "Following output cube size specifications are available: "
00656                        "'std' or 'max'");
00657 
00658 
00659         KMO_TRY_ASSURE((strcmp(smethod, "none") == 0) ||
00660                        (strcmp(smethod, "header") == 0) ||
00661                        (strcmp(smethod, "center") == 0) ||
00662                        (strcmp(smethod, "user") == 0),
00663                        CPL_ERROR_ILLEGAL_INPUT,
00664                        "Following shift methods are available : 'none', "
00665                        "'header', 'center' or 'user'");
00666 
00667         if (strcmp(smethod, "user") == 0) {
00668             filename = kmo_dfs_get_parameter_string(parlist,
00669                                          "kmos.kmo_multi_reconstruct.filename");
00670             KMO_TRY_CHECK_ERROR_STATE();
00671 
00672             KMO_TRY_ASSURE(strcmp(filename, "") != 0,
00673                            CPL_ERROR_ILLEGAL_INPUT,
00674                            "path of file with shift information must be "
00675                            "provided!");
00676 
00677             KMO_TRY_EXIT_IF_ERROR(
00678                 kmo_dfs_print_parameter_help(parlist,
00679                                         "kmos.kmo_multi_reconstruct.filename"));
00680         }
00681 
00682         KMO_TRY_EXIT_IF_ERROR(
00683             kmo_dfs_print_parameter_help(parlist,
00684                                          "kmos.kmo_multi_reconstruct.smethod"));
00685 
00686         ifus_txt = kmo_dfs_get_parameter_string(parlist,
00687                                              "kmos.kmo_multi_reconstruct.ifus");
00688         KMO_TRY_CHECK_ERROR_STATE();
00689 
00690         name = kmo_dfs_get_parameter_string(parlist,
00691                                             "kmos.kmo_multi_reconstruct.name");
00692         KMO_TRY_CHECK_ERROR_STATE();
00693 
00694         if (strcmp(ifus_txt, "") != 0) {
00695             KMO_TRY_ASSURE(strcmp(name, "") == 0,
00696                            CPL_ERROR_ILLEGAL_INPUT,
00697                            "name parameter must be NULL if IFU indices are "
00698                            "provided!");
00699 
00700             KMO_TRY_EXIT_IF_NULL(
00701                 ifus = kmo_identify_values(ifus_txt));
00702 
00703             KMO_TRY_ASSURE(cpl_vector_get_size(ifus) == nr_science_frames,
00704                            CPL_ERROR_ILLEGAL_INPUT,
00705                            "ifus parameter must have the same number of values "
00706                            "than frames provided ) (%lld!=%d)",
00707                            cpl_vector_get_size(ifus), nr_science_frames);
00708 
00709             for (i = 0; i < nr_science_frames; i++) {
00710                 KMO_TRY_ASSURE((cpl_vector_get(ifus, i) > 0.5 &&
00711                                cpl_vector_get(ifus, i) < 24.5 ),
00712                                CPL_ERROR_ILLEGAL_INPUT,
00713                                "IFU numbers must be in the range 1..24");
00714             }
00715         }
00716 
00717         if (strcmp(name, "") != 0) {
00718             KMO_TRY_ASSURE(strcmp(ifus_txt, "") == 0,
00719                            CPL_ERROR_ILLEGAL_INPUT,
00720                            "ifus parameter must be NULL if name is provided!");
00721         }
00722 
00723         KMO_TRY_ASSURE((strcmp(name, "") != 0) || (strcmp(ifus_txt, "") != 0),
00724                        CPL_ERROR_ILLEGAL_INPUT,
00725                        "Either the name of the object or the numbers of the "
00726                        "IFUs to combine must be provided (--name or --ifus "
00727                        "parameters)");
00728 
00729         KMO_TRY_EXIT_IF_ERROR(
00730             kmo_dfs_print_parameter_help(parlist,
00731                                          "kmos.kmo_multi_reconstruct.ifus"));
00732 
00733         KMO_TRY_EXIT_IF_ERROR(
00734             kmo_dfs_print_parameter_help(parlist,
00735                                          "kmos.kmo_multi_reconstruct.name"));
00736 
00737 
00738         suppress_extension = kmo_dfs_get_parameter_bool(parlist,
00739                                           "kmos.kmo_multi_reconstruct.suppress_extension");
00740         KMO_TRY_CHECK_ERROR_STATE();
00741         KMO_TRY_EXIT_IF_ERROR(
00742             kmo_dfs_print_parameter_help(parlist, "kmos.kmo_multi_reconstruct.suppress_extension"));
00743 
00744         KMO_TRY_ASSURE((suppress_extension == TRUE) || (suppress_extension == FALSE),
00745                        CPL_ERROR_ILLEGAL_INPUT,
00746                        "suppress_extension must be TRUE or FALSE!");
00747 
00748         dev_cal = kmo_dfs_get_parameter_bool(parlist,
00749                                              "kmos.kmo_multi_reconstruct.dev_cal");
00750            KMO_TRY_CHECK_ERROR_STATE();
00751            KMO_TRY_EXIT_IF_ERROR(
00752                kmo_dfs_print_parameter_help(parlist, "kmos.kmo_multi_reconstruct.dev_cal"));
00753 
00754            KMO_TRY_ASSURE((dev_cal == TRUE) || (dev_cal == FALSE),
00755                           CPL_ERROR_ILLEGAL_INPUT,
00756                           "dev_cal must be TRUE or FALSE!");
00757 
00758         KMO_TRY_EXIT_IF_ERROR(
00759             kmo_combine_pars_load(parlist,
00760                                   "kmos.kmo_multi_reconstruct",
00761                                   &cmethod,
00762                                   &cpos_rej,
00763                                   &cneg_rej,
00764                                   &citer,
00765                                   &cmin,
00766                                   &cmax,
00767                                   FALSE));
00768 
00769         kmo_band_pars_load(parlist, "kmos.kmo_multi_reconstruct");
00770 
00771         cpl_msg_info("", "-------------------------------------------");
00772 
00773         KMO_TRY_EXIT_IF_NULL(
00774             tmp_frame = kmo_dfs_get_frame(frameset, SCIENCE));
00775 
00776         KMO_TRY_EXIT_IF_NULL(
00777             suffix = kmo_dfs_get_suffix(tmp_frame, TRUE, FALSE));
00778 
00779         KMO_TRY_EXIT_IF_ERROR(
00780             kmo_check_frame_setup_md5_xycal(frameset));
00781         KMO_TRY_EXIT_IF_ERROR(
00782             kmo_check_frame_setup_md5(frameset));
00783 
00784         cpl_msg_info("", "Detected instrument setup:   %s", suffix+1);
00785         cpl_msg_info("", "(grating 1, 2 & 3)");
00786         cpl_msg_info("", "-------------------------------------------");
00787 
00788         // assure that filters and grating  match for
00789         // XCAL, YCAL, LCAL and for data frames to reconstruct
00790         KMO_TRY_EXIT_IF_ERROR(
00791             kmo_check_frameset_setup(frameset, XCAL, TRUE, FALSE, FALSE));
00792         KMO_TRY_EXIT_IF_ERROR(
00793             kmo_check_frameset_setup(frameset, YCAL, TRUE, FALSE, FALSE));
00794         KMO_TRY_EXIT_IF_ERROR(
00795             kmo_check_frameset_setup(frameset, LCAL, TRUE, FALSE, FALSE));
00796         KMO_TRY_EXIT_IF_ERROR(
00797             kmo_check_frame_setup(frameset, XCAL, YCAL, TRUE, FALSE, TRUE));
00798         KMO_TRY_EXIT_IF_ERROR(
00799             kmo_check_frame_setup(frameset, XCAL, LCAL, TRUE, FALSE, TRUE));
00800         KMO_TRY_EXIT_IF_ERROR(
00801             kmo_check_frameset_setup(frameset, SCIENCE, TRUE, FALSE, FALSE));
00802         KMO_TRY_EXIT_IF_ERROR(
00803             kmo_check_frame_setup(frameset, XCAL, SCIENCE, TRUE, FALSE, TRUE));
00804         KMO_TRY_EXIT_IF_ERROR(
00805             kmo_check_frame_setup_md5_xycal(frameset));
00806         KMO_TRY_EXIT_IF_ERROR(
00807             kmo_check_frame_setup_md5(frameset));
00808 
00809 //        KMO_TRY_EXIT_IF_ERROR(
00810 //            kmo_check_cal_frames_rotangle(frameset, XCAL, YCAL));
00811 //        KMO_TRY_EXIT_IF_ERROR(
00812 //            kmo_check_cal_frames_rotangle(frameset, XCAL, LCAL));
00813 
00814         nr_alloc = nr_science_frames;
00815         KMO_TRY_EXIT_IF_NULL(
00816             exposure_filename = cpl_malloc(nr_alloc * sizeof(char *)));
00817         KMO_TRY_EXIT_IF_NULL(
00818             exposure_objectname = cpl_malloc(nr_alloc * sizeof(char *)));
00819         KMO_TRY_EXIT_IF_NULL(
00820             exposure_ifus  = cpl_malloc(nr_alloc * sizeof(int)));
00821 
00822         // check exposure frames
00823         for (i = 0; i < nr_science_frames; i++) {
00824             KMO_TRY_EXIT_IF_NULL(
00825                 tmp_str = cpl_sprintf("%d", i));
00826 
00827             KMO_TRY_EXIT_IF_NULL(
00828                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00829             cpl_free(tmp_str);
00830 
00831             KMO_TRY_EXIT_IF_NULL(
00832                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00833 
00834             kmo_init_fits_desc(&desc);
00835 
00836             desc = kmo_identify_fits_header(exposure_filename[i]);
00837             KMO_TRY_CHECK_ERROR_STATE_MSG("Provided fits file doesn't seem to "
00838                                           "be in KMOS-format!");
00839 
00840             KMO_TRY_ASSURE(((desc.nr_ext == KMOS_NR_DETECTORS) ||
00841                             ((desc.nr_ext == 2*KMOS_NR_DETECTORS))) &&
00842                            (desc.ex_badpix == FALSE) &&
00843                            ((desc.fits_type == raw_fits) ||
00844                             (desc.fits_type == f2d_fits)) &&
00845                            (desc.frame_type == detector_frame),
00846                            CPL_ERROR_ILLEGAL_INPUT,
00847                            "The frame to reconstruct isn't in the correct "
00848                            "format!!!");
00849             kmo_free_fits_desc(&desc);
00850         }
00851 
00852         // select IFU for each exposure
00853         KMO_TRY_EXIT_IF_NULL(
00854             empty_frames = cpl_malloc(nr_alloc * sizeof(cpl_frame *)));
00855         int found=0;
00856         for (i = 0; i < nr_science_frames; i++) {
00857             empty_frames[i] = NULL;
00858             if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
00859                 found = 1;
00860 //                const char *tmpString;
00861                 exposure_ifus[i] = (int) (cpl_vector_get(ifus, i) + 0.1);
00862                 KMO_TRY_EXIT_IF_NULL(
00863                     pl = kmclipm_propertylist_load(exposure_filename[i], 0));
00864                 KMO_TRY_EXIT_IF_NULL(
00865                     tmp_ocs = cpl_sprintf("%s%d%s", IFU_NAME_PREFIX,
00866                                           exposure_ifus[i], IFU_NAME_POSTFIX));
00867                 if (cpl_propertylist_has(pl, tmp_ocs)) {
00868                     tmp_str = (char*)cpl_propertylist_get_string(pl, tmp_ocs);
00869                 } else {
00870                     tmp_str = "";
00871                 }
00872                 KMO_TRY_EXIT_IF_NULL(
00873                     exposure_objectname[i] = cpl_sprintf("%s", tmp_str));
00874                 cpl_free(tmp_ocs);
00875                 cpl_propertylist_delete(pl); pl = NULL;
00876             }  else {                   //IFU selected by user given object name
00877                 exposure_objectname[i] = (char*)name;
00878                 KMO_TRY_EXIT_IF_NULL(
00879                     tmp_str = cpl_sprintf("%d", i));
00880 
00881                 KMO_TRY_EXIT_IF_NULL(
00882                     frame = kmo_dfs_get_frame(exposures, tmp_str));
00883                 cpl_free(tmp_str);
00884 
00885                 KMO_TRY_CHECK_ERROR_STATE();
00886                 int this_ifu = kmo_get_index_from_ocs_name(frame, name);
00887                 KMO_TRY_CHECK_ERROR_STATE();
00888                 if (this_ifu > 0) {
00889                     found = 1;
00890                     exposure_ifus[i] = this_ifu;
00891                 } else {
00892                     empty_frames[i] = frame;
00893                     exposure_ifus[i] = -1;
00894                     cpl_msg_warning("",
00895                                     "Could not find any IFU with an object "
00896                                     "named '%s' in file %s",
00897                                     name, exposure_filename[i]);
00898                 }
00899             }
00900             KMO_TRY_CHECK_ERROR_STATE();
00901         }
00902         if (! found) {
00903             cpl_msg_error("",
00904                           "Could not find any IFU with an object named '%s' in "
00905                           "any input file", name);
00906             KMO_TRY_EXIT_WITH_ERROR(CPL_ERROR_ILLEGAL_INPUT);
00907         }
00908         int j = 0;
00909         for (i = 0; i < nr_alloc; i++) {
00910             if (empty_frames[i] != NULL) {
00911                 KMO_TRY_EXIT_IF_ERROR(
00912                     cpl_frameset_erase_frame(exposures, empty_frames[i]));
00913                 nr_science_frames--;
00914                 exposure_ifus[j] = exposure_ifus[i];
00915             } else {
00916                 exposure_ifus[j] = exposure_ifus[i];
00917                 j++;
00918             }
00919         }
00920         for (i = 0; i < nr_science_frames; i++) {
00921             KMO_TRY_EXIT_IF_NULL(
00922                 tmp_str = cpl_sprintf("%d", i));
00923 
00924             KMO_TRY_EXIT_IF_NULL(
00925                 frame = kmo_dfs_get_frame(exposures, tmp_str));
00926             cpl_free(tmp_str);
00927 
00928             KMO_TRY_EXIT_IF_NULL(
00929                 exposure_filename[i] = (char*)cpl_frame_get_filename(frame));
00930         }
00931 
00932         cpl_free(empty_frames); empty_frames = NULL;
00933 
00934         // get reference header, subheader and set grid definition
00935         device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00936 
00937         KMO_TRY_EXIT_IF_NULL(
00938             ref_main_header = kmclipm_propertylist_load(exposure_filename[0],0));
00939         KMO_TRY_EXIT_IF_NULL(
00940             ref_frame = cpl_frameset_get_first(exposures));
00941         KMO_TRY_EXIT_IF_NULL(
00942             ref_sub_header = kmclipm_propertylist_load(exposure_filename[0],
00943                                                        device_nr));
00944         KMO_TRY_EXIT_IF_ERROR(
00945             kmclipm_setup_grid(&gd, imethod, neighborhoodRange, pix_scale));
00946 
00947         exposure_rotangle = kmo_mr_get_rot_angle(kmo_dfs_get_frame(exposures, "0"));
00948 
00949         KMO_TRY_EXIT_IF_NULL(
00950             lcal_frame = kmo_dfs_get_frame(frameset, LCAL));
00951 
00952         KMO_TRY_EXIT_IF_NULL(
00953             lcalImg = kmo_dfs_load_cal_image_frame(lcal_frame,
00954                                                    1, 0, exposure_rotangle,
00955                                                    FALSE, NULL,
00956                                                    &rotangle_found, -1, 0, 0));
00957 
00958         KMO_TRY_EXIT_IF_NULL(
00959             tmp_header = kmo_dfs_load_primary_header(frameset, LCAL));
00960 
00961         KMO_TRY_EXIT_IF_NULL(
00962             keyword = cpl_sprintf("%s%d%s", IFU_FILTID_PREFIX, device_nr,
00963                                   IFU_FILTID_POSTFIX));
00964         KMO_TRY_EXIT_IF_NULL(
00965             filter_id = cpl_propertylist_get_string(tmp_header, keyword));
00966 
00967         int band_method = 0;
00968         KMO_TRY_EXIT_IF_NULL(
00969             band_table = kmo_dfs_load_table(frameset, WAVE_BAND, 1, 0));
00970 
00971         KMO_TRY_EXIT_IF_ERROR(
00972             kmclipm_setup_grid_band_lcal(&gd, lcalImg, filter_id,
00973                                          band_method, band_table));
00974         cpl_image_delete(lcalImg); lcalImg = NULL;
00975         cpl_propertylist_delete(tmp_header); tmp_header = NULL;
00976         cpl_free(keyword); keyword = NULL;
00977         cpl_table_delete(band_table); band_table = NULL;
00978 
00979         //extract sub-headers for each exposures, calculate WCS
00980         KMO_TRY_EXIT_IF_NULL(
00981             header_data = cpl_malloc(nr_science_frames*sizeof(cpl_propertylist*)));
00982         for (i = 0; i < nr_science_frames; i++) {
00983            device_nr = ((exposure_ifus[0] -1) / KMOS_IFUS_PER_DETECTOR) + 1;
00984            KMO_TRY_EXIT_IF_NULL(
00985                header_data[i] = kmclipm_propertylist_load(exposure_filename[i],
00986                                                           device_nr));
00987            KMO_TRY_EXIT_IF_ERROR(
00988                 kmclipm_update_property_int(header_data[i],"NAXIS", 3,""));
00989            KMO_TRY_EXIT_IF_ERROR(
00990                 kmclipm_update_property_int(header_data[i],"NAXIS1",gd.x.dim,""));
00991            KMO_TRY_EXIT_IF_ERROR(
00992                 kmclipm_update_property_int(header_data[i],"NAXIS2",gd.y.dim,""));
00993            KMO_TRY_EXIT_IF_ERROR(
00994                 kmclipm_update_property_int(header_data[i],"NAXIS3",gd.l.dim,""));
00995            cpl_propertylist *tmpHeader;
00996            KMO_TRY_EXIT_IF_NULL(
00997                 tmpHeader = kmclipm_propertylist_load(exposure_filename[i],0));
00998            KMO_TRY_EXIT_IF_ERROR(
00999                 kmo_calc_wcs_gd(tmpHeader, header_data[i], exposure_ifus[i], gd));
01000            cpl_propertylist_delete(tmpHeader);
01001         }
01002 
01003         // check rotation angle
01004         if (dev_cal == FALSE) {
01005             cd1_1 = kmo_dfs_get_property_double(header_data[0], CD1_1);
01006             cd1_2 = kmo_dfs_get_property_double(header_data[0], CD1_2);
01007             KMO_TRY_CHECK_ERROR_STATE();
01008             ang1 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
01009             for (i = 1; i < nr_science_frames; i++) {
01010                 cd1_1 = kmo_dfs_get_property_double(header_data[i], CD1_1);
01011                 cd1_2 = kmo_dfs_get_property_double(header_data[i], CD1_2);
01012                 KMO_TRY_CHECK_ERROR_STATE();
01013                 ang2 = atan(cd1_2/cd1_1)*180/CPL_MATH_PI;
01014 
01015                 if (strcmp(smethod, "none") != 0) {
01016                     // center, header, user
01017                     KMO_TRY_ASSURE(fabs(ang1-ang2) <= 0.5,
01018                                    CPL_ERROR_ILLEGAL_INPUT,
01019                                    "Orientation of cube 1 (%gdeg) and cube %d "
01020                                    "(%gdeg) differ! "
01021                                    "Align the orientation of this cube with "
01022                                    "kmo_rotate before applying this recipe.",
01023                                    ang1, i+1, ang2);
01024                 } else {
01025                     // none
01026                     if (fabs(ang1-ang2) > 0.5) {
01027                         cpl_msg_warning("",
01028                                         "Orientation of cube 1 (%gdeg) and cube %d "
01029                                         "(%gdeg) differ! Processing anyway.",
01030                                         ang1, i+1, ang2);
01031                     }
01032                 }
01033             }
01034         }
01035 
01036         // set x/y shifts
01037         KMO_TRY_EXIT_IF_NULL(
01038             xshifts = cpl_malloc(nr_science_frames * sizeof(double)));
01039         KMO_TRY_EXIT_IF_NULL(
01040             yshifts = cpl_malloc(nr_science_frames * sizeof(double)));
01041         KMO_TRY_EXIT_IF_ERROR(
01042             kmo_mr_get_offsets(nr_science_frames, smethod, imethod, neighborhoodRange,
01043                                filename, frameset, exposures, exposure_ifus,
01044                                (const cpl_propertylist**)header_data,
01045                                fmethod,
01046                                cmethod,
01047                                cpos_rej,
01048                                cneg_rej,
01049                                citer,
01050                                cmin,
01051                                cmax,
01052                                pix_scale,
01053                                xshifts, yshifts));
01054 
01055         for (i = 0; i < nr_science_frames; i++) {
01056             printf("exposure %d: filename %s, selected IFU %d, object name "
01057                    "\"%s\", xshift %f, yshift %f\n", i, exposure_filename[i],
01058                    exposure_ifus[i], exposure_objectname[i], xshifts[i], yshifts[i]);
01059         }
01060 
01061         //
01062         // set spatial part of the grid
01063         //
01064 //        size = "max";
01065         if (strcmp(size, "max") == 0) {
01066             double xmin=0, xmax=0, ymin=0, ymax=0;
01067             double gxshift, gyshift, gxdim, gydim;
01068             double pixel_resolution = pix_scale;
01069             int xdim, ydim;
01070 
01071             for (i = 0; i < nr_science_frames; i++) {
01072                 if (xmin > xshifts[i]) { xmin = xshifts[i]; }
01073                 if (xmax < xshifts[i]) { xmax = xshifts[i]; }
01074                 if (ymin > yshifts[i]) { ymin = yshifts[i]; }
01075                 if (ymax < yshifts[i]) { ymax = yshifts[i]; }
01076             }
01077             if (xmax > 0.0001) {
01078                 gxshift = - ceil(xmax);
01079             } else {
01080                 gxshift = 0.;
01081             }
01082             if (ymin < -0.0001) {
01083                 gyshift = floor(ymin);
01084             } else {
01085                 gyshift = 0.;
01086             }
01087             if (xmin < -0.0001) {
01088                 gxdim = - floor(xmin);
01089             } else {
01090                 gxdim = 0.;
01091             }
01092             if (ymax > 0.0001) {
01093                 gydim = ceil(ymax);
01094             } else {
01095                 gydim = 0.;
01096             }
01097 
01098             xdim = (int) (gxdim - gxshift + .5);
01099             ydim = (int) (gydim - gyshift + .5);
01100             gd.x.start += gxshift * pixel_resolution;
01101             gd.y.start += gyshift * pixel_resolution;
01102             gd.x.dim += xdim;
01103             gd.y.dim += ydim;
01104 //            printf("X: %f < %f      Y: %f < %f \n",xmin,xmax,ymin,ymax);
01105 //            printf("gxshift: %f  gxdim: %f   xdim: %d        gyshift: %f  gydim: %f  ydim: %d \n",
01106 //                    gxshift, gxdim, xdim, gyshift, gydim, ydim);
01107 //            printf("GD: %f  %d     %f %d\n", gd.x.start, gd.x.dim, gd.y.start, gd.y.dim);
01108         }
01109 
01110         //
01111         // reconstruct multiple detector images
01112         //
01113 
01114 //        printf("GD: %f %f %d     %f %f %d     %f %f %d\n",
01115 //                gd.x.start, gd.x.delta, gd.x.dim,
01116 //                gd.y.start, gd.y.delta, gd.y.dim,
01117 //                gd.l.start, gd.l.delta, gd.l.dim);
01118 
01119         KMO_TRY_EXIT_IF_ERROR(
01120             kmo_priv_multi_reconstruct(frameset,
01121                                        exposures,
01122                                        exposure_ifus,
01123                                        xshifts,
01124                                        yshifts,
01125                                        gd,
01126                                        &cube_combined_data,
01127                                        &cube_combined_noise,
01128                                        pix_scale));
01129 
01130         if (!suppress_extension) {
01131             // setup output category COMBINE + ESO PRO CATG
01132             if (strcmp(ifus_txt, "") != 0) { //IFU selected by user given list
01133                 KMO_TRY_EXIT_IF_NULL(
01134                     tmp_str = cpl_sprintf("IFU"));
01135             } else {
01136                 KMO_TRY_EXIT_IF_NULL(
01137                     tmp_str = cpl_sprintf("%s", name));
01138             }
01139 
01140             KMO_TRY_EXIT_IF_NULL(
01141                 filename_output_cube = cpl_sprintf("%s_%s", CUBE_MULTI, tmp_str));
01142             cpl_free(tmp_str); tmp_str = NULL;
01143         } else {
01144             KMO_TRY_EXIT_IF_NULL(
01145                 filename_output_cube = cpl_sprintf("%s", CUBE_MULTI));
01146         }
01147 
01148         KMO_TRY_EXIT_IF_ERROR(
01149             kmo_dfs_save_main_header(frameset, filename_output_cube, "",
01150                                      ref_frame, NULL, parlist, cpl_func));
01151         // save output
01152         KMO_TRY_EXIT_IF_NULL(
01153             extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01154                                           EXT_DATA));
01155 
01156         // calculate WCS
01157         KMO_TRY_EXIT_IF_ERROR(
01158             kmo_calc_wcs_gd(ref_main_header, ref_sub_header, exposure_ifus[0], gd));
01159 
01160         KMO_TRY_EXIT_IF_ERROR(
01161             kmclipm_update_property_string(ref_sub_header,
01162                                            EXTNAME,
01163                                            extname,
01164                                            "FITS extension name"));
01165         cpl_free(extname); extname = NULL;
01166 
01167         KMO_TRY_EXIT_IF_ERROR(
01168             kmo_dfs_save_cube(cube_combined_data, filename_output_cube,
01169                               "", ref_sub_header, 0./0.));
01170 
01171         if (cube_combined_noise != NULL) {
01172             KMO_TRY_EXIT_IF_NULL(
01173                 extname = kmo_extname_creator(ifu_frame, exposure_ifus[0],
01174                                               EXT_NOISE));
01175 
01176             KMO_TRY_EXIT_IF_ERROR(
01177                 kmclipm_update_property_string(ref_sub_header,
01178                                         EXTNAME,
01179                                         extname,
01180                                         "FITS extension name"));
01181             cpl_free(extname); extname = NULL;
01182 
01183             KMO_TRY_EXIT_IF_ERROR(
01184                 kmo_dfs_save_cube(cube_combined_noise, filename_output_cube,
01185                                   "", ref_sub_header, 0./0.));
01186         }
01187     }
01188     KMO_CATCH
01189     {
01190         KMO_CATCH_MSG();
01191         ret_val = -1;
01192     }
01193 
01194     cpl_free(suffix); suffix = NULL;
01195     cpl_free(filename_output_cube); filename_output_cube = NULL;
01196     cpl_propertylist_delete(main_header); main_header = NULL;
01197     cpl_vector_delete(ifus); ifus = NULL;
01198     cpl_imagelist_delete(cube_combined_data); cube_combined_data = NULL;
01199     cpl_imagelist_delete(cube_combined_noise); cube_combined_noise = NULL;
01200     if (exposures != NULL) {cpl_frameset_delete(exposures);}
01201     if (exposure_filename != NULL) {cpl_free(exposure_filename);}
01202     if ((ifus_txt != NULL) && (strcmp(ifus_txt, "") != 0)) { //IFU selected by user given list
01203         for (i = 0; i < nr_alloc; i++) {
01204             cpl_free(exposure_objectname[i]);
01205         }
01206     }
01207     if (exposure_objectname != NULL) {cpl_free(exposure_objectname);}
01208     if (exposure_ifus != NULL) {cpl_free(exposure_ifus);}
01209     if (ref_main_header != NULL) {cpl_propertylist_delete(ref_main_header);}
01210     if (ref_sub_header != NULL) {cpl_propertylist_delete(ref_sub_header);}
01211     if (xshifts != NULL) {cpl_free(xshifts);}
01212     if (yshifts != NULL) {cpl_free(yshifts);}
01213 
01214     if (data_cube_list != NULL) {
01215         for (i = 0; i < nr_science_frames; i++) {
01216             cpl_imagelist_delete(data_cube_list[i]); data_cube_list[i] = NULL;
01217         }
01218         cpl_free(data_cube_list); data_cube_list = NULL;
01219     }
01220 
01221     if (noise_cube_list != NULL) {
01222         for (i = 0; i < nr_science_frames; i++) {
01223             cpl_imagelist_delete(noise_cube_list[i]); noise_cube_list[i] = NULL;
01224         }
01225         cpl_free(noise_cube_list); noise_cube_list = NULL;
01226     }
01227 
01228     if (data_header_list != NULL) {
01229         for (i = 0; i < nr_science_frames; i++) {
01230             cpl_propertylist_delete(data_header_list[i]);
01231             data_header_list[i] = NULL;
01232         }
01233         cpl_free(data_header_list); data_header_list = NULL;
01234     }
01235 
01236     if (noise_header_list != NULL) {
01237         for (i = 0; i < nr_science_frames; i++) {
01238             cpl_propertylist_delete(noise_header_list[i]);
01239             noise_header_list[i] = NULL;
01240         }
01241         cpl_free(noise_header_list); noise_header_list = NULL;
01242     }
01243 
01244     if (header_data != NULL) {
01245         for (i = 0; i < nr_science_frames; i++) {
01246             cpl_propertylist_delete(header_data[i]);
01247             header_data[i] = NULL;
01248         }
01249         cpl_free(header_data); header_data = NULL;
01250     }
01251 
01252     return ret_val;
01253 }
01254